attribute.html revision ed73fd1af1279111c591bd65981adbdc23a3a94a
a86310b25a2fc01f76df88293287b3908ab3d7f0Mark Andrews<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
a86310b25a2fc01f76df88293287b3908ab3d7f0Mark Andrews <script type="text/javascript" src="/build/yui/yui.js"></script>
09755f72700f2ea34254bc234e335322bda63434Evan Hunt #console .yui3-console-entry {
f8ae0a35d0219fb8e4beb897a2d0a189f1d2d181Evan Hunt padding:2px;
filter: (window.location.search.match(/[?&]filter=([^&]+)/) || [])[1] || 'min'
Y.ObjectAssert.areEqual(o1, o2);
Y.ObjectAssert.areEqual(o2, o1);
Test.superclass.constructor.apply(this, arguments);
Test.NAME = 'test';
Test.ATTRS = {
AttrHost.superclass.constructor.apply(this, arguments);
AttrHost.NAME = "attrHost";
AttrHost.ATTRS = {
validator: Y.Lang.isString,
AttrHost.superclass.constructor.apply(this, arguments);
ExtendedAttrHost.NAME = "extendedAttrHost";
return ((value == undefined) || Y.Lang.isString(value));
"complex.X.A" : {
"complex.Y.A" : {
return this.get("H") + 10;
return val.toUpperCase();
Y.extend(ExtendedAttrHost, AttrHost, {
if (name.indexOf(".") == -1) {
Y.Assert.areEqual("I", name);
if (name.indexOf(".") == -1) {
Y.Assert.areEqual("I", name);
if (name.indexOf(".") == -1) {
Y.Assert.areEqual("I", name);
var h = this.createHost();
h.on("AChange", function(e) {
if (e.newVal == "PREVENT") {
h.after("AChange", function(e) {
h.set("A", "MyNewAVal");
h.set("A", "PREVENT");
Y.ArrayAssert.itemsAreEqual(expectedEvents, actualEvents);
var h = this.createHost({A:"MyAVal"});
h.on("AChange", function(e) {
h.after("AChange", function(e) {
h.set("A", "MyNewAVal");
Y.ArrayAssert.itemsAreEqual(expectedEvents, actualEvents);
var h = this.createHost();
var expectedEvents = ["Before1MyNewAVal", "Before2MyNewAVal", "After1MyNewAVal", "After2MyNewAVal", "Before1STOPAFTER", "Before2STOPAFTER", "After1STOPAFTER", "Before1STOPBEFORE"];
h.on("AChange", function(e) {
if (e.newVal == "STOPBEFORE") {
h.after("AChange", function(e) {
if (e.newVal == "STOPAFTER") {
h.on("AChange", function(e) {
h.after("AChange", function(e) {
h.set("A", "MyNewAVal");
h.set("A", "STOPAFTER");
h.set("A", "STOPBEFORE");
Y.ArrayAssert.itemsAreEqual(expectedEvents, actualEvents);
var h = this.createHost({A:"MyAVal", C:"MyCVal", D:"MyDVal"});
h.on("AChange", function() {
actualEvents.push("BeforeAChange");
h.after("AChange", function() {
actualEvents.push("AfterAChange");
h.on("CChange", function() {
actualEvents.push("BeforeCChange");
h.on("CChange", function() {
actualEvents.push("BeforeCChange");
h.on("DChange", function() {
actualEvents.push("BeforeDChange");
h.on("DChange", function() {
actualEvents.push("BeforeDChange");
h.set("A", 200); // Invalid - before fired, after not fired [ value can be changed to be made valid ]
h.set("C", "MyNewCVal"); // Write Once - neither before nor after are fired
h.set("D", "MyNewDVal"); // Read Only - neither before not after are fired
Y.ArrayAssert.itemsAreEqual(expectedEvents, actualEvents);
var h = this.createHost({A:"MyAVal"});
h.on("AChange", function(e) {
h.after("AChange", function(e) {
h.set("A", "MyNewAVal");
var h = this.createHost({A:"MyAVal"});
h.on("AChange", function(e) {
actualEvents.push("BeforeAChange");
h.after("AChange", function(e) {
actualEvents.push("AfterAChange");
h.on("complexChange", function(e) {
actualEvents.push("BeforeComplexChange");
h.after("complexChange", function(e) {
actualEvents.push("AfterComplexChange");
if (!e.subAttrName) {
h.on("PassThroughChange", function(e) {
actualEvents.push("BeforePassThroughChange");
h.after("PassThroughChange", function(e) {
actualEvents.push("AfterPassThroughChange");
h.set("A", "MyAVal"); // No Change
h.set("A", "MyNewAVal"); // Change
h.set("complex.Z.A", 3); // Change, even though value of complex is unchanged, we don't deep compare objects.
h.set("complex", {A:1, B:2, C:3}); // Change, obj reference differs
h.set("complex", a); // Change, value changed
a.push("B");
h.set("complex", a); // Change, same object ref, but we don't know if contents changed, so fire event
h.set("PassThrough", "MyPassThrough");
h.set("PassThrough", "MyPassThrough");
h.set("PassThrough", "MyNewPassThrough");
Y.ArrayAssert.itemsAreEqual(expectedEvents, actualEvents);
var h = this.createHost({
actualEvents.push("OnAChange");
actualEvents.push("OnInit");
actualEvents.push("AfterAChange");
actualEvents.push("AfterInit");
h.set("A", "Foo");
Y.ArrayAssert.itemsAreEqual(expectedEvents, actualEvents);
h.set("foo", "bar");
h.set("foo", "foobar");
Y.Attribute.call(this, null, userVals);
FooBar.ATTRS = {
o1.set("foo", "foobar");
o.set("foo", "bar");
var h = this.createHost();
var h = this.createHost({A:"MyAVal", B:"MyBVal", C:"MyCVal", D:"MyDVal", E:"MyEVal", DE:"MyDEVal"});
h.set("C", "MyNewCVal");
h.set("D", "MyNewDVal");
h.set("E", "MyNewEVal");
var h = this.createHost();
h.set("A", "MyNewAVal");
h.set("B", "MyNewBVal");
h.set("C", "MyNewCVal");
h.set("D", "MyNewDVal");
h.set("E", "MyNewEVal");
h.set("DE", "MyNewDEVal");
var h = this.createHost();
h.set("E", "MyNewEVal");
h.set("C", "MyNewCVal");
var h = this.createHost({E:"MyEVal"});
h.set("E", "MyNewEVal");
var h = this.createHost({ initOnly: "initOnlyVal"});
h.set("initOnly", "NewInitOnlyVal");
var h1 = this.createHost();
h1.set("initOnly", "InitOnlyVal");
var h = this.createHost();
h.set("AdHoc", "TestAdHoc");
h.addAttr("AdHoc", {
return val.toUpperCase();
h.set("AdHoc", "TestAdHocConfigured");
var h = this.createHost({
AttrHost.prototype._allowAdHocAttrs = false;
var h = this.createHost({A:"MyAVal", B:"MyBVal", C:"MyCVal", D:"MyDVal", E:"MyEVal", DE:"MyDEVal"});
h.set("A", "MyNewAVal");
h.set("B", "MyNewBVal");
h.set("C", "MyNewCVal");
h.set("D", "MyNewDVal");
h.set("E", "MyNewEVal");
h.set("DE", "MyNewDEVal");
h.reset("A");
h.reset("D");
h.reset();
var h = this.createHost();
areObjectsReallyEqual(expectedVals, h.getAttrs());
var h = this.createHost();
areObjectsReallyEqual(expectedVals, h.getAttrs(true));
var h = this.createHost();
h.set("A", "MyAVal");
h.set("A", 100);
h.set("B", "two");
h.set("B", 2);
h.set("B", false);
var h = this.createHost();
h.on("DChange", function(e) {
h.on("EChange", function(e) {
h.after("DChange", function(e) {
h.after("EChange", function(e) {
h.set("D", "MyNewDVal");
h.set("E", "MyNewEVal");
var h = this.createHost();
var val = h.get("complex");
Y.each(val, function(v, k) {
var h = this.createHost({
"complex.X.A": 11,
"complex.Y.A": 12,
"complex.Z.A": 13,
"complex.W.A": 14 // Does not exist, not allowed to set
var h = this.createHost();
var h = this.createHost();
var expectedEvents = ["Beforecomplex.X.A", "Aftercomplex.X.A", "Beforecomplex.Y.A", "Aftercomplex.Y.A", "Beforecomplex.Y", "Aftercomplex.Y"];
h.on("complexChange", function(e) {
h.after("complexChange", function(e) {
var h = this.createHost();
var expectedEvents = ["On AChange Y Broadcast", "After AChange Y Broadcast", "On BChange Y Broadcast", "After BChange Y Broadcast", "On BChange YUI Broadcast", "After BChange YUI Broadcast", "On CChange", "After CChange"];
Y.Global.on("attrHost:AChange", function() {
actualEvents.push("On AChange YUI Broadcast");
Y.Global.after("attrHost:AChange", function() {
actualEvents.push("After AChange YUI Broadcast");
Y.on("attrHost:AChange", function() {
actualEvents.push("On AChange Y Broadcast");
Y.after("attrHost:AChange", function() {
actualEvents.push("After AChange Y Broadcast");
Y.Global.on("attrHost:BChange", function() {
actualEvents.push("On BChange YUI Broadcast");
Y.Global.after("attrHost:BChange", function() {
actualEvents.push("After BChange YUI Broadcast");
Y.on("attrHost:BChange", function() {
actualEvents.push("On BChange Y Broadcast");
h.on("CChange", function() {
actualEvents.push("On CChange");
h.after("CChange", function() {
actualEvents.push("After CChange");
Y.after("attrHost:BChange", function() {
actualEvents.push("After BChange Y Broadcast");
Y.Global.on("attrHost:CChange", function() {
actualEvents.push("On CChange YUI Broadcast");
Y.Global.after("attrHost:CChange", function() {
actualEvents.push("After CChange YUI Broadcast");
Y.on("attrHost:CChange", function() {
actualEvents.push("On CChange Y Broadcast");
Y.after("attrHost:CChange", function() {
actualEvents.push("After CChange Y Broadcast");
h.set("A", "NewA");
h.set("B", "NewB");
h.set("C", "NewC");
Y.ArrayAssert.itemsAreEqual(expectedEvents, actualEvents);
var h = this.createHost({A:5});
Y.Assert.areEqual("AVal", h.get("A")); // Numerical value validation failure should revert to default value
var h = this.createHost();
Y.on("attrHost:AChange", function() {
actualEvents.push("On AChange Y Broadcast");
Y.after("attrHost:AChange", function() {
actualEvents.push("After AChange Y Broadcast");
h.set("A", "NewA");
h.modifyAttr("A", {
return val.toUpperCase();
Y.Assert.fail("Setter should not be called");
Y.Assert.fail("Validator should not be called");
h.set("A", "NewAAfterGetterBroadCast");
h.set("A", 5);
h.modifyAttr("A", {
h.set("A", "NewAAfterReadOnly");
Y.ArrayAssert.itemsAreEqual(expectedEvents, actualEvents);
var h = this.createHost();
var q = h._protectAttrs(AttrHost.ATTRS);
q.A.newprop = "new prop value";
q.A.value = "modified value";
basicTemplate = Y.merge(basicTemplate, sharedEventTests);
var h = this.createHost();
var h = this.createHost({A:"MyAVal", B:"MyBVal", C:"MyCVal", D:"MyDVal", E:"MyEVal", F:"MyFVal"});
h.set("C", "MyNewCVal");
h.set("D", "MyNewDVal");
h.set("E", "MyNewEVal");
var h = this.createHost();
h.set("A", "MyNewAVal");
h.set("B", "MyNewBVal");
h.set("C", "MyNewCVal");
h.set("D", "MyNewDVal");
h.set("E", "MyNewEVal");
h.set("F", "MyNewFVal");
h.set("DE", "MyNewDEVal");
var h = this.createHost();
h.set("AdHoc", "TestAdHoc");
var h = this.createHost({A:"MyAVal", B:"MyBVal", C:"MyCVal", D:"MyDVal", E:"MyEVal", F:"MyFVal", DE:"MyDEVal"});
h.set("A", "MyNewAVal");
h.set("B", "MyNewBVal");
h.set("C", "MyNewCVal");
h.set("D", "MyNewDVal");
h.set("E", "MyNewEVal");
h.set("F", "MyNewFVal");
h.set("DE", "MyNewDEVal");
h.reset("A");
h.reset("D");
h.reset();
var h = this.createHost();
areObjectsReallyEqual(expectedVals, h.getAttrs());
var h = this.createHost();
areObjectsReallyEqual(expectedVals, h.getAttrs(true));
var h = this.createHost();
h.set("A", "MyAVal");
h.set("A", 100);
h.set("B", "two");
h.set("B", 2);
h.set("B", true);
h.set("F", "MyNewFVal");
h.set("F", 3);
Y.Assert.areEqual("MyNewFVal", h.get("F")); // Validation should prevent the attribute from being set
var h = this.createHost();
var expectedEvents = ["BeforeTryDAgain", "AfterTRYDAGAIN", "BeforeTryEAgain", "Aftertryeagain" ]; // Last entry: e.newVal is not "get" normalized
h.on("DChange", function(e) {
h.on("EChange", function(e) {
h.after("DChange", function(e) {
h.after("EChange", function(e) {
h.set("D", "MyNewDVal");
h.set("E", "MyNewEVal");
Y.ArrayAssert.itemsAreEqual(expectedEvents, actualEvents);
var h = this.createHost();
var val = h.get("complex");
Y.each(val, function(v, k) {
var h = this.createHost({
"complex.X.A": 11,
"complex.Y.A": 12,
"complex.Z.A": 13,
"complex.W.A": 14 // Does not exist, not allowed to set
var h = this.createHost();
var h = this.createHost();
var expectedEvents = ["Beforecomplex.X.A", "Aftercomplex.X.A", "Beforecomplex.Y.A", "Aftercomplex.Y.A", "Beforecomplex.Y", "Aftercomplex.Y"];
h.on("complexChange", function(e) {
h.after("complexChange", function(e) {
var h = this.createHost();
var h = this.createHost();
h.set("I", {a:7, b:8});
var h = this.createHost();
var expectedEvents = ["On AChange Y Broadcast", "After AChange Y Broadcast", "On BChange Y Broadcast", "After BChange Y Broadcast", "On BChange YUI Broadcast", "After BChange YUI Broadcast", "On CChange", "After CChange"];
Y.Global.on("extendedAttrHost:AChange", function() {
actualEvents.push("On AChange YUI Broadcast");
Y.Global.after("extendedAttrHost:AChange", function() {
actualEvents.push("After AChange YUI Broadcast");
Y.on("extendedAttrHost:AChange", function() {
actualEvents.push("On AChange Y Broadcast");
Y.after("extendedAttrHost:AChange", function() {
actualEvents.push("After AChange Y Broadcast");
Y.Global.on("extendedAttrHost:BChange", function() {
actualEvents.push("On BChange YUI Broadcast");
Y.Global.after("extendedAttrHost:BChange", function() {
actualEvents.push("After BChange YUI Broadcast");
Y.on("extendedAttrHost:BChange", function() {
actualEvents.push("On BChange Y Broadcast");
Y.after("extendedAttrHost:BChange", function() {
actualEvents.push("After BChange Y Broadcast");
h.on("CChange", function() {
actualEvents.push("On CChange");
h.after("CChange", function() {
actualEvents.push("After CChange");
Y.Global.on("extendedAttrHost:CChange", function() {
actualEvents.push("On CChange YUI Broadcast");
Y.Global.after("extendedAttrHost:CChange", function() {
actualEvents.push("After CChange YUI Broadcast");
Y.on("extendedAttrHost:CChange", function() {
actualEvents.push("On CChange Y Broadcast");
Y.after("extendedAttrHost:CChange", function() {
actualEvents.push("After CChange Y Broadcast");
h.set("A", "NewA");
h.set("B", "NewB");
h.set("C", "NewC");
Y.ArrayAssert.itemsAreEqual(expectedEvents, actualEvents);
var h = this.createHost();
Y.on("extendedAttrHost:AChange", function() {
actualEvents.push("On AChange Y Broadcast");
Y.after("extendedAttrHost:AChange", function() {
actualEvents.push("After AChange Y Broadcast");
h.set("A", "NewA");
h.modifyAttr("A", {
return val.toUpperCase();
Y.Assert.fail("Setter should not be called");
Y.Assert.fail("Validator should not be called");
h.set("A", "NewAAfterGetterBroadCast");
h.set("A", 5);
h.modifyAttr("A", {
h.set("A", "NewAAfterReadOnly");
Y.ArrayAssert.itemsAreEqual(expectedEvents, actualEvents);
var h = this.createHost();
h.on("ZChange", function() {
actualEvents.push("BeforeZChange");
h.after("ZChange", function() {
actualEvents.push("AfterZChange");
h.set("Z", "MyZ");
h.set("Z", "MYZ");
Y.ArrayAssert.itemsAreEqual(expectedEvents, actualEvents);
extendedTemplate = Y.merge(extendedTemplate, sharedEventTests);
t.getAttrs();
t.getAttrs();
Y.log("Construction Time Populated (lazy): " + ((end-start)/n), "perf");
Y.log("Construction Time (lazy and silent init): " + ((end-start)/n), "perf");
suite.add(new Y.Test.Case(augmentTemplate)); // run twice, just to make sure static class state not modified