From 0d9a9b8e2d7a529475600d3589d4e1a50c41cb90 Mon Sep 17 00:00:00 2001 From: Patrick Tsai Date: Sat, 22 Aug 2015 22:45:00 -0400 Subject: [PATCH] v1.12.0 - parent sections now auto-check if all children are selected --- Gruntfile.js | 2 +- jquery.tree-multiselect.min.css | 2 +- jquery.tree-multiselect.min.js | 4 +- package.json | 2 +- src/jquery.tree-multiselect.css | 2 +- src/jquery.tree-multiselect.js | 39 +++++- test/helper.js | 3 + test/integration/options.html | 124 ------------------- test/integration/options.js | 124 +++++++++++++++++++ test/integration/section-creation.js | 148 +++++++++++++++++++++++ test/integration/sections.html | 160 ------------------------- test/integration/title-autochecking.js | 74 ++++++++++++ test/runner.html | 16 +++ 13 files changed, 405 insertions(+), 295 deletions(-) create mode 100644 test/helper.js delete mode 100644 test/integration/options.html create mode 100644 test/integration/options.js create mode 100644 test/integration/section-creation.js delete mode 100644 test/integration/sections.html create mode 100644 test/integration/title-autochecking.js create mode 100644 test/runner.html diff --git a/Gruntfile.js b/Gruntfile.js index ea8cb0f..5d45ad7 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -5,7 +5,7 @@ module.exports = function(grunt) { options: { force: true }, - all: ['test/**/*.html'] + all: ['test/runner.html'] }, cssmin: { dist: { diff --git a/jquery.tree-multiselect.min.css b/jquery.tree-multiselect.min.css index f30a0cf..08798f1 100644 --- a/jquery.tree-multiselect.min.css +++ b/jquery.tree-multiselect.min.css @@ -1,2 +1,2 @@ -/* jQuery Tree Multiselect v1.11.1 | (c) Patrick Tsai | MIT Licensed */ +/* jQuery Tree Multiselect v1.12.0 | (c) Patrick Tsai | MIT Licensed */ div.tree-multiselect div.title:hover,div.tree-multiselect input[type=checkbox]:hover{cursor:pointer}div.tree-multiselect{border:2px solid #D8D8D8;border-radius:5px;display:table;height:inherit;width:100%}div.tree-multiselect>div.selected,div.tree-multiselect>div.selections{vertical-align:top;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;display:table-cell;padding:1%;width:50%}div.tree-multiselect>div.selections{border-right:solid 2px #D8D8D8}div.tree-multiselect div.section>div.item,div.tree-multiselect div.section>div.section{padding-left:20px}div.tree-multiselect div.item,div.tree-multiselect div.title{margin-bottom:2px}div.tree-multiselect div.title{background:#767676;color:#fff;padding:2px}div.tree-multiselect div.title>*{display:inline-block}div.tree-multiselect div.title>span.collapse-section{margin:0 3px;width:8px}div.tree-multiselect input[type=checkbox]{margin-right:5px}div.tree-multiselect>div.selections div.item{margin-left:16px}div.tree-multiselect>div.selected>div.item{padding:2px 5px;border-radius:2px;background:#EAEAEA}div.tree-multiselect>div.selected>div.item.ui-sortable-handle:hover{cursor:move}div.tree-multiselect span.description,div.tree-multiselect span.remove-selected{padding:0 3px;margin-right:5px;background:#777;color:#fff;border-radius:2px}div.tree-multiselect span.remove-selected:hover{cursor:pointer}div.tree-multiselect span.description:hover{cursor:help}div.tree-multiselect div.temp-description-popup{background:#FAFAFA;padding:5px;border:2px solid #676767;border-radius:3px}div.tree-multiselect span.selectedSectionName{float:right;font-style:italic} \ No newline at end of file diff --git a/jquery.tree-multiselect.min.js b/jquery.tree-multiselect.min.js index ecbcd7f..d20151e 100644 --- a/jquery.tree-multiselect.min.js +++ b/jquery.tree-multiselect.min.js @@ -1,2 +1,2 @@ -/* jQuery Tree Multiselect v1.11.1 | (c) Patrick Tsai | MIT Licensed */ -!function(a){function b(b){return a(b).clone().children().remove().end().text()}function c(b){var c={allowBatchSelection:!0,sortable:!1,collapsible:!0,sectionDelimiter:"/",showSectionOnSelected:!0,startCollapsed:!1};return a.extend({},c,b)}function d(b,c){function d(b,c){for(var d=f,e=0;e option").each(function(){var b=a(this).attr("data-section").split(n.sectionDelimiter),c=a(this).val(),e=a(this).text(),f=a(this).attr("data-description"),g=a(this).attr("data-index"),h=new p(c,e,f,g);d(b,h)}),e.call(c,f)}function e(b){function c(b){var c=document.createElement("div");c.className="section";var d=document.createElement("div");return d.className="title",d.innerHTML=b,a(c).append(d),a(this).append(c),c}function d(b){var c=b.text,d=b.value,e=b.description,f=b.index,g=document.createElement("div");g.className="item",a(g).text(c||d).attr({"data-value":d,"data-description":e,"data-index":f}),a(this).append(g)}if(b.constructor==p)d.call(this,b);else if(a.isArray(b))for(var f=0;f?"),d=a(b).find("div.item[data-description!=''][data-description]");c.prependTo(d),a("div.item > span.description").unbind().mouseenter(function(){var b=a(this).parent(),c=b.attr("data-description"),d=document.createElement("div");d.className="temp-description-popup",d.innerHTML=c,d.style.position="absolute",b.append(d)}).mouseleave(function(){a("div.temp-description-popup").remove()})}function g(b){var c=a("",{type:"checkbox"}),d=null;d=n.allowBatchSelection?a(b).find("div.title, div.item"):a(b).find("div.item"),c.prependTo(d),a(b).find("input[type=checkbox]").click(function(a){a.stopPropagation()})}function h(b,c){var d=a(b).val();if(d)for(var e=0;e input[type=checkbox]").prop("checked",!0)}}function i(b){var c=a(b).find("div.title > input[type=checkbox]");c.change(function(){var b=a(this).closest("div.section"),c=b.find("input[type=checkbox]"),d=a(this).is(":checked");c.prop("checked",d)})}function j(b){var c=a(b).find("input[type=checkbox]");c.change(function(){if(!a(this).is(":checked")){var b=a(this).parents("div.section");b.find("> div.title > input[type=checkbox]").prop("checked",!1)}})}function k(b){var c="-",d="+",e=a(b).find("div.title"),f=document.createElement("span");f.className="collapse-section",n.startCollapsed?(a(f).text(d),e.siblings().toggle()):a(f).text(c),e.prepend(f),a("span.collapse-section").unbind().click(function(b){b.stopPropagation();var e=a(this).text();a(this).text(e==c?d:c);var f=a(this).parent();f.siblings().toggle()}),e.click(function(){a(this).find("> span.collapse-section").trigger("click")})}function l(c,d,e){function f(b){var c=b.text,e=b.value,f=b.sectionName,g=document.createElement("div");g.className="item",g.innerHTML=c,n.showSectionOnSelected&&a(g).append(""+f+""),a(g).attr("data-value",e).prepend("×").appendTo(d)}function g(e){var g=[];a(d).find("div.item").each(function(){g.push(b(this))});var h=e.filter(function(a){return-1==g.indexOf(a.text)});h.forEach(function(a){f(a)}),m(c,d)}function h(c){var e=[];c.forEach(function(a){e.push(a.text)}),a(d).find("div.item").each(function(){var c=b(this);-1==e.indexOf(c)&&a(this).remove()})}function i(){var b=a(e),c=[];a(d).find("div.item").each(function(){c.push(a(this).attr("data-value"))}),b.val(c),a(e).html(a(e).find("option").sort(function(b,d){var e=c.indexOf(a(b).attr("value")),f=c.indexOf(a(d).attr("value"));return e>f?1:f>e?-1:0}))}function j(){var e=a(c).find("div.item").has("> input[type=checkbox]:checked"),f=[];if(e.each(function(c){var d=b(this),e=a(this).attr("data-value"),g=a(this).attr("data-index");a(this).attr("data-index",void 0);var h=a.map(a(this).parents("div.section").get().reverse(),function(c){return b(a(c).find("> div.title"))}).join("/");f.push({text:d,value:e,index:g,sectionName:h})}),f.sort(function(a,b){return a.index>b.index?1:a.index input[type=checkbox]");e.prop("checked",!1),e.trigger("change")})}var n;a.fn.treeMultiselect=function(b){return n=c(b),this.each(function(){var b=a(this);b.attr("multiple","").css("display","none");var c=new o;c.build(b);var e=c.selections;d(b,e),f(e),g(e),h(b,e),i(e),j(e),n.collapsible&&k(e);var p=c.selected;l(e,p,b),m(e,p)}),this};var o=function(){};o.prototype.build=function(b){var c=document.createElement("div");c.className="tree-multiselect",a(b).after(c);var d=document.createElement("div");d.className="selections",a(c).append(d);var e=document.createElement("div");e.className="selected",a(c).append(e),this.tree=c,this.selections=d,this.selected=e};var p=function(a,b,c,d){this.value=a,this.text=b,this.description=c,this.index=d}}(jQuery); \ No newline at end of file +/* jQuery Tree Multiselect v1.12.0 | (c) Patrick Tsai | MIT Licensed */ +!function(a){function b(b){return a(b).clone().children().remove().end().text()}function c(b){var c={allowBatchSelection:!0,sortable:!1,collapsible:!0,sectionDelimiter:"/",showSectionOnSelected:!0,startCollapsed:!1};return a.extend({},c,b)}function d(b,c){function d(b,c){for(var d=f,e=0;e option").each(function(){var b=a(this).attr("data-section").split(o.sectionDelimiter),c=a(this).val(),e=a(this).text(),f=a(this).attr("data-description"),g=a(this).attr("data-index"),h=new q(c,e,f,g);d(b,h)}),e.call(c,f)}function e(b){function c(b){var c=document.createElement("div");c.className="section";var d=document.createElement("div");return d.className="title",d.innerHTML=b,a(c).append(d),a(this).append(c),c}function d(b){var c=b.text,d=b.value,e=b.description,f=b.index,g=document.createElement("div");g.className="item",a(g).text(c||d).attr({"data-value":d,"data-description":e,"data-index":f}),a(this).append(g)}if(b.constructor==q)d.call(this,b);else if(a.isArray(b))for(var f=0;f?"),d=a(b).find("div.item[data-description!=''][data-description]");c.prependTo(d),a("div.item > span.description").unbind().mouseenter(function(){var b=a(this).parent(),c=b.attr("data-description"),d=document.createElement("div");d.className="temp-description-popup",d.innerHTML=c,d.style.position="absolute",b.append(d)}).mouseleave(function(){a("div.temp-description-popup").remove()})}function g(b){var c=a("",{type:"checkbox"}),d=null;d=o.allowBatchSelection?a(b).find("div.title, div.item"):a(b).find("div.item"),c.prependTo(d),a(b).find("input[type=checkbox]").click(function(a){a.stopPropagation()})}function h(b,c){var d=a(b).val();if(d)for(var e=0;e input[type=checkbox]").prop("checked",!0)}}function i(b){var c=a(b).find("div.title > input[type=checkbox]");c.change(function(){var b=a(this).closest("div.section"),c=b.find("input[type=checkbox]"),d=a(this).is(":checked");c.prop("checked",d)})}function j(b){var c=a(b).find("input[type=checkbox]");c.change(function(){if(!a(this).is(":checked")){var c=a(this).parentsUntil(b,"div.section");c.find("> div.title > input[type=checkbox]").prop("checked",!1)}})}function k(b){function c(){var c=a(b).find("div.section");c.each(function(){var b=a(this),c=b.find("div.item"),d=c.filter(function(){var b=a(this).find("> input[type=checkbox]");return!b.is(":checked")});if(0===d.length){var e=a(this).find("> div.title > input[type=checkbox]");e.prop("checked",!0)}})}var d=a(b).find("div.item > input[type=checkbox]");d.change(function(){c()}),c()}function l(b){var c="-",d="+",e=a(b).find("div.title"),f=document.createElement("span");f.className="collapse-section",o.startCollapsed?(a(f).text(d),e.siblings().toggle()):a(f).text(c),e.prepend(f),a("span.collapse-section").unbind().click(function(b){b.stopPropagation();var e=a(this).text();a(this).text(e==c?d:c);var f=a(this).parent();f.siblings().toggle()}),e.click(function(){a(this).find("> span.collapse-section").trigger("click")})}function m(c,d,e){function f(b){var c=b.text,e=b.value,f=b.sectionName,g=document.createElement("div");g.className="item",g.innerHTML=c,o.showSectionOnSelected&&a(g).append(""+f+""),a(g).attr("data-value",e).prepend("×").appendTo(d)}function g(e){var g=[];a(d).find("div.item").each(function(){g.push(b(this))});var h=e.filter(function(a){return-1==g.indexOf(a.text)});h.forEach(function(a){f(a)}),n(c,d)}function h(c){var e=[];c.forEach(function(a){e.push(a.text)}),a(d).find("div.item").each(function(){var c=b(this);-1==e.indexOf(c)&&a(this).remove()})}function i(){var b=a(e),c=[];a(d).find("div.item").each(function(){c.push(a(this).attr("data-value"))}),b.val(c),a(e).html(a(e).find("option").sort(function(b,d){var e=c.indexOf(a(b).attr("value")),f=c.indexOf(a(d).attr("value"));return e>f?1:f>e?-1:0}))}function j(){var e=a(c).find("div.item").has("> input[type=checkbox]:checked"),f=[];if(e.each(function(d){var e=b(this),g=a(this).attr("data-value"),h=a(this).attr("data-index");a(this).attr("data-index",void 0);var i=a.map(a(this).parentsUntil(c,"div.section").get().reverse(),function(c){return b(a(c).find("> div.title"))}).join("/");f.push({text:e,value:g,index:h,sectionName:i})}),f.sort(function(a,b){return a.index>b.index?1:a.index input[type=checkbox]");e.prop("checked",!1),e.trigger("change")})}var o;a.fn.treeMultiselect=function(b){return o=c(b),this.each(function(){var b=a(this);b.attr("multiple","").css("display","none");var c=new p;c.build(b);var e=c.selections;d(b,e),f(e),g(e),h(b,e),o.allowBatchSelection&&(i(e),j(e),k(e)),o.collapsible&&l(e);var q=c.selected;m(e,q,b),n(e,q)}),this};var p=function(){};p.prototype.build=function(b){var c=document.createElement("div");c.className="tree-multiselect",a(b).after(c);var d=document.createElement("div");d.className="selections",a(c).append(d);var e=document.createElement("div");e.className="selected",a(c).append(e),this.tree=c,this.selections=d,this.selected=e};var q=function(a,b,c,d){this.value=a,this.text=b,this.description=c,this.index=d}}(jQuery); \ No newline at end of file diff --git a/package.json b/package.json index d7636c8..91cd548 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "jquery.tree-multiselect.js", - "version": "1.11.1", + "version": "1.12.0", "description": "jQuery multiple select with nested options", "main": "jquery.tree-multiselect.min.js", "scripts": { diff --git a/src/jquery.tree-multiselect.css b/src/jquery.tree-multiselect.css index 83f352e..a1f06e5 100644 --- a/src/jquery.tree-multiselect.css +++ b/src/jquery.tree-multiselect.css @@ -1,6 +1,6 @@ /* * jQuery Tree Multiselect - * v1.11.1 + * v1.12.0 * * (c) Patrick Tsai * MIT Licensed diff --git a/src/jquery.tree-multiselect.js b/src/jquery.tree-multiselect.js index 626b2f0..6ef0808 100644 --- a/src/jquery.tree-multiselect.js +++ b/src/jquery.tree-multiselect.js @@ -1,6 +1,6 @@ /* * jQuery Tree Multiselect - * v1.11.1 + * v1.12.0 * * (c) Patrick Tsai * MIT Licensed @@ -25,8 +25,12 @@ addDescriptionHover(selectionContainer); addCheckboxes(selectionContainer); checkPreselectedSelections(originalSelect, selectionContainer); - armTitleCheckboxes(selectionContainer); - uncheckParentsOnUnselect(selectionContainer); + + if (options.allowBatchSelection) { + armTitleCheckboxes(selectionContainer); + uncheckParentsOnUnselect(selectionContainer); + checkParentsOnAllChildrenSelected(selectionContainer); + } if (options.collapsible) { addCollapsibility(selectionContainer); @@ -241,11 +245,36 @@ var checkboxes = $(selectionContainer).find("input[type=checkbox]"); checkboxes.change(function() { if ($(this).is(":checked")) return; - var sectionParents = $(this).parents("div.section"); + var sectionParents = $(this).parentsUntil(selectionContainer, "div.section"); sectionParents.find("> div.title > input[type=checkbox]").prop('checked', false); }); } + function checkParentsOnAllChildrenSelected(selectionContainer) { + function check() { + var sections = $(selectionContainer).find("div.section"); + sections.each(function() { + var section = $(this); + var sectionItems = section.find("div.item"); + var unselectedItems = sectionItems.filter(function() { + var checkbox = $(this).find("> input[type=checkbox]"); + return !(checkbox.is(":checked")); + }); + if (unselectedItems.length === 0) { + var sectionCheckbox = $(this).find("> div.title > input[type=checkbox]"); + sectionCheckbox.prop('checked', true); + } + }); + } + + var checkboxes = $(selectionContainer).find("div.item > input[type=checkbox]"); + checkboxes.change(function() { + check(); + }); + + check(); + } + function addCollapsibility(selectionContainer) { var hideIndicator = "-"; var expandIndicator = "+"; @@ -352,7 +381,7 @@ var value = $(this).attr('data-value'); var index = $(this).attr('data-index'); $(this).attr('data-index', undefined); - var sectionName = $.map($(this).parents("div.section").get().reverse(), function(parentSection) { + var sectionName = $.map($(this).parentsUntil(selectionContainer, "div.section").get().reverse(), function(parentSection) { return textOf($(parentSection).find("> div.title")); }).join("/"); selections.push({ text: text, value: value, index: index, sectionName: sectionName }); diff --git a/test/helper.js b/test/helper.js new file mode 100644 index 0000000..a884ec4 --- /dev/null +++ b/test/helper.js @@ -0,0 +1,3 @@ +function textOf(el) { + return $(el).clone().children().remove().end().text(); +} diff --git a/test/integration/options.html b/test/integration/options.html deleted file mode 100644 index 59126ac..0000000 --- a/test/integration/options.html +++ /dev/null @@ -1,124 +0,0 @@ - -
- - - - - diff --git a/test/integration/options.js b/test/integration/options.js new file mode 100644 index 0000000..cb771d2 --- /dev/null +++ b/test/integration/options.js @@ -0,0 +1,124 @@ +QUnit.module("Options", { + beforeEach: function(assert) { + var select = document.createElement("select"); + select.setAttribute("multiple", "multiple"); + $("div#qunit-fixture").append(select); + assert.equal($("select").length, 1); + } +}); + +QUnit.test("Is collapsible by default, but not collapsed", function(assert) { + $("select").append(""); + $("select").append(""); + $("select").append(""); + $("select").treeMultiselect(); + + $("div.section").each(function() { + var collapseSpan = $(this).find("> div.title > span.collapse-section"); + assert.equal(collapseSpan.length, 1, "should have a collapse element"); + }); + + $("div.item").each(function() { + assert.ok($(this).is(":visible"), "all items should be visible"); + }); +}); + +QUnit.test("Can be collapsed if specified", function(assert) { + $("select").append(""); + $("select").append(""); + $("select").append(""); + + $("select").append(""); + $("select").append(""); + $("select").append(""); + + var options = { + startCollapsed: true + }; + + $("select").treeMultiselect(options); + + $("div.item").each(function() { + assert.ok($(this).is(":hidden"), "all items should be hidden"); + }); + + $("div.section div.section").each(function() { + assert.ok($(this).is(":hidden"), "all inner sections should be hidden"); + }); +}); + +QUnit.test("startCollapsed doesn't do anything if collapsible is false", function(assert) { + $("select").append(""); + $("select").append(""); + $("select").append(""); + + $("select").append(""); + $("select").append(""); + $("select").append(""); + + var options = { + collapsible: false, + startCollapsed: true + }; + + $("select").treeMultiselect(options); + + $("div.item").each(function() { + assert.ok($(this).is(":visible"), "all items should be hidden"); + }); + + $("div.section div.section").each(function() { + assert.ok($(this).is(":visible"), "all inner sections should be visible"); + }); +}); + +QUnit.test("can set a different section delimiter", function(assert) { + var options = { + sectionDelimiter: '-' + }; + + $("select").append(""); + $("select").append(""); + $("select").append(""); + + $("select").treeMultiselect(options); + + assert.equal($("div.selections div.section").length, 3, "should be three sections"); + + var innerSections = $("div.selections div.section > div.section"); + assert.equal(innerSections.length, 2, "should be two inner sections"); + + assert.equal(textOf(innerSections.first().find("div.title")), "inner", "first inner section name is incorrect"); + assert.equal(textOf(innerSections.last().find("div.title")), "inner2", "first inner section name is incorrect"); +}); + +QUnit.test("can disable batch select", function(assert) { + var options = { + allowBatchSelection: false + }; + + $("select").append(""); + $("select").append(""); + $("select").append(""); + + $("select").append(""); + $("select").append(""); + $("select").append(""); + $("select").treeMultiselect(options); + + var title = $("div.selections > div.section > div.title"); + + assert.equal(title.find("> input[type=checkbox]").length, 0, "should be no checkboxes on titles anywhere"); +}); + +QUnit.test("can disable section display on selected items", function(assert) { + $("select").append(""); + var options = { + showSectionOnSelected: false + }; + $("select").treeMultiselect(options); + + var selectedItem = $("div.selected div.item"); + assert.equal(selectedItem.length, 1, "there should be one selected item"); + assert.equal(selectedItem.find("span.selectedSectionName").length, 0, "there should be no description spans"); +}); diff --git a/test/integration/section-creation.js b/test/integration/section-creation.js new file mode 100644 index 0000000..0c469a5 --- /dev/null +++ b/test/integration/section-creation.js @@ -0,0 +1,148 @@ +QUnit.module("Section Creation", { + beforeEach: function(assert) { + var select = document.createElement("select"); + select.setAttribute("multiple", "multiple"); + $("div#qunit-fixture").append(select); + assert.equal($("select").length, 1); + } +}); + +QUnit.test("creates the base div.tree-multiselect element", function(assert) { + $("select").treeMultiselect(); + assert.equal($("div.tree-multiselect").length, 1, "should only be one tree-multiselect element"); +}); + +QUnit.test("creates the selections and selected containers", function(assert) { + $("select").treeMultiselect(); + + assert.equal($("div.selections").length, 1, "should create a selections element"); + assert.equal($("div.selected").length, 1, "should create a selected element"); +}); + +QUnit.test("creates a section with title and items", function(assert) { + $("select").append(""); + $("select").append(""); + $("select").append(""); + $("select").treeMultiselect(); + + assert.equal($("div.selections > div.section").length, 1, "should create one section"); + + var title = $("div.selections > div.section > div.title"); + assert.equal(title.length, 1, "should create one title"); + assert.equal(textOf(title), "section", "title is incorrect"); + + var collapse = title.find("span.collapse-section"); + assert.equal(collapse.length, 1, "should create one collapse span"); + + var checkbox = title.find("input[type=checkbox]"); + assert.equal(checkbox.length, 1, "should create a section title checkbox"); + + var items = $("div.selections > div.section > div.item"); + assert.equal(items.length, 3, "should create three items in section"); + var itemTexts = ["item1", "item2", "item3"] + items.each(function(index, item) { + assert.equal($(item).text(), itemTexts[index], "item text is incorrect"); + assert.ok($(item).is(":visible"), "item should be visible by default"); + }); +}); + +QUnit.test("can generate nested sections", function(assert) { + $("select").append(""); + $("select").append(""); + $("select").append(""); + $("select").append(""); + + $("select").treeMultiselect(); + + assert.equal($("div.section").length, 3, "there should be three sections"); + assert.equal($("div.section > div.section").length, 2, "there should be two sections inside the other"); + + var outerSection = $("div.section").first(); + assert.equal(textOf(outerSection.find("> div.title")), "alphabet", "outer section name should be 'alphabet'"); + + var outerItem = outerSection.find("> div.item"); + assert.equal(outerItem.length, 1, "there should be one outer item"); + assert.equal(outerItem.first().text(), "Google", "outer item should be Google"); + + var innerSections = $("div.section").slice(1); + var firstInnerSection = innerSections.first(); + var lastInnerSection = innerSections.last(); + assert.equal(textOf(firstInnerSection.find("> div.title")), "capitals", "one inner section name should be 'capitals'"); + assert.equal(textOf(lastInnerSection.find("> div.title")), "lowercase", "the other inner section name should be 'lowercase'"); + + var capitalsItems = firstInnerSection.find("> div.item"); + assert.equal(capitalsItems.length, 2, "capitals should have two items"); + assert.equal(capitalsItems.first().text(), "ABC", "first item should be ABC"); + assert.equal(capitalsItems.last().text(), "DEF", "last item should be DEF"); + + var lowercaseItems = lastInnerSection.find("> div.item"); + assert.equal(lowercaseItems.length, 1, "lowercase should have one item"); + assert.equal(lowercaseItems.first().text(), "xyz", "item should be xyz"); +}); + +QUnit.test("selects options that were selected in original select", function(assert) { + $("select").append(""); + $("select").append(""); + + $("select").val(["one"]); + + $("select").treeMultiselect(); + + var itemOne = $("div.item").filter(function() { + return $(this).clone().children().remove().end().text() == 'one'; + }); + assert.ok(itemOne.find("> input[type=checkbox]").prop('checked'), "one should be checked"); + + var itemTwo = $("div.item").filter(function() { + return $(this).clone().children().remove().end().text() == 'two'; + }); + assert.ok(!itemTwo.find("> input[type=checkbox]").prop('checked'), "two should not be checked"); +}); + +QUnit.test("respects the data-index attribute", function(assert) { + $("select").append(""); + $("select").append(""); + $("select").append(""); + $("select").treeMultiselect(); + + var selected = $("div.selected > div.item"); + assert.equal(selected.length, 3, "should be three selected items"); + var order = ["Two", "One", "Three"]; + + selected.each(function(i, item) { + assert.equal(textOf(item), order[i], "data-index puts items in the wrong order"); + }); +}); + +QUnit.test("data-index works on nested elements", function(assert) { + $("select").append(""); + $("select").append(""); + $("select").append(""); + $("select").treeMultiselect(); + + var selected = $("div.selected > div.item"); + assert.equal(selected.length, 3, "should be three selected items"); + var order = ["Two", "One", "Three"]; + + selected.each(function(i, item) { + assert.equal(textOf(item), order[i], "data-index puts nested items in the wrong order"); + }); +}); + +QUnit.test("data-description gets put on selections", function(assert) { + $("select").append(""); + $("select").treeMultiselect(); + + var item = $("div.selections div.item"); + assert.equal(item.length, 1, "should be one item"); + assert.equal(item.first().attr('data-description'), "foo-description", "item description is not put correctly on selection"); +}); + +QUnit.test("section on selected items is displayed correctly", function(assert) { + $("select").append(""); + $("select").treeMultiselect(); + + var sectionSpan = $("div.selected div.item span.selectedSectionName"); + assert.equal(sectionSpan.length, 1, "should be one section name span"); + assert.equal(textOf(sectionSpan), "foo/bar/baz", "selected item section name is incorrect"); +}); diff --git a/test/integration/sections.html b/test/integration/sections.html deleted file mode 100644 index 2e066c6..0000000 --- a/test/integration/sections.html +++ /dev/null @@ -1,160 +0,0 @@ - -
- - - - - diff --git a/test/integration/title-autochecking.js b/test/integration/title-autochecking.js new file mode 100644 index 0000000..d2ad6e5 --- /dev/null +++ b/test/integration/title-autochecking.js @@ -0,0 +1,74 @@ +QUnit.module("Title Autochecking", { + beforeEach: function(assert) { + var select = document.createElement("select"); + select.setAttribute("multiple", "multiple"); + $("div#qunit-fixture").append(select); + assert.equal($("select").length, 1); + } +}); + +QUnit.test("section checkboxes should be checked when all children are selected initially", function(assert) { + $("select").append(""); + $("select").append(""); + $("select").treeMultiselect(); + + assert.equal($("input[type=checkbox]").length, 3, "there should be three checkboxes"); + assert.equal($("div.item > input[type=checkbox]").length, 2, "two checkboxes should be item checkboxes"); + assert.equal($("input[type=checkbox]:checked").length, 3, "all three should be checked"); +}); + +QUnit.test("section checkboxes should be checked when all children are selected", function(assert) { + $("select").append(""); + $("select").append(""); + $("select").treeMultiselect(); + + assert.equal($("input[type=checkbox]:checked").length, 1, "only one item should be checked"); + + var lastItem = $("div.selections div.item").last(); + lastItem.find("> input[type=checkbox]").prop('checked', true).trigger('change'); + + assert.equal($("input[type=checkbox]:checked").length, 3, "both items and the title should be checked"); +}); + +QUnit.test("top level parent should not be checked if only one child section is completely checked", function(assert) { + $("select").append(""); + $("select").append(""); + $("select").treeMultiselect(); + + var topLevel = $("div.section").first(); + assert.ok(!(topLevel.find("> div.title > input[type=checkbox]").is(":checked")), "top level parent should not checked"); +}); + +QUnit.test("top level parent checking with only one child section completely checked, now with triggers", function(assert) { + $("select").append(""); + $("select").append(""); + $("select").append(""); + $("select").treeMultiselect(); + + var topLevel = $("div.section").first(); + assert.ok(!(topLevel.find("> div.title > input[type=checkbox]").is(":checked")), "top level parent should not checked"); + + var barSection = $("div.section").filter(function() { + return textOf($(this).find("> div.title")) == 'bar'; + }); + assert.equal(barSection.length, 1, "should be on 'bar' section"); + assert.ok(!(barSection.find("> div.title > input[type=checkbox]").is(":checked")), "bar section is not checked yet"); + + barSection.find("div.item > input[type=checkbox]").prop('checked', true).trigger('change'); + + assert.ok(barSection.find("> div.title > input[type=checkbox]").is(":checked"), "bar section should be checked now"); + assert.ok(!(topLevel.find("> div.title > input[type=checkbox]").is(":checked")), "top level section should still not be checked"); +}); + +QUnit.test("titles should unselect when a child is unselected", function(assert) { + $("select").append(""); + $("select").treeMultiselect(); + + assert.ok($("div.title > input[type=checkbox]").is(":checked"), "title should initially be checked"); + + var item = $("div.item > input[type=checkbox]").first(); + item.prop("checked", false); + item.trigger('change'); + + assert.ok(!($("div.title > input[type=checkbox]").is(":checked")), "title should not be checked now"); +}); diff --git a/test/runner.html b/test/runner.html new file mode 100644 index 0000000..72c753e --- /dev/null +++ b/test/runner.html @@ -0,0 +1,16 @@ + + + + + + + + + + + + + +
+ +