├── .travis.yml
├── LICENSE
├── README.md
├── bower.json
├── dist
├── multipicker.min.css
└── multipicker.min.js
├── gulpfile.js
├── index.html
├── package.json
├── roadmap.md
├── src
├── multipicker.css
└── multipicker.js
└── tests
├── test.html
└── tests.js
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | language: node_js
3 | node_js:
4 | - '6'
5 | before_script:
6 | - npm install -g gulp
7 | - npm link gulp
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Stepan
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Multipicker
2 |
3 | Plugin's [`official website`](http://styopdev.github.io/multiPicker/) with demos, also [`available in Russian`](http://styopdev.github.io/multiPicker/ru.html).
4 |
5 | Multipicker is jQuery plugin for selecting days, numbers or other elements, it supports multi selecting (like checkboxes) or single element selection (like radio buttons).
6 |
7 | #### How to use
8 |
9 | There are several ways for multipicker plugin installation:
10 |
11 | + using npm: `npm install multipicker`
12 |
13 | + using bower: `bower install multipicker`
14 |
15 | + download and unpack zip file from [github repository](https://github.com/styopdev/multiPicker).
16 |
17 | Load the latest version of jQuery library and plugin's files from `dist` folder in the html document.
18 |
19 | ```
20 |
21 |
22 |
23 | ```
24 | ##### Multipicker usage basic example.
25 |
26 | ```html
27 |
28 | Su
29 | Mo
30 | Tu
31 | We
32 | Th
33 | Fr
34 | Sa
35 |
36 | ```
37 |
38 | ```javascript
39 | $("#days").multiPicker({ selector : "li" });
40 | ```
41 | 
42 |
43 | #### Repository files' structure
44 |
45 | 
46 |
47 | ### Options
48 | * `selector` (required) - element type used inside of picker (html tag like `li` / `span` / `i`, `checkbox` / `radio` - for input type `checkbox` / `radio`)
49 | * `inputName` - name of input where checked values will be stored. Plugin will create new one if input does not exist on the page (only for non checkbox / radio elements). If `inputName` doesn't specified, picker container's id will be used for input name. For avoiding conflict strongly recommend to provide valid, unique name.
50 | * `valueSource` - source from where plugin should get value for element, possible values are: `index`, `text`, `data-*` attribute, default value is `index` (only for non checkbox / radio elements)
51 | * `prePopulate` - string or array of element(s) which should be selected by default (useful for edit mode), could be `index`, `data-*` or `text` of elements', must match to valueSource
52 | * `disabled` - string or array of element(s) which should be disabled (useful for edit mode), could be `index`, `data-*` or `text` of elements', must match to valueSource. Also its possible to disable elements using checkboxes' and radiobuttons' disabled attribute, like ` `
53 | * `isSingle` - allows user to select only one option from picker (like input[type="radio"] in pure html forms) default value is false (only for non checkbox / radio elements)
54 | * `cssOptions` - object with options described below:
55 |
56 |
57 | | Option | Default value | Description |
58 | |-----------|----------------|--------------|
59 | | vertical | false | picker's horizontal / vertical position |
60 | | quadratic | false | by default picker is rounded, specify this option true to make it square |
61 | | size | "medium" | picker's size, available values are "small", "medium", "large" |
62 | | picker | empty object | css styles (key / value js object) will be assigned to the picker |
63 | | element | empty object | css styles (key / value js object) will be assigned to the elements inside of picker |
64 | | selected | empty object | css styles (key / value js object) will be assigned to the selected elements inside of picker |
65 | | hover | empty object | css styles (key / value js object) will be assigned to the hover elements inside of picker | |
66 |
67 | ### Events
68 | * `onInit` - called when picker has finished initialization, doesn't receive any argument
69 | * `onSelect` - called when item selected, function receive 2 arguments: selected item and it's value
70 | * `onUnselect` - called when item deselected, function receive 2 arguments: deselected item and it's value
71 |
72 | ### Methods
73 | Methods are implemented in bootstrap.js style - `.multiPicker("methodname").multiPicker("anotherMethod", options)`. All methods are chainable, some of them accepts arguments.
74 |
75 | * `get` - get picker's current value, receive callback style function as an argument.
76 | ```js
77 | $("#days").multiPicker({ selector: 'li' }).multiPicker('get', function (value) { /* value available here */ });
78 | ```
79 | * `select` - select elements, receive array or string of element(s) values which should be selected.
80 | ```js
81 | $("#days").multiPicker({ selector: 'li' }).multiPicker('select', [1, 2]);
82 | ```
83 | * `unselect` - select elements, receive array or string of element(s) values which should be unselected.
84 | ```js
85 | $("#days").multiPicker({ selector: 'li' }).multiPicker('unselect', "2");
86 | ```
87 | * `disable` - disable elements, receive array or string of element(s) values which should be disabled.
88 | ```js
89 | $("#days").multiPicker({ selector: 'li' }).multiPicker('disable', [1, 2]);
90 | ```
91 | * `enable` - enable elements, receive array or string of element(s) values which should be enabled
92 | ```js
93 | $("#days").multiPicker({ selector: 'li' }).multiPicker('enable', [1, 2]);
94 | ```
95 | * `clear` - reset picker, doesn't receive any argument.
96 | ```js
97 | $("#days").multiPicker({ selector: 'li' }).multiPicker('clear');
98 | ```
99 |
100 | #### Usage with checkboxes and radiobuttons.
101 | In case when html tags like `li` or `span` used in multipicker, it will store values in hidden input, which will be a string separated by commas, like this `"Su, Mo, Fr, Sa"`.
102 | You should split this string on the server (on client in some cases), to store these values in database or make it possible to use them in picker in the future (for example when user wants to edit his choices).
103 |
104 | In case when you are using checkboxes or radiobuttons, selected items will check checkbox/radiobutton in standart html way. Picker will modify your markup, and you will get html code like these:
105 |
106 | multiple items for checkboxes
107 | ```html
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 | ```
118 | or single selected item for radiobuttons
119 | ```html
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 | ```
130 |
131 | You can access selected values in standart way as you would do with checkboxes and radiobuttons if plugin wouldn't been used.
132 |
133 | ##### More Examples:
134 |
135 | Set `isSingle`: true to make only one element selectable like radiobuttons in html.
136 | ```javascript
137 | $("#days").multiPicker({
138 | selector: "li",
139 | isSingle: true
140 | });
141 | ```
142 | 
143 |
144 | Specify `prePopulate` array and valueSource options to get some options selected by default
145 |
146 | ```javascript
147 | $("#days").multiPicker({
148 | selector : "li",
149 | prePopulate : ["Tu", "Fr"],
150 | valueSource : "data-value"
151 | });
152 | ```
153 | 
154 |
155 |
156 | To make your picker vertical just use `cssOptions` `vertical : true` property
157 |
158 | ```html
159 |
160 | Su
161 | Mo
162 | Tu
163 | We
164 | Th
165 | Fr
166 | Sa
167 |
168 | ```
169 | ```javascript
170 | $("#days-vertical").multiPicker({
171 | selector : "span",
172 | cssOptions : {
173 | vertical: true
174 | }
175 | });
176 | ```
177 |
178 | 
179 |
180 | ##### Using radiobuttons
181 |
182 | ```html
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 | ```
193 | ```javascript
194 | $("#languages").multiPicker({ selector : "radio" });
195 | ```
196 | 
197 |
198 | ##### Using checkboxes
199 | With vertical, quadratic and prepopulated options:
200 | ```html
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 | ```
211 | ```javascript
212 | $("#programming-languages").multiPicker({
213 | selector : "checkbox",
214 | prePopulate : ["C", "C++"],
215 | cssOptions : {
216 | quadratic : true,
217 | vertical : true
218 | }
219 | });
220 | ```
221 | 
222 |
223 | ##### Design customisation
224 | Plugin allows to use label tags to apply item text and keep input's value hidden from user. To apply custom design to multipicker you should use cssOptions (which is described in options section).
225 |
226 | For Example, this picker's code
227 |
228 | 
229 |
230 | will be:
231 |
232 | ```html
233 |
234 | JAN
235 |
236 | FEB
237 |
238 | MAR
239 |
240 | APR
241 |
242 | MAY
243 |
244 | JUN
245 |
246 | JUL
247 |
248 | AUG
249 |
250 | SEB
251 |
252 | OCT
253 |
254 | NOV
255 |
256 | DEC
257 |
258 |
259 | ```
260 | ```javascript
261 | $("#clubs").multiPicker({
262 | selector : "checkbox",
263 | prePopulate : "1",
264 | isSingle : true,
265 | cssOptions : {
266 | size : "large",
267 | element : {
268 | "font-size" : "11px",
269 | "color" : "#3a3a3a",
270 | "font-weight" : "bold"
271 | },
272 | selected: {
273 | "border-color" : "#ff4c4c",
274 | "font-size" : "14px"
275 | },
276 | picker: {
277 | "border-color" : "#ff4c4c"
278 | }
279 | }
280 | });
281 | ```
282 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "multipicker",
3 | "main": "multiPicker.js",
4 | "homepage": "http://styopdev.github.io/multiPicker",
5 | "authors": [
6 | "Stepan Vardanyan "
7 | ],
8 | "description": "Multipicker is jQuery plugin for elements selecting using mouse clicks and drag, supports multi selecting.",
9 | "moduleType": [
10 | "globals"
11 | ],
12 | "keywords": [
13 | "picker",
14 | "rangepicker",
15 | "plugin",
16 | "jquery"
17 | ],
18 | "license": "MIT",
19 | "ignore": [
20 | "**/.*",
21 | "node_modules",
22 | "bower_components",
23 | "test",
24 | "tests"
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------
/dist/multipicker.min.css:
--------------------------------------------------------------------------------
1 | .checklist::selection{background:none}.checklist::-moz-selection{background:none}.checklist{border:2px solid #e8e8e8;border-radius:30px;display:inline-block;width:auto;padding:4px;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.checklist > *{display:inline-block;padding:10px 0;width:38px;cursor:pointer;text-align:center;color:#0036ff;border:2px solid transparent;font-size:13px}.checklist > :not(:first-child){margin-left:-7px}.checklist > .active{border-radius:50px;border:2px solid #0036ff;color:#000}.checklist > .right-side{border-bottom-left-radius:0;border-top-left-radius:0;border-left:2px solid transparent}.checklist > .left-side{border-bottom-right-radius:0;border-top-right-radius:0;border-right:2px solid transparent}.checklist > .center-side{border-bottom-right-radius:0;border-top-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;border-right:2px solid transparent;border-left:2px solid transparent}.checklist [data-disabled="true"]{cursor:not-allowed}.checklist.vertical{width:38px;padding:3px 4px}.checklist.vertical > *{margin-left:-2px}.checklist.vertical > :not(:first-child){margin-top:-7px}.checklist.vertical > .right-side{border-radius:50px;border-top-right-radius:0;border-top-left-radius:0;border-left:2px solid #0036ff;border-top:2px solid transparent}.checklist.vertical > .left-side{border-radius:50px;border-bottom-left-radius:0;border-bottom-right-radius:0;border-right:2px solid #0036ff;border-bottom:2px solid transparent}.checklist.vertical > .center-side{border-bottom-right-radius:0;border-top-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:0;border-top:2px solid transparent;border-bottom:2px solid transparent;border-right:2px solid #0036ff;border-left:2px solid #0036ff}.checklist.small > *{width:30px;padding:7px 0;font-size:11px}.checklist.small > .active{border-width:1px;padding:8px 1px}.checklist.vertical.small{width:30px;padding:2px 3px}.checklist.large > *{width:45px;padding:12px 0;font-size:15px}.checklist.large > .active{border-width:2px}.checklist.vertical.large{width:45px;padding:5px}.checklist.quadratic,.checklist.quadratic > *,.checklist.vertical.quadratic > *{border-radius:0}.checklist input{display:none}.checklist.more-padded-l{padding-left:11px}.checklist.more-padded-t{padding-top:10px}
--------------------------------------------------------------------------------
/dist/multipicker.min.js:
--------------------------------------------------------------------------------
1 | !function(e){var t=function(){this.options={activeClass:"active",valueSource:"index",prePopulate:null,disabled:null,cssOptions:{vertical:!1,quadratic:!1,size:"medium",picker:null,element:null,hover:null,selected:null}},this.type="inline",this.input=null,this.selector=null,this.isPressed=!1,this.lastElem="",this.mouseUpTimer,this.setEvendHandlers=function(){function e(e){var t=e.target;e.originalEvent.changedTouches&&e.originalEvent.changedTouches[0]&&(t=document.elementFromPoint(e.originalEvent.changedTouches[0].clientX,e.originalEvent.changedTouches[0].clientY)),i.isPressed&&i.lastElem!==t&&(i.hover(t),i.lastElem=t),e.preventDefault()}function t(e){i.isPressed=!1,i.mouseUpTimer=setTimeout(function(){i.isPressed=!0},100)}function s(e){i.isPressed=!1}var i=this;this.items.click(function(){i.select.call(this,i,!1)});var o=this.finishHover.bind(this);this.items.on("touchmove",e),this.items.on("touchend",o),this.selector.on("touchstart",t),this.selector.on("touchcancel",s),this.items.mousemove(e),this.items.mouseup(o),this.selector.mousedown(t),this.selector.mouseleave(s)},this.hover=function(t){e(t).hasClass("checklist")||this.select.call(e(t),this,!1)},this.finishHover=function(e){clearTimeout(this.mouseUpTimer),this.lastElem=null,this.isPressed=!1},this.select=function(s,i,o){var n;if(!e(this).attr("data-disabled")){if(n="index"===s.options.valueSource?e(this).index():"data-"===s.options.valueSource.substring(0,5)?e(this).attr(s.options.valueSource):"text"===s.options.valueSource?e(this).text():e(this).val(),s.options.isSingle)return s.clear(),e(this).siblings("."+s.options.activeClass).removeClass(),e(this).addClass(s.options.activeClass),s.addValue(this,n),void(s.options.onSelect&&"function"==typeof s.options.onSelect&&!i&&s.options.onSelect(this,n));if(void 0!==o&&!0===o||void 0===o&&e(this).hasClass(s.options.activeClass)){if(!e(this).hasClass(s.options.activeClass))return;e(this).removeClass(),s.removeValue(this,n),t.updateClasses(e(this),s.options.activeClass),s.options.onUnselect&&"function"==typeof s.options.onUnselect&&!i&&s.options.onUnselect(this,n)}else{if(e(this).hasClass(s.options.activeClass))return;e(this).addClass(s.options.activeClass),s.addValue(this,n),t.updateClasses(e(this),s.options.activeClass),s.options.onSelect&&"function"==typeof s.options.onSelect&&!i&&s.options.onSelect(this,n)}}},this.addValue=function(t,s){if("inline"===this.type){var i=this.input.val();i&&(i+=","),i+=s,this.input.val(i)}else this.selector.find("input[value='"+e(t).attr("data-value")+"']").attr("checked",!0)},this.removeValue=function(t,s){if("inline"===this.type){var i=this.input.val();i=i.replace(","+s,"").replace(s+",","").replace(s,""),this.input.val(i)}else this.selector.find("input[value='"+e(t).attr("data-value")+"']").attr("checked",!1)},this.getValue=function(t){if("inline"===this.type)return t(this.input.val());var s=[];return this.selector.find("input[checked='checked']").each(function(t,i){s.push(e(i).val())}),t(s)},this.clear=function(){"inline"===this.type?(this.input.val(""),this.selector.find(".active").removeClass()):(this.selector.find(".active").removeClass(),this.selector.find("input").attr("checked",!1))},this.prePopulate=function(){if(t.isArray(this.options.prePopulate)&&this.options.prePopulate.length)for(var s in this.options.prePopulate){var i=this.options.prePopulate[s],o=this.getElementSelector(i);e(o).index()<0?console.warn("Multipicker: prepopulated element doesn`t found `%s`",i):this.select.call(o,this,!0)}else{o=this.getElementSelector(this.options.prePopulate);e(o).index()<0?console.warn("Multipicker: prepopulated element doesn`t found`%s`",this.options.prePopulate):this.select.call(o,this,!0)}},this.disable=function(s,i){if(t.isArray(s)&&s.length)for(var o in s){var n=s[o],a=this.getElementSelector(n);e(a).index()<0?console.warn("Multipicker: prepopulated element doesn`t found `%s`",n):i?e(a).removeAttr("data-disabled"):e(a).attr("data-disabled",!0)}else{a=this.getElementSelector(s);e(a).index()<0?console.warn("Multipicker: disabled element doesn`t found`%s`",s):i?e(a).removeAttr("data-disabled"):e(a).attr("data-disabled",!0)}},this.getElementSelector=function(e){return"index"!==this.options.valueSource&&this.options.valueSource?"data-"===this.options.valueSource.substring(0,5)?this.selector.find(this.options.selector+"["+this.options.valueSource+"='"+e+"']"):"text"===this.options.valueSource?this.selector.find(this.options.selector+":contains('"+e+"')"):void 0:this.items.eq(e)}};t.isArray=function(e){if("[object Array]"===Object.prototype.toString.call(e))return!0},t.updateClasses=function(t,s){var i={item:t=e(t),next:t.next(),prev:t.prev(),nextNext:t.next().next(),prevPrev:t.prev().prev()};i.item.hasClass(s)?i.next.hasClass(s)&&i.prev.hasClass(s)?(i.nextNext.hasClass(s)?i.next.attr("class",s+" center-side"):i.next.attr("class",s+" right-side"),i.prevPrev.hasClass(s)?i.prev.attr("class",s+" center-side"):i.prev.attr("class",s+" left-side"),i.item.attr("class","active center-side")):i.next.hasClass(s)&&!i.prev.hasClass(s)?(i.nextNext.hasClass(s)?i.next.attr("class",s+" center-side"):i.next.attr("class",s+" right-side"),i.item.attr("class","active left-side")):!i.next.hasClass(s)&&i.prev.hasClass(s)&&(i.prevPrev.hasClass(s)?i.prev.attr("class",s+" center-side"):i.prev.attr("class",s+" left-side"),i.item.attr("class",s+" right-side")):(i.next.hasClass("right-side")&&i.next.attr("class",s),i.prev.hasClass("left-side")&&i.prev.attr("class",s),i.prev.hasClass("center-side")&&i.prev.attr("class",s+" right-side"),i.next.hasClass("center-side")&&i.next.attr("class",s+" left-side"))},t.generateStyles=function(t,s){var i="";if(s.picker){i+="#"+t+".checklist {";for(var o in s.picker)i+=o+":"+s.picker[o]+";";i+="}"}if(s.element){i+="#"+t+" > * {";for(var o in s.element)i+=o+":"+s.element[o]+";";i+="}"}if(s.selected){i+="#"+t+" > *.active {";for(var o in s.selected)i+=o+":"+s.selected[o]+";";i+="}"}if(s.hover){i+="#"+t+" > *:hover {";for(var o in s.hover)i+=o+":"+s.hover[o]+";";i+="}"}e("head").append("")},t.API=function(e,s,i){if(~["select","unselect","enable","disable","clear","get"].indexOf(e))return(t.isArray(this)?this:[this]).forEach(function(o){if("function"==typeof s?i=s:t.isArray(s)||(s=[s]),"get"===e||"clear"==e||s)switch(e){case"select":s.forEach(function(e){var t=o.getElementSelector(e);t.length&&o.select.call(t,o,!1,!1)});break;case"unselect":s.forEach(function(e){var t=o.getElementSelector(e);t.length&&o.select.call(t,o,!1,!0)});break;case"enable":o.disable.call(o,s,!0);break;case"disable":o.disable.call(o,s,!1);break;case"clear":o.clear();break;case"get":o.getValue(i)}else console.warn("Empty enable/disable elements")}),this;console.warn("Method "+e+" doesn't exist")},e.fn.extend({multiPicker:function(s,i){if("string"!=typeof s){var o=[],n=e(this).length>1;return e(this).each(function(i,a){var l=new t;if(l.options=e.extend(l.options,s),l.selector=e(a),"checkbox"===l.options.selector||"radio"===l.options.selector?(l.type=l.options.selector,"radio"===l.type&&(l.options.isSingle=!0),l.selector.find("label").css("display","none"),l.options.disabled?t.isArray(l.options.disabled)||(l.options.disabled=[l.options.disabled]):l.options.disabled=[],e(l.selector).find("input").each(function(t,s){var i=e(s).val(),o=e("label[for='"+e(s).attr("id")+"']").text()||i;l.selector.append(""+o+" "),e(s).prop("disabled")&&l.options.disabled.push(i)}),l.items=l.selector.find("span"),l.options.valueSource="data-value",l.options.selector="span",l.options.cssOptions.vertical?l.selector.addClass("more-padded-t"):l.selector.addClass("more-padded-l")):(l.options.inputName=l.options.inputName||l.selector.attr("id"),"inline"===l.type&&(e("[name="+l.options.inputName+"]").length?l.input=e("[name="+l.options.inputName+"]"):(l.selector.after(" "),l.input=e("[name="+l.options.inputName+"]"))),l.items=l.selector.find(l.options.selector)),l.selector.addClass("checklist"),l.options.cssOptions.vertical&&l.selector.addClass("vertical"),l.options.cssOptions.size&&l.selector.addClass(l.options.cssOptions.size),l.options.cssOptions.quadratic&&l.selector.addClass("quadratic"),(l.options.cssOptions.picker||l.options.cssOptions.element||l.options.cssOptions.hover||l.options.cssOptions.selected)&&t.generateStyles(l.selector.attr("id"),l.options.cssOptions),l.options.prePopulate&&t.isArray(l.options.prePopulate)&&l.options.prePopulate.length>1&&l.options.isSingle)throw"Can not prePopulate more then 1 item, with `isSingle` true option";if(l.options.valueSource&&"index"===l.options.valueSource&&"text"===l.options.valueSource&&"data-"!==l.options.valueSource.substring(0,5))throw"Invalid value source";if("data-disabled"===l.options.valueSource)throw"`data-disabled` attribute is reserved, choose another name";(l.options.prePopulate||0===l.options.prePopulate)&&l.prePopulate(),(t.isArray(l.options.disabled)&&l.options.disabled.length||l.options.disabled&&!t.isArray(l.options.disabled)||0===l.options.disabled)&&l.disable(l.options.disabled,!1),l.selector.attr("ondragstart","return false"),l.setEvendHandlers(),l.options.onInit&&"function"==typeof l.options.onInit&&l.options.onInit(),n&&(l.multiPicker=t.API),o.push(l)}),o.multiPicker=t.API,o}}})}(jQuery);
2 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp'),
2 | qunit = require('gulp-qunit');
3 |
4 | gulp.task('test', function() {
5 | return gulp.src('tests/test.html')
6 | .pipe(qunit());
7 | });
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Multi Picker
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
79 |
80 |
81 | Multipicker demo
82 |
83 |
84 | Su
85 | Mo
86 | Tu
87 | We
88 | Th
89 | Fr
90 | Sa
91 |
92 |
93 |
94 |
95 | Su
96 | Mo
97 | Tu
98 | We
99 | Th
100 | Fr
101 | Sa
102 |
103 |
104 |
105 |
106 | Su
107 | Mo
108 | Tu
109 | We
110 | Th
111 | Fr
112 | Sa
113 |
114 |
115 |
116 |
117 | Su
118 | Mo
119 | Tu
120 | We
121 | Th
122 | Fr
123 | Sa
124 |
125 |
126 |
127 |
155 |
156 |
157 |
168 |
169 |
180 |
189 |
190 |
191 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "multipicker",
3 | "version": "1.1.1",
4 | "description": "Multipicker is jQuery plugin for elements selecting using mouse clicks and drag, supports multi selecting.",
5 | "main": "multipicker.js",
6 | "scripts": {
7 | "test": "gulp test"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/styopdev/multiPicker.git"
12 | },
13 | "keywords": [
14 | "rangepicker",
15 | "picker",
16 | "selectable",
17 | "form",
18 | "checkbox"
19 | ],
20 | "author": "Stepan ",
21 | "license": "MIT ",
22 | "bugs": {
23 | "url": "https://github.com/styopdev/multiPicker/issues"
24 | },
25 | "homepage": "http://styopdev.github.io/multiPicker",
26 | "devDependencies": {
27 | "gulp-qunit": "^1.5.0"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/roadmap.md:
--------------------------------------------------------------------------------
1 | - [x] All new browsers compatability.
2 | - [x] Checkbox, radiobuttons support.
3 | - [x] Disabled items.
4 | - [x] Initialize using any jquery selector (not only an id), bulk initialize.
5 | - [x] Make it possible to call: select / unselect / disable / enable / getSelected / reset - programmatically f.e. `$(...).multiPicker('select', [1, 2]);`
6 | - [x] Write tests.
7 |
--------------------------------------------------------------------------------
/src/multipicker.css:
--------------------------------------------------------------------------------
1 | .checklist::selection {
2 | background: none;
3 | }
4 | .checklist::-moz-selection {
5 | background: none;
6 | }
7 | .checklist {
8 | border: 2px solid #e8e8e8;
9 | border-radius: 30px;
10 | display: inline-block;
11 | width: auto;
12 | padding: 4px;
13 | -webkit-touch-callout: none;
14 | -webkit-user-select: none;
15 | -khtml-user-select: none;
16 | -moz-user-select: none;
17 | -ms-user-select: none;
18 | user-select: none;
19 | }
20 | .checklist > * {
21 | display: inline-block;
22 | padding: 10px 0px;
23 | width: 38px;
24 | cursor: pointer;
25 | text-align: center;
26 | color: #0036ff;
27 | border: 2px solid transparent;
28 | font-size: 13px;
29 | }
30 | .checklist > *:not(:first-child) {
31 | margin-left: -7px;
32 | }
33 | .checklist > .active {
34 | border-radius: 50px;
35 | border: 2px solid #0036ff;
36 | color: #000000;
37 | }
38 | .checklist > .right-side {
39 | border-bottom-left-radius: 0;
40 | border-top-left-radius: 0;
41 | border-left: 2px solid transparent;
42 | }
43 | .checklist > .left-side {
44 | border-bottom-right-radius: 0;
45 | border-top-right-radius: 0;
46 | border-right: 2px solid transparent;
47 | }
48 | .checklist > .center-side {
49 | border-bottom-right-radius:0;
50 | border-top-right-radius: 0;
51 | border-bottom-left-radius: 0;
52 | border-top-left-radius: 0;
53 | border-right: 2px solid transparent;
54 | border-left: 2px solid transparent;
55 | }
56 | .checklist [data-disabled="true"] {
57 | cursor: not-allowed;
58 | }
59 | .checklist.vertical {
60 | width: 38px;
61 | padding: 3px 4px;
62 | }
63 | .checklist.vertical > * {
64 | margin-left: -2px;
65 | }
66 | .checklist.vertical > *:not(:first-child) {
67 | margin-top: -7px;
68 | }
69 | .checklist.vertical > .right-side {
70 | border-radius: 50px;
71 | border-top-right-radius: 0;
72 | border-top-left-radius: 0;
73 | border-left: 2px solid #0036ff;
74 | border-top: 2px solid transparent;
75 | }
76 | .checklist.vertical > .left-side {
77 | border-radius: 50px;
78 | border-bottom-left-radius: 0;
79 | border-bottom-right-radius: 0;
80 | border-right: 2px solid #0036ff;
81 | border-bottom: 2px solid transparent;
82 | }
83 | .checklist.vertical > .center-side {
84 | border-bottom-right-radius:0;
85 | border-top-right-radius: 0 ;
86 | border-bottom-left-radius: 0;
87 | border-top-left-radius: 0 ;
88 | border-top: 2px solid transparent;
89 | border-bottom: 2px solid transparent;
90 | border-right: 2px solid #0036ff;
91 | border-left: 2px solid #0036ff;
92 | }
93 | .checklist.small > * {
94 | width: 30px;
95 | padding: 7px 0;
96 | font-size: 11px;
97 | }
98 | .checklist.small > .active {
99 | border-width: 1px;
100 | padding: 8px 1px;
101 | }
102 | .checklist.vertical.small {
103 | width: 30px;
104 | }
105 | .checklist.vertical.small {
106 | padding: 2px 3px;
107 | }
108 | .checklist.large > * {
109 | width: 45px;
110 | padding: 12px 0px;
111 | font-size: 15px;
112 | }
113 | .checklist.large > .active {
114 | border-width: 2px;
115 | }
116 | .checklist.vertical.large {
117 | width: 45px;
118 | }
119 | .checklist.vertical.large {
120 | padding: 5px 5px;
121 | }
122 | .checklist.quadratic, .checklist.quadratic > * , .checklist.vertical.quadratic > * {
123 | border-radius: 0;
124 | }
125 | .checklist input {
126 | display: none;
127 | }
128 | .checklist.more-padded-l {
129 | padding-left: 11px;
130 | }
131 | .checklist.more-padded-t {
132 | padding-top: 10px;
133 | }
134 |
--------------------------------------------------------------------------------
/src/multipicker.js:
--------------------------------------------------------------------------------
1 | (function($) {
2 | var MultiPicker = function () {
3 | this.options = {
4 | activeClass : "active",
5 | valueSource : "index",
6 | prePopulate : null,
7 | disabled : null,
8 | cssOptions : {
9 | vertical : false,
10 | quadratic : false,
11 | size : "medium",
12 | picker : null,
13 | element : null,
14 | hover : null,
15 | selected : null
16 | }
17 | };
18 | this.type = "inline";
19 | this.input = null;
20 | this.selector = null;
21 | this.isPressed = false;
22 | this.lastElem = "";
23 | this.mouseUpTimer;
24 |
25 | this.setEvendHandlers = function () {
26 | var picker = this;
27 | this.items.click(function () {
28 | picker.select.call(this, picker, false);
29 | });
30 |
31 | function mousemove (e) {
32 | var target = e.target;
33 | // get correct target for touch events
34 | if (e.originalEvent.changedTouches && e.originalEvent.changedTouches[0]) {
35 | target = document.elementFromPoint(e.originalEvent.changedTouches[0].clientX, e.originalEvent.changedTouches[0].clientY);
36 | }
37 |
38 | if (picker.isPressed && picker.lastElem !== target) {
39 | picker.hover(target);
40 | picker.lastElem = target;
41 | }
42 | e.preventDefault();
43 | };
44 |
45 | function mousedown (e) {
46 | picker.isPressed = false;
47 | picker.mouseUpTimer = setTimeout(function () {
48 | picker.isPressed = true;
49 | }, 100);
50 | };
51 |
52 | function mouseleave (e) {
53 | picker.isPressed = false;
54 | };
55 |
56 | var mouseup = this.finishHover.bind(this);
57 | // touch events
58 | this.items.on("touchmove", mousemove);
59 | this.items.on("touchend", mouseup);
60 | this.selector.on("touchstart", mousedown);
61 | this.selector.on("touchcancel", mouseleave);
62 | // mouse events
63 | this.items.mousemove(mousemove);
64 | this.items.mouseup(mouseup);
65 | this.selector.mousedown(mousedown);
66 | this.selector.mouseleave(mouseleave);
67 | };
68 |
69 | this.hover = function (target) {
70 | if (!$(target).hasClass("checklist")) {
71 | this.select.call($(target), this, false);
72 | }
73 | };
74 |
75 | this.finishHover = function (e) {
76 | clearTimeout(this.mouseUpTimer);
77 | this.lastElem = null;
78 | this.isPressed = false;
79 | };
80 |
81 | // arguments: element as this, picker, isPrepopulated flag which is true only on init
82 | this.select = function (picker, isPrepopulated, isUnselect) {
83 | var selectedVal;
84 | if ($(this).attr("data-disabled")) {
85 | return;
86 | }
87 |
88 | if (picker.options.valueSource === "index") {
89 | selectedVal = $(this).index();
90 | } else if (picker.options.valueSource.substring(0, 5) === "data-") {
91 | selectedVal = $(this).attr(picker.options.valueSource);
92 | } else if (picker.options.valueSource === "text") {
93 | selectedVal = $(this).text();
94 | } else {
95 | selectedVal = $(this).val();
96 | }
97 |
98 | if (picker.options.isSingle) {
99 | picker.clear();
100 |
101 | $(this).siblings("." + picker.options.activeClass).removeClass();
102 | $(this).addClass(picker.options.activeClass);
103 |
104 | picker.addValue(this, selectedVal);
105 | if (picker.options.onSelect && typeof picker.options.onSelect === "function" && !isPrepopulated) {
106 | picker.options.onSelect(this, selectedVal);
107 | }
108 | return;
109 | }
110 |
111 | if ((typeof isUnselect !== "undefined" && isUnselect === true) || (typeof isUnselect === "undefined" && $(this).hasClass(picker.options.activeClass))) {
112 | // unselect case
113 | if (!$(this).hasClass(picker.options.activeClass)) {
114 | return;
115 | }
116 | $(this).removeClass();
117 |
118 | picker.removeValue(this, selectedVal);
119 | MultiPicker.updateClasses($(this), picker.options.activeClass);
120 | if (picker.options.onUnselect && typeof picker.options.onUnselect === "function" && !isPrepopulated) {
121 | picker.options.onUnselect(this, selectedVal);
122 | }
123 | } else {
124 | // select case
125 | if ($(this).hasClass(picker.options.activeClass)) {
126 | return;
127 | }
128 | $(this).addClass(picker.options.activeClass);
129 |
130 | picker.addValue(this, selectedVal);
131 |
132 | MultiPicker.updateClasses($(this), picker.options.activeClass);
133 | if (picker.options.onSelect && typeof picker.options.onSelect === "function" && !isPrepopulated) {
134 | picker.options.onSelect(this, selectedVal);
135 | }
136 | }
137 | };
138 |
139 | this.addValue = function (el, val) {
140 | if (this.type === "inline") {
141 | var currValue = this.input.val();
142 | if (currValue) {
143 | currValue += ",";
144 | }
145 | currValue += val;
146 |
147 | this.input.val(currValue);
148 | } else {
149 | this.selector.find("input[value='" + $(el).attr("data-value") + "']").attr("checked", true);
150 | }
151 | };
152 |
153 | this.removeValue = function (el, val) {
154 | if (this.type === "inline") {
155 | var currValue = this.input.val();
156 | currValue = currValue.replace("," + val, "").replace(val + ",", "").replace(val, "");
157 | this.input.val(currValue);
158 | } else {
159 | this.selector.find("input[value='" + $(el).attr("data-value") + "']").attr("checked", false);
160 | }
161 | };
162 |
163 | this.getValue = function (cb) {
164 | if (this.type === "inline") {
165 | return cb(this.input.val());
166 | } else {
167 | var values = [];
168 |
169 | this.selector.find("input[checked='checked']").each(function (index, elem) {
170 | values.push($(elem).val());
171 | });
172 | return cb(values);
173 | }
174 | };
175 |
176 | this.clear = function () {
177 | if (this.type === "inline") {
178 | this.input.val("");
179 | this.selector.find(".active").removeClass();
180 | } else {
181 | this.selector.find(".active").removeClass();
182 | this.selector.find("input").attr("checked", false);
183 | }
184 | };
185 |
186 | this.prePopulate = function () {
187 | if (MultiPicker.isArray(this.options.prePopulate) && this.options.prePopulate.length) {
188 | for (var key in this.options.prePopulate) {
189 | var searched = this.options.prePopulate[key];
190 | var element = this.getElementSelector(searched);
191 |
192 | if ($(element).index() < 0) {
193 | console.warn("Multipicker: prepopulated element doesn`t found `%s`", searched);
194 | } else {
195 | this.select.call(element, this, true);
196 | }
197 | }
198 | } else {
199 | var element = this.getElementSelector(this.options.prePopulate);
200 | if ($(element).index() < 0) {
201 | console.warn("Multipicker: prepopulated element doesn`t found`%s`", this.options.prePopulate);
202 | } else {
203 | this.select.call(element, this, true);
204 | }
205 | }
206 | };
207 |
208 | this.disable = function (disableItems, isEnable) {
209 | if (MultiPicker.isArray(disableItems) && disableItems.length) {
210 | for (var key in disableItems) {
211 | var searched = disableItems[key];
212 | var element = this.getElementSelector(searched);
213 |
214 | if ($(element).index() < 0) {
215 | console.warn("Multipicker: prepopulated element doesn`t found `%s`", searched);
216 | } else {
217 | if (isEnable) {
218 | $(element).removeAttr("data-disabled");
219 | } else {
220 | $(element).attr("data-disabled", true);
221 | }
222 | }
223 | }
224 | } else {
225 | var element = this.getElementSelector(disableItems);
226 | if ($(element).index() < 0) {
227 | console.warn("Multipicker: disabled element doesn`t found`%s`", disableItems);
228 | } else {
229 | if (isEnable) {
230 | $(element).removeAttr("data-disabled");
231 | } else {
232 | $(element).attr("data-disabled", true);
233 | }
234 | }
235 | }
236 | };
237 |
238 | this.getElementSelector = function (searched) {
239 | if (this.options.valueSource === "index" || !this.options.valueSource) {
240 | return this.items.eq(searched);
241 | } else if (this.options.valueSource.substring(0, 5) === "data-") {
242 | return this.selector.find(this.options.selector + "[" + this.options.valueSource + "='" + searched + "']");
243 | } else if (this.options.valueSource === "text") {
244 | return this.selector.find(this.options.selector + ":contains('" + searched + "')");
245 | }
246 | };
247 | };
248 |
249 | MultiPicker.isArray = function (obj) {
250 | if (Object.prototype.toString.call(obj) === '[object Array]') {
251 | return true;
252 | }
253 | };
254 |
255 | MultiPicker.updateClasses = function (item, className) {
256 | var item = $(item);
257 | var ny = { /* nearbyItems */
258 | item: item,
259 | next: item.next(),
260 | prev: item.prev(),
261 | nextNext: item.next().next(),
262 | prevPrev: item.prev().prev()
263 | };
264 |
265 | if (ny.item.hasClass(className)) {
266 | if (ny.next.hasClass(className) && ny.prev.hasClass(className)) {
267 | if (ny.nextNext.hasClass(className)) {
268 | ny.next.attr('class', className + " center-side");
269 | } else {
270 | ny.next.attr('class', className + " right-side");
271 | }
272 | if (ny.prevPrev.hasClass(className)) {
273 | ny.prev.attr('class', className + " center-side");
274 | } else {
275 | ny.prev.attr('class', className + " left-side");
276 | }
277 | ny.item.attr("class", "active center-side");
278 | } else if (ny.next.hasClass(className) && !ny.prev.hasClass(className)) {
279 | if (ny.nextNext.hasClass(className)) {
280 | ny.next.attr("class", className + " center-side");
281 | } else {
282 | ny.next.attr("class", className + " right-side");
283 | }
284 | ny.item.attr("class", "active left-side");
285 | } else if (!ny.next.hasClass(className) && ny.prev.hasClass(className)) {
286 | if (ny.prevPrev.hasClass(className)) {
287 | ny.prev.attr("class", className + " center-side");
288 | } else {
289 | ny.prev.attr("class", className + " left-side");
290 | }
291 | ny.item.attr("class", className + " right-side");
292 | }
293 | } else {
294 | if (ny.next.hasClass("right-side")) {
295 | ny.next.attr("class", className);
296 | }
297 | if (ny.prev.hasClass("left-side")) {
298 | ny.prev.attr("class", className);
299 | }
300 | if (ny.prev.hasClass("center-side")) {
301 | ny.prev.attr("class", className + " right-side");
302 | }
303 | if (ny.next.hasClass("center-side")) {
304 | ny.next.attr("class", className + " left-side");
305 | }
306 | }
307 | };
308 |
309 | MultiPicker.generateStyles = function (id, cssOptions) {
310 | var styles = "";
311 | if (cssOptions.picker) {
312 | styles += "#" + id + ".checklist {";
313 | for (var key in cssOptions.picker) {
314 | styles += key + ":" + cssOptions.picker[key] + ";";
315 | }
316 | styles += "}";
317 | }
318 |
319 | if (cssOptions.element) {
320 | styles += "#" + id + " > * {"
321 | for (var key in cssOptions.element) {
322 | styles += key + ":" + cssOptions.element[key] + ";";
323 | }
324 | styles += "}";
325 | }
326 |
327 | if (cssOptions.selected) {
328 | styles += "#" + id + " > *.active {"
329 | for (var key in cssOptions.selected) {
330 | styles += key + ":" + cssOptions.selected[key] + ";";
331 | }
332 | styles += "}";
333 | }
334 |
335 | if (cssOptions.hover) {
336 | styles += "#" + id + " > *:hover {"
337 | for (var key in cssOptions.hover) {
338 | styles += key + ":" + cssOptions.hover[key] + ";";
339 | }
340 | styles += "}";
341 | }
342 | $("head").append("");
343 | };
344 |
345 | MultiPicker.API = function (method, values, cb) {
346 | if (!~["select", "unselect", "enable", "disable", "clear", "get"].indexOf(method)) {
347 | console.warn("Method " + method + " doesn't exist");
348 | return;
349 | }
350 | var pickers = !MultiPicker.isArray(this) ? [this] : this;
351 |
352 | pickers.forEach(function (picker) {
353 | if (typeof values === "function") {
354 | cb = values;
355 | } else if (!MultiPicker.isArray(values)) {
356 | values = [values];
357 | }
358 | if (method !== "get" && method != "clear") {
359 | if (!values) {
360 | console.warn("Empty enable/disable elements");
361 | return;
362 | }
363 | }
364 | switch (method) {
365 | case "select" :
366 | values.forEach(function(value) {
367 | var elSelector = picker.getElementSelector(value);
368 | if (elSelector.length) {
369 | picker.select.call(elSelector, picker, false, false);
370 | }
371 | });
372 | break;
373 | case "unselect" :
374 | values.forEach(function(value) {
375 | var elSelector = picker.getElementSelector(value);
376 | if (elSelector.length) {
377 | picker.select.call(elSelector, picker, false, true);
378 | }
379 | });
380 | break;
381 | case "enable" :
382 | picker.disable.call(picker, values, true);
383 | break;
384 | case "disable" :
385 | picker.disable.call(picker, values, false);
386 | break;
387 | case "clear" :
388 | picker.clear();
389 | break;
390 | case "get" :
391 | picker.getValue(cb);
392 | break;
393 | }
394 | });
395 | return this;
396 | };
397 |
398 | $.fn.extend({
399 | multiPicker: function (opt, values) {
400 | if (typeof opt !== "string") {
401 | var pickers = [];
402 | var isBulkInit = $(this).length > 1 ? true : false;
403 |
404 | $(this).each(function(index, elem) {
405 | var picker = new MultiPicker();
406 | // init picker instance
407 | picker.options = $.extend(picker.options, opt);
408 | picker.selector = $(elem);
409 |
410 | if (picker.options.selector === "checkbox" || picker.options.selector === "radio") {
411 | // in the case when checkbox / radiobutton used for picker, hide them and append new
412 | // `span` tags for each input, with the same value stored in `data-value` attribute
413 | picker.type = picker.options.selector;
414 | if (picker.type === "radio") {
415 | picker.options.isSingle = true;
416 | }
417 |
418 | // hide all labels inside picker
419 | picker.selector.find("label").css("display", "none");
420 |
421 | if (picker.options.disabled) {
422 | if (!MultiPicker.isArray(picker.options.disabled)) {
423 | picker.options.disabled = [picker.options.disabled];
424 | }
425 | } else {
426 | picker.options.disabled = [];
427 | }
428 | $(picker.selector).find("input").each(function (index, item) {
429 | var itemValue = $(item).val();
430 | // use label text if provided else use input `value` attribute
431 | var labelText = $("label[for='" + $(item).attr("id") + "']").text() || itemValue;
432 | picker.selector.append("" + labelText + " ");
433 | if ($(item).prop('disabled')) {
434 | picker.options.disabled.push(itemValue);
435 | }
436 | });
437 |
438 | picker.items = picker.selector.find("span");
439 | picker.options.valueSource = "data-value";
440 | picker.options.selector = "span";
441 |
442 | if (picker.options.cssOptions.vertical) {
443 | picker.selector.addClass("more-padded-t");
444 | } else {
445 | picker.selector.addClass("more-padded-l");
446 | }
447 | } else {
448 | // non-checkbox/radiobuttons used for picker
449 | picker.options.inputName = picker.options.inputName || picker.selector.attr("id");
450 |
451 | if (picker.type === "inline") {
452 | if (!$("[name=" + picker.options.inputName + "]").length) {
453 | picker.selector.after(" ");
454 | picker.input = $("[name=" + picker.options.inputName + "]");
455 | } else {
456 | picker.input = $("[name=" + picker.options.inputName + "]");
457 | }
458 | }
459 | picker.items = picker.selector.find(picker.options.selector);
460 | }
461 |
462 | picker.selector.addClass("checklist");
463 |
464 | if (picker.options.cssOptions.vertical) {
465 | picker.selector.addClass("vertical");
466 | }
467 |
468 | if (picker.options.cssOptions.size) {
469 | picker.selector.addClass(picker.options.cssOptions.size);
470 | }
471 |
472 | if (picker.options.cssOptions.quadratic) {
473 | picker.selector.addClass("quadratic");
474 | }
475 |
476 | if (picker.options.cssOptions.picker || picker.options.cssOptions.element || picker.options.cssOptions.hover || picker.options.cssOptions.selected) {
477 | MultiPicker.generateStyles(picker.selector.attr("id"), picker.options.cssOptions);
478 | }
479 |
480 | if (picker.options.prePopulate && MultiPicker.isArray(picker.options.prePopulate) && picker.options.prePopulate.length > 1 && picker.options.isSingle) {
481 | throw "Can not prePopulate more then 1 item, with `isSingle` true option";
482 | }
483 |
484 | if (picker.options.valueSource && !(picker.options.valueSource !== "index" || picker.options.valueSource !== "text" || picker.options.valueSource.substring(0, 5) === "data-")) {
485 | throw "Invalid value source";
486 | } else if (picker.options.valueSource === "data-disabled") {
487 | throw "`data-disabled` attribute is reserved, choose another name";
488 | }
489 |
490 | if (picker.options.prePopulate || picker.options.prePopulate === 0) {
491 | picker.prePopulate();
492 | }
493 |
494 | if (MultiPicker.isArray(picker.options.disabled) && picker.options.disabled.length || picker.options.disabled && !MultiPicker.isArray(picker.options.disabled) || picker.options.disabled === 0) {
495 | picker.disable(picker.options.disabled, false);
496 | }
497 |
498 | picker.selector.attr("ondragstart", 'return false');
499 | picker.setEvendHandlers();
500 |
501 | if (picker.options.onInit && typeof picker.options.onInit === "function") {
502 | picker.options.onInit();
503 | }
504 | if (isBulkInit) {
505 | picker.multiPicker = MultiPicker.API;
506 | }
507 | pickers.push(picker);
508 | });
509 |
510 | pickers.multiPicker = MultiPicker.API;
511 | return pickers;
512 | }
513 | }
514 | });
515 | })(jQuery);
516 |
--------------------------------------------------------------------------------
/tests/test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Test page
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | Su
15 | Mo
16 | Tu
17 | We
18 | Th
19 | Fr
20 | Sa
21 |
22 |
23 |
24 | Day 1
25 | Day 2
26 | Day 3
27 | Day 4
28 | Day 5
29 |
30 |
31 |
35 |
36 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | Mo
68 | Tu
69 | We
70 | Th
71 | Fr
72 |
73 |
74 |
75 | Su
76 | Mo
77 | Tu
78 | We
79 | Th
80 | Fr
81 | Sa
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/tests/tests.js:
--------------------------------------------------------------------------------
1 | QUnit.test("Simple initialization", function(assert) {
2 | assert.expect(4);
3 |
4 | var picker = $("#days").multiPicker({
5 | selector: "li",
6 | onInit: function () {
7 | assert.ok(true, "onInit called");
8 | }
9 | });
10 |
11 | assert.ok($("#days").hasClass("checklist"), "Css class `checklist` added");
12 | assert.equal($("input[type='hidden'][name='days']").length, 1, "Hidden input has been created");
13 | assert.equal($("#days .active").length, 0, "No elements has been selected");
14 | });
15 |
16 | QUnit.test("Initialization with prepopulate", function(assert) {
17 | assert.expect(5);
18 |
19 | $("#prepopulate").multiPicker({
20 | selector: "li",
21 | prePopulate: ["0", "1"],
22 | cssOptions: {
23 | size: "large",
24 | element: {
25 | "font-size": "11px"
26 | }
27 | },
28 | onInit: function () {
29 | assert.ok(true, "on init");
30 | }
31 | });
32 | assert.ok($("#prepopulate li:eq(0)").hasClass("active") && $("#prepopulate li:eq(1)").hasClass("active"), "Days 0, 2 have been selected");
33 | assert.ok(!$("#prepopulate li:eq(3)").hasClass("active") && !$("#prepopulate li:eq(4)").hasClass("active") && !$("#prepopulate li:eq(5)").hasClass("active"), "Days 3, 4, 5 are not selected");
34 |
35 | assert.ok($("#prepopulate").hasClass("checklist"), "Css class `checklist` added");
36 | assert.equal($("input[type='hidden'][name='prepopulate']").length, 1, "Hidden input created");
37 | });
38 |
39 | QUnit.test("Initializate single picker", function(assert) {
40 | assert.expect(3);
41 |
42 | $("#single").multiPicker({
43 | selector: "li",
44 | isSingle: true,
45 | onInit: function () {
46 | assert.ok(true, "onInit called");
47 | }
48 | });
49 |
50 | assert.ok($("#single").hasClass("checklist"), "Css class `checklist` added");
51 | assert.equal($("input[type='hidden'][name='single']").length, 1, "Hidden input created");
52 | });
53 |
54 | QUnit.test("Initialize with specified input name option", function(assert) {
55 | assert.expect(4);
56 | $("#input-name-specified").multiPicker({
57 | selector: "li",
58 | inputName: "yes-or-no",
59 | onInit: function() {
60 | assert.ok(true, "onInit called");
61 | }
62 | });
63 |
64 | assert.ok($("#input-name-specified").hasClass("checklist"), "Css class `checklist` added");
65 | assert.equal($("input[type='hidden'][name='yes-or-no']").length, 1, "New input with specified name created");
66 | assert.equal($("input[type='hidden'][name='input-name-specified']").length, 0, "Id doesnt used for new input name");
67 | });
68 |
69 | QUnit.test("Initialize checkbox", function(assert) {
70 | assert.expect(3);
71 | $("#programming-languages").multiPicker({
72 | selector: "checkbox",
73 | onInit: function() {
74 | assert.ok(true, "onInit called");
75 | }
76 | });
77 |
78 | assert.ok($("#programming-languages").hasClass("checklist"), "CSS class `checklist` added");
79 | assert.equal($("input[type='hidden'][name='programming-languages']").length, 0, "No hidden input created");
80 | });
81 |
82 | QUnit.test("Initialize radiobuttons", function(assert) {
83 | assert.expect(3);
84 | $("#languages").multiPicker({
85 | selector: "radio",
86 | onInit: function() {
87 | assert.ok(true, "onInit called");
88 | }
89 | });
90 |
91 | assert.ok($("#languages").hasClass("checklist"), "Css class `checklist` added");
92 | assert.equal($("input[type='hidden'][name='languages']").length, 0, "No hidden input created");
93 | });
94 |
95 | QUnit.test("Test events ", function(assert) {
96 | assert.expect(5);
97 |
98 | var picker = $("#test-events").multiPicker({
99 | selector: "li",
100 | onInit: function () {
101 | assert.ok(true, "onInit called");
102 | },
103 | onSelect: function (el, val) {
104 | assert.ok(true, "on Select called");
105 | assert.equal(val, "1", "on Select value is ok");
106 | },
107 | onUnselect : function (el, val) {
108 | assert.ok(true, "Unselect called");
109 | assert.equal(val, "1", "Unselect value is ok");
110 | }
111 | });
112 |
113 | picker.multiPicker("select", ["1"]);
114 | picker.multiPicker("unselect", ["1"]);
115 | });
116 |
117 | QUnit.test("Api test", function(assert) {
118 | assert.expect(11);
119 |
120 | var picker = $("#api-test").multiPicker({
121 | selector: "li"
122 | });
123 |
124 | picker.multiPicker('select', [1, 3]);
125 | assert.ok($("#api-test li:eq(1)").hasClass("active") && $("#api-test li:eq(3)").hasClass("active"), "Days 1, 3 have been selected");
126 |
127 | picker.multiPicker('select', 4);
128 | assert.ok($("#api-test li:eq(4)").hasClass("active"), "Day 4 has been selected");
129 |
130 | picker.multiPicker('unselect', 4);
131 | assert.ok(!$("#api-test li:eq(4)").hasClass("active"), "Day 4 has been unselected");
132 |
133 | picker.multiPicker('unselect', [1, 3]);
134 | assert.ok(!$("#api-test li:eq(1)").hasClass("active") && !$("#api-test li:eq(3)").hasClass("active"), "Days 1, 3 have been unselected");
135 |
136 | picker.multiPicker('select', [2, 4]);
137 | picker.multiPicker('clear');
138 | assert.equal($("#api-test .active").length, 0, "Picker cleared");
139 | picker.multiPicker('get', function (val) {
140 | assert.ok(!val, 'Pickers value cleared');
141 | });
142 |
143 | picker.multiPicker('select', [1, 3]);
144 | picker.multiPicker('get', function (val) {
145 | assert.equal(val, '1,3', "Picker values specified correctly");
146 | });
147 |
148 | picker.multiPicker('disable', 0);
149 | assert.ok($("#api-test li:eq(0)").attr("data-disabled"), "Day 0 has been disabled");
150 |
151 | picker.multiPicker('enable', 0);
152 | assert.ok(!$("#api-test li:eq(0)").attr("data-disabled"), "Day 0 has been enabled");
153 |
154 | picker.multiPicker('disable', [1, 3, 4]);
155 | assert.ok($("#api-test li:eq(1)").attr("data-disabled") && $("#api-test li:eq(3)").attr("data-disabled") && $("#api-test li:eq(4)").attr("data-disabled"), "Day 1, 3, 4 have been disabled");
156 |
157 | picker.multiPicker('enable', [1, 3, 4]);
158 | assert.ok(!$("#api-test li:eq(1)").attr("data-disabled") && !$("#api-test li:eq(3)").attr("data-disabled") && !$("#api-test li:eq(4)").attr("data-disabled"), "Day 1, 3, 4 have been enabled");
159 | });
160 | $("#api-test-radio").multiPicker({
161 | selector: "radio"
162 | });
163 |
164 | QUnit.test("Api test checkboxes", function(assert) {
165 | assert.expect(11);
166 |
167 | var picker = $("#api-test-checkbox").multiPicker({
168 | selector: "checkbox"
169 | });
170 |
171 | picker.multiPicker('select', ["EN", "RU"]);
172 | assert.ok($("#api-test-checkbox span[data-value='EN']").hasClass("active") && $("#api-test-checkbox span[data-value='RU']").hasClass("active"), "Langs EN, HY have been selected");
173 |
174 | picker.multiPicker('select', "HY");
175 | assert.ok($("#api-test-checkbox span[data-value='HY']").hasClass("active"), "Lang HY has been selected");
176 |
177 | picker.multiPicker('unselect', "HY");
178 | assert.ok(!$("#api-test-checkbox span[data-value='HY']").hasClass("active"), "Lang HY has been unselected");
179 |
180 | picker.multiPicker('unselect', ["EN", "RU"]);
181 | assert.ok(!$("#api-test-checkbox span[data-value='EN']").hasClass("active") && !$("#api-test-checkbox span[data-value='RU']").hasClass("active"), "Langs EN, HY have been unselected");
182 |
183 | picker.multiPicker('select', ["HY", "JP"]);
184 | picker.multiPicker('clear');
185 | assert.equal($("#api-test-checkbox .active").length, 0, "Picker cleared");
186 | picker.multiPicker('get', function (val) {
187 | assert.equal(val.length, 0, 'Pickers value cleared');
188 | });
189 |
190 | picker.multiPicker('select', ["EN", "RU"]);
191 | picker.multiPicker('get', function (val) {
192 | assert.deepEqual(val, ["EN", "RU"], "Picker values specified correctly");
193 | });
194 |
195 | picker.multiPicker('disable', "HY");
196 | assert.ok($("#api-test-checkbox span[data-value='HY']").attr("data-disabled"), "Lang HY has been disabled");
197 |
198 | picker.multiPicker('enable', "HY");
199 | assert.ok(!$("#api-test-checkbox span[data-value='HY']").attr("data-disabled"), "Lang HY has been enabled");
200 |
201 | picker.multiPicker('disable', ["EN", "RU", "JP"]);
202 | assert.ok($("#api-test-checkbox span[data-value='EN']").attr("data-disabled") && $("#api-test-checkbox span[data-value='RU']").attr("data-disabled") && $("#api-test-checkbox span[data-value='JP']").attr("data-disabled"), "Langs EN, RU, JP have been disabled");
203 |
204 | picker.multiPicker('enable', ["EN", "RU", "JP"]);
205 | assert.ok(!$("#api-test-checkbox span[data-value='EN']").attr("data-disabled") && !$("#api-test-checkbox span[data-value='RU']").attr("data-disabled") && !$("#api-test-checkbox span[data-value='JP']").attr("data-disabled"), "Langs EN, RU, JP have been enabled");
206 | });
207 |
--------------------------------------------------------------------------------