Merge lp:~henninge/launchpad/bug-410864-undefined-in-picker into lp:launchpad

Proposed by Henning Eggers
Status: Merged
Approved by: Curtis Hovey
Approved revision: no longer in the source branch.
Merged at revision: 13196
Proposed branch: lp:~henninge/launchpad/bug-410864-undefined-in-picker
Merge into: lp:launchpad
Diff against target: 472 lines (+155/-94)
9 files modified
lib/canonical/launchpad/webapp/configure.zcml (+2/-2)
lib/lp/app/javascript/picker.js (+21/-44)
lib/lp/app/javascript/tests/test_personpicker.html (+1/-1)
lib/lp/app/javascript/tests/test_personpicker.js (+4/-4)
lib/lp/app/javascript/tests/test_picker.html (+1/-0)
lib/lp/app/javascript/tests/test_picker.js (+36/-9)
lib/lp/app/javascript/widgets.js (+75/-32)
lib/lp/app/widgets/popup.py (+13/-1)
lib/lp/app/widgets/templates/form-picker-macros.pt (+2/-1)
To merge this branch: bzr merge lp:~henninge/launchpad/bug-410864-undefined-in-picker
Reviewer Review Type Date Requested Status
Curtis Hovey (community) code Approve
Review via email: mp+63911@code.launchpad.net

Commit message

[r=sinzui][bug=410864,787595] Work on the picker widget: Retargets the personpicker yui widget to extend the new lp-picker yui widget. Fixes a regression that let the result batches run out of proportion. Fixes the 'too many results' display.

Description of the change

= Summary =

Apart from fixing the linked bug this branch also piggybacks a fix for a
regression introduced by the fix for bug 778129 (my bad).

This regression caused the picker widget to display all the batches of
results even if a search box was available. Instead it should display
the "Too many search results" message and not display any results.

The reason for bug 410864 lies in lazr-js assuming that an empty result
list indicates that a search returned no results. But enforcing the
batch limit also creates empty result list in which case the
message "No items matched ..." produced by lazr-js is not fitting.
To prevent that message, a one-item result list with an empty item
was created which caused "undefined" to appear as the title of that
one item.

== Proposed fix ==

For the regression: The code used "config.show_search_box" in the
create() method but config might not always have such a member. So
create() needs to mimic the behavior of the createPickerPatcher()
method and default show_search_box to true when it is undefined.

For the actual bug: The render method needs to be aware that it
could get an empty data as a result and produce an empty result
element accordingly. A better fix would be to make lazr-js's
behavior regarding empty result lists configurable but I went for the
least-impact solution. Another squad is doing work on the picker and
they may well touch this.

== Pre-implementation notes ==

Chatted a big with deryck, did not catch Curtis on IRC.

== Tests ==

lib/lp/app/javascript/tests/test_picker.html

== Demo and Q/A ==

Go to a bug page, open the picker for the bug target and enter
"linux". You should get a "Too many results" message but no
"undefined" in the empty list below.

= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/app/javascript/picker.js
  lib/lp/app/javascript/tests/test_picker.js

./lib/lp/app/javascript/picker.js
     337: 'Picker' has not been fully defined yet.

To post a comment you must log in.
Revision history for this message
Curtis Hovey (sinzui) wrote :

