Merge lp:~wallyworld/launchpad/branch-infotype-portlet2-1040999 into lp:launchpad

Proposed by Ian Booth on 2012-08-28
Status: Merged
Approved by: Ian Booth on 2012-08-29
Approved revision: no longer in the source branch.
Merged at revision: 15875
Proposed branch: lp:~wallyworld/launchpad/branch-infotype-portlet2-1040999
Merge into: lp:launchpad
Prerequisite: lp:~wallyworld/launchpad/branch-infotype-portlet-1040999
Diff against target: 730 lines (+516/-72)
9 files modified
lib/lp/app/javascript/information_type.js (+83/-0)
lib/lp/bugs/javascript/information_type_choice.js (+17/-69)
lib/lp/bugs/javascript/tests/test_information_type_choice.html (+2/-0)
lib/lp/bugs/javascript/tests/test_information_type_choice.js (+2/-2)
lib/lp/code/browser/branch.py (+1/-1)
lib/lp/code/javascript/branch.information_type_choice.js (+122/-0)
lib/lp/code/javascript/tests/test_information_type_choice.html (+96/-0)
lib/lp/code/javascript/tests/test_information_type_choice.js (+179/-0)
lib/lp/code/templates/branch-portlet-privacy.pt (+14/-0)
To merge this branch: bzr merge lp:~wallyworld/launchpad/branch-infotype-portlet2-1040999
Reviewer Review Type Date Requested Status
Richard Harding (community) 2012-08-28 Approve on 2012-08-28
Review via email: mp+121527@code.launchpad.net

Commit Message

Add javascript widget to edit branch information type, refactor out common code.

Description of the Change

== Implementation ==

This branch adds the javascript code to provide a popup choice widget for editing branch information type.
There is already similar functionality for editing bug info type, so common code was pulled out and put in a common module which both import and use.

== Tests ==

Add new yui tests for branch info type widget, update existing yui tests for bug info type widget.

== Lint ==

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/app/javascript/information_type.js
  lib/lp/bugs/javascript/information_type_choice.js
  lib/lp/bugs/javascript/tests/test_information_type_choice.html
  lib/lp/bugs/javascript/tests/test_information_type_choice.js
  lib/lp/code/javascript/branch.information_type_choice.js
  lib/lp/code/javascript/tests/test_information_type_choice.html
  lib/lp/code/javascript/tests/test_information_type_choice.js
  lib/lp/code/templates/branch-portlet-privacy.pt

To post a comment you must log in.
Richard Harding (rharding) wrote :

Just a quick comment in looking over things. It would be best if the banner, portlet, and the actual change widget all communicated via an event vs direct calls. The widget should just fire a 'privacy_value_change' event that the banner and portlet can listen to and respond as required. In this way you're not tied to having these exact parts in place and code couple possibly be shared more from bug/code uses. Any data needed can be passed into the event as misc data.

Ian Booth (wallyworld) wrote :

> Just a quick comment in looking over things. It would be best if the banner,
> portlet, and the actual change widget all communicated via an event vs direct
> calls. The widget should just fire a 'privacy_value_change' event that the
> banner and portlet can listen to and respond as required. In this way you're
> not tied to having these exact parts in place and code couple possibly be
> shared more from bug/code uses. Any data needed can be passed into the event
> as misc data.

Yes, agree. The common functionality is factored out into a separate module in this branch. The decoupling using events can happen later though since this branch is large enough already and is simply building on what was there previously.

Richard Harding (rharding) wrote :

#30
Are there better names we can use than key, key_name? I'm not sure how they're supposed to be different. I see later that you're giving it a key in the cache to find the data. How about cache_key and then type_name, type_value?

#307
You don't need to call the superclass for renderUI. It's meant to be implemented by your class.

http://yuilibrary.com/yui/docs/api/files/widget_js_Widget.js.html#l623

#333
Same for bindUI

http://yuilibrary.com/yui/docs/api/files/widget_js_Widget.js.html#l612

#335
Can you just move the check for the privacy_link node into the initializer() of the class and set an attribute that's a kill switch. Then all the code should just check its own ATTR

if this.get('enabled')

or something. One method is checking for a node to determine if it should run, the next method then starts checking things the previous one creates and it's a bit of a stack of cards.

review: Approve
Ian Booth (wallyworld) wrote :

Thanks Rick.

