Merge lp:~wallyworld/launchpad/new-team-picker-load-form into lp:launchpad

Proposed by Ian Booth
Status: Merged
Approved by: Curtis Hovey
Approved revision: no longer in the source branch.
Merged at revision: 15492
Proposed branch: lp:~wallyworld/launchpad/new-team-picker-load-form
Merge into: lp:launchpad
Prerequisite: lp:~wallyworld/launchpad/new-team-picker
Diff against target: 1007 lines (+326/-204)
11 files modified
lib/lp/app/javascript/formoverlay/formoverlay.js (+4/-4)
lib/lp/app/javascript/picker/person_picker.js (+124/-86)
lib/lp/app/javascript/picker/picker.js (+62/-37)
lib/lp/app/javascript/picker/picker_patcher.js (+5/-6)
lib/lp/app/javascript/picker/tests/test_personpicker.html (+22/-5)
lib/lp/app/javascript/picker/tests/test_personpicker.js (+62/-6)
lib/lp/app/javascript/picker/tests/test_picker_patcher.js (+34/-23)
lib/lp/app/javascript/subscribers/subscribers_list.js (+6/-6)
lib/lp/bugs/javascript/filebug_dupefinder.js (+2/-2)
lib/lp/registry/javascript/sharing/shareepicker.js (+0/-24)
lib/lp/registry/javascript/sharing/tests/test_shareepicker.js (+5/-5)
To merge this branch: bzr merge lp:~wallyworld/launchpad/new-team-picker-load-form
Reviewer Review Type Date Requested Status
Curtis Hovey (community) code Approve
Review via email: mp+111543@code.launchpad.net

Commit message

Load the team form from the model and make it available for the New Team functionality in the pickers.

Description of the change

== Implementation ==

The branch continues the work to add team creation capability to the person picker. The previous branch hard coded a sample team form, this branch provides the infrastructure to fetch the actual team form html from the model using an XHR ++form++ call. There are also some small fixes noted in the review comments from the previous branch.

There may be several pickers which need to have the create team form html provided to them. We don't want to make a separate XHR call for each picker, so what happens is that the first picker to be processed makes the call and the others are queued up and provided with the result when it arrives. A YUI namespace is used to coordinate the workflow since the picker javascript can live inside separate yui instances and events don't propagate across instances.

The XHR call to fetch the create team form happens from the picker initialisation. By the time the user clicks on the New Team link, the form should already have been loaded and rendered, but if not, the user sees a big spinner which is replaced by the form automatically when it arrives.

This branch sees a form containing every team attribute rendered. The next branch will implement a form with only a subset of the attributes eg name, displayname, subscription policy etc.

== Tests ==

Existing yui tests were modified to account for the XHR call and stub that out. A test was added to ensure only one XHR call is made for multiple pickers.

== Lint ==

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/app/javascript/picker/person_picker.js
  lib/lp/app/javascript/picker/picker.js
  lib/lp/app/javascript/picker/picker_patcher.js
  lib/lp/app/javascript/picker/tests/test_personpicker.html
  lib/lp/app/javascript/picker/tests/test_personpicker.js
  lib/lp/app/javascript/picker/tests/test_picker_patcher.js
  lib/lp/registry/javascript/sharing/shareepicker.js
  lib/lp/registry/javascript/sharing/tests/test_shareepicker.js

To post a comment you must log in.
Revision history for this message
Richard Harding (rharding) wrote :

Ian, just giving a quick look and was curious if you'd thought about doing the load_new_team_form purely with events? The pickers would listen to an event: Y.on('new_team_form:load') and then the ajax code could just fire that event with the html it fetched to help decouple the whole thing and make it easier to test each endpoint?

Revision history for this message
Ian Booth (wallyworld) wrote :

Hi Rick

It was buried in my long covering letter - yes I did consider it, but this approach will suffer the same sad fate as when it was tried previously - there are separate yui instances involved due to js embedded in the widget TAL so event propagation won't work across instances and global events are verboten. So I have to use the pattern introduced previously ie coordinate things using a namespace.

Revision history for this message
Curtis Hovey (sinzui) wrote :

Thank you for this branch. I have a few comments that need fixing before you land this branch.

=== modified file 'lib/lp/app/javascript/picker/person_picker.js'
--- lib/lp/app/javascript/picker/person_picker.js 2012-06-21 07:43:17 +0000
+++ lib/lp/app/javascript/picker/person_picker.js 2012-06-25 04:17:20 +0000
...

We prefer function expressions because they clearly show that the
function is a value of a variable. function statements are always hoisted
to the top of where scope is defined to ensure you can call them before they
are defined. Browsers and developers handle this badly.

