diff --git a/README.md b/README.md index 6ce64e1..a5a97ec 100644 --- a/README.md +++ b/README.md @@ -1 +1,92 @@ -# select2-to-tree \ No newline at end of file +Select2-to-Tree +======= + +Select2-to-Tree is an extension to Select2, a popular select boxes library: https://github.com/select2/select2. + +Though Select2 is very versatile, it only supports a single level of nesting. See https://select2.github.io/options.html#how-many-levels-of-nesting-are-allowed: +
+Because Select2 falls back to an <optgroup> when creating nested options, only a single level of nesting is supported. Any additional levels of nesting is not guarenteed to be displayed properly across all browsers and devices.
+ +Select2-to-Tree extends Select2 to support arbitrary level of nesting. + +Browser compatibility +--------------------- +* IE 8+ +* Chrome 8+ +* Firefox 10+ +* Safari 3+ +* Opera 10.6+ + +Usage +----- +Firstly, you need to know the usage of Select2: https://github.com/select2/select2 + +Then, in your HTML document, you add the Select2 library (the `*.js` file & `*.css` file, currently the version should be 4.0+), and the Select2-to-Tree library (the `*.js` file & `*.css` file in the "`src`" folder). jQuery is also needed. + +There are 2 ways to use Select2-to-Tree: + +

1. Use data, and empty <select> element(see "Example 1" in "example/example.html"):

+ +Suppose your HTML is like this: +```html + +``` +And your data: +```js +var mydata = [ + {id:1, name:"USA", inc:[ + {name:"west", inc:[ + {id:111, name:"California", inc:[ + {id:1111, name:"Los Angeles", inc:[ + {id:11111, name:"Hollywood"} + ]}, + {id:1112, name:"San Diego"} + ]}, + {id:112, name:"Oregon"}, + ]}, + ]}, + {id:2, name:"India"}, + {id:3, name:"中国"} +]; +``` +And you call Select2-to-Tree like the following: +```js +$("#sel_1").select2ToTree({treeData: {dataArr:mydata}, maximumSelectionLength: 3}); +``` +"`{treeData: {dataArr:mydata}`" is for Select2-to-Tree, "`maximumSelectionLength: 3`" is for Select2 (and you can set the other Select2 arguments if needed) + +About the data structure: "`id`" will be used as option value, "`name`" will be used as option label, and "`inc`" will be used to specify sub-level options. If your data structure is not like this, you can set arguments in "`treeData`" to change the default behavior, e.g., `treeData: {dataArr: mydata, valFld: "value", labelFld: "text", incFld: "sub"}`: +- `dataArr`, an array containing the data. +- `valFld`, the option value field, it's "`id`" by default. (if the value is empty, the corresponding option will be unselectable, see the "west" option in the example) +- `labelFld`, the option label field, it's "`name`" by default. +- `incFld`, the sub options field, it's "`inc`" by default. +- `dftVal`, the default value. + +The above are all the parameters supported by Select2-to-Tree. + +

2. directly create the <select> element(see "Example 2" in "example/example.html"):

+ +If it's hard to create the required data structure, you can directly create the <select> element. It's like the following: +```html + +``` +- the classes `l1`,`l2`,`l3`,`l4`,`l5`..., setting the nesting level. +- the attribute `data-pup`, setting the value of the parent level option. +- the class `non-leaf`, setting whether the option has children or not. + +Then, you call Select2-to-Tree (the "`treeData`" argument of Select-to-Tree is not needed here, but you can set arguments for Select2): +```js +$("#sel_2").select2ToTree(); +``` + +Copyright and license +--------------------- +The license is available within the repository in the [LICENSE][license] file. diff --git a/example/example.html b/example/example.html new file mode 100644 index 0000000..4f28db3 --- /dev/null +++ b/example/example.html @@ -0,0 +1,50 @@ + + + + + Select2-to-Tree * example + + + + + + + +

Example 1

+ + + +


+ +

Example 2

