bootstrap-duallistbox-rails 3.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 930773806e11675037a59cb2fadd3d89cf9e680c
4
+ data.tar.gz: 7f614c6062f1619eb8353b2738e212b32f62c0b0
5
+ SHA512:
6
+ metadata.gz: e5fa354286151bdac738c4caa98ab306aafcfbc835481e31f0f919a8d37a60c29bb522e3bfd72bf12a3d891917f9492cbcfb4f5a52e6fe03bfd354d8f83085d6
7
+ data.tar.gz: 1f0c4622cbf3292f605ee71d4bf6dfaacd545a348ee551aee8a3b201c31ce08afdc3ca130e42f2989cca7a0fc7ce35037a307b7fdb4302bfbc622dc8536670bc
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in bootstrap-duallistbox-rails.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Damien Dormal
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
13
+ all 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
21
+ THE SOFTWARE.
@@ -0,0 +1,38 @@
1
+ # Bootstrap::Duallistbox::Rails
2
+
3
+ Assets for https://github.com/istvan-ujjmeszaros/bootstrap-duallistbox - see it for details
4
+
5
+ add to application.js and application.css something like
6
+
7
+ //= require bootstrap-duallistbox
8
+
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ ```ruby
15
+ gem 'bootstrap-duallistbox-rails'
16
+ ```
17
+
18
+ And then execute:
19
+
20
+ $ bundle
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install bootstrap-duallistbox-rails
25
+
26
+ ## Development
27
+
28
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
29
+
30
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
31
+
32
+ ## Contributing
33
+
34
+ 1. Fork it ( https://github.com/[my-github-username]/bootstrap-duallistbox-rails/fork )
35
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
36
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
37
+ 4. Push to the branch (`git push origin my-new-feature`)
38
+ 5. Create a new Pull Request
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "bootstrap/duallistbox/rails"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'bootstrap-duallistbox-rails/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "bootstrap-duallistbox-rails"
8
+ spec.version = Bootstrap::Duallistbox::Rails::VERSION
9
+ spec.authors = ["Damien Dormal"]
10
+ spec.email = ["dormal.damien@gmail.com"]
11
+
12
+ spec.summary = %q{assets for bootstrap-duallistbox}
13
+ spec.description = %q{assets for bootstrap-duallistbox}
14
+ spec.homepage = "https://github.com/damsonn/bootstrap-duallistbox-rails"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_dependency "rails", ">= 4.0.0"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.8"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ end
@@ -0,0 +1,10 @@
1
+ require 'bootstrap-duallistbox-rails/version'
2
+
3
+ module Bootstrap
4
+ module Duallistbox
5
+ module Rails
6
+ class Engine < ::Rails::Engine
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,7 @@
1
+ module Bootstrap
2
+ module Duallistbox
3
+ module Rails
4
+ VERSION = "3.0.2"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,717 @@
1
+ /*
2
+ * Bootstrap Duallistbox - v3.0.2
3
+ * A responsive dual listbox widget optimized for Twitter Bootstrap. It works on all modern browsers and on touch devices.
4
+ * http://www.virtuosoft.eu/code/bootstrap-duallistbox/
5
+ *
6
+ * Made by István Ujj-Mészáros
7
+ * Under Apache License v2.0 License
8
+ */
9
+ ;(function ($, window, document, undefined) {
10
+ // Create the defaults once
11
+ var pluginName = 'bootstrapDualListbox',
12
+ defaults = {
13
+ bootstrap2Compatible: false,
14
+ filterTextClear: 'show all',
15
+ filterPlaceHolder: 'Filter',
16
+ moveSelectedLabel: 'Move selected',
17
+ moveAllLabel: 'Move all',
18
+ removeSelectedLabel: 'Remove selected',
19
+ removeAllLabel: 'Remove all',
20
+ moveOnSelect: true, // true/false (forced true on androids, see the comment later)
21
+ preserveSelectionOnMove: false, // 'all' / 'moved' / false
22
+ selectedListLabel: false, // 'string', false
23
+ nonSelectedListLabel: false, // 'string', false
24
+ helperSelectNamePostfix: '_helper', // 'string_of_postfix' / false
25
+ selectorMinimalHeight: 100,
26
+ showFilterInputs: true, // whether to show filter inputs
27
+ nonSelectedFilter: '', // string, filter the non selected options
28
+ selectedFilter: '', // string, filter the selected options
29
+ infoText: 'Showing all {0}', // text when all options are visible / false for no info text
30
+ infoTextFiltered: '<span class="label label-warning">Filtered</span> {0} from {1}', // when not all of the options are visible due to the filter
31
+ infoTextEmpty: 'Empty list', // when there are no options present in the list
32
+ filterOnValues: false // filter by selector's values, boolean
33
+ },
34
+ // Selections are invisible on android if the containing select is styled with CSS
35
+ // http://code.google.com/p/android/issues/detail?id=16922
36
+ isBuggyAndroid = /android/i.test(navigator.userAgent.toLowerCase());
37
+
38
+ // The actual plugin constructor
39
+ function BootstrapDualListbox(element, options) {
40
+ this.element = $(element);
41
+ // jQuery has an extend method which merges the contents of two or
42
+ // more objects, storing the result in the first object. The first object
43
+ // is generally empty as we don't want to alter the default options for
44
+ // future instances of the plugin
45
+ this.settings = $.extend({}, defaults, options);
46
+ this._defaults = defaults;
47
+ this._name = pluginName;
48
+ this.init();
49
+ }
50
+
51
+ function triggerChangeEvent(dualListbox) {
52
+ dualListbox.element.trigger('change');
53
+ }
54
+
55
+ function updateSelectionStates(dualListbox) {
56
+ dualListbox.element.find('option').each(function(index, item) {
57
+ var $item = $(item);
58
+ if (typeof($item.data('original-index')) === 'undefined') {
59
+ $item.data('original-index', dualListbox.elementCount++);
60
+ }
61
+ if (typeof($item.data('_selected')) === 'undefined') {
62
+ $item.data('_selected', false);
63
+ }
64
+ });
65
+ }
66
+
67
+ function changeSelectionState(dualListbox, original_index, selected) {
68
+ dualListbox.element.find('option').each(function(index, item) {
69
+ var $item = $(item);
70
+ if ($item.data('original-index') === original_index) {
71
+ $item.prop('selected', selected);
72
+ }
73
+ });
74
+ }
75
+
76
+ function formatString(s, args) {
77
+ return s.replace(/\{(\d+)\}/g, function(match, number) {
78
+ return typeof args[number] !== 'undefined' ? args[number] : match;
79
+ });
80
+ }
81
+
82
+ function refreshInfo(dualListbox) {
83
+ if (!dualListbox.settings.infoText) {
84
+ return;
85
+ }
86
+
87
+ var visible1 = dualListbox.elements.select1.find('option').length,
88
+ visible2 = dualListbox.elements.select2.find('option').length,
89
+ all1 = dualListbox.element.find('option').length - dualListbox.selectedElements,
90
+ all2 = dualListbox.selectedElements,
91
+ content = '';
92
+
93
+ if (all1 === 0) {
94
+ content = dualListbox.settings.infoTextEmpty;
95
+ } else if (visible1 === all1) {
96
+ content = formatString(dualListbox.settings.infoText, [visible1, all1]);
97
+ } else {
98
+ content = formatString(dualListbox.settings.infoTextFiltered, [visible1, all1]);
99
+ }
100
+
101
+ dualListbox.elements.info1.html(content);
102
+ dualListbox.elements.box1.toggleClass('filtered', !(visible1 === all1 || all1 === 0));
103
+
104
+ if (all2 === 0) {
105
+ content = dualListbox.settings.infoTextEmpty;
106
+ } else if (visible2 === all2) {
107
+ content = formatString(dualListbox.settings.infoText, [visible2, all2]);
108
+ } else {
109
+ content = formatString(dualListbox.settings.infoTextFiltered, [visible2, all2]);
110
+ }
111
+
112
+ dualListbox.elements.info2.html(content);
113
+ dualListbox.elements.box2.toggleClass('filtered', !(visible2 === all2 || all2 === 0));
114
+ }
115
+
116
+ function refreshSelects(dualListbox) {
117
+ dualListbox.selectedElements = 0;
118
+
119
+ dualListbox.elements.select1.empty();
120
+ dualListbox.elements.select2.empty();
121
+
122
+ dualListbox.element.find('option').each(function(index, item) {
123
+ var $item = $(item);
124
+ if ($item.prop('selected')) {
125
+ dualListbox.selectedElements++;
126
+ dualListbox.elements.select2.append($item.clone(true).prop('selected', $item.data('_selected')));
127
+ } else {
128
+ dualListbox.elements.select1.append($item.clone(true).prop('selected', $item.data('_selected')));
129
+ }
130
+ });
131
+
132
+ if (dualListbox.settings.showFilterInputs) {
133
+ filter(dualListbox, 1);
134
+ filter(dualListbox, 2);
135
+ }
136
+ refreshInfo(dualListbox);
137
+ }
138
+
139
+ function filter(dualListbox, selectIndex) {
140
+ if (!dualListbox.settings.showFilterInputs) {
141
+ return;
142
+ }
143
+
144
+ saveSelections(dualListbox, selectIndex);
145
+
146
+ dualListbox.elements['select'+selectIndex].empty().scrollTop(0);
147
+ var regex = new RegExp($.trim(dualListbox.elements['filterInput'+selectIndex].val()), 'gi'),
148
+ options = dualListbox.element;
149
+
150
+ if (selectIndex === 1) {
151
+ options = options.find('option').not(':selected');
152
+ } else {
153
+ options = options.find('option:selected');
154
+ }
155
+
156
+ options.each(function(index, item) {
157
+ var $item = $(item),
158
+ isFiltered = true;
159
+ if (item.text.match(regex) || (dualListbox.settings.filterOnValues && $item.attr('value').match(regex) ) ) {
160
+ isFiltered = false;
161
+ dualListbox.elements['select'+selectIndex].append($item.clone(true).prop('selected', $item.data('_selected')));
162
+ }
163
+ dualListbox.element.find('option').eq($item.data('original-index')).data('filtered'+selectIndex, isFiltered);
164
+ });
165
+
166
+ refreshInfo(dualListbox);
167
+ }
168
+
169
+ function saveSelections(dualListbox, selectIndex) {
170
+ dualListbox.elements['select'+selectIndex].find('option').each(function(index, item) {
171
+ var $item = $(item);
172
+ dualListbox.element.find('option').eq($item.data('original-index')).data('_selected', $item.prop('selected'));
173
+ });
174
+ }
175
+
176
+ function sortOptions(select) {
177
+ select.find('option').sort(function(a, b) {
178
+ return ($(a).data('original-index') > $(b).data('original-index')) ? 1 : -1;
179
+ }).appendTo(select);
180
+ }
181
+
182
+ function clearSelections(dualListbox) {
183
+ dualListbox.elements.select1.find('option').each(function() {
184
+ dualListbox.element.find('option').data('_selected', false);
185
+ });
186
+ }
187
+
188
+ function move(dualListbox) {
189
+ if (dualListbox.settings.preserveSelectionOnMove === 'all' && !dualListbox.settings.moveOnSelect) {
190
+ saveSelections(dualListbox, 1);
191
+ saveSelections(dualListbox, 2);
192
+ } else if (dualListbox.settings.preserveSelectionOnMove === 'moved' && !dualListbox.settings.moveOnSelect) {
193
+ saveSelections(dualListbox, 1);
194
+ }
195
+
196
+ dualListbox.elements.select1.find('option:selected').each(function(index, item) {
197
+ var $item = $(item);
198
+ if (!$item.data('filtered1')) {
199
+ changeSelectionState(dualListbox, $item.data('original-index'), true);
200
+ }
201
+ });
202
+
203
+ refreshSelects(dualListbox);
204
+ triggerChangeEvent(dualListbox);
205
+ sortOptions(dualListbox.elements.select2);
206
+ }
207
+
208
+ function remove(dualListbox) {
209
+ if (dualListbox.settings.preserveSelectionOnMove === 'all' && !dualListbox.settings.moveOnSelect) {
210
+ saveSelections(dualListbox, 1);
211
+ saveSelections(dualListbox, 2);
212
+ } else if (dualListbox.settings.preserveSelectionOnMove === 'moved' && !dualListbox.settings.moveOnSelect) {
213
+ saveSelections(dualListbox, 2);
214
+ }
215
+
216
+ dualListbox.elements.select2.find('option:selected').each(function(index, item) {
217
+ var $item = $(item);
218
+ if (!$item.data('filtered2')) {
219
+ changeSelectionState(dualListbox, $item.data('original-index'), false);
220
+ }
221
+ });
222
+
223
+ refreshSelects(dualListbox);
224
+ triggerChangeEvent(dualListbox);
225
+ sortOptions(dualListbox.elements.select1);
226
+ }
227
+
228
+ function moveAll(dualListbox) {
229
+ if (dualListbox.settings.preserveSelectionOnMove === 'all' && !dualListbox.settings.moveOnSelect) {
230
+ saveSelections(dualListbox, 1);
231
+ saveSelections(dualListbox, 2);
232
+ } else if (dualListbox.settings.preserveSelectionOnMove === 'moved' && !dualListbox.settings.moveOnSelect) {
233
+ saveSelections(dualListbox, 1);
234
+ }
235
+
236
+ dualListbox.element.find('option').each(function(index, item) {
237
+ var $item = $(item);
238
+ if (!$item.data('filtered1')) {
239
+ $item.prop('selected', true);
240
+ }
241
+ });
242
+
243
+ refreshSelects(dualListbox);
244
+ triggerChangeEvent(dualListbox);
245
+ }
246
+
247
+ function removeAll(dualListbox) {
248
+ if (dualListbox.settings.preserveSelectionOnMove === 'all' && !dualListbox.settings.moveOnSelect) {
249
+ saveSelections(dualListbox, 1);
250
+ saveSelections(dualListbox, 2);
251
+ } else if (dualListbox.settings.preserveSelectionOnMove === 'moved' && !dualListbox.settings.moveOnSelect) {
252
+ saveSelections(dualListbox, 2);
253
+ }
254
+
255
+ dualListbox.element.find('option').each(function(index, item) {
256
+ var $item = $(item);
257
+ if (!$item.data('filtered2')) {
258
+ $item.prop('selected', false);
259
+ }
260
+ });
261
+
262
+ refreshSelects(dualListbox);
263
+ triggerChangeEvent(dualListbox);
264
+ }
265
+
266
+ function bindEvents(dualListbox) {
267
+ dualListbox.elements.form.submit(function(e) {
268
+ if (dualListbox.elements.filterInput1.is(':focus')) {
269
+ e.preventDefault();
270
+ dualListbox.elements.filterInput1.focusout();
271
+ } else if (dualListbox.elements.filterInput2.is(':focus')) {
272
+ e.preventDefault();
273
+ dualListbox.elements.filterInput2.focusout();
274
+ }
275
+ });
276
+
277
+ dualListbox.element.on('bootstrapDualListbox.refresh', function(e, mustClearSelections){
278
+ dualListbox.refresh(mustClearSelections);
279
+ });
280
+
281
+ dualListbox.elements.filterClear1.on('click', function() {
282
+ dualListbox.setNonSelectedFilter('', true);
283
+ });
284
+
285
+ dualListbox.elements.filterClear2.on('click', function() {
286
+ dualListbox.setSelectedFilter('', true);
287
+ });
288
+
289
+ dualListbox.elements.moveButton.on('click', function() {
290
+ move(dualListbox);
291
+ });
292
+
293
+ dualListbox.elements.moveAllButton.on('click', function() {
294
+ moveAll(dualListbox);
295
+ });
296
+
297
+ dualListbox.elements.removeButton.on('click', function() {
298
+ remove(dualListbox);
299
+ });
300
+
301
+ dualListbox.elements.removeAllButton.on('click', function() {
302
+ removeAll(dualListbox);
303
+ });
304
+
305
+ dualListbox.elements.filterInput1.on('change keyup', function() {
306
+ filter(dualListbox, 1);
307
+ });
308
+
309
+ dualListbox.elements.filterInput2.on('change keyup', function() {
310
+ filter(dualListbox, 2);
311
+ });
312
+ }
313
+
314
+ BootstrapDualListbox.prototype = {
315
+ init: function () {
316
+ // Add the custom HTML template
317
+ this.container = $('' +
318
+ '<div class="bootstrap-duallistbox-container">' +
319
+ ' <div class="box1">' +
320
+ ' <label></label>' +
321
+ ' <span class="info-container">' +
322
+ ' <span class="info"></span>' +
323
+ ' <button type="button" class="btn clear1 pull-right"></button>' +
324
+ ' </span>' +
325
+ ' <input class="filter" type="text">' +
326
+ ' <div class="btn-group buttons">' +
327
+ ' <button type="button" class="btn moveall">' +
328
+ ' <i></i>' +
329
+ ' <i></i>' +
330
+ ' </button>' +
331
+ ' <button type="button" class="btn move">' +
332
+ ' <i></i>' +
333
+ ' </button>' +
334
+ ' </div>' +
335
+ ' <select multiple="multiple"></select>' +
336
+ ' </div>' +
337
+ ' <div class="box2">' +
338
+ ' <label></label>' +
339
+ ' <span class="info-container">' +
340
+ ' <span class="info"></span>' +
341
+ ' <button type="button" class="btn clear2 pull-right"></button>' +
342
+ ' </span>' +
343
+ ' <input class="filter" type="text">' +
344
+ ' <div class="btn-group buttons">' +
345
+ ' <button type="button" class="btn remove">' +
346
+ ' <i></i>' +
347
+ ' </button>' +
348
+ ' <button type="button" class="btn removeall">' +
349
+ ' <i></i>' +
350
+ ' <i></i>' +
351
+ ' </button>' +
352
+ ' </div>' +
353
+ ' <select multiple="multiple"></select>' +
354
+ ' </div>' +
355
+ '</div>')
356
+ .insertBefore(this.element);
357
+
358
+ // Cache the inner elements
359
+ this.elements = {
360
+ originalSelect: this.element,
361
+ box1: $('.box1', this.container),
362
+ box2: $('.box2', this.container),
363
+ filterInput1: $('.box1 .filter', this.container),
364
+ filterInput2: $('.box2 .filter', this.container),
365
+ filterClear1: $('.box1 .clear1', this.container),
366
+ filterClear2: $('.box2 .clear2', this.container),
367
+ label1: $('.box1 > label', this.container),
368
+ label2: $('.box2 > label', this.container),
369
+ info1: $('.box1 .info', this.container),
370
+ info2: $('.box2 .info', this.container),
371
+ select1: $('.box1 select', this.container),
372
+ select2: $('.box2 select', this.container),
373
+ moveButton: $('.box1 .move', this.container),
374
+ removeButton: $('.box2 .remove', this.container),
375
+ moveAllButton: $('.box1 .moveall', this.container),
376
+ removeAllButton: $('.box2 .removeall', this.container),
377
+ form: $($('.box1 .filter', this.container)[0].form)
378
+ };
379
+
380
+ // Set select IDs
381
+ this.originalSelectName = this.element.attr('name') || '';
382
+ var select1Id = 'bootstrap-duallistbox-nonselected-list_' + this.originalSelectName,
383
+ select2Id = 'bootstrap-duallistbox-selected-list_' + this.originalSelectName;
384
+ this.elements.select1.attr('id', select1Id);
385
+ this.elements.select2.attr('id', select2Id);
386
+ this.elements.label1.attr('for', select1Id);
387
+ this.elements.label2.attr('for', select2Id);
388
+
389
+ // Apply all settings
390
+ this.selectedElements = 0;
391
+ this.elementCount = 0;
392
+ this.setBootstrap2Compatible(this.settings.bootstrap2Compatible);
393
+ this.setFilterTextClear(this.settings.filterTextClear);
394
+ this.setFilterPlaceHolder(this.settings.filterPlaceHolder);
395
+ this.setMoveSelectedLabel(this.settings.moveSelectedLabel);
396
+ this.setMoveAllLabel(this.settings.moveAllLabel);
397
+ this.setRemoveSelectedLabel(this.settings.removeSelectedLabel);
398
+ this.setRemoveAllLabel(this.settings.removeAllLabel);
399
+ this.setMoveOnSelect(this.settings.moveOnSelect);
400
+ this.setPreserveSelectionOnMove(this.settings.preserveSelectionOnMove);
401
+ this.setSelectedListLabel(this.settings.selectedListLabel);
402
+ this.setNonSelectedListLabel(this.settings.nonSelectedListLabel);
403
+ this.setHelperSelectNamePostfix(this.settings.helperSelectNamePostfix);
404
+ this.setSelectOrMinimalHeight(this.settings.selectorMinimalHeight);
405
+
406
+ updateSelectionStates(this);
407
+
408
+ this.setShowFilterInputs(this.settings.showFilterInputs);
409
+ this.setNonSelectedFilter(this.settings.nonSelectedFilter);
410
+ this.setSelectedFilter(this.settings.selectedFilter);
411
+ this.setInfoText(this.settings.infoText);
412
+ this.setInfoTextFiltered(this.settings.infoTextFiltered);
413
+ this.setInfoTextEmpty(this.settings.infoTextEmpty);
414
+ this.setFilterOnValues(this.settings.filterOnValues);
415
+
416
+ // Hide the original select
417
+ this.element.hide();
418
+
419
+ bindEvents(this);
420
+ refreshSelects(this);
421
+
422
+ return this.element;
423
+ },
424
+ setBootstrap2Compatible: function(value, refresh) {
425
+ this.settings.bootstrap2Compatible = value;
426
+ if (value) {
427
+ this.container.removeClass('row').addClass('row-fluid bs2compatible');
428
+ this.container.find('.box1, .box2').removeClass('col-md-6').addClass('span6');
429
+ this.container.find('.clear1, .clear2').removeClass('btn-default btn-xs').addClass('btn-mini');
430
+ this.container.find('input, select').removeClass('form-control');
431
+ this.container.find('.btn').removeClass('btn-default');
432
+ this.container.find('.moveall > i, .move > i').removeClass('glyphicon glyphicon-arrow-right').addClass('icon-arrow-right');
433
+ this.container.find('.removeall > i, .remove > i').removeClass('glyphicon glyphicon-arrow-left').addClass('icon-arrow-left');
434
+ } else {
435
+ this.container.removeClass('row-fluid bs2compatible').addClass('row');
436
+ this.container.find('.box1, .box2').removeClass('span6').addClass('col-md-6');
437
+ this.container.find('.clear1, .clear2').removeClass('btn-mini').addClass('btn-default btn-xs');
438
+ this.container.find('input, select').addClass('form-control');
439
+ this.container.find('.btn').addClass('btn-default');
440
+ this.container.find('.moveall > i, .move > i').removeClass('icon-arrow-right').addClass('glyphicon glyphicon-arrow-right');
441
+ this.container.find('.removeall > i, .remove > i').removeClass('icon-arrow-left').addClass('glyphicon glyphicon-arrow-left');
442
+ }
443
+ if (refresh) {
444
+ refreshSelects(this);
445
+ }
446
+ return this.element;
447
+ },
448
+ setFilterTextClear: function(value, refresh) {
449
+ this.settings.filterTextClear = value;
450
+ this.elements.filterClear1.html(value);
451
+ this.elements.filterClear2.html(value);
452
+ if (refresh) {
453
+ refreshSelects(this);
454
+ }
455
+ return this.element;
456
+ },
457
+ setFilterPlaceHolder: function(value, refresh) {
458
+ this.settings.filterPlaceHolder = value;
459
+ this.elements.filterInput1.attr('placeholder', value);
460
+ this.elements.filterInput2.attr('placeholder', value);
461
+ if (refresh) {
462
+ refreshSelects(this);
463
+ }
464
+ return this.element;
465
+ },
466
+ setMoveSelectedLabel: function(value, refresh) {
467
+ this.settings.moveSelectedLabel = value;
468
+ this.elements.moveButton.attr('title', value);
469
+ if (refresh) {
470
+ refreshSelects(this);
471
+ }
472
+ return this.element;
473
+ },
474
+ setMoveAllLabel: function(value, refresh) {
475
+ this.settings.moveAllLabel = value;
476
+ this.elements.moveAllButton.attr('title', value);
477
+ if (refresh) {
478
+ refreshSelects(this);
479
+ }
480
+ return this.element;
481
+ },
482
+ setRemoveSelectedLabel: function(value, refresh) {
483
+ this.settings.removeSelectedLabel = value;
484
+ this.elements.removeButton.attr('title', value);
485
+ if (refresh) {
486
+ refreshSelects(this);
487
+ }
488
+ return this.element;
489
+ },
490
+ setRemoveAllLabel: function(value, refresh) {
491
+ this.settings.removeAllLabel = value;
492
+ this.elements.removeAllButton.attr('title', value);
493
+ if (refresh) {
494
+ refreshSelects(this);
495
+ }
496
+ return this.element;
497
+ },
498
+ setMoveOnSelect: function(value, refresh) {
499
+ if (isBuggyAndroid) {
500
+ value = true;
501
+ }
502
+ this.settings.moveOnSelect = value;
503
+ if (this.settings.moveOnSelect) {
504
+ this.container.addClass('moveonselect');
505
+ var self = this;
506
+ this.elements.select1.on('change', function() {
507
+ move(self);
508
+ });
509
+ this.elements.select2.on('change', function() {
510
+ remove(self);
511
+ });
512
+ } else {
513
+ this.container.removeClass('moveonselect');
514
+ this.elements.select1.off('change');
515
+ this.elements.select2.off('change');
516
+ }
517
+ if (refresh) {
518
+ refreshSelects(this);
519
+ }
520
+ return this.element;
521
+ },
522
+ setPreserveSelectionOnMove: function(value, refresh) {
523
+ // We are forcing to move on select and disabling preserveSelectionOnMove on Android
524
+ if (isBuggyAndroid) {
525
+ value = false;
526
+ }
527
+ this.settings.preserveSelectionOnMove = value;
528
+ if (refresh) {
529
+ refreshSelects(this);
530
+ }
531
+ return this.element;
532
+ },
533
+ setSelectedListLabel: function(value, refresh) {
534
+ this.settings.selectedListLabel = value;
535
+ if (value) {
536
+ this.elements.label2.show().html(value);
537
+ } else {
538
+ this.elements.label2.hide().html(value);
539
+ }
540
+ if (refresh) {
541
+ refreshSelects(this);
542
+ }
543
+ return this.element;
544
+ },
545
+ setNonSelectedListLabel: function(value, refresh) {
546
+ this.settings.nonSelectedListLabel = value;
547
+ if (value) {
548
+ this.elements.label1.show().html(value);
549
+ } else {
550
+ this.elements.label1.hide().html(value);
551
+ }
552
+ if (refresh) {
553
+ refreshSelects(this);
554
+ }
555
+ return this.element;
556
+ },
557
+ setHelperSelectNamePostfix: function(value, refresh) {
558
+ this.settings.helperSelectNamePostfix = value;
559
+ if (value) {
560
+ this.elements.select1.attr('name', this.originalSelectName + value + '1');
561
+ this.elements.select2.attr('name', this.originalSelectName + value + '2');
562
+ } else {
563
+ this.elements.select1.removeAttr('name');
564
+ this.elements.select2.removeAttr('name');
565
+ }
566
+ if (refresh) {
567
+ refreshSelects(this);
568
+ }
569
+ return this.element;
570
+ },
571
+ setSelectOrMinimalHeight: function(value, refresh) {
572
+ this.settings.selectorMinimalHeight = value;
573
+ var height = this.element.height();
574
+ if (this.element.height() < value) {
575
+ height = value;
576
+ }
577
+ this.elements.select1.height(height);
578
+ this.elements.select2.height(height);
579
+ if (refresh) {
580
+ refreshSelects(this);
581
+ }
582
+ return this.element;
583
+ },
584
+ setShowFilterInputs: function(value, refresh) {
585
+ if (!value) {
586
+ this.setNonSelectedFilter('');
587
+ this.setSelectedFilter('');
588
+ refreshSelects(this);
589
+ this.elements.filterInput1.hide();
590
+ this.elements.filterInput2.hide();
591
+ } else {
592
+ this.elements.filterInput1.show();
593
+ this.elements.filterInput2.show();
594
+ }
595
+ this.settings.showFilterInputs = value;
596
+ if (refresh) {
597
+ refreshSelects(this);
598
+ }
599
+ return this.element;
600
+ },
601
+ setNonSelectedFilter: function(value, refresh) {
602
+ if (this.settings.showFilterInputs) {
603
+ this.settings.nonSelectedFilter = value;
604
+ this.elements.filterInput1.val(value);
605
+ if (refresh) {
606
+ refreshSelects(this);
607
+ }
608
+ return this.element;
609
+ }
610
+ },
611
+ setSelectedFilter: function(value, refresh) {
612
+ if (this.settings.showFilterInputs) {
613
+ this.settings.selectedFilter = value;
614
+ this.elements.filterInput2.val(value);
615
+ if (refresh) {
616
+ refreshSelects(this);
617
+ }
618
+ return this.element;
619
+ }
620
+ },
621
+ setInfoText: function(value, refresh) {
622
+ this.settings.infoText = value;
623
+ if (refresh) {
624
+ refreshSelects(this);
625
+ }
626
+ return this.element;
627
+ },
628
+ setInfoTextFiltered: function(value, refresh) {
629
+ this.settings.infoTextFiltered = value;
630
+ if (refresh) {
631
+ refreshSelects(this);
632
+ }
633
+ return this.element;
634
+ },
635
+ setInfoTextEmpty: function(value, refresh) {
636
+ this.settings.infoTextEmpty = value;
637
+ if (refresh) {
638
+ refreshSelects(this);
639
+ }
640
+ return this.element;
641
+ },
642
+ setFilterOnValues: function(value, refresh) {
643
+ this.settings.filterOnValues = value;
644
+ if (refresh) {
645
+ refreshSelects(this);
646
+ }
647
+ return this.element;
648
+ },
649
+ getContainer: function() {
650
+ return this.container;
651
+ },
652
+ refresh: function(mustClearSelections) {
653
+ updateSelectionStates(this);
654
+
655
+ if (!mustClearSelections) {
656
+ saveSelections(this, 1);
657
+ saveSelections(this, 2);
658
+ } else {
659
+ clearSelections(this);
660
+ }
661
+
662
+ refreshSelects(this);
663
+ },
664
+ destroy: function() {
665
+ this.container.remove();
666
+ this.element.show();
667
+ $.data(this, 'plugin_' + pluginName, null);
668
+ return this.element;
669
+ }
670
+ };
671
+
672
+ // A really lightweight plugin wrapper around the constructor,
673
+ // preventing against multiple instantiations
674
+ $.fn[ pluginName ] = function (options) {
675
+ var args = arguments;
676
+
677
+ // Is the first parameter an object (options), or was omitted, instantiate a new instance of the plugin.
678
+ if (options === undefined || typeof options === 'object') {
679
+ return this.each(function () {
680
+ // If this is not a select
681
+ if (!$(this).is('select')) {
682
+ $(this).find('select').each(function(index, item) {
683
+ // For each nested select, instantiate the Dual List Box
684
+ $(item).bootstrapDualListbox(options);
685
+ });
686
+ } else if (!$.data(this, 'plugin_' + pluginName)) {
687
+ // Only allow the plugin to be instantiated once so we check that the element has no plugin instantiation yet
688
+
689
+ // if it has no instance, create a new one, pass options to our plugin constructor,
690
+ // and store the plugin instance in the elements jQuery data object.
691
+ $.data(this, 'plugin_' + pluginName, new BootstrapDualListbox(this, options));
692
+ }
693
+ });
694
+ // If the first parameter is a string and it doesn't start with an underscore or "contains" the `init`-function,
695
+ // treat this as a call to a public method.
696
+ } else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
697
+
698
+ // Cache the method call to make it possible to return a value
699
+ var returns;
700
+
701
+ this.each(function () {
702
+ var instance = $.data(this, 'plugin_' + pluginName);
703
+ // Tests that there's already a plugin-instance and checks that the requested public method exists
704
+ if (instance instanceof BootstrapDualListbox && typeof instance[options] === 'function') {
705
+ // Call the method of our plugin instance, and pass it the supplied arguments.
706
+ returns = instance[options].apply(instance, Array.prototype.slice.call(args, 1));
707
+ }
708
+ });
709
+
710
+ // If the earlier cached method gives a value back return the value,
711
+ // otherwise return this to preserve chainability.
712
+ return returns !== undefined ? returns : this;
713
+ }
714
+
715
+ };
716
+
717
+ })(jQuery, window, document);
@@ -0,0 +1,86 @@
1
+ /*
2
+ * Bootstrap Duallistbox - v3.0.2
3
+ * A responsive dual listbox widget optimized for Twitter Bootstrap. It works on all modern browsers and on touch devices.
4
+ * http://www.virtuosoft.eu/code/bootstrap-duallistbox/
5
+ *
6
+ * Made by István Ujj-Mészáros
7
+ * Under Apache License v2.0 License
8
+ */
9
+ .bootstrap-duallistbox-container .buttons {
10
+ width: 100%;
11
+ margin-bottom: -1px;
12
+ }
13
+
14
+ .bootstrap-duallistbox-container label {
15
+ display: block;
16
+ }
17
+
18
+ .bootstrap-duallistbox-container .info {
19
+ display: inline-block;
20
+ margin-bottom: 5px;
21
+ font-size: 11px;
22
+ }
23
+
24
+ .bootstrap-duallistbox-container .clear1,
25
+ .bootstrap-duallistbox-container .clear2 {
26
+ display: none;
27
+ font-size: 10px;
28
+ }
29
+
30
+ .bootstrap-duallistbox-container .box1.filtered .clear1,
31
+ .bootstrap-duallistbox-container .box2.filtered .clear2 {
32
+ display: inline-block;
33
+ }
34
+
35
+ .bootstrap-duallistbox-container .move,
36
+ .bootstrap-duallistbox-container .remove {
37
+ width: 60%;
38
+ }
39
+
40
+ .bootstrap-duallistbox-container .btn-group .btn {
41
+ border-bottom-left-radius: 0;
42
+ border-bottom-right-radius: 0;
43
+ }
44
+ .bootstrap-duallistbox-container select {
45
+ border-top-left-radius: 0;
46
+ border-top-right-radius: 0;
47
+ }
48
+
49
+ .bootstrap-duallistbox-container .moveall,
50
+ .bootstrap-duallistbox-container .removeall {
51
+ width: 40%;
52
+ }
53
+
54
+ .bootstrap-duallistbox-container.bs2compatible .btn-group > .btn + .btn {
55
+ margin-left: 0;
56
+ }
57
+
58
+ .bootstrap-duallistbox-container select {
59
+ width: 100%;
60
+ height: 300px;
61
+ padding: 0;
62
+ }
63
+
64
+ .bootstrap-duallistbox-container .filter {
65
+ display: inline-block;
66
+ width: 100%;
67
+ height: 31px;
68
+ margin: 0 0 5px 0;
69
+ -webkit-box-sizing: border-box;
70
+ -moz-box-sizing: border-box;
71
+ box-sizing: border-box;
72
+ }
73
+
74
+ .bootstrap-duallistbox-container .filter.placeholder {
75
+ color: #aaa;
76
+ }
77
+
78
+ .bootstrap-duallistbox-container.moveonselect .move,
79
+ .bootstrap-duallistbox-container.moveonselect .remove {
80
+ display:none;
81
+ }
82
+
83
+ .bootstrap-duallistbox-container.moveonselect .moveall,
84
+ .bootstrap-duallistbox-container.moveonselect .removeall {
85
+ width: 100%;
86
+ }
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bootstrap-duallistbox-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 3.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Damien Dormal
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-06-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 4.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 4.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.8'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.8'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ description: assets for bootstrap-duallistbox
56
+ email:
57
+ - dormal.damien@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - Gemfile
64
+ - LICENSE.txt
65
+ - README.md
66
+ - Rakefile
67
+ - bin/console
68
+ - bin/setup
69
+ - bootstrap-duallistbox-rails.gemspec
70
+ - lib/bootstrap-duallistbox-rails.rb
71
+ - lib/bootstrap-duallistbox-rails/version.rb
72
+ - vendor/assets/javascripts/bootstrap-duallistbox.js
73
+ - vendor/assets/stylesheets/bootstrap-duallistbox.css
74
+ homepage: https://github.com/damsonn/bootstrap-duallistbox-rails
75
+ licenses:
76
+ - MIT
77
+ metadata: {}
78
+ post_install_message:
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ requirements: []
93
+ rubyforge_project:
94
+ rubygems_version: 2.4.6
95
+ signing_key:
96
+ specification_version: 4
97
+ summary: assets for bootstrap-duallistbox
98
+ test_files: []