active_frontend 14.0.99 → 14.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 81d929bbda4bb03643b3f14d0b48b1bfa7185a7c
4
- data.tar.gz: a1f515f1c2608a3ec7b7693057b632e53034c162
3
+ metadata.gz: f57c9edde86486ff06bfd1b06a40ee8c37bb369e
4
+ data.tar.gz: 458fcea810df0496b760427523b2e1ddf12de5de
5
5
  SHA512:
6
- metadata.gz: a949db01af534d560057a6a2d0563ff539be89f411948938f9535fea216144e2a203fbff2159fcdc7c91de4279d1575bb5037209d8f1071ff568e8756e9e98f7
7
- data.tar.gz: 342a4d9a68ac7b28baa3e0ead15c3373c71b5e588713d17e9ba461724d99d4132f7481a7c4a576f35888b5db32c98ce89745a8ab94fc13c9cb69d6c9daa1bbe7
6
+ metadata.gz: dd62aead62296100fe505794f36fe0fee9b5be6f1eadb4c9b283e3a26900036cc1480d4fa5c2925ad289b0cb2479aad7c0afe4e188d2f11f25a414043c5eac25
7
+ data.tar.gz: bedb7761b4179de6a64f41f527a4c4239afdb6d832ded11013740f8148585ca9c789ec9190a1b514f71f3ea307402c96d22d02a553e9a2af881dd0017d70c7d8
@@ -1,3 +1,3 @@
1
1
  module ActiveFrontend
2
- VERSION = '14.0.99'.freeze
2
+ VERSION = '14.1.0'.freeze
3
3
  end
@@ -30,6 +30,7 @@
30
30
  //= require base/_selectpicker
31
31
  //= require base/_timepicker
32
32
  //= require base/_typeahead
33
+ //= require base/_tag
33
34
  //= require base/_timeago
34
35
  //= require base/_switch
35
36
  //= require base/_timezone
@@ -44,5 +45,6 @@
44
45
  //= require extensions/_copy
45
46
  //= require extensions/_funnel
46
47
  //= require extensions/_map
48
+ //= require extensions/_push
47
49
  //= require extensions/_wysiwyg
48
50
  //
@@ -46,6 +46,7 @@
46
46
  @import 'components/selectpicker';
47
47
  @import 'components/timepicker';
48
48
  @import 'components/typeahead';
49
+ @import 'components/tag';
49
50
  @import 'components/ad';
50
51
  @import 'components/label_and_badge';
51
52
  @import 'components/breadcrumb';
@@ -30,6 +30,7 @@
30
30
  //= require base/_selectpicker
31
31
  //= require base/_timepicker
32
32
  //= require base/_typeahead
33
+ //= require base/_tag
33
34
  //= require base/_timeago
34
35
  //= require base/_switch
35
36
  //= require base/_timezone
@@ -44,5 +45,6 @@
44
45
  //= require extensions/_copy
45
46
  //= require extensions/_funnel
46
47
  //= require extensions/_map
48
+ //= require extensions/_push
47
49
  //= require extensions/_wysiwyg
48
50
  //