+ + + + diff --git a/src/select2totree.css b/src/select2totree.css index 67ded07..b4939ca 100644 --- a/src/select2totree.css +++ b/src/select2totree.css @@ -1,45 +1,69 @@ /*! - * Select2-to-Tree CSS 0.6.0 + * Select2-to-Tree CSS 0.8.0 + * https://github.com/clivezhg/select2-to-tree */ + .s2-to-tree * { + box-sizing: border-box; + } .s2-to-tree .select2-results__option.l1 { margin-left: 0.6em; + font-size: 1em; } .s2-to-tree .select2-results__option.l2 { margin-left: 1.4em; + font-size: 0.95em; } .s2-to-tree .select2-results__option.l3 { margin-left: 2.2em; + font-size: 0.91em; } .s2-to-tree .select2-results__option.l4 { margin-left: 3.0em; + font-size: 0.87em; } .s2-to-tree .select2-results__option.l5 { margin-left: 3.8em; + font-size: 0.83em; } - -.s2-to-tree li.select2-results__option:not(.non-leaf) { - border-left: 1px solid lightgray; +.s2-to-tree .select2-results__option.l6 { + margin-left: 4.5em; + font-size: 0.8em; +} +.s2-to-tree .select2-results__option.l7 { + margin-left: 5.3em; + font-size: 0.77em; } +.s2-to-tree .select2-results__option.l8 { + margin-left: 6.0em; + font-size: 0.75em; +} + .s2-to-tree li.select2-results__option.non-leaf .expand-collapse:hover { color: red; } .s2-to-tree li.select2-results__option.non-leaf .expand-collapse::before { content: "+"; position: absolute; - left: -5px; /* 'padding: 6px' in select2's css */ - width: 11px; - font-size: larger; + left: -0.35em; + font-size: larger; + cursor: pointer; } .s2-to-tree li.select2-results__option.non-leaf.opened .expand-collapse::before { content: "−"; } +.s2-to-tree .item-label { + display: inline-block; + margin-left: 0.5em; + padding: 3px; + width: calc(100% - 11px); +} + .s2-to-tree li.select2-results__option { position: relative; - box-sizing: border-box; - padding: 0px 6px; - height: 1.1em; + padding: 0px; + height: 1.6em; overflow-y: hidden; transition: height 0.18s; } @@ -48,28 +72,29 @@ height: 0px; } .s2-to-tree li.select2-results__option[data-pup].showme { - height: 1.1em; + height: 1.6em; overflow-y: visible; } -.s2-to-tree.select2-container .select2-results__option--highlighted[aria-selected] > span:not(.expand-collapse) { +.s2-to-tree.select2-container--default .select2-results__option--highlighted[aria-selected] > span.item-label { background-color: #5897fb; color: white; - padding: 3px 6px; } - -.s2-to-tree.select2-container li.select2-results__option--highlighted[aria-selected] { - background-color: inherit; - color: inherit; +.s2-to-tree.select2-container--default li.select2-results__option[aria-selected="true"] > span.item-label { + background-color: #ddd; +} +.s2-to-tree.select2-container--default li.select2-results__option--highlighted[aria-selected], +.s2-to-tree.select2-container--default li.select2-results__option[aria-selected="true"] { + background-color: inherit; + color: inherit; } .s2-to-tree li.select2-results__option.l1 { display: block; - height: auto; overflow-y: visible; } .s2-to-tree.searching-result li.select2-results__option { - height: auto; + height: 1.6em; display: block; } diff --git a/src/select2totree.js b/src/select2totree.js index 3bd04e0..b365e97 100644 --- a/src/select2totree.js +++ b/src/select2totree.js @@ -1,17 +1,18 @@ /*! - * Select2-to-Tree 0.6.0 - * https://github.com/clivezhg/select2-to-tree/ + * Select2-to-Tree 0.8.0 + * https://github.com/clivezhg/select2-to-tree */ (function ($) { $.fn.select2ToTree = function (options) { var defaults = { - theme: "default" // set this option (e.g., "bootstrap") to set different style + theme: "default" }; var opts = $.extend(defaults, options); if (opts.treeData) { buildSelect(opts.treeData, this); } opts.templateResult = function (data, container) { + var $iteme = $("").text(data.text); if (data.element) { var ele = data.element; container.setAttribute("data-val", ele.value); @@ -20,10 +21,10 @@ container.setAttribute("data-pup", ele.getAttribute("data-pup")); } if ($(container).hasClass("non-leaf")) { - return $('').text(data.text); + return $('' + $("
').text(data.text); + return $iteme; }; var expandCollapseTime = 0; @@ -43,7 +44,6 @@ s2inst.on("select2:open", function (evt) { var s2data = s2inst.data("select2"); - /* In 3.X, we can use the 'onSelect' method. "The 4.0 release...At the core, it is a full rewrite..." */ // The 'click' event will be after 'select2:selecting' s2data.$dropdown.addClass("s2-to-tree"); s2data.$dropdown.find(".searching-result").removeClass("searching-result"); @@ -78,10 +78,14 @@ var $opt = $(""); $opt.text(data[treeData.labelFld || "name"]); $opt.val(data[treeData.valFld || "id"]); + if($opt.val() === "") { + $opt.prop("disabled", true); + $opt.val(getUniqueValue()); + } $opt.addClass("l" + curLevel); if (pup) $opt.attr("data-pup", pup); $el.append($opt); - var inc = data[treeData.valFld || "inc"]; + var inc = data[treeData.incFld || "inc"]; if (inc) { $opt.addClass("non-leaf"); buildOptions(inc, curLevel+1, $opt.val()); @@ -92,6 +96,11 @@ if (treeData.dftVal) $el.val(treeData.dftVal); } + var uniqueIdx = 1; + function getUniqueValue() { + return "autoUniqueVal_" + uniqueIdx++; + } + function toggleSubOptions(target) { $(target.parentNode).toggleClass("opened"); showHideSub(target.parentNode); @@ -122,4 +131,5 @@ showHideSub(this); }); } + })(jQuery);