attribute.html revision f56f1f09f1262a349b35886a3dc54e54e53087c0
aadc0b0e666b9b335884a2437510798ae8949343Adam Moore<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
aadc0b0e666b9b335884a2437510798ae8949343Adam Moore <script type="text/javascript" src="/build/yui/yui.js"></script>
aadc0b0e666b9b335884a2437510798ae8949343Adam Moore #console .yui-console-entry {
aadc0b0e666b9b335884a2437510798ae8949343Adam Moore padding:2px;
aadc0b0e666b9b335884a2437510798ae8949343Adam Moore min-height:0;
aadc0b0e666b9b335884a2437510798ae8949343Adam Moore #console .yui-console-entry-fail .yui-console-entry-cat {
aadc0b0e666b9b335884a2437510798ae8949343Adam Moore background-color:red;
aadc0b0e666b9b335884a2437510798ae8949343Adam Moore #console .yui-console-entry-pass .yui-console-entry-cat {
aadc0b0e666b9b335884a2437510798ae8949343Adam Moore background-color:green;
aadc0b0e666b9b335884a2437510798ae8949343Adam Moore #console .yui-console-entry-perf .yui-console-entry-cat {
3a1493afa5d204a301f770bf1e95318cf9a7bff8Adam Moore background-color:blue;
0bb2673f6a4a24e3d3f8952c58484f657a9f8de4Adam Moore position:static;
aadc0b0e666b9b335884a2437510798ae8949343Adam Moore html, body {
aadc0b0e666b9b335884a2437510798ae8949343Adam Moore height:100%;
84ef1431cec1eb31a3bc3f3b96ef5e9f885b367bAdam Moore YUI({filter:"raw", useBrowserConsole:false}).use("dump", "attribute-complex", "base", "console", "test", function(Y) {
aadc0b0e666b9b335884a2437510798ae8949343Adam Moore function areObjectsReallyEqual(o1, o2) {
aadc0b0e666b9b335884a2437510798ae8949343Adam Moore function Test(cfg, lazy, silentInit) {
aadc0b0e666b9b335884a2437510798ae8949343Adam Moore this._lazyAddAttrs = lazy;
aadc0b0e666b9b335884a2437510798ae8949343Adam Moore this._silentInit = silentInit;
3a1493afa5d204a301f770bf1e95318cf9a7bff8Adam Moore Test.superclass.constructor.apply(this, arguments);
aadc0b0e666b9b335884a2437510798ae8949343Adam Moore value: "Foo",
aadc0b0e666b9b335884a2437510798ae8949343Adam Moore setter: function(n) {
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);
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("AdHoc", "TestAdHoc");
h.addAttr("AdHoc", {
return val.toUpperCase();
h.set("AdHoc", "TestAdHocConfigured");
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");
Y.Test.Runner.add(new Y.Test.Case(basicTemplate)); // Running again, to make sure static attributes aren't modified
Y.Test.Runner.add(new Y.Test.Case(extendedTemplate)); // Running again, to make sure static attributes aren't modified