launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #04514
[Merge] lp:~allenap/launchpad/packageset-picker into lp:launchpad
Gavin Panella has proposed merging lp:~allenap/launchpad/packageset-picker into lp:launchpad with lp:~allenap/launchpad/javascript-utils-2 as a prerequisite.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #814531 in Launchpad itself: "PackagesetPickerWidget does not consistently fire choicesChange events"
https://bugs.launchpad.net/launchpad/+bug/814531
For more details, see:
https://code.launchpad.net/~allenap/launchpad/packageset-picker/+merge/70762
This branch does the following:
- Change ChoiceListWidget to support a richer model of choices, like
SelectWidget. At the moment ChoiceListWidget uses the choice values
as labels too, and doesn't allow associating arbitrary data with
choices.
- Ensure that the selection is preserved, as much as possible, when
changing "choices".
- Reimplement ChoiceListWidget.remove_choices and .add_choices using
the attributes.
- ChoiceListWidget's "type" attribute should be changed to resemble
SelectWidget's "multiple" attribute. The implementation should use
checkboxes or radio buttons, but not expose that detail.
- Pay attention to events during the changes. Things like choiceChange
and choicesChange need to be fired consistently.
My next steps - before landing this change - will be:
- Change anything that depends on or inherits from SelectWidget to use
ChoiceListWidget.
- Remove SelectWidget.
--
https://code.launchpad.net/~allenap/launchpad/packageset-picker/+merge/70762
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~allenap/launchpad/packageset-picker into lp:launchpad.
=== modified file 'lib/lp/app/javascript/formwidgets/formwidgets.js'
--- lib/lp/app/javascript/formwidgets/formwidgets.js 2011-08-05 08:42:36 +0000
+++ lib/lp/app/javascript/formwidgets/formwidgets.js 2011-08-08 16:18:30 +0000
@@ -14,6 +14,10 @@
var namespace = Y.namespace('lp.app.formwidgets');
+var owns = Y.Object.owns,
+ values = Y.Object.values,
+ attrcaller = Y.lp.extras.attrcaller;
+
/**
* A form row matching that which LaunchpadForm presents, containing a
@@ -189,19 +193,19 @@
*/
choices: {
getter: function() {
- return this.fieldNode.all("li > input").get("value");
+ return this.fieldNode.all("li").map(
+ this._choiceFromNode, this);
},
setter: function(value, name) {
- var choices = Y.Array.unique(value).sort();
+ var compare = Y.bind(this._compareChoices, this);
+ var choices = this._convertChoices(value).sort(compare);
+ var create = Y.bind(this._nodeFromChoice, this);
var list = Y.Node.create("<ul />");
- var self = this;
- choices.forEach(
- function(choice) {
- var item = self._createChoice(choice);
- list.append(item);
- }
- );
+ var append = Y.bind(list.append, list);
+ choices.map(create).forEach(append);
+ var selection = this.get("choice");
this.fieldNode.empty().append(list);
+ this.set("choice", selection);
}
},
@@ -212,27 +216,32 @@
*/
choice: {
setter: function(value, name) {
- if (!Y.Lang.isArray(value)) {
- value = [value];
- }
- this.fieldNode.all("li > input").each(
- function(node) {
- node.set(
- "checked",
- value.indexOf(node.get("value")) >= 0);
- }
- );
+ if (value === null) {
+ // De-select everything.
+ this.fieldNode.all("li > input").set("checked", false);
+ }
+ else {
+ var choices = this._convertChoices(
+ Y.Lang.isArray(value) ? value : [value]);
+ var choicemap = {};
+ choices.forEach(
+ function(choice) {
+ choicemap[choice.value] = true;
+ }
+ );
+ this.fieldNode.all("li > input").each(
+ function(node) {
+ var checked = owns(choicemap, node.get("value"));
+ node.set("checked", checked);
+ }
+ );
+ }
},
getter: function() {
- var choice = [];
- this.fieldNode.all("li > input").each(
- function(node) {
- if (node.get("checked")) {
- choice.push(node.get("value"));
- }
- }
- );
- if (this.get("type") === "radio") {
+ var inputs = this.fieldNode.all("li > input:checked");
+ var nodes = inputs.map(attrcaller("ancestor"));
+ var choice = nodes.map(this._choiceFromNode, this);
+ if (!this.get("multiple")) {
if (choice.length === 0) {
choice = null;
}
@@ -248,14 +257,17 @@
},
/**
- * The input type to display. Choose from "checkbox" or "radio".
+ * Whether multiple choices can be made.
*
- * @property type
+ * @property multiple
*/
- type: {
- value: "checkbox",
+ multiple: {
+ value: true,
setter: function(value, name) {
- this.fieldNode.all("li > input").set("type", value);
+ value = value ? true : false;
+ var field_type = value ? "checkbox" : "radio";
+ this.fieldNode.all("li > input").set("type", field_type);
+ return value;
}
}
@@ -266,92 +278,129 @@
Y.extend(ChoiceListWidget, FormRowWidget, {
/**
- * Helper method to create an entry for the select widget.
- *
- * @method _createChoice
- */
- _createChoice: function(choice) {
- var field_name = this.get("name");
- var field_type = this.get("type");
- var item = Y.Node.create(
+ * Convert a "bare" choice into a object choice with text and
+ * value keys.
+ *
+ * @param {String|Object} choice
+ */
+ _convertChoice: function(choice) {
+ return Y.Lang.isString(choice) ?
+ {value: choice, text: choice} : choice;
+ },
+
+ /**
+ * Convert an array of choices using _convertChoice.
+ *
+ * @param {Array|Y.Array} choices
+ */
+ _convertChoices: function(choices) {
+ return Y.Array.map(choices, this._convertChoice, this);
+ },
+
+ /**
+ * Default method to sort choices.
+ *
+ * @param {Object|String} ca A choice. If it is an object it must
+ * contain a <code>text</code> attribute.
+ * @param {Object|String} cb A choice. If it is an object it must
+ * contain a <code>text</code> attribute.
+ */
+ _compareChoices: function(ca, cb) {
+ var keya = Y.Lang.isObject(ca) ? ca.text : ca,
+ keyb = Y.Lang.isObject(cb) ? cb.text : cb;
+ if (keya == keyb) {
+ return 0;
+ }
+ else {
+ return (keya > keyb) ? 1 : -1;
+ }
+ },
+
+ /**
+ * Return a node that represents the given choice object.
+ *
+ * @method _nodeFromChoice
+ */
+ _nodeFromChoice: function(choice) {
+ var field_name = this.get("name");
+ var field_type = this.get("multiple") ? "checkbox" : "radio";
+ var item = Y.Node.create(
"<li><input /> <label /></li>");
item.one("input")
.set("type", field_type)
.set("name", field_name)
- .set("value", choice);
+ .set("value", choice.value);
item.one("label")
.setAttribute(
"for", item.one("input").generateID())
.setStyle("font-weight", "normal")
- .set("text", choice);
+ .set("text", choice.text);
+ item.setData(choice.data);
return item;
},
- /**
+ /**
+ * Return a choice object represented by the given node.
+ *
+ * @method _choiceFromNode
+ */
+ _choiceFromNode: function(node) {
+ return {
+ data: node.getData(),
+ text: node.one("label").get("text"),
+ value: node.one("input").get("value")
+ };
+ },
+
+ /**
* Remove a list of choices from the possible widget's choices.
*
* @method remove_choices
*/
remove_choices: function(choices) {
- choices.forEach(
+ var choicemap = {};
+ // Create a mapping of value -> choice for the given choices.
+ this._convertChoices(choices).forEach(
function(choice) {
- this.fieldNode.all("select > option").each(
- function(option) { options.push(option); });
- this.fieldNode.all(
- "li input[value=" + choice + "]").each(
- function(li_input) {
- li_input.get('parentNode').remove();
- }
- );
- },
- this
+ choicemap[choice.value] = true;
+ }
);
+ // Filter out the choices mentioned.
+ choices = this.get("choices").filter(function(choice) {
+ return !owns(choicemap, choice.value);
+ });
+ // Set back again.
+ this.set("choices", choices);
+ // Tell everyone!
Y.lazr.anim.green_flash({node: this.fieldNode}).run();
},
- _sorted_position: function(choice) {
- var options = [];
- this.fieldNode.all("input").each(
- function(node) {
- options.push(node.get('value'));
- }
- );
- options.push(choice);
- return options.sort().indexOf(choice);
- },
-
- /**
+ /**
* Add new choices (if they are not already present).
*
* @method add_choices
*/
- add_choices: function(new_choices) {
- new_choices.forEach(
+ add_choices: function(choices) {
+ var choicemap = {};
+ // Create a mapping of value -> choice for the given choices.
+ this._convertChoices(choices).forEach(
function(choice) {
- if (this.fieldNode.all(
- "li > input[value=" + choice + "]").isEmpty()) {
- var list = this.fieldNode.one('ul');
- if (list === null) {
- list = Y.Node.create("<ul />");
- this.fieldNode.empty().append(list);
- }
- var option = this._createChoice(choice);
- var options = list.all('input');
- if (options.isEmpty()) {
- list.append(option);
- }
- else {
- var pos = this._sorted_position(choice);
- if (pos === 0) {
- list.prepend(option);
- }
- else {
- list.insertBefore(option, options.item(pos));
- }
- }
- }
- }, this
+ choicemap[choice.value] = choice;
+ }
);
+ // Allow existing choices to be redefined.
+ choices = this.get("choices").map(function(choice) {
+ if (owns(choicemap, choice.value)) {
+ choice = choicemap[choice.value];
+ delete choicemap[choice.value];
+ }
+ return choice;
+ });
+ // Add the new choices (i.e. what remains in choicemap).
+ choices = choices.concat(values(choicemap));
+ // Set back again.
+ this.set("choices", choices);
+ // Tell everyone!
Y.lazr.anim.green_flash({node: this.fieldNode}).run();
}
=== modified file 'lib/lp/app/javascript/formwidgets/tests/test_formwidgets.js'
--- lib/lp/app/javascript/formwidgets/tests/test_formwidgets.js 2011-08-05 08:54:55 +0000
+++ lib/lp/app/javascript/formwidgets/tests/test_formwidgets.js 2011-08-08 16:18:30 +0000
@@ -44,7 +44,7 @@
Y.Node.create("<input /><input />"));
this.widget.set("name", "field");
this.widget.render(this.container);
- ArrayAssert.itemsAreEqual(
+ ArrayAssert.itemsAreSame(
["field", "field"],
this.container.all("input").get("name"));
},
@@ -55,7 +55,7 @@
this.widget.set("name", "field");
this.widget.render(this.container);
this.widget.set("name", "plain");
- ArrayAssert.itemsAreEqual(
+ ArrayAssert.itemsAreSame(
["plain", "plain"],
this.container.all("input").get("name"));
},
@@ -63,7 +63,7 @@
testRenderLabel: function() {
this.widget.set("label", "Test label");
this.widget.render(this.container);
- Assert.areEqual(
+ Assert.areSame(
"Test label",
this.container.one("label").get("text"));
},
@@ -72,7 +72,7 @@
this.widget.set("label", "Test label");
this.widget.render(this.container);
this.widget.set("label", "Another label");
- Assert.areEqual(
+ Assert.areSame(
"Another label",
this.container.one("label").get("text"));
},
@@ -80,7 +80,7 @@
testRenderDescription: function() {
this.widget.set("description", "Test description.");
this.widget.render(this.container);
- Assert.areEqual(
+ Assert.areSame(
"Test description.",
this.container.one("p.formHelp").get("text"));
},
@@ -89,7 +89,7 @@
this.widget.set("description", "Test description.");
this.widget.render(this.container);
this.widget.set("description", "Another description.");
- Assert.areEqual(
+ Assert.areSame(
"Another description.",
this.container.one("p.formHelp").get("text"));
},
@@ -100,11 +100,11 @@
this.widget.render(this.container);
Assert.isFalse(this.container
.one('span.helper').hasClass("unseen"));
- Assert.areEqual(
+ Assert.areSame(
"Help text",
this.container.one("a")
.one('span.invisible-link').get("text"));
- Assert.areEqual(
+ Assert.areSame(
"http://test.com/test.html",
this.container.one("a").get('href'));
},
@@ -113,10 +113,10 @@
this.widget.set("help",
{link: "http://test.com/test.html", text: "Help text"});
this.widget.render(this.container);
- Assert.areEqual(
+ Assert.areSame(
"http://test.com/test.html",
this.widget.get("help").link);
- Assert.areEqual(
+ Assert.areSame(
"Help text",
this.widget.get("help").text);
},
@@ -128,11 +128,11 @@
this.widget.set(
"help",
{link: "http://test.com/test2.html", text: "Help text2"});
- Assert.areEqual(
+ Assert.areSame(
"Help text2",
this.container.one("a")
.one('span.invisible-link').get("text"));
- Assert.areEqual(
+ Assert.areSame(
"http://test.com/test2.html",
this.container.one("a").get('href'));
},
@@ -159,7 +159,7 @@
testShowError: function() {
this.widget.showError("Unrealistic expectations.");
- Assert.areEqual(
+ Assert.areSame(
"Unrealistic expectations.",
this.widget.fieldNode.one("p").get("text"));
}
@@ -180,90 +180,204 @@
this.container.remove(true);
},
+ testCompareChoices: function() {
+ // _compareChoices can compare objects or strings.
+ var widget = this.widget;
+ var comparisons = [
+ // String comparisons.
+ {ca: "foo", cb: "foo", expected: +0},
+ {ca: "foo", cb: "bar", expected: +1},
+ {ca: "bar", cb: "foo", expected: -1},
+ // Object comparisons.
+ {ca: {text: "foo"}, cb: {text: "foo"}, expected: +0},
+ {ca: {text: "foo"}, cb: {text: "bar"}, expected: +1},
+ {ca: {text: "bar"}, cb: {text: "foo"}, expected: -1},
+ // Mixed comparisons.
+ {ca: {text: "foo"}, cb: "foo", expected: +0},
+ {ca: "foo", cb: {text: "foo"}, expected: +0},
+ {ca: {text: "foo"}, cb: "bar", expected: +1},
+ {ca: "foo", cb: {text: "bar"}, expected: +1},
+ {ca: {text: "bar"}, cb: "foo", expected: -1},
+ {ca: "bar", cb: {text: "foo"}, expected: -1}
+ ];
+ Y.each(comparisons, function(comparison) {
+ Assert.areSame(
+ comparison.expected,
+ widget._compareChoices(
+ comparison.ca, comparison.cb));
+ });
+ },
+
testRenderChoices: function() {
this.widget.set("choices", ["a", "b"]);
this.widget.render(this.container);
- ArrayAssert.itemsAreEqual(
+ ArrayAssert.itemsAreSame(
["a", "b"],
this.container.all("li > input").get("value"));
- ArrayAssert.itemsAreEqual(
+ ArrayAssert.itemsAreSame(
["a", "b"],
this.container.all("li > label").get("text"));
- ArrayAssert.itemsAreEqual(
+ ArrayAssert.itemsAreSame(
["checkbox", "checkbox"],
this.container.all("li > input").getAttribute("type"));
},
+ testRenderObjectChoices: function() {
+ var choices = [
+ {value: "a", text: "A", data: "aaa"},
+ {value: "b", text: "B", data: "bbb"}
+ ];
+ this.widget.set("choices", choices);
+ this.widget.render(this.container);
+ ArrayAssert.itemsAreSame(
+ ["a", "b"],
+ this.container.all("li > input").get("value"));
+ ArrayAssert.itemsAreSame(
+ ["A", "B"],
+ this.container.all("li > label").get("text"));
+ var items = [];
+ this.container.all("li").each(
+ function(node) { items.push(node); });
+ ArrayAssert.itemsAreSame(
+ ["aaa", "bbb"],
+ this.container.all("li").map(
+ function(node) { return node.getData(); }));
+ },
+
testRenderChoicesChange: function() {
this.widget.set("choices", ["a", "b"]);
this.widget.render(this.container);
this.widget.set("choices", ["c", "d", "e"]);
- ArrayAssert.itemsAreEqual(
+ ArrayAssert.itemsAreSame(
["c", "d", "e"],
this.container.all("li > input").get("value"));
- ArrayAssert.itemsAreEqual(
+ ArrayAssert.itemsAreSame(
["c", "d", "e"],
this.container.all("li > label").get("text"));
},
- testRenderAddChoices: function() {
+ testRenderAddChoices: function() {
this.widget.add_choices(["a", "b"]);
this.widget.render(this.container);
- ArrayAssert.itemsAreEqual(
+ ArrayAssert.itemsAreSame(
["a", "b"],
this.container.all("li > input").get("value"));
- ArrayAssert.itemsAreEqual(
+ ArrayAssert.itemsAreSame(
["a", "b"],
this.container.all("li > label").get("text"));
- ArrayAssert.itemsAreEqual(
+ ArrayAssert.itemsAreSame(
["checkbox", "checkbox"],
this.container.all("li > input").getAttribute("type"));
},
testRenderRemoveChoices: function() {
- this.widget.add_choices(["a", "b", "c", "d"]);
+ this.widget.set("choices", ["a", "b", "c", "d"]);
this.widget.render(this.container);
this.widget.remove_choices(["b", "d"]);
- ArrayAssert.itemsAreEqual(
+ ArrayAssert.itemsAreSame(
["a", "c"],
this.container.all("li > input").get("value"));
- ArrayAssert.itemsAreEqual(
+ ArrayAssert.itemsAreSame(
["a", "c"],
this.container.all("li > label").get("text"));
},
- testRenderChoicesChangeType: function() {
+ testRenderChoicesChangeMultiple: function() {
this.widget.set("choices", ["a", "b"]);
this.widget.render(this.container);
- this.widget.set("type", "radio");
- ArrayAssert.itemsAreEqual(
+ this.widget.set("multiple", false);
+ ArrayAssert.itemsAreSame(
["radio", "radio"],
this.container.all("li > input").getAttribute("type"));
-
+ },
+
+ testChoicesWithStrings: function() {
+ /* The choices attribute should be an array, and it may
+ contain unadorned strings. However, it always returns
+ object choices in sorted order. */
+ ArrayAssert.itemsAreSame(
+ [], this.widget.get("choices"));
+ this.widget.set("choices", ["foo", "bar"]);
+ var choices = this.widget.get("choices");
+ choices.forEach(function(choice) {
+ Assert.isObject(choice);
+ Assert.areSame(choice.text, choice.value);
+ });
+ ArrayAssert.itemsAreSame(
+ ["bar", "foo"], attrselect("text")(choices));
+ ArrayAssert.itemsAreSame(
+ ["bar", "foo"], attrselect("value")(choices));
+ },
+
+ testChoicesWithObjects: function() {
+ /* The choices attribute should be an array, and it may
+ contain objects with text and value keys. It always
+ returns object choices in order, sorted by text. */
+ ArrayAssert.itemsAreSame(
+ [], this.widget.get("choices"));
+ this.widget.set("choices", [
+ {text: "Bbb", value: "xxx"},
+ {text: "Aaa", value: "zzz"}
+ ]);
+ var choices = this.widget.get("choices");
+ choices.forEach(function(choice) {
+ Assert.isObject(choice);
+ });
+ ArrayAssert.itemsAreSame(
+ ["Aaa", "Bbb"], attrselect("text")(choices));
+ ArrayAssert.itemsAreSame(
+ ["zzz", "xxx"], attrselect("value")(choices));
+ },
+
+ testChoicesWithObjectsAndData: function() {
+ /* The choices attribute should be an array. The objects
+ it contains can optionally have a data key which is
+ stored and returned when referencing the choices
+ attribute. */
+ ArrayAssert.itemsAreSame(
+ [], this.widget.get("choices"));
+ this.widget.set("choices", [
+ {text: "Bbb", value: "xxx", data: 123},
+ {text: "Aaa", value: "zzz", data: 456}
+ ]);
+ var choices = this.widget.get("choices");
+ ArrayAssert.itemsAreSame(
+ [456, 123], attrselect("data")(choices));
+ },
+
+ testChoicesPreservesSelection: function() {
+ /* Setting new choices preserves, as much as possible, the
+ existing selection. */
+ this.widget.set("choices", ["a", "b", "c"]);
+ this.widget.set("choice", ["a", "c"]);
+ this.widget.set("choices", ["a", "b", "d"]);
+ var choice = this.widget.get("choice");
+ ArrayAssert.itemsAreSame(
+ ["a"], attrselect("value")(choice));
},
testChoiceWithCheckBox: function() {
this.widget
- .set("type", "checkbox")
+ .set("multiple", true)
.set("choices", ["a", "b"]);
- ArrayAssert.itemsAreEqual(
+ ArrayAssert.itemsAreSame(
[], this.widget.get("choice"));
this.widget.fieldNode.one("input[value=a]")
.set("checked", "checked");
- ArrayAssert.itemsAreEqual(
- ["a"], this.widget.get("choice"));
+ ArrayAssert.itemsAreSame(
+ ["a"], attrselect("value")(this.widget.get("choice")));
},
testChoiceWithRadio: function() {
// When both radio buttons are checked (this is possible in some
// broken DOMs/JS engined), choice is undefined.
this.widget
- .set("type", "radio")
+ .set("multiple", false)
.set("choices", ["a", "b"]);
Assert.isNull(this.widget.get("choice"));
this.widget.fieldNode.one("input[value=a]")
.set("checked", "checked");
- Assert.areEqual("a", this.widget.get("choice"));
+ Assert.areSame("a", this.widget.get("choice").value);
this.widget.fieldNode.one("input[value=b]")
.set("checked", "checked");
if (this.widget.fieldNode.one("input[value=a]").get("checked")) {
@@ -273,42 +387,84 @@
}
else {
// The host browser's DOM/JS is sane.
- ArrayAssert.itemsAreEqual(
- ["b"], this.widget.get("choice"));
+ ArrayAssert.itemsAreSame(
+ ["b"], this.widget.get("choice").value);
}
},
testSetChoiceWithCheckBox: function() {
this.widget
- .set("type", "checkbox")
+ .set("multiple", true)
.set("choices", ["a", "b"])
.set("choice", "a");
- ArrayAssert.itemsAreEqual(
- ["a"], this.widget.get("choice"));
+ ArrayAssert.itemsAreSame(
+ ["a"], attrselect("value")(this.widget.get("choice")));
this.widget.set("choice", ["a"]);
- ArrayAssert.itemsAreEqual(
- ["a"], this.widget.get("choice"));
+ ArrayAssert.itemsAreSame(
+ ["a"], attrselect("value")(this.widget.get("choice")));
this.widget.set("choice", ["a", "b"]);
- ArrayAssert.itemsAreEqual(
- ["a", "b"], this.widget.get("choice"));
+ ArrayAssert.itemsAreSame(
+ ["a", "b"], attrselect("value")(this.widget.get("choice")));
this.widget.set("choice", ["b", "c"]);
- ArrayAssert.itemsAreEqual(
- ["b"], this.widget.get("choice"));
+ ArrayAssert.itemsAreSame(
+ ["b"], attrselect("value")(this.widget.get("choice")));
},
testSetChoiceWithRadio: function() {
this.widget
- .set("type", "radio")
+ .set("multiple", false)
.set("choices", ["a", "b"])
.set("choice", "a");
- ArrayAssert.itemsAreEqual(
- "a", this.widget.get("choice"));
+ ArrayAssert.itemsAreSame(
+ "a", this.widget.get("choice").value);
this.widget.set("choice", ["a"]);
- ArrayAssert.itemsAreEqual(
- "a", this.widget.get("choice"));
+ ArrayAssert.itemsAreSame(
+ "a", this.widget.get("choice").value);
this.widget.set("choice", "b");
- ArrayAssert.itemsAreEqual(
- "b", this.widget.get("choice"));
+ ArrayAssert.itemsAreSame(
+ "b", this.widget.get("choice").value);
+ },
+
+ testSetChoiceWithObjectChoice: function() {
+ /* An object choice (i.e. an object with text, value and
+ optional data members) can be passed into when setting
+ the choice attribute. Only the value is considered. */
+ this.widget
+ .set("multiple", false)
+ .set("choices", ["a", "b"])
+ .set("choice", {text: "A", value: "a"});
+ ArrayAssert.itemsAreSame(
+ "a", this.widget.get("choice").value);
+ },
+
+ testAddChoicesEvents: function() {
+ /* Calling add_choices() causes choicesChange and
+ choiceChange events to fire. */
+ var events = [], push = Y.bind(events.push, events);
+ this.widget.after("choicesChange", push);
+ this.widget.after("choiceChange", push);
+ this.widget.add_choices(["a", "b"]);
+ ArrayAssert.containsMatch(
+ function(event) { return event.attrName == "choice"; },
+ events);
+ ArrayAssert.containsMatch(
+ function(event) { return event.attrName == "choices"; },
+ events);
+ },
+
+ testRemoveChoicesEvents: function() {
+ /* Calling remove_choices() causes choicesChange and
+ choiceChange events to fire. */
+ var events = [], push = Y.bind(events.push, events);
+ this.widget.after("choicesChange", push);
+ this.widget.after("choiceChange", push);
+ this.widget.remove_choices(["a", "b"]);
+ ArrayAssert.containsMatch(
+ function(event) { return event.attrName == "choice"; },
+ events);
+ ArrayAssert.containsMatch(
+ function(event) { return event.attrName == "choices"; },
+ events);
}
};
@@ -340,10 +496,10 @@
.set("name", "foo")
.set("choices", this.choices);
var select = this.widget.fieldNode.one("select");
- Assert.areEqual("foo", select.get("name"));
+ Assert.areSame("foo", select.get("name"));
this.widget
.set("name", "bar");
- Assert.areEqual("bar", select.get("name"));
+ Assert.areSame("bar", select.get("name"));
},
testChoices: function() {
@@ -351,13 +507,13 @@
var choices_observed = this.widget.get("choices");
/* We have to compare bit by bit ourselves because
Javascript is a language born in hell. */
- ArrayAssert.itemsAreEqual(
+ ArrayAssert.itemsAreSame(
attrselect("value")(this.choices),
attrselect("value")(choices_observed));
- ArrayAssert.itemsAreEqual(
+ ArrayAssert.itemsAreSame(
attrselect("text")(this.choices),
attrselect("text")(choices_observed));
- ArrayAssert.itemsAreEqual(
+ ArrayAssert.itemsAreSame(
attrselect("data")(this.choices),
attrselect("data")(choices_observed));
},
@@ -365,10 +521,10 @@
testRenderChoices: function() {
this.widget.set("choices", this.choices);
this.widget.render(this.container);
- ArrayAssert.itemsAreEqual(
+ ArrayAssert.itemsAreSame(
["a", "b", "c"],
this.container.all("select > option").get("value"));
- ArrayAssert.itemsAreEqual(
+ ArrayAssert.itemsAreSame(
["A", "B", "C"],
this.container.all("select > option").get("text"));
},
@@ -392,10 +548,10 @@
{value: "c", text: "C", data: 789}
];
this.widget.set("choices", choices2);
- ArrayAssert.itemsAreEqual(
+ ArrayAssert.itemsAreSame(
["b", "c"],
this.container.all("select > option").get("value"));
- ArrayAssert.itemsAreEqual(
+ ArrayAssert.itemsAreSame(
["B", "C"],
this.container.all("select > option").get("text"));
},
@@ -408,15 +564,15 @@
but this appears impossible; the browser seems to
select the first option when rendering. */
this.widget.fieldNode.all("option").set("selected", false);
- ArrayAssert.itemsAreEqual(
+ ArrayAssert.itemsAreSame(
[], this.widget.get("choice"));
this.widget.fieldNode.one("option[value=a]")
.set("selected", true);
- ArrayAssert.itemsAreEqual(
+ ArrayAssert.itemsAreSame(
["a"], this.widget.get("choice"));
this.widget.fieldNode.one("option[value=c]")
.set("selected", true);
- ArrayAssert.itemsAreEqual(
+ ArrayAssert.itemsAreSame(
["a", "c"], this.widget.get("choice"));
},
@@ -425,21 +581,21 @@
.set("multiple", true)
.set("choices", this.choices)
.set("choice", "a");
- ArrayAssert.itemsAreEqual(
+ ArrayAssert.itemsAreSame(
["a"], this.widget.get("choice"));
this.widget.set("choice", ["a"]);
- ArrayAssert.itemsAreEqual(
+ ArrayAssert.itemsAreSame(
["a"], this.widget.get("choice"));
this.widget.set("choice", ["a", "b"]);
- ArrayAssert.itemsAreEqual(
+ ArrayAssert.itemsAreSame(
["a", "b"], this.widget.get("choice"));
this.widget.set("choice", ["b", "z"]);
- ArrayAssert.itemsAreEqual(
+ ArrayAssert.itemsAreSame(
["b"], this.widget.get("choice"));
},
testSize: function() {
- Assert.areEqual(1, this.widget.get("size"));
+ Assert.areSame(1, this.widget.get("size"));
},
testRenderSize: function() {
@@ -447,7 +603,7 @@
.set("choices", this.choices)
.set("size", 7)
.render(this.container);
- Assert.areEqual(
+ Assert.areSame(
7, this.widget.fieldNode.one("select").get("size"));
},
@@ -457,7 +613,7 @@
.set("size", 3)
.render(this.container)
.set("size", 5);
- Assert.areEqual(
+ Assert.areSame(
5, this.widget.fieldNode.one("select").get("size"));
},
@@ -466,7 +622,7 @@
/* Without argument, autoSize() sets the size to the same
as the number of choices. */
this.widget.autoSize();
- Assert.areEqual(3, this.widget.get("size"));
+ Assert.areSame(3, this.widget.get("size"));
},
testAutoSizeMoreChoicesThanMaxiumum: function() {
@@ -475,7 +631,7 @@
choices unless there are more than the specified
maximum. */
this.widget.autoSize(2);
- Assert.areEqual(2, this.widget.get("size"));
+ Assert.areSame(2, this.widget.get("size"));
},
testAutoSizeFewerChoicesThanMaxiumum: function() {
@@ -483,11 +639,11 @@
/* autoSize() sets the size to the same as the number of
choices. */
this.widget.autoSize(5);
- Assert.areEqual(3, this.widget.get("size"));
+ Assert.areSame(3, this.widget.get("size"));
},
testMultiple: function() {
- Assert.areEqual(false, this.widget.get("multiple"));
+ Assert.areSame(false, this.widget.get("multiple"));
},
testRenderMultiple: function() {
@@ -567,7 +723,7 @@
testShowError: function() {
this.widget.showError("The Man From U.N.C.L.E.");
- Assert.areEqual(
+ Assert.areSame(
"The Man From U.N.C.L.E.",
this.actions.one("p.error.message").get("text"));
},
Follow ups