diff --git a/src/widget/HISTORY.md b/src/widget/HISTORY.md index a898d8e08c9..bc5e6d7dfa0 100644 --- a/src/widget/HISTORY.md +++ b/src/widget/HISTORY.md @@ -4,18 +4,18 @@ Widget Change History @VERSION@ ------ -* No changes. +* Improved support for single-box widgets (BB === CB) by defaulting boundingBox to srcNode if CONTENT_TEMPLATE is null. 3.11.0 ------ -* The Widget HTML_PARSER implementation has been updated to use the new +* The Widget HTML_PARSER implementation has been updated to use the new _preAddAttrs() hook in Base, since Base now adds all attributes across the hierarchy in one shot. Widget HTML_PARSER requires contentBox/srcNode, and related attributes to be set up first. This is purely an internal implementation change at the base Widget layer, - and there is no impact to existing implementations. + and there is no impact to existing implementations. 3.10.3 ------ diff --git a/src/widget/js/Widget.js b/src/widget/js/Widget.js index fe9e313df54..b6c319c6e45 100644 --- a/src/widget/js/Widget.js +++ b/src/widget/js/Widget.js @@ -181,7 +181,7 @@ ATTRS[RENDERED] = { * @writeOnce */ ATTRS[BOUNDING_BOX] = { - value:null, + valueFn:"_defaultBB", setter: "_setBB", writeOnce: TRUE }; @@ -773,6 +773,25 @@ Y.extend(Widget, Y.Base, { return (this.CONTENT_TEMPLATE === null) ? this.get(BOUNDING_BOX) : this._setBox(null, node, this.CONTENT_TEMPLATE, false); }, + /** + * Returns the default value for the boundingBox attribute. + * + * For the Widget class, this will most commonly be null (resulting in a new + * boundingBox node instance being created), unless a srcNode was provided + * and CONTENT_TEMPLATE is null, in which case it will be srcNode. + * This behavior was introduced in @VERSION@ to accomodate single-box widgets + * whose BB & CB both point to srcNode (e.g. Y.Button). + * + * @method _defaultBB + * @protected + */ + _defaultBB : function() { + var node = this.get(SRC_NODE), + nullCT = (this.CONTENT_TEMPLATE === null); + + return ((node && nullCT) ? node : null); + }, + /** * Returns the default value for the contentBox attribute. * diff --git a/src/widget/tests/unit/widget.html b/src/widget/tests/unit/widget.html index 6d0d9d8b432..25d226e0fe4 100644 --- a/src/widget/tests/unit/widget.html +++ b/src/widget/tests/unit/widget.html @@ -988,6 +988,41 @@ Y.Assert.areEqual("myWidget[foo]", w.toString()); + w.destroy(); + }, + + "testBoundingBoxWithSrcNode" : function() { + var w = this.createWidget({ + boundingBox: Y.Node.create(""), + srcNode: Y.Node.create("") + }); + + Y.Assert.areEqual("span", w.get("boundingBox").get("tagName").toLowerCase()); + Y.Assert.areEqual("span", w.get("contentBox").get("tagName").toLowerCase()); + Y.Assert.areEqual("bb", w.get("boundingBox").get("id")); + Y.Assert.areEqual("cb", w.get("contentBox").get("id")); + + w.destroy(); + }, + + "testOverridenBoundingBoxATTR" : function() { + function MyOtherWidget () { + MyOtherWidget.superclass.constructor.apply(this, arguments); + } + + Y.extend(MyOtherWidget, MyWidget, {}, { + NAME: 'MyOtherWidget', + ATTRS: { + boundingBox: { + value: Y.Node.create('
') + } + } + }); + + var w = new MyOtherWidget(); + + Y.Assert.areEqual("another-widget", w.get("boundingBox").get("id")); + w.destroy(); } }, true); @@ -1059,8 +1094,7 @@ w.render(); - // FIXME: Include after this is fixed: http://yuilibrary.com/projects/yui3/ticket/2530076, 2530311. - // Y.Assert.areSame(n, w.get("contentBox"), "srcNode not used as content box"); + Y.Assert.areSame(n, w.get("contentBox"), "srcNode not used as content box"); Y.Assert.isFalse(w.get("boundingBox").hasClass("yui3-mysingleboxwidget-loading"), "yui3-mysingleboxwidget-loading should have removed"); w.destroy(); @@ -1146,7 +1180,7 @@ w.destroy(); }, - // FIXME: Include after this is fixed: http://yuilibrary.com/projects/yui3/ticket/2530076, 2530311. + // FIXME: Include after this is fixed: http://yuilibrary.com/projects/yui3/ticket/2530076. "testContentBox" : null, /* @@ -1190,7 +1224,7 @@ w.destroy(); }, - // FIXME: Include after this is fixed: http://yuilibrary.com/projects/yui3/ticket/2530076, 2530311. + // FIXME: Include after this is fixed: http://yuilibrary.com/projects/yui3/ticket/2530076. "testContentBoxRenderTo" : null, /* @@ -1214,11 +1248,7 @@ }, */ - // FIXME: Include after this is fixed: http://yuilibrary.com/projects/yui3/ticket/2530076, 2530311. - "testSrcNode" : null, - - /* - function() { + "testSrcNode" : function() { var container = Y.one("#widgetRenderContainer"); container.append("
"); @@ -1235,11 +1265,10 @@ Y.Assert.isTrue(w.get("boundingBox").compareTo(sn), "cb !== bb !== sn"); Y.Assert.isTrue(w.get("boundingBox").get("parentNode").compareTo(container), "srcNode moved from it's place in the DOM"); - // Y.Assert.isNotNull(w.get("contentBox").one("#foo"), "contents of srcNode not maintained"); + Y.Assert.isNotNull(w.get("contentBox").one("#foo"), "contents of srcNode not maintained"); w.destroy(true); - } - */ + }, // CONSCIOUSLY NOT TESTED - CAN'T PASS 2 BOXES TO A SINGLE BOX WIDGET "testBoundingBoxContentBox" : null, @@ -1252,6 +1281,21 @@ Y.Assert.areEqual("mySingleBoxWidget[foo]", w.toString()); + w.destroy(); + }, + + "testBoundingBoxWithSrcNode" : function() { + var w = this.createWidget({ + boundingBox: Y.Node.create(""), + srcNode: Y.Node.create("") + }); + + // If CONTENT_TEMPLATE is null, CB resolves to BB (see: Widget#_setCB). + // While creating a single-box by specifying BB & srcNode probably doesn't, + // make sense, this test is here to ensure that changes to current behavior are + // considered before being made. + Y.Assert.isTrue(w.get("contentBox").compareTo(w.get("boundingBox")), "bb !== cb"); + w.destroy(); }