launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #04146
[Merge] lp:~wallyworld/launchpad/lazrjs-picker-consolidate into lp:launchpad
Ian Booth has proposed merging lp:~wallyworld/launchpad/lazrjs-picker-consolidate into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #805782 in Launchpad itself: "Consolidate lp and lazr pickers"
https://bugs.launchpad.net/launchpad/+bug/805782
For more details, see:
https://code.launchpad.net/~wallyworld/launchpad/lazrjs-picker-consolidate/+merge/66847
Now that the lazr-js Javascript is in the lp tree, cleanup needs to be done. This branch consolidates the picker implementations.
== Implementation ==
Take the lp picker extensions for rendering additional details (as required for disclosure) and merge into the lazr picker code.
Move the lp person picker implementation into the new lp lazr tree.
Place the pickers into the Y.lazr.picker namespace (was previously Y.lazr and lp.app.picker)
There were a number of tests related to the "Assign Me"/"Remove" links which were in the picker test suite. These were moved to the person picker test suite since the person picker provides the code to implement these links.
So the current picker related code is:
lp/app/javascript/lazr/picker.js
- the core picker implementation
lp/app/javascript/lazr/person_picker.js
- extends picker to provide support for "assign to me", and "remove me" buttons
lp/app/javascript/picker_patcher.js (renamed from picker.js to avoid confusion as to what it provides)
- adds support for using a picker to patch a resource attribute
- provides a create() method to instantiate a picker
- add yes/no conformation
There is still more to be done. The yesno confirmation code should be split out, the tests need to be consolidated etc. The person picker test cases should inherit from the base picker ones (there's a fair bit of code duplication that would be removed).
== Tests ==
bin/test -vvc -layer=YUI
== Lint ==
Sadly jslint didn't complete - it was consuming > 2.2Gb of RAM and 100% CPU when it was killed.
--
https://code.launchpad.net/~wallyworld/launchpad/lazrjs-picker-consolidate/+merge/66847
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wallyworld/launchpad/lazrjs-picker-consolidate into lp:launchpad.
=== renamed file 'lib/lp/app/javascript/widgets.js' => 'lib/lp/app/javascript/lazr/picker/person_picker.js'
--- lib/lp/app/javascript/widgets.js 2011-06-30 13:56:48 +0000
+++ lib/lp/app/javascript/lazr/picker/person_picker.js 2011-07-05 04:21:00 +0000
@@ -1,74 +1,10 @@
/* Copyright 2011 Canonical Ltd. This software is licensed under the
* GNU Affero General Public License version 3 (see the file LICENSE).
*
- * @namespace Y.lp.app.widgets
- * @requires Y.lazr.picker
- */
-YUI.add('lp.app.widgets', function(Y) {
-var namespace = Y.namespace('lp.app.widgets');
-
-/**
- * Extend the lazr-js Picker.
- */
-var Picker = function() {
- Picker.superclass.constructor.apply(this, arguments);
-};
-
-Y.extend(Picker, Y.lazr.Picker, {
- // We want to render alt title slightly differently.
- _renderTitleUI: function(data) {
- var li_title = Y.Node.create(
- '<span></span>').addClass(Y.lazr.Picker.C_RESULT_TITLE);
- if (data.title === undefined) {
- // Display an empty element if data is empty.
- return li_title;
- }
- var title = this._text_or_link(
- data.title, data.title_link, data.link_css);
- li_title.appendChild(title);
- if (data.alt_title) {
- var alt_link = null;
- if (data.alt_title_link) {
- alt_link =Y.Node.create('<a></a>')
- .addClass(data.link_css)
- .addClass('discreet');
- alt_link.set('text', " Details...")
- .set('href', data.alt_title_link);
- Y.on('click', function(e) {
- e.halt();
- window.open(data.alt_title_link);
- }, alt_link);
- }
- li_title.appendChild(' (');
- li_title.appendChild(document.createTextNode(data.alt_title));
- li_title.appendChild(')');
- if (alt_link !== null) {
- li_title.appendChild(alt_link);
- }
- }
- return li_title;
- },
-
- /**
- * Create the widget's HTML components.
- * <p>
- * This method is invoked after renderUI is invoked for the Widget class
- * using YUI's aop infrastructure.
- * </p>
- *
- * @method _renderUIPicker
- * @protected
- */
- _renderUIPicker: function() {
- Picker.superclass._renderUIPicker.apply(this, arguments);
- var body = this._batches_box.get('parentNode');
- body.removeChild(this._batches_box);
- this._results_box.insert(this._batches_box, 'after');
- }
-});
-
-Picker.NAME = 'picker';
-namespace.Picker = Picker;
+ * @namespace Y.lazr.person-picker
+ * @requires lazr.picker
+ */
+YUI.add('lazr.person-picker', function(Y) {
/*
* Extend the picker into the PersonPicker
@@ -79,10 +15,9 @@
PersonPicker.superclass.constructor.apply(this, arguments);
this._extra_buttons = Y.Node.create('<div class="extra-form-buttons"/>');
Y.after(this._renderPersonPickerUI, this, 'renderUI');
- Y.after(this._syncPersonPickerResultsUI, this, 'resultsChange');
};
-Y.extend(PersonPicker, namespace.Picker, {
+Y.extend(PersonPicker, Y.lazr.picker.Picker, {
initializer: function(cfg) {
PersonPicker.superclass.initializer.apply(this, arguments);
@@ -126,7 +61,7 @@
},
assign_me: function () {
- name = LP.links.me.replace('/~', '');
+ var name = LP.links.me.replace('/~', '');
this.fire('save', {value: name});
},
@@ -175,7 +110,8 @@
});
}
});
-PersonPicker.NAME = 'person-picker';
+PersonPicker.NAME = 'picker';
+var namespace = Y.namespace('lazr.picker');
namespace.PersonPicker = PersonPicker;
}, "0.1", {"requires": ["lazr.picker"]});
=== modified file 'lib/lp/app/javascript/lazr/picker/picker.js'
--- lib/lp/app/javascript/lazr/picker/picker.js 2011-06-29 14:56:15 +0000
+++ lib/lp/app/javascript/lazr/picker/picker.js 2011-07-05 04:21:00 +0000
@@ -6,7 +6,7 @@
* Module containing the Lazr searchable picker.
*
* @module lazr.picker
- * @namespace lazr
+ * @namespace lazr.picker
*/
/**
@@ -351,15 +351,32 @@
_renderTitleUI: function(data) {
var li_title = Y.Node.create(
'<span></span>').addClass(C_RESULT_TITLE);
+ if (data.title === undefined) {
+ // Display an empty element if data is empty.
+ return li_title;
+ }
var title = this._text_or_link(
data.title, data.title_link, data.link_css);
li_title.appendChild(title);
if (data.alt_title) {
- var alt_title = this._text_or_link(
- data.alt_title, data.alt_title_link, data.link_css);
+ var alt_link = null;
+ if (data.alt_title_link) {
+ alt_link =Y.Node.create('<a></a>')
+ .addClass(data.link_css)
+ .addClass('discreet');
+ alt_link.set('text', " Details...")
+ .set('href', data.alt_title_link);
+ Y.on('click', function(e) {
+ e.halt();
+ window.open(data.alt_title_link);
+ }, alt_link);
+ }
li_title.appendChild(' (');
- li_title.appendChild(alt_title);
+ li_title.appendChild(document.createTextNode(data.alt_title));
li_title.appendChild(')');
+ if (alt_link !== null) {
+ li_title.appendChild(alt_link);
+ }
}
return li_title;
},
@@ -432,8 +449,9 @@
li.appendChild(
Y.Node.create('<img />').set('src', data.image));
}
- if (li_badges !== null)
+ if (li_badges !== null) {
li.appendChild(li_badges);
+ }
li.appendChild(li_title);
li.appendChild(li_desc);
// Attach handlers.
@@ -550,8 +568,8 @@
var body = Y.Node.create('<div></div>');
body.appendChild(search_box);
+ body.appendChild(this._results_box);
body.appendChild(this._batches_box);
- body.appendChild(this._results_box);
body.appendChild(this._footer_slot_box);
body.addClass('yui3-widget-bd');
@@ -971,7 +989,7 @@
initializer: function(config) {
var input = Y.one(config.input_element);
this.doAfter('save', function (e) {
- var result = e.details[Y.lazr.Picker.SAVE_RESULT];
+ var result = e.details[Y.lazr.picker.Picker.SAVE_RESULT];
input.set("value", result.value);
// If the search input isn't blurred before it is focused,
// then the I-beam disappears.
@@ -986,8 +1004,9 @@
}
});
-Y.lazr.Picker = Picker;
-Y.lazr.TextFieldPickerPlugin = TextFieldPickerPlugin;
+var namespace = Y.namespace('lazr.picker');
+namespace.Picker = Picker;
+namespace.TextFieldPickerPlugin = TextFieldPickerPlugin;
}, "0.1", {"skinnable": true,
"requires": ["oop", "event", "event-focus", "node", "plugin",
=== modified file 'lib/lp/app/javascript/lazr/picker/tests/picker.js'
--- lib/lp/app/javascript/lazr/picker/tests/picker.js 2011-06-29 14:56:15 +0000
+++ lib/lp/app/javascript/lazr/picker/tests/picker.js 2011-07-05 04:21:00 +0000
@@ -35,7 +35,7 @@
name: 'picker_basics',
setUp: function() {
- this.picker = new Y.lazr.Picker();
+ this.picker = new Y.lazr.picker.Picker();
},
tearDown: function() {
@@ -44,7 +44,7 @@
test_picker_can_be_instantiated: function() {
Assert.isInstanceOf(
- Y.lazr.Picker, this.picker, "Picker failed to be instantiated");
+ Y.lazr.picker.Picker, this.picker, "Picker failed to be instantiated");
},
test_picker_is_stackable: function() {
@@ -483,7 +483,7 @@
},
test_save_does_not_clear_widget_when_clear_on_save_is_false: function () {
- picker = new Y.lazr.Picker({clear_on_save: false});
+ picker = new Y.lazr.picker.Picker({clear_on_save: false});
picker.render();
picker._search_input.set('value', 'foo');
@@ -504,7 +504,7 @@
},
test_cancel_event_clears_widget_when_clear_on_cancel_is_true: function () {
- picker = new Y.lazr.Picker({clear_on_cancel: true});
+ picker = new Y.lazr.picker.Picker({clear_on_cancel: true});
picker.render();
picker._search_input.set('value', 'foo');
@@ -922,8 +922,8 @@
this.search_input = Y.Node.create(
'<input id="field.initval" value="foo" />');
var node = Y.one(document.body).appendChild(this.search_input);
- this.picker = new Y.lazr.Picker();
- this.picker.plug(Y.lazr.TextFieldPickerPlugin,
+ this.picker = new Y.lazr.picker.Picker();
+ this.picker.plug(Y.lazr.picker.TextFieldPickerPlugin,
{input_element: '[id="field.initval"]'});
},
=== renamed file 'lib/lp/app/javascript/picker.js' => 'lib/lp/app/javascript/picker_patcher.js'
--- lib/lp/app/javascript/picker.js 2011-06-28 11:26:36 +0000
+++ lib/lp/app/javascript/picker_patcher.js 2011-07-05 04:21:00 +0000
@@ -122,7 +122,7 @@
});
};
- // Create a new assign_me and remove_assigne function that uses the
+ // Create a new assign_me and remove_assignee function that uses the
// patcher save method instead of the standard picker save.
var assign_me = function () {
picker.hide();
@@ -157,7 +157,7 @@
};
config.save = save;
- var picker = namespace.create(vocabulary, config, activator);
+ var picker = namespace.create(vocabulary, config);
picker._resource_uri = resource_uri;
var remove_button = picker.remove_button;
var assign_me_button = picker.assign_me_button;
@@ -325,7 +325,7 @@
/**
* Creates a picker widget that has already been rendered and hidden.
*
- * @requires dom, dump, lazr.overlay, lazr.picker
+ * @requires dom, dump, lazr.overlay
* @method create
* @param {String} vocabulary Name of the vocabulary to query.
* @param {Object} config Optional Object literal of config name/value pairs.
@@ -337,7 +337,7 @@
* config.show_search_box: Should the search box be
* shown.
*/
-namespace.create = function (vocabulary, config, activator) {
+namespace.create = function (vocabulary, config) {
if (Y.UA.ie) {
return;
}
@@ -385,19 +385,19 @@
var picker = null;
if (picker_type === 'person') {
- picker = new Y.lp.app.widgets.PersonPicker(new_config);
+ picker = new Y.lazr.picker.PersonPicker(new_config);
} else {
- picker = new Y.lp.app.widgets.Picker(new_config);
+ picker = new Y.lazr.picker.Picker(new_config);
}
- // We don't want the Y.lazr.Picker default save to fire since this hides
+ // We don't want the default save to fire since this hides
// the form. We want to do this ourselves after any validation has had a
// chance to be performed.
picker.publish('save', { defaultFn: function(){} } );
picker.subscribe('save', function (e) {
Y.log('Got save event.');
- var picker_result = e.details[Y.lazr.Picker.SAVE_RESULT];
+ var picker_result = e.details[Y.lazr.picker.Picker.SAVE_RESULT];
var do_save = function() {
if (Y.Lang.isFunction(config.save)) {
config.save(picker_result);
@@ -510,6 +510,6 @@
};
}, "0.1", {"requires": [
- "io", "dom", "dump", "event", "lazr.picker", "lazr.activator",
- "json-parse", "lp.client", "lp.app.widgets"
+ "io", "dom", "dump", "event", "lazr.activator", "json-parse",
+ "lp.client", "lazr.picker", "lazr.person-picker"
]});
=== modified file 'lib/lp/app/javascript/tests/test_personpicker.html'
--- lib/lp/app/javascript/tests/test_personpicker.html 2011-06-09 13:32:43 +0000
+++ lib/lp/app/javascript/tests/test_personpicker.html 2011-07-05 04:21:00 +0000
@@ -15,26 +15,32 @@
href="../../../../canonical/launchpad/javascript/test.css" />
<script type="text/javascript" src="../../../app/javascript/client.js"></script>
<script type="text/javascript" src="../../../app/javascript/lp.js"></script>
+ <script type="text/javascript" src="../lazr/picker/picker.js"></script>
+ <script type="text/javascript" src="../picker_patcher.js"></script>
<!-- The module under test -->
- <script type="text/javascript" src="../widgets.js"></script>
+ <script type="text/javascript" src="../lazr/picker/person_picker.js"></script>
<!-- The test suite -->
<script type="text/javascript" src="test_personpicker.js"></script>
</head>
- <body class="yui3-skin-sam">
-
- <!-- The example markup required by the script to run -->
- <input type="text" value="" id="choose"
- name="choose" size="20"
- maxlength=""
- onKeyPress="" style=""
- class="" />
- <span class="">
- (<a id="show-widget" href="/people/">Find…</a>)
- </span>
-
- <!-- The test output -->
- <div id="log"></div>
- </body>
+<body class="yui3-skin-sam">
+ <div class="yui3-widget yui3-activator yui3-activator-focused">
+ <span id="picker_id" class="yui3-activator-content yui3-activator-success">
+ <span id="pickertest">
+ <span>
+ A picker widget test
+ <button id="edit-pickertest-btn"
+ class="lazr-btn yui3-activator-act yui3-activator-hidden">
+ Edit
+ </button>
+ </span>
+ <span class="yui3-activator-data-box">
+ </span>
+ <span class="yui3-activator-message-box yui3-activator-hidden"></span>
+ </span>
+ </span>
+ </div>
+ <div id="log"></div>
+</body>
</html>
=== modified file 'lib/lp/app/javascript/tests/test_personpicker.js'
--- lib/lp/app/javascript/tests/test_personpicker.js 2011-06-30 13:56:48 +0000
+++ lib/lp/app/javascript/tests/test_personpicker.js 2011-07-05 04:21:00 +0000
@@ -6,134 +6,335 @@
base: '../../../../canonical/launchpad/icing/yui/',
filter: 'raw', combine: false,
fetchCSS: false
- }).use('test', 'console', 'plugin', 'lp.app.widgets',
+ }).use('test', 'console', 'plugin',
+ 'lazr.picker', 'lazr.person-picker', 'lp.app.picker',
'node-event-simulate', function(Y) {
- var suite = new Y.Test.Suite("PersonPicker Tests");
-
- suite.add(new Y.Test.Case({
- name: 'Basic Functions',
-
- setUp: function() {
- window.LP = {
- links: {me: '/~no-one'},
- cache: {}
- };
- this.vocabulary = [
- {
- "value": "fred",
- "title": "Fred",
- "css": "sprite-person",
- "description": "fred@xxxxxxxxxxx",
- "api_uri": "~/fred"
- },
- {
- "value": "frieda",
- "title": "Frieda",
- "css": "sprite-person",
- "description": "frieda@xxxxxxxxxxx",
- "api_uri": "~/frieda"
- }
- ];
- },
-
- test_render: function () {
- var personpicker = new Y.lp.app.widgets.PersonPicker();
- personpicker.render();
- personpicker.show();
-
- // The extra buttons section exists
- Y.Assert.isNotNull(Y.one('.extra-form-buttons'));
- Y.Assert.isNotUndefined(personpicker.assign_me_button);
- Y.Assert.isNotUndefined(personpicker.remove_button);
- personpicker.destroy();
- },
-
- test_search_field_focus: function () {
- var personpicker = new Y.lp.app.widgets.PersonPicker();
- personpicker.render();
- personpicker.hide();
-
- var got_focus = false;
- personpicker._search_input.on('focus', function(e) {
- got_focus = true;
- });
- personpicker.show();
- Y.Assert.isTrue(got_focus, "search input did not get focus.");
- personpicker.destroy();
- },
-
- test_buttons: function () {
- var personpicker = new Y.lp.app.widgets.PersonPicker();
- personpicker.render();
- personpicker.show();
-
- // Patch the picker so the assign_me and remove methods can be
- // tested.
- var data = null;
- personpicker.on('save', function (result) {
- data = result.value;
- });
- var remove = Y.one('.yui-picker-remove-button');
- remove.simulate('click');
- Y.Assert.areEqual('', data);
-
- var assign_me = Y.one('.yui-picker-assign-me-button');
- assign_me.simulate('click');
- Y.Assert.areEqual('no-one', data);
- personpicker.destroy();
- },
-
- test_buttons_config: function () {
- cfg = {
- show_assign_me_button: false,
- show_remove_button: false
- };
-
- personpicker = new Y.lp.app.widgets.PersonPicker(cfg);
- personpicker.render();
- personpicker.show();
-
- Y.Assert.isNotNull(Y.one('.extra-form-buttons'));
- Y.Assert.isUndefined(personpicker.remove_button);
- Y.Assert.isUndefined(personpicker.assign_me_button);
- personpicker.destroy();
- },
-
- _change_results: function (picker, no_result) {
- // simulates search by setting a value and the result
- picker._search_input.set('value', 'foo');
- if (no_result) {
- picker.set('results', []);
- } else {
- picker.set('results', this.vocabulary);
+var Assert = Y.Assert;
+
+/* Helper function to clean up a dynamically added widget instance. */
+function cleanup_widget(widget) {
+ // Nuke the boundingBox, but only if we've touched the DOM.
+ if (widget.get('rendered')) {
+ var bb = widget.get('boundingBox');
+ bb.get('parentNode').removeChild(bb);
+ }
+ // Kill the widget itself.
+ widget.destroy();
+ var data_box = Y.one('#picker_id .yui3-activator-data-box');
+ var link = data_box.one('a');
+ if (link) {
+ link.get('parentNode').removeChild(link);
+ }
+}
+
+/*
+ * A wrapper for the Y.Event.simulate() function. The wrapper accepts
+ * CSS selectors and Node instances instead of raw nodes.
+ */
+function simulate(widget, selector, evtype, options) {
+ var rawnode = Y.Node.getDOMNode(widget.one(selector));
+ Y.Event.simulate(rawnode, evtype, options);
+}
+
+var suite = new Y.Test.Suite("PersonPicker Tests");
+
+/*
+ * Test cases for assign and remove buttons.
+ */
+suite.add(new Y.Test.Case({
+
+ name: 'picker_assign_remove_button',
+
+ setUp: function() {
+ this.ME = '/~me';
+ window.LP = {
+ links: {me: this.ME},
+ cache: {}
+ };
+ this.vocabulary = [
+ {
+ "value": "me",
+ "title": "Me",
+ "css": "sprite-person",
+ "description": "me@xxxxxxxxxxx",
+ "api_uri": "~/me"
+ },
+ {
+ "value": "someone",
+ "title": "Someone Else",
+ "css": "sprite-person",
+ "description": "someone@xxxxxxxxxxx",
+ "api_uri": "~/someone"
}
- },
-
- test_buttons_vanish: function () {
- personpicker = new Y.lp.app.widgets.PersonPicker(cfg);
- personpicker.render();
- this._change_results(personpicker, false);
- Y.Assert.isTrue(personpicker._extra_buttons.hasClass('unseen'));
-
- this._change_results(personpicker, true);
- Y.Assert.isFalse(personpicker._extra_buttons.hasClass('unseen'));
- personpicker.destroy();
- }
- }));
-
- // Hook for the test runner to get test results.
- var handle_complete = function(data) {
- window.status = '::::' + JSON.stringify(data);
- };
- Y.Test.Runner.on('complete', handle_complete);
- Y.Test.Runner.add(suite);
-
- var console = new Y.Console({newestOnTop: false});
- console.render('#log');
-
- Y.on('domready', function() {
- Y.Test.Runner.run();
- });
-});
-
+ ];
+
+ // We patch Launchpad client to return some fake data for the patch
+ // operation.
+ Y.lp.client.Launchpad = function() {};
+ Y.lp.client.Launchpad.prototype.patch =
+ function(uri, representation, config, headers) {
+ // our setup assumes success, so we just do the success
+ // callback.
+ var entry_repr = {
+ 'lp_html': {'test_link': '<a href="/~me">Content</a>'}
+ };
+ var result = new Y.lp.client.Entry(
+ null, entry_repr, "a_self_link");
+ config.on.success(result);
+ };
+ },
+
+ tearDown: function() {
+ cleanup_widget(this.picker);
+ delete window.LP;
+ },
+
+ create_picker: function(
+ show_assign_me_button, show_remove_button, field_value) {
+ if (field_value !== undefined) {
+ var data_box = Y.one('#picker_id .yui3-activator-data-box');
+ data_box.appendChild(Y.Node.create('<a>Content</a>'));
+ data_box.one('a').set('href', field_value);
+ }
+ if (show_assign_me_button === undefined) {
+ show_assign_me_button = false;
+ }
+ if (show_remove_button === undefined) {
+ show_remove_button = false;
+ }
+
+ var config = {
+ "step_title": "Choose someone",
+ "header": "Pick Someone",
+ "validate_callback": null,
+ "show_search_box": true,
+ "show_assign_me_button": show_assign_me_button,
+ "show_remove_button": show_remove_button,
+ "assign_button_text": "Assign Moi",
+ "remove_button_text": "Remove someone",
+ "picker_type": 'person'
+ };
+ this.picker = Y.lp.app.picker.addPickerPatcher(
+ this.vocabulary,
+ "foo/bar",
+ "test_link",
+ "picker_id",
+ config);
+ },
+
+ _check_button_state: function(btn_class, is_visible) {
+ var assign_me_button = Y.one(btn_class);
+ Assert.isNotNull(assign_me_button);
+ if (is_visible) {
+ Assert.isFalse(
+ assign_me_button.hasClass('yui3-picker-hidden'),
+ btn_class + " should be visible but is hidden");
+ } else {
+ Assert.isTrue(
+ assign_me_button.hasClass('yui3-picker-hidden'),
+ btn_class + " should be hidden but is visible");
+ }
+ },
+
+ _check_assign_me_button_state: function(is_visible) {
+ this._check_button_state('.yui-picker-assign-me-button', is_visible);
+ },
+
+ _check_remove_button_state: function(is_visible) {
+ this._check_button_state('.yui-picker-remove-button', is_visible);
+ },
+
+ test_render_with_links: function () {
+ // The extra buttons section exists when there are assign/remove links
+ this.create_picker(true, true);
+ this.picker.render();
+ this.picker.show();
+
+ Y.Assert.isNotNull(Y.one('.extra-form-buttons'));
+ Y.Assert.isNotUndefined(this.picker.assign_me_button);
+ Y.Assert.isNotUndefined(this.picker.remove_button);
+ },
+
+ test_render_without_links: function () {
+ // The extra buttons section doesn't exists when there no
+ // assign/remove links.
+ this.create_picker(false, false);
+ this.picker.render();
+ this.picker.show();
+
+ Y.Assert.isNotNull(Y.one('.extra-form-buttons'));
+ Y.Assert.isUndefined(this.picker.remove_button);
+ Y.Assert.isUndefined(this.picker.assign_me_button);
+ },
+
+ test_picker_assign_me_button_text: function() {
+ // The assign me button text is correct.
+ this.create_picker(true, true);
+ this.picker.render();
+ var assign_me_button = Y.one('.yui-picker-assign-me-button');
+ Assert.areEqual('Assign Moi', assign_me_button.get('innerHTML'));
+ },
+
+ test_picker_remove_button_text: function() {
+ // The remove button text is correct.
+ this.create_picker(true, true);
+ this.picker.render();
+ var remove_button = Y.one('.yui-picker-remove-button');
+ Assert.areEqual('Remove someone', remove_button.get('innerHTML'));
+ },
+
+ test_picker_has_assign_me_button: function() {
+ // The assign me button is shown.
+ this.create_picker(true, true);
+ this.picker.render();
+ this._check_assign_me_button_state(true);
+ },
+
+ test_picker_no_assign_me_button_unless_configured: function() {
+ // The assign me button is only rendered if show_assign_me_button
+ // config setting is true.
+ this.create_picker(false, true);
+ this.picker.render();
+ Assert.isNull(Y.one('.yui-picker-assign-me-button'));
+ },
+
+ test_picker_no_assign_me_button_if_value_is_me: function() {
+ // The assign me button is not shown if the picker is created for a
+ // field where the value is "me".
+ this.create_picker(true, true, this.ME);
+ this.picker.render();
+ this._check_assign_me_button_state(false);
+ },
+
+ test_picker_assign_me_button_hide_on_save: function() {
+ // The assign me button is shown initially but hidden if the picker
+ // saves a value equal to 'me'.
+ this.create_picker(true, true);
+ this._check_assign_me_button_state(true);
+ this.picker.set('results', this.vocabulary);
+ this.picker.render();
+ simulate(
+ this.picker.get('boundingBox').one('.yui3-picker-results'),
+ 'li:nth-child(1)', 'click');
+ this._check_assign_me_button_state(false);
+ },
+
+ test_picker_no_remove_button_if_null_value: function() {
+ // The remove button is not shown if the picker is created for a field
+ // which has a null value.
+ this.create_picker(true, true);
+ this.picker.render();
+ this._check_remove_button_state(false);
+ },
+
+ test_picker_has_remove_button_if_value: function() {
+ // The remove button is shown if the picker is created for a field
+ // which has a value.
+ this.create_picker(true, true, this.ME);
+ this.picker.render();
+ this._check_remove_button_state(true);
+ },
+
+ test_picker_no_remove_button_unless_configured: function() {
+ // The remove button is only rendered if show_remove_button setting is
+ // true.
+ this.create_picker(true, false, this.ME);
+ this.picker.render();
+ Assert.isNull(Y.one('.yui-picker-remove-button'));
+ },
+
+ test_picker_remove_button_clicked: function() {
+ // The remove button is hidden once a picker value has been removed.
+ // And the assign me button is shown.
+ this.create_picker(true, true, this.ME);
+ this.picker.render();
+ var remove = Y.one('.yui-picker-remove-button');
+ remove.simulate('click');
+ this._check_remove_button_state(false);
+ this._check_assign_me_button_state(true);
+ },
+
+ test_picker_assign_me_button_clicked: function() {
+ // The assign me button is hidden once it is clicked.
+ // And the remove button is shown.
+ this.create_picker(true, true);
+ this.picker.render();
+ var remove = Y.one('.yui-picker-assign-me-button');
+ remove.simulate('click');
+ this._check_remove_button_state(true);
+ this._check_assign_me_button_state(false);
+ },
+
+ test_search_field_focus: function () {
+ // The search field has focus when the picker is shown.
+ this.create_picker();
+ this.picker.render();
+ this.picker.hide();
+
+ var got_focus = false;
+ this.picker._search_input.on('focus', function(e) {
+ got_focus = true;
+ });
+ this.picker.show();
+ Y.Assert.isTrue(got_focus, "search input did not get focus.");
+ },
+
+ test_buttons_save: function () {
+ // The assign/remove links save the correct values.
+ this.picker = new Y.lazr.picker.PersonPicker();
+ this.picker.render();
+ this.picker.show();
+
+ // Patch the picker so the assign_me and remove methods can be
+ // tested.
+ var data = null;
+ this.picker.on('save', function (result) {
+ data = result.value;
+ });
+ var remove = Y.one('.yui-picker-remove-button');
+ remove.simulate('click');
+ Y.Assert.areEqual('', data);
+
+ var assign_me = Y.one('.yui-picker-assign-me-button');
+ assign_me.simulate('click');
+ Y.Assert.areEqual('me', data);
+ },
+
+ _change_results: function (picker, no_result) {
+ // simulates search by setting a value and the result
+ picker._search_input.set('value', 'foo');
+ if (no_result) {
+ picker.set('results', []);
+ } else {
+ picker.set('results', this.vocabulary);
+ }
+ },
+
+ test_buttons_vanish: function () {
+ // The assign/remove links are hidden when a search is performed.
+ this.create_picker(true, true);
+ this.picker.render();
+ this._change_results(this.picker, false);
+ Y.Assert.isTrue(this.picker._extra_buttons.hasClass('unseen'));
+
+ this._change_results(this.picker, true);
+ Y.Assert.isFalse(this.picker._extra_buttons.hasClass('unseen'));
+ }
+}));
+
+// Hook for the test runner to get test results.
+var handle_complete = function(data) {
+ window.status = '::::' + JSON.stringify(data);
+};
+Y.Test.Runner.on('complete', handle_complete);
+Y.Test.Runner.add(suite);
+
+var console = new Y.Console({newestOnTop: false});
+console.render('#log');
+
+Y.on('domready', function() {
+ Y.Test.Runner.run();
+});
+
+});
=== modified file 'lib/lp/app/javascript/tests/test_picker.html'
--- lib/lp/app/javascript/tests/test_picker.html 2011-06-09 08:39:57 +0000
+++ lib/lp/app/javascript/tests/test_picker.html 2011-07-05 04:21:00 +0000
@@ -15,14 +15,14 @@
<script type="text/javascript" src="../../../../canonical/launchpad/icing/lazr/build/testing/config.js"></script>
<script type="text/javascript" src="../../../../canonical/launchpad/icing/lazr/build/activator/activator.js"></script>
<script type="text/javascript" src="../../../../canonical/launchpad/icing/lazr/build/overlay/overlay.js"></script>
- <script type="text/javascript" src="../../../../canonical/launchpad/icing/lazr/build/picker/picker.js"></script>
<script type="text/javascript" src="../../../../canonical/launchpad/icing/lazr/build/anim/anim.js"></script>
<script type="text/javascript" src="../../../../canonical/launchpad/icing/lazr/build/lazr/lazr.js"></script>
<script type="text/javascript" src="../client.js"></script>
- <script type="text/javascript" src="../widgets.js"></script>
+ <script type="text/javascript" src="../picker_patcher.js"></script>
<!-- The module under test -->
- <script type="text/javascript" src="../picker.js"></script>
+ <script type="text/javascript" src="../../../../canonical/launchpad/icing/lazr/build/picker/picker.js"></script>
+ <script type="text/javascript" src="../../../../canonical/launchpad/icing/lazr/build/picker/person_picker.js"></script>
<!-- The test suite -->
<script type="text/javascript" src="test_picker.js"></script>
=== modified file 'lib/lp/app/javascript/tests/test_picker.js'
--- lib/lp/app/javascript/tests/test_picker.js 2011-06-28 17:04:35 +0000
+++ lib/lp/app/javascript/tests/test_picker.js 2011-07-05 04:21:00 +0000
@@ -6,7 +6,7 @@
combine: false,
fetchCSS: false
}).use('test', 'console', 'node', 'lp', 'lp.client', 'escape', 'event',
- 'event-focus', 'event-simulate', 'lazr.picker', 'lp.app.widgets',
+ 'event-focus', 'event-simulate', 'lazr.picker', 'lazr.person-picker',
'lp.app.picker', 'node-event-simulate',
function(Y) {
@@ -80,8 +80,6 @@
"step_title": "Choose someone",
"header": "Pick Someone",
"null_display_value": "Noone",
- "show_remove_button": true,
- "show_assign_me_button": true,
"validate_callback": validate_callback
});
},
@@ -90,7 +88,7 @@
// The picker can be instantiated.
this.create_picker();
Assert.isInstanceOf(
- Y.lp.app.widgets.Picker, this.picker,
+ Y.lazr.picker.Picker, this.picker,
"Picker failed to be instantiated");
},
@@ -144,7 +142,7 @@
'<input id="field.testfield" value="foo" />');
node = Y.one(document.body).appendChild(this.text_input);
this.create_picker();
- this.picker.plug(Y.lazr.TextFieldPickerPlugin,
+ this.picker.plug(Y.lazr.picker.TextFieldPickerPlugin,
{input_element: '[id="field.testfield"]'});
this.picker.set('results', this.vocabulary);
this.picker.render();
@@ -234,201 +232,6 @@
}));
/*
- * Test cases for assign and remove buttons.
- */
-suite.add(new Y.Test.Case({
-
- name: 'picker_assign_remove_button',
-
- setUp: function() {
- var i;
- this.vocabulary = new Array(121);
- for (i = 0; i <5; i++) {
- this.vocabulary[i] = {
- "value": "value-" + i,
- "title": "title-" + i,
- "css": "sprite-person",
- "description": "description-" + i,
- "api_uri": "~/fred-" + i};
- }
- this.ME = '/~me';
- window.LP = {
- links: {
- me: this.ME
- },
- cache: {}
- };
-
- // We patch Launchpad client to return some fake data for the patch
- // operation.
- Y.lp.client.Launchpad = function() {};
- Y.lp.client.Launchpad.prototype.patch =
- function(uri, representation, config, headers) {
- // our setup assumes success, so we just do the success
- // callback.
- var entry_repr = {
- 'lp_html': {'test_link': '<a href="/~me">Content</a>'}
- };
- var result = new Y.lp.client.Entry(
- null, entry_repr, "a_self_link");
- config.on.success(result);
- };
-
- },
-
- tearDown: function() {
- cleanup_widget(this.picker);
- delete window.LP;
- },
-
- create_picker: function(
- show_assign_me_button, show_remove_button, field_value) {
- if (field_value !== undefined) {
- var data_box = Y.one('#picker_id .yui3-activator-data-box');
- data_box.appendChild(Y.Node.create('<a>Content</a>'));
- data_box.one('a').set('href', field_value);
- }
-
- var config = {
- "step_title": "Choose someone",
- "header": "Pick Someone",
- "validate_callback": null,
- "show_search_box": true,
- "show_assign_me_button": show_assign_me_button,
- "show_remove_button": show_remove_button,
- "assign_button_text": "Assign Moi",
- "remove_button_text": "Remove someone"
- };
- this.picker = Y.lp.app.picker.addPickerPatcher(
- this.vocabulary,
- "foo/bar",
- "test_link",
- "picker_id",
- config);
- },
-
- _check_button_state: function(btn_class, is_visible) {
- var assign_me_button = Y.one(btn_class);
- Assert.isNotNull(assign_me_button);
- if (is_visible) {
- Assert.isFalse(
- assign_me_button.hasClass('yui3-picker-hidden'),
- btn_class + " should be visible but is hidden");
- } else {
- Assert.isTrue(
- assign_me_button.hasClass('yui3-picker-hidden'),
- btn_class + " should be hidden but is visible");
- }
- },
-
- _check_assign_me_button_state: function(is_visible) {
- this._check_button_state('.yui-picker-assign-me-button', is_visible);
- },
-
- _check_remove_button_state: function(is_visible) {
- this._check_button_state('.yui-picker-remove-button', is_visible);
- },
-
- test_picker_assign_me_button_text: function() {
- // The assign me button text is correct.
- this.create_picker(true, true);
- this.picker.render();
- var assign_me_button = Y.one('.yui-picker-assign-me-button');
- Assert.areEqual('Assign Moi', assign_me_button.get('innerHTML'));
- },
-
- test_picker_remove_button_text: function() {
- // The remove button text is correct.
- this.create_picker(true, true);
- this.picker.render();
- var remove_button = Y.one('.yui-picker-remove-button');
- Assert.areEqual('Remove someone', remove_button.get('innerHTML'));
- },
-
- test_picker_has_assign_me_button: function() {
- // The assign me button is shown.
- this.create_picker(true, true);
- this.picker.render();
- this._check_assign_me_button_state(true);
- },
-
- test_picker_no_assign_me_button_unless_configured: function() {
- // The assign me button is only rendered if show_assign_me_button
- // config setting is true.
- this.create_picker(false, true);
- this.picker.render();
- Assert.isNull(Y.one('.yui-picker-assign-me-button'));
- },
-
- test_picker_no_assign_me_button_if_value_is_me: function() {
- // The assign me button is not shown if the picker is created for a
- // field where the value is "me".
- this.create_picker(true, true, this.ME);
- this.picker.render();
- this._check_assign_me_button_state(false);
- },
-
- test_picker_assign_me_button_hide_on_save: function() {
- // The assign me button is shown initially but hidden if the picker
- // saves a value equal to 'me'.
- this.create_picker(true, true);
- this._check_assign_me_button_state(true);
- this.picker.set('results', this.vocabulary);
- this.picker.render();
- simulate(
- this.picker.get('boundingBox').one('.yui3-picker-results'),
- 'li:nth-child(1)', 'click');
- this._check_assign_me_button_state(false);
- },
-
- test_picker_no_remove_button_if_null_value: function() {
- // The remove button is not shown if the picker is created for a field
- // which has a null value.
- this.create_picker(true, true);
- this.picker.render();
- this._check_remove_button_state(false);
- },
-
- test_picker_has_remove_button_if_value: function() {
- // The remove button is shown if the picker is created for a field
- // which has a value.
- this.create_picker(true, true, this.ME);
- this.picker.render();
- this._check_remove_button_state(true);
- },
-
- test_picker_no_remove_button_unless_configured: function() {
- // The remove button is only rendered if show_remove_button setting is
- // true.
- this.create_picker(true, false, this.ME);
- this.picker.render();
- Assert.isNull(Y.one('.yui-picker-remove-button'));
- },
-
- test_picker_remove_button_clicked: function() {
- // The remove button is hidden once a picker value has been removed.
- // And the assign me button is shown.
- this.create_picker(true, true, this.ME);
- this.picker.render();
- var remove = Y.one('.yui-picker-remove-button');
- remove.simulate('click');
- this._check_remove_button_state(false);
- this._check_assign_me_button_state(true);
- },
-
- test_picker_assign_me_button_clicked: function() {
- // The assign me button is hidden once it is clicked.
- // And the remove button is shown.
- this.create_picker(true, true);
- this.picker.render();
- var remove = Y.one('.yui-picker-assign-me-button');
- remove.simulate('click');
- this._check_remove_button_state(true);
- this._check_assign_me_button_state(false);
- }
-}));
-
-/*
* Test cases for a picker with a large vocabulary.
*/
suite.add(new Y.Test.Case({
=== modified file 'lib/lp/app/widgets/templates/form-picker-macros.pt'
--- lib/lp/app/widgets/templates/form-picker-macros.pt 2011-07-01 10:56:28 +0000
+++ lib/lp/app/widgets/templates/form-picker-macros.pt 2011-07-05 04:21:00 +0000
@@ -60,7 +60,7 @@
}
});
}
- picker.plug(Y.lazr.TextFieldPickerPlugin,
+ picker.plug(Y.lazr.picker.TextFieldPickerPlugin,
{input_element: '[id=\x22${view/input_id}\x22]'});
return picker;
}
=== modified file 'lib/lp/bugs/javascript/tests/test_subscribers_list.html'
--- lib/lp/bugs/javascript/tests/test_subscribers_list.html 2011-06-16 13:50:58 +0000
+++ lib/lp/bugs/javascript/tests/test_subscribers_list.html 2011-07-05 04:21:00 +0000
@@ -23,9 +23,9 @@
<script type="text/javascript"
src="../../../app/javascript/lp-names.js"></script>
<script type="text/javascript"
- src="../../../app/javascript/picker.js"></script>
+ src="../../../app/javascript/picker_patcher.js"></script>
<script type="text/javascript"
- src="../../../app/javascript/widgets.js"></script>
+ src="../../../app/javascript/lazr/picker/person_picker.js"></script>
<!-- Pre-requisite -->
<script type="text/javascript"
Follow ups