attribute.html revision 2b7125b1271732c191ab0b73be768534afd62fc5
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync <script type="text/javascript" src="/build/yui/yui.js"></script>
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync #console .yui3-console-entry {
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync padding:2px;
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync margin:0px;
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync min-height:0;
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync #console .yui3-console-entry-fail .yui3-console-entry-cat {
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync background-color:red;
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync #console .yui3-console-entry-pass .yui3-console-entry-cat {
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync background-color:green;
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync #console .yui3-console-entry-perf .yui3-console-entry-cat {
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync background-color:blue;
5eabf773597082761832bc0a32b3660e8771f9f1vboxsync position:static;
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync html, body {
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync height:100%;
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync useBrowserConsole:false,
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync filter: (window.location.search.match(/[?&]filter=([^&]+)/) || [])[1] || 'min'
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync }).use("dump", "attribute-complex", "base", "console", "test", function(Y) {
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync function areObjectsReallyEqual(o1, o2) {
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync function TestAugment(attrs, values) {}
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync function TestAugmentWithATTRS(attrs, values) {}
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync value:"bar"
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync function Test(cfg, lazy, silentInit) {
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync this._lazyAddAttrs = lazy;
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync this._silentInit = silentInit;
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync Test.superclass.constructor.apply(this, arguments);
021c939a9e3f688c0c3bbd759354be906bb2dcabvboxsync value: "Foo",
021c939a9e3f688c0c3bbd759354be906bb2dcabvboxsync setter: function(n) {
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync value: "Bar",
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync setter: function(n) {
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync value: true
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync value: false,
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync setter: function(lock) {
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync return lock;
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync value: false
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync value: true
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync value: true
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync value: false
dced478b440a327fb550155c0f73c1ac968ad93bvboxsync value: true
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync value: false
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync value: false
dced478b440a327fb550155c0f73c1ac968ad93bvboxsync value: false,
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync setter: function(val) {
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync return val;
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync value: null,
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync setter: function(val) {
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync return false;
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync value: ['default'],
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync getter: function() {
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync return false;
a50f2b5d48e2f3f8bae70aa49f76f225352b67cdvboxsync setter: function(g) {
021c939a9e3f688c0c3bbd759354be906bb2dcabvboxsync value: null,
1a25adaca81841abf5e6cdfed02eaff64941357dvboxsync setter: function(g) {
021c939a9e3f688c0c3bbd759354be906bb2dcabvboxsync writeOnce: true,
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync value: null
a50f2b5d48e2f3f8bae70aa49f76f225352b67cdvboxsync writeOnce: true,
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync value: null
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync writeOnce: true,
c189e41dcbb9bbda9b5bc41e07ef0fce82bbff7avboxsync value: null
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({
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({
AttrHost.prototype._allowAdHocAttrs = false;
var h = this.createHost({
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