@grafit/era-dependencies 1.0.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.
Files changed (72) hide show
  1. package/package.json +7 -0
  2. package/vendor/fonts/FontAwesome.otf +0 -0
  3. package/vendor/fonts/fontawesome-webfont.eot +0 -0
  4. package/vendor/fonts/fontawesome-webfont.svg +685 -0
  5. package/vendor/fonts/fontawesome-webfont.ttf +0 -0
  6. package/vendor/fonts/fontawesome-webfont.woff +0 -0
  7. package/vendor/fonts/fontawesome-webfont.woff2 +0 -0
  8. package/vendor/fonts/glyphicons-halflings-regular.eot +0 -0
  9. package/vendor/fonts/glyphicons-halflings-regular.svg +288 -0
  10. package/vendor/fonts/glyphicons-halflings-regular.ttf +0 -0
  11. package/vendor/fonts/glyphicons-halflings-regular.woff +0 -0
  12. package/vendor/fonts/glyphicons-halflings-regular.woff2 +0 -0
  13. package/vendor/scripts/angular/angular-cookies.js +322 -0
  14. package/vendor/scripts/angular/angular-file-upload.js +2087 -0
  15. package/vendor/scripts/angular/angular-filter.js +2287 -0
  16. package/vendor/scripts/angular/angular-locale_ru-ru.js +143 -0
  17. package/vendor/scripts/angular/angular-route.js +1069 -0
  18. package/vendor/scripts/angular/angular-sanitize.js +738 -0
  19. package/vendor/scripts/angular/angular-ui-router-0.2.18.js +4539 -0
  20. package/vendor/scripts/angular/angular.js +31768 -0
  21. package/vendor/scripts/angular/datetimepicker.js +578 -0
  22. package/vendor/scripts/angular/datetimepicker.templates.js +30 -0
  23. package/vendor/scripts/angular/mask.min.js +7 -0
  24. package/vendor/scripts/angular/ng-table.js +1518 -0
  25. package/vendor/scripts/angular/select.js +2356 -0
  26. package/vendor/scripts/angular/ui-bootstrap-tpls-2.1.3.js +7536 -0
  27. package/vendor/scripts/angular/uploader.js +3 -0
  28. package/vendor/scripts/bootbox.js +985 -0
  29. package/vendor/scripts/bootstrap.js +2377 -0
  30. package/vendor/scripts/es6-shim.js +3837 -0
  31. package/vendor/scripts/highchart/highcharts-more.src.js +3165 -0
  32. package/vendor/scripts/highchart/highstock.src.js +32008 -0
  33. package/vendor/scripts/highchart/modules/boost.src.js +2721 -0
  34. package/vendor/scripts/highchart/modules/exporting.src.js +951 -0
  35. package/vendor/scripts/jquery/jquery.js +11008 -0
  36. package/vendor/scripts/jquery.datetimepicker.full.js +2911 -0
  37. package/vendor/scripts/keycloak.js +2382 -0
  38. package/vendor/scripts/lodash.js +16733 -0
  39. package/vendor/scripts/moment-with-locales.js +12251 -0
  40. package/vendor/scripts/moment.js +4234 -0
  41. package/vendor/scripts/old/datepicker-ru.js +38 -0
  42. package/vendor/scripts/old/jquery-ui-1.11.1.js +16375 -0
  43. package/vendor/scripts/old/jquery.form.js +1278 -0
  44. package/vendor/scripts/perfect-scrollbar.js +1549 -0
  45. package/vendor/scripts/pickmeup/pickmeup-locales.js +11 -0
  46. package/vendor/scripts/pickmeup/pickmeup.js +1383 -0
  47. package/vendor/scripts/quill.js +9676 -0
  48. package/vendor/scripts/socket.io.min.js +3 -0
  49. package/vendor/scripts/textAngular/angular-spectrum-colorpicker.min.js +2 -0
  50. package/vendor/scripts/textAngular/spectrum.min.js +1 -0
  51. package/vendor/scripts/textAngular/textAngular-dropdownToggle.js +38 -0
  52. package/vendor/scripts/textAngular/textAngular-rangy.min.js +478 -0
  53. package/vendor/scripts/textAngular/textAngular-sanitize.min.js +322 -0
  54. package/vendor/scripts/textAngular/textAngular.min.js +1481 -0
  55. package/vendor/scripts/textAngular/textAngularSetup.js +1013 -0
  56. package/vendor/styles/bootstrap-theme.css +587 -0
  57. package/vendor/styles/bootstrap-theme.css.map +1 -0
  58. package/vendor/styles/bootstrap-theme.min.css +6 -0
  59. package/vendor/styles/bootstrap-theme.min.css.map +1 -0
  60. package/vendor/styles/bootstrap.css +6757 -0
  61. package/vendor/styles/bootstrap.css.map +1 -0
  62. package/vendor/styles/bootstrap.min.css +6 -0
  63. package/vendor/styles/bootstrap.min.css.map +1 -0
  64. package/vendor/styles/datetimepicker.css +115 -0
  65. package/vendor/styles/font-awesome.css +2199 -0
  66. package/vendor/styles/jquery.datetimepicker.min.css +1 -0
  67. package/vendor/styles/ng-table.css +136 -0
  68. package/vendor/styles/normalize.css +424 -0
  69. package/vendor/styles/perfect-scrollbar.css +165 -0
  70. package/vendor/styles/pickmeup.css +137 -0
  71. package/vendor/styles/spectrum.min.css +1 -0
  72. package/vendor/styles/textAngular.css +193 -0
