jquery-selectric-rails 1.9.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +48 -0
- data/lib/jquery/selectric/rails.rb +11 -0
- data/lib/jquery/selectric/rails/version.rb +7 -0
- data/vendor/assets/javascripts/jquery.selectric.js +5 -0
- data/vendor/assets/javascripts/lib/jquery.selectric.js +538 -0
- data/vendor/assets/stylesheets/jquery.selectric.css +191 -0
- data/vendor/assets/stylesheets/jquery.selectric.css.scss +208 -0
- metadata +111 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 550481339156e1e8f2043e57f5207e7be844abf8
|
4
|
+
data.tar.gz: c9d9451249cbbba393119388261b2a261f568aa0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6874fdd45dc68f1eeb4c29afe4b4fadd9a40c0bcd4c0d3f985f75404766a8f9817c274c9424b7ea9314125143248f5297fe2918424e94ccaced2c814ad899aa8
|
7
|
+
data.tar.gz: dc9da3bb34206a0c48cbaec2cb3194b604cd27a723319ed4a9449b8a0f598a42ad12fa59c08c57a574bcc2afd6e6c829bf465ba9fd7223af06061f41ddb9fd9c
|
data/README.md
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# jQuery::Selectric::Rails
|
2
|
+
|
3
|
+
This gem provides [jQuery Selectric](https://github.com/lcdsantos/jQuery-Selectric) plugin for your Rails application.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'jquery-selectric-rails'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install jquery-selectric-rails
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
### Include the Redactor assets
|
22
|
+
|
23
|
+
Add to your `application.js`:
|
24
|
+
|
25
|
+
//= require jquery.selectric
|
26
|
+
|
27
|
+
Add to your `application.css`:
|
28
|
+
|
29
|
+
*= require jquery.selectric
|
30
|
+
|
31
|
+
|
32
|
+
Or if you are using SASS:
|
33
|
+
|
34
|
+
@import('jquery.selectric');
|
35
|
+
|
36
|
+
### Initialize
|
37
|
+
|
38
|
+
For each select that you want to apply jQuery Selectric, add the "selectric" class and ensure it has a unique ID:
|
39
|
+
|
40
|
+
<%= select_tag :my_select, options_for_select(['option1', 'option2']), class: "selectric" %>
|
41
|
+
|
42
|
+
## Contributing
|
43
|
+
|
44
|
+
1. Fork it
|
45
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
46
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
47
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
48
|
+
5. Create new Pull Request
|
@@ -0,0 +1,538 @@
|
|
1
|
+
;(function($) {
|
2
|
+
'use strict';
|
3
|
+
|
4
|
+
var pluginName = 'selectric',
|
5
|
+
classList = 'Input Items Open Disabled TempShow HideSelect Wrapper Hover Responsive Above Scroll Group GroupLabel',
|
6
|
+
bindSufix = '.sl',
|
7
|
+
defaults = {
|
8
|
+
onChange: function(elm) { $(elm).change(); },
|
9
|
+
maxHeight: 300,
|
10
|
+
keySearchTimeout: 500,
|
11
|
+
arrowButtonMarkup: '<b class="button">▾</b>',
|
12
|
+
disableOnMobile: true,
|
13
|
+
openOnHover: false,
|
14
|
+
hoverIntentTimeout: 500,
|
15
|
+
expandToItemText: false,
|
16
|
+
responsive: false,
|
17
|
+
preventWindowScroll: true,
|
18
|
+
inheritOriginalWidth: false,
|
19
|
+
allowWrap: true,
|
20
|
+
customClass: {
|
21
|
+
prefix: pluginName,
|
22
|
+
camelCase: false,
|
23
|
+
overwrite: true
|
24
|
+
},
|
25
|
+
optionsItemBuilder: '{text}', // function(itemData, element, index)
|
26
|
+
labelBuilder: '{text}' // function(currItem)
|
27
|
+
},
|
28
|
+
hooks = {
|
29
|
+
add: function(callbackName, hookName, fn) {
|
30
|
+
if ( !this[callbackName] )
|
31
|
+
this[callbackName] = {};
|
32
|
+
|
33
|
+
this[callbackName][hookName] = fn;
|
34
|
+
},
|
35
|
+
remove: function(callbackName, hookName) {
|
36
|
+
delete this[callbackName][hookName];
|
37
|
+
}
|
38
|
+
},
|
39
|
+
_utils = {
|
40
|
+
// Replace diacritics
|
41
|
+
replaceDiacritics: function(s) {
|
42
|
+
// /[\340-\346]/g, // a
|
43
|
+
// /[\350-\353]/g, // e
|
44
|
+
// /[\354-\357]/g, // i
|
45
|
+
// /[\362-\370]/g, // o
|
46
|
+
// /[\371-\374]/g, // u
|
47
|
+
// /[\361]/g, // n
|
48
|
+
// /[\347]/g, // c
|
49
|
+
// /[\377]/g // y
|
50
|
+
var d = '40-46 50-53 54-57 62-70 71-74 61 47 77'.replace(/\d+/g, '\\3$&').split(' '),
|
51
|
+
k = d.length;
|
52
|
+
|
53
|
+
while (k--)
|
54
|
+
s = s.toLowerCase().replace(RegExp('[' + d[k] + ']', 'g'), 'aeiouncy'.charAt(k));
|
55
|
+
|
56
|
+
return s;
|
57
|
+
},
|
58
|
+
// https://gist.github.com/atesgoral/984375
|
59
|
+
format: function(f) {var a=arguments;return(""+f).replace(/{(\d+|(\w+))}/g,function(s,i,p) {return p&&a[1]?a[1][p]:a[i]})},
|
60
|
+
nextEnabledItem: function(selectItems, selected) {
|
61
|
+
while ( selectItems[ selected = (selected + 1) % selectItems.length ].disabled ) {}
|
62
|
+
return selected;
|
63
|
+
},
|
64
|
+
previousEnabledItem: function(selectItems, selected) {
|
65
|
+
while ( selectItems[ selected = (selected > 0 ? selected : selectItems.length) - 1 ].disabled ) {}
|
66
|
+
return selected;
|
67
|
+
},
|
68
|
+
toDash: function(str) {
|
69
|
+
return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
|
70
|
+
},
|
71
|
+
triggerCallback: function(fn, scope) {
|
72
|
+
var elm = scope.element,
|
73
|
+
func = scope.options['on' + fn];
|
74
|
+
|
75
|
+
if ( $.isFunction(func) )
|
76
|
+
func.call(elm, elm, scope);
|
77
|
+
|
78
|
+
if ( hooks[fn] ) {
|
79
|
+
$.each(hooks[fn], function() {
|
80
|
+
this.call(elm, elm, scope);
|
81
|
+
});
|
82
|
+
}
|
83
|
+
|
84
|
+
$(elm).trigger(pluginName + '-' + _utils.toDash(fn), scope);
|
85
|
+
}
|
86
|
+
},
|
87
|
+
$doc = $(document),
|
88
|
+
$win = $(window),
|
89
|
+
Selectric = function(element, opts) {
|
90
|
+
var _this = this,
|
91
|
+
$original = $(element),
|
92
|
+
$input, $items, $itemsScroll, $wrapper, $label, $outerWrapper, $li,
|
93
|
+
isOpen = false,
|
94
|
+
isEnabled = false,
|
95
|
+
selected,
|
96
|
+
currValue,
|
97
|
+
itemsHeight,
|
98
|
+
itemsInnerHeight,
|
99
|
+
finalWidth,
|
100
|
+
optionsLength,
|
101
|
+
eventTriggers,
|
102
|
+
isMobile = /android|ip(hone|od|ad)/i.test(navigator.userAgent),
|
103
|
+
tabindex = $original.prop('tabindex'),
|
104
|
+
labelBuilder;
|
105
|
+
|
106
|
+
function _init(opts) {
|
107
|
+
_this.options = $.extend(true, {}, defaults, _this.options, opts);
|
108
|
+
_this.classes = {};
|
109
|
+
_this.element = element;
|
110
|
+
|
111
|
+
_utils.triggerCallback('BeforeInit', _this);
|
112
|
+
|
113
|
+
// Disable on mobile browsers
|
114
|
+
if ( _this.options.disableOnMobile && isMobile ) {
|
115
|
+
_this.disableOnMobile = true;
|
116
|
+
return;
|
117
|
+
}
|
118
|
+
|
119
|
+
// Preserve data
|
120
|
+
_destroy(true);
|
121
|
+
|
122
|
+
// Generate classNames for elements
|
123
|
+
var customClass = _this.options.customClass,
|
124
|
+
postfixes = classList.split(' '),
|
125
|
+
originalWidth = $original.width();
|
126
|
+
|
127
|
+
$.each(postfixes, function(i, currClass) {
|
128
|
+
var c = customClass.prefix + '-' + currClass;
|
129
|
+
_this.classes[currClass.toLowerCase()] = customClass.camelCase ? c : _utils.toDash(c);
|
130
|
+
});
|
131
|
+
|
132
|
+
$input = $('<input/>', { 'class': _this.classes.input, 'readonly': isMobile });
|
133
|
+
$items = $('<div/>', { 'class': _this.classes.items, 'tabindex': -1 });
|
134
|
+
$itemsScroll = $('<div/>', { 'class': _this.classes.scroll });
|
135
|
+
$wrapper = $('<div/>', { 'class': customClass.prefix, 'html': _this.options.arrowButtonMarkup });
|
136
|
+
$label = $('<p class="label"/>');
|
137
|
+
$outerWrapper = $original.wrap('<div>').parent().append($wrapper.prepend($label), $items, $input);
|
138
|
+
|
139
|
+
eventTriggers = {
|
140
|
+
open : _open,
|
141
|
+
close : _close,
|
142
|
+
destroy : _destroy,
|
143
|
+
refresh : _refresh,
|
144
|
+
init : _init
|
145
|
+
};
|
146
|
+
|
147
|
+
$original.on(eventTriggers).wrap('<div class="' + _this.classes.hideselect + '">');
|
148
|
+
$.extend(_this, eventTriggers);
|
149
|
+
|
150
|
+
labelBuilder = _this.options.labelBuilder;
|
151
|
+
|
152
|
+
if ( _this.options.inheritOriginalWidth && originalWidth > 0 )
|
153
|
+
$outerWrapper.width(originalWidth);
|
154
|
+
|
155
|
+
_populate();
|
156
|
+
}
|
157
|
+
|
158
|
+
// Generate options markup and event binds
|
159
|
+
function _populate() {
|
160
|
+
_this.items = [];
|
161
|
+
|
162
|
+
var $options = $original.children(),
|
163
|
+
_$li = '<ul>',
|
164
|
+
$justOptions = $original.find('option'),
|
165
|
+
selectedIndex = $justOptions.index($justOptions.filter(':selected')),
|
166
|
+
currIndex = 0;
|
167
|
+
|
168
|
+
currValue = (selected = ~selectedIndex ? selectedIndex : 0);
|
169
|
+
|
170
|
+
if ( optionsLength = $options.length ) {
|
171
|
+
// Build options markup
|
172
|
+
$options.each(function() {
|
173
|
+
var $elm = $(this);
|
174
|
+
|
175
|
+
if ( $elm.is('optgroup') ) {
|
176
|
+
var groupDisabled = $elm.prop('disabled'),
|
177
|
+
$children = $elm.children();
|
178
|
+
|
179
|
+
_$li += _utils.format('<ul class="{1}"><li class="{2}">{3}</li>',
|
180
|
+
$.trim([_this.classes.group, groupDisabled ? 'disabled' : '', $elm.prop('class')].join(' ')),
|
181
|
+
_this.classes.grouplabel,
|
182
|
+
$elm.prop('label')
|
183
|
+
);
|
184
|
+
|
185
|
+
if ( groupDisabled ) {
|
186
|
+
$children.prop('disabled', true);
|
187
|
+
}
|
188
|
+
|
189
|
+
$children.each(buildOption);
|
190
|
+
|
191
|
+
_$li += '</ul>';
|
192
|
+
} else {
|
193
|
+
buildOption.call($elm);
|
194
|
+
}
|
195
|
+
|
196
|
+
function buildOption() {
|
197
|
+
var $elm = $(this),
|
198
|
+
optionText = $elm.html(),
|
199
|
+
selectDisabled = $elm.prop('disabled'),
|
200
|
+
itemBuilder = _this.options.optionsItemBuilder;
|
201
|
+
|
202
|
+
_this.items[currIndex] = {
|
203
|
+
element : $elm,
|
204
|
+
value : $elm.val(),
|
205
|
+
text : optionText,
|
206
|
+
slug : _utils.replaceDiacritics(optionText),
|
207
|
+
disabled : selectDisabled
|
208
|
+
};
|
209
|
+
|
210
|
+
_$li += _utils.format('<li data-index="{1}" class="{2}">{3}</li>',
|
211
|
+
currIndex,
|
212
|
+
$.trim([currIndex == currValue ? 'selected' : '', currIndex == optionsLength - 1 ? 'last' : '', selectDisabled ? 'disabled' : ''].join(' ')),
|
213
|
+
$.isFunction(itemBuilder) ? itemBuilder(_this.items[currIndex], $elm, currIndex) : _utils.format(itemBuilder, _this.items[currIndex])
|
214
|
+
);
|
215
|
+
|
216
|
+
currIndex++;
|
217
|
+
}
|
218
|
+
});
|
219
|
+
|
220
|
+
$items.append( $itemsScroll.html(_$li + '</ul>') );
|
221
|
+
|
222
|
+
$label.html(
|
223
|
+
$.isFunction(labelBuilder) ? labelBuilder(_this.items[currValue]) : _utils.format(labelBuilder, _this.items[currValue])
|
224
|
+
)
|
225
|
+
}
|
226
|
+
|
227
|
+
$wrapper.add($original).add($outerWrapper).add($input).off(bindSufix);
|
228
|
+
|
229
|
+
$outerWrapper.prop('class', [
|
230
|
+
_this.classes.wrapper,
|
231
|
+
_this.options.customClass.overwrite ?
|
232
|
+
$original.prop('class').replace(/\S+/g, _this.options.customClass.prefix + '-$&') :
|
233
|
+
$original.prop('class'),
|
234
|
+
_this.options.responsive ? _this.classes.responsive : ''
|
235
|
+
].join(' '));
|
236
|
+
|
237
|
+
if ( !$original.prop('disabled') ) {
|
238
|
+
isEnabled = true;
|
239
|
+
|
240
|
+
// Not disabled, so... Removing disabled class and bind hover
|
241
|
+
$outerWrapper.removeClass(_this.classes.disabled).on('mouseenter' + bindSufix + ' mouseleave' + bindSufix, function(e) {
|
242
|
+
$(this).toggleClass(_this.classes.hover);
|
243
|
+
|
244
|
+
// Delay close effect when openOnHover is true
|
245
|
+
if ( _this.options.openOnHover ) {
|
246
|
+
clearTimeout(_this.closeTimer);
|
247
|
+
e.type == 'mouseleave' ? _this.closeTimer = setTimeout(_close, _this.options.hoverIntentTimeout) : _open();
|
248
|
+
}
|
249
|
+
});
|
250
|
+
|
251
|
+
// Toggle open/close
|
252
|
+
$wrapper.on('click' + bindSufix, function(e) {
|
253
|
+
isOpen ? _close() : _open(e);
|
254
|
+
});
|
255
|
+
|
256
|
+
$input
|
257
|
+
.prop({
|
258
|
+
tabindex: tabindex,
|
259
|
+
disabled: false
|
260
|
+
})
|
261
|
+
.on('keypress' + bindSufix, _handleSystemKeys)
|
262
|
+
.on('keydown' + bindSufix, function(e) {
|
263
|
+
_handleSystemKeys(e);
|
264
|
+
|
265
|
+
// Clear search
|
266
|
+
clearTimeout(_this.resetStr);
|
267
|
+
_this.resetStr = setTimeout(function() {
|
268
|
+
$input.val('');
|
269
|
+
}, _this.options.keySearchTimeout);
|
270
|
+
|
271
|
+
var key = e.keyCode || e.which;
|
272
|
+
|
273
|
+
// If it's a directional key
|
274
|
+
// 37 => Left
|
275
|
+
// 38 => Up
|
276
|
+
// 39 => Right
|
277
|
+
// 40 => Down
|
278
|
+
if ( key > 36 && key < 41 ) {
|
279
|
+
if ( !_this.options.allowWrap ) {
|
280
|
+
if ( (key < 39 && selected == 0) || (key > 38 && (selected + 1) == _this.items.length) ) {
|
281
|
+
return;
|
282
|
+
}
|
283
|
+
}
|
284
|
+
|
285
|
+
_select(_utils[(key < 39 ? 'previous' : 'next') + 'EnabledItem'](_this.items, selected));
|
286
|
+
}
|
287
|
+
})
|
288
|
+
.on('focusin' + bindSufix, function(e) {
|
289
|
+
// Stupid, but necessary... Prevent the flicker when
|
290
|
+
// focusing out and back again in the browser window
|
291
|
+
$input.one('blur', function() {
|
292
|
+
$input.blur();
|
293
|
+
});
|
294
|
+
|
295
|
+
isOpen || _open(e);
|
296
|
+
})
|
297
|
+
.on('oninput' in $input[0] ? 'input' : 'keyup', function() {
|
298
|
+
if ( $input.val().length ) {
|
299
|
+
// Search in select options
|
300
|
+
$.each(_this.items, function(i, elm) {
|
301
|
+
if ( RegExp('^' + $input.val(), 'i').test(elm.slug) && !elm.disabled ) {
|
302
|
+
_select(i);
|
303
|
+
return false;
|
304
|
+
}
|
305
|
+
});
|
306
|
+
}
|
307
|
+
});
|
308
|
+
|
309
|
+
$original.prop('tabindex', false);
|
310
|
+
|
311
|
+
// Remove styles from items box
|
312
|
+
// Fix incorrect height when refreshed is triggered with fewer options
|
313
|
+
$li = $('li', $items.removeAttr('style')).on({
|
314
|
+
// Prevent <input> blur on Chrome
|
315
|
+
mousedown: function(e) {
|
316
|
+
e.preventDefault();
|
317
|
+
e.stopPropagation();
|
318
|
+
},
|
319
|
+
click: function() {
|
320
|
+
// The second parameter is to close the box after click
|
321
|
+
_select($(this).data('index'), true);
|
322
|
+
|
323
|
+
// Chrome doesn't close options box if select is wrapped with a label
|
324
|
+
// We need to 'return false' to avoid that
|
325
|
+
return false;
|
326
|
+
}
|
327
|
+
}).filter('[data-index]');
|
328
|
+
} else {
|
329
|
+
$outerWrapper.addClass(_this.classes.disabled);
|
330
|
+
$input.prop('disabled', true);
|
331
|
+
}
|
332
|
+
|
333
|
+
_utils.triggerCallback('Init', _this);
|
334
|
+
}
|
335
|
+
|
336
|
+
function _refresh() {
|
337
|
+
_utils.triggerCallback('Refresh', _this);
|
338
|
+
_populate();
|
339
|
+
}
|
340
|
+
|
341
|
+
// Behavior when system keys is pressed
|
342
|
+
function _handleSystemKeys(e) {
|
343
|
+
var key = e.keyCode || e.which;
|
344
|
+
|
345
|
+
if ( key == 13 ) {
|
346
|
+
e.preventDefault();
|
347
|
+
}
|
348
|
+
|
349
|
+
// Tab / Enter / ESC
|
350
|
+
if ( /^(9|13|27)$/.test(key) ) {
|
351
|
+
e.stopPropagation();
|
352
|
+
_select(selected, true);
|
353
|
+
}
|
354
|
+
}
|
355
|
+
|
356
|
+
// Set options box width/height
|
357
|
+
function _calculateOptionsDimensions() {
|
358
|
+
// Calculate options box height
|
359
|
+
// Set a temporary class on the hidden parent of the element
|
360
|
+
var hiddenChildren = $items.closest(':visible').children(':hidden').addClass(_this.classes.tempshow),
|
361
|
+
maxHeight = _this.options.maxHeight,
|
362
|
+
itemsWidth = $items.outerWidth(),
|
363
|
+
wrapperWidth = $wrapper.outerWidth() - (itemsWidth - $items.width());
|
364
|
+
|
365
|
+
// Set the dimensions, minimum is wrapper width, expand for long items if option is true
|
366
|
+
if ( !_this.options.expandToItemText || wrapperWidth > itemsWidth )
|
367
|
+
finalWidth = wrapperWidth;
|
368
|
+
else {
|
369
|
+
// Make sure the scrollbar width is included
|
370
|
+
$items.css('overflow', 'scroll');
|
371
|
+
|
372
|
+
// Set a really long width for $outerWrapper
|
373
|
+
$outerWrapper.width(9e4);
|
374
|
+
finalWidth = $items.width();
|
375
|
+
// Set scroll bar to auto
|
376
|
+
$items.css('overflow', '');
|
377
|
+
$outerWrapper.width('');
|
378
|
+
}
|
379
|
+
|
380
|
+
$items.width(finalWidth).height() > maxHeight && $items.height(maxHeight);
|
381
|
+
|
382
|
+
// Remove the temporary class
|
383
|
+
hiddenChildren.removeClass(_this.classes.tempshow);
|
384
|
+
}
|
385
|
+
|
386
|
+
// Open the select options box
|
387
|
+
function _open(e) {
|
388
|
+
_utils.triggerCallback('BeforeOpen', _this);
|
389
|
+
|
390
|
+
if ( e ) {
|
391
|
+
e.preventDefault();
|
392
|
+
e.stopPropagation();
|
393
|
+
}
|
394
|
+
|
395
|
+
if ( isEnabled ) {
|
396
|
+
_calculateOptionsDimensions();
|
397
|
+
|
398
|
+
// Find any other opened instances of select and close it
|
399
|
+
$('.' + _this.classes.hideselect, '.' + _this.classes.open).children()[pluginName]('close');
|
400
|
+
|
401
|
+
isOpen = true;
|
402
|
+
itemsHeight = $items.outerHeight();
|
403
|
+
itemsInnerHeight = $items.height();
|
404
|
+
|
405
|
+
// Toggle options box visibility
|
406
|
+
$outerWrapper.addClass(_this.classes.open);
|
407
|
+
|
408
|
+
// Give dummy input focus
|
409
|
+
$input.val('').is(':focus') || $input.focus();
|
410
|
+
|
411
|
+
$doc.on('click' + bindSufix, _close).on('scroll' + bindSufix, _isInViewport);
|
412
|
+
_isInViewport();
|
413
|
+
|
414
|
+
// Prevent window scroll when using mouse wheel inside items box
|
415
|
+
if ( _this.options.preventWindowScroll ) {
|
416
|
+
$doc.on('mousewheel' + bindSufix + ' DOMMouseScroll' + bindSufix, '.' + _this.classes.scroll, function(e) {
|
417
|
+
var orgEvent = e.originalEvent,
|
418
|
+
scrollTop = $(this).scrollTop(),
|
419
|
+
deltaY = 0;
|
420
|
+
|
421
|
+
if ( 'detail' in orgEvent ) { deltaY = orgEvent.detail * -1; }
|
422
|
+
if ( 'wheelDelta' in orgEvent ) { deltaY = orgEvent.wheelDelta; }
|
423
|
+
if ( 'wheelDeltaY' in orgEvent ) { deltaY = orgEvent.wheelDeltaY; }
|
424
|
+
if ( 'deltaY' in orgEvent ) { deltaY = orgEvent.deltaY * -1; }
|
425
|
+
|
426
|
+
if ( scrollTop == (this.scrollHeight - itemsInnerHeight) && deltaY < 0 || scrollTop == 0 && deltaY > 0 ) {
|
427
|
+
e.preventDefault();
|
428
|
+
}
|
429
|
+
});
|
430
|
+
}
|
431
|
+
|
432
|
+
_detectItemVisibility(selected);
|
433
|
+
|
434
|
+
_utils.triggerCallback('Open', _this);
|
435
|
+
}
|
436
|
+
}
|
437
|
+
|
438
|
+
// Detect is the options box is inside the window
|
439
|
+
function _isInViewport() {
|
440
|
+
$outerWrapper.toggleClass(_this.classes.above, $outerWrapper.offset().top + $outerWrapper.outerHeight() + itemsHeight > $win.scrollTop() + $win.height());
|
441
|
+
}
|
442
|
+
|
443
|
+
// Close the select options box
|
444
|
+
function _close() {
|
445
|
+
_utils.triggerCallback('BeforeClose', _this);
|
446
|
+
|
447
|
+
if ( currValue != selected ) {
|
448
|
+
_utils.triggerCallback('BeforeChange', _this);
|
449
|
+
|
450
|
+
var text = _this.items[selected].text;
|
451
|
+
|
452
|
+
// Apply changed value to original select
|
453
|
+
$original
|
454
|
+
.prop('selectedIndex', currValue = selected)
|
455
|
+
.data('value', text);
|
456
|
+
|
457
|
+
// Change label text
|
458
|
+
$label.html(
|
459
|
+
$.isFunction(labelBuilder) ? labelBuilder(_this.items[selected]) : _utils.format(labelBuilder, _this.items[selected])
|
460
|
+
)
|
461
|
+
|
462
|
+
_utils.triggerCallback('Change', _this);
|
463
|
+
}
|
464
|
+
|
465
|
+
// Remove custom events on document
|
466
|
+
$doc.off(bindSufix);
|
467
|
+
|
468
|
+
// Remove visible class to hide options box
|
469
|
+
$outerWrapper.removeClass(_this.classes.open);
|
470
|
+
|
471
|
+
isOpen = false;
|
472
|
+
|
473
|
+
_utils.triggerCallback('Close', _this);
|
474
|
+
}
|
475
|
+
|
476
|
+
// Select option
|
477
|
+
function _select(index, close) {
|
478
|
+
// Parameter index is required
|
479
|
+
if ( index == undefined ) {
|
480
|
+
return;
|
481
|
+
}
|
482
|
+
|
483
|
+
// If element is disabled, can't select it
|
484
|
+
if ( !_this.items[index].disabled ) {
|
485
|
+
// If 'close' is false (default), the options box won't close after
|
486
|
+
// each selected item, this is necessary for keyboard navigation
|
487
|
+
$li
|
488
|
+
.removeClass('selected')
|
489
|
+
.eq(selected = index)
|
490
|
+
.addClass('selected');
|
491
|
+
|
492
|
+
_detectItemVisibility(index);
|
493
|
+
close && _close();
|
494
|
+
}
|
495
|
+
}
|
496
|
+
|
497
|
+
// Detect if currently selected option is visible and scroll the options box to show it
|
498
|
+
function _detectItemVisibility(index) {
|
499
|
+
var liHeight = $li.eq(index).outerHeight(),
|
500
|
+
liTop = $li[index].offsetTop,
|
501
|
+
itemsScrollTop = $itemsScroll.scrollTop(),
|
502
|
+
scrollT = liTop + liHeight * 2;
|
503
|
+
|
504
|
+
$itemsScroll.scrollTop(
|
505
|
+
scrollT > itemsScrollTop + itemsHeight ? scrollT - itemsHeight :
|
506
|
+
liTop - liHeight < itemsScrollTop ? liTop - liHeight :
|
507
|
+
itemsScrollTop
|
508
|
+
);
|
509
|
+
}
|
510
|
+
|
511
|
+
// Unbind and remove
|
512
|
+
function _destroy(preserveData) {
|
513
|
+
if ( isEnabled ) {
|
514
|
+
$items.add($wrapper).add($input).remove();
|
515
|
+
!preserveData && $original.removeData(pluginName).removeData('value');
|
516
|
+
$original.prop('tabindex', tabindex).off(bindSufix).off(eventTriggers).unwrap().unwrap();
|
517
|
+
isEnabled = false;
|
518
|
+
}
|
519
|
+
}
|
520
|
+
|
521
|
+
_init(opts);
|
522
|
+
};
|
523
|
+
|
524
|
+
// A really lightweight plugin wrapper around the constructor,
|
525
|
+
// preventing against multiple instantiations
|
526
|
+
$.fn[pluginName] = function(args) {
|
527
|
+
return this.each(function() {
|
528
|
+
var data = $.data(this, pluginName);
|
529
|
+
|
530
|
+
if ( data && !data.disableOnMobile )
|
531
|
+
(''+args === args && data[args]) ? data[args]() : data.init(args);
|
532
|
+
else
|
533
|
+
$.data(this, pluginName, new Selectric(this, args));
|
534
|
+
});
|
535
|
+
};
|
536
|
+
|
537
|
+
$.fn[pluginName].hooks = hooks;
|
538
|
+
}(jQuery));
|
@@ -0,0 +1,191 @@
|
|
1
|
+
/*======================================
|
2
|
+
Selectric v1.9.3
|
3
|
+
======================================*/
|
4
|
+
.selectric-wrapper {
|
5
|
+
position: relative;
|
6
|
+
cursor: pointer;
|
7
|
+
}
|
8
|
+
|
9
|
+
.selectric-responsive {
|
10
|
+
width: 100%;
|
11
|
+
}
|
12
|
+
|
13
|
+
.selectric {
|
14
|
+
border: 1px solid #DDD;
|
15
|
+
background: #F8F8F8;
|
16
|
+
position: relative;
|
17
|
+
}
|
18
|
+
.selectric .label {
|
19
|
+
display: block;
|
20
|
+
white-space: nowrap;
|
21
|
+
overflow: hidden;
|
22
|
+
text-overflow: ellipsis;
|
23
|
+
margin: 0 38px 0 10px;
|
24
|
+
font-size: 12px;
|
25
|
+
line-height: 38px;
|
26
|
+
color: #444;
|
27
|
+
height: 38px;
|
28
|
+
}
|
29
|
+
.selectric .button {
|
30
|
+
display: block;
|
31
|
+
position: absolute;
|
32
|
+
right: 0;
|
33
|
+
top: 0;
|
34
|
+
width: 38px;
|
35
|
+
height: 38px;
|
36
|
+
color: #BBB;
|
37
|
+
text-align: center;
|
38
|
+
font: 0/0 a;
|
39
|
+
*font: 20px/38px Lucida Sans Unicode, Arial Unicode MS, Arial;
|
40
|
+
}
|
41
|
+
.selectric .button:after {
|
42
|
+
content: " ";
|
43
|
+
position: absolute;
|
44
|
+
top: 0;
|
45
|
+
right: 0;
|
46
|
+
bottom: 0;
|
47
|
+
left: 0;
|
48
|
+
margin: auto;
|
49
|
+
width: 0;
|
50
|
+
height: 0;
|
51
|
+
border: 4px solid transparent;
|
52
|
+
border-top-color: #BBB;
|
53
|
+
border-bottom: none;
|
54
|
+
}
|
55
|
+
|
56
|
+
.selectric-hover .selectric {
|
57
|
+
border-color: #C4C4C4;
|
58
|
+
}
|
59
|
+
.selectric-hover .selectric .button {
|
60
|
+
color: #A2A2A2;
|
61
|
+
}
|
62
|
+
.selectric-hover .selectric .button:after {
|
63
|
+
border-top-color: #A2A2A2;
|
64
|
+
}
|
65
|
+
|
66
|
+
.selectric-open {
|
67
|
+
z-index: 9999;
|
68
|
+
}
|
69
|
+
.selectric-open .selectric {
|
70
|
+
border-color: #C4C4C4;
|
71
|
+
}
|
72
|
+
.selectric-open .selectric-items {
|
73
|
+
display: block;
|
74
|
+
}
|
75
|
+
|
76
|
+
.selectric-disabled {
|
77
|
+
filter: alpha(opacity=50);
|
78
|
+
opacity: 0.5;
|
79
|
+
cursor: default;
|
80
|
+
-webkit-user-select: none;
|
81
|
+
-moz-user-select: none;
|
82
|
+
-ms-user-select: none;
|
83
|
+
user-select: none;
|
84
|
+
}
|
85
|
+
|
86
|
+
.selectric-hide-select {
|
87
|
+
position: relative;
|
88
|
+
overflow: hidden;
|
89
|
+
width: 0;
|
90
|
+
height: 0;
|
91
|
+
}
|
92
|
+
.selectric-hide-select select {
|
93
|
+
position: absolute;
|
94
|
+
left: -100%;
|
95
|
+
display: none;
|
96
|
+
}
|
97
|
+
|
98
|
+
.selectric-input {
|
99
|
+
position: absolute !important;
|
100
|
+
top: 0 !important;
|
101
|
+
left: 0 !important;
|
102
|
+
overflow: hidden !important;
|
103
|
+
clip: rect(0, 0, 0, 0) !important;
|
104
|
+
margin: 0 !important;
|
105
|
+
padding: 0 !important;
|
106
|
+
width: 1px !important;
|
107
|
+
height: 1px !important;
|
108
|
+
outline: none !important;
|
109
|
+
border: none !important;
|
110
|
+
*font: 0/0 a !important;
|
111
|
+
background: none !important;
|
112
|
+
}
|
113
|
+
|
114
|
+
.selectric-temp-show {
|
115
|
+
position: absolute !important;
|
116
|
+
visibility: hidden !important;
|
117
|
+
display: block !important;
|
118
|
+
}
|
119
|
+
|
120
|
+
/* Items box */
|
121
|
+
.selectric-items {
|
122
|
+
display: none;
|
123
|
+
position: absolute;
|
124
|
+
top: 100%;
|
125
|
+
left: 0;
|
126
|
+
background: #F8F8F8;
|
127
|
+
border: 1px solid #C4C4C4;
|
128
|
+
z-index: -1;
|
129
|
+
box-shadow: 0 0 10px -6px;
|
130
|
+
}
|
131
|
+
.selectric-items .selectric-scroll {
|
132
|
+
height: 100%;
|
133
|
+
overflow: auto;
|
134
|
+
}
|
135
|
+
.selectric-above .selectric-items {
|
136
|
+
top: auto;
|
137
|
+
bottom: 100%;
|
138
|
+
}
|
139
|
+
.selectric-items ul, .selectric-items li {
|
140
|
+
list-style: none;
|
141
|
+
padding: 0;
|
142
|
+
margin: 0;
|
143
|
+
font-size: 12px;
|
144
|
+
line-height: 20px;
|
145
|
+
min-height: 20px;
|
146
|
+
}
|
147
|
+
.selectric-items li {
|
148
|
+
display: block;
|
149
|
+
padding: 8px;
|
150
|
+
border-top: 1px solid #FFF;
|
151
|
+
border-bottom: 1px solid #EEE;
|
152
|
+
color: #666;
|
153
|
+
cursor: pointer;
|
154
|
+
}
|
155
|
+
.selectric-items li.selected {
|
156
|
+
background: #EFEFEF;
|
157
|
+
color: #444;
|
158
|
+
}
|
159
|
+
.selectric-items li:hover {
|
160
|
+
background: #F0F0F0;
|
161
|
+
color: #444;
|
162
|
+
}
|
163
|
+
.selectric-items .disabled {
|
164
|
+
filter: alpha(opacity=50);
|
165
|
+
opacity: 0.5;
|
166
|
+
cursor: default !important;
|
167
|
+
background: none !important;
|
168
|
+
color: #666 !important;
|
169
|
+
-webkit-user-select: none;
|
170
|
+
-moz-user-select: none;
|
171
|
+
-ms-user-select: none;
|
172
|
+
user-select: none;
|
173
|
+
}
|
174
|
+
.selectric-items .selectric-group .selectric-group-label {
|
175
|
+
font-weight: bold;
|
176
|
+
padding-left: 10px;
|
177
|
+
cursor: default;
|
178
|
+
-webkit-user-select: none;
|
179
|
+
-moz-user-select: none;
|
180
|
+
-ms-user-select: none;
|
181
|
+
user-select: none;
|
182
|
+
background: none;
|
183
|
+
color: #444;
|
184
|
+
}
|
185
|
+
.selectric-items .selectric-group.disabled li {
|
186
|
+
filter: alpha(opacity=100);
|
187
|
+
opacity: 1;
|
188
|
+
}
|
189
|
+
.selectric-items .selectric-group li {
|
190
|
+
padding-left: 25px;
|
191
|
+
}
|
@@ -0,0 +1,208 @@
|
|
1
|
+
$main-color: #DDD;
|
2
|
+
$secondary-color: #BBB;
|
3
|
+
$bg-color: #F8F8F8;
|
4
|
+
$text-color: #444;
|
5
|
+
$height: 40px;
|
6
|
+
$spacing: 10px;
|
7
|
+
$border-width: 1px;
|
8
|
+
$inner-height: $height - ($border-width * 2);
|
9
|
+
|
10
|
+
.selectric-wrapper {
|
11
|
+
position: relative;
|
12
|
+
cursor: pointer;
|
13
|
+
}
|
14
|
+
|
15
|
+
.selectric-responsive {
|
16
|
+
width: 100%;
|
17
|
+
}
|
18
|
+
|
19
|
+
.selectric {
|
20
|
+
border: $border-width solid $main-color;
|
21
|
+
background: $bg-color;
|
22
|
+
position: relative;
|
23
|
+
|
24
|
+
.label {
|
25
|
+
display: block;
|
26
|
+
white-space: nowrap;
|
27
|
+
overflow: hidden;
|
28
|
+
text-overflow: ellipsis;
|
29
|
+
margin: 0 $inner-height 0 $spacing;
|
30
|
+
font-size: 12px;
|
31
|
+
line-height: $inner-height;
|
32
|
+
color: $text-color;
|
33
|
+
height: $inner-height;
|
34
|
+
}
|
35
|
+
|
36
|
+
.button {
|
37
|
+
display: block;
|
38
|
+
position: absolute;
|
39
|
+
right: 0;
|
40
|
+
top: 0;
|
41
|
+
width: $inner-height;
|
42
|
+
height: $inner-height;
|
43
|
+
color: $secondary-color;
|
44
|
+
text-align: center;
|
45
|
+
font: 0/0 a;
|
46
|
+
*font: 20px/#{$inner-height} Lucida Sans Unicode, Arial Unicode MS, Arial;
|
47
|
+
|
48
|
+
&:after {
|
49
|
+
content: " ";
|
50
|
+
position: absolute;
|
51
|
+
top: 0;
|
52
|
+
right: 0;
|
53
|
+
bottom: 0;
|
54
|
+
left: 0;
|
55
|
+
margin: auto;
|
56
|
+
width: 0;
|
57
|
+
height: 0;
|
58
|
+
border: 4px solid transparent;
|
59
|
+
border-top-color: $secondary-color;
|
60
|
+
border-bottom: none;
|
61
|
+
}
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
.selectric-hover .selectric {
|
66
|
+
border-color: darken($main-color, 10%);
|
67
|
+
|
68
|
+
.button {
|
69
|
+
color: darken($secondary-color, 10%);
|
70
|
+
|
71
|
+
&:after {
|
72
|
+
border-top-color: darken($secondary-color, 10%);
|
73
|
+
}
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
77
|
+
.selectric-open {
|
78
|
+
z-index: 9999;
|
79
|
+
|
80
|
+
.selectric {
|
81
|
+
border-color: darken($main-color, 10%);
|
82
|
+
}
|
83
|
+
|
84
|
+
.selectric-items {
|
85
|
+
display: block;
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
.selectric-disabled {
|
90
|
+
filter: alpha(opacity=50);
|
91
|
+
opacity: 0.5;
|
92
|
+
cursor: default;
|
93
|
+
user-select: none;
|
94
|
+
}
|
95
|
+
|
96
|
+
.selectric-hide-select {
|
97
|
+
position: relative;
|
98
|
+
overflow: hidden;
|
99
|
+
width: 0;
|
100
|
+
height: 0;
|
101
|
+
|
102
|
+
select {
|
103
|
+
position: absolute;
|
104
|
+
left: -100%;
|
105
|
+
display: none;
|
106
|
+
}
|
107
|
+
}
|
108
|
+
|
109
|
+
.selectric-input {
|
110
|
+
position: absolute !important;
|
111
|
+
top: 0 !important;
|
112
|
+
left: 0 !important;
|
113
|
+
overflow: hidden !important;
|
114
|
+
clip: rect(0, 0, 0, 0) !important;
|
115
|
+
margin: 0 !important;
|
116
|
+
padding: 0 !important;
|
117
|
+
width: 1px !important;
|
118
|
+
height: 1px !important;
|
119
|
+
outline: none !important;
|
120
|
+
border: none !important;
|
121
|
+
*font: 0/0 a !important;
|
122
|
+
background: none !important;
|
123
|
+
}
|
124
|
+
|
125
|
+
.selectric-temp-show {
|
126
|
+
position: absolute !important;
|
127
|
+
visibility: hidden !important;
|
128
|
+
display: block !important;
|
129
|
+
}
|
130
|
+
|
131
|
+
/* Items box */
|
132
|
+
.selectric-items {
|
133
|
+
display: none;
|
134
|
+
position: absolute;
|
135
|
+
top: 100%;
|
136
|
+
left: 0;
|
137
|
+
background: $bg-color;
|
138
|
+
border: 1px solid darken($main-color, 10%);
|
139
|
+
z-index: -1;
|
140
|
+
box-shadow: 0 0 10px -6px;
|
141
|
+
|
142
|
+
.selectric-scroll {
|
143
|
+
height: 100%;
|
144
|
+
overflow: auto;
|
145
|
+
}
|
146
|
+
|
147
|
+
.selectric-above & {
|
148
|
+
top: auto;
|
149
|
+
bottom: 100%;
|
150
|
+
}
|
151
|
+
|
152
|
+
ul, li {
|
153
|
+
list-style: none;
|
154
|
+
padding: 0;
|
155
|
+
margin: 0;
|
156
|
+
font-size: 12px;
|
157
|
+
line-height: 20px;
|
158
|
+
min-height: 20px;
|
159
|
+
}
|
160
|
+
|
161
|
+
li {
|
162
|
+
display: block;
|
163
|
+
padding: 8px;
|
164
|
+
border-top: 1px solid #FFF;
|
165
|
+
border-bottom: 1px solid #EEE;
|
166
|
+
color: #666;
|
167
|
+
cursor: pointer;
|
168
|
+
|
169
|
+
&.selected {
|
170
|
+
background: #EFEFEF;
|
171
|
+
color: #444;
|
172
|
+
}
|
173
|
+
|
174
|
+
&:hover {
|
175
|
+
background: #F0F0F0;
|
176
|
+
color: #444;
|
177
|
+
}
|
178
|
+
}
|
179
|
+
|
180
|
+
.disabled {
|
181
|
+
filter: alpha(opacity=50);
|
182
|
+
opacity: 0.5;
|
183
|
+
cursor: default !important;
|
184
|
+
background: none !important;
|
185
|
+
color: #666 !important;
|
186
|
+
user-select: none;
|
187
|
+
}
|
188
|
+
|
189
|
+
.selectric-group {
|
190
|
+
.selectric-group-label {
|
191
|
+
font-weight: bold;
|
192
|
+
padding-left: 10px;
|
193
|
+
cursor: default;
|
194
|
+
user-select: none;
|
195
|
+
background: none;
|
196
|
+
color: #444;
|
197
|
+
}
|
198
|
+
|
199
|
+
&.disabled li {
|
200
|
+
filter: alpha(opacity=100);
|
201
|
+
opacity: 1;
|
202
|
+
}
|
203
|
+
|
204
|
+
li {
|
205
|
+
padding-left: 25px;
|
206
|
+
}
|
207
|
+
}
|
208
|
+
}
|
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jquery-selectric-rails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.9.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Michael Johann
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-09-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.10'
|
20
|
+
- - ">"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '1.10'
|
23
|
+
type: :development
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.10'
|
30
|
+
- - ">"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '1.10'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: rake
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '10.4'
|
40
|
+
- - ">"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '10.4'
|
43
|
+
type: :development
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '10.4'
|
50
|
+
- - ">"
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '10.4'
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: railties
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - "~>"
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '3.2'
|
60
|
+
- - ">"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '3.2'
|
63
|
+
type: :runtime
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '3.2'
|
70
|
+
- - ">"
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '3.2'
|
73
|
+
description: This gem contains the jquery selectric plugin for Rails applications
|
74
|
+
email:
|
75
|
+
- mjohann@rails-experts.com
|
76
|
+
executables: []
|
77
|
+
extensions: []
|
78
|
+
extra_rdoc_files: []
|
79
|
+
files:
|
80
|
+
- README.md
|
81
|
+
- lib/jquery/selectric/rails.rb
|
82
|
+
- lib/jquery/selectric/rails/version.rb
|
83
|
+
- vendor/assets/javascripts/jquery.selectric.js
|
84
|
+
- vendor/assets/javascripts/lib/jquery.selectric.js
|
85
|
+
- vendor/assets/stylesheets/jquery.selectric.css
|
86
|
+
- vendor/assets/stylesheets/jquery.selectric.css.scss
|
87
|
+
homepage: https://github.com/malagant/jquery-selectric-rails
|
88
|
+
licenses:
|
89
|
+
- MIT
|
90
|
+
metadata: {}
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
requirements: []
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 2.4.5
|
108
|
+
signing_key:
|
109
|
+
specification_version: 4
|
110
|
+
summary: jQuery Selectric integrated into the asset pipeline
|
111
|
+
test_files: []
|