Skip to content
Browse files

gallery-2011.06.15-19-18 ghinch gallery-form

  • Loading branch information...
1 parent e2cc5b9 commit 796eed03dc492fbe62c460305087250b719f09ab YUI Builder committed Jun 15, 2011
View
57 src/gallery-form/js/button.js
@@ -1,13 +1,7 @@
Y.FormButton = Y.Base.create('button-field', Y.FormField, [Y.WidgetChild], {
- _renderButtonNode : function () {
- var contentBox = this.get('contentBox'), bn;
-
- bn = Y.Node.create(Y.FormButton.NODE_TEMPLATE);
- contentBox.appendChild(bn);
- this._fieldNode = bn;
- },
- _syncLabelNode: function () {},
+ FIELD_TEMPLATE : '<button></button>',
+ LABEL_TEMPLATE: '',
_syncFieldNode : function () {
this._fieldNode.setAttrs({
@@ -23,17 +17,26 @@ Y.FormButton = Y.Base.create('button-field', Y.FormField, [Y.WidgetChild], {
return;
}
- var oc = this.get('onclick');
Y.Event.purgeElement(this._fieldNode, true, 'click');
- Y.on('click', Y.bind(oc.fn, oc.scope, true), this._fieldNode);
+ Y.on('click', Y.bind(this._promptConfirm, this), this._fieldNode);
},
- renderUI : function () {
- this._renderButtonNode();
+ _promptConfirm: function(event) {
+ event.preventDefault();
+ var message = this.get("message"),
+ onclick = this.get("onclick");
+
+ if (message) {
+ if (!this.get("confirm")(message)) {
+ return;
+ }
+ }
+ onclick.fn.apply(onclick.scope);
},
bindUI : function () {
this.after('onclickChange', Y.bind(this._setClickHandler, this, true));
+ this.after('disabledChange', this._syncDisabled, this);
this._setClickHandler();
}
}, {
@@ -59,8 +62,32 @@ Y.FormButton = Y.Base.create('button-field', Y.FormField, [Y.WidgetChild], {
val.argument = val.argument || {};
return val;
}
- }
- },
+ },
+
+ /**
+ * @attribute message
+ * @type String
+ * @default null
+ * @description Optional confirmation message to be passed to the
+ * confirm function.
+ */
+ message: {
+ validator : Y.Lang.isString,
+ value: null
+ },
- NODE_TEMPLATE : '<button></button>'
+ /**
+ * @attribute confirm
+ * @type Function
+ * @default null
+ * @description Optional confirmation function called when the button
+ * is clicked. It will be be passed the string set in the 'message'
+ * attribute. If it returns 'true' the the onclick handler will be
+ * called, otherwise it will be skipped.
+ */
+ confirm: {
+ validator : Y.Lang.isFunction,
+ value: null
+ }
+ }
});
View
41 src/gallery-form/js/choice-field.js
@@ -7,6 +7,11 @@
* selection of choices
*/
Y.ChoiceField = Y.Base.create('choice-field', Y.FormField, [Y.WidgetParent, Y.WidgetChild], {
+
+ LABEL_TEMPLATE: '<span></span>',
+ SINGLE_CHOICE: Y.RadioField,
+ MULTI_CHOICE: Y.CheckboxField,
+
/**
* @method _validateChoices
* @protected
@@ -45,22 +50,16 @@ Y.ChoiceField = Y.Base.create('choice-field', Y.FormField, [Y.WidgetParent, Y.Wi
return true;
},
- _renderLabelNode: function() {
- var contentBox = this.get('contentBox'),
- titleNode = Y.Node.create('<span></span>');
-
- titleNode.set('innerHTML', this.get('label'));
- contentBox.appendChild(titleNode);
-
- this._labelNode = titleNode;
- },
-
_renderFieldNode: function() {
var contentBox = this.get('contentBox'),
- choices = this.get('choices'),
- multiple = this.get('multi'),
- fieldType = (multiple === true ? Y.CheckboxField: Y.RadioField);
+ parent = contentBox.one("." + this.FIELD_CLASS),
+ choices = this.get('choices'),
+ multiple = this.get('multi'),
+ fieldType = (multiple === true ? this.MULTI_CHOICE: this.SINGLE_CHOICE);
+ if (!parent) {
+ parent = contentBox;
+ }
Y.Array.each(choices,
function(c, i, a) {
var cfg = {
@@ -71,9 +70,9 @@ Y.ChoiceField = Y.Base.create('choice-field', Y.FormField, [Y.WidgetParent, Y.Wi
},
field = new fieldType(cfg);
- field.render(contentBox);
+ field.render(parent);
}, this);
- this._fieldNode = contentBox.all('input');
+ this._fieldNode = parent.all('input');
},
_syncFieldNode: function() {
@@ -91,6 +90,17 @@ Y.ChoiceField = Y.Base.create('choice-field', Y.FormField, [Y.WidgetParent, Y.Wi
}
},
+ /**
+ * @method _afterChoiceChange
+ * @description When the available choices for the choice field change,
+ * the old ones are removed and the new ones are rendered.
+ */
+ _afterChoicesChange: function(event) {
+ var contentBox = this.get("contentBox");
+ contentBox.all(".yui3-form-field").remove();
+ this._renderFieldNode();
+ },
+
clear: function() {
this._fieldNode.each(function(node, index, list) {
node.set('checked', false);
@@ -114,6 +124,7 @@ Y.ChoiceField = Y.Base.create('choice-field', Y.FormField, [Y.WidgetParent, Y.Wi
this.set('value', value);
},
this));
+ this.after('choicesChange', this._afterChoicesChange);
}
},
View
16 src/gallery-form/js/file-field.js
@@ -6,18 +6,4 @@
* @description A file field node
*/
-Y.FileField = Y.Base.create('file-field', Y.FormField, [Y.WidgetChild], {
- _renderFieldNode : function () {
- var contentBox = this.get('contentBox'),
- field = contentBox.one('#' + this.get('id'));
-
- if (!field) {
- field = Y.Node.create(Y.FileField.FILE_INPUT_TEMPLATE);
- contentBox.appendChild(field);
- }
-
- this._fieldNode = field;
- }
-}, {
- FILE_INPUT_TEMPLATE : '<input type="file" />'
-});
+Y.FileField = Y.Base.create('file-field', Y.FormField, [Y.WidgetChild]);
View
192 src/gallery-form/js/form-field.js
@@ -10,6 +10,68 @@ Y.FormField = Y.Base.create('form-field', Y.Widget, [Y.WidgetParent, Y.WidgetChi
toString: function() {
return this.name;
},
+
+ /**
+ * @property FormField.FIELD_TEMPLATE
+ * @type String
+ * @description Template used to render the field node
+ */
+ FIELD_TEMPLATE : '<input></input>',
+
+ /**
+ * @property FormField.FIELD_CLASS
+ * @type String
+ * @description CSS class used to locate a placeholder for
+ * the field node and style it.
+ */
+ FIELD_CLASS : 'field',
+
+ /**
+ * @property FormField.LABEL_TEMPLATE
+ * @type String
+ * @description Template used to draw a label node
+ */
+ LABEL_TEMPLATE : '<label></label>',
+
+ /**
+ * @property FormField.LABEL_CLASS
+ * @type String
+ * @description CSS class used to locate a placeholder for
+ * the label node and style it.
+ */
+ LABEL_CLASS : 'label',
+
+ /**
+ * @property FormField.HINT_TEMPLATE
+ * @type String
+ * @description Optionally a template used to draw a hint node. Derived
+ * classes can use it to provide additional information about the field
+ */
+ HINT_TEMPLATE : '',
+
+ /**
+ * @property FormField.HINT_CLASS
+ * @type String
+ * @description CSS class used to locate a placeholder for
+ * the hint node and style it.
+ */
+ HINT_CLASS : 'hint',
+
+ /**
+ * @property FormField.ERROR_TEMPLATE
+ * @type String
+ * @description Template used to draw an error node
+ */
+ ERROR_TEMPLATE : '<span></span>',
+
+ /**
+ * @property FormField.ERROR_CLASS
+ * @type String
+ * @description CSS class used to locate a placeholder for
+ * the error node and style it.
+ */
+ ERROR_CLASS : 'error',
+
/**
* @property _labelNode
* @protected
@@ -18,6 +80,14 @@ Y.FormField = Y.Base.create('form-field', Y.Widget, [Y.WidgetParent, Y.WidgetChi
*/
_labelNode: null,
+ /**
+ * @property _hintNode
+ * @protected
+ * @type Object
+ * @description The hint node with extra text describing the field
+ */
+ _hintNode : null,
+
/**
* @property _fieldNode
* @protected
@@ -105,6 +175,35 @@ Y.FormField = Y.Base.create('form-field', Y.Widget, [Y.WidgetParent, Y.WidgetChi
},
/**
+ * @method _renderNode
+ * @protected
+ * @description Helper method to render new nodes, possibly replacing
+ * markup placeholders.
+ */
+ _renderNode : function (nodeTemplate, nodeClass, nodeBefore) {
+ if (!nodeTemplate) {
+ return null;
+ }
+ var contentBox = this.get('contentBox'),
+ node = Y.Node.create(nodeTemplate),
+ placeHolder = contentBox.one('.' + nodeClass);
+
+ node.addClass(nodeClass);
+
+ if (placeHolder) {
+ placeHolder.replace(node);
+ } else {
+ if (nodeBefore) {
+ contentBox.insertBefore(node, nodeBefore);
+ } else {
+ contentBox.appendChild(node);
+ }
+ }
+
+ return node;
+ },
+
+ /**
* @method _renderLabelNode
* @protected
* @description Draws the form field's label node into the contentBox
@@ -114,14 +213,25 @@ Y.FormField = Y.Base.create('form-field', Y.Widget, [Y.WidgetParent, Y.WidgetChi
labelNode = contentBox.one('label');
if (!labelNode || labelNode.get('for') != this.get('id')) {
- labelNode = Y.Node.create(Y.FormField.LABEL_TEMPLATE);
- contentBox.appendChild(labelNode);
+ labelNode = this._renderNode(this.LABEL_TEMPLATE, this.LABEL_CLASS);
}
this._labelNode = labelNode;
},
/**
+ * @method _renderHintNode
+ * @protected
+ * @description Draws the hint node into the contentBox. If a node is
+ * found in the contentBox with class HINT_CLASS, it will be
+ * considered a markup placeholder and replaced with the hint node.
+ */
+ _renderHintNode : function () {
+ this._hintNode = this._renderNode(this.HINT_TEMPLATE,
+ this.HINT_CLASS);
+ },
+
+ /**
* @method _renderFieldNode
* @protected
* @description Draws the field node into the contentBox
@@ -131,8 +241,7 @@ Y.FormField = Y.Base.create('form-field', Y.Widget, [Y.WidgetParent, Y.WidgetChi
field = contentBox.one('#' + this.get('id'));
if (!field) {
- field = Y.Node.create(Y.FormField.INPUT_TEMPLATE);
- contentBox.appendChild(field);
+ field = this._renderNode(this.FIELD_TEMPLATE, this.FIELD_CLASS);
}
this._fieldNode = field;
@@ -144,16 +253,35 @@ Y.FormField = Y.Base.create('form-field', Y.Widget, [Y.WidgetParent, Y.WidgetChi
* @description Syncs the the label node and this instances attributes
*/
_syncLabelNode: function() {
+ var label = this.get('label'),
+ required = this.get('required'),
+ requiredLabel = this.get('requiredLabel');
if (this._labelNode) {
- this._labelNode.setAttrs({
- innerHTML: this.get('label')
- });
+ this._labelNode.set("text", "");
+ if (label) {
+ this._labelNode.append("<span class='caption'>" + label + "</span>");
+ }
+ if (required && requiredLabel) {
+ this._labelNode.append("<span class='separator'> </span>");
+ this._labelNode.append("<span class='required'>" + requiredLabel + "</span>");
+ }
this._labelNode.setAttribute('for', this.get('id') + Y.FormField.FIELD_ID_SUFFIX);
}
},
/**
- * @method _syncLabelNode
+ * @method _syncHintNode
+ * @protected
+ * @description Syncs the hintNode
+ */
+ _syncHintNode : function () {
+ if (this._hintNode) {
+ this._hintNode.set("text", this.get("hint"));
+ }
+ },
+
+ /**
+ * @method _syncFieldNode
* @protected
* @description Syncs the fieldNode and this instances attributes
*/
@@ -215,12 +343,9 @@ Y.FormField = Y.Base.create('form-field', Y.Widget, [Y.WidgetParent, Y.WidgetChi
* @description Adds an error node with the supplied message
*/
_showError: function(errMsg) {
- var contentBox = this.get('contentBox'),
- errorNode = Y.Node.create('<span>' + errMsg + '</span>');
-
- errorNode.addClass('error');
- contentBox.insertBefore(errorNode, this._labelNode);
+ var errorNode = this._renderNode(this.ERROR_TEMPLATE, this.ERROR_CLASS, this._labelNode);
+ errorNode.set("text", errMsg);
this._errorNode = errorNode;
},
@@ -231,8 +356,7 @@ Y.FormField = Y.Base.create('form-field', Y.Widget, [Y.WidgetParent, Y.WidgetChi
*/
_clearError: function() {
if (this._errorNode) {
- var contentBox = this.get('contentBox');
- contentBox.removeChild(this._errorNode);
+ this._errorNode.remove();
this._errorNode = null;
}
},
@@ -304,6 +428,7 @@ Y.FormField = Y.Base.create('form-field', Y.Widget, [Y.WidgetParent, Y.WidgetChi
renderUI: function() {
this._renderLabelNode();
this._renderFieldNode();
+ this._renderHintNode();
},
bindUI: function() {
@@ -360,6 +485,7 @@ Y.FormField = Y.Base.create('form-field', Y.Widget, [Y.WidgetParent, Y.WidgetChi
syncUI: function() {
this.get('boundingBox').removeAttribute('tabindex');
this._syncLabelNode();
+ this._syncHintNode();
this._syncFieldNode();
this._syncError();
this._syncDisabled();
@@ -425,6 +551,17 @@ Y.FormField = Y.Base.create('form-field', Y.Widget, [Y.WidgetParent, Y.WidgetChi
},
/**
+ * @attribute hint
+ * @type String
+ * @default ""
+ * @description Extra text explaining what the field is about.
+ */
+ hint : {
+ value : '',
+ validator : Y.Lang.isString
+ },
+
+ /**
* @attribute validator
* @type Function
* @default "function () { return true; }"
@@ -475,6 +612,17 @@ Y.FormField = Y.Base.create('form-field', Y.Widget, [Y.WidgetParent, Y.WidgetChi
validateInline: {
value: false,
validator: Y.Lang.isBoolean
+ },
+
+ /**
+ * @attribute requiredLabel
+ * @type String
+ * @description Text to append to the labal caption for a required
+ * field, by default nothing will be appended.
+ */
+ requiredLabel : {
+ value : '',
+ validator : Y.Lang.isString
}
},
@@ -660,20 +808,6 @@ Y.FormField = Y.Base.create('form-field', Y.Widget, [Y.WidgetParent, Y.WidgetChi
INVALID_SPECIAL_CHARS: "Please use only letters and numbers",
/**
- * @property FormField.INPUT_TEMPLATE
- * @type String
- * @description Template used to draw an input node
- */
- INPUT_TEMPLATE: '<input />',
-
- /**
- * @property FormField.LABEL_TEMPLATE
- * @type String
- * @description Template used to draw a label node
- */
- LABEL_TEMPLATE: '<label></label>',
-
- /**
* @property FormField.REQUIRED_ERROR_TEXT
* @type String
* @description Error text to display for a required field
View
2 src/gallery-form/js/form.js
@@ -246,6 +246,7 @@ Y.Form = Y.Base.create('form', Y.Widget, [Y.WidgetParent], {
var formAction = this.get('action'),
formMethod = this.get('method'),
submitViaIO = this.get('submitViaIO'),
+ io = this.get("io"),
transaction,
cfg;
@@ -258,7 +259,6 @@ Y.Form = Y.Base.create('form', Y.Widget, [Y.WidgetParent], {
}
};
- var io = this.get("io");
transaction = io(formAction, cfg);
this._ioIds[transaction.id] = transaction;
} else {
View
2 src/gallery-form/js/reset.js
@@ -6,5 +6,5 @@
* @description A reset button
*/
Y.ResetButton = Y.Base.create('reset-button', Y.FormField, [Y.WidgetChild], {
- _renderLabelNode: function() {}
+ LABEL_TEMPLATE: ''
});
View
80 src/gallery-form/js/select-field.js
@@ -6,22 +6,23 @@
* @description A select field node
*/
Y.SelectField = Y.Base.create('select-field', Y.ChoiceField, [Y.WidgetParent, Y.WidgetChild], {
+
+ FIELD_TEMPLATE : '<select></select>',
+
+ /**
+ * @property SelectField.DEFAULT_OPTION_TEXT
+ * @type String
+ * @description The display title of the default choice in the select box
+ */
+ DEFAULT_OPTION_TEXT : 'Choose one',
+
/**
* @method _renderFieldNode
* @protected
* @description Draws the select node into the contentBox
*/
_renderFieldNode: function() {
- var contentBox = this.get('contentBox'),
- field = contentBox.one('#' + this.get('id'));
-
- if (!field) {
- field = Y.Node.create(Y.SelectField.NODE_TEMPLATE);
- contentBox.appendChild(field);
- }
-
- this._fieldNode = field;
-
+ Y.SelectField.superclass.constructor.superclass._renderFieldNode.apply(this, arguments);
this._renderOptionNodes();
},
@@ -57,6 +58,7 @@ Y.SelectField = Y.Base.create('select-field', Y.ChoiceField, [Y.WidgetParent, Y.
Y.SelectField.superclass.constructor.superclass._syncFieldNode.apply(this, arguments);
this._fieldNode.setAttrs({
+ size : this.get('size'),
multiple: (this.get('multi') === true ? 'multiple': '')
});
},
@@ -75,7 +77,7 @@ Y.SelectField = Y.Base.create('select-field', Y.ChoiceField, [Y.WidgetParent, Y.
if (useDefaultOption === true) {
choices.unshift({
- label: Y.SelectField.DEFAULT_OPTION_TEXT,
+ label : this.DEFAULT_OPTION_TEXT,
value: ''
});
}
@@ -100,6 +102,18 @@ Y.SelectField = Y.Base.create('select-field', Y.ChoiceField, [Y.WidgetParent, Y.
},
/**
+ * @method _afterChoiceChange
+ * @description When the available options for the select field change,
+ * the old ones are removed and the new ones are rendered.
+ */
+ _afterChoicesChange: function(evt) {
+ var options = this._fieldNode.all("option");
+ options.remove();
+ this._renderOptionNodes();
+ this._syncOptionNodes();
+ },
+
+ /**
* @method clear
* @description Restores the selected option to the default
*/
@@ -109,6 +123,7 @@ Y.SelectField = Y.Base.create('select-field', Y.ChoiceField, [Y.WidgetParent, Y.
bindUI: function() {
Y.SelectField.superclass.constructor.superclass.bindUI.apply(this, arguments);
+ this.after('choicesChange', this._afterChoicesChange);
},
syncUI: function() {
@@ -118,26 +133,12 @@ Y.SelectField = Y.Base.create('select-field', Y.ChoiceField, [Y.WidgetParent, Y.
},
{
/**
- * @property SelectField.NODE_TEMPLATE
- * @type String
- * @description Template used to draw a select node
- */
- NODE_TEMPLATE: '<select></select>',
-
- /**
* @property SelectField.OPTION_TEMPLATE
* @type String
* @description Template used to draw an option node
*/
OPTION_TEMPLATE: '<option></option>',
- /**
- * @property SelectField.DEFAULT_OPTION_TEXT
- * @type String
- * @description The display title of the default choice in the select box
- */
- DEFAULT_OPTION_TEXT: 'Choose one',
-
ATTRS: {
/**
* @attribute useDefaultOption
@@ -149,6 +150,35 @@ Y.SelectField = Y.Base.create('select-field', Y.ChoiceField, [Y.WidgetParent, Y.
useDefaultOption: {
validator: Y.Lang.isBoolean,
value: true
+ },
+
+ /**
+ * @attribute choices
+ * @type Array
+ * @description The choices to render into this field
+ */
+ choices: {
+ validator: function(val) {
+ if (this.get("useDefaultOption") &&
+ Y.Lang.isArray(val) &&
+ val.length === 0) {
+ // Empty arrays are okay if useDefaultOption is 'true'
+ return true;
+ } else {
+ return this._validateChoices(val);
+ }
+ }
+ },
+
+ /**
+ * @attribute size
+ * @type String
+ * @default 0
+ * @description Value of 'size' attribute of the select element.
+ */
+ size : {
+ validator : Y.Lang.isString,
+ value : '0'
}
}
});
View
26 src/gallery-form/js/textarea-field.js
@@ -6,29 +6,7 @@
* @description A hidden field node
*/
Y.TextareaField = Y.Base.create('textarea-field', Y.FormField, [Y.WidgetChild], {
- _renderFieldNode : function () {
- var contentBox = this.get('contentBox'),
- field = contentBox.one('#' + this.get('id'));
-
- if (!field) {
- field = Y.Node.create(Y.TextareaField.NODE_TEMPLATE);
- field.setAttrs({
- name : this.get('name'),
- innerHTML : this.get('value')
- });
- contentBox.appendChild(field);
- }
- field.setAttribute('tabindex', Y.FormField.tabIndex);
- Y.FormField.tabIndex++;
-
- this._fieldNode = field;
- }
-}, {
- /**
- * @property TextareaField.NODE_TEMPLATE
- * @type String
- * @description Template used to draw a textarea node
- */
- NODE_TEMPLATE : '<textarea></textarea>'
+ FIELD_TEMPLATE : '<textarea></textarea>'
+
});
View
24 src/gallery-form/tests/button.js
@@ -19,6 +19,7 @@ suite.add(new Y.Test.Case({
testRenderUI: function() {
var contentBox = this.button.get("contentBox");
Y.Assert.isNotNull(contentBox.one("button"));
+ Y.Assert.isNull(contentBox.one("label"));
},
// The 'onclick' attribute can be set to an event handler for the
@@ -50,6 +51,29 @@ suite.add(new Y.Test.Case({
var buttonNode = contentBox.one("button");
Y.Assert.areEqual("Press me", buttonNode.get("text"));
Y.Assert.areEqual(this.button.get("id") + "-field", buttonNode.get("id"));
+ },
+
+ // If the message attribute is set, the button prompts for confirmation.
+ testOnClickWithConfirm: function() {
+ var messages = [];
+ this.button.set("message", "Really?");
+ this.button.set("confirm", function(message) {
+ messages.push(message);
+ return true;
+ });
+ var contentBox = this.button.get("contentBox");
+ var buttonNode = contentBox.one("button");
+ this.button.set("onclick", {fn: function() {}});
+ buttonNode.simulate("click");
+ Y.ArrayAssert.itemsAreEqual(["Really?"], messages);
+ },
+
+ // It's possible to toggle the disabled state of a FormButton.
+ testDisable: function() {
+ this.button.disable();
+ var contentBox = this.button.get("contentBox");
+ var buttonNode = contentBox.one("button");
+ Y.Assert.areEqual("disabled", buttonNode.getAttribute("disabled"));
}
}));
View
74 src/gallery-form/tests/choice-field.js
@@ -72,6 +72,80 @@ suite.add(new Y.Test.Case({
this.choice.clear();
Y.ArrayAssert.itemsAreEqual([false, false], inputs.get("checked"));
},
+
+ // When the 'choices' attribute changes, the widget is refreshed.
+ testChangeChoices: function() {
+ this.choice.set("choices", [{label: "Foo", value: "foo"},
+ {label: "Bar", value: "bar"}]);
+ this.choice.render();
+ this.choice.set("choices", [{label: "Egg", value: "egg"}]);
+ var contentBox = this.choice.get("contentBox");
+ var radios = contentBox.all("> div");
+ Y.Assert.areEqual(1, radios.size());
+ var label = radios.item(0).one("label");
+ var input = radios.item(0).one("input");
+ Y.Assert.areEqual("Egg", label.get("text"));
+ Y.Assert.areEqual("egg", input.get("value"));
+ }
+}));
+
+
+var CustomRadioField = function(config) {
+ CustomRadioField.superclass.constructor.apply(this, arguments);
+};
+
+CustomRadioField.NAME = "radio-field";
+
+Y.extend(CustomRadioField, Y.RadioField, {
+
+ CONTENT_TEMPLATE: ["<div class='custom-choice'>",
+ " <span class='field'></span>",
+ " <span class='label'></span>",
+ "</div>"].join("")
+});
+
+
+var CustomChoiceField = function(config) {
+ CustomChoiceField.superclass.constructor.apply(this, arguments);
+};
+
+CustomChoiceField.NAME = "custom-choice-field";
+
+Y.extend(CustomChoiceField, Y.ChoiceField, {
+
+ SINGLE_CHOICE: CustomRadioField,
+ CONTENT_TEMPLATE: ["<div>",
+ " <div>",
+ " <div class='field'></div>",
+ " </div>",
+ "</div>"].join("")
+});
+
+
+suite.add(new Y.Test.Case({
+
+ name: "CustomChoiceFieldTest",
+
+ setUp: function() {
+ var boundingBox = Y.Node.create("<div></div>");
+ var scaffolding = Y.one("#scaffolding");
+ scaffolding.setContent(boundingBox);
+ this.field = new CustomChoiceField({boundingBox: boundingBox,
+ name: "some-field",
+ choices: [{label: "Foo", value: "foo"},
+ {label: "Bar", value: "bar"}]});
+ this.field.render();
+ },
+
+ // If a placeholder node is found for the field node, the choice widgets
+ // are appended to it.
+ testRenderUI: function() {
+ var contentBox = this.field.get("contentBox"),
+ parent = contentBox.one(".field"),
+ choices = parent.get("children");
+ Y.Assert.areEqual(2, choices.size());
+ Y.Assert.isTrue(choices.item(0).one("div").hasClass("custom-choice"));
+ }
}));
Y.Test.Runner.add(suite);
View
86 src/gallery-form/tests/form-field.js
@@ -53,9 +53,10 @@ suite.add(new Y.Test.Case({
var contentBox = this.field.get("contentBox");
var error = contentBox.one("label").previous();
Y.Assert.areEqual("span", error.get("nodeName").toLowerCase());
+ Y.Assert.isTrue(error.hasClass("error"));
Y.Assert.areEqual("Bad value", error.get("text"));
this.field.set("error", null);
- Y.Assert.isNull(contentBox.one("span"));
+ Y.Assert.isNull(contentBox.one("span.error"));
},
// If the 'validateInline' attribute is set, the field value is validated
@@ -68,12 +69,12 @@ suite.add(new Y.Test.Case({
var input = contentBox.one("input");
input.set("value", "foo");
input.simulate("blur");
- Y.Assert.isNotNull(contentBox.one("span"));
+ Y.Assert.isNotNull(contentBox.one("span.error"));
this.field.set("error", null);
this.field.set("validateInline", false);
input.set("value", "bar");
input.simulate("blur");
- Y.Assert.isNull(contentBox.one("span"));
+ Y.Assert.isNull(contentBox.one("span.error"));
},
// If the 'validateInline' attribute is set, the field value is validated
@@ -101,9 +102,88 @@ suite.add(new Y.Test.Case({
Y.Assert.areEqual("nice-field", input.get("name"));
Y.Assert.areEqual("Nice value", input.get("value"));
Y.Assert.areEqual(id + "-field", input.get("id"));
+ },
+
+ // With the 'requiredLabel' attribute it's possible to specify some
+ // custom text to be appended to the label caption for required fields.
+ testRequiredLabel: function() {
+ this.field.set("required", true);
+ this.field.set("requiredLabel", "(Required)");
+ this.field.set("label", "Nice field");
+ this.field.syncUI();
+ var contentBox = this.field.get("contentBox");
+ var label = contentBox.one("label");
+ var required = label.one("span.required");
+ Y.Assert.areEqual("(Required)", required.get("text"));
+ Y.Assert.isTrue(required.hasClass("required"));
}
}));
+
+var CustomFormField = function(config) {
+ CustomFormField.superclass.constructor.apply(this, arguments);
+};
+
+CustomFormField.NAME = "custom-form-field";
+
+Y.extend(CustomFormField, Y.FormField, {
+
+ CONTENT_TEMPLATE: ["<div>",
+ " <span class='label'></span>",
+ " <div>",
+ " <div>",
+ " <span class='field'></span>",
+ " </div>",
+ " <div>",
+ " <span class='error'></span>",
+ " </div>",
+ " </div>",
+ " <span class='hint'></span>",
+ "</div>"].join(""),
+
+ HINT_TEMPLATE: "<div></div>"
+});
+
+
+suite.add(new Y.Test.Case({
+
+ name: "CustomFormFieldTest",
+
+ setUp: function() {
+ var boundingBox = Y.Node.create("<div></div>");
+ var scaffolding = Y.one("#scaffolding");
+ scaffolding.setContent(boundingBox);
+ this.field = new CustomFormField({boundingBox: boundingBox,
+ name: "some-field",
+ label: "Some field",
+ hint: "Very nice field",
+ required: true,
+ requiredLabel: "(Required)",
+ value: "foo"});
+ this.field.render();
+ },
+
+ // If placeholders nodes are found in the content box markup, they
+ // are replaced with the relevant form field nodes.
+ testRenderUI: function() {
+ var contentBox = this.field.get("contentBox"),
+ contentBoxChildren = contentBox.get("children"),
+ label = contentBoxChildren.item(0),
+ field = contentBoxChildren.item(1),
+ hint = contentBoxChildren.item(2);
+ Y.Assert.areEqual("label", label.get("nodeName").toLowerCase());
+ Y.Assert.areEqual("Some field", label.one("span.caption").get("text"));
+ Y.Assert.areEqual("(Required)", label.one("span.required").get("text"));
+ Y.Assert.areEqual("div", field.get("nodeName").toLowerCase());
+ Y.Assert.areEqual("foo", field.one("input.field").get("value"));
+ Y.Assert.areEqual("div", hint.get("nodeName").toLowerCase());
+ Y.Assert.areEqual("Very nice field", hint.get("text"));
+ this.field.set("error", "Invalid");
+ Y.Assert.areEqual("Invalid", field.one("span.error").get("text"));
+ }
+}));
+
+
Y.Test.Runner.add(suite);
Y.Test.Runner.run();
View
28 src/gallery-form/tests/select-field.js
@@ -21,11 +21,13 @@ suite.add(new Y.Test.Case({
field,
options;
this.select.set("name", "some-field");
+ this.select.set("size", "2");
this.select.set("choices", [{label: "Foo", value: "foo"},
{label: "Bar", value: "bar"}]);
this.select.render();
field = contentBox.one("select");
Y.Assert.areEqual("some-field", field.get("name"));
+ Y.Assert.areEqual("2", field.get("size"));
options = contentBox.all("option");
Y.Assert.areEqual("Choose one", options.item(0).get("text"));
Y.Assert.areEqual("", options.item(0).get("value"));
@@ -36,6 +38,17 @@ suite.add(new Y.Test.Case({
Y.Assert.areEqual("bar", options.item(2).get("value"));
},
+ // The SelectField widget can render the default option only.
+ testRenderWithDefaultOnly: function() {
+ var contentBox = this.select.get("contentBox"),
+ options;
+ this.select.set("choices", []);
+ this.select.render();
+ options = contentBox.all("option");
+ Y.Assert.areEqual("Choose one", options.item(0).get("text"));
+ Y.Assert.areEqual("", options.item(0).get("value"));
+ },
+
// If the 'multi' attribute is set to true, the select element
// will have the 'multiple' property set.
testRenderWithMulti: function() {
@@ -47,6 +60,21 @@ suite.add(new Y.Test.Case({
this.select.render();
field = contentBox.one("select");
Y.Assert.isTrue(field.get("multiple"));
+ },
+
+ // When the 'choices' attribute changes, the widget is refreshed.
+ testChangeChoices: function() {
+ this.select.set("choices", [{label: "Foo", value: "foo"},
+ {label: "Bar", value: "bar"}]);
+ this.select.render();
+ this.select.set("choices", [{label: "Egg", value: "egg"}]);
+ var contentBox = this.select.get("contentBox");
+ var options = contentBox.all("option");
+ Y.Assert.areEqual(2, options.size());
+ Y.Assert.areEqual("Choose one", options.item(0).get("text"));
+ Y.Assert.areEqual("", options.item(0).get("value"));
+ Y.Assert.areEqual("Egg", options.item(1).get("text"));
+ Y.Assert.areEqual("egg", options.item(1).get("value"));
}
}));

0 comments on commit 796eed0

Please sign in to comment.
Something went wrong with that request. Please try again.