@@ -0,0 +1,2287 @@
1
+ /**
2
+ * Bunch of useful filters for angularJS(with no external dependencies!)
3
+ * @version v0.5.7 - 2015-10-04 * @link https://github.com/a8m/angular-filter
4
+ * @author Ariel Mashraki <ariel@mashraki.co.il>
5
+ * @license MIT License, http://www.opensource.org/licenses/MIT
6
+ */
7
+ (function ( window, angular, undefined ) {
8
+ /*jshint globalstrict:true*/
9
+ 'use strict';
10
+
11
+ var isDefined = angular.isDefined,
12
+ isUndefined = angular.isUndefined,
13
+ isFunction = angular.isFunction,
14
+ isString = angular.isString,
15
+ isNumber = angular.isNumber,
16
+ isObject = angular.isObject,
17
+ isArray = angular.isArray,
18
+ forEach = angular.forEach,
19
+ extend = angular.extend,
20
+ copy = angular.copy,
21
+ equals = angular.equals;
22
+
23
+
24
+ /**
25
+ * @description
26
+ * get an object and return array of values
27
+ * @param object
28
+ * @returns {Array}
29
+ */
30
+ function toArray(object) {
31
+ return isArray(object)
32
+ ? object
33
+ : Object.keys(object).map(function(key) {
34
+ return object[key];
35
+ });
36
+ }
37
+
38
+ /**
39
+ * @param value
40
+ * @returns {boolean}
41
+ */
42
+ function isNull(value) {
43
+ return value === null;
44
+ }
45
+
46
+ /**
47
+ * @description
48
+ * return if object contains partial object
49
+ * @param partial{object}
50
+ * @param object{object}
51
+ * @returns {boolean}
52
+ */
53
+ function objectContains(partial, object) {
54
+ var keys = Object.keys(partial);
55
+
56
+ return keys.map(function(el) {
57
+ return (object[el] !== undefined) && (object[el] == partial[el]);
58
+ }).indexOf(false) == -1;
59
+
60
+ }
61
+
62
+ /**
63
+ * @description
64
+ * search for approximate pattern in string
65
+ * @param word
66
+ * @param pattern
67
+ * @returns {*}
68
+ */
69
+ function hasApproxPattern(word, pattern) {
70
+ if(pattern === '')
71
+ return word;
72
+
73
+ var index = word.indexOf(pattern.charAt(0));
74
+
75
+ if(index === -1)
76
+ return false;
77
+
78
+ return hasApproxPattern(word.substr(index+1), pattern.substr(1))
79
+ }
80
+
81
+ /**
82
+ * @description
83
+ * return the first n element of an array,
84
+ * if expression provided, is returns as long the expression return truthy
85
+ * @param array
86
+ * @param n {number}
87
+ * @param expression {$parse}
88
+ * @return array or single object
89
+ */
90
+ function getFirstMatches(array, n, expression) {
91
+ var count = 0;
92
+
93
+ return array.filter(function(elm) {
94
+ var rest = isDefined(expression) ? (count < n && expression(elm)) : count < n;
95
+ count = rest ? count+1 : count;
96
+
97
+ return rest;
98
+ });
99
+ }
100
+ /**
101
+ * Polyfill to ECMA6 String.prototype.contains
102
+ */
103
+ if (!String.prototype.contains) {
104
+ String.prototype.contains = function() {
105
+ return String.prototype.indexOf.apply(this, arguments) !== -1;
106
+ };
107
+ }
108
+
109
+ /**
110
+ * @param num {Number}
111
+ * @param decimal {Number}
112
+ * @param $math
113
+ * @returns {Number}
114
+ */
115
+ function convertToDecimal(num, decimal, $math){
116
+ return $math.round(num * $math.pow(10,decimal)) / ($math.pow(10,decimal));
117
+ }
118
+
119
+ /**
120
+ * @description
121
+ * Get an object, and return an array composed of it's properties names(nested too).
122
+ * @param obj {Object}
123
+ * @param stack {Array}
124
+ * @param parent {String}
125
+ * @returns {Array}
126
+ * @example
127
+ * parseKeys({ a:1, b: { c:2, d: { e: 3 } } }) ==> ["a", "b.c", "b.d.e"]
128
+ */
129
+ function deepKeys(obj, stack, parent) {
130
+ stack = stack || [];
131
+ var keys = Object.keys(obj);
132
+
133
+ keys.forEach(function(el) {
134
+ //if it's a nested object
135
+ if(isObject(obj[el]) && !isArray(obj[el])) {
136
+ //concatenate the new parent if exist
137
+ var p = parent ? parent + '.' + el : parent;
138
+ deepKeys(obj[el], stack, p || el);
139
+ } else {
140
+ //create and save the key
141
+ var key = parent ? parent + '.' + el : el;
142
+ stack.push(key)
143
+ }
144
+ });
145
+ return stack
146
+ }
147
+
148
+ /**
149
+ * @description
150
+ * Test if given object is a Scope instance
151
+ * @param obj
152
+ * @returns {Boolean}
153
+ */
154
+ function isScope(obj) {
155
+ return obj && obj.$evalAsync && obj.$watch;
156
+ }
157
+
158
+ /**
159
+ * @ngdoc filter
160
+ * @name a8m.angular
161
+ * @kind function
162
+ *
163
+ * @description
164
+ * reference to angular function
165
+ */
166
+
167
+ angular.module('a8m.angular', [])
168
+
169
+ .filter('isUndefined', function () {
170
+ return function (input) {
171
+ return angular.isUndefined(input);
172
+ }
173
+ })
174
+ .filter('isDefined', function() {
175
+ return function (input) {
176
+ return angular.isDefined(input);
177
+ }
178
+ })
179
+ .filter('isFunction', function() {
180
+ return function (input) {
181
+ return angular.isFunction(input);
182
+ }
183
+ })
184
+ .filter('isString', function() {
185
+ return function (input) {
186
+ return angular.isString(input)
187
+ }
188
+ })
189
+ .filter('isNumber', function() {
190
+ return function (input) {
191
+ return angular.isNumber(input);
192
+ }
193
+ })
194
+ .filter('isArray', function() {
195
+ return function (input) {
196
+ return angular.isArray(input);
197
+ }
198
+ })
199
+ .filter('isObject', function() {
200
+ return function (input) {
201
+ return angular.isObject(input);
202
+ }
203
+ })
204
+ .filter('isEqual', function() {
205
+ return function (o1, o2) {
206
+ return angular.equals(o1, o2);
207
+ }
208
+ });
209
+
210
+ /**
211
+ * @ngdoc filter
212
+ * @name a8m.conditions
213
+ * @kind function
214
+ *
215
+ * @description
216
+ * reference to math conditions
217
+ */
218
+ angular.module('a8m.conditions', [])
219
+
220
+ .filter({
221
+ isGreaterThan : isGreaterThanFilter,
222
+ '>' : isGreaterThanFilter,
223
+
224
+ isGreaterThanOrEqualTo : isGreaterThanOrEqualToFilter,
225
+ '>=' : isGreaterThanOrEqualToFilter,
226
+
227
+ isLessThan : isLessThanFilter,
228
+ '<' : isLessThanFilter,
229
+
230
+ isLessThanOrEqualTo : isLessThanOrEqualToFilter,
231
+ '<=' : isLessThanOrEqualToFilter,
232
+
233
+ isEqualTo : isEqualToFilter,
234
+ '==' : isEqualToFilter,
235
+
236
+ isNotEqualTo : isNotEqualToFilter,
237
+ '!=' : isNotEqualToFilter,
238
+
239
+ isIdenticalTo : isIdenticalToFilter,
240
+ '===' : isIdenticalToFilter,
241
+
242
+ isNotIdenticalTo : isNotIdenticalToFilter,
243
+ '!==' : isNotIdenticalToFilter
244
+ });
245
+
246
+ function isGreaterThanFilter() {
247
+ return function (input, check) {
248
+ return input > check;
249
+ };
250
+ }
251
+
252
+ function isGreaterThanOrEqualToFilter() {
253
+ return function (input, check) {
254
+ return input >= check;
255
+ };
256
+ }
257
+
258
+ function isLessThanFilter() {
259
+ return function (input, check) {
260
+ return input < check;
261
+ };
262
+ }
263
+
264
+ function isLessThanOrEqualToFilter() {
265
+ return function (input, check) {
266
+ return input <= check;
267
+ };
268
+ }
269
+
270
+ function isEqualToFilter() {
271
+ return function (input, check) {
272
+ return input == check;
273
+ };
274
+ }
275
+
276
+ function isNotEqualToFilter() {
277
+ return function (input, check) {
278
+ return input != check;
279
+ };
280
+ }
281
+
282
+ function isIdenticalToFilter() {
283
+ return function (input, check) {
284
+ return input === check;
285
+ };
286
+ }
287
+
288
+ function isNotIdenticalToFilter() {
289
+ return function (input, check) {
290
+ return input !== check;
291
+ };
292
+ }
293
+ /**
294
+ * @ngdoc filter
295
+ * @name isNull
296
+ * @kind function
297
+ *
298
+ * @description
299
+ * checks if value is null or not
300
+ * @return Boolean
301
+ */
302
+ angular.module('a8m.is-null', [])
303
+ .filter('isNull', function () {
304
+ return function(input) {
305
+ return isNull(input);
306
+ }
307
+ });
308
+
309
+ /**
310
+ * @ngdoc filter
311
+ * @name after-where
312
+ * @kind function
313
+ *
314
+ * @description
315
+ * get a collection and properties object, and returns all of the items
316
+ * in the collection after the first that found with the given properties.
317
+ *
318
+ */
319
+ angular.module('a8m.after-where', [])
320
+ .filter('afterWhere', function() {
321
+ return function (collection, object) {
322
+
323
+ collection = isObject(collection)
324
+ ? toArray(collection)
325
+ : collection;
326
+
327
+ if(!isArray(collection) || isUndefined(object)) return collection;
328
+
329
+ var index = collection.map( function( elm ) {
330
+ return objectContains(object, elm);
331
+ }).indexOf( true );
332
+
333
+ return collection.slice((index === -1) ? 0 : index);
334
+ }
335
+ });
336
+
337
+ /**
338
+ * @ngdoc filter
339
+ * @name after
340
+ * @kind function
341
+ *
342
+ * @description
343
+ * get a collection and specified count, and returns all of the items
344
+ * in the collection after the specified count.
345
+ *
346
+ */
347
+
348
+ angular.module('a8m.after', [])
349
+ .filter('after', function() {
350
+ return function (collection, count) {
351
+ collection = isObject(collection)
352
+ ? toArray(collection)
353
+ : collection;
354
+
355
+ return (isArray(collection))
356
+ ? collection.slice(count)
357
+ : collection;
358
+ }
359
+ });
360
+
361
+ /**
362
+ * @ngdoc filter
363
+ * @name before-where
364
+ * @kind function
365
+ *
366
+ * @description
367
+ * get a collection and properties object, and returns all of the items
368
+ * in the collection before the first that found with the given properties.
369
+ */
370
+ angular.module('a8m.before-where', [])
371
+ .filter('beforeWhere', function() {
372
+ return function (collection, object) {
373
+
374
+ collection = isObject(collection)
375
+ ? toArray(collection)
376
+ : collection;
377
+
378
+ if(!isArray(collection) || isUndefined(object)) return collection;
379
+
380
+ var index = collection.map( function( elm ) {
381
+ return objectContains(object, elm);
382
+ }).indexOf( true );
383
+
384
+ return collection.slice(0, (index === -1) ? collection.length : ++index);
385
+ }
386
+ });
387
+
388
+ /**
389
+ * @ngdoc filter
390
+ * @name before
391
+ * @kind function
392
+ *
393
+ * @description
394
+ * get a collection and specified count, and returns all of the items
395
+ * in the collection before the specified count.
396
+ */
397
+ angular.module('a8m.before', [])
398
+ .filter('before', function() {
399
+ return function (collection, count) {
400
+ collection = isObject(collection)
401
+ ? toArray(collection)
402
+ : collection;
403
+
404
+ return (isArray(collection))
405
+ ? collection.slice(0, (!count) ? count : --count)
406
+ : collection;
407
+ }
408
+ });
409
+
410
+ /**
411
+ * @ngdoc filter
412
+ * @name chunkBy
413
+ * @kind function
414
+ *
415
+ * @description
416
+ * Collect data into fixed-length chunks or blocks
417
+ */
418
+
419
+ angular.module('a8m.chunk-by', ['a8m.filter-watcher'])
420
+ .filter('chunkBy', ['filterWatcher', function (filterWatcher) {
421
+ return function (array, n, fillVal) {
422
+
423
+ return filterWatcher.isMemoized('chunkBy', arguments) ||
424
+ filterWatcher.memoize('chunkBy', arguments, this,
425
+ _chunkBy(array, n, fillVal));
426
+ /**
427
+ * @description
428
+ * Get array with size `n` in `val` inside it.
429
+ * @param n
430
+ * @param val
431
+ * @returns {Array}
432
+ */
433
+ function fill(n, val) {
434
+ var ret = [];
435
+ while (n--) ret[n] = val;
436
+ return ret;
437
+ }
438
+
439
+ function _chunkBy(array, n, fillVal) {
440
+ if (!isArray(array)) return array;
441
+ return array.map(function (el, i, self) {
442
+ i = i * n;
443
+ el = self.slice(i, i + n);
444
+ return !isUndefined(fillVal) && el.length < n
445
+ ? el.concat(fill(n - el.length, fillVal))
446
+ : el;
447
+ }).slice(0, Math.ceil(array.length / n));
448
+ }
449
+ }
450
+ }]);
451
+
452
+ /**
453
+ * @ngdoc filter
454
+ * @name concat
455
+ * @kind function
456
+ *
457
+ * @description
458
+ * get (array/object, object/array) and return merged collection
459
+ */
460
+ angular.module('a8m.concat', [])
461
+ .filter('concat', [function () {
462
+ return function (collection, joined) {
463
+
464
+ if (isUndefined(joined)) return collection;
465
+
466
+ if (isArray(collection)) {
467
+ return isObject(joined)
468
+ ? collection.concat(toArray(joined))
469
+ : collection.concat(joined);
470
+ }
471
+
472
+ if (isObject(collection)) {
473
+ var array = toArray(collection);
474
+ return (isObject(joined))
475
+ ? array.concat(toArray(joined))
476
+ : array.concat(joined);
477
+ }
478
+ return collection;
479
+ };
480
+ }
481
+ ]);
482
+
483
+ /**
484
+ * @ngdoc filter
485
+ * @name contains
486
+ * @kind function
487
+ *
488
+ * @description
489
+ * Checks if given expression is present in one or more object in the collection
490
+ */
491
+ angular.module('a8m.contains', [])
492
+ .filter({
493
+ contains: ['$parse', containsFilter],
494
+ some: ['$parse', containsFilter]
495
+ });
496
+
497
+ function containsFilter($parse) {
498
+ return function (collection, expression) {
499
+
500
+ collection = isObject(collection) ? toArray(collection) : collection;
501
+
502
+ if(!isArray(collection) || isUndefined(expression)) {
503
+ return false;
504
+ }
505
+
506
+ return collection.some(function(elm) {
507
+ return (isObject(elm) || isFunction(expression))
508
+ ? $parse(expression)(elm)
509
+ : elm === expression;
510
+ });
511
+
512
+ }
513
+ }
514
+
515
+ /**
516
+ * @ngdoc filter
517
+ * @name countBy
518
+ * @kind function
519
+ *
520
+ * @description
521
+ * Sorts a list into groups and returns a count for the number of objects in each group.
522
+ */
523
+
524
+ angular.module('a8m.count-by', [])
525
+
526
+ .filter('countBy', [ '$parse', function ( $parse ) {
527
+ return function (collection, property) {
528
+
529
+ var result = {},
530
+ get = $parse(property),
531
+ prop;
532
+
533
+ collection = (isObject(collection)) ? toArray(collection) : collection;
534
+
535
+ if(!isArray(collection) || isUndefined(property)) {
536
+ return collection;
537
+ }
538
+
539
+ collection.forEach( function( elm ) {
540
+ prop = get(elm);
541
+
542
+ if(!result[prop]) {
543
+ result[prop] = 0;
544
+ }
545
+
546
+ result[prop]++;
547
+ });
548
+
549
+ return result;
550
+ }
551
+ }]);
552
+
553
+ /**
554
+ * @ngdoc filter
555
+ * @name defaults
556
+ * @kind function
557
+ *
558
+ * @description
559
+ * defaultsFilter allows to specify a default fallback value for properties that resolve to undefined.
560
+ */
561
+ angular.module('a8m.defaults', [])
562
+ .filter('defaults', ['$parse', function( $parse ) {
563
+ return function(collection, defaults) {
564
+
565
+ collection = isObject(collection) ? toArray(collection) : collection;
566
+
567
+ if(!isArray(collection) || !isObject(defaults)) {
568
+ return collection;
569
+ }
570
+
571
+ var keys = deepKeys(defaults);
572
+
573
+ collection.forEach(function(elm) {
574
+ //loop through all the keys
575
+ keys.forEach(function(key) {
576
+ var getter = $parse(key);
577
+ var setter = getter.assign;
578
+ //if it's not exist
579
+ if(isUndefined(getter(elm))) {
580
+ //get from defaults, and set to the returned object
581
+ setter(elm, getter(defaults))
582
+ }
583
+ });
584
+ });
585
+
586
+ return collection;
587
+ }
588
+ }]);
589
+ /**
590
+ * @ngdoc filter
591
+ * @name every
592
+ * @kind function
593
+ *
594
+ * @description
595
+ * Checks if given expression is present in all members in the collection
596
+ *
597
+ */
598
+ angular.module('a8m.every', [])
599
+ .filter('every', ['$parse', function($parse) {
600
+ return function (collection, expression) {
601
+ collection = isObject(collection) ? toArray(collection) : collection;
602
+
603
+ if(!isArray(collection) || isUndefined(expression)) {
604
+ return true;
605
+ }
606
+
607
+ return collection.every( function(elm) {
608
+ return (isObject(elm) || isFunction(expression))
609
+ ? $parse(expression)(elm)
610
+ : elm === expression;
611
+ });
612
+ }
613
+ }]);
614
+
615
+ /**
616
+ * @ngdoc filter
617
+ * @name filterBy
618
+ * @kind function
619
+ *
620
+ * @description
621
+ * filter by specific properties, avoid the rest
622
+ */
623
+ angular.module('a8m.filter-by', [])
624
+ .filter('filterBy', ['$parse', function( $parse ) {
625
+ return function(collection, properties, search) {
626
+ var comparator;
627
+
628
+ search = (isString(search) || isNumber(search)) ?
629
+ String(search).toLowerCase() : undefined;
630
+
631
+ collection = isObject(collection) ? toArray(collection) : collection;
632
+
633
+ if(!isArray(collection) || isUndefined(search)) {
634
+ return collection;
635
+ }
636
+
637
+ return collection.filter(function(elm) {
638
+ return properties.some(function(prop) {
639
+
640
+ /**
641
+ * check if there is concatenate properties
642
+ * example:
643
+ * object: { first: 'foo', last:'bar' }
644
+ * filterBy: ['first + last'] => search by full name(i.e 'foo bar')
645
+ */
646
+ if(!~prop.indexOf('+')) {
647
+ comparator = $parse(prop)(elm)
648
+ } else {
649
+ var propList = prop.replace(new RegExp('\\s', 'g'), '').split('+');
650
+ comparator = propList.reduce(function(prev, cur, index) {
651
+ return (index === 1) ? $parse(prev)(elm) + ' ' + $parse(cur)(elm) :
652
+ prev + ' ' + $parse(cur)(elm);
653
+ });
654
+ }
655
+
656
+ return (isString(comparator) || isNumber(comparator))
657
+ ? String(comparator).toLowerCase().contains(search)
658
+ : false;
659
+ });
660
+ });
661
+ }
662
+ }]);
663
+
664
+ /**
665
+ * @ngdoc filter
666
+ * @name first
667
+ * @kind function
668
+ *
669
+ * @description
670
+ * Gets the first element or first n elements of an array
671
+ * if callback is provided, is returns as long the callback return truthy
672
+ */
673
+ angular.module('a8m.first', [])
674
+ .filter('first', ['$parse', function( $parse ) {
675
+ return function(collection) {
676
+ var n
677
+ , getter
678
+ , args;
679
+
680
+ collection = isObject(collection)
681
+ ? toArray(collection)
682
+ : collection;
683
+
684
+ if(!isArray(collection)) {
685
+ return collection;
686
+ }
687
+
688
+ args = Array.prototype.slice.call(arguments, 1);
689
+ n = (isNumber(args[0])) ? args[0] : 1;
690
+ getter = (!isNumber(args[0])) ? args[0] : (!isNumber(args[1])) ? args[1] : undefined;
691
+
692
+ return (args.length) ? getFirstMatches(collection, n,(getter) ? $parse(getter) : getter) :
693
+ collection[0];
694
+ }
695
+ }]);
696
+
697
+ /**
698
+ * @ngdoc filter
699
+ * @name flatten
700
+ * @kind function
701
+ *
702
+ * @description
703
+ * Flattens a nested array (the nesting can be to any depth).
704
+ * If you pass shallow, the array will only be flattened a single level
705
+ */
706
+ angular.module('a8m.flatten', [])
707
+ .filter('flatten', function () {
708
+ return function(collection, shallow) {
709
+
710
+ shallow = shallow || false;
711
+ collection = isObject(collection)
712
+ ? toArray(collection)
713
+ : collection;
714
+
715
+ if(!isArray(collection)) {
716
+ return collection;
717
+ }
718
+
719
+ return !shallow
720
+ ? flatten(collection, 0)
721
+ : [].concat.apply([], collection);
722
+ }
723
+ });
724
+
725
+ /**
726
+ * flatten nested array (the nesting can be to any depth).
727
+ * @param array {Array}
728
+ * @param i {int}
729
+ * @returns {Array}
730
+ * @private
731
+ */
732
+ function flatten(array, i) {
733
+ i = i || 0;
734
+
735
+ if(i >= array.length)
736
+ return array;
737
+
738
+ if(isArray(array[i])) {
739
+ return flatten(array.slice(0,i)
740
+ .concat(array[i], array.slice(i+1)), i);
741
+ }
742
+ return flatten(array, i+1);
743
+ }
744
+
745
+ /**
746
+ * @ngdoc filter
747
+ * @name fuzzyByKey
748
+ * @kind function
749
+ *
750
+ * @description
751
+ * fuzzy string searching by key
752
+ */
753
+ angular.module('a8m.fuzzy-by', [])
754
+ .filter('fuzzyBy', ['$parse', function ( $parse ) {
755
+ return function (collection, property, search, csensitive) {
756
+
757
+ var sensitive = csensitive || false,
758
+ prop, getter;
759
+
760
+ collection = isObject(collection) ? toArray(collection) : collection;
761
+
762
+ if(!isArray(collection) || isUndefined(property)
763
+ || isUndefined(search)) {
764
+ return collection;
765
+ }
766
+
767
+ getter = $parse(property);
768
+
769
+ return collection.filter(function(elm) {
770
+
771
+ prop = getter(elm);
772
+ if(!isString(prop)) {
773
+ return false;
774
+ }
775
+
776
+ prop = (sensitive) ? prop : prop.toLowerCase();
777
+ search = (sensitive) ? search : search.toLowerCase();
778
+
779
+ return hasApproxPattern(prop, search) !== false
780
+ })
781
+ }
782
+
783
+ }]);
784
+ /**
785
+ * @ngdoc filter
786
+ * @name fuzzy
787
+ * @kind function
788
+ *
789
+ * @description
790
+ * fuzzy string searching for array of strings, objects
791
+ */
792
+ angular.module('a8m.fuzzy', [])
793
+ .filter('fuzzy', function () {
794
+ return function (collection, search, csensitive) {
795
+ var sensitive = csensitive || false;
796
+ collection = isObject(collection) ? toArray(collection) : collection;
797
+
798
+ if(!isArray(collection) || isUndefined(search)) {
799
+ return collection;
800
+ }
801
+
802
+ search = (sensitive) ? search : search.toLowerCase();
803
+
804
+ return collection.filter(function(elm) {
805
+ if(isString(elm)) {
806
+ elm = (sensitive) ? elm : elm.toLowerCase();
807
+ return hasApproxPattern(elm, search) !== false
808
+ }
809
+ return (isObject(elm)) ? _hasApproximateKey(elm, search) : false;
810
+ });
811
+
812
+ /**
813
+ * checks if object has key{string} that match
814
+ * to fuzzy search pattern
815
+ * @param object
816
+ * @param search
817
+ * @returns {boolean}
818
+ * @private
819
+ */
820
+ function _hasApproximateKey(object, search) {
821
+ var properties = Object.keys(object),
822
+ prop, flag;
823
+ return 0 < properties.filter(function (elm) {
824
+ prop = object[elm];
825
+
826
+ //avoid iteration if we found some key that equal[performance]
827
+ if(flag) return true;
828
+
829
+ if (isString(prop)) {
830
+ prop = (sensitive) ? prop : prop.toLowerCase();
831
+ return flag = (hasApproxPattern(prop, search) !== false);
832
+ }
833
+
834
+ return false;
835
+
836
+ }).length;
837
+ }
838
+ }
839
+ });
840
+
841
+ /**
842
+ * @ngdoc filter
843
+ * @name groupBy
844
+ * @kind function
845
+ *
846
+ * @description
847
+ * Create an object composed of keys generated from the result of running each element of a collection,
848
+ * each key is an array of the elements.
849
+ */
850
+
851
+ angular.module('a8m.group-by', [ 'a8m.filter-watcher' ])
852
+ .filter('groupBy', [ '$parse', 'filterWatcher', function ( $parse, filterWatcher ) {
853
+ return function (collection, property) {
854
+
855
+ if(!isObject(collection) || isUndefined(property)) {
856
+ return collection;
857
+ }
858
+
859
+ return filterWatcher.isMemoized('groupBy', arguments) ||
860
+ filterWatcher.memoize('groupBy', arguments, this,
861
+ _groupBy(collection, $parse(property)));
862
+
863
+ /**
864
+ * groupBy function
865
+ * @param collection
866
+ * @param getter
867
+ * @returns {{}}
868
+ */
869
+ function _groupBy(collection, getter) {
870
+ var result = {};
871
+ var prop;
872
+
873
+ forEach( collection, function( elm ) {
874
+ prop = getter(elm);
875
+
876
+ if(!result[prop]) {
877
+ result[prop] = [];
878
+ }
879
+ result[prop].push(elm);
880
+ });
881
+ return result;
882
+ }
883
+ }
884
+ }]);
885
+
886
+ /**
887
+ * @ngdoc filter
888
+ * @name isEmpty
889
+ * @kind function
890
+ *
891
+ * @description
892
+ * get collection or string and return if it empty
893
+ */
894
+ angular.module('a8m.is-empty', [])
895
+ .filter('isEmpty', function () {
896
+ return function(collection) {
897
+ return isObject(collection)
898
+ ? !toArray(collection).length
899
+ : !collection.length;
900
+ }
901
+ });
902
+
903
+ /**
904
+ * @ngdoc filter
905
+ * @name join
906
+ * @kind function
907
+ *
908
+ * @description
909
+ * join a collection by a provided delimiter (space by default)
910
+ */
911
+ angular.module('a8m.join', [])
912
+ .filter('join', function () {
913
+ return function (input, delimiter) {
914
+ if (isUndefined(input) || !isArray(input)) {
915
+ return input;
916
+ }
917
+ if (isUndefined(delimiter)) delimiter = ' ';
918
+
919
+ return input.join(delimiter);
920
+ };
921
+ })
922
+ ;
923
+
924
+ /**
925
+ * @ngdoc filter
926
+ * @name last
927
+ * @kind function
928
+ *
929
+ * @description
930
+ * Gets the last element or last n elements of an array
931
+ * if callback is provided, is returns as long the callback return truthy
932
+ */
933
+ angular.module('a8m.last', [])
934
+ .filter('last', ['$parse', function( $parse ) {
935
+ return function(collection) {
936
+ var n
937
+ , getter
938
+ , args
939
+ //cuz reverse change our src collection
940
+ //and we don't want side effects
941
+ , reversed = copy(collection);
942
+
943
+ reversed = isObject(reversed)
944
+ ? toArray(reversed)
945
+ : reversed;
946
+
947
+ if(!isArray(reversed)) {
948
+ return reversed;
949
+ }
950
+
951
+ args = Array.prototype.slice.call(arguments, 1);
952
+ n = (isNumber(args[0])) ? args[0] : 1;
953
+ getter = (!isNumber(args[0])) ? args[0] : (!isNumber(args[1])) ? args[1] : undefined;
954
+
955
+ return (args.length)
956
+ //send reversed collection as arguments, and reverse it back as result
957
+ ? getFirstMatches(reversed.reverse(), n,(getter) ? $parse(getter) : getter).reverse()
958
+ //get the last element
959
+ : reversed[reversed.length-1];
960
+ }
961
+ }]);
962
+
963
+ /**
964
+ * @ngdoc filter
965
+ * @name map
966
+ * @kind function
967
+ *
968
+ * @description
969
+ * Returns a new collection of the results of each expression execution.
970
+ */
971
+ angular.module('a8m.map', [])
972
+ .filter('map', ['$parse', function($parse) {
973
+ return function (collection, expression) {
974
+
975
+ collection = isObject(collection)
976
+ ? toArray(collection)
977
+ : collection;
978
+
979
+ if(!isArray(collection) || isUndefined(expression)) {
980
+ return collection;
981
+ }
982
+
983
+ return collection.map(function (elm) {
984
+ return $parse(expression)(elm);
985
+ });
986
+ }
987
+ }]);
988
+
989
+ /**
990
+ * @ngdoc filter
991
+ * @name omit
992
+ * @kind function
993
+ *
994
+ * @description
995
+ * filter collection by expression
996
+ */
997
+
998
+ angular.module('a8m.omit', [])
999
+
1000
+ .filter('omit', ['$parse', function($parse) {
1001
+ return function (collection, expression) {
1002
+
1003
+ collection = isObject(collection)
1004
+ ? toArray(collection)
1005
+ : collection;
1006
+
1007
+ if(!isArray(collection) || isUndefined(expression)) {
1008
+ return collection;
1009
+ }
1010
+
1011
+ return collection.filter(function (elm) {
1012
+ return !($parse(expression)(elm));
1013
+ });
1014
+ }
1015
+ }]);
1016
+
1017
+ /**
1018
+ * @ngdoc filter
1019
+ * @name pick
1020
+ * @kind function
1021
+ *
1022
+ * @description
1023
+ * filter collection by expression
1024
+ */
1025
+
1026
+ angular.module('a8m.pick', [])
1027
+
1028
+ .filter('pick', ['$parse', function($parse) {
1029
+ return function (collection, expression) {
1030
+
1031
+ collection = isObject(collection)
1032
+ ? toArray(collection)
1033
+ : collection;
1034
+
1035
+ if(!isArray(collection) || isUndefined(expression)) {
1036
+ return collection;
1037
+ }
1038
+
1039
+ return collection.filter(function (elm) {
1040
+ return $parse(expression)(elm);
1041
+ });
1042
+ }
1043
+ }]);
1044
+
1045
+ /**
1046
+ * @ngdoc filter
1047
+ * @name range
1048
+ * @kind function
1049
+ *
1050
+ * @description
1051
+ * rangeFilter provides some support for a for loop using numbers
1052
+ */
1053
+ angular.module('a8m.range', [])
1054
+ .filter('range', function () {
1055
+ return function (input, total) {
1056
+ for (var i = 0; i < parseInt(total); i++) {
1057
+ input.push(i);
1058
+ }
1059
+ return input;
1060
+ };
1061
+ });
1062
+ /**
1063
+ * @ngdoc filter
1064
+ * @name removeWith
1065
+ * @kind function
1066
+ *
1067
+ * @description
1068
+ * get collection and properties object, and removed elements
1069
+ * with this properties
1070
+ */
1071
+
1072
+ angular.module('a8m.remove-with', [])
1073
+ .filter('removeWith', function() {
1074
+ return function (collection, object) {
1075
+
1076
+ if(isUndefined(object)) {
1077
+ return collection;
1078
+ }
1079
+ collection = isObject(collection)
1080
+ ? toArray(collection)
1081
+ : collection;
1082
+
1083
+ return collection.filter(function (elm) {
1084
+ return !objectContains(object, elm);
1085
+ });
1086
+ }
1087
+ });
1088
+
1089
+
1090
+ /**
1091
+ * @ngdoc filter
1092
+ * @name remove
1093
+ * @kind function
1094
+ *
1095
+ * @description
1096
+ * remove specific members from collection
1097
+ */
1098
+
1099
+ angular.module('a8m.remove', [])
1100
+
1101
+ .filter('remove', function () {
1102
+ return function (collection) {
1103
+ collection = isObject(collection) ? toArray(collection) : collection;
1104
+ var args = Array.prototype.slice.call(arguments, 1);
1105
+
1106
+ if(!isArray(collection)) {
1107
+ return collection;
1108
+ }
1109
+
1110
+ return collection.filter( function( member ) {
1111
+ return !args.some(function(nest) {
1112
+ return equals(nest, member);
1113
+ })
1114
+ });
1115
+ }
1116
+ });
1117
+
1118
+ /**
1119
+ * @ngdoc filter
1120
+ * @name reverse
1121
+ * @kind function
1122
+ *
1123
+ * @description
1124
+ * Reverses a string or collection
1125
+ */
1126
+ angular.module('a8m.reverse', [])
1127
+ .filter('reverse',[ function () {
1128
+ return function (input) {
1129
+ input = isObject(input) ? toArray(input) : input;
1130
+
1131
+ if(isString(input)) {
1132
+ return input.split('').reverse().join('');
1133
+ }
1134
+
1135
+ return isArray(input)
1136
+ ? input.slice().reverse()
1137
+ : input;
1138
+ }
1139
+ }]);
1140
+
1141
+ /**
1142
+ * @ngdoc filter
1143
+ * @name searchField
1144
+ * @kind function
1145
+ *
1146
+ * @description
1147
+ * for each member, join several strings field and add them to
1148
+ * new field called 'searchField' (use for search filtering)
1149
+ */
1150
+ angular.module('a8m.search-field', [])
1151
+ .filter('searchField', ['$parse', function ($parse) {
1152
+ return function (collection) {
1153
+
1154
+ var get, field;
1155
+
1156
+ collection = isObject(collection) ? toArray(collection) : collection;
1157
+
1158
+ var args = Array.prototype.slice.call(arguments, 1);
1159
+
1160
+ if(!isArray(collection) || !args.length) {
1161
+ return collection;
1162
+ }
1163
+
1164
+ return collection.map(function(member) {
1165
+
1166
+ field = args.map(function(field) {
1167
+ get = $parse(field);
1168
+ return get(member);
1169
+ }).join(' ');
1170
+
1171
+ return extend(member, { searchField: field });
1172
+ });
1173
+ }
1174
+ }]);
1175
+
1176
+ /**
1177
+ * @ngdoc filter
1178
+ * @name toArray
1179
+ * @kind function
1180
+ *
1181
+ * @description
1182
+ * Convert objects into stable arrays.
1183
+ * if addKey set to true,the filter also attaches a new property
1184
+ * $key to the value containing the original key that was used in
1185
+ * the object we are iterating over to reference the property
1186
+ */
1187
+ angular.module('a8m.to-array', [])
1188
+ .filter('toArray', function() {
1189
+ return function (collection, addKey) {
1190
+
1191
+ if(!isObject(collection)) {
1192
+ return collection;
1193
+ }
1194
+
1195
+ return !addKey
1196
+ ? toArray(collection)
1197
+ : Object.keys(collection).map(function (key) {
1198
+ return extend(collection[key], { $key: key });
1199
+ });
1200
+ }
1201
+ });
1202
+
1203
+ /**
1204
+ * @ngdoc filter
1205
+ * @name unique/uniq
1206
+ * @kind function
1207
+ *
1208
+ * @description
1209
+ * get collection and filter duplicate members
1210
+ * if uniqueFilter get a property(nested to) as argument it's
1211
+ * filter by this property as unique identifier
1212
+ */
1213
+
1214
+ angular.module('a8m.unique', [])
1215
+ .filter({
1216
+ unique: ['$parse', uniqFilter],
1217
+ uniq: ['$parse', uniqFilter]
1218
+ });
1219
+
1220
+ function uniqFilter($parse) {
1221
+ return function (collection, property) {
1222
+
1223
+ collection = isObject(collection) ? toArray(collection) : collection;
1224
+
1225
+ if (!isArray(collection)) {
1226
+ return collection;
1227
+ }
1228
+
1229
+ //store all unique identifiers
1230
+ var uniqueItems = [],
1231
+ get = $parse(property);
1232
+
1233
+ return (isUndefined(property))
1234
+ //if it's kind of primitive array
1235
+ ? collection.filter(function (elm, pos, self) {
1236
+ return self.indexOf(elm) === pos;
1237
+ })
1238
+ //else compare with equals
1239
+ : collection.filter(function (elm) {
1240
+ var prop = get(elm);
1241
+ if(some(uniqueItems, prop)) {
1242
+ return false;
1243
+ }
1244
+ uniqueItems.push(prop);
1245
+ return true;
1246
+ });
1247
+
1248
+ //checked if the unique identifier is already exist
1249
+ function some(array, member) {
1250
+ if(isUndefined(member)) {
1251
+ return false;
1252
+ }
1253
+ return array.some(function(el) {
1254
+ return equals(el, member);
1255
+ });
1256
+ }
1257
+ }
1258
+ }
1259
+
1260
+ /**
1261
+ * @ngdoc filter
1262
+ * @name where
1263
+ * @kind function
1264
+ *
1265
+ * @description
1266
+ * of each element in a collection to the given properties object,
1267
+ * returning an array of all elements that have equivalent property values.
1268
+ *
1269
+ */
1270
+ angular.module('a8m.where', [])
1271
+ .filter('where', function() {
1272
+ return function (collection, object) {
1273
+ if(isUndefined(object)) return collection;
1274
+ collection = isObject(collection)
1275
+ ? toArray(collection)
1276
+ : collection;
1277
+
1278
+ return collection.filter(function (elm) {
1279
+ return objectContains(object, elm);
1280
+ });
1281
+ }
1282
+ });
1283
+
1284
+ /**
1285
+ * @ngdoc filter
1286
+ * @name xor
1287
+ * @kind function
1288
+ *
1289
+ * @description
1290
+ * Exclusive or filter by expression
1291
+ */
1292
+
1293
+ angular.module('a8m.xor', [])
1294
+
1295
+ .filter('xor', ['$parse', function($parse) {
1296
+ return function (col1, col2, expression) {
1297
+
1298
+ expression = expression || false;
1299
+
1300
+ col1 = isObject(col1) ? toArray(col1) : col1;
1301
+ col2 = isObject(col2) ? toArray(col2) : col2;
1302
+
1303
+ if(!isArray(col1) || !isArray(col2)) return col1;
1304
+
1305
+ return col1.concat(col2)
1306
+ .filter(function(elm) {
1307
+ return !(some(elm, col1) && some(elm, col2));
1308
+ });
1309
+
1310
+ function some(el, col) {
1311
+ var getter = $parse(expression);
1312
+ return col.some(function(dElm) {
1313
+ return expression
1314
+ ? equals(getter(dElm), getter(el))
1315
+ : equals(dElm, el);
1316
+ });
1317
+ }
1318
+ }
1319
+ }]);
1320
+
1321
+ /**
1322
+ * @ngdoc filter
1323
+ * @name formatBytes
1324
+ * @kind function
1325
+ *
1326
+ * @description
1327
+ * Convert bytes into appropriate display
1328
+ * 1024 bytes => 1 KB
1329
+ */
1330
+ angular.module('a8m.math.byteFmt', ['a8m.math'])
1331
+ .filter('byteFmt', ['$math', function ($math) {
1332
+ return function (bytes, decimal) {
1333
+
1334
+ if(isNumber(decimal) && isFinite(decimal) && decimal%1===0 && decimal >= 0 &&
1335
+ isNumber(bytes) && isFinite(bytes)) {
1336
+ if(bytes < 1024) { // within 1 KB so B
1337
+ return convertToDecimal(bytes, decimal, $math) + ' B';
1338
+ } else if(bytes < 1048576) { // within 1 MB so KB
1339
+ return convertToDecimal((bytes / 1024), decimal, $math) + ' KB';
1340
+ } else if(bytes < 1073741824){ // within 1 GB so MB
1341
+ return convertToDecimal((bytes / 1048576), decimal, $math) + ' MB';
1342
+ } else { // GB or more
1343
+ return convertToDecimal((bytes / 1073741824), decimal, $math) + ' GB';
1344
+ }
1345
+
1346
+ }
1347
+ return "NaN";
1348
+ }
1349
+ }]);
1350
+ /**
1351
+ * @ngdoc filter
1352
+ * @name degrees
1353
+ * @kind function
1354
+ *
1355
+ * @description
1356
+ * Convert angle from radians to degrees
1357
+ */
1358
+ angular.module('a8m.math.degrees', ['a8m.math'])
1359
+ .filter('degrees', ['$math', function ($math) {
1360
+ return function (radians, decimal) {
1361
+ // if decimal is not an integer greater than -1, we cannot do. quit with error "NaN"
1362
+ // if degrees is not a real number, we cannot do also. quit with error "NaN"
1363
+ if(isNumber(decimal) && isFinite(decimal) && decimal%1===0 && decimal >= 0 &&
1364
+ isNumber(radians) && isFinite(radians)) {
1365
+ var degrees = (radians * 180) / $math.PI;
1366
+ return $math.round(degrees * $math.pow(10,decimal)) / ($math.pow(10,decimal));
1367
+ } else {
1368
+ return "NaN";
1369
+ }
1370
+ }
1371
+ }]);
1372
+
1373
+
1374
+
1375
+ /**
1376
+ * @ngdoc filter
1377
+ * @name formatBytes
1378
+ * @kind function
1379
+ *
1380
+ * @description
1381
+ * Convert bytes into appropriate display
1382
+ * 1024 kilobytes => 1 MB
1383
+ */
1384
+ angular.module('a8m.math.kbFmt', ['a8m.math'])
1385
+ .filter('kbFmt', ['$math', function ($math) {
1386
+ return function (bytes, decimal) {
1387
+
1388
+ if(isNumber(decimal) && isFinite(decimal) && decimal%1===0 && decimal >= 0 &&
1389
+ isNumber(bytes) && isFinite(bytes)) {
1390
+ if(bytes < 1024) { // within 1 MB so KB
1391
+ return convertToDecimal(bytes, decimal, $math) + ' KB';
1392
+ } else if(bytes < 1048576) { // within 1 GB so MB
1393
+ return convertToDecimal((bytes / 1024), decimal, $math) + ' MB';
1394
+ } else {
1395
+ return convertToDecimal((bytes / 1048576), decimal, $math) + ' GB';
1396
+ }
1397
+ }
1398
+ return "NaN";
1399
+ }
1400
+ }]);
1401
+ /**
1402
+ * @ngdoc module
1403
+ * @name math
1404
+ * @description
1405
+ * reference to global Math object
1406
+ */
1407
+ angular.module('a8m.math', [])
1408
+ .factory('$math', ['$window', function ($window) {
1409
+ return $window.Math;
1410
+ }]);
1411
+
1412
+ /**
1413
+ * @ngdoc filter
1414
+ * @name max
1415
+ * @kind function
1416
+ *
1417
+ * @description
1418
+ * Math.max will get an array and return the max value. if an expression
1419
+ * is provided, will return max value by expression.
1420
+ */
1421
+ angular.module('a8m.math.max', ['a8m.math'])
1422
+ .filter('max', ['$math', '$parse', function ($math, $parse) {
1423
+ return function (input, expression) {
1424
+
1425
+ if(!isArray(input)) {
1426
+ return input;
1427
+ }
1428
+ return isUndefined(expression)
1429
+ ? $math.max.apply($math, input)
1430
+ : input[indexByMax(input, expression)];
1431
+ };
1432
+
1433
+ /**
1434
+ * @private
1435
+ * @param array
1436
+ * @param exp
1437
+ * @returns {number|*|Number}
1438
+ */
1439
+ function indexByMax(array, exp) {
1440
+ var mappedArray = array.map(function(elm){
1441
+ return $parse(exp)(elm);
1442
+ });
1443
+ return mappedArray.indexOf($math.max.apply($math, mappedArray));
1444
+ }
1445
+ }]);
1446
+ /**
1447
+ * @ngdoc filter
1448
+ * @name min
1449
+ * @kind function
1450
+ *
1451
+ * @description
1452
+ * Math.min will get an array and return the min value. if an expression
1453
+ * is provided, will return min value by expression.
1454
+ */
1455
+ angular.module('a8m.math.min', ['a8m.math'])
1456
+ .filter('min', ['$math', '$parse', function ($math, $parse) {
1457
+ return function (input, expression) {
1458
+
1459
+ if(!isArray(input)) {
1460
+ return input;
1461
+ }
1462
+ return isUndefined(expression)
1463
+ ? $math.min.apply($math, input)
1464
+ : input[indexByMin(input, expression)];
1465
+ };
1466
+
1467
+ /**
1468
+ * @private
1469
+ * @param array
1470
+ * @param exp
1471
+ * @returns {number|*|Number}
1472
+ */
1473
+ function indexByMin(array, exp) {
1474
+ var mappedArray = array.map(function(elm){
1475
+ return $parse(exp)(elm);
1476
+ });
1477
+ return mappedArray.indexOf($math.min.apply($math, mappedArray));
1478
+ }
1479
+ }]);
1480
+ /**
1481
+ * @ngdoc filter
1482
+ * @name Percent
1483
+ * @kind function
1484
+ *
1485
+ * @description
1486
+ * percentage between two numbers
1487
+ */
1488
+ angular.module('a8m.math.percent', ['a8m.math'])
1489
+ .filter('percent', ['$math', '$window', function ($math, $window) {
1490
+ return function (input, divided, round) {
1491
+
1492
+ var divider = isString(input) ? $window.Number(input) : input;
1493
+ divided = divided || 100;
1494
+ round = round || false;
1495
+
1496
+ if (!isNumber(divider) || $window.isNaN(divider)) return input;
1497
+
1498
+ return round
1499
+ ? $math.round((divider / divided) * 100)
1500
+ : (divider / divided) * 100;
1501
+ }
1502
+ }]);
1503
+
1504
+ /**
1505
+ * @ngdoc filter
1506
+ * @name toRadians
1507
+ * @kind function
1508
+ *
1509
+ * @description
1510
+ * Convert angle from degrees to radians
1511
+ */
1512
+ angular.module('a8m.math.radians', ['a8m.math'])
1513
+ .filter('radians', ['$math', function ($math) {
1514
+ return function (degrees, decimal) {
1515
+ // if decimal is not an integer greater than -1, we cannot do. quit with error "NaN"
1516
+ // if degrees is not a real number, we cannot do also. quit with error "NaN"
1517
+ if(isNumber(decimal) && isFinite(decimal) && decimal%1===0 && decimal >= 0 &&
1518
+ isNumber(degrees) && isFinite(degrees)) {
1519
+ var radians = (degrees * 3.14159265359) / 180;
1520
+ return $math.round(radians * $math.pow(10,decimal)) / ($math.pow(10,decimal));
1521
+ }
1522
+ return "NaN";
1523
+ }
1524
+ }]);
1525
+
1526
+
1527
+
1528
+ /**
1529
+ * @ngdoc filter
1530
+ * @name Radix
1531
+ * @kind function
1532
+ *
1533
+ * @description
1534
+ * converting decimal numbers to different bases(radix)
1535
+ */
1536
+ angular.module('a8m.math.radix', [])
1537
+ .filter('radix', function () {
1538
+ return function (input, radix) {
1539
+ var RANGE = /^[2-9]$|^[1-2]\d$|^3[0-6]$/;
1540
+
1541
+ if(!isNumber(input) || !RANGE.test(radix)) {
1542
+ return input;
1543
+ }
1544
+
1545
+ return input.toString(radix).toUpperCase();
1546
+ }
1547
+ });
1548
+
1549
+ /**
1550
+ * @ngdoc filter
1551
+ * @name formatBytes
1552
+ * @kind function
1553
+ *
1554
+ * @description
1555
+ * Convert number into abbreviations.
1556
+ * i.e: K for one thousand, M for Million, B for billion
1557
+ * e.g: number of users:235,221, decimal:1 => 235.2 K
1558
+ */
1559
+ angular.module('a8m.math.shortFmt', ['a8m.math'])
1560
+ .filter('shortFmt', ['$math', function ($math) {
1561
+ return function (number, decimal) {
1562
+ if(isNumber(decimal) && isFinite(decimal) && decimal%1===0 && decimal >= 0 &&
1563
+ isNumber(number) && isFinite(number)){
1564
+ if(number < 1e3) {
1565
+ return number;
1566
+ } else if(number < 1e6) {
1567
+ return convertToDecimal((number / 1e3), decimal, $math) + ' K';
1568
+ } else if(number < 1e9){
1569
+ return convertToDecimal((number / 1e6), decimal, $math) + ' M';
1570
+ } else {
1571
+ return convertToDecimal((number / 1e9), decimal, $math) + ' B';
1572
+ }
1573
+
1574
+ }
1575
+ return "NaN";
1576
+ }
1577
+ }]);
1578
+ /**
1579
+ * @ngdoc filter
1580
+ * @name sum
1581
+ * @kind function
1582
+ *
1583
+ * @description
1584
+ * Sum up all values within an array
1585
+ */
1586
+ angular.module('a8m.math.sum', [])
1587
+ .filter('sum', function () {
1588
+ return function (input, initial) {
1589
+ return !isArray(input)
1590
+ ? input
1591
+ : input.reduce(function(prev, curr) {
1592
+ return prev + curr;
1593
+ }, initial || 0);
1594
+ }
1595
+ });
1596
+
1597
+ /**
1598
+ * @ngdoc filter
1599
+ * @name endsWith
1600
+ * @kind function
1601
+ *
1602
+ * @description
1603
+ * checks whether string ends with the ends parameter.
1604
+ */
1605
+ angular.module('a8m.ends-with', [])
1606
+
1607
+ .filter('endsWith', function () {
1608
+ return function (input, ends, csensitive) {
1609
+
1610
+ var sensitive = csensitive || false,
1611
+ position;
1612
+
1613
+ if(!isString(input) || isUndefined(ends)) {
1614
+ return input;
1615
+ }
1616
+
1617
+ input = (sensitive) ? input : input.toLowerCase();
1618
+ position = input.length - ends.length;
1619
+
1620
+ return input.indexOf((sensitive) ? ends : ends.toLowerCase(), position) !== -1;
1621
+ }
1622
+ });
1623
+
1624
+ /**
1625
+ * @ngdoc filter
1626
+ * @name latinize
1627
+ * @kind function
1628
+ *
1629
+ * @description
1630
+ * remove accents/diacritics from a string
1631
+ */
1632
+ angular.module('a8m.latinize', [])
1633
+ .filter('latinize',[ function () {
1634
+ var defaultDiacriticsRemovalap = [
1635
+ {'base':'A', 'letters':'\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F'},
1636
+ {'base':'AA','letters':'\uA732'},
1637
+ {'base':'AE','letters':'\u00C6\u01FC\u01E2'},
1638
+ {'base':'AO','letters':'\uA734'},
1639
+ {'base':'AU','letters':'\uA736'},
1640
+ {'base':'AV','letters':'\uA738\uA73A'},
1641
+ {'base':'AY','letters':'\uA73C'},
1642
+ {'base':'B', 'letters':'\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181'},
1643
+ {'base':'C', 'letters':'\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E'},
1644
+ {'base':'D', 'letters':'\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779'},
1645
+ {'base':'DZ','letters':'\u01F1\u01C4'},
1646
+ {'base':'Dz','letters':'\u01F2\u01C5'},
1647
+ {'base':'E', 'letters':'\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E'},
1648
+ {'base':'F', 'letters':'\u0046\u24BB\uFF26\u1E1E\u0191\uA77B'},
1649
+ {'base':'G', 'letters':'\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E'},
1650
+ {'base':'H', 'letters':'\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D'},
1651
+ {'base':'I', 'letters':'\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197'},
1652
+ {'base':'J', 'letters':'\u004A\u24BF\uFF2A\u0134\u0248'},
1653
+ {'base':'K', 'letters':'\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2'},
1654
+ {'base':'L', 'letters':'\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780'},
1655
+ {'base':'LJ','letters':'\u01C7'},
1656
+ {'base':'Lj','letters':'\u01C8'},
1657
+ {'base':'M', 'letters':'\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C'},
1658
+ {'base':'N', 'letters':'\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4'},
1659
+ {'base':'NJ','letters':'\u01CA'},
1660
+ {'base':'Nj','letters':'\u01CB'},
1661
+ {'base':'O', 'letters':'\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C'},
1662
+ {'base':'OI','letters':'\u01A2'},
1663
+ {'base':'OO','letters':'\uA74E'},
1664
+ {'base':'OU','letters':'\u0222'},
1665
+ {'base':'OE','letters':'\u008C\u0152'},
1666
+ {'base':'oe','letters':'\u009C\u0153'},
1667
+ {'base':'P', 'letters':'\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754'},
1668
+ {'base':'Q', 'letters':'\u0051\u24C6\uFF31\uA756\uA758\u024A'},
1669
+ {'base':'R', 'letters':'\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782'},
1670
+ {'base':'S', 'letters':'\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784'},
1671
+ {'base':'T', 'letters':'\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786'},
1672
+ {'base':'TZ','letters':'\uA728'},
1673
+ {'base':'U', 'letters':'\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244'},
1674
+ {'base':'V', 'letters':'\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245'},
1675
+ {'base':'VY','letters':'\uA760'},
1676
+ {'base':'W', 'letters':'\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72'},
1677
+ {'base':'X', 'letters':'\u0058\u24CD\uFF38\u1E8A\u1E8C'},
1678
+ {'base':'Y', 'letters':'\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE'},
1679
+ {'base':'Z', 'letters':'\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762'},
1680
+ {'base':'a', 'letters':'\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250'},
1681
+ {'base':'aa','letters':'\uA733'},
1682
+ {'base':'ae','letters':'\u00E6\u01FD\u01E3'},
1683
+ {'base':'ao','letters':'\uA735'},
1684
+ {'base':'au','letters':'\uA737'},
1685
+ {'base':'av','letters':'\uA739\uA73B'},
1686
+ {'base':'ay','letters':'\uA73D'},
1687
+ {'base':'b', 'letters':'\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253'},
1688
+ {'base':'c', 'letters':'\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184'},
1689
+ {'base':'d', 'letters':'\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A'},
1690
+ {'base':'dz','letters':'\u01F3\u01C6'},
1691
+ {'base':'e', 'letters':'\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD'},
1692
+ {'base':'f', 'letters':'\u0066\u24D5\uFF46\u1E1F\u0192\uA77C'},
1693
+ {'base':'g', 'letters':'\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F'},
1694
+ {'base':'h', 'letters':'\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265'},
1695
+ {'base':'hv','letters':'\u0195'},
1696
+ {'base':'i', 'letters':'\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131'},
1697
+ {'base':'j', 'letters':'\u006A\u24D9\uFF4A\u0135\u01F0\u0249'},
1698
+ {'base':'k', 'letters':'\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3'},
1699
+ {'base':'l', 'letters':'\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747'},
1700
+ {'base':'lj','letters':'\u01C9'},
1701
+ {'base':'m', 'letters':'\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F'},
1702
+ {'base':'n', 'letters':'\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5'},
1703
+ {'base':'nj','letters':'\u01CC'},
1704
+ {'base':'o', 'letters':'\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275'},
1705
+ {'base':'oi','letters':'\u01A3'},
1706
+ {'base':'ou','letters':'\u0223'},
1707
+ {'base':'oo','letters':'\uA74F'},
1708
+ {'base':'p','letters':'\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755'},
1709
+ {'base':'q','letters':'\u0071\u24E0\uFF51\u024B\uA757\uA759'},
1710
+ {'base':'r','letters':'\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783'},
1711
+ {'base':'s','letters':'\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B'},
1712
+ {'base':'t','letters':'\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787'},
1713
+ {'base':'tz','letters':'\uA729'},
1714
+ {'base':'u','letters': '\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289'},
1715
+ {'base':'v','letters':'\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C'},
1716
+ {'base':'vy','letters':'\uA761'},
1717
+ {'base':'w','letters':'\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73'},
1718
+ {'base':'x','letters':'\u0078\u24E7\uFF58\u1E8B\u1E8D'},
1719
+ {'base':'y','letters':'\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF'},
1720
+ {'base':'z','letters':'\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763'}
1721
+ ];
1722
+
1723
+ var diacriticsMap = {};
1724
+ for (var i = 0; i < defaultDiacriticsRemovalap.length; i++) {
1725
+ var letters = defaultDiacriticsRemovalap[i].letters.split("");
1726
+ for (var j = 0; j < letters.length ; j++){
1727
+ diacriticsMap[letters[j]] = defaultDiacriticsRemovalap[i].base;
1728
+ }
1729
+ }
1730
+
1731
+ // "what?" version ... http://jsperf.com/diacritics/12
1732
+ function removeDiacritics (str) {
1733
+ return str.replace(/[^\u0000-\u007E]/g, function(a){
1734
+ return diacriticsMap[a] || a;
1735
+ });
1736
+ }
1737
+
1738
+ return function (input) {
1739
+
1740
+ return isString(input)
1741
+ ? removeDiacritics(input)
1742
+ : input;
1743
+ }
1744
+ }]);
1745
+
1746
+ /**
1747
+ * @ngdoc filter
1748
+ * @name ltrim
1749
+ * @kind function
1750
+ *
1751
+ * @description
1752
+ * Left trim. Similar to trimFilter, but only for left side.
1753
+ */
1754
+ angular.module('a8m.ltrim', [])
1755
+ .filter('ltrim', function () {
1756
+ return function(input, chars) {
1757
+
1758
+ var trim = chars || '\\s';
1759
+
1760
+ return isString(input)
1761
+ ? input.replace(new RegExp('^' + trim + '+'), '')
1762
+ : input;
1763
+ }
1764
+ });
1765
+
1766
+ /**
1767
+ * @ngdoc filter
1768
+ * @name match
1769
+ * @kind function
1770
+ *
1771
+ * @description
1772
+ * Return the matched pattern in a string.
1773
+ */
1774
+ angular.module('a8m.match', [])
1775
+ .filter('match', function () {
1776
+ return function (input, pattern, flag) {
1777
+
1778
+ var reg = new RegExp(pattern, flag);
1779
+
1780
+ return isString(input)
1781
+ ? input.match(reg)
1782
+ : null;
1783
+ }
1784
+ });
1785
+
1786
+ /**
1787
+ * @ngdoc filter
1788
+ * @name repeat
1789
+ * @kind function
1790
+ *
1791
+ * @description
1792
+ * Repeats a string n times
1793
+ */
1794
+ angular.module('a8m.repeat', [])
1795
+ .filter('repeat',[ function () {
1796
+ return function (input, n, separator) {
1797
+
1798
+ var times = ~~n;
1799
+
1800
+ if(!isString(input)) {
1801
+ return input;
1802
+ }
1803
+
1804
+ return !times
1805
+ ? input
1806
+ : strRepeat(input, --n, separator || '');
1807
+ }
1808
+ }]);
1809
+
1810
+ /**
1811
+ * Repeats a string n times with given separator
1812
+ * @param str string to repeat
1813
+ * @param n number of times
1814
+ * @param sep separator
1815
+ * @returns {*}
1816
+ */
1817
+ function strRepeat(str, n, sep) {
1818
+ if(!n) {
1819
+ return str;
1820
+ }
1821
+ return str + sep + strRepeat(str, --n, sep);
1822
+ }
1823
+ /**
1824
+ * @ngdoc filter
1825
+ * @name rtrim
1826
+ * @kind function
1827
+ *
1828
+ * @description
1829
+ * Right trim. Similar to trimFilter, but only for right side.
1830
+ */
1831
+ angular.module('a8m.rtrim', [])
1832
+ .filter('rtrim', function () {
1833
+ return function(input, chars) {
1834
+
1835
+ var trim = chars || '\\s';
1836
+
1837
+ return isString(input)
1838
+ ? input.replace(new RegExp(trim + '+$'), '')
1839
+ : input;
1840
+ }
1841
+ });
1842
+
1843
+ /**
1844
+ * @ngdoc filter
1845
+ * @name slugify
1846
+ * @kind function
1847
+ *
1848
+ * @description
1849
+ * remove spaces from string, replace with "-" or given argument
1850
+ */
1851
+ angular.module('a8m.slugify', [])
1852
+ .filter('slugify',[ function () {
1853
+ return function (input, sub) {
1854
+
1855
+ var replace = (isUndefined(sub)) ? '-' : sub;
1856
+
1857
+ return isString(input)
1858
+ ? input.toLowerCase().replace(/\s+/g, replace)
1859
+ : input;
1860
+ }
1861
+ }]);
1862
+
1863
+ /**
1864
+ * @ngdoc filter
1865
+ * @name startWith
1866
+ * @kind function
1867
+ *
1868
+ * @description
1869
+ * checks whether string starts with the starts parameter.
1870
+ */
1871
+ angular.module('a8m.starts-with', [])
1872
+ .filter('startsWith', function () {
1873
+ return function (input, start, csensitive) {
1874
+
1875
+ var sensitive = csensitive || false;
1876
+
1877
+ if(!isString(input) || isUndefined(start)) {
1878
+ return input;
1879
+ }
1880
+
1881
+ input = (sensitive) ? input : input.toLowerCase();
1882
+
1883
+ return !input.indexOf((sensitive) ? start : start.toLowerCase());
1884
+ }
1885
+ });
1886
+
1887
+ /**
1888
+ * @ngdoc filter
1889
+ * @name stringular
1890
+ * @kind function
1891
+ *
1892
+ * @description
1893
+ * get string with {n} and replace match with enumeration values
1894
+ */
1895
+ angular.module('a8m.stringular', [])
1896
+ .filter('stringular', function () {
1897
+ return function(input) {
1898
+
1899
+ var args = Array.prototype.slice.call(arguments, 1);
1900
+
1901
+ return input.replace(/{(\d+)}/g, function (match, number) {
1902
+ return isUndefined(args[number]) ? match : args[number];
1903
+ });
1904
+ }
1905
+ });
1906
+
1907
+ /**
1908
+ * @ngdoc filter
1909
+ * @name stripTags
1910
+ * @kind function
1911
+ *
1912
+ * @description
1913
+ * strip html tags from string
1914
+ */
1915
+ angular.module('a8m.strip-tags', [])
1916
+ .filter('stripTags', function () {
1917
+ return function(input) {
1918
+ return isString(input)
1919
+ ? input.replace(/<\S[^><]*>/g, '')
1920
+ : input;
1921
+ }
1922
+ });
1923
+
1924
+ /**
1925
+ * @ngdoc filter
1926
+ * @name test
1927
+ * @kind function
1928
+ *
1929
+ * @description
1930
+ * test if a string match a pattern.
1931
+ */
1932
+ angular.module('a8m.test', [])
1933
+ .filter('test', function () {
1934
+ return function (input, pattern, flag) {
1935
+
1936
+ var reg = new RegExp(pattern, flag);
1937
+
1938
+ return isString(input)
1939
+ ? reg.test(input)
1940
+ : input;
1941
+ }
1942
+ });
1943
+
1944
+ /**
1945
+ * @ngdoc filter
1946
+ * @name trim
1947
+ * @kind function
1948
+ *
1949
+ * @description
1950
+ * Strip whitespace (or other characters) from the beginning and end of a string
1951
+ */
1952
+ angular.module('a8m.trim', [])
1953
+ .filter('trim', function () {
1954
+ return function(input, chars) {
1955
+
1956
+ var trim = chars || '\\s';
1957
+
1958
+ return isString(input)
1959
+ ? input.replace(new RegExp('^' + trim + '+|' + trim + '+$', 'g'), '')
1960
+ : input;
1961
+ }
1962
+ });
1963
+
1964
+ /**
1965
+ * @ngdoc filter
1966
+ * @name truncate
1967
+ * @kind function
1968
+ *
1969
+ * @description
1970
+ * truncates a string given a specified length, providing a custom string to denote an omission.
1971
+ */
1972
+ angular.module('a8m.truncate', [])
1973
+ .filter('truncate', function () {
1974
+ return function(input, length, suffix, preserve) {
1975
+
1976
+ length = isUndefined(length) ? input.length : length;
1977
+ preserve = preserve || false;
1978
+ suffix = suffix || '';
1979
+
1980
+ if(!isString(input) || (input.length <= length)) return input;
1981
+
1982
+ return input.substring(0, (preserve)
1983
+ ? ((input.indexOf(' ', length) === -1) ? input.length : input.indexOf(' ', length))
1984
+ : length) + suffix;
1985
+ };
1986
+ });
1987
+
1988
+ /**
1989
+ * @ngdoc filter
1990
+ * @name ucfirst
1991
+ * @kind function
1992
+ *
1993
+ * @description
1994
+ * ucfirst
1995
+ */
1996
+ angular.module('a8m.ucfirst', [])
1997
+ .filter('ucfirst', [function() {
1998
+ return function(input) {
1999
+ return isString(input)
2000
+ ? input
2001
+ .split(' ')
2002
+ .map(function (ch) {
2003
+ return ch.charAt(0).toUpperCase() + ch.substring(1);
2004
+ })
2005
+ .join(' ')
2006
+ : input;
2007
+ }
2008
+ }]);
2009
+
2010
+ /**
2011
+ * @ngdoc filter
2012
+ * @name uriComponentEncode
2013
+ * @kind function
2014
+ *
2015
+ * @description
2016
+ * get string as parameter and return encoded string
2017
+ */
2018
+ angular.module('a8m.uri-component-encode', [])
2019
+ .filter('uriComponentEncode',['$window', function ($window) {
2020
+ return function (input) {
2021
+ return isString(input)
2022
+ ? $window.encodeURIComponent(input)
2023
+ : input;
2024
+ }
2025
+ }]);
2026
+
2027
+ /**
2028
+ * @ngdoc filter
2029
+ * @name uriEncode
2030
+ * @kind function
2031
+ *
2032
+ * @description
2033
+ * get string as parameter and return encoded string
2034
+ */
2035
+ angular.module('a8m.uri-encode', [])
2036
+ .filter('uriEncode',['$window', function ($window) {
2037
+ return function (input) {
2038
+ return isString(input)
2039
+ ? $window.encodeURI(input)
2040
+ : input;
2041
+ }
2042
+ }]);
2043
+
2044
+ /**
2045
+ * @ngdoc filter
2046
+ * @name wrap
2047
+ * @kind function
2048
+ *
2049
+ * @description
2050
+ * Wrap a string with another string
2051
+ */
2052
+ angular.module('a8m.wrap', [])
2053
+ .filter('wrap', function () {
2054
+ return function(input, wrap, ends) {
2055
+ return isString(input) && isDefined(wrap)
2056
+ ? [wrap, input, ends || wrap].join('')
2057
+ : input;
2058
+ }
2059
+ });
2060
+
2061
+ /**
2062
+ * @ngdoc provider
2063
+ * @name filterWatcher
2064
+ * @kind function
2065
+ *
2066
+ * @description
2067
+ * store specific filters result in $$cache, based on scope life time(avoid memory leak).
2068
+ * on scope.$destroy remove it's cache from $$cache container
2069
+ */
2070
+
2071
+ angular.module('a8m.filter-watcher', [])
2072
+ .provider('filterWatcher', function() {
2073
+
2074
+ this.$get = ['$window', '$rootScope', function($window, $rootScope) {
2075
+
2076
+ /**
2077
+ * Cache storing
2078
+ * @type {Object}
2079
+ */
2080
+ var $$cache = {};
2081
+
2082
+ /**
2083
+ * Scope listeners container
2084
+ * scope.$destroy => remove all cache keys
2085
+ * bind to current scope.
2086
+ * @type {Object}
2087
+ */
2088
+ var $$listeners = {};
2089
+
2090
+ /**
2091
+ * $timeout without triggering the digest cycle
2092
+ * @type {function}
2093
+ */
2094
+ var $$timeout = $window.setTimeout;
2095
+
2096
+ /**
2097
+ * @description
2098
+ * get `HashKey` string based on the given arguments.
2099
+ * @param fName
2100
+ * @param args
2101
+ * @returns {string}
2102
+ */
2103
+ function getHashKey(fName, args) {
2104
+ function replacerFactory() {
2105
+ var cache = [];
2106
+ return function(key, val) {
2107
+ if(isObject(val) && !isNull(val)) {
2108
+ if (~cache.indexOf(val)) return '[Circular]';
2109
+ cache.push(val)
2110
+ }
2111
+ if($window == val) return '$WINDOW';
2112
+ if($window.document == val) return '$DOCUMENT';
2113
+ if(isScope(val)) return '$SCOPE';
2114
+ return val;
2115
+ }
2116
+ }
2117
+ return [fName, JSON.stringify(args, replacerFactory())]
2118
+ .join('#')
2119
+ .replace(/"/g,'');
2120
+ }
2121
+
2122
+ /**
2123
+ * @description
2124
+ * fir on $scope.$destroy,
2125
+ * remove cache based scope from `$$cache`,
2126
+ * and remove itself from `$$listeners`
2127
+ * @param event
2128
+ */
2129
+ function removeCache(event) {
2130
+ var id = event.targetScope.$id;
2131
+ forEach($$listeners[id], function(key) {
2132
+ delete $$cache[key];
2133
+ });
2134
+ delete $$listeners[id];
2135
+ }
2136
+
2137
+ /**
2138
+ * @description
2139
+ * for angular version that greater than v.1.3.0
2140
+ * it clear cache when the digest cycle is end.
2141
+ */
2142
+ function cleanStateless() {
2143
+ $$timeout(function() {
2144
+ if(!$rootScope.$$phase)
2145
+ $$cache = {};
2146
+ }, 2000);
2147
+ }
2148
+
2149
+ /**
2150
+ * @description
2151
+ * Store hashKeys in $$listeners container
2152
+ * on scope.$destroy, remove them all(bind an event).
2153
+ * @param scope
2154
+ * @param hashKey
2155
+ * @returns {*}
2156
+ */
2157
+ function addListener(scope, hashKey) {
2158
+ var id = scope.$id;
2159
+ if(isUndefined($$listeners[id])) {
2160
+ scope.$on('$destroy', removeCache);
2161
+ $$listeners[id] = [];
2162
+ }
2163
+ return $$listeners[id].push(hashKey);
2164
+ }
2165
+
2166
+ /**
2167
+ * @description
2168
+ * return the `cacheKey` or undefined.
2169
+ * @param filterName
2170
+ * @param args
2171
+ * @returns {*}
2172
+ */
2173
+ function $$isMemoized(filterName, args) {
2174
+ var hashKey = getHashKey(filterName, args);
2175
+ return $$cache[hashKey];
2176
+ }
2177
+
2178
+ /**
2179
+ * @description
2180
+ * store `result` in `$$cache` container, based on the hashKey.
2181
+ * add $destroy listener and return result
2182
+ * @param filterName
2183
+ * @param args
2184
+ * @param scope
2185
+ * @param result
2186
+ * @returns {*}
2187
+ */
2188
+ function $$memoize(filterName, args, scope, result) {
2189
+ var hashKey = getHashKey(filterName, args);
2190
+ //store result in `$$cache` container
2191
+ $$cache[hashKey] = result;
2192
+ // for angular versions that less than 1.3
2193
+ // add to `$destroy` listener, a cleaner callback
2194
+ if(isScope(scope)) {
2195
+ addListener(scope, hashKey);
2196
+ } else {
2197
+ cleanStateless();
2198
+ }
2199
+ return result;
2200
+ }
2201
+
2202
+ return {
2203
+ isMemoized: $$isMemoized,
2204
+ memoize: $$memoize
2205
+ }
2206
+ }];
2207
+ });
2208
+
2209
+
2210
+ /**
2211
+ * @ngdoc module
2212
+ * @name angular.filters
2213
+ * @description
2214
+ * Bunch of useful filters for angularJS
2215
+ */
2216
+
2217
+ angular.module('angular.filter', [
2218
+
2219
+ 'a8m.ucfirst',
2220
+ 'a8m.uri-encode',
2221
+ 'a8m.uri-component-encode',
2222
+ 'a8m.slugify',
2223
+ 'a8m.latinize',
2224
+ 'a8m.strip-tags',
2225
+ 'a8m.stringular',
2226
+ 'a8m.truncate',
2227
+ 'a8m.starts-with',
2228
+ 'a8m.ends-with',
2229
+ 'a8m.wrap',
2230
+ 'a8m.trim',
2231
+ 'a8m.ltrim',
2232
+ 'a8m.rtrim',
2233
+ 'a8m.repeat',
2234
+ 'a8m.test',
2235
+ 'a8m.match',
2236
+
2237
+ 'a8m.to-array',
2238
+ 'a8m.concat',
2239
+ 'a8m.contains',
2240
+ 'a8m.unique',
2241
+ 'a8m.is-empty',
2242
+ 'a8m.after',
2243
+ 'a8m.after-where',
2244
+ 'a8m.before',
2245
+ 'a8m.before-where',
2246
+ 'a8m.defaults',
2247
+ 'a8m.where',
2248
+ 'a8m.reverse',
2249
+ 'a8m.remove',
2250
+ 'a8m.remove-with',
2251
+ 'a8m.group-by',
2252
+ 'a8m.count-by',
2253
+ 'a8m.chunk-by',
2254
+ 'a8m.search-field',
2255
+ 'a8m.fuzzy-by',
2256
+ 'a8m.fuzzy',
2257
+ 'a8m.omit',
2258
+ 'a8m.pick',
2259
+ 'a8m.every',
2260
+ 'a8m.filter-by',
2261
+ 'a8m.xor',
2262
+ 'a8m.map',
2263
+ 'a8m.first',
2264
+ 'a8m.last',
2265
+ 'a8m.flatten',
2266
+ 'a8m.join',
2267
+ 'a8m.range',
2268
+
2269
+ 'a8m.math',
2270
+ 'a8m.math.max',
2271
+ 'a8m.math.min',
2272
+ 'a8m.math.percent',
2273
+ 'a8m.math.radix',
2274
+ 'a8m.math.sum',
2275
+ 'a8m.math.degrees',
2276
+ 'a8m.math.radians',
2277
+ 'a8m.math.byteFmt',
2278
+ 'a8m.math.kbFmt',
2279
+ 'a8m.math.shortFmt',
2280
+
2281
+ 'a8m.angular',
2282
+ 'a8m.conditions',
2283
+ 'a8m.is-null',
2284
+
2285
+ 'a8m.filter-watcher'
2286
+ ]);
2287
+ })( window, window.angular );