diff --git a/ScrollableContainer.js b/ScrollableContainer.js new file mode 100755 index 0000000000..b5b7c67c22 --- /dev/null +++ b/ScrollableContainer.js @@ -0,0 +1,29 @@ +define([ + "delite/register", + "delite/Widget", + "delite/Container", + "delite/Scrollable" +], function (register, Widget, Container, Scrollable) { + + // module: + // deliteful/ScrollableContainer + + return register("d-scrollable-container", [HTMLElement, Widget, Container, Scrollable], { + // summary: + // A container widget with scrolling capabilities. + // description: + // A container widget which can scroll its content + // horizontally and/or vertically. Its scrolling capabilities + // and API are provided by the mixin delite/Scrollable. + // example: + // | + // |
...
+ // |
...
+ // |
...
+ // |
+ + // baseClass: String + // The name of the CSS class of this widget. + baseClass: "d-scrollable-container" + }); +}); diff --git a/tests/ScrollableContainer-shared.js b/tests/ScrollableContainer-shared.js new file mode 100755 index 0000000000..70eada7be6 --- /dev/null +++ b/tests/ScrollableContainer-shared.js @@ -0,0 +1,209 @@ +define([ + "intern!object", + "intern/chai!assert", + "dojo/dom-geometry", + "dojo/dom-class" +], function (registerSuite, assert, domGeom, domClass) { + + // This object is shared by ScrollableContainer tests. + + return { + "Default CSS" : function () { + var w = document.getElementById("sc1"); + assert.isTrue(domClass.contains(w, "d-scrollable-container"), + "Expecting d-scrollable-container CSS class! (id='sc1')"); + assert.isTrue(domClass.contains(w, "d-scrollable"), // class added by the mixin delite/Scrollable + "Expecting d-scrollable CSS class! (id='sc1')"); + + w = document.getElementById("sc2"); // with scrollDirection == "none" + assert.equal(w.scrollDirection, "none", "wrong scroll direction for id=sc2!"); + assert.isTrue(domClass.contains(w, "d-scrollable-container"), + "Expecting d-scrollable-container CSS class! (id='sc2')"); + // when scrollDirection is "none", this CSS class should NOT be present: + assert.isFalse(domClass.contains(w, "d-scrollable"), + "Not expecting d-scrollable CSS class! (id='sc2')"); + + w = document.getElementById("mysc1"); + assert.isTrue(domClass.contains(w, "d-scrollable-container"), + "Expecting d-scrollable-container CSS class! (id='mysc1')"); + assert.isTrue(domClass.contains(w, "d-scrollable"), // class added by the mixin delite/Scrollable + "Expecting d-scrollable CSS class! (id='mysc1')"); + }, + + "CSS class dependency on scrollDirection" : function () { + var w = document.getElementById("sc1"); + assert.isTrue(domClass.contains(w, "d-scrollable-container"), + "Expecting d-scrollable-container CSS class! (id='sc1')"); + assert.isTrue(domClass.contains(w, "d-scrollable"), // class added by the mixin delite/Scrollable + "Expecting d-scrollable CSS class! (id='sc1')"); + + w.scrollDirection = "none"; + w.validateRendering(); // scrollDirection is an invalidating property + assert.isTrue(domClass.contains(w, "d-scrollable-container"), + "Expecting d-scrollable-container CSS class! (scrollDirection='none')"); + // when scrollDirection is "none", this CSS class should NOT be present: + assert.isFalse(domClass.contains(w, "d-scrollable"), + "Not expecting d-scrollable CSS class! (scrollDirection='none')"); + + w.scrollDirection = "vertical"; // set back to "vertical" + w.validateRendering(); + assert.isTrue(domClass.contains(w, "d-scrollable-container"), + "Expecting d-scrollable-container CSS class! (scrollDirection='vertical')"); + assert.isTrue(domClass.contains(w, "d-scrollable"), // class added by the mixin delite/Scrollable + "Expecting d-scrollable CSS class! (scrollDirection='vertical')"); + + w.scrollDirection = "horizontal"; // same for "horizontal" + w.validateRendering(); + assert.isTrue(domClass.contains(w, "d-scrollable-container"), + "Expecting d-scrollable-container CSS class! (scrollDirection='horizontal')"); + assert.isTrue(domClass.contains(w, "d-scrollable"), // class added by the mixin delite/Scrollable + "Expecting d-scrollable CSS class! (scrollDirection='horizontal')"); + + w.scrollDirection = "both"; // same for "both" + w.validateRendering(); + assert.isTrue(domClass.contains(w, "d-scrollable-container"), + "Expecting d-scrollable-container CSS class! (scrollDirection='both')"); + assert.isTrue(domClass.contains(w, "d-scrollable"), // class added by the mixin delite/Scrollable + "Expecting d-scrollable CSS class! (scrollDirection='both')"); + + w.scrollDirection = "none"; // and none again + w.validateRendering(); + assert.isTrue(domClass.contains(w, "d-scrollable-container"), + "Expecting d-scrollable-container CSS class! (scrollDirection='none')"); + // when scrollDirection is "none", this CSS class should NOT be present: + assert.isFalse(domClass.contains(w, "d-scrollable"), + "Not expecting d-scrollable CSS class! (scrollDirection='none')"); + }, + + "scrollableNode" : function () { + var w = document.getElementById("sc1"); + assert.isTrue(w.scrollableNode === w, "Wrong scrollableNode!"); + }, + + "scrollTop/scrollLeft" : function () { + var w = document.getElementById("sc1"); + w.scrollDirection = "both"; + w.validateRendering(); + assert.equal(w.scrollableNode.scrollTop, 0, "scrollTop"); + assert.equal(w.scrollableNode.scrollLeft, 0, "scrollLeft"); + }, + + "scrollBy" : function () { + var w = document.getElementById("sc1"); + var d = this.async(1000); + w.scrollDirection = "both"; + w.validateRendering(); + w.scrollBy({x: 10}); + assert.equal(w.scrollableNode.scrollLeft, 10, "scrollLeft #1"); + assert.equal(w.scrollableNode.scrollTop, 0, "scrollTop #1"); + w.scrollBy({y: 10}); + assert.equal(w.scrollableNode.scrollLeft, 10, "scrollLeft #2"); + assert.equal(w.scrollableNode.scrollTop, 10, "scrollTop #2"); + w.scrollBy({x: 10, y: 10}); + assert.equal(w.scrollableNode.scrollLeft, 20, "scrollLeft #3"); + assert.equal(w.scrollableNode.scrollTop, 20, "scrollTop #3"); + + // Now with animation: + w.scrollBy({x: 10, y: 10}, 100/*duration*/); + setTimeout(d.callback(function () { + assert.equal(w.scrollableNode.scrollLeft, 30, "scrollLeft #4"); + assert.equal(w.scrollableNode.scrollTop, 30, "scrollTop #4"); + + w.scrollBy({x: 10, y: 10}, 0/*duration*/); + // when the duration is 0, no animation, thus no need to test asynchronously + assert.equal(w.scrollableNode.scrollLeft, 40, "scrollLeft #5"); + assert.equal(w.scrollableNode.scrollTop, 40, "scrollTop #5"); + }), 1000); + + return d; + }, + + "scrollTo" : function () { + var w = document.getElementById("sc1"); + var d = this.async(1000); + w.scrollDirection = "both"; + w.validateRendering(); + w.scrollTo({x: 10}); + assert.equal(w.scrollableNode.scrollLeft, 10, "scrollLeft #1"); + w.scrollTo({y: 10}); + assert.equal(w.scrollableNode.scrollTop, 10, "scrollTop #1"); + w.scrollTo({x: 20, y: 20}); + assert.equal(w.scrollableNode.scrollLeft, 20, "scrollLeft #2"); + assert.equal(w.scrollableNode.scrollTop, 20, "scrollTop #2"); + + // Now with animation: + w.scrollTo({x: 30, y: 30}, 100/*duration*/); + setTimeout(d.callback(function () { + assert.equal(w.scrollableNode.scrollLeft, 30, "scrollLeft #3"); + assert.equal(w.scrollableNode.scrollTop, 30, "scrollTop #3"); + + w.scrollTo({x: 40, y: 40}, 0/*duration*/); + // when the duration is 0, no animation, thus no need to test asynchronously + assert.equal(w.scrollableNode.scrollLeft, 40, "scrollLeft #4"); + assert.equal(w.scrollableNode.scrollTop, 40, "scrollTop #4"); + }), 1000); + + return d; + }, + + "getCurrentScroll" : function () { + var w = document.getElementById("sc1"); + var pos = {x: 10, y: 10}; + w.scrollDirection = "both"; + w.validateRendering(); + w.scrollTo(pos); + assert.deepEqual(w.getCurrentScroll(), pos, "Wrong getCurrentScroll!"); + }, + + "isTop/Bottom/Left/RightScroll" : function () { + var w = document.getElementById("sc1"); + var wContent = document.getElementById("sc1content"); + var pos = {x: 10, y: 10}; + var box = domGeom.getMarginBox(wContent); + var width = box.w; + var height = box.h; + w.scrollDirection = "both"; + w.validateRendering(); + w.scrollTo(pos); + assert.isFalse(w.isTopScroll(), "isTopScroll() #1"); + assert.isFalse(w.isBottomScroll(), "isBottomScroll() #1"); + assert.isFalse(w.isRightScroll(), "isRightScroll() #1"); + assert.isFalse(w.isLeftScroll(), "isLeftScroll() #1"); + + pos = {x: 0, y: 10}; + w.scrollTo(pos); + assert.isFalse(w.isTopScroll(), "isTopScroll() #2"); + assert.isFalse(w.isBottomScroll(), "isBottomScroll() #2"); + assert.isFalse(w.isRightScroll(), "isRightScroll() #2"); + assert.isTrue(w.isLeftScroll(), "isLeftScroll() #2"); + + pos = {x: 10, y: 0}; + w.scrollTo(pos); + assert.isTrue(w.isTopScroll(), "isTopScroll() #3"); + assert.isFalse(w.isBottomScroll(), "isBottomScroll() #3"); + assert.isFalse(w.isRightScroll(), "isRightScroll() #3"); + assert.isFalse(w.isLeftScroll(), "isLeftScroll() #3"); + + pos = {x: width, y: 10}; + w.scrollTo(pos); + assert.isFalse(w.isTopScroll(), "isTopScroll() #4"); + assert.isFalse(w.isBottomScroll(), "isBottomScroll() #4"); + assert.isTrue(w.isRightScroll(), "isRightScroll() #4"); + assert.isFalse(w.isLeftScroll(), "isLeftScroll() #4"); + + pos = {x: 10, y: height}; + w.scrollTo(pos); + assert.isFalse(w.isTopScroll(), "isTopScroll() #5"); + assert.isTrue(w.isBottomScroll(), "isBottomScroll() #5"); + assert.isFalse(w.isRightScroll(), "isRightScroll() #5"); + assert.isFalse(w.isLeftScroll(), "isLeftScroll() #5"); + + pos = {x: 0, y: 0}; + w.scrollTo(pos); + assert.isTrue(w.isTopScroll(), "isTopScroll() #6"); + assert.isFalse(w.isBottomScroll(), "isBottomScroll() #6"); + assert.isFalse(w.isRightScroll(), "isRightScroll() #6"); + assert.isTrue(w.isLeftScroll(), "isLeftScroll() #6"); + } + }; +}); diff --git a/tests/ScrollableContainer.js b/tests/ScrollableContainer.js new file mode 100755 index 0000000000..c861af12f2 --- /dev/null +++ b/tests/ScrollableContainer.js @@ -0,0 +1,89 @@ +define([ + "dcl/dcl", + "intern!object", + "intern/chai!assert", + "dojo/dom-class", + "delite/register", + "delite/Widget", + "delite/Scrollable", + "deliteful/ScrollableContainer", + "./ScrollableContainer-shared" +], function (dcl, registerSuite, assert, domClass, register, Widget, + Scrollable, ScrollableContainer, ScrollableSharedTests) { + + // Note that the actual testing is done in ScrollableContainer-shared. + + var container, MyScrollableWidget, MyScrollableContainer; + /*jshint multistr: true */ + var html = " \ +
\ +
\ + \ + \ + \ + "; + + + // Markup use-case + + var suite = { + name: "delite/ScrollableContainer: markup", + setup: function () { + container = document.createElement("div"); + document.body.appendChild(container); + container.innerHTML = html; + register("my-scrolable-container", [ScrollableContainer], {}); + register.parse(); + }, + teardown: function () { + container.parentNode.removeChild(container); + } + }; + + dcl.mix(suite, ScrollableSharedTests); + + registerSuite(suite); + + // Programatic creation + + suite = { + name: "delite/ScrollableContainer: programatic", + setup: function () { + container = document.createElement("div"); + document.body.appendChild(container); + + MyScrollableContainer = register("my-sc-prog", [ScrollableContainer], {}); + + var w = new ScrollableContainer({ id: "sc1" }); + w.style.position = "absolute"; + w.style.width = "200px"; + w.style.height = "200px"; + container.appendChild(w); + w.startup(); + + var innerContent = document.createElement("div"); + innerContent.id = "sc1content"; + innerContent.style.width = "2000px"; + innerContent.style.height = "2000px"; + w.appendChild(innerContent); + w.startup(); + + w = new MyScrollableContainer({ id: "mysc1" }); + container.appendChild(w); + w.startup(); + + w = new ScrollableContainer({ id: "sc2" }); + w.scrollDirection = "none"; + container.appendChild(w); + w.startup(); + }, + teardown: function () { + container.parentNode.removeChild(container); + } + }; + + dcl.mix(suite, ScrollableSharedTests); + + registerSuite(suite); +}); diff --git a/tests/intern/unit.js b/tests/intern/unit.js index 7f48721ad4..fe04d5e328 100644 --- a/tests/intern/unit.js +++ b/tests/intern/unit.js @@ -1,3 +1,4 @@ // Listing of all the deliteful unit tests define([ + "../ScrollableContainer" ]); diff --git a/tests/test_ScrollableContainer-full-screen.html b/tests/test_ScrollableContainer-full-screen.html new file mode 100755 index 0000000000..41d830df06 --- /dev/null +++ b/tests/test_ScrollableContainer-full-screen.html @@ -0,0 +1,131 @@ + + + + + + + ScrollableContainer demo + + + + + + + + + + + + +
Header
+ + + + + +
Footer
+
+ + diff --git a/tests/test_ScrollableContainer-small.html b/tests/test_ScrollableContainer-small.html new file mode 100755 index 0000000000..16d138a0fb --- /dev/null +++ b/tests/test_ScrollableContainer-small.html @@ -0,0 +1,221 @@ + + + + + + + ScrollableContainer demo + + + + + + + + + + + + +
Header 1
+ + + + + +
Footer 1
+
+ + +
Header 2
+ + + + + +
Footer 2
+
+ + diff --git a/tests/test_ScrollableContainer.html b/tests/test_ScrollableContainer.html new file mode 100755 index 0000000000..d3b8d78eba --- /dev/null +++ b/tests/test_ScrollableContainer.html @@ -0,0 +1,194 @@ + + + + + + + ScrollableContainer demo + + + + + + + + + + + + + + + + + + + + + + + + + +