@@ -0,0 +1,649 @@
1
+ +function ($) {
2
+ 'use strict';
3
+
4
+ // TAG CLASS DEFINITION
5
+ // ====================
6
+
7
+ var Tag = function (element, options) {
8
+ this.isInit = true;
9
+ this.itemsArray = [];
10
+ this.$element = $(element);
11
+ this.$element.hide();
12
+ this.isSelect = (element.tagName === 'SELECT');
13
+ this.multiple = (this.isSelect && element.hasAttribute('multiple'));
14
+ this.objectItems = options && options.itemValue;
15
+ this.placeholderText = element.hasAttribute('placeholder') ? this.$element.attr('placeholder') : '';
16
+ this.inputSize = Math.max(1, this.placeholderText.length);
17
+ this.$container = $('<div class="form-tags"></div>');
18
+ this.$input = $('<input type="text" placeholder="' + this.placeholderText + '"/>').appendTo(this.$container);
19
+ this.$element.before(this.$container);
20
+ this.build(options);
21
+ this.isInit = false;
22
+ };
23
+
24
+ Tag.VERSION = '1.0.0';
25
+ Tag.DEFAULTS = {
26
+ itemText: function(item) {
27
+ return this.itemValue(item);
28
+ },
29
+ itemTitle: function(item) {
30
+ return null;
31
+ },
32
+ itemValue: function(item) {
33
+ return item ? item.toString() : item;
34
+ },
35
+ onTagExists: function(item, $tag) {},
36
+ tagClass: function(item) {
37
+ return 'label';
38
+ },
39
+ addOnBlur: true,
40
+ allowDuplicates: false,
41
+ cancelConfirmKeysOnEmpty: false,
42
+ confirmKeys: [13, 44],
43
+ delimiter: ',',
44
+ delimiterRegex: null,
45
+ focusClass: 'focus',
46
+ freeInput: true,
47
+ maxChars: undefined,
48
+ maxTags: undefined,
49
+ triggerChange: true,
50
+ trimValue: true
51
+ };
52
+
53
+ Tag.prototype.constructor = Tag;
54
+
55
+ Tag.prototype.stopTimer = function () {
56
+ return clearTimeout(this.interval);
57
+ };
58
+
59
+ Tag.prototype.getHtmlAttributes = function (item) {
60
+ if (this.options.itemAttributes === undefined) return '';
61
+
62
+ var res = ' ';
63
+ var itemAttributes = this.options.itemAttributes;
64
+
65
+ for (var e in itemAttributes) {
66
+ if (typeof itemAttributes[e] !== 'function') {
67
+ res += e + '="' + itemAttributes[e].toString() + '"';
68
+ } else {
69
+ res += e + '="' + itemAttributes[e](item) + '"';
70
+ }
71
+ }
72
+
73
+ return res;
74
+ };
75
+
76
+ Tag.prototype.add = function(item, dontPushVal, options) {
77
+ var _self = this;
78
+
79
+ if (_self.options.maxTags && _self.itemsArray.length >= _self.options.maxTags) return;
80
+ if (item !== false && !item) return;
81
+
82
+ if (typeof item === "string" && _self.options.trimValue) {
83
+ item = $.trim(item);
84
+ }
85
+
86
+ if (typeof item === 'object' && !_self.objectItems) throw("Can't add objects when itemValue option is not set");
87
+ if (item.toString().match(/^\s*$/)) return;
88
+ if (_self.isSelect && !_self.multiple && _self.itemsArray.length > 0) _self.remove(_self.itemsArray[0]);
89
+
90
+ if (typeof item === 'string' && this.$element[0].tagName === 'INPUT') {
91
+ var delimiter = (_self.options.delimiterRegex) ? _self.options.delimiterRegex : _self.options.delimiter;
92
+ var items = item.split(delimiter);
93
+
94
+ if (items.length > 1) {
95
+ for (var i = 0; i < items.length; i++) {
96
+ this.add(items[i], true);
97
+ }
98
+
99
+ if (!dontPushVal) _self.pushVal(_self.options.triggerChange);
100
+
101
+ return;
102
+ }
103
+ }
104
+
105
+ var itemValue = _self.options.itemValue(item);
106
+ var itemText = _self.options.itemText(item);
107
+ var tagClass = _self.options.tagClass(item);
108
+ var itemTitle = _self.options.itemTitle(item);
109
+
110
+ var existing = $.grep(_self.itemsArray, function(item) {
111
+ return _self.options.itemValue(item) === itemValue;
112
+ })[0];
113
+
114
+ if (existing && !_self.options.allowDuplicates) {
115
+ if (_self.options.onTagExists) {
116
+ var $existingTag = $('.tag', _self.$container).filter(function () {
117
+ return $(this).data('item') === existing;
118
+ });
119
+
120
+ _self.options.onTagExists(item, $existingTag);
121
+ }
122
+
123
+ return;
124
+ }
125
+
126
+ if (_self.items().toString().length + item.length + 1 > _self.options.maxInputLength) return;
127
+
128
+ var beforeItemAddEvent = $.Event('beforeItemAdd', {
129
+ item: item,
130
+ cancel: false,
131
+ options: options
132
+ });
133
+
134
+ _self.$element.trigger(beforeItemAddEvent);
135
+
136
+ if (beforeItemAddEvent.cancel) return;
137
+
138
+ _self.itemsArray.push(item);
139
+
140
+ var attrs = _self.getHtmlAttributes(item);
141
+ var $tag = $('<span ' +
142
+ _self.htmlEncode(attrs) +
143
+ ' class="tag ' +
144
+ _self.htmlEncode(tagClass) +
145
+ (itemTitle !== null ? ('" title="' + itemTitle) : '') +
146
+ '">' +
147
+ _self.htmlEncode(itemText) +
148
+ '<span data-role="remove"></span></span>');
149
+
150
+ $tag.data('item', item);
151
+
152
+ _self.findInputWrapper()
153
+ .before($tag);
154
+
155
+ $tag.after(' ');
156
+
157
+ var optionExists = (
158
+ $('option[value="' + encodeURIComponent(itemValue) + '"]', _self.$element).length ||
159
+ $('option[value="' + _self.htmlEncode(itemValue) + '"]', _self.$element).length
160
+ );
161
+
162
+ if (_self.isSelect && !optionExists) {
163
+ var $option = $('<option selected>' + _self.htmlEncode(itemText) + '</option>');
164
+
165
+ $option.data('item', item)
166
+ .attr('value', itemValue);
167
+ _self.$element.append($option);
168
+ }
169
+
170
+ if (!dontPushVal) _self.pushVal(_self.options.triggerChange);
171
+
172
+ if (_self.options.maxTags === _self.itemsArray.length || _self.items().toString().length === _self.options.maxInputLength) {
173
+ _self.$container
174
+ .addClass('form-tags-max');
175
+ }
176
+
177
+ if ($('.typeahead', _self.$container).length) {
178
+ setTimeout(function () {
179
+ _self.$input.val('');
180
+ }, 0);
181
+ }
182
+
183
+ if (this.isInit) {
184
+ _self.$element.trigger($.Event('itemAddedOnInit', {
185
+ item: item,
186
+ options: options
187
+ }));
188
+ } else {
189
+ _self.$element.trigger($.Event('itemAdded', {
190
+ item: item,
191
+ options: options
192
+ }));
193
+ }
194
+ };
195
+
196
+ Tag.prototype.remove = function(item, dontPushVal, options) {
197
+ var _self = this;
198
+
199
+ if (_self.objectItems) {
200
+ if (typeof item === 'object') {
201
+ item = $.grep(_self.itemsArray, function (other) {
202
+ return _self.options.itemValue(other) === _self.options.itemValue(item);
203
+ });
204
+ } else {
205
+ item = $.grep(_self.itemsArray, function (other) {
206
+ return _self.options.itemValue(other) === item;
207
+ });
208
+ }
209
+
210
+ item = item[item.length-1];
211
+ }
212
+
213
+ if (item) {
214
+ var beforeItemRemoveEvent = $.Event('beforeItemRemove', {
215
+ item: item,
216
+ cancel: false,
217
+ options: options
218
+ });
219
+
220
+ _self.$element.trigger(beforeItemRemoveEvent);
221
+
222
+ if (beforeItemRemoveEvent.cancel) return;
223
+
224
+ $('.tag', _self.$container).filter(function () {
225
+ return $(this).data('item') === item;
226
+ }).remove();
227
+ $('option', _self.$element).filter(function () {
228
+ return $(this).data('item') === item;
229
+ }).remove();
230
+
231
+ if ($.inArray(item, _self.itemsArray) !== -1) _self.itemsArray.splice($.inArray(item, _self.itemsArray), 1);
232
+ }
233
+
234
+ if (!dontPushVal) _self.pushVal(_self.options.triggerChange);
235
+
236
+ if (_self.options.maxTags > _self.itemsArray.length) _self.$container.removeClass('form-tags-max');
237
+
238
+ _self.$element
239
+ .trigger($.Event('itemRemoved', {
240
+ item: item,
241
+ options: options
242
+ }));
243
+ };
244
+
245
+ Tag.prototype.removeAll = function() {
246
+ $('.tag', this.$container).remove();
247
+ $('option', this.$element).remove();
248
+
249
+ while(this.itemsArray.length > 0) this.itemsArray.pop();
250
+
251
+ this.pushVal(this.options.triggerChange);
252
+ };
253
+
254
+ Tag.prototype.refresh = function() {
255
+ var _self = this;
256
+
257
+ $('.tag', _self.$container).each(function() {
258
+ var $tag = $(this);
259
+ var item = $tag.data('item');
260
+ var itemValue = _self.options.itemValue(item);
261
+ var itemText = _self.options.itemText(item);
262
+ var tagClass = _self.options.tagClass(item);
263
+
264
+ $tag.attr('class', null);
265
+ $tag.addClass('tag ' + _self.htmlEncode(tagClass));
266
+ $tag.contents()
267
+ .filter(function () {
268
+ return this.nodeType == 3;
269
+ })[0].nodeValue = _self.htmlEncode(itemText);
270
+
271
+ if (_self.isSelect) {
272
+ var option = $('option', _self.$element).filter(function () {
273
+ return $(this).data('item') === item;
274
+ });
275
+
276
+ option.attr('value', itemValue);
277
+ }
278
+ });
279
+ };
280
+
281
+ Tag.prototype.items = function() {
282
+ return this.itemsArray;
283
+ };
284
+
285
+ Tag.prototype.pushVal = function() {
286
+ var _self = this;
287
+ var val = $.map(_self.items(), function (item) {
288
+ return _self.options.itemValue(item).toString();
289
+ });
290
+
291
+ _self.$element.val(val, true);
292
+
293
+ if (_self.options.triggerChange) _self.$element.trigger('change');
294
+ };
295
+
296
+ Tag.prototype.build = function(options) {
297
+ var _self = this;
298
+
299
+ _self.options = $.extend({}, Tag.DEFAULTS, options);
300
+
301
+ if (_self.objectItems) _self.options.freeInput = false;
302
+
303
+ _self.makeOptionItemFunction(_self.options, 'itemValue');
304
+ _self.makeOptionItemFunction(_self.options, 'itemText');
305
+ _self.makeOptionFunction(_self.options, 'tagClass');
306
+
307
+ if (_self.$element.data('source') || _self.options.typeahead) {
308
+ var typeahead = _self.$element.data('source');
309
+
310
+ if (typeahead === undefined) {
311
+ typeahead = _self.options.typeahead || {};
312
+ } else {
313
+ typeahead = { source: typeahead };
314
+ }
315
+
316
+ _self.makeOptionFunction(typeahead, 'source');
317
+
318
+ _self.$input.typeahead($.extend({}, typeahead, {
319
+ source: function (query, process) {
320
+ function processItems(items) {
321
+ var texts = [];
322
+
323
+ for (var i = 0; i < items.length; i++) {
324
+ var text = _self.options.itemText(items[i]);
325
+ map[text] = items[i];
326
+ texts.push(text);
327
+ }
328
+ process(texts);
329
+ }
330
+
331
+ this.map = {};
332
+ var map = this.map;
333
+ var data = typeahead.source(query);
334
+
335
+ $.when(data).then(processItems);
336
+ },
337
+ updater: function (text) {
338
+ _self.add(this.map[text]);
339
+ return this.map[text];
340
+ },
341
+ matcher: function (text) {
342
+ return (text.toLowerCase().indexOf(this.query.trim().toLowerCase()) !== -1);
343
+ },
344
+ sorter: function (texts) {
345
+ return texts.sort();
346
+ },
347
+ highlighter: function (text) {
348
+ var i = text.indexOf('<small');
349
+ var old = '';
350
+
351
+ if (i > 0) {
352
+ old = text.substring(i, text.length);
353
+ text = text.substring(0, i - 1);
354
+ }
355
+
356
+ var regex = new RegExp('(' + this.query + ')', 'gi');
357
+ return text.replace(regex, '<strong>$1</strong>') + old;
358
+ }
359
+ }));
360
+ }
361
+
362
+ _self.$container.on('click', $.proxy(function(event) {
363
+ if (! _self.$element.attr('disabled')) _self.$input.removeAttr('disabled');
364
+
365
+ _self.$input.focus();
366
+ }, _self));
367
+
368
+ if (_self.options.addOnBlur && _self.options.freeInput) {
369
+ _self.$input.on('focusout', $.proxy(function(event) {
370
+ if ($('.typeahead', _self.$container).length === 0) {
371
+ _self.add(_self.$input.val());
372
+ _self.$input.val('');
373
+ }
374
+ }, _self));
375
+ }
376
+
377
+ _self.$container.on({
378
+ focusin: function() {
379
+ _self.$container.addClass(_self.options.focusClass);
380
+ },
381
+ focusout: function() {
382
+ _self.$container.removeClass(_self.options.focusClass);
383
+ },
384
+ });
385
+
386
+ _self.$container.on('keydown input', 'input', $.proxy(function(event) {
387
+ var $input = $(event.target);
388
+ var $inputWrapper = _self.findInputWrapper();
389
+
390
+ if (_self.$element.attr('disabled')) {
391
+ _self.$input.attr('disabled', 'disabled');
392
+ return;
393
+ }
394
+
395
+ switch (event.which) {
396
+ case 8:
397
+ if (_self.doGetCaretPosition($input[0]) === 0) {
398
+ var prev = $inputWrapper.prev();
399
+
400
+ if (prev.length) _self.remove(prev.data('item'));
401
+ }
402
+ break;
403
+ case 46:
404
+ if (_self.doGetCaretPosition($input[0]) === 0) {
405
+ var next = $inputWrapper.next();
406
+
407
+ if (next.length) _self.remove(next.data('item'));
408
+ }
409
+ break;
410
+ case 37:
411
+ var $prevTag = $inputWrapper.prev();
412
+
413
+ if ($input.val().length === 0 && $prevTag[0]) {
414
+ $prevTag.before($inputWrapper);
415
+ $input.focus();
416
+ }
417
+ break;
418
+ case 39:
419
+ var $nextTag = $inputWrapper.next();
420
+
421
+ if ($input.val().length === 0 && $nextTag[0]) {
422
+ $nextTag.after($inputWrapper);
423
+ $input.focus();
424
+ }
425
+ break;
426
+ default:
427
+ // ignore
428
+ }
429
+
430
+ var textLength = $input.val().length;
431
+ var wordSpace = Math.ceil(textLength / 5);
432
+ var size = textLength + wordSpace + 1;
433
+
434
+ $input.attr('size', Math.max(this.inputSize, $input.val().length));
435
+ }, _self));
436
+
437
+ _self.$container.on('keypress', 'input', $.proxy(function(event) {
438
+ var $input = $(event.target);
439
+
440
+ if (_self.$element.attr('disabled')) {
441
+ _self.$input.attr('disabled', 'disabled');
442
+ return;
443
+ }
444
+
445
+ var text = $input.val();
446
+ var maxLengthReached = _self.options.maxChars && text.length >= _self.options.maxChars;
447
+
448
+ if (_self.options.freeInput && (_self.keyCombinationInList(event, _self.options.confirmKeys) || maxLengthReached)) {
449
+ if (text.length !== 0) {
450
+ _self.add(maxLengthReached ? text.substr(0, _self.options.maxChars) : text);
451
+ $input.val('');
452
+ }
453
+
454
+ if (_self.options.cancelConfirmKeysOnEmpty === false) event.preventDefault();
455
+ }
456
+
457
+ var textLength = $input.val().length;
458
+ var wordSpace = Math.ceil(textLength / 5);
459
+ var size = textLength + wordSpace + 1;
460
+
461
+ $input.attr('size', Math.max(this.inputSize, $input.val().length));
462
+ }, _self));
463
+
464
+ _self.$container.on('click', '[data-role=remove]', $.proxy(function(event) {
465
+ if (_self.$element.attr('disabled')) return;
466
+
467
+ _self.remove($(event.target).closest('.tag').data('item'));
468
+ }, _self));
469
+
470
+ if (_self.options.itemValue === Tag.DEFAULTS.itemValue) {
471
+ if (_self.$element[0].tagName === 'INPUT') {
472
+ _self.add(_self.$element.val());
473
+ } else {
474
+ $('option', _self.$element).each(function() {
475
+ _self.add($(this).attr('value'), true);
476
+ });
477
+ }
478
+ }
479
+ };
480
+
481
+ Tag.prototype.destroy = function() {
482
+ var _self = this;
483
+
484
+ this.$container
485
+ .off('keypress', 'input')
486
+ .off('click', '[role=remove]')
487
+ .remove();
488
+
489
+ this.$element
490
+ .removeData('tagsinput')
491
+ .show();
492
+ };
493
+
494
+ Tag.prototype.focus = function() {
495
+ this.$input.focus();
496
+ };
497
+
498
+ Tag.prototype.input = function() {
499
+ return this.$input;
500
+ };
501
+
502
+ Tag.prototype.findInputWrapper = function() {
503
+ var elt = this.$input[0];
504
+ var container = this.$container[0];
505
+
506
+ while (elt && elt.parentNode !== container) {
507
+ elt = elt.parentNode;
508
+ }
509
+
510
+ return $(elt);
511
+ };
512
+
513
+ Tag.prototype.makeOptionItemFunction = function (options, key) {
514
+ if (typeof options[key] !== 'function') {
515
+ var propertyName = options[key];
516
+
517
+ options[key] = function(item) {
518
+ return item[propertyName];
519
+ };
520
+ }
521
+ };
522
+
523
+ Tag.prototype.makeOptionFunction = function (options, key) {
524
+ if (typeof options[key] !== 'function') {
525
+ var value = options[key];
526
+
527
+ options[key] = function() {
528
+ return value;
529
+ };
530
+ }
531
+ };
532
+
533
+ Tag.prototype.doGetCaretPosition = function (oField) {
534
+ var iCaretPos = 0;
535
+
536
+ if (document.selection) {
537
+ oField.focus ();
538
+
539
+ var oSel = document.selection.createRange();
540
+
541
+ oSel.moveStart('character', -oField.value.length);
542
+
543
+ iCaretPos = oSel.text.length;
544
+ } else if (oField.selectionStart || oField.selectionStart == '0') {
545
+ iCaretPos = oField.selectionStart;
546
+ }
547
+
548
+ return (iCaretPos);
549
+ };
550
+
551
+ Tag.prototype.keyCombinationInList = function (keyPressEvent, lookupList) {
552
+ var found = false;
553
+
554
+ $.each(lookupList, function (index, keyCombination) {
555
+ if (typeof (keyCombination) === 'number' && keyPressEvent.which === keyCombination) {
556
+ found = true;
557
+ return false;
558
+ }
559
+
560
+ if (keyPressEvent.which === keyCombination.which) {
561
+ var alt = !keyCombination.hasOwnProperty('altKey') || keyPressEvent.altKey === keyCombination.altKey;
562
+ var shift = !keyCombination.hasOwnProperty('shiftKey') || keyPressEvent.shiftKey === keyCombination.shiftKey;
563
+ var ctrl = !keyCombination.hasOwnProperty('ctrlKey') || keyPressEvent.ctrlKey === keyCombination.ctrlKey;
564
+
565
+ if (alt && shift && ctrl) {
566
+ found = true;
567
+ return false;
568
+ }
569
+ }
570
+ });
571
+
572
+ return found;
573
+ };
574
+
575
+ Tag.prototype.htmlEncode = function (value) {
576
+ if (value) {
577
+ return $('<div />').text(value).html();
578
+ } else {
579
+ return '';
580
+ }
581
+ };
582
+
583
+ // TAG PLUGIN DEFINITION
584
+ // =====================
585
+
586
+ function Plugin(arg1, arg2, arg3) {
587
+ var results = [];
588
+
589
+ this.each(function () {
590
+ var _self = $(this);
591
+ var tagsinput = _self.data('tagsinput');
592
+
593
+ if (!tagsinput) {
594
+ tagsinput = new Tag(this, arg1);
595
+
596
+ _self.data('tagsinput', tagsinput);
597
+
598
+ results.push(tagsinput);
599
+
600
+ if (this.tagName === 'SELECT') $('option', _self).attr('selected', 'selected');
601
+
602
+ _self.val(_self.val());
603
+ } else if (!arg1 && !arg2) {
604
+ results.push(tagsinput);
605
+ } else if (tagsinput[arg1] !== undefined) {
606
+ var retVal;
607
+
608
+ if (tagsinput[arg1].length === 3 && arg3 !== undefined){
609
+ retVal = tagsinput[arg1](arg2, null, arg3);
610
+ } else {
611
+ retVal = tagsinput[arg1](arg2);
612
+ }
613
+
614
+ if (retVal !== undefined) results.push(retVal);
615
+ }
616
+ });
617
+
618
+ if (typeof arg1 === 'string') {
619
+ return results.length > 1 ? results : results[0];
620
+ } else {
621
+ return results;
622
+ }
623
+ }
624
+
625
+ var old = $.fn.tag;
626
+
627
+ $.fn.tag = Plugin;
628
+ $.fn.tag.Constructor = Tag;
629
+
630
+ // TAG NO CONFLICT
631
+ // ===============
632
+
633
+ $.fn.tag.noConflict = function () {
634
+ $.fn.tag = old;
635
+ return this;
636
+ };
637
+
638
+ // TAG DATA-API
639
+ // ============
640
+
641
+ $(document).on('ready.bs.tag.data-api', function () {
642
+ $('[data-toggle="tag"]').each(function () {
643
+ var $this = $(this);
644
+ if ($this.data('tag')) return;
645
+ Plugin.call($this, $this.data());
646
+ });
647
+ });
648
+
649
+ }(jQuery);
@@ -0,0 +1,372 @@
1
+ (function (global, factory) {
2
+ 'use strict';
3
+
4
+ if (typeof define === 'function' && define.amd) {
5
+ define(function () {
6
+ return new (factory(global, global.document))();
7
+ });
8
+ } else if (typeof module !== 'undefined' && module.exports) {
9
+ module.exports = new (factory(global, global.document))();
10
+ } else {
11
+ global.Push = new (factory(global, global.document))();
12
+ }
13
+ })(typeof window !== 'undefined' ? window : this, function (w, d) {
14
+ var Push = function () {
15
+ var
16
+ self = this,
17
+ isUndefined = function (obj) { return obj === undefined; },
18
+ isString = function (obj) { return typeof obj === 'string'; },
19
+ isFunction = function (obj) { return obj && {}.toString.call(obj) === '[object Function]'; },
20
+ currentId = 0,
21
+ incompatibilityErrorMessage = 'PushError: push.js is incompatible with browser.',
22
+ notifications = {},
23
+ lastWorkerPath = null,
24
+
25
+ closeNotification = function (id) {
26
+ var errored = false;
27
+ var notification = notifications[id];
28
+
29
+ if (typeof notification !== 'undefined') {
30
+ if (notification.close) {
31
+ notification.close();
32
+ } else if (notification.cancel) {
33
+ notification.cancel();
34
+ } else if (w.external && w.external.msIsSiteMode) {
35
+ w.external.msSiteModeClearIconOverlay();
36
+ } else {
37
+ errored = true;
38
+ throw new Error('Unable to close notification: unknown interface');
39
+ }
40
+
41
+ if (!errored) return removeNotification(id);
42
+ }
43
+
44
+ return false;
45
+ },
46
+
47
+ addNotification = function (notification) {
48
+ var id = currentId;
49
+
50
+ notifications[id] = notification;
51
+ currentId++;
52
+
53
+ return id;
54
+ },
55
+
56
+ removeNotification = function (id) {
57
+ var dict = {};
58
+ var success = false;
59
+ var key;
60
+
61
+ for (key in notifications) {
62
+ if (notifications.hasOwnProperty(key)) {
63
+ if (key != id) {
64
+ dict[key] = notifications[key];
65
+ } else {
66
+ success = true;
67
+ }
68
+ }
69
+ }
70
+
71
+ notifications = dict;
72
+
73
+ return success;
74
+ },
75
+
76
+ prepareNotification = function (id, options) {
77
+ var wrapper;
78
+
79
+ wrapper = {
80
+ get: function () {
81
+ return notifications[id];
82
+ },
83
+ close: function () {
84
+ closeNotification(id);
85
+ }
86
+ };
87
+
88
+ if (options.timeout) {
89
+ setTimeout(function () {
90
+ wrapper.close();
91
+ }, options.timeout);
92
+ }
93
+
94
+ return wrapper;
95
+ },
96
+
97
+ createCallback = function (title, options, resolve) {
98
+ var notification;
99
+ var onClose;
100
+
101
+ options = options || {};
102
+
103
+ self.lastWorkerPath = options.serviceWorker || 'serviceWorker.js';
104
+
105
+ onClose = function (id) {
106
+ removeNotification(id);
107
+
108
+ if (isFunction(options.onClose)) {
109
+ options.onClose.call(this, notification);
110
+ }
111
+ };
112
+
113
+ if (w.Notification) {
114
+ try {
115
+ notification = new w.Notification(title, {
116
+ icon: (isString(options.icon) || isUndefined(options.icon)) ? options.icon : options.icon.x32,
117
+ body: options.body,
118
+ tag: options.tag,
119
+ requireInteraction: options.requireInteraction,
120
+ silent: options.silent
121
+ });
122
+ } catch (e) {
123
+ if (w.navigator) {
124
+ w.navigator.serviceWorker.register(self.lastWorkerPath);
125
+ w.navigator.serviceWorker.ready.then(function (registration) {
126
+ var localData = {
127
+ id: currentId,
128
+ link: options.link,
129
+ origin: document.location.href,
130
+ onClick: (isFunction(options.onClick)) ? options.onClick.toString() : '',
131
+ onClose: (isFunction(options.onClose)) ? options.onClose.toString() : ''
132
+ };
133
+
134
+ if (typeof options.data !== 'undefined' && options.data !== null) {
135
+ localData = Object.assign(localData, options.data);
136
+ }
137
+
138
+ registration.showNotification(title, {
139
+ icon: options.icon,
140
+ body: options.body,
141
+ vibrate: options.vibrate,
142
+ tag: options.tag,
143
+ data: localData,
144
+ requireInteraction: options.requireInteraction
145
+ }).then(function() {
146
+ var id;
147
+
148
+ registration.getNotifications().then(function(notifications) {
149
+ id = addNotification(notifications[notifications.length - 1]);
150
+
151
+ registration.active.postMessage('');
152
+ navigator.serviceWorker.addEventListener('message', function (event) {
153
+ var data = JSON.parse(event.data);
154
+
155
+ if (data.action === 'close' && Number.isInteger(data.id)) removeNotification(data.id);
156
+ });
157
+
158
+ resolve(prepareNotification(id, options));
159
+ });
160
+ });
161
+ });
162
+ }
163
+ }
164
+ } else if (w.webkitNotifications) {
165
+ notification = w.webkitNotifications.createNotification(
166
+ options.icon,
167
+ title,
168
+ options.body
169
+ );
170
+
171
+ notification.show();
172
+ } else if (navigator.mozNotification) {
173
+ notification = navigator.mozNotification.createNotification(
174
+ title,
175
+ options.body,
176
+ options.icon
177
+ );
178
+
179
+ notification.show();
180
+ } else if (w.external && w.external.msIsSiteMode()) {
181
+ w.external.msSiteModeClearIconOverlay();
182
+ w.external.msSiteModeSetIconOverlay(
183
+ ((isString(options.icon) || isUndefined(options.icon)) ? options.icon : options.icon.x16),
184
+ title
185
+ );
186
+ w.external.msSiteModeActivate();
187
+
188
+ notification = {};
189
+ } else {
190
+ throw new Error('Unable to create notification: unknown interface');
191
+ }
192
+
193
+ if (typeof(notification) !== 'undefined') {
194
+ var id = addNotification(notification);
195
+ var wrapper = prepareNotification(id, options);
196
+
197
+ if (isFunction(options.onShow)) notification.addEventListener('show', options.onShow);
198
+ if (isFunction(options.onError)) notification.addEventListener('error', options.onError);
199
+ if (isFunction(options.onClick)) notification.addEventListener('click', options.onClick);
200
+
201
+ notification.addEventListener('close', function() {
202
+ onClose(id);
203
+ });
204
+ notification.addEventListener('cancel', function() {
205
+ onClose(id);
206
+ });
207
+
208
+ resolve(wrapper);
209
+ }
210
+
211
+ resolve({});
212
+ },
213
+
214
+ Permission = {
215
+ DEFAULT: 'default',
216
+ GRANTED: 'granted',
217
+ DENIED: 'denied'
218
+ },
219
+
220
+ Permissions = [Permission.GRANTED, Permission.DEFAULT, Permission.DENIED];
221
+
222
+ self.Permission = Permission;
223
+
224
+ self.Permission.request = function (onGranted, onDenied) {
225
+ var existing = self.Permission.get();
226
+
227
+ if (!self.isSupported) {
228
+ throw new Error(incompatibilityErrorMessage);
229
+ }
230
+
231
+ callback = function (result) {
232
+ switch (result) {
233
+ case self.Permission.GRANTED:
234
+ if (onGranted) onGranted();
235
+ break;
236
+ case self.Permission.DENIED:
237
+ if (onDenied) onDenied();
238
+ break;
239
+ default:
240
+ // Nothing
241
+ }
242
+ };
243
+
244
+ if (existing !== self.Permission.DEFAULT) {
245
+ callback(existing);
246
+ } else if (w.Notification && w.Notification.requestPermission) {
247
+ Notification.requestPermission(callback);
248
+ } else if (w.webkitNotifications && w.webkitNotifications.checkPermission) {
249
+ w.webkitNotifications.requestPermission(callback);
250
+ } else {
251
+ throw new Error(incompatibilityErrorMessage);
252
+ }
253
+ };
254
+
255
+ self.Permission.has = function () {
256
+ return Permission.get() === Permission.GRANTED;
257
+ };
258
+
259
+ self.Permission.get = function () {
260
+ var permission;
261
+
262
+ if (!self.isSupported) {
263
+ throw new Error(incompatibilityErrorMessage);
264
+ }
265
+
266
+ if (w.Notification && w.Notification.permissionLevel) {
267
+ permission = w.Notification.permissionLevel;
268
+ } else if (w.webkitNotifications && w.webkitNotifications.checkPermission) {
269
+ permission = Permissions[w.webkitNotifications.checkPermission()];
270
+ } else if (w.Notification && w.Notification.permission) {
271
+ permission = w.Notification.permission;
272
+ } else if (navigator.mozNotification) {
273
+ permission = Permission.GRANTED;
274
+ } else if (w.external && w.external.msIsSiteMode() !== undefined) {
275
+ permission = w.external.msIsSiteMode() ? Permission.GRANTED : Permission.DEFAULT;
276
+ } else {
277
+ throw new Error(incompatibilityErrorMessage);
278
+ }
279
+
280
+ return permission;
281
+ };
282
+
283
+ self.isSupported = (function () {
284
+ var isSupported = false;
285
+
286
+ try {
287
+ isSupported = !!(w.Notification ||
288
+ w.webkitNotifications ||
289
+ navigator.mozNotification ||
290
+ (w.external && w.external.msIsSiteMode() !== undefined));
291
+ } catch (e) {
292
+ // Nothing
293
+ }
294
+
295
+ return isSupported;
296
+ })();
297
+
298
+ self.create = function (title, options) {
299
+ var promiseCallback;
300
+
301
+ if (!self.isSupported) {
302
+ throw new Error(incompatibilityErrorMessage);
303
+ }
304
+
305
+ if (!isString(title)) {
306
+ throw new Error('PushError: Title of notification must be a string');
307
+ }
308
+
309
+ if (!self.Permission.has()) {
310
+ promiseCallback = function(resolve, reject) {
311
+ self.Permission.request(function() {
312
+ try {
313
+ createCallback(title, options, resolve);
314
+ } catch (e) {
315
+ reject(e);
316
+ }
317
+ }, function() {
318
+ reject('Permission request declined');
319
+ });
320
+ };
321
+ } else {
322
+ promiseCallback = function(resolve, reject) {
323
+ try {
324
+ createCallback(title, options, resolve);
325
+ } catch (e) {
326
+ reject(e);
327
+ }
328
+ };
329
+ }
330
+
331
+ return new Promise(promiseCallback);
332
+ };
333
+
334
+ self.count = function () {
335
+ var count = 0;
336
+ var key;
337
+
338
+ for (key in notifications) {
339
+ count++;
340
+ }
341
+
342
+ return count;
343
+ },
344
+
345
+ self.__lastWorkerPath = function () {
346
+ return self.lastWorkerPath;
347
+ },
348
+
349
+ self.close = function (tag) {
350
+ var key;
351
+
352
+ for (key in notifications) {
353
+ notification = notifications[key];
354
+
355
+ if (notification.tag === tag) return closeNotification(key);
356
+ }
357
+ },
358
+
359
+ self.clear = function () {
360
+ var success = true;
361
+ var key;
362
+
363
+ for (key in notifications) {
364
+ success = success && closeNotification(key);
365
+ }
366
+
367
+ return success;
368
+ };
369
+ };
370
+
371
+ return Push;
372
+ });
@@ -46,6 +46,7 @@
46
46
  @import 'components/selectpicker';