Thank you for this change. I think the branch conflicts with https://code.launchpad.net/~jcsackett/launchpad/oh-oh-pick-me-pick-me-3 which moved modules and chunks of code. I recognise the area you made changes. You may need to make these same changes to lp.app.javascript.widgets

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/canonical/launchpad/webapp/configure.zcml'
--- lib/canonical/launchpad/webapp/configure.zcml 2011-05-27 21:03:22 +0000
+++ lib/canonical/launchpad/webapp/configure.zcml 2011-06-09 08:46:18 +0000
@@ -396,10 +396,10 @@
396 permission="zope.Public"396 permission="zope.Public"
397 />397 />
398398
399 <!-- Define the widget used by PublicPersonChoice fields. -->399 <!-- Define the widget used by PersonChoice fields. -->
400 <view400 <view
401 type="zope.publisher.interfaces.browser.IBrowserRequest"401 type="zope.publisher.interfaces.browser.IBrowserRequest"
402 for="lp.services.fields.PublicPersonChoice402 for="lp.services.fields.PersonChoice
403 canonical.launchpad.webapp.vocabulary.IHugeVocabulary"403 canonical.launchpad.webapp.vocabulary.IHugeVocabulary"
404 provides="zope.app.form.interfaces.IInputWidget"404 provides="zope.app.form.interfaces.IInputWidget"
405 factory="lp.app.widgets.popup.PersonPickerWidget"405 factory="lp.app.widgets.popup.PersonPickerWidget"
406406
=== modified file 'lib/lp/app/javascript/picker.js'
--- lib/lp/app/javascript/picker.js 2011-06-06 03:24:06 +0000
+++ lib/lp/app/javascript/picker.js 2011-06-09 08:46:18 +0000
@@ -328,47 +328,6 @@
328 Y.on('change', copy_selected_value, select_menu);328 Y.on('change', copy_selected_value, select_menu);
329 };329 };
330330
331
332/**
333 * Extend the lazr-js Picker.
334 */
335var Picker = function() {
336 Picker.superclass.constructor.apply(this, arguments);
337};
338
339Y.extend(Picker, Y.lazr.Picker, {
340 // We want to render alt title slightly differently.
341 _renderTitleUI: function(data) {
342 var li_title = Y.Node.create(
343 '<span></span>').addClass(Y.lazr.Picker.C_RESULT_TITLE);
344 var title = this._text_or_link(
345 data.title, data.title_link, data.link_css);
346 li_title.appendChild(title);
347 if (data.alt_title) {
348 var alt_link = null;
349 if (data.alt_title_link) {
350 alt_link =Y.Node.create('<a></a>')
351 .addClass(data.link_css)
352 .addClass('discreet');
353 alt_link.set('text', " Details...")
354 .set('href', data.alt_title_link);
355 Y.on('click', function(e) {
356 e.halt();
357 window.open(data.alt_title_link);
358 }, alt_link);
359 }
360 li_title.appendChild('&nbsp;(');
361 li_title.appendChild(document.createTextNode(data.alt_title));
362 if (alt_link !== null)
363 li_title.appendChild(alt_link);
364 li_title.appendChild(')');
365 }
366 return li_title;
367 }
368});
369Picker.NAME = 'picker';
370namespace.Picker = Picker;
371
372/**331/**
373 * Creates a picker widget that has already been rendered and hidden.332 * Creates a picker widget that has already been rendered and hidden.
374 *333 *
@@ -381,6 +340,8 @@
381 * config.step_title overrides the subtitle.340 * config.step_title overrides the subtitle.
382 * config.save is a Function (optional) which takes341 * config.save is a Function (optional) which takes
383 * a single string argument.342 * a single string argument.
343 * config.show_search_box: Should the search box be
344 * shown.
384 */345 */
385namespace.create = function (vocabulary, config, activator) {346namespace.create = function (vocabulary, config, activator) {
386 if (Y.UA.ie) {347 if (Y.UA.ie) {
@@ -389,6 +350,8 @@
389350
390 var header = 'Choose an item.';351 var header = 'Choose an item.';
391 var step_title = "Enter search terms";352 var step_title = "Enter search terms";
353 var show_search_box = true;
354 var picker_type = "default";
392 if (config !== undefined) {355 if (config !== undefined) {
393 if (config.header !== undefined) {356 if (config.header !== undefined) {
394 header = config.header;357 header = config.header;
@@ -397,6 +360,14 @@
397 if (config.step_title !== undefined) {360 if (config.step_title !== undefined) {
398 step_title = config.step_title;361 step_title = config.step_title;
399 }362 }
363
364 if (config.show_search_box !== undefined) {
365 show_search_box = config.show_search_box;
366 }
367
368 if (config.picker_type !== undefined) {
369 picker_type = config.picker_type;
370 }
400 }371 }
401372
402 if (typeof vocabulary !== 'string' && typeof vocabulary !== 'object') {373 if (typeof vocabulary !== 'string' && typeof vocabulary !== 'object') {
@@ -417,7 +388,13 @@
417 zIndex: 1000,388 zIndex: 1000,
418 visible: false389 visible: false
419 });390 });
420 var picker = new Picker(new_config);391
392 var picker = null;
393 if (picker_type === 'person') {
394 picker = new Y.lp.app.widgets.PersonPicker(new_config);
395 } else {
396 picker = new Y.lp.app.widgets.Picker(new_config);
397 }
421398
422 // We don't want the Y.lazr.Picker default save to fire since this hides399 // We don't want the Y.lazr.Picker default save to fire since this hides
423 // the form. We want to do this ourselves after any validation has had a400 // the form. We want to do this ourselves after any validation has had a
@@ -457,7 +434,7 @@
457 var batch = 0;434 var batch = 0;
458 var display_vocabulary = function(results, total_size, start) {435 var display_vocabulary = function(results, total_size, start) {
459 var max_size = MAX_BATCHES * BATCH_SIZE;436 var max_size = MAX_BATCHES * BATCH_SIZE;
460 if (config.show_search_box && total_size > max_size) {437 if (show_search_box && total_size > max_size) {
461 picker.set('error',438 picker.set('error',
462 'Too many matches. Please try to narrow your search.');439 'Too many matches. Please try to narrow your search.');
463 // Display a single empty result item so that the picker440 // Display a single empty result item so that the picker
@@ -540,5 +517,5 @@
540517
541}, "0.1", {"requires": [518}, "0.1", {"requires": [
542 "io", "dom", "dump", "event", "lazr.picker", "lazr.activator",519 "io", "dom", "dump", "event", "lazr.picker", "lazr.activator",
543 "json-parse", "lp.client"520 "json-parse", "lp.client", "lp.app.widgets"
544 ]});521 ]});
545522
=== renamed file 'lib/lp/registry/javascript/tests/test_personpicker.html' => 'lib/lp/app/javascript/tests/test_personpicker.html'
--- lib/lp/registry/javascript/tests/test_personpicker.html 2011-06-01 13:59:43 +0000
+++ lib/lp/app/javascript/tests/test_personpicker.html 2011-06-09 08:46:18 +0000
@@ -17,7 +17,7 @@
17 <script type="text/javascript" src="../../../app/javascript/lp.js"></script>17 <script type="text/javascript" src="../../../app/javascript/lp.js"></script>
1818
19 <!-- The module under test -->19 <!-- The module under test -->
20 <script type="text/javascript" src="../personpicker.js"></script>20 <script type="text/javascript" src="../widgets.js"></script>
2121
22 <!-- The test suite -->22 <!-- The test suite -->
23 <script type="text/javascript" src="test_personpicker.js"></script>23 <script type="text/javascript" src="test_personpicker.js"></script>
2424
=== renamed file 'lib/lp/registry/javascript/tests/test_personpicker.js' => 'lib/lp/app/javascript/tests/test_personpicker.js'
--- lib/lp/registry/javascript/tests/test_personpicker.js 2011-06-06 17:43:55 +0000
+++ lib/lp/app/javascript/tests/test_personpicker.js 2011-06-09 08:46:18 +0000
@@ -6,10 +6,10 @@
6 base: '../../../../canonical/launchpad/icing/yui/',6 base: '../../../../canonical/launchpad/icing/yui/',
7 filter: 'raw', combine: false,7 filter: 'raw', combine: false,
8 fetchCSS: false8 fetchCSS: false
9 }).use('test', 'console', 'plugin', 'lp.registry.personpicker',9 }).use('test', 'console', 'plugin', 'lp.app.widgets',
10 'node-event-simulate', function(Y) {10 'node-event-simulate', function(Y) {
1111
12 var suite = new Y.Test.Suite("lp.registry.personpicker Tests");12 var suite = new Y.Test.Suite("lp.app.widgets.PersonPicker Tests");
1313
14 suite.add(new Y.Test.Case({14 suite.add(new Y.Test.Case({
15 name: 'personpicker',15 name: 'personpicker',
@@ -22,7 +22,7 @@
22 },22 },
2323
24 test_render: function () {24 test_render: function () {
25 var personpicker = new Y.lp.registry.personpicker.PersonPicker();25 var personpicker = new Y.lp.app.widgets.PersonPicker();
26 personpicker.render();26 personpicker.render();
27 personpicker.show();27 personpicker.show();
2828
@@ -33,7 +33,7 @@
33 },33 },
3434
35 test_buttons: function () {35 test_buttons: function () {
36 var personpicker = new Y.lp.registry.personpicker.PersonPicker();36 var personpicker = new Y.lp.app.widgets.PersonPicker();
37 personpicker.render();37 personpicker.render();
38 personpicker.show();38 personpicker.show();
3939
4040
=== modified file 'lib/lp/app/javascript/tests/test_picker.html'
--- lib/lp/app/javascript/tests/test_picker.html 2011-04-19 11:27:26 +0000
+++ lib/lp/app/javascript/tests/test_picker.html 2011-06-09 08:46:18 +0000
@@ -19,6 +19,7 @@
19 <script type="text/javascript" src="../../../../canonical/launchpad/icing/lazr/build/anim/anim.js"></script>19 <script type="text/javascript" src="../../../../canonical/launchpad/icing/lazr/build/anim/anim.js"></script>
20 <script type="text/javascript" src="../../../../canonical/launchpad/icing/lazr/build/lazr/lazr.js"></script>20 <script type="text/javascript" src="../../../../canonical/launchpad/icing/lazr/build/lazr/lazr.js"></script>
21 <script type="text/javascript" src="../client.js"></script>21 <script type="text/javascript" src="../client.js"></script>
22 <script type="text/javascript" src="../widgets.js"></script>
2223
23 <!-- The module under test -->24 <!-- The module under test -->
24 <script type="text/javascript" src="../picker.js"></script>25 <script type="text/javascript" src="../picker.js"></script>
2526
=== modified file 'lib/lp/app/javascript/tests/test_picker.js'
--- lib/lp/app/javascript/tests/test_picker.js 2011-06-03 22:46:35 +0000
+++ lib/lp/app/javascript/tests/test_picker.js 2011-06-09 08:46:18 +0000
@@ -6,8 +6,8 @@
6 combine: false,6 combine: false,
7 fetchCSS: false7 fetchCSS: false
8 }).use('test', 'console', 'node', 'lp', 'lp.client', 'escape', 'event',8 }).use('test', 'console', 'node', 'lp', 'lp.client', 'escape', 'event',
9 'event-focus', 'event-simulate', 'lazr.picker','lp.app.picker',9 'event-focus', 'event-simulate', 'lazr.picker', 'lp.app.widgets',
10 'node-event-simulate',10 'lp.app.picker', 'node-event-simulate',
11 function(Y) {11 function(Y) {
1212
13var Assert = Y.Assert;13var Assert = Y.Assert;
@@ -86,7 +86,8 @@
86 // The picker can be instantiated.86 // The picker can be instantiated.
87 this.create_picker();87 this.create_picker();
88 Assert.isInstanceOf(88 Assert.isInstanceOf(
89 Y.lazr.Picker, this.picker, "Picker failed to be instantiated");89 Y.lp.app.widgets.Picker, this.picker,
90 "Picker failed to be instantiated");
90 },91 },
9192
92 // Called when the picker saves it's data. Sets a flag for checking.93 // Called when the picker saves it's data. Sets a flag for checking.
@@ -243,17 +244,32 @@
243 },244 },
244245
245 create_picker: function(show_search_box) {246 create_picker: function(show_search_box) {
247 var config = {
248 "step_title": "Choose someone",
249 "header": "Pick Someone",
250 "validate_callback": null
251 };
252 if (show_search_box !== undefined) {
253 config.show_search_box = show_search_box;
254 }
246 this.picker = Y.lp.app.picker.addPickerPatcher(255 this.picker = Y.lp.app.picker.addPickerPatcher(
247 this.vocabulary,256 this.vocabulary,
248 "foo/bar",257 "foo/bar",
249 "test_link",258 "test_link",
250 "picker_id",259 "picker_id",
251 {260 config
252 "step_title": "Choose someone",261 );
253 "header": "Pick Someone",262 },
254 "show_search_box": show_search_box,263
255 "validate_callback": null264 test_picker_displays_empty_list: function() {
256 });265 // With too many results, the results will be empty.
266 this.create_picker(true);
267 this.picker.render();
268 this.picker.set('min_search_chars', 0);
269 this.picker.fire('search', '');
270 var result_text = this.picker.get('contentBox')
271 .one('.yui3-picker-results').get('text');
272 Assert.areEqual('', result_text);
257 },273 },
258274
259 test_picker_displays_warning: function() {275 test_picker_displays_warning: function() {
@@ -267,6 +283,17 @@
267 this.picker.get('error'));283 this.picker.get('error'));
268 },284 },
269285
286 test_picker_displays_warning_by_default: function() {
287 // If show_search_box is not supplied in config, it defaults to true.
288 // Thus the picker will refuse to display more than 120 values.
289 this.create_picker();
290 this.picker.set('min_search_chars', 0);
291 this.picker.fire('search', '');
292 Assert.areEqual(
293 'Too many matches. Please try to narrow your search.',
294 this.picker.get('error'));
295 },
296
270 test_picker_no_warning: function() {297 test_picker_no_warning: function() {
271 // Without a search box the picker will also display more than298 // Without a search box the picker will also display more than
272 // 120 values.299 // 120 values.
273300
=== renamed file 'lib/lp/registry/javascript/personpicker.js' => 'lib/lp/app/javascript/widgets.js'
--- lib/lp/registry/javascript/personpicker.js 2011-05-31 18:27:50 +0000
+++ lib/lp/app/javascript/widgets.js 2011-06-09 08:46:18 +0000
@@ -1,21 +1,69 @@
1/* Copyright 2011 Canonical Ltd. This software is licensed under the1/* Copyright 2011 Canonical Ltd. This software is licensed under the
2 * GNU Affero General Public License version 3 (see the file LICENSE).2 * GNU Affero General Public License version 3 (see the file LICENSE).
3 *3 *
4 * @namespace Y.lp.registry.personpicker4 * @namespace Y.lp.app.widgets
5 * @requires lazr.picker5 * @requires Y.lazr.picker
6 */6 */
7YUI.add('lp.registry.personpicker', function(Y) {7YUI.add('lp.app.widgets', function(Y) {
8var namespace = Y.namespace('lp.registry.personpicker');8var namespace = Y.namespace('lp.app.widgets');
99
10var footer_label = ".yui3-picker-footer-slot"10/**
11 * Extend the lazr-js Picker.
12 */
13var Picker = function() {
14 Picker.superclass.constructor.apply(this, arguments);
15};
16
17Y.extend(Picker, Y.lazr.Picker, {
18 // We want to render alt title slightly differently.
19 _renderTitleUI: function(data) {
20 var li_title = Y.Node.create(
21 '<span></span>').addClass(Y.lazr.Picker.C_RESULT_TITLE);
22 if (data.title === undefined) {
23 // Display an empty element if data is empty.
24 return li_title;
25 }
26 var title = this._text_or_link(
27 data.title, data.title_link, data.link_css);
28 li_title.appendChild(title);
29 if (data.alt_title) {
30 var alt_link = null;
31 if (data.alt_title_link) {
32 alt_link =Y.Node.create('<a></a>')
33 .addClass(data.link_css)
34 .addClass('discreet');
35 alt_link.set('text', " Details...")
36 .set('href', data.alt_title_link);
37 Y.on('click', function(e) {
38 e.halt();
39 window.open(data.alt_title_link);
40 }, alt_link);
41 }
42 li_title.appendChild('&nbsp;(');
43 li_title.appendChild(document.createTextNode(data.alt_title));
44 li_title.appendChild(')');
45 if (alt_link !== null) {
46 li_title.appendChild(alt_link);
47 }
48 }
49 return li_title;
50 }
51});
52
53Picker.NAME = 'picker';
54namespace.Picker = Picker;
55
56/*
57 * Extend the picker into the PersonPicker
58 */
59var footer_label = ".yui3-picker-footer-slot";
1160
12var PersonPicker = function() {61var PersonPicker = function() {
13 PersonPicker.superclass.constructor.apply(this, arguments);62 PersonPicker.superclass.constructor.apply(this, arguments);
14
15 this._extra_buttons = Y.Node.create('<div class="extra-form-buttons"/>');63 this._extra_buttons = Y.Node.create('<div class="extra-form-buttons"/>');
16};64};
1765
18Y.extend(PersonPicker, Y.lazr.Picker, {66Y.extend(PersonPicker, namespace.Picker, {
19 hide: function() {67 hide: function() {
20 this.get('boundingBox').setStyle('display', 'none');68 this.get('boundingBox').setStyle('display', 'none');
21 },69 },
@@ -36,29 +84,24 @@
36 renderUI: function() {84 renderUI: function() {
37 this.constructor.superclass.renderUI.call(this);85 this.constructor.superclass.renderUI.call(this);
38 var remove_button, assign_me_button;86 var remove_button, assign_me_button;
39 //# TODO config should set extrabuttons
40 var show_remove_button = true;
41 var show_assign_me_button = true;
42 var remove_button_text = "Remove assignee";87 var remove_button_text = "Remove assignee";
43 var assign_me_button_text = "Assign me";88 var assign_me_button_text = "Assign me";
44 if (show_remove_button) {89
45 remove_button = Y.Node.create(90 remove_button = Y.Node.create(
46 '<a class="yui-picker-remove-button bg-image" ' +91 '<a class="yui-picker-remove-button bg-image" ' +
47 'href="javascript:void(0)" ' +92 'href="javascript:void(0)" ' +
48 'style="background-image: url(/@@/remove); padding-right: 1em">' +93 'style="background-image: url(/@@/remove); padding-right: 1em">' +
49 remove_button_text + '</a>');94 remove_button_text + '</a>');
50 remove_button.on('click', this.remove, this);95 remove_button.on('click', this.remove, this);
51 this._extra_buttons.appendChild(remove_button);96 this._extra_buttons.appendChild(remove_button);
52 }97
53 if (show_assign_me_button) {98 assign_me_button = Y.Node.create(
54 assign_me_button = Y.Node.create(99 '<a class="yui-picker-assign-me-button bg-image" ' +
55 '<a class="yui-picker-assign-me-button bg-image" ' +100 'href="javascript:void(0)" ' +
56 'href="javascript:void(0)" ' +101 'style="background-image: url(/@@/person)">' +
57 'style="background-image: url(/@@/person)">' +102 assign_me_button_text + '</a>');
58 assign_me_button_text + '</a>');103 assign_me_button.on('click', this.assign_me, this);
59 assign_me_button.on('click', this.assign_me, this);104 this._extra_buttons.appendChild(assign_me_button);
60 this._extra_buttons.appendChild(assign_me_button);
61 }
62 },105 },
63106
64 syncUI: function() {107 syncUI: function() {
@@ -69,6 +112,6 @@
69 }112 }
70});113});
71PersonPicker.NAME = 'person-picker';114PersonPicker.NAME = 'person-picker';
72namespace.PersonPicker = PersonPicker115namespace.PersonPicker = PersonPicker;
73116
74}, "0.1", {"requires": ['lazr.picker']});117}, "0.1", {"requires": ["lazr.picker"]});
75118
=== modified file 'lib/lp/app/widgets/popup.py'
--- lib/lp/app/widgets/popup.py 2011-06-01 13:59:43 +0000
+++ lib/lp/app/widgets/popup.py 2011-06-09 08:46:18 +0000
@@ -18,6 +18,7 @@
1818
19from canonical.launchpad.webapp import canonical_url19from canonical.launchpad.webapp import canonical_url
20from lp.app.browser.stringformatter import FormattersAPI20from lp.app.browser.stringformatter import FormattersAPI
21from lp.services.features import getFeatureFlag
21from lp.services.propertycache import cachedproperty22from lp.services.propertycache import cachedproperty
2223
2324
@@ -26,6 +27,8 @@
2627
27 __call__ = ViewPageTemplateFile('templates/form-picker.pt')28 __call__ = ViewPageTemplateFile('templates/form-picker.pt')
2829
30 picker_type = 'default'
31
29 popup_name = 'popup-vocabulary-picker'32 popup_name = 'popup-vocabulary-picker'
3033
31 # Override inherited attributes for the form field.34 # Override inherited attributes for the form field.
@@ -157,6 +160,16 @@
157160
158 include_create_team_link = False161 include_create_team_link = False
159162
163 @property
164 def picker_type(self):
165 # This is a method for now so we can block the use of the new
166 # person picker js behind our picker_enhancments feature flag.
167 if bool(getFeatureFlag('disclosure.picker_enhancements.enabled')):
168 picker_type = 'person'
169 else:
170 picker_type = 'default'
171 return picker_type
172
160 def chooseLink(self):173 def chooseLink(self):
161 link = super(PersonPickerWidget, self).chooseLink()174 link = super(PersonPickerWidget, self).chooseLink()
162 if self.include_create_team_link:175 if self.include_create_team_link:
@@ -172,7 +185,6 @@
172class BugTrackerPickerWidget(VocabularyPickerWidget):185class BugTrackerPickerWidget(VocabularyPickerWidget):
173186
174 __call__ = ViewPageTemplateFile('templates/bugtracker-picker.pt')187 __call__ = ViewPageTemplateFile('templates/bugtracker-picker.pt')
175
176 link_template = """188 link_template = """
177 or (<a id="create-bugtracker-link"189 or (<a id="create-bugtracker-link"
178 href="/bugs/bugtrackers/+newbugtracker"190 href="/bugs/bugtrackers/+newbugtracker"
179191
=== modified file 'lib/lp/app/widgets/templates/form-picker-macros.pt'
--- lib/lp/app/widgets/templates/form-picker-macros.pt 2011-06-01 20:55:24 +0000
+++ lib/lp/app/widgets/templates/form-picker-macros.pt 2011-06-09 08:46:18 +0000
@@ -40,7 +40,8 @@
40 var config = {40 var config = {
41 header: ${view/header_text},41 header: ${view/header_text},
42 step_title: ${view/step_title_text},42 step_title: ${view/step_title_text},
43 extra_no_results_message: ${view/extra_no_results_message}43 extra_no_results_message: ${view/extra_no_results_message},
44 picker_type: '${view/picker_type}'
44 };45 };
45 var picker = Y.lp.app.picker.create('${view/vocabulary_name}', config);46 var picker = Y.lp.app.picker.create('${view/vocabulary_name}', config);
46 if (config.extra_no_results_message !== null) {47 if (config.extra_no_results_message !== null) {