Merge lp:~wallyworld/launchpad/sharing-picker-title-959417 into lp:launchpad

Proposed by Ian Booth
Status: Merged
Approved by: Curtis Hovey
Approved revision: no longer in the source branch.
Merged at revision: 15030
Proposed branch: lp:~wallyworld/launchpad/sharing-picker-title-959417
Merge into: lp:launchpad
Diff against target: 314 lines (+136/-62)
2 files modified
lib/lp/registry/javascript/sharing/shareepicker.js (+78/-58)
lib/lp/registry/javascript/sharing/tests/test_shareepicker.js (+58/-4)
To merge this branch: bzr merge lp:~wallyworld/launchpad/sharing-picker-title-959417
Reviewer Review Type Date Requested Status
Curtis Hovey (community) code Approve
Review via email: mp+99459@code.launchpad.net

Commit message

Improve the title and step title displayed by the sharee picker and fix the re-selection of a sharee.

Description of the change

== Implementation ==

The branch fixes 2 issues with the sharee picker:
1. Improve title and step title
2. After selecting a sharee, if the Back button is used and a new sharee is selected, the old sharee was still being used.

The picker displays different text for title and step title depending on if a new sharee is being added or if an existing sharee is being updated.

New sharee:
Share with a user or team
Select sharing policies for Fred

Edit sharee:
Update sharing policies
Update sharing policies for Fred

A bit of refactoring was done to move the code to render the step 2 content to a separate method.

== Tests ==

Update test_shareepicker.js to test the new title/steptitle behaviour and add a new test for the sharee selection issue.

== Lint ==

Linting changed files:
  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
Curtis Hovey (sinzui) wrote :

thank you.