47
47
  @import 'components/timepicker';
48
48
  @import 'components/typeahead';
49
+ @import 'components/tag';
49
50
  @import 'components/ad';
50
51
  @import 'components/label_and_badge';
51
52
  @import 'components/breadcrumb';
@@ -5,6 +5,7 @@
5
5
  // Selects
6
6
  // Checkboxes & Radios
7
7
  // Notes
8
+ // Tags
8
9
  // Labels
9
10
  // Addons
10
11
 
@@ -43,7 +44,8 @@ input { overflow: visible; }
43
44
  optgroup { font-weight: text-weight(semibold); }
44
45
  input,
45
46
  select,
46
- textarea {
47
+ textarea,
48
+ .form-tags {
47
49
  @include appearance(none);
48
50
  @include transition(all 0.3s ease-in-out);
49
51
  background: color(white);
@@ -59,7 +61,8 @@ textarea {
59
61
  }
60
62
  input:not([type='submit']),
61
63
  select,
62
- textarea {
64
+ textarea,
65
+ .form-tags {
63
66
  box-shadow: inset 0 2px 0 0 darkish-color(light-haze);
64
67
 
65
68
  &.dark {
@@ -80,11 +83,13 @@ textarea {
80
83
  color: color(gray);
81
84
  font-weight: text-weight(normal) !important;
82
85
  }
83
- &:focus {
86
+ &:focus,
87
+ &.focus {
84
88
  box-shadow: inset 0 2px 0 0 transparentize(color(blue), 0.5);
85
89
  border-color: color(blue);
86
90
  }
87
- &:focus:invalid {
91
+ &:focus:invalid,
92
+ &.focus:invalid {
88
93
  box-shadow: inset 0 2px 0 0 transparentize(color(red), 0.5);
89
94
  border-color: color(red);
90
95
  }
@@ -436,6 +441,24 @@ textarea {
436
441
  margin: -10px 0 10px;
437
442
  }
438
443
 
444
+ // Tags
445
+ // ==================================================
446
+ .form-tags {
447
+ white-space: normal;
448
+
449
+ input,
450
+ input:focus {
451
+ background: color(transparent);
452
+ border: 0;
453
+ box-shadow: none;
454
+ display: inline-block;
455
+ outline: none;
456
+ margin: 0;
457
+ padding: 0;
458
+ width: auto;
459
+ }
460
+ }
461
+
439
462
  // Labels
440
463
  // ==================================================
441
464
  .form-input,
@@ -0,0 +1,23 @@
1
+ // Table of Contents
2
+ // ==================================================
3
+ // Tag
4
+
5
+ // scss-lint:disable ImportantRule
6
+
7
+ // Tag
8
+ // ==================================================
9
+ .tag {
10
+ margin: 2px 2px 2px 0;
11
+ padding-right: 22px !important;
12
+
13
+ [data-role='remove'] {
14
+ cursor: pointer;
15
+ margin-left: 5px;
16
+
17
+ &::after {
18
+ content: '\39';
19
+ font-family: 'dripicons';
20
+ position: absolute;
21
+ }
22
+ }
23
+ }
@@ -10,11 +10,9 @@
10
10
  margin-top: 10px;
11
11
  z-index: 1060;
12
12
 
13
- > li > a b { color: color(blue); }
14
- }
15
- x {
16
- display: block;
17
- color: color(gray);
18
- font-style: italic;
19
- font-weight: normal;
13
+ > li > a b,
14
+ > li.active > a {
15
+ color: color(blue);
16
+ font-weight: text-weight(semibold);
17
+ }
20
18
  }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_frontend
3
3
  version: !ruby/object:Gem::Version
4
- version: 14.0.99
4
+ version: 14.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Juan Gomez
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-06-13 00:00:00.000000000 Z
11
+ date: 2017-06-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -238,6 +238,7 @@ files:
238
238
  - vendor/assets/javascripts/base/_switch.js
239
239
  - vendor/assets/javascripts/base/_tab.js
240
240
  - vendor/assets/javascripts/base/_table.js
241
+ - vendor/assets/javascripts/base/_tag.js
241
242
  - vendor/assets/javascripts/base/_timeago.js
242
243
  - vendor/assets/javascripts/base/_timepicker.js
243
244
  - vendor/assets/javascripts/base/_timezone.js
@@ -251,6 +252,7 @@ files:
251
252
  - vendor/assets/javascripts/extensions/_copy.js
252
253
  - vendor/assets/javascripts/extensions/_funnel.js
253
254
  - vendor/assets/javascripts/extensions/_map.js
255
+ - vendor/assets/javascripts/extensions/_push.js
254
256
  - vendor/assets/javascripts/extensions/_wysiwyg.js
255
257
  - vendor/assets/stylesheets/.DS_Store
256
258
  - vendor/assets/stylesheets/.keep
@@ -303,6 +305,7 @@ files:
303
305
  - vendor/assets/stylesheets/components/_sidebar.scss
304
306
  - vendor/assets/stylesheets/components/_spinner.scss
305
307
  - vendor/assets/stylesheets/components/_switch.scss
308
+ - vendor/assets/stylesheets/components/_tag.scss
306
309
  - vendor/assets/stylesheets/components/_timepicker.scss
307
310
  - vendor/assets/stylesheets/components/_tooltip.scss
308
311
  - vendor/assets/stylesheets/components/_transition.scss