+ function on_success(id, response, picker) {
        var on_success = function(id, response, picker) {

...
+ function on_failure(id, response, picker) {
        var on_failure = function(id, response, picker) {

=== modified file 'lib/lp/app/javascript/picker/tests/test_personpicker.html'
--- lib/lp/app/javascript/picker/tests/test_personpicker.html 2012-06-21 03:48:05 +0000
+++ lib/lp/app/javascript/picker/tests/test_personpicker.html 2012-06-25 04:17:20 +0000
...
I don't think the   belongs in this test, or in code to make this
visible to webkit...this link is missing action-icon. lazr-btn was intended
for <button>. I think a lot of code uses it as a marker, but we do not
have css rules to make it present weill with links.
+ <a id="edit-anotherpickertest-btn"
+ class="sprite edit lazr-btn yui3-activator-act"
+ href="/fnord/+edit-people"
+ >&nbsp;Edit</a>

=== modified file 'lib/lp/app/javascript/picker/tests/test_personpicker.js'
--- lib/lp/app/javascript/picker/tests/test_personpicker.js 2012-06-22 14:12:33 +0000
+++ lib/lp/app/javascript/picker/tests/test_personpicker.js 2012-06-25 04:17:20 +0000
...

@@ -325,6 +329,32 @@
This markup is invalid. The YUI test will not play in some browsers, notably
IE which knows that <tr> elements may only contain <td>. Some browsers will
will add the <td> for you in the DOM...but that means scripts may break
because they assume there is no <td>.
+ _simple_team_form: function() {
+ return '<table><tr>' +
+ '<input id="field.name">' +
+ '<input id="field.displayname"></tr></table>';
+ },

review: Approve (code)
Revision history for this message
Ian Booth (wallyworld) wrote :

Thanks for the review.

>
> === modified file 'lib/lp/app/javascript/picker/person_picker.js'
> --- lib/lp/app/javascript/picker/person_picker.js 2012-06-21 07:43:17 +0000
> +++ lib/lp/app/javascript/picker/person_picker.js 2012-06-25 04:17:20 +0000
> ...
>
> We prefer function expressions because they clearly show that the
> function is a value of a variable. function statements are always hoisted
> to the top of where scope is defined to ensure you can call them before they
> are defined. Browsers and developers handle this badly.
>

Fair point. I would never do this myself if I were writing the code from
scratch. This code pattern was lifted from formoverlay, and is also used
in subscribers_list and filebug_dupfinder. I'll file a bug to ensure
these other places are fixed.

>
> === modified file 'lib/lp/app/javascript/picker/tests/test_personpicker.html'
> --- lib/lp/app/javascript/picker/tests/test_personpicker.html 2012-06-21 03:48:05 +0000
> +++ lib/lp/app/javascript/picker/tests/test_personpicker.html 2012-06-25 04:17:20 +0000
> ...
> I don't think the &nbsp; belongs in this test, or in code to make this
> visible to webkit...this link is missing action-icon. lazr-btn was intended
> for <button>. I think a lot of code uses it as a marker, but we do not
> have css rules to make it present weill with links.
> + <a id="edit-anotherpickertest-btn"
> + class="sprite edit lazr-btn yui3-activator-act"
> + href="/fnord/+edit-people"
> + >&nbsp;Edit</a>
>
>

Ah, the &nbsp; is old markup originally added to the test harness by
copying old rendered lp html before the recent css changes and this html
in the test was copied to create anotherpicker anchor for this branch.
The tests don't seem to care either way. I'll certainly amend the markup
to confirm with the recent changes.

> === modified file 'lib/lp/app/javascript/picker/tests/test_personpicker.js'
> --- lib/lp/app/javascript/picker/tests/test_personpicker.js 2012-06-22 14:12:33 +0000
> +++ lib/lp/app/javascript/picker/tests/test_personpicker.js 2012-06-25 04:17:20 +0000
> ...
>
> @@ -325,6 +329,32 @@
> This markup is invalid. The YUI test will not play in some browsers, notably
> IE which knows that <tr> elements may only contain <td>. Some browsers will
> will add the <td> for you in the DOM...but that means scripts may break
> because they assume there is no <td>.
> + _simple_team_form: function() {
> + return '<table><tr>' +
> + '<input id="field.name">' +
> + '<input id="field.displayname"></tr></table>';
> + },
>

Yes, you are correct. Clearly my attempt at some trivial html for the
test failed. Will fix.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/app/javascript/formoverlay/formoverlay.js'
--- lib/lp/app/javascript/formoverlay/formoverlay.js 2011-08-31 02:58:52 +0000
+++ lib/lp/app/javascript/formoverlay/formoverlay.js 2012-06-26 00:18:26 +0000
@@ -523,17 +523,17 @@
523 * @param url {String} The URL from where to load the form content.523 * @param url {String} The URL from where to load the form content.
524 */524 */
525 loadFormContentAndRender: function (url) {525 loadFormContentAndRender: function (url) {
526 function on_success(id, response, overlay) {526 var on_success = function(id, response, overlay) {
527 overlay.set('form_content', response.responseText);527 overlay.set('form_content', response.responseText);
528 overlay.renderUI();528 overlay.renderUI();
529 overlay.bindUI();529 overlay.bindUI();
530 }530 };
531 function on_failure(id, response, overlay) {531 var on_failure = function(id, response, overlay) {
532 overlay.set(532 overlay.set(
533 'form_content',533 'form_content',
534 "Sorry, an error occurred while loading the form.");534 "Sorry, an error occurred while loading the form.");
535 overlay.renderUI();535 overlay.renderUI();
536 }536 };
537 var cfg = {537 var cfg = {
538 on: {success: on_success, failure: on_failure},538 on: {success: on_success, failure: on_failure},
539 "arguments": this539 "arguments": this
540540
=== modified file 'lib/lp/app/javascript/picker/person_picker.js'
--- lib/lp/app/javascript/picker/person_picker.js 2012-06-21 07:43:17 +0000
+++ lib/lp/app/javascript/picker/person_picker.js 2012-06-26 00:18:26 +0000
@@ -18,62 +18,50 @@
18 if (!Y.Lang.isValue(LP.links.me)) {18 if (!Y.Lang.isValue(LP.links.me)) {
19 this.set('show_assign_me_button', false);19 this.set('show_assign_me_button', false);
20 }20 }
21 this.set('new_team_template', this._new_team_template());21 if (this.get('show_create_team')) {
22 this.set('new_team_form', this._new_team_form());22 // We need to provide the 'New team' link.
23 // There could be several pickers and we only want to make the XHR
24 // call to get the form once. So first one gets to do the call and
25 // subsequent ones register the to be notified of the result.
26 this.team_form_node = Y.Node.create(this._new_team_template());
27 this.form_namespace = Y.namespace('lp.app.picker.teamform');
28 var form_callbacks = this.form_namespace.form_callbacks;
29 var perform_load = false;
30 if (!Y.Lang.isArray(form_callbacks)) {
31 perform_load = true;
32 form_callbacks = [];
33 this.form_namespace.form_callbacks = form_callbacks;
34 }
35 form_callbacks.push({
36 picker: this,
37 callback: this._render_new_team_form});
38 this._load_new_team_form(perform_load);
39 }
23 },40 },
2441
25 _new_team_template: function() {42 _new_team_template: function() {
26 return [43 return [
27 '<div class="new-team-node">',44 '<div class="new-team-node">',
28 '<div class="step-on" style="width: 100%;"></div>',45 '<div id=new-team-form-placeholder ',
29 '<div class="transparent important-notice-popup">',46 'class="yui3-overlay-indicator-content">',
30 '{{> new_team_form}}',47 '<img src="/@@/spinner-big/">',
31 '<div class="extra-form-buttons">',48 '</div>',
32 '<button class="yes_button" type="button"></button>',49 '<div class="extra-form-buttons hidden">',
33 '<button class="no_button" type="button"></button>',50 '<button class="yes_button" type="button">',
51 'Create Team</button>',
52 '<button class="no_button" type="button">Cancel</button>',
34 '</div>',53 '</div>',
35 '</div>',54 '</div>',
36 '</div>'].join('');55 '</div>'].join('');
37 },56 },
3857
39 _new_team_form: function() {
40 // TODO - get the form using ++form++
41 return [
42 "<table id='launchpad-form-widgets' class='form'>",
43 "<tbody><tr><td colspan='2'><div>",
44 "<label for='field.name'>Name:</label><div>",
45 "<input type='text' value='' size='20'",
46 " name='field.name' id='field.name'",
47 " class='lowerCaseText textType'></div>",
48 "<p class='formHelp'>",
49 " A short unique name, beginning with a lower-case letter",
50 " or number, and containing only letters, numbers, dots,",
51 " hyphens, or plus signs.</p>",
52 "</div></td></tr><tr><td colspan='2'><div>",
53 "<label for='field.displayname'>Display Name:</label><div>",
54 "<input type='text' value='' size='20'",
55 " name='field.displayname' id='field.displayname'",
56 " class='textType'></div>",
57 "<p class='formHelp'>",
58 " This team's name as you would like it displayed",
59 " throughout Launchpad.</p>",
60 "</div></td></tr><tr><td colspan='2'><div>",
61 "<label for='field.visibility'>Visibility:</label>",
62 "<div><div><div class='value'>",
63 "<select size='1'",
64 " name='field.visibility' id='field.visibility'>",
65 "<option value='PUBLIC' selected='selected'>Public</option>",
66 "<option value='PRIVATE'>Private</option></select></div>",
67 "</div></div><p class='formHelp'>",
68 " Anyone can see a public team's data. Only team members",
69 " and Launchpad admins can see private team data.",
70 " Private teams cannot become public.</p>",
71 "</div></td></tr></tbody></table>"
72 ].join('');
73 },
74
75 hide: function() {58 hide: function() {
76 this.get('boundingBox').setStyle('display', 'none');59 this.get('boundingBox').setStyle('display', 'none');
60 // We want to cancel the new team form is there is one rendered.
61 var node = this.get('contentBox').one('.new-team-node');
62 if (Y.Lang.isValue(node) && !node.hasClass('hidden')) {
63 this.hide_extra_content(node, false);
64 }
77 Y.lazr.picker.Picker.prototype.hide.call(this);65 Y.lazr.picker.Picker.prototype.hide.call(this);
78 },66 },
7967
@@ -128,72 +116,113 @@
128 });116 });
129 },117 },
130118
131 _cancel_new_team: function(picker) {119 _cancel_new_team: function() {
132 var node = picker.get('contentBox').one('.new-team-node');120 var node = this.get('contentBox').one('.new-team-node');
133 picker.hide_extra_content(node);121 this.hide_extra_content(node);
134 },122 },
135123
136 _save_new_team: function(picker) {124 _save_new_team: function() {
137 var node = picker.get('contentBox').one('.new-team-node');125 var node = this.get('contentBox').one('.new-team-node');
138 var team_name = Y.Node.getDOMNode(node.one('[id=field.name]')).value;126 var team_name = node.one('[id=field.name]').get('value');
139 var team_display_name =127 var team_display_name = node.one('[id=field.displayname]')
140 Y.Node.getDOMNode(node.one('[id=field.displayname]')).value;128 .get('value');
141 picker.hide_extra_content(node);129 this.hide_extra_content(node, false);
142 // TODO - make back end call to save team130 // TODO - make back end call to save team
143 var value = {131 var value = {
144 "api_uri": "/~" + team_name,132 "api_uri": "/~" + team_name,
145 "title": team_display_name,133 "title": team_display_name,
146 "value": team_name,134 "value": team_name,
147 "metadata": "team"};135 "metadata": "team"};
148 picker.fire('validate', value);136 this.fire('validate', value);
149 },137 },
150138
151 show_new_team_form: function () {139 _load_new_team_form: function (perform_load) {
152 var partials = {new_team_form: this.get('new_team_form')};140 // Load the new team form from the model using an XHR call.
153 var html = Y.lp.mustache.to_html(141 // If perform_load is true, this is the first invocation of this method
154 this.get('new_team_template'), {}, partials);142 // across all pickers so we do the XHR call and send the result to all
155 var self = this;143 // registered pickers.
144 // If perform_load is false, another picker is making the XNR call and
145 // all we want to do is receive and render the preloaded_team_form.
146 // We first check though that the result hasn't arrived already.
147 var preloaded_team_form = this.form_namespace.team_form;
148 if (Y.Lang.isValue(preloaded_team_form)) {
149 this._render_new_team_form(preloaded_team_form, true);
150 return;
151 }
152 if (!perform_load) {
153 return;
154 }
155
156 var on_success = function(id, response, picker) {
157 Y.Array.each(picker.form_namespace.form_callbacks,
158 function(callback_info) {
159 Y.bind(
160 callback_info.callback, callback_info.picker,
161 response.responseText, true)();
162 });
163 picker.form_namespace.team_form = response.responseText;
164 };
165 var on_failure = function(id, response, picker) {
166 Y.Array.each(picker.form_namespace.form_callbacks,
167 function(callback_info) {
168 Y.bind(
169 callback_info.callback, callback_info.picker,
170 'Sorry, an error occurred while loading the form.',
171 false)();
172 });
173 };
174 var cfg = {
175 on: {success: on_success, failure: on_failure},
176 "arguments": this
177 };
178 var uri = Y.lp.client.get_absolute_uri('people/+newteam/++form++');
179 uri = uri.replace('api/devel', '');
180 this.get("io_provider").io(uri, cfg);
181 },
182
183 _render_new_team_form: function(form_html, show_submit) {
184 // Poke the actual team form into the DOM and wire up the save and
185 // cancel buttons.
186 this.team_form_node.one('#new-team-form-placeholder')
187 .replace(form_html);
156 var button_callback = function(e, callback_fn) {188 var button_callback = function(e, callback_fn) {
157 e.halt();189 e.halt();
158 if (Y.Lang.isFunction(callback_fn) ) {190 if (Y.Lang.isFunction(callback_fn) ) {
159 callback_fn(self);191 Y.bind(callback_fn, this)();
160 }192 }
161 };193 };
162 var team_form_node = Y.Node.create(html);194 var submit_button = this.team_form_node.one(".yes_button");
163 team_form_node.one(".yes_button")195 if (show_submit) {
164 .set('text', 'Create Team')196 submit_button.on(
165 .on('click', function(e) {197 'click', button_callback, this, this._save_new_team);
166 button_callback(e, self._save_new_team);198 } else {
167 });199 submit_button.addClass('hidden');
200 }
201 this.team_form_node.one(".no_button")
202 .on('click', button_callback, this, this._cancel_new_team);
203 this.team_form_node.one('.extra-form-buttons')
204 .removeClass('hidden');
205 },
168206
169 team_form_node.one(".no_button")207 show_new_team_form: function() {
170 .set('text', 'Cancel')
171 .on('click', function(e) {
172 button_callback(e, self._cancel_new_team);
173 });
174 this.get('contentBox').one('.yui3-widget-bd')
175 .insert(team_form_node, 'before');
176 this.show_extra_content(208 this.show_extra_content(
177 team_form_node.one(".important-notice-popup"),209 this.team_form_node, "Enter new team details");
178 "Enter new team details");
179 },210 },
180211
181 _assign_me_button_html: function() {212 _assign_me_button_html: function() {
182 return [213 return [
183 '<a class="yui-picker-assign-me-button bg-image ',214 '<a class="yui-picker-assign-me-button sprite person ',
184 'js-action" href="javascript:void(0)" ',215 'js-action" href="javascript:void(0)" ',
185 'style="background-image: url(/@@/person); ',216 'style="padding-right: 1em">',
186 'padding-right: 1em">',
187 this.get('assign_me_text'),217 this.get('assign_me_text'),
188 '</a>'].join('');218 '</a>'].join('');
189 },219 },
190220
191 _remove_button_html: function() {221 _remove_button_html: function() {
192 return [222 return [
193 '<a class="yui-picker-remove-button bg-image js-action" ',223 '<a class="yui-picker-remove-button sprite remove ',
194 'href="javascript:void(0)" ',224 'js-action" href="javascript:void(0)" ',
195 'style="background-image: url(/@@/remove); ',225 'style="padding-right: 1em">',
196 'padding-right: 1em">',
197 this.get('remove_person_text'),226 this.get('remove_person_text'),
198 '</a>'].join('');227 '</a>'].join('');
199 },228 },
@@ -250,7 +279,16 @@
250 min_search_chars: {value: 2},279 min_search_chars: {value: 2},
251 show_create_team: {value: false},280 show_create_team: {value: false},
252 new_team_template: {value: null},281 new_team_template: {value: null},
253 new_team_form: {value: null}282 new_team_form: {value: null},
283 /**
284 * The object that provides the io function for doing XHR requests.
285 *
286 * @attribute io_provider
287 * @type object
288 * @default Y
289 */
290 io_provider: {value: Y}
254 }291 }
255});292});
256}, "0.1", {"requires": ["base", "node", "lazr.picker", "lp.mustache"]});293}, "0.1", {"requires": [
294 "base", "node", "lazr.picker"]});
257295
=== modified file 'lib/lp/app/javascript/picker/picker.js'
--- lib/lp/app/javascript/picker/picker.js 2012-06-22 14:12:33 +0000
+++ lib/lp/app/javascript/picker/picker.js 2012-06-26 00:18:26 +0000
@@ -825,56 +825,81 @@
825 /*825 /*
826 * Insert the extra content into the form and animate its appearance.826 * Insert the extra content into the form and animate its appearance.
827 */827 */
828 show_extra_content: function(extra_content, header) {828 show_extra_content: function(extra_content, header, steptitle, progress) {
829 if (Y.Lang.isValue(header)) {829 if (Y.Lang.isValue(header)) {
830 this.set('picker_header', this.get('headerContent'));830 if (!Y.Lang.isValue(this.get('saved_header'))) {
831 this.set('saved_header', this.get('headerContent'));
832 }
831 this.set(833 this.set(
832 'headerContent',834 'headerContent',
833 Y.Node.create("<h2></h2>").set('text', header));835 Y.Node.create("<h2></h2>").set('text', header));
834 }836 }
835 this.get('contentBox').one('.yui3-widget-bd').hide();837 if (Y.Lang.isValue(steptitle)) {
836 this.get('contentBox').all('.steps').hide();838 if (!Y.Lang.isValue(this.get('saved_steptitle'))) {
837 var duration = 0;839 this.set('saved_steptitle', this.get('steptitle'));
838 if (this.get('use_animation')) {840 }
839 duration = 0.9;841 this.set('steptitle', steptitle);
840 }842 }
841 var fade_in = new Y.Anim({843 if (Y.Lang.isValue(progress)) {
842 node: extra_content,844 if (!Y.Lang.isValue(this.get('saved_progress'))) {
843 to: {opacity: 1},845 this.set('saved_progress', this.get('progress'));
844 duration: duration846 }
845 });847 this.set('progress', progress);
846 fade_in.run();848 }
849 var contentBox = this.get('contentBox');
850 var original_content = contentBox.one('.yui3-widget-bd');
851 var extra_content_id = extra_content.get('id');
852 if (!Y.Lang.isValue(contentBox.one('#'+extra_content_id))) {
853 extra_content.addClass('important-notice-popup');
854 original_content.insert(extra_content, 'before');
855 }
856 this._fade_in(extra_content, original_content);
847 },857 },
848858
849 hide_extra_content: function(extra_content_node) {859 hide_extra_content: function(extra_content_node, use_animation) {
850 var saved_header = this.get('picker_header');860 var saved_header = this.get('saved_header');
851 if (Y.Lang.isValue(saved_header)) {861 if (Y.Lang.isValue(saved_header)) {
852 this.set('headerContent', saved_header);862 this.set('headerContent', saved_header);
853 this.set('picker_header', null);863 this.set('saved_header', null);
854 }864 }
855 this.get('contentBox').all('.steps').show();865 var saved_steptitle = this.get('saved_steptitle');
866 if (Y.Lang.isValue(saved_steptitle)) {
867 this.set('steptitle', saved_steptitle);
868 this.set('saved_steptitle', null);
869 }
870 var saved_progress = this.get('saved_progress');
871 if (Y.Lang.isValue(saved_progress)) {
872 this.set('progress', saved_progress);
873 this.set('saved_progress', null);
874 }
856 var content_node = this.get('contentBox').one('.yui3-widget-bd');875 var content_node = this.get('contentBox').one('.yui3-widget-bd');
857 if (extra_content_node !== null) {876 this._fade_in(content_node, extra_content_node, use_animation);
858 extra_content_node.get('parentNode')877 },
859 .removeChild(extra_content_node);878
860 content_node.addClass('transparent');879 _fade_in: function(content_node, old_content, use_animation) {
861 content_node.setStyle('opacity', 0);880 content_node.removeClass('hidden');
862 content_node.show();881 if (old_content === null) {
863 var duration = 0;
864 if (this.get('use_animation')) {
865 duration = 0.6;
866 }
867 var content_fade_in = new Y.Anim({
868 node: content_node,
869 to: {opacity: 1},
870 duration: duration
871 });
872 content_fade_in.run();
873 } else {
874 content_node.removeClass('transparent');882 content_node.removeClass('transparent');
875 content_node.setStyle('opacity', 1);883 content_node.setStyle('opacity', 1);
876 content_node.show();884 content_node.show();
877 }885 return;
886 }
887 old_content.addClass('hidden');
888 if (!Y.Lang.isValue(use_animation)) {
889 use_animation = this.get('use_animation');
890 }
891 if (!use_animation) {
892 old_content.setStyle('opacity', 1);
893 return;
894 }
895 content_node.addClass('transparent');
896 content_node.setStyle('opacity', 0);
897 var fade_in = new Y.Anim({
898 node: content_node,
899 to: {opacity: 1},
900 duration: 0.8
901 });
902 fade_in.run();
878 },903 },
879904
880 /*905 /*
881906
=== modified file 'lib/lp/app/javascript/picker/picker_patcher.js'
--- lib/lp/app/javascript/picker/picker_patcher.js 2012-06-21 03:48:05 +0000
+++ lib/lp/app/javascript/picker/picker_patcher.js 2012-06-26 00:18:26 +0000
@@ -247,14 +247,11 @@
247247
248 var node = Y.Node.create(248 var node = Y.Node.create(
249 ['<div class="validation-node">',249 ['<div class="validation-node">',
250 '<div class="step-on" style="width: 100%;"></div>',
251 '<div class="transparent important-notice-popup">',
252 '<div class="validation-content-placeholder"></div>',250 '<div class="validation-content-placeholder"></div>',
253 '<div class="extra-form-buttons">',251 '<div class="extra-form-buttons">',
254 '<button class="yes_button" type="button"></button>',252 '<button class="yes_button" type="button"></button>',
255 '<button class="no_button" type="button"></button>',253 '<button class="no_button" type="button"></button>',
256 '</div>',254 '</div>',
257 '</div>',
258 '</div>'].join(''));255 '</div>'].join(''));
259256
260 var button_callback = function(e, callback_fn) {257 var button_callback = function(e, callback_fn) {
@@ -272,8 +269,7 @@
272 .on('click', function(e) { button_callback(e, no_fn); });269 .on('click', function(e) { button_callback(e, no_fn); });
273270
274 node.one(".validation-content-placeholder").replace(content);271 node.one(".validation-content-placeholder").replace(content);
275 picker.get('contentBox').one('.yui3-widget-bd').insert(node, 'before');272 picker.show_extra_content(node);
276 picker.show_extra_content(node.one(".important-notice-popup"));
277};273};
278274
279/*275/*
@@ -315,6 +311,9 @@
315function reset_form(picker) {311function reset_form(picker) {
316 var validation_node = picker.get('contentBox').one('.validation-node');312 var validation_node = picker.get('contentBox').one('.validation-node');
317 picker.hide_extra_content(validation_node);313 picker.hide_extra_content(validation_node);
314 if (Y.Lang.isValue(validation_node)) {
315 validation_node.remove(true);
316 }
318}317}
319318
320319
@@ -348,7 +347,6 @@
348 validators, picker, picker_result, do_save, do_cancel) {347 validators, picker, picker_result, do_save, do_cancel) {
349 if (validators.length === 0) {348 if (validators.length === 0) {
350 do_save();349 do_save();
351 reset_form(picker);
352 return;350 return;
353 }351 }
354 var validator_callback = validators.pop();352 var validator_callback = validators.pop();
@@ -495,6 +493,7 @@
495 Y.log('Got save event.');493 Y.log('Got save event.');
496 var picker_result = e.details[Y.lazr.picker.Picker.SAVE_RESULT];494 var picker_result = e.details[Y.lazr.picker.Picker.SAVE_RESULT];
497 user_has_searched = false;495 user_has_searched = false;
496 reset_form(picker);
498 picker.hide();497 picker.hide();
499 if (Y.Lang.isFunction(config.save)) {498 if (Y.Lang.isFunction(config.save)) {
500 config.save(picker_result);499 config.save(picker_result);
501500
=== modified file 'lib/lp/app/javascript/picker/tests/test_personpicker.html'
--- lib/lp/app/javascript/picker/tests/test_personpicker.html 2012-06-21 03:48:05 +0000
+++ lib/lp/app/javascript/picker/tests/test_personpicker.html 2012-06-26 00:18:26 +0000
@@ -36,8 +36,6 @@
36 <script type="text/javascript"36 <script type="text/javascript"
37 src="../../../../../../build/js/lp/app/lazr/lazr.js"></script>37 src="../../../../../../build/js/lp/app/lazr/lazr.js"></script>
38 <script type="text/javascript"38 <script type="text/javascript"
39 src="../../../../../../build/js/lp/app/mustache.js"></script>
40 <script type="text/javascript"
41 src="../../../../../../build/js/lp/app/overlay/overlay.js"></script>39 src="../../../../../../build/js/lp/app/overlay/overlay.js"></script>
42 <script type="text/javascript"40 <script type="text/javascript"
43 src="../../../../../../build/js/lp/app/effects/effects.js"></script>41 src="../../../../../../build/js/lp/app/effects/effects.js"></script>
@@ -49,6 +47,8 @@
49 src="../../../../../../build/js/lp/app/picker/picker.js"></script>47 src="../../../../../../build/js/lp/app/picker/picker.js"></script>
50 <script type="text/javascript"48 <script type="text/javascript"
51 src="../../../../../../build/js/lp/app/picker/picker_patcher.js"></script>49 src="../../../../../../build/js/lp/app/picker/picker_patcher.js"></script>
50 <script type="text/javascript"
51 src="../../../../../../build/js/lp/app/testing/mockio.js"></script>
5252
5353
54 <!-- The module under test. -->54 <!-- The module under test. -->
@@ -69,9 +69,26 @@
69 <span>69 <span>
70 A picker widget test70 A picker widget test
71 <a id="edit-pickertest-btn"71 <a id="edit-pickertest-btn"
72 class="sprite edit lazr-btn yui3-activator-act"72 class="sprite edit action-icon yui3-activator-act"
73 href="/fnord/+edit-people"73 href="/fnord/+edit-people"
74 >&nbsp;Edit</a>74 >Edit</a>
75 </span>
76 <span class="yui3-activator-data-box">
77 </span>
78 <span class="yui3-activator-message-box yui3-activator-hidden"></span>
79 </span>
80 </span>
81 </div>
82
83 <div class="yui3-widget yui3-activator yui3-activator-focused">
84 <span id="anotherpicker_id" class="yui3-activator-content yui3-activator-success">
85 <span id="anotherpickertest">
86 <span>
87 Another picker widget test
88 <a id="edit-anotherpickertest-btn"
89 class="sprite edit action-icon yui3-activator-act"
90 href="/fnord/+edit-people"
91 >Edit</a>
75 </span>92 </span>
76 <span class="yui3-activator-data-box">93 <span class="yui3-activator-data-box">
77 </span>94 </span>
7895
=== modified file 'lib/lp/app/javascript/picker/tests/test_personpicker.js'
--- lib/lp/app/javascript/picker/tests/test_personpicker.js 2012-06-22 14:12:33 +0000
+++ lib/lp/app/javascript/picker/tests/test_personpicker.js 2012-06-26 00:18:26 +0000
@@ -3,7 +3,7 @@
33
4YUI().use('test', 'console', 'plugin',4YUI().use('test', 'console', 'plugin',
5 'lazr.picker', 'lazr.person-picker', 'lp.app.picker',5 'lazr.picker', 'lazr.person-picker', 'lp.app.picker',
6 'lp.app.mustache', 'node-event-simulate', function(Y) {6 'lp.testing.mockio', 'node-event-simulate', function(Y) {
77
8 var Assert = Y.Assert;8 var Assert = Y.Assert;
99
@@ -88,6 +88,10 @@
8888
89 tearDown: function() {89 tearDown: function() {
90 cleanup_widget(this.picker);90 cleanup_widget(this.picker);
91 var form_namespace = Y.namespace('lp.app.picker.teamform');
92 form_namespace.form_callbacks = null;
93 form_namespace.team_form = null;
94 delete this.mockio;
91 delete window.LP;95 delete window.LP;
92 },96 },
9397
@@ -325,6 +329,32 @@
325 Assert.isNull(Y.one('.yui-picker-new-team-button'));329 Assert.isNull(Y.one('.yui-picker-new-team-button'));
326 },330 },
327331
332 _simple_team_form: function() {
333 return '<table><tr><td></td>' +
334 '<input id="field.name">' +
335 '<input id="field.displayname"></td></tr></table>';
336 },
337
338 test_picker_new_team_xhr_calls: function() {
339 // Only one XHR call is made to fetch the team form even if more
340 // than one picker is used.
341 this.create_picker(this._picker_params(false, false, true));
342 var config = {
343 "io_provider": this.mockio,
344 "use_animation": false,
345 "picker_type": "person",
346 "show_create_team": true
347 };
348 var another = Y.lp.app.picker.addPickerPatcher(
349 this.vocabulary,
350 "foo/bar",
351 "test_link",
352 "anotherpicker_id",
353 config);
354 Y.Assert.areEqual(1, this.mockio.requests.length);
355 another.destroy();
356 },
357
328 test_picker_new_team_button_click_shows_form: function() {358 test_picker_new_team_button_click_shows_form: function() {
329 // Clicking the new team button displays the new team form.359 // Clicking the new team button displays the new team form.
330 this.create_picker(this._picker_params(true, true, true));360 this.create_picker(this._picker_params(true, true, true));
@@ -336,7 +366,8 @@
336 'Enter new team details',366 'Enter new team details',
337 this.picker.get('headerContent').get('text'));367 this.picker.get('headerContent').get('text'));
338 Y.Assert.isNotNull(368 Y.Assert.isNotNull(
339 this.picker.get('contentBox').one('[id=field.name]'));369 this.picker.get('contentBox')
370 .one('input[id=field.name]'));
340 Y.Assert.areEqual('none',371 Y.Assert.areEqual('none',
341 this.picker.get('contentBox').one('.yui3-widget-bd')372 this.picker.get('contentBox').one('.yui3-widget-bd')
342 .getStyle('display'));373 .getStyle('display'));
@@ -360,8 +391,9 @@
360 Y.Assert.areEqual(391 Y.Assert.areEqual(
361 'Pick Someone',392 'Pick Someone',
362 this.picker.get('headerContent').get('text'));393 this.picker.get('headerContent').get('text'));
363 Y.Assert.isNull(394 Y.Assert.isNotNull(
364 this.picker.get('contentBox').one('[id=field.name]'));395 this.picker.get('contentBox').one('input[id=field.name]')
396 .ancestor('div.hidden'));
365 Y.Assert.isNotNull(397 Y.Assert.isNotNull(
366 this.picker.get('contentBox').one('.yui3-picker-search'));398 this.picker.get('contentBox').one('.yui3-picker-search'));
367 },399 },
@@ -385,8 +417,8 @@
385 var new_team =417 var new_team =
386 picker_content.one('.yui-picker-new-team-button');418 picker_content.one('.yui-picker-new-team-button');
387 new_team.simulate('click');419 new_team.simulate('click');
388 var team_name = picker_content.one('[id=field.name]');420 var team_name = picker_content.one('input[id=field.name]');
389 Y.Node.getDOMNode(team_name).value = 'fred';421 team_name.set('value', 'fred');
390 var form_buttons = picker_content.one('.extra-form-buttons');422 var form_buttons = picker_content.one('.extra-form-buttons');
391 simulate(423 simulate(
392 form_buttons, 'button:nth-child(1)', 'click');424 form_buttons, 'button:nth-child(1)', 'click');
@@ -409,7 +441,9 @@
409 data_box.one('a').set('href', field_value);441 data_box.one('a').set('href', field_value);
410 }442 }
411443
444 this.mockio = new Y.lp.testing.mockio.MockIo();
412 var config = {445 var config = {
446 "io_provider": this.mockio,
413 "use_animation": false,447 "use_animation": false,
414 "picker_type": "person",448 "picker_type": "person",
415 "step_title": "Choose someone",449 "step_title": "Choose someone",
@@ -431,6 +465,14 @@
431 "test_link",465 "test_link",
432 "picker_id",466 "picker_id",
433 config);467 config);
468 if (params.show_create_team) {
469 Y.Assert.areEqual(
470 'file:////people/+newteam/++form++',
471 this.mockio.last_request.url);
472 this.mockio.success({
473 responseText: this._simple_team_form(),
474 responseHeaders: {'Content-Type': 'text/html'}});
475 }
434 }476 }
435 };477 };
436478
@@ -444,6 +486,9 @@
444486
445 tearDown: function() {487 tearDown: function() {
446 cleanup_widget(this.picker);488 cleanup_widget(this.picker);
489 var form_namespace = Y.namespace('lp.app.picker.teamform');
490 form_namespace.form_callbacks = null;
491 form_namespace.team_form = null;
447 this.search_input.remove();492 this.search_input.remove();
448 delete window.LP;493 delete window.LP;
449 },494 },
@@ -458,7 +503,10 @@
458 if (field_value !== undefined) {503 if (field_value !== undefined) {
459 text_field.set('text', field_value);504 text_field.set('text', field_value);
460 }505 }
506 this.mockio = new Y.lp.testing.mockio.MockIo();
461 var config = {507 var config = {
508 "io_provider": this.mockio,
509 "use_animation": false,
462 "picker_type": "person",510 "picker_type": "person",
463 "header": "Pick Someone",511 "header": "Pick Someone",
464 "associated_field_id": associated_field_id,512 "associated_field_id": associated_field_id,
@@ -473,6 +521,14 @@
473 };521 };
474 this.picker = Y.lp.app.picker.create(522 this.picker = Y.lp.app.picker.create(
475 this.vocabulary, config, associated_field_id);523 this.vocabulary, config, associated_field_id);
524 if (params.show_create_team) {
525 Y.Assert.areEqual(
526 'file:////people/+newteam/++form++',
527 this.mockio.last_request.url);
528 this.mockio.success({
529 responseText: this._simple_team_form(),
530 responseHeaders: {'Content-Type': 'text/html'}});
531 }
476 }532 }
477 };533 };
478534
479535
=== modified file 'lib/lp/app/javascript/picker/tests/test_picker_patcher.js'
--- lib/lp/app/javascript/picker/tests/test_picker_patcher.js 2012-04-06 17:28:25 +0000
+++ lib/lp/app/javascript/picker/tests/test_picker_patcher.js 2012-06-26 00:18:26 +0000
@@ -71,6 +71,7 @@
7171
72 create_picker: function(validate_callback, extra_config) {72 create_picker: function(validate_callback, extra_config) {
73 var config = {73 var config = {
74 "use_animation": false,
74 "step_title": "Choose someone",75 "step_title": "Choose someone",
75 "header": "Pick Someone",76 "header": "Pick Someone",
76 "null_display_value": "No one",77 "null_display_value": "No one",
@@ -96,7 +97,7 @@
96 create_picker_direct: function(associated_field) {97 create_picker_direct: function(associated_field) {
97 this.picker = Y.lp.app.picker.create(98 this.picker = Y.lp.app.picker.create(
98 this.vocabulary,99 this.vocabulary,
99 undefined,100 {use_animation: false},
100 associated_field);101 associated_field);
101 var self = this;102 var self = this;
102 this.picker.subscribe('save', function(e) {103 this.picker.subscribe('save', function(e) {
@@ -118,7 +119,8 @@
118 yesno_validate_callback: function(expected_value) {119 yesno_validate_callback: function(expected_value) {
119 return function(picker, value, save_fn, cancel_fn) {120 return function(picker, value, save_fn, cancel_fn) {
120 Assert.areEqual(121 Assert.areEqual(
121 expected_value, value.api_uri, "unexpected picker value");122 expected_value,
123 value.api_uri, "unexpected picker value");
122 if (value === null) {124 if (value === null) {
123 return true;125 return true;
124 }126 }
@@ -189,9 +191,10 @@
189 Assert.areEqual('message', footer_slot.get('text'));191 Assert.areEqual('message', footer_slot.get('text'));
190 },192 },
191193
192 test_footer_node_preserved_without_extra_no_results_message: function () {194 test_footer_node_preserved_without_extra_no_results_message:
193 // If "extra_no_results_message" is not defined, the footer slot node195 function () {
194 // should be preserved.196 // If "extra_no_results_message" is not defined, the footer slot
197 // node should be preserved.
195 this.create_picker();198 this.create_picker();
196 var footer_node = Y.Node.create("<span>foobar</span>");199 var footer_node = Y.Node.create("<span>foobar</span>");
197 this.picker.set('footer_slot', footer_node);200 this.picker.set('footer_slot', footer_node);
@@ -211,7 +214,8 @@
211 simulate(214 simulate(
212 this.picker.get('boundingBox').one('.yui3-picker-results'),215 this.picker.get('boundingBox').one('.yui3-picker-results'),
213 'li:nth-child(2)', 'click');216 'li:nth-child(2)', 'click');
214 var yesno = this.picker.get('contentBox').one('.extra-form-buttons');217 var yesno = this.picker.get('contentBox')
218 .one('.extra-form-buttons');
215219
216 simulate(220 simulate(
217 yesno, 'button:nth-child(1)', 'click');221 yesno, 'button:nth-child(1)', 'click');
@@ -232,7 +236,8 @@
232 simulate(236 simulate(
233 this.picker.get('boundingBox').one('.yui3-picker-results'),237 this.picker.get('boundingBox').one('.yui3-picker-results'),
234 'li:nth-child(2)', 'click');238 'li:nth-child(2)', 'click');
235 var yesno = this.picker.get('contentBox').one('.extra-form-buttons');239 var yesno = this.picker.get('contentBox')
240 .one('.extra-form-buttons');
236241
237 simulate(242 simulate(
238 yesno, 'button:nth-child(1)', 'click');243 yesno, 'button:nth-child(1)', 'click');
@@ -249,7 +254,8 @@
249 simulate(254 simulate(
250 this.picker.get('boundingBox').one('.yui3-picker-results'),255 this.picker.get('boundingBox').one('.yui3-picker-results'),
251 'li:nth-child(2)', 'click');256 'li:nth-child(2)', 'click');
252 var yesno = this.picker.get('contentBox').one('.extra-form-buttons');257 var yesno = this.picker.get('contentBox')
258 .one('.extra-form-buttons');
253 simulate(259 simulate(
254 yesno, 'button:nth-child(2)', 'click');260 yesno, 'button:nth-child(2)', 'click');
255 Assert.isNull(this.saved_picker_value);261 Assert.isNull(this.saved_picker_value);
@@ -260,7 +266,8 @@
260 simulate(266 simulate(
261 this.picker.get('boundingBox').one('.yui3-picker-results'),267 this.picker.get('boundingBox').one('.yui3-picker-results'),
262 'li:nth-child(2)', 'click');268 'li:nth-child(2)', 'click');
263 var yesno = this.picker.get('contentBox').one('.extra-form-buttons');269 var yesno = this.picker.get('contentBox')
270 .one('.extra-form-buttons');
264 // Click the Yes button.271 // Click the Yes button.
265 simulate(yesno, 'button:nth-child(1)', 'click');272 simulate(yesno, 'button:nth-child(1)', 'click');
266 yesno = this.picker.get('contentBox').one('.extra-form-buttons');273 yesno = this.picker.get('contentBox').one('.extra-form-buttons');
@@ -329,7 +336,8 @@
329 simulate(336 simulate(
330 this.picker.get('boundingBox').one('.yui3-picker-results'),337 this.picker.get('boundingBox').one('.yui3-picker-results'),
331 'li:nth-child(2)', 'click');338 'li:nth-child(2)', 'click');
332 var yesno = this.picker.get('contentBox').one('.extra-form-buttons');339 var yesno = this.picker.get('contentBox')
340 .one('.extra-form-buttons');
333 // Click the Yes button.341 // Click the Yes button.
334 simulate(yesno, 'button:nth-child(1)', 'click');342 simulate(yesno, 'button:nth-child(1)', 'click');
335 yesno = this.picker.get('contentBox').one('.extra-form-buttons');343 yesno = this.picker.get('contentBox').one('.extra-form-buttons');
@@ -339,8 +347,8 @@
339 },347 },
340348
341 test_connect_select_menu: function() {349 test_connect_select_menu: function() {
342 // connect_select_menu() connects the select menu's onchange event to350 // connect_select_menu() connects the select menu's onchange event
343 // copy the selected value to the text input field.351 // to copy the selected value to the text input field.
344 this.text_input = Y.Node.create(352 this.text_input = Y.Node.create(
345 '<input id="field.testfield" value="foo" />');353 '<input id="field.testfield" value="foo" />');
346 var node = Y.one(document.body).appendChild(this.text_input);354 var node = Y.one(document.body).appendChild(this.text_input);
@@ -390,7 +398,8 @@
390 'li:nth-child(2)', 'click');398 'li:nth-child(2)', 'click');
391 // expected_text is a little weird since breaks between p tags and399 // expected_text is a little weird since breaks between p tags and
392 // buttons are lost.400 // buttons are lost.
393 var expected_text = 'This action will reveal this team\'s name to ' +401 var expected_text =
402 'This action will reveal this team\'s name to ' +
394 'the public.ContinueChoose Again';403 'the public.ContinueChoose Again';
395 var text = Y.one(".validation-node").get('text');404 var text = Y.one(".validation-node").get('text');
396 Assert.areEqual(expected_text, text);405 Assert.areEqual(expected_text, text);
@@ -473,8 +482,9 @@
473 },482 },
474483
475 test_picker_displays_warning_by_default: function() {484 test_picker_displays_warning_by_default: function() {
476 // If show_search_box is not supplied in config, it defaults to true.485 // If show_search_box is not supplied in config, it defaults to
477 // Thus the picker will refuse to display more than 120 values.486 // true. Thus the picker will refuse to display more than 120
487 // values.
478 this.create_picker();488 this.create_picker();
479 this.picker.set('min_search_chars', 0);489 this.picker.set('min_search_chars', 0);
480 this.picker.fire('search', '');490 this.picker.fire('search', '');
@@ -536,9 +546,9 @@
536 this.mock_io.failure(546 this.mock_io.failure(
537 {responseHeaders: this.get_oops_headers('OOPS')});547 {responseHeaders: this.get_oops_headers('OOPS')});
538 Assert.areEqual(548 Assert.areEqual(
539 "Sorry, something went wrong with your search. We've recorded " +549 "Sorry, something went wrong with your search. " +
540 "what happened, and we'll fix it as soon as possible. " +550 "We've recorded what happened, and we'll fix it as soon " +
541 "(Error ID: OOPS)",551 "as possible. (Error ID: OOPS)",
542 this.picker.get('error'));552 this.picker.get('error'));
543 },553 },
544554
@@ -615,9 +625,10 @@
615 },625 },
616626
617 test_automated_search_error_ignored_if_user_has_searched: function() {627 test_automated_search_error_ignored_if_user_has_searched: function() {
618 // If an automated search (like loading branch suggestions) returns an628 // If an automated search (like loading branch suggestions) returns
619 // error and the user has submitted a search, then the error from the629 // an error and the user has submitted a search, then the error
620 // automated search is ignored so as not to confuse the user.630 // from the automated search is ignored so as not to confuse the
631 // user.
621 var mock_io = new Y.lp.testing.mockio.MockIo();632 var mock_io = new Y.lp.testing.mockio.MockIo();
622 var picker = this.create_picker(mock_io);633 var picker = this.create_picker(mock_io);
623 picker.fire('search', 'test');634 picker.fire('search', 'test');
@@ -629,7 +640,7 @@
629640
630 }));641 }));
631642
632}, '0.1', {'requires': ['test', 'console', 'lp.pickert', 'node', 'lp', 'lp.client',643}, '0.1', {'requires': ['test', 'console', 'lp.app.picker', 'node',
633 'event-focus', 'event-simulate', 'lazr.picker', 'lazr.person-picker',644 'event-focus', 'event-simulate', 'lazr.picker', 'lazr.person-picker',
634 'lp.app.picker', 'node-event-simulate', 'escape', 'event',645 'lp.app.picker', 'node-event-simulate', 'escape', 'event',
635 'lp.testing.mockio',]});646 'lp.testing.mockio', 'lp', 'lp.client']});
636647
=== modified file 'lib/lp/app/javascript/subscribers/subscribers_list.js'
--- lib/lp/app/javascript/subscribers/subscribers_list.js 2012-06-07 19:43:37 +0000
+++ lib/lp/app/javascript/subscribers/subscribers_list.js 2012-06-26 00:18:26 +0000
@@ -255,7 +255,7 @@
255 var loader = this;255 var loader = this;
256256
257 // Fetch the person and add a subscription.257 // Fetch the person and add a subscription.
258 function on_success(subscribers) {258 var on_success = function(subscribers) {
259 loader._loadSubscribersFromList(subscribers);259 loader._loadSubscribersFromList(subscribers);
260 // We may need to set up the subscribe me link.260 // We may need to set up the subscribe me link.
261 // This has to be done after subscribers have been loaded so that we261 // This has to be done after subscribers have been loaded so that we
@@ -264,7 +264,7 @@
264 loader._setupSubscribeMe();264 loader._setupSubscribeMe();
265 }265 }
266 loader.subscribers_list.stopActivity();266 loader.subscribers_list.stopActivity();
267 }267 };
268268
269 var config = { on: {269 var config = { on: {
270 success: on_success,270 success: on_success,
@@ -484,7 +484,7 @@
484 }484 }
485 var loader = this;485 var loader = this;
486486
487 function on_success() {487 var on_success = function() {
488 var unsubscribe_callback = loader._getUnsubscribeCallback();488 var unsubscribe_callback = loader._getUnsubscribeCallback();
489 if (update_subscribers_list) {489 if (update_subscribers_list) {
490 loader.subscribers_list.stopSubscriberActivity(subscriber, true);490 loader.subscribers_list.stopSubscriberActivity(subscriber, true);
@@ -502,8 +502,8 @@
502 };502 };
503 loader._updateSubscribeMeLink(true);503 loader._updateSubscribeMeLink(true);
504 }504 }
505 }505 };
506 function on_failure(t_id, response) {506 var on_failure = function(t_id, response) {
507 if (update_subscribers_list) {507 if (update_subscribers_list) {
508 loader.subscribers_list.stopSubscriberActivity(508 loader.subscribers_list.stopSubscriberActivity(
509 subscriber, false, function() {509 subscriber, false, function() {
@@ -524,7 +524,7 @@
524 false,524 false,
525 error_msg525 error_msg
526 );526 );
527 }527 };
528 var config = {528 var config = {
529 on: { success: on_success,529 on: { success: on_success,
530 failure: on_failure },530 failure: on_failure },
531531
=== modified file 'lib/lp/bugs/javascript/filebug_dupefinder.js'
--- lib/lp/bugs/javascript/filebug_dupefinder.js 2012-05-25 14:38:42 +0000
+++ lib/lp/bugs/javascript/filebug_dupefinder.js 2012-06-26 00:18:26 +0000
@@ -177,7 +177,7 @@
177 search_button.removeClass(UNSEEN);177 search_button.removeClass(UNSEEN);
178 }178 }
179179
180 function on_success(transaction_id, response, args) {180 var on_success = function(transaction_id, response, args) {
181 // Hide the spinner and show the duplicates.181 // Hide the spinner and show the duplicates.
182 Y.one('#spinner').addClass(UNSEEN);182 Y.one('#spinner').addClass(UNSEEN);
183183
@@ -216,7 +216,7 @@
216 // Finally, change the label on the search button and show it again.216 // Finally, change the label on the search button and show it again.
217 search_button.set('value', 'Check again');217 search_button.set('value', 'Check again');
218 search_button.removeClass(UNSEEN);218 search_button.removeClass(UNSEEN);
219 }219 };
220220
221 var search_term = encodeURI(search_field.get('value'));221 var search_term = encodeURI(search_field.get('value'));
222 var search_url = search_url_base + '?title=' + search_term;222 var search_url = search_url_base + '?title=' + search_term;
223223
=== modified file 'lib/lp/registry/javascript/sharing/shareepicker.js'
--- lib/lp/registry/javascript/sharing/shareepicker.js 2012-04-26 21:01:19 +0000
+++ lib/lp/registry/javascript/sharing/shareepicker.js 2012-06-26 00:18:26 +0000
@@ -29,10 +29,6 @@
29 },29 },
30 sharing_permissions: {30 sharing_permissions: {
31 value: []31 value: []
32 },
33 // Override for testing
34 anim_duration: {
35 value: 1
36 }32 }
37};33};
3834
@@ -77,26 +73,6 @@
77 });73 });
78 },74 },
7975
80 _fade_in: function(content_node, old_content) {
81 content_node.removeClass('unseen');
82 if (old_content === null) {
83 return;
84 }
85 old_content.addClass('unseen');
86 var anim_duration = this.get('anim_duration');
87 if (anim_duration === 0) {
88 return;
89 }
90 content_node.addClass('transparent');
91 content_node.setStyle('opacity', 0);
92 var fade_in = new Y.Anim({
93 node: content_node,
94 to: {opacity: 1},
95 duration: anim_duration
96 });
97 fade_in.run();
98 },
99
100 _display_step_one: function() {76 _display_step_one: function() {
101 this.set('headerContent', this.step_one_header);77 this.set('headerContent', this.step_one_header);
102 this.set(78 this.set(
10379
=== modified file 'lib/lp/registry/javascript/sharing/tests/test_shareepicker.js'
--- lib/lp/registry/javascript/sharing/tests/test_shareepicker.js 2012-04-26 21:01:19 +0000
+++ lib/lp/registry/javascript/sharing/tests/test_shareepicker.js 2012-06-26 00:18:26 +0000
@@ -54,7 +54,7 @@
5454
55 _create_picker: function(overrides) {55 _create_picker: function(overrides) {
56 var config = {56 var config = {
57 anim_duration: 0,57 use_animation: false,
58 progressbar: true,58 progressbar: true,
59 progress: 50,59 progress: 50,
60 headerContent: "<h2>Share with a user or team</h2>",60 headerContent: "<h2>Share with a user or team</h2>",
@@ -111,7 +111,7 @@
111 // The progress should be 75%111 // The progress should be 75%
112 Y.Assert.areEqual(75, this.picker.get('progress'));112 Y.Assert.areEqual(75, this.picker.get('progress'));
113 // The first step ui should be hidden.113 // The first step ui should be hidden.
114 Y.Assert.isTrue(cb.one('.yui3-widget-bd').hasClass('unseen'));114 Y.Assert.isTrue(cb.one('.yui3-widget-bd').hasClass('hidden'));
115 // The step title should be updated according to the selected115 // The step title should be updated according to the selected
116 // person. The title should remain unchanged.116 // person. The title should remain unchanged.
117 Y.Assert.areEqual(117 Y.Assert.areEqual(
@@ -122,7 +122,7 @@
122 'Select sharing policies for Fred', steptitle);122 'Select sharing policies for Fred', steptitle);
123 // The second step ui should be visible.123 // The second step ui should be visible.
124 var step_two_content = cb.one('.picker-content-two');124 var step_two_content = cb.one('.picker-content-two');
125 Y.Assert.isFalse(step_two_content.hasClass('unseen'));125 Y.Assert.isFalse(step_two_content.hasClass('hidden'));
126 // The second step ui should contain input buttons for each access126 // The second step ui should contain input buttons for each access
127 // policy type for each sharing permission.127 // policy type for each sharing permission.
128 Y.Array.each(this.information_types, function(info_type) {128 Y.Array.each(this.information_types, function(info_type) {
@@ -281,7 +281,7 @@
281 // The progress should be 50%281 // The progress should be 50%
282 Y.Assert.areEqual(50, this.picker.get('progress'));282 Y.Assert.areEqual(50, this.picker.get('progress'));
283 // The first step ui should be visible.283 // The first step ui should be visible.
284 Y.Assert.isFalse(cb.one('.yui3-widget-bd').hasClass('unseen'));284 Y.Assert.isFalse(cb.one('.yui3-widget-bd').hasClass('hidden'));
285 // The title and step title should be updated.285 // The title and step title should be updated.
286 Y.Assert.areEqual(286 Y.Assert.areEqual(
287 'Share with a user or team',287 'Share with a user or team',
@@ -291,7 +291,7 @@
291 'Search for user or exclusive team with whom to share',291 'Search for user or exclusive team with whom to share',
292 steptitle);292 steptitle);
293 // The second step ui should be hidden.293 // The second step ui should be hidden.
294 Y.Assert.isTrue(step_two_content.hasClass('unseen'));294 Y.Assert.isTrue(step_two_content.hasClass('hidden'));
295 },295 },
296296
297 // Test that a selection made in step two is correctly passed to the297 // Test that a selection made in step two is correctly passed to the