> #30
> Are there better names we can use than key, key_name? I'm not sure how they're
> supposed to be different. I see later that you're giving it a key in the cache
> to find the data. How about cache_key and then type_name, type_value?
>

The names made sense to me :-)
I'll look at renaming.

>
> #335
> Can you just move the check for the privacy_link node into the initializer()
> of the class and set an attribute that's a kill switch. Then all the code
> should just check its own ATTR
>
> if this.get('enabled')
>
> or something. One method is checking for a node to determine if it should run,
> the next method then starts checking things the previous one creates and it's
> a bit of a stack of cards.

Sure. Will do that.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'lib/lp/app/javascript/information_type.js'
2--- lib/lp/app/javascript/information_type.js 1970-01-01 00:00:00 +0000
3+++ lib/lp/app/javascript/information_type.js 2012-08-29 04:50:32 +0000
4@@ -0,0 +1,83 @@
5+/* Copyright 2012 Canonical Ltd. This software is licensed under the
6+ * GNU Affero General Public License version 3 (see the file LICENSE).
7+ *
8+ * Base functionality for displaying Information Type data.
9+ */
10+
11+YUI.add('lp.app.information_type', function(Y) {
12+
13+var namespace = Y.namespace('lp.app.information_type');
14+
15+var get_information_type_banner_text = function(value) {
16+ var text_template = "This page contains {info_type} information.";
17+ var info_type = namespace.information_type_value_from_key(
18+ value, 'value', 'name');
19+ return Y.Lang.sub(text_template, {'info_type': info_type});
20+};
21+
22+/**
23+ * Lookup the information_type property, keyed on the named value.
24+ *
25+ * @param cache_key_value the key value to lookup
26+ * @param key_property_name the key property name used to access the key value
27+ * @param value_property_name the value property name
28+ * @return {*}
29+ */
30+namespace.information_type_value_from_key = function(cache_key_value,
31+ key_property_name,
32+ value_property_name) {
33+ var data = null;
34+ Y.Array.some(LP.cache.information_type_data, function(info_type) {
35+ if (info_type[key_property_name] === cache_key_value) {
36+ data = info_type[value_property_name];
37+ return true;
38+ }
39+ return false;
40+ });
41+ return data;
42+};
43+
44+/**
45+ * Update the privacy portlet to display the specified information type value.
46+ *
47+ * @param value
48+ */
49+namespace.update_privacy_portlet = function(value) {
50+ var description = namespace.information_type_value_from_key(
51+ value, 'value', 'description');
52+ var desc_node = Y.one('#information-type-description');
53+ if (Y.Lang.isValue(desc_node)) {
54+ desc_node.set('text', description);
55+ }
56+ var summary = Y.one('#information-type-summary');
57+ var private_type =
58+ Y.Array.indexOf(LP.cache.private_types, value) >= 0;
59+ if (private_type) {
60+ summary.replaceClass('public', 'private');
61+ } else {
62+ summary.replaceClass('private', 'public');
63+ }
64+};
65+
66+/**
67+ * Update the privacy banner to display the specified information type value.
68+ *
69+ * @param value
70+ */
71+namespace.update_privacy_banner = function(value) {
72+ var body = Y.one('body');
73+ var privacy_banner = Y.lp.app.banner.privacy.getPrivacyBanner();
74+ var private_type =
75+ Y.Array.indexOf(LP.cache.private_types, value) >= 0;
76+ if (private_type) {
77+ body.replaceClass('public', 'private');
78+ var banner_text = get_information_type_banner_text(value);
79+ privacy_banner.updateText(banner_text);
80+ privacy_banner.show();
81+ } else {
82+ body.replaceClass('private', 'public');
83+ privacy_banner.hide();
84+ }
85+};
86+
87+}, "0.1", {"requires": ["base", "oop", "node", "lp.app.banner.privacy"]});
88
89=== modified file 'lib/lp/bugs/javascript/information_type_choice.js'
90--- lib/lp/bugs/javascript/information_type_choice.js 2012-08-24 12:49:00 +0000
91+++ lib/lp/bugs/javascript/information_type_choice.js 2012-08-29 04:50:32 +0000
92@@ -7,30 +7,12 @@
93 YUI.add('lp.bugs.information_type_choice', function(Y) {
94
95 var namespace = Y.namespace('lp.bugs.information_type_choice');
96+var information_type = Y.namespace('lp.app.information_type');
97
98 // For testing.
99 var skip_animation = false;
100
101 /**
102- * Lookup the information_type property, keyed on the named value.
103- * @param key the key to lookup
104- * @param key_name the key property name
105- * @param value_name the value property_name
106- * @return {*}
107- */
108-var information_type_value_from_key = function(key, key_name,
109- value_name) {
110- var data = null;
111- Y.Array.some(LP.cache.information_type_data, function(info_type) {
112- if (info_type[key_name] === key) {
113- data = info_type[value_name];
114- return true;
115- }
116- });
117- return data;
118-};
119-
120-/**
121 * Save the new information type. If validate_change is true, then a check
122 * will be done to ensure the bug will not become invisible. If the bug will
123 * become invisible, a confirmation popup is used to confirm the user's
124@@ -57,11 +39,11 @@
125 widget, initial_value, lp_client);
126 return true;
127 }
128- var orig_value = information_type_value_from_key(
129+ var orig_value = information_type.information_type_value_from_key(
130 LP.cache.bug.information_type, 'name', 'value');
131 widget.set('value', orig_value);
132 widget._showFailed();
133- update_privacy_portlet(orig_value);
134+ information_type.update_privacy_portlet(orig_value);
135 return false;
136 };
137 var submit_url = document.URL + "/+secrecy";
138@@ -101,49 +83,13 @@
139 lp_client.io_provider.io(submit_url, config);
140 };
141
142-var update_privacy_portlet = function(value) {
143- var description = information_type_value_from_key(
144- value, 'value', 'description');
145- var desc_node = Y.one('#information-type-description');
146- if (Y.Lang.isValue(desc_node)) {
147- desc_node.set('text', description);
148- }
149- var summary = Y.one('#information-type-summary');
150- var private_type = (Y.Array.indexOf(LP.cache.private_types, value) >= 0);
151- if (private_type) {
152- summary.replaceClass('public', 'private');
153- } else {
154- summary.replaceClass('private', 'public');
155- }
156-};
157-
158-var update_privacy_banner = function(value) {
159- var body = Y.one('body');
160- var privacy_banner = Y.lp.app.banner.privacy.getPrivacyBanner();
161- var private_type = (Y.Array.indexOf(LP.cache.private_types, value) >= 0);
162- if (private_type) {
163- body.replaceClass('public', 'private');
164- var banner_text = namespace.get_information_type_banner_text(value);
165- privacy_banner.updateText(banner_text);
166- privacy_banner.show();
167- } else {
168- body.replaceClass('private', 'public');
169- privacy_banner.hide();
170- }
171-};
172-
173-namespace.get_information_type_banner_text = function(value) {
174- var text_template = "This page contains {info_type} information.";
175- var info_type = information_type_value_from_key(value, 'value', 'name');
176- return Y.Lang.substitute(text_template, {'info_type': info_type});
177-};
178-
179 namespace.information_type_save_success = function(widget, value,
180 subscribers_list,
181 subscribers_data) {
182 LP.cache.bug.information_type =
183- information_type_value_from_key(value, 'value', 'name');
184- update_privacy_banner(value);
185+ information_type.information_type_value_from_key(
186+ value, 'value', 'name');
187+ information_type.update_privacy_banner(value);
188 widget._showSucceeded();
189 if (Y.Lang.isObject(subscribers_data)) {
190 var subscribers = subscribers_data.subscription_data;
191@@ -174,7 +120,7 @@
192 lp_client) {
193 var value = widget.get('value');
194 var do_save = function() {
195- update_privacy_portlet(value);
196+ information_type.update_privacy_portlet(value);
197 namespace.save_information_type(
198 widget, initial_value, value, lp_client, false);
199 };
200@@ -182,7 +128,7 @@
201 // change while the confirmation dialog is showing.
202 var new_value = widget.get('value');
203 widget.set('value', initial_value);
204- update_privacy_portlet(initial_value);
205+ information_type.update_privacy_portlet(initial_value);
206 var confirm_text_template = [
207 '<p class="block-sprite large-warning">',
208 ' You are about to mark this bug as ',
209@@ -193,13 +139,14 @@
210 ' <strong>Please confirm you really want to do this.</strong>',
211 '</p>'
212 ].join('');
213- var title = information_type_value_from_key(value, 'value', 'name');
214+ var title = information_type.information_type_value_from_key(
215+ value, 'value', 'name');
216 var confirm_text = Y.Lang.sub(confirm_text_template,
217 {information_type: title});
218 var co = new Y.lp.app.confirmationoverlay.ConfirmationOverlay({
219 submit_fn: function() {
220 widget.set('value', new_value);
221- update_privacy_portlet(new_value);
222+ information_type.update_privacy_portlet(new_value);
223 do_save();
224 },
225 form_content: confirm_text,
226@@ -211,13 +158,13 @@
227 namespace.setup_information_type_choice = function(privacy_link, lp_client,
228 skip_anim) {
229 skip_animation = skip_anim;
230- var initial_value = information_type_value_from_key(
231+ var initial_value = information_type.information_type_value_from_key(
232 LP.cache.bug.information_type, 'name', 'value');
233- var information_type = Y.one('#information-type');
234+ var information_type_value = Y.one('#information-type');
235 var information_type_edit = new Y.ChoiceSource({
236 editicon: privacy_link,
237 contentBox: Y.one('#privacy'),
238- value_location: information_type,
239+ value_location: information_type_value,
240 value: initial_value,
241 title: "Change information type",
242 items: LP.cache.information_type_data,
243@@ -228,7 +175,7 @@
244 information_type_edit.render();
245 information_type_edit.on("save", function(e) {
246 var value = information_type_edit.get('value');
247- update_privacy_portlet(value);
248+ information_type.update_privacy_portlet(value);
249 namespace.save_information_type(
250 information_type_edit, initial_value, value, lp_client, true);
251
252@@ -238,4 +185,5 @@
253 };
254 }, "0.1", {"requires": ["base", "oop", "node", "event", "io-base",
255 "lazr.choiceedit", "lp.bugs.bugtask_index",
256- "lp.app.banner.privacy", "lp.app.choice"]});
257+ "lp.app.banner.privacy", "lp.app.choice",
258+ "lp.app.information_type"]});
259
260=== modified file 'lib/lp/bugs/javascript/tests/test_information_type_choice.html'
261--- lib/lp/bugs/javascript/tests/test_information_type_choice.html 2012-07-03 07:06:48 +0000
262+++ lib/lp/bugs/javascript/tests/test_information_type_choice.html 2012-08-29 04:50:32 +0000
263@@ -30,6 +30,8 @@
264 <script type="text/javascript"
265 src="../../../../../build/js/lp/app/choice.js"></script>
266 <script type="text/javascript"
267+ src="../../../../../build/js/lp/app/information_type.js"></script>
268+ <script type="text/javascript"
269 src="../../../../../build/js/lp/app/testing/mockio.js"></script>
270 <script type="text/javascript"
271 src="../../../../../build/js/lp/app/client.js"></script>
272
273=== modified file 'lib/lp/bugs/javascript/tests/test_information_type_choice.js'
274--- lib/lp/bugs/javascript/tests/test_information_type_choice.js 2012-08-24 12:49:00 +0000
275+++ lib/lp/bugs/javascript/tests/test_information_type_choice.js 2012-08-29 04:50:32 +0000
276@@ -304,5 +304,5 @@
277 }));
278
279 }, '0.1', {'requires': ['test', 'console', 'event', 'node-event-simulate',
280- 'lp.testing.mockio', 'lp.client','lp.bugs.subscribers',
281- 'lp.bugs.information_type_choice']});
282+ 'lp.testing.mockio', 'lp.client', 'lp.app.informatin_type',
283+ 'lp.bugs.information_type_choice', 'lp.bugs.subscribers']});
284
285=== modified file 'lib/lp/code/browser/branch.py'
286--- lib/lp/code/browser/branch.py 2012-08-29 04:50:31 +0000
287+++ lib/lp/code/browser/branch.py 2012-08-29 04:50:32 +0000
288@@ -737,7 +737,7 @@
289 # If we're stacked on a private branch, only show that
290 # information type.
291 if self.context.stacked_on and self.context.stacked_on.private:
292- shown_types = {self.context.stacked_on.information_type}
293+ shown_types = set([self.context.stacked_on.information_type])
294 else:
295 shown_types = (
296 InformationType.PUBLIC,
297
298=== added file 'lib/lp/code/javascript/branch.information_type_choice.js'
299--- lib/lp/code/javascript/branch.information_type_choice.js 1970-01-01 00:00:00 +0000
300+++ lib/lp/code/javascript/branch.information_type_choice.js 2012-08-29 04:50:32 +0000
301@@ -0,0 +1,122 @@
302+/* Copyright 2012 Canonical Ltd. This software is licensed under the
303+ * GNU Affero General Public License version 3 (see the file LICENSE).
304+ *
305+ * Information Type choice widget for branch pages.
306+ */
307+
308+YUI.add('lp.code.branch.information_type_choice', function(Y) {
309+
310+var namespace = Y.namespace('lp.code.branch.information_type_choice');
311+var information_type = Y.namespace('lp.app.information_type');
312+var superclass = Y.Widget;
313+
314+namespace.BranchInformationTypeWidget = Y.Base.create(
315+ "branchInformationTypeWidget", Y.Widget, [], {
316+ initializer: function(cfg) {
317+ this.lp_client = new Y.lp.client.Launchpad(cfg);
318+ this.privacy_link = Y.one('#privacy-link');
319+ },
320+
321+ renderUI: function() {
322+ // If user doesn't have permission, no link, nothing to do.
323+ if (!Y.Lang.isValue(this.privacy_link)) {
324+ return;
325+ }
326+ var initial_value = information_type.information_type_value_from_key(
327+ LP.cache.context.information_type, 'name', 'value');
328+ var information_type_value = Y.one('#information-type');
329+ this.information_type_edit = new Y.ChoiceSource({
330+ editicon: this.privacy_link,
331+ contentBox: Y.one('#privacy'),
332+ value_location: information_type_value,
333+ value: initial_value,
334+ title: "Change information type",
335+ items: LP.cache.information_type_data,
336+ backgroundColor: '#FFFF99',
337+ flashEnabled: false
338+ });
339+ Y.lp.app.choice.hook_up_choicesource_spinner(
340+ this.information_type_edit);
341+ this.information_type_edit.render();
342+ this.privacy_link.addClass('js-action');
343+ },
344+
345+ bindUI: function() {
346+ // If user doesn't have permission, no link, nothing to do.
347+ if (!Y.Lang.isValue(this.privacy_link)) {
348+ return;
349+ }
350+ var that = this;
351+ this.information_type_edit.on("save", function(e) {
352+ var value = that.information_type_edit.get('value');
353+ information_type.update_privacy_portlet(value);
354+ that._save_information_type(value);
355+
356+ });
357+ },
358+
359+ _save_information_type: function(value) {
360+ var that = this;
361+ var widget = this.information_type_edit;
362+ var error_handler = new Y.lp.client.FormErrorHandler();
363+ error_handler.showError = function(error_msg) {
364+ Y.lp.app.errors.display_error(
365+ Y.one('#information-type'), error_msg);
366+ };
367+ error_handler.handleError = function() {
368+ var orig_value = information_type.information_type_value_from_key(
369+ LP.cache.context.information_type, 'name', 'value');
370+ widget.set('value', orig_value);
371+ if (that.get('use_animation')) {
372+ widget._showFailed();
373+ }
374+ information_type.update_privacy_portlet(orig_value);
375+ return false;
376+ };
377+ var submit_url = document.URL + "/+edit-information-type";
378+ var qs = Y.lp.client.append_qs(
379+ '', 'field.actions.change', 'Change Branch');
380+ qs = Y.lp.client.append_qs(qs, 'field.information_type', value);
381+ var config = {
382+ method: "POST",
383+ headers: {'Accept': 'application/xhtml;application/json'},
384+ data: qs,
385+ on: {
386+ start: function () {
387+ widget._uiSetWaiting();
388+ },
389+ end: function () {
390+ widget._uiClearWaiting();
391+ },
392+ success: function (id, response) {
393+ that._information_type_save_success(value);
394+ Y.lp.client.display_notifications(
395+ response.getResponseHeader('X-Lazr-Notifications'));
396+ },
397+ failure: error_handler.getFailureHandler()
398+ }
399+ };
400+ this.lp_client.io_provider.io(submit_url, config);
401+ },
402+
403+ _information_type_save_success: function(value) {
404+ LP.cache.context.information_type =
405+ information_type.information_type_value_from_key(
406+ value, 'value', 'name');
407+ information_type.update_privacy_banner(value);
408+ if (this.get('use_animation')) {
409+ this.information_type_edit._showSucceeded();
410+ }
411+ }
412+}, {
413+ ATTRS: {
414+ // For testing
415+ use_animation: {
416+ value: true
417+ }
418+ }
419+});
420+
421+}, "0.1", {"requires": ["base", "oop", "node", "event", "io-base",
422+ "lazr.choiceedit", "lp.app.banner.privacy",
423+ "lp.app.choice", "lp.app.information_type"]});
424
425=== added file 'lib/lp/code/javascript/tests/test_information_type_choice.html'
426--- lib/lp/code/javascript/tests/test_information_type_choice.html 1970-01-01 00:00:00 +0000
427+++ lib/lp/code/javascript/tests/test_information_type_choice.html 2012-08-29 04:50:32 +0000
428@@ -0,0 +1,96 @@
429+<!DOCTYPE html>
430+<!--
431+Copyright 2012 Canonical Ltd. This software is licensed under the
432+GNU Affero General Public License version 3 (see the file LICENSE).
433+-->
434+
435+<html>
436+ <head>
437+ <title>lp.code.branch.information_type_choice Tests</title>
438+
439+ <!-- YUI and test setup -->
440+ <script type="text/javascript"
441+ src="../../../../../build/js/yui/yui/yui.js">
442+ </script>
443+ <link rel="stylesheet"
444+ href="../../../../../build/js/yui/console/assets/console-core.css" />
445+ <link rel="stylesheet"
446+ href="../../../../../build/js/yui/console/assets/skins/sam/console.css" />
447+ <link rel="stylesheet"
448+ href="../../../../../build/js/yui/test/assets/skins/sam/test.css" />
449+
450+ <script type="text/javascript"
451+ src="../../../../../build/js/lp/app/testing/testrunner.js"></script>
452+
453+ <link rel="stylesheet" href="../../../app/javascript/testing/test.css" />
454+
455+ <!-- Dependencies -->
456+ <script type="text/javascript"
457+ src="../../../../../build/js/lp/app/lp.js"></script>
458+ <script type="text/javascript"
459+ src="../../../../../build/js/lp/app/choice.js"></script>
460+ <script type="text/javascript"
461+ src="../../../../../build/js/lp/app/information_type.js"></script>
462+ <script type="text/javascript"
463+ src="../../../../../build/js/lp/app/testing/mockio.js"></script>
464+ <script type="text/javascript"
465+ src="../../../../../build/js/lp/app/client.js"></script>
466+ <script type="text/javascript"
467+ src="../../../../../build/js/lp/app/extras/extras.js"></script>
468+ <script type="text/javascript"
469+ src="../../../../../build/js/lp/app/activator/activator.js"></script>
470+ <script type="text/javascript"
471+ src="../../../../../build/js/lp/app/anim/anim.js"></script>
472+ <script type="text/javascript"
473+ src="../../../../../build/js/lp/app/effects/effects.js"></script>
474+ <script type="text/javascript"
475+ src="../../../../../build/js/lp/app/lazr/lazr.js"></script>
476+ <script type="text/javascript"
477+ src="../../../../../build/js/lp/app/choiceedit/choiceedit.js"></script>
478+ <script type="text/javascript"
479+ src="../../../../../build/js/lp/app/mustache.js"></script>
480+ <script type="text/javascript"
481+ src="../../../../../build/js/lp/app/inlineedit/editor.js"></script>
482+ <script type="text/javascript"
483+ src="../../../../../build/js/lp/app/formoverlay/formoverlay.js"></script>
484+ <script type="text/javascript"
485+ src="../../../../../build/js/lp/app/overlay/overlay.js"></script>
486+ <script type="text/javascript"
487+ src="../../../../../build/js/lp/app/expander.js"></script>
488+ <script type="text/javascript"
489+ src="../../../../../build/js/lp/app/errors.js"></script>
490+ <script type="text/javascript"
491+ src="../../../../../build/js/lp/app/banners/banner.js"></script>
492+ <script type="text/javascript"
493+ src="../../../../../build/js/lp/app/banners/privacy.js"></script>
494+
495+ <!-- The module under test. -->
496+ <script type="text/javascript" src="../branch.information_type_choice.js"></script>
497+
498+ <!-- Placeholder for any css asset for this module. -->
499+ <!-- <link rel="stylesheet" href="../assets/bugs.information_type_choice-ctest_inforore.css" /> -->
500+
501+ <!-- The test suite -->
502+ <script type="text/javascript" src="test_information_type_choice.js"></script>
503+
504+ </head>
505+ <body class="yui3-skin-sam">
506+ <ul id="suites">
507+ <li>lp.code.branch.information_type_choice.test</li>
508+ </ul>
509+ <div id="fixture"></div>
510+ <script type="text/x-template" id="portlet-template">
511+ <div id="privacy">
512+ <div id="privacy-text">
513+ <span id="information-type-summary" class="sprite public">
514+ This report contains
515+ <strong id="information-type">Public</strong>
516+ information
517+ </span>
518+ <a class="sprite edit" id="privacy-link" href="#">edit</a>
519+ <div id="information-type-description">Everyone can see this information.</div>
520+ </div>
521+ </div>
522+ </script>
523+ </body>
524+</html>
525
526=== added file 'lib/lp/code/javascript/tests/test_information_type_choice.js'
527--- lib/lp/code/javascript/tests/test_information_type_choice.js 1970-01-01 00:00:00 +0000
528+++ lib/lp/code/javascript/tests/test_information_type_choice.js 2012-08-29 04:50:32 +0000
529@@ -0,0 +1,179 @@
530+/* Copyright (c) 2012, Canonical Ltd. All rights reserved. */
531+
532+YUI.add('lp.code.branch.information_type_choice.test', function (Y) {
533+
534+ var tests = Y.namespace('lp.code.branch.information_type_choice.test');
535+ var ns = Y.lp.code.branch.information_type_choice;
536+ tests.suite = new Y.Test.Suite(
537+ 'lp.code.branch.information_type_choice Tests');
538+
539+ tests.suite.add(new Y.Test.Case({
540+ name: 'lp.code.branch.information_type_choice_tests',
541+
542+ setUp: function() {
543+ window.LP = {
544+ cache: {
545+ context: {
546+ web_link: '',
547+ information_type: 'Public'
548+ },
549+ private_types: ['PROPRIETARY', 'USERDATA'],
550+ information_type_data: [
551+ {'value': 'PUBLIC', 'name': 'Public',
552+ 'description': 'Public Description'},
553+ {'value': 'PUBLICSECURITY', 'name': 'Public Security',
554+ 'description': 'Public Security Description'},
555+ {'value': 'PROPRIETARY', 'name': 'Proprietary',
556+ 'description': 'Private Description'},
557+ {'value': 'USERDATA', 'name': 'Private',
558+ 'description': 'Private Description'}
559+ ]
560+ }
561+ };
562+ this.fixture = Y.one('#fixture');
563+ var portlet = Y.Node.create(
564+ Y.one('#portlet-template').getContent());
565+ this.fixture.appendChild(portlet);
566+ this.mockio = new Y.lp.testing.mockio.MockIo();
567+ },
568+
569+ tearDown: function () {
570+ if (this.fixture !== null) {
571+ this.fixture.empty(true);
572+ }
573+ delete this.fixture;
574+ delete this.mockio;
575+ delete window.LP;
576+ },
577+
578+ makeWidget: function() {
579+ this.widget = new ns.BranchInformationTypeWidget({
580+ io_provider: this.mockio,
581+ use_animation: false
582+ });
583+ this.widget.render();
584+ },
585+
586+ _shim_privacy_banner: function () {
587+ var old_func = Y.lp.app.banner.privacy.getPrivacyBanner;
588+ Y.lp.app.banner.privacy.getPrivacyBanner = function () {
589+ return {
590+ show: function () { Y.fire('test:banner:show'); },
591+ hide: function () { Y.fire('test:banner:hide'); },
592+ updateText: function () { Y.fire('test:banner:update'); }
593+ };
594+ };
595+ return old_func;
596+ },
597+
598+ _unshim_privacy_banner: function (old_func) {
599+ Y.lp.app.banner.privacy.getPrivacyBanner = old_func;
600+ },
601+
602+ test_library_exists: function () {
603+ Y.Assert.isObject(Y.lp.code.branch.information_type_choice,
604+ "Cannot locate the " +
605+ "lp.code.branch.information_type_choice module");
606+ },
607+
608+ // The widget is created as expected.
609+ test_create_widget: function() {
610+ this.makeWidget();
611+ Y.Assert.isInstanceOf(
612+ ns.BranchInformationTypeWidget, this.widget,
613+ "Branch info type widget failed to be instantiated");
614+ var privacy_link = Y.one('#privacy-link');
615+ Y.Assert.isTrue(privacy_link.hasClass('js-action'));
616+ },
617+
618+ // The save XHR call works as expected.
619+ test_save_information_type: function() {
620+ this.makeWidget();
621+ var save_success_called = false;
622+ this.widget._information_type_save_success = function(value) {
623+ Y.Assert.areEqual('USERDATA', value);
624+ save_success_called = true;
625+ };
626+ this.widget._save_information_type('USERDATA');
627+ this.mockio.success({
628+ responseText: '',
629+ responseHeaders: {'Content-Type': 'application/json'}});
630+ Y.Assert.areEqual(
631+ document.URL + '/+edit-information-type',
632+ this.mockio.last_request.url);
633+ Y.Assert.areEqual(
634+ 'field.actions.change=Change%20Branch&' +
635+ 'field.information_type=USERDATA',
636+ this.mockio.last_request.config.data);
637+ Y.Assert.isTrue(save_success_called);
638+ },
639+
640+ // Setting a private type shows the privacy banner.
641+ test_information_type_save_success_private: function() {
642+ this.makeWidget();
643+ var old_func = this._shim_privacy_banner();
644+ var hide_flag = false;
645+ var update_flag = false;
646+ Y.on('test:banner:show', function() {
647+ hide_flag = true;
648+ });
649+ Y.on('test:banner:update', function() {
650+ update_flag = true;
651+ });
652+
653+ this.widget._information_type_save_success('PROPRIETARY');
654+ var body = Y.one('body');
655+ Y.Assert.isTrue(body.hasClass('private'));
656+ Y.Assert.isTrue(hide_flag);
657+ Y.Assert.isTrue(update_flag);
658+ Y.Assert.areEqual(
659+ 'Proprietary', LP.cache.context.information_type);
660+ this._unshim_privacy_banner(old_func);
661+ },
662+
663+ // Setting a private type hides the privacy banner.
664+ test_information_type_save_success_public: function() {
665+ this.makeWidget();
666+ var old_func = this._shim_privacy_banner();
667+ var flag = false;
668+ Y.on('test:banner:hide', function() {
669+ flag = true;
670+ });
671+ var summary = Y.one('#information-type-summary');
672+ summary.replaceClass('public', 'private');
673+
674+ this.widget._information_type_save_success('PUBLIC');
675+ var body = Y.one('body');
676+ Y.Assert.isTrue(body.hasClass('public'));
677+ Y.Assert.isTrue(flag);
678+ Y.Assert.areEqual('Public', LP.cache.context.information_type);
679+ this._unshim_privacy_banner(old_func);
680+ },
681+
682+ // Test error handling when a save fails.
683+ test_information_type_save_error: function() {
684+ this.makeWidget();
685+ this.widget.information_type_edit.set('value', 'USERDATA');
686+ this.widget._save_information_type('USERDATA');
687+ this.mockio.last_request.respond({
688+ status: 500,
689+ statusText: 'An error occurred'
690+ });
691+ // The original info type value from the cache should have been
692+ // set back into the widget.
693+ Y.Assert.areEqual(
694+ 'PUBLIC',
695+ this.widget.information_type_edit.get('value'));
696+ var description_node = Y.one('#information-type-description');
697+ Y.Assert.areEqual(
698+ 'Public Description', description_node.get('text'));
699+ var summary = Y.one('#information-type-summary');
700+ Y.Assert.isTrue(summary.hasClass('public'));
701+ // The error was displayed.
702+ Y.Assert.isNotNull(Y.one('.yui3-lazr-formoverlay-errors'));
703+ }
704+ }));
705+
706+}, '0.1', {'requires': ['test', 'console', 'event', 'node-event-simulate',
707+ 'lp.testing.mockio', 'lp.client', 'lp.app.information_type',
708+ 'lp.code.branch.information_type_choice']});
709
710=== modified file 'lib/lp/code/templates/branch-portlet-privacy.pt'
711--- lib/lp/code/templates/branch-portlet-privacy.pt 2012-08-29 04:50:31 +0000
712+++ lib/lp/code/templates/branch-portlet-privacy.pt 2012-08-29 04:50:32 +0000
713@@ -18,3 +18,17 @@
714 <div id="information-type-description" style="padding-top: 5px"
715 tal:content="view/information_type_description"></div>
716 </div>
717+
718+<tal:script>
719+ <script type="text/javascript">
720+ LPJS.use('lp.code.branch.information_type_choice', function(Y) {
721+ Y.on('domready',
722+ function(e) {
723+ var widget = new Y.lp.code.branch.information_type_choice.BranchInformationTypeWidget();
724+ widget.render();
725+ },
726+ window);
727+ });
728+ </script>
729+</tal:script>
730+