review: Approve (code)
Revision history for this message
pedro cavazos (aaacavazos) :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/registry/javascript/sharing/shareepicker.js'
2--- lib/lp/registry/javascript/sharing/shareepicker.js 2012-03-21 03:18:56 +0000
3+++ lib/lp/registry/javascript/sharing/shareepicker.js 2012-03-27 02:40:57 +0000
4@@ -52,6 +52,7 @@
5 }
6 this.set('information_types', information_types);
7 this.set('sharing_permissions', sharing_permissions);
8+ this.step_one_header = this.get('headerContent');
9 var self = this;
10 this.subscribe('save', function (e) {
11 e.halt();
12@@ -63,6 +64,8 @@
13 var data = e.details[Y.lazr.picker.Picker.SAVE_RESULT];
14 switch(step_nr) {
15 case 1:
16+ data.sharee_name = data.title;
17+ delete data.title;
18 self._display_step_two(data);
19 break;
20 case 2:
21@@ -95,6 +98,7 @@
22 },
23
24 _display_step_one: function() {
25+ this.set('headerContent', this.step_one_header);
26 this.set(
27 'steptitle',
28 'Search for user or exclusive team with whom to share');
29@@ -105,67 +109,79 @@
30 this._fade_in(step_one_content, step_two_content);
31 },
32
33+ _render_step_two: function(back_enabled, allowed_permissions) {
34+ var step_two_html = [
35+ '<div class="picker-content-two transparent">',
36+ '<div class="step-links">',
37+ '<a class="prev js-action" href="#">Back</a>',
38+ '<button class="next lazr-pos lazr-btn"></button>',
39+ '<a class="next js-action" href="#">Select</a>',
40+ '</div></div>'
41+ ].join(' ');
42+ var self = this;
43+ var step_two_content = Y.Node.create(step_two_html);
44+ // Remove the back link if required.
45+ if (Y.Lang.isBoolean(back_enabled) && !back_enabled ) {
46+ step_two_content.one('a.prev').remove(true);
47+ } else {
48+ step_two_content.one('a.prev').on('click', function(e) {
49+ e.halt();
50+ self._display_step_one();
51+ });
52+ }
53+ // By default, we only show All or Nothing.
54+ if (!Y.Lang.isValue(allowed_permissions)) {
55+ allowed_permissions = ['ALL', 'NOTHING'];
56+ }
57+ var sharing_permissions = [];
58+ Y.Array.each(this.get('sharing_permissions'),
59+ function(permission) {
60+ if (Y.Array.indexOf(
61+ allowed_permissions, permission.value) >=0) {
62+ sharing_permissions.push(permission);
63+ }
64+ });
65+ var policy_selector = self._make_policy_selector(sharing_permissions);
66+ step_two_content.one('div.step-links')
67+ .insert(policy_selector, 'before');
68+ step_two_content.all('input[name^=field.permission]')
69+ .on('click', function(e) {
70+ self._disable_select_if_all_info_choices_nothing(step_two_content);
71+ });
72+ return step_two_content;
73+ },
74+
75 _display_step_two: function(data) {
76- var title = Y.Lang.substitute('Select sharing policies for {name}',
77- {name: data.title});
78- this.set('steptitle', title);
79+ if (Y.Lang.isValue(data.title)) {
80+ this.set(
81+ 'headerContent',
82+ Y.Node.create('<h2></h2>').set('text', data.title));
83+ }
84+ var steptitle = data.steptitle;
85+ if (!Y.Lang.isValue(steptitle)) {
86+ steptitle = Y.Lang.substitute(
87+ 'Select sharing policies for {name}',
88+ {name: data.sharee_name});
89+ }
90+ this.set('steptitle', steptitle);
91 this.set('progress', 75);
92 var contentBox = this.get('contentBox');
93 var step_one_content = contentBox.one('.yui3-widget-bd');
94 var step_two_content = contentBox.one('.picker-content-two');
95 if (step_two_content === null) {
96- var step_two_html = [
97- '<div class="picker-content-two transparent">',
98- '<div class="step-links">',
99- '<a class="prev js-action" href="#">Back</a>',
100- '<button class="next lazr-pos lazr-btn"></button>',
101- '<a class="next js-action" href="#">Select</a>',
102- '</div></div>'
103- ].join(' ');
104- step_two_content = Y.Node.create(step_two_html);
105- var self = this;
106- // Remove the back link if required.
107- if (Y.Lang.isBoolean(data.back_enabled)
108- && !data.back_enabled ) {
109- step_two_content.one('a.prev').remove(true);
110- } else {
111- step_two_content.one('a.prev').on('click', function(e) {
112- e.halt();
113- self._display_step_one();
114- });
115- }
116- // Wire up the next (ie submit) links.
117- step_two_content.all('.next').on('click', function(e) {
118- e.halt();
119- // Only submit if at least one info type is selected.
120- if (!self._all_info_choices_unticked(step_two_content)) {
121- self.fire('save', data, 2);
122- }
123- });
124- // By default, we only show All or Nothing.
125- var allowed_permissions = ['ALL', 'NOTHING'];
126- if (Y.Lang.isValue(data.allowed_permissions)) {
127- allowed_permissions = data.allowed_permissions;
128- }
129- var sharing_permissions = [];
130- Y.Array.each(this.get('sharing_permissions'),
131- function(permission) {
132- if (Y.Array.indexOf(
133- allowed_permissions, permission.value) >=0) {
134- sharing_permissions.push(permission);
135- }
136- });
137- var policy_selector = self._make_policy_selector(
138- sharing_permissions);
139- step_two_content.one('div.step-links')
140- .insert(policy_selector, 'before');
141+ step_two_content = this._render_step_two(
142+ data.back_enabled, data.allowed_permissions);
143 step_one_content.insert(step_two_content, 'after');
144- step_two_content.all('input[name^=field.permission]')
145- .on('click', function(e) {
146- self._disable_select_if_all_info_choices_unticked(
147- step_two_content);
148- });
149 }
150+ // Wire up the next (ie submit) links.
151+ step_two_content.detach('click');
152+ step_two_content.delegate('click', function(e) {
153+ e.halt();
154+ // Only submit if at least one info type is selected.
155+ if (!this._all_info_choices_nothing(step_two_content)) {
156+ this.fire('save', data, 2);
157+ }
158+ }, '.next', this);
159 // Initially set all radio buttons to Nothing.
160 step_two_content.all('input[name^=field.permission][value=NOTHING]')
161 .each(function(radio_button) {
162@@ -183,7 +199,7 @@
163 }
164 });
165 }
166- this._disable_select_if_all_info_choices_unticked(step_two_content);
167+ this._disable_select_if_all_info_choices_nothing(step_two_content);
168 this._fade_in(step_two_content, step_one_content);
169 },
170
171@@ -193,7 +209,7 @@
172 * @return {Boolean}
173 * @private
174 */
175- _all_info_choices_unticked: function(content) {
176+ _all_info_choices_nothing: function(content) {
177 var all_unticked = true;
178 content.all('input[name^=field.permission]')
179 .each(function(info_node) {
180@@ -209,8 +225,8 @@
181 * @param content
182 * @private
183 */
184- _disable_select_if_all_info_choices_unticked: function(content) {
185- var disable_links = this._all_info_choices_unticked(content);
186+ _disable_select_if_all_info_choices_nothing: function(content) {
187+ var disable_links = this._all_info_choices_nothing(content);
188 content.all('.next').each(function(node) {
189 if (disable_links) {
190 node.addClass('invalid-link');
191@@ -328,8 +344,12 @@
192 }
193 switch (config.first_step) {
194 case 2:
195+ var steptitle = Y.Lang.substitute(
196+ 'Update sharing policies for {name}',
197+ {name: config.sharee.person_name});
198 var data = {
199- title: config.sharee.person_name,
200+ title: 'Update sharing policies',
201+ steptitle: steptitle,
202 api_uri: config.sharee.person_uri,
203 sharee_permissions: config.sharee_permissions,
204 allowed_permissions: config.allowed_permissions,
205
206=== modified file 'lib/lp/registry/javascript/sharing/tests/test_shareepicker.js'
207--- lib/lp/registry/javascript/sharing/tests/test_shareepicker.js 2012-03-21 03:18:56 +0000
208+++ lib/lp/registry/javascript/sharing/tests/test_shareepicker.js 2012-03-27 02:40:57 +0000
209@@ -57,7 +57,7 @@
210 anim_duration: 0,
211 progressbar: true,
212 progress: 50,
213- headerContent: "<h2>Grant access</h2>",
214+ headerContent: "<h2>Share with a user or team</h2>",
215 steptitle: "Search for user or exclusive team " +
216 "with whom to share",
217 zIndex: 1000,
218@@ -96,6 +96,9 @@
219 this.picker.set('results', this.vocabulary);
220 this.picker.render();
221 var cb = this.picker.get('contentBox');
222+ Y.Assert.areEqual(
223+ 'Share with a user or team',
224+ this.picker.get('headerContent').get('text'));
225 var steptitle = cb.one('.contains-steptitle h2').getContent();
226 Y.Assert.areEqual(
227 'Search for user or exclusive team with whom to share',
228@@ -110,7 +113,10 @@
229 // The first step ui should be hidden.
230 Y.Assert.isTrue(cb.one('.yui3-widget-bd').hasClass('unseen'));
231 // The step title should be updated according to the selected
232- // person.
233+ // person. The title should remain unchanged.
234+ Y.Assert.areEqual(
235+ 'Share with a user or team',
236+ this.picker.get('headerContent').get('text'));
237 steptitle = cb.one('.contains-steptitle h2').getContent();
238 Y.Assert.areEqual(
239 'Select sharing policies for Fred', steptitle);
240@@ -172,9 +178,13 @@
241 sharee_permissions: {'P1': 'ALL'}
242 });
243 var cb = this.picker.get('contentBox');
244+ // Check the title and step title are correct.
245 var steptitle = cb.one('.contains-steptitle h2').getContent();
246 Y.Assert.areEqual(
247- 'Select sharing policies for Fred', steptitle);
248+ 'Update sharing policies',
249+ this.picker.get('headerContent').get('text'));
250+ Y.Assert.areEqual(
251+ 'Update sharing policies for Fred', steptitle);
252 // By default, selections only for ALL and NOTHING are available
253 // (and no others).
254 Y.Assert.isNotNull(cb.one('input[value=ALL]'));
255@@ -244,7 +254,10 @@
256 Y.Assert.areEqual(50, this.picker.get('progress'));
257 // The first step ui should be visible.
258 Y.Assert.isFalse(cb.one('.yui3-widget-bd').hasClass('unseen'));
259- // The step title should be updated.
260+ // The title and step title should be updated.
261+ Y.Assert.areEqual(
262+ 'Share with a user or team',
263+ this.picker.get('headerContent').get('text'));
264 var steptitle = cb.one('.contains-steptitle h2').getContent();
265 Y.Assert.areEqual(
266 'Search for user or exclusive team with whom to share',
267@@ -288,6 +301,47 @@
268 Y.Assert.areEqual('~/fred', selected_result.api_uri);
269 },
270
271+ // Test that a new sharee can be selected after click the Back button
272+ // and the new sharee is correctly used in the final result.
273+ test_sharee_reselection: function() {
274+ var selected_result;
275+ this.picker = this._create_picker(
276+ {
277+ save: function(result) {
278+ selected_result = result;
279+ }
280+ }
281+ );
282+ // Select a person to trigger transition to next step.
283+ this.picker.set('results', this.vocabulary);
284+ this.picker.render();
285+ this.picker.get('boundingBox').one(
286+ '.yui3-picker-results li:nth-child(1)').simulate('click');
287+ var cb = this.picker.get('contentBox');
288+ var step_two_content = cb.one('.picker-content-two');
289+ var back_link = step_two_content.one('a.prev');
290+ back_link.simulate('click');
291+ // Select a different person.
292+ this.picker.get('boundingBox').one(
293+ '.yui3-picker-results li:nth-child(2)').simulate('click');
294+ // Select an access policy.
295+ step_two_content
296+ .one('input[name=field.permission.P2][value="ALL"]')
297+ .simulate('click');
298+ var select_link = step_two_content.one('a.next');
299+ select_link.simulate('click');
300+ // Check the results.
301+ Y.Assert.areEqual(
302+ 3, Y.Object.size(selected_result.selected_permissions));
303+ Y.Assert.areEqual(
304+ selected_result.selected_permissions.P1, 'NOTHING');
305+ Y.Assert.areEqual(
306+ selected_result.selected_permissions.P2, 'ALL');
307+ Y.Assert.areEqual(
308+ selected_result.selected_permissions.P3, 'NOTHING');
309+ Y.Assert.areEqual('~/frieda', selected_result.api_uri);
310+ },
311+
312 // When no info types are selected, the Submit links are disabled.
313 test_no_selected_info_types: function() {
314 var save_called = false;