UNPKG

30.8 kBJavaScriptView Raw
1/*!
2 * Snakeskin v7.3.0 (live)
3 * https://github.com/SnakeskinTpl/Snakeskin
4 *
5 * Released under the MIT license
6 * https://github.com/SnakeskinTpl/Snakeskin/blob/master/LICENSE
7 *
8 * Date: 'Thu, 14 Jun 2018 10:04:57 GMT
9 */
10
11(function (global, factory) {
12 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
13 typeof define === 'function' && define.amd ? define('Snakeskin', factory) :
14 (global.Snakeskin = factory());
15}(this, (function () { 'use strict';
16
17var Snakeskin = void 0;
18var Snakeskin$1 = Snakeskin = {
19 VERSION: [7, 3, 0]
20};
21
22/**
23 * The operation UID
24 * @type {?string}
25 */
26Snakeskin.UID = null;
27
28/**
29 * The namespace for directives
30 * @const
31 */
32Snakeskin.Directives = {};
33
34/**
35 * The namespace for filters
36 * @const
37 */
38Snakeskin.Filters = {};
39
40/**
41 * The namespace for super-global variables
42 * @const
43 */
44Snakeskin.Vars = {};
45
46/**
47 * The namespace for local variables
48 * @const
49 */
50Snakeskin.LocalVars = {};
51
52/**
53 * The cache of templates
54 * @const
55 */
56Snakeskin.cache = {};
57
58Array.isArray = Array.isArray || function (obj) {
59 return {}.call(obj) === '[object Array]';
60};
61
62String.prototype.trim = String.prototype.trim || function () {
63 var str = this.replace(/^\s\s*/, '');
64
65 var i = str.length;
66
67 for (var rgxp = /\s/; rgxp.test(str.charAt(--i));) {
68 // Do nothing
69 }
70
71 return str.substring(0, i + 1);
72};
73
74/**
75 * Returns true if the specified value is a function
76 *
77 * @param {?} obj - source value
78 * @return {boolean}
79 */
80function isFunction(obj) {
81 return typeof obj === 'function';
82}
83
84/**
85 * Returns true if the specified value is a number
86 *
87 * @param {?} obj - source value
88 * @return {boolean}
89 */
90
91
92/**
93 * Returns true if the specified value is a string
94 *
95 * @param {?} obj - source value
96 * @return {boolean}
97 */
98function isString(obj) {
99 return typeof obj === 'string';
100}
101
102/**
103 * Returns true if the specified value is a boolean
104 *
105 * @param {?} obj - source value
106 * @return {boolean}
107 */
108
109
110/**
111 * Returns true if the specified value is an array
112 *
113 * @param {?} obj - source value
114 * @return {boolean}
115 */
116function isArray(obj) {
117 return Array.isArray(obj);
118}
119
120/**
121 * Returns true if the specified value is a plain object
122 *
123 * @param {?} obj - source value
124 * @return {boolean}
125 */
126function isObject(obj) {
127 return Boolean(obj) && obj.constructor === Object;
128}
129
130/**
131 * Special Snakeskin class for escaping HTML entities from an object
132 *
133 * @constructor
134 * @param {?} obj - source object
135 * @param {?string=} [opt_attr] - type of attribute declaration
136 */
137Snakeskin$1.HTMLObject = function (obj, opt_attr) {
138 this.value = obj;
139 this.attr = opt_attr;
140};
141
142/**
143 * StringBuffer constructor
144 *
145 * @constructor
146 * @return {!Array}
147 */
148Snakeskin$1.StringBuffer = function () {
149 return [];
150};
151
152/**
153 * @param {!Function} child
154 * @param {!Function} parent
155 */
156function inherit(child, parent) {
157 /** @constructor */
158 var F = function F() {
159 this.constructor = child;
160 };
161
162 F.prototype = parent.prototype;
163 child.prototype = new F();
164}
165
166/**
167 * Node constructor
168 * @constructor
169 */
170Snakeskin$1.Node = function () {};
171
172/**
173 * Returns the number of child elements
174 * @return {number}
175 */
176Snakeskin$1.Node.prototype.length = function () {
177 return this.value.childNodes.length;
178};
179
180/**
181 * Returns text content
182 * @return {string}
183 */
184Snakeskin$1.Node.prototype.textContent = function () {
185 return this.value.textContent;
186};
187
188/**
189 * DocumentFragment constructor
190 *
191 * @constructor
192 * @extends {Snakeskin.Node}
193 * @param {string} renderMode - rendering mode of templates
194 */
195Snakeskin$1.DocumentFragment = function (renderMode) {
196 this.renderMode = renderMode;
197 this.value = document.createDocumentFragment();
198};
199
200inherit(Snakeskin$1.DocumentFragment, Snakeskin$1.Node);
201
202/**
203 * Appends a child to the document fragment
204 * @param {?} el - element for appending
205 */
206Snakeskin$1.DocumentFragment.prototype.appendChild = function (el) {
207 this.value.appendChild(el);
208};
209
210/**
211 * Returns text content
212 * @return {string}
213 */
214Snakeskin$1.DocumentFragment.prototype.textContent = function () {
215 var children = this.value.childNodes;
216
217 var res = '';
218 for (var i = 0; i < children.length; i++) {
219 res += children[i].outerHTML || children[i].textContent;
220 }
221
222 return res;
223};
224
225/**
226 * Element constructor
227 *
228 * @constructor
229 * @extends {Snakeskin.Node}
230 *
231 * @param {string} name - element name
232 * @param {string} renderMode - rendering mode of templates
233 */
234Snakeskin$1.Element = function (name, renderMode) {
235 this.renderMode = renderMode;
236 this.value = document.createElement(name);
237};
238
239inherit(Snakeskin$1.Element, Snakeskin$1.Node);
240
241/**
242 * Appends a child to the element
243 * @param {?} el - element for appending
244 */
245Snakeskin$1.Element.prototype.appendChild = function (el) {
246 this.value.appendChild(el);
247};
248
249/**
250 * Sets an attribute to the element
251 *
252 * @param {string} name - attribute name
253 * @param {string} val - attribute value
254 */
255Snakeskin$1.Element.prototype.setAttribute = function (name, val) {
256 this.value.setAttribute(name, val);
257};
258
259/**
260 * Returns text content
261 * @return {string}
262 */
263Snakeskin$1.Element.prototype.textContent = function () {
264 return this.value.outerHTML;
265};
266
267/**
268 * Comment constructor
269 *
270 * @constructor
271 * @extends {Snakeskin.Node}
272 *
273 * @param {string} text - comment text
274 * @param {string} renderMode - rendering mode of templates
275 */
276Snakeskin$1.Comment = function (text, renderMode) {
277 this.renderMode = renderMode;
278 this.value = document.createComment(text);
279};
280
281inherit(Snakeskin$1.Comment, Snakeskin$1.Node);
282
283/**
284 * Text constructor
285 *
286 * @constructor
287 * @extends {Snakeskin.Node}
288 *
289 * @param {string} text
290 * @param {string} renderMode - rendering mode of templates
291 */
292Snakeskin$1.Text = function (text, renderMode) {
293 this.renderMode = renderMode;
294 this.value = document.createTextNode(text);
295};
296
297inherit(Snakeskin$1.Text, Snakeskin$1.Node);
298
299/**
300 * Map of inline tag names
301 * @const
302 */
303Snakeskin$1.inlineTags = {
304 'html': {
305 'area': 'href',
306 'base': 'href',
307 'br': true,
308 'col': true,
309 'embed': 'src',
310 'hr': true,
311 'img': 'src',
312 'input': 'value',
313 'link': 'href',
314 'meta': 'content',
315 'param': 'value',
316 'source': 'src',
317 'track': 'src',
318 'wbr': true
319 },
320
321 'xml': {}
322};
323
324/**
325 * Appends a value to the specified element
326 *
327 * @param {(!Snakeskin.DocumentFragment|!Snakeskin.Element)} el - base element
328 * @param {?} val - value for appending
329 * @param {string} renderMode - rendering mode of templates
330 * @return {(!Snakeskin.Element|!Snakeskin.Comment|!Snakeskin.Text)}
331 */
332Snakeskin$1.appendChild = function (el, val, renderMode) {
333 if (val instanceof Snakeskin$1.Node === false) {
334 val = new Snakeskin$1.Text(String(val), renderMode);
335 }
336
337 if (el) {
338 el.appendChild(val.value);
339 }
340
341 return val;
342};
343
344/**
345 * Sets an attribute to the specified element
346 *
347 * @param {!Snakeskin.Node} node - source element
348 * @param {string} name - attribute name
349 * @param {?} val - attribute value
350 */
351Snakeskin$1.setAttribute = function (node, name, val) {
352 node.setAttribute(name, val instanceof Snakeskin$1.Node ? val.textContent() : String(val));
353};
354
355var keys = function () {
356 return (/\[native code]/.test(Object.keys && Object.keys.toString()) && Object.keys
357 );
358}();
359
360/**
361 * Common iterator
362 * (with hasOwnProperty for objects)
363 *
364 * @param {(Array|Object|undefined)} obj - source object
365 * @param {(
366 * function(?, ?, !Array, {isFirst: boolean, isLast: boolean, length: number})|
367 * function(?, ?, !Object, {i: number, isFirst: boolean, isLast: boolean, length: number})
368 * )} callback - callback function
369 */
370Snakeskin$1.forEach = function (obj, callback) {
371 if (!obj) {
372 return;
373 }
374
375 var length = 0;
376
377 if (isArray(obj)) {
378 length = obj.length;
379 for (var i = 0; i < length; i++) {
380 if (callback(obj[i], i, obj, { isFirst: i === 0, isLast: i === length - 1, length: length }) === false) {
381 break;
382 }
383 }
384 } else if (keys) {
385 var arr = keys(obj);
386
387 length = arr.length;
388 for (var _i = 0; _i < length; _i++) {
389 if (callback(obj[arr[_i]], arr[_i], obj, { i: _i, isFirst: _i === 0, isLast: _i === length - 1, length: length }) === false) {
390 break;
391 }
392 }
393 } else {
394 if (callback.length >= 4) {
395 for (var key in obj) {
396 if (!obj.hasOwnProperty(key)) {
397 break;
398 }
399
400 length++;
401 }
402 }
403
404 var _i2 = 0;
405 for (var _key in obj) {
406 if (!obj.hasOwnProperty(_key)) {
407 break;
408 }
409
410 if (callback(obj[_key], _key, obj, { i: _i2, isFirst: _i2 === 0, isLast: _i2 === length - 1, length: length }) === false) {
411 break;
412 }
413
414 _i2++;
415 }
416 }
417};
418
419/**
420 * Object iterator
421 * (without hasOwnProperty)
422 *
423 * @param {(Object|undefined)} obj - source object
424 * @param {function(?, string, !Object, {i: number, isFirst: boolean, isLast: boolean, length: number})} callback - callback function
425 */
426Snakeskin$1.forIn = function (obj, callback) {
427 if (!obj) {
428 return;
429 }
430
431 var length = 0,
432 i = 0;
433
434 if (callback.length >= 4) {
435 /* eslint-disable guard-for-in */
436 for (var ignore in obj) {
437 length++;
438 }
439 /* eslint-enable guard-for-in */
440 }
441
442 for (var key in obj) {
443 if (callback(obj[key], key, obj, { i: i, isFirst: i === 0, isLast: i === length - 1, length: length }) === false) {
444 break;
445 }
446
447 i++;
448 }
449};
450
451/**
452 * Decorates a function by another functions
453 *
454 * @param {!Array<!Function>} decorators - array of decorator functions
455 * @param {!Function} fn - source function
456 * @return {!Function}
457 */
458Snakeskin$1.decorate = function (decorators, fn) {
459 Snakeskin$1.forEach(decorators, function (decorator) {
460 return fn = decorator(fn) || fn;
461 });
462 fn.decorators = decorators;
463 return fn;
464};
465
466/**
467 * Gets an object with an undefined type
468 * (for the GCC)
469 *
470 * @param {?} val - source object
471 * @return {?}
472 */
473function any(val) {
474 return val;
475}
476
477/**
478 * String tag (for ES6 string templates) for truncate starting whitespaces and eol-s
479 *
480 * @param {!Array<string>} strings
481 * @param {...?} expr
482 * @return {string}
483 */
484
485
486var rRgxp = /([\\/'*+?|()[\]{}.^$-])/g;
487
488/**
489 * Escapes RegExp characters in a string
490 *
491 * @param {string} str - source string
492 * @return {string}
493 */
494function r(str) {
495 return str.replace(rRgxp, '\\$1');
496}
497
498var isNotPrimitiveRgxp = /^\(*\s*(.*?)\s*\)*$/;
499var isNotPrimitiveMap = { 'false': true, 'null': true, 'true': true, 'undefined': true };
500
501/**
502 * Returns true if the specified string can't be parse as a primitive value
503 *
504 * @param {string} str - source string
505 * @param {Object<string, boolean>=} opt_map - map of primitives
506 * @return {boolean}
507 */
508function isNotPrimitive(str, opt_map) {
509 str = ((isNotPrimitiveRgxp.exec(str) || [])[1] || '').trim();
510 return Boolean(str && isNaN(Number(str)) && !(opt_map || isNotPrimitiveMap)[str]);
511}
512
513
514
515var stringRender = {
516 'stringBuffer': true,
517 'stringConcat': true
518};
519
520var attrSeparators = {
521 '-': true,
522 ':': true,
523 '_': true
524};
525
526var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
527 return typeof obj;
528} : function (obj) {
529 return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
530};
531
532
533
534
535
536var asyncGenerator = function () {
537 function AwaitValue(value) {
538 this.value = value;
539 }
540
541 function AsyncGenerator(gen) {
542 var front, back;
543
544 function send(key, arg) {
545 return new Promise(function (resolve, reject) {
546 var request = {
547 key: key,
548 arg: arg,
549 resolve: resolve,
550 reject: reject,
551 next: null
552 };
553
554 if (back) {
555 back = back.next = request;
556 } else {
557 front = back = request;
558 resume(key, arg);
559 }
560 });
561 }
562
563 function resume(key, arg) {
564 try {
565 var result = gen[key](arg);
566 var value = result.value;
567
568 if (value instanceof AwaitValue) {
569 Promise.resolve(value.value).then(function (arg) {
570 resume("next", arg);
571 }, function (arg) {
572 resume("throw", arg);
573 });
574 } else {
575 settle(result.done ? "return" : "normal", result.value);
576 }
577 } catch (err) {
578 settle("throw", err);
579 }
580 }
581
582 function settle(type, value) {
583 switch (type) {
584 case "return":
585 front.resolve({
586 value: value,
587 done: true
588 });
589 break;
590
591 case "throw":
592 front.reject(value);
593 break;
594
595 default:
596 front.resolve({
597 value: value,
598 done: false
599 });
600 break;
601 }
602
603 front = front.next;
604
605 if (front) {
606 resume(front.key, front.arg);
607 } else {
608 back = null;
609 }
610 }
611
612 this._invoke = send;
613
614 if (typeof gen.return !== "function") {
615 this.return = undefined;
616 }
617 }
618
619 if (typeof Symbol === "function" && Symbol.asyncIterator) {
620 AsyncGenerator.prototype[Symbol.asyncIterator] = function () {
621 return this;
622 };
623 }
624
625 AsyncGenerator.prototype.next = function (arg) {
626 return this._invoke("next", arg);
627 };
628
629 AsyncGenerator.prototype.throw = function (arg) {
630 return this._invoke("throw", arg);
631 };
632
633 AsyncGenerator.prototype.return = function (arg) {
634 return this._invoke("return", arg);
635 };
636
637 return {
638 wrap: function (fn) {
639 return function () {
640 return new AsyncGenerator(fn.apply(this, arguments));
641 };
642 },
643 await: function (value) {
644 return new AwaitValue(value);
645 }
646 };
647}();
648
649
650
651
652
653
654
655
656
657
658
659
660
661var defineProperty = function (obj, key, value) {
662 if (key in obj) {
663 Object.defineProperty(obj, key, {
664 value: value,
665 enumerable: true,
666 configurable: true,
667 writable: true
668 });
669 } else {
670 obj[key] = value;
671 }
672
673 return obj;
674};
675
676var _COMMENTS;
677var _BASE_SYS_ESCAPES;
678var _SYS_ESCAPES;
679var _STRONG_SYS_ESCAPES;
680
681// The base directive separators
682// >>>
683
684var LEFT_BOUND = '{';
685var ADV_LEFT_BOUND = '#';
686
687// <<<
688// The additional directive separators
689// >>>
690
691var I18N = '`';
692
693var SINGLE_COMMENT = '///';
694var MULT_COMMENT_START = '/*';
695var MULT_COMMENT_END = '*/';
696
697var COMMENTS = (_COMMENTS = {}, defineProperty(_COMMENTS, SINGLE_COMMENT, SINGLE_COMMENT), defineProperty(_COMMENTS, MULT_COMMENT_START, MULT_COMMENT_START), defineProperty(_COMMENTS, MULT_COMMENT_END, MULT_COMMENT_END), _COMMENTS);
698
699var MICRO_TEMPLATE = '${';
700
701var BASE_SHORTS = defineProperty({
702 '-': true
703}, ADV_LEFT_BOUND, true);
704
705var SHORTS = {};
706
707Snakeskin$1.forEach(BASE_SHORTS, function (el, key) {
708 return SHORTS[key] = true;
709});
710
711// <<<
712// The context modifiers
713// >>>
714
715
716
717// <<<
718// Jade-Like
719// >>>
720
721var CONCAT = '&';
722var CONCAT_END = '.';
723var IGNORE = '|';
724var INLINE = ' :: ';
725
726// <<<
727// The filter modifiers
728// >>>
729
730
731
732// <<<
733// Escaping
734// >>>
735
736var BASE_SYS_ESCAPES = (_BASE_SYS_ESCAPES = {
737 '\\': true,
738 '"': true,
739 '\'': true,
740 '/': true
741}, defineProperty(_BASE_SYS_ESCAPES, I18N, true), defineProperty(_BASE_SYS_ESCAPES, LEFT_BOUND, true), defineProperty(_BASE_SYS_ESCAPES, SINGLE_COMMENT.charAt(0), true), defineProperty(_BASE_SYS_ESCAPES, MULT_COMMENT_START.charAt(0), true), _BASE_SYS_ESCAPES);
742
743var SYS_ESCAPES = (_SYS_ESCAPES = {
744 '\\': true
745}, defineProperty(_SYS_ESCAPES, I18N, true), defineProperty(_SYS_ESCAPES, LEFT_BOUND, true), defineProperty(_SYS_ESCAPES, ADV_LEFT_BOUND, true), defineProperty(_SYS_ESCAPES, SINGLE_COMMENT.charAt(0), true), defineProperty(_SYS_ESCAPES, MULT_COMMENT_START.charAt(0), true), defineProperty(_SYS_ESCAPES, CONCAT, true), defineProperty(_SYS_ESCAPES, CONCAT_END, true), defineProperty(_SYS_ESCAPES, IGNORE, true), defineProperty(_SYS_ESCAPES, INLINE.trim().charAt(0), true), _SYS_ESCAPES);
746
747Snakeskin$1.forEach(BASE_SHORTS, function (el, key) {
748 return SYS_ESCAPES[key.charAt(0)] = true;
749});
750
751var STRONG_SYS_ESCAPES = (_STRONG_SYS_ESCAPES = {
752 '\\': true
753}, defineProperty(_STRONG_SYS_ESCAPES, I18N, true), defineProperty(_STRONG_SYS_ESCAPES, SINGLE_COMMENT.charAt(0), true), defineProperty(_STRONG_SYS_ESCAPES, MULT_COMMENT_START.charAt(0), true), _STRONG_SYS_ESCAPES);
754
755var MICRO_TEMPLATE_ESCAPES = defineProperty({
756 '\\': true
757}, MICRO_TEMPLATE.charAt(0), true);
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773// <<<
774// The reserved names
775// >>>
776
777
778
779var tmpSep = [];
780
781Snakeskin$1.forEach(attrSeparators, function (el, key) {
782 tmpSep.push(r(key));
783});
784
785
786
787
788
789var attrKey = /([^\s=]+)/;
790
791var Filters = Snakeskin$1.Filters;
792
793/**
794 * Imports an object to Filters
795 *
796 * @param {!Object} filters - import object
797 * @param {?string=} [opt_namespace] - namespace for saving, for example foo.bar
798 * @return {!Object}
799 */
800
801Snakeskin$1.importFilters = function (filters, opt_namespace) {
802 var obj = Filters;
803
804 if (opt_namespace) {
805 Snakeskin$1.forEach(opt_namespace.split('.'), function (el) {
806 obj[el] = obj[el] || {};
807 obj = obj[el];
808 });
809 }
810
811 Snakeskin$1.forEach(filters, function (el, key) {
812 return obj[key] = el;
813 });
814
815 return this;
816};
817
818/**
819 * Sets parameters to the specified Snakeskin filter
820 *
821 * @param {(string|!Function)} filter - filter name or the filter function
822 * @param {Object} params - parameters
823 * @return {!Function}
824 */
825Snakeskin$1.setFilterParams = function (filter, params) {
826 var safe = params['safe'];
827
828 if (safe) {
829 params['bind'] = ['Unsafe'].concat(params['bind'] || []);
830 }
831
832 var tmp = void 0;
833 function wrapper(val, Unsafe) {
834 var _tmp2;
835
836 for (var _len = arguments.length, args = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
837 args[_key - 2] = arguments[_key];
838 }
839
840 if (val && isFunction(Unsafe) && val instanceof Unsafe) {
841 var _tmp;
842
843 val.value = (_tmp = tmp).call.apply(_tmp, [this, val.value].concat(args));
844 return val;
845 }
846
847 return (_tmp2 = tmp).call.apply(_tmp2, [this, val].concat(args));
848 }
849
850 if (isString(filter)) {
851 if (safe) {
852 tmp = Filters[filter];
853 Filters[filter] = wrapper;
854 }
855
856 Filters[filter] = Filters[filter] || function (str) {
857 return str;
858 };
859 Filters[filter]['ssFilterParams'] = params;
860 return Filters[filter];
861 }
862
863 if (safe) {
864 tmp = filter;
865 filter = wrapper;
866 }
867
868 filter['ssFilterParams'] = params;
869 return any(filter);
870};
871
872/**
873 * Console API
874 * @const
875 */
876Filters['console'] = {
877 /**
878 * @param {?} val
879 * @return {?}
880 */
881 'dir': function dir(val) {
882 var _console;
883
884 (_console = console).dir.apply(_console, arguments);
885 return val;
886 },
887
888
889 /**
890 * @param {?} val
891 * @return {?}
892 */
893 'error': function error(val) {
894 var _console2;
895
896 (_console2 = console).error.apply(_console2, arguments);
897 return val;
898 },
899
900
901 /**
902 * @param {?} val
903 * @return {?}
904 */
905 'info': function info(val) {
906 var _console3;
907
908 (_console3 = console).info.apply(_console3, arguments);
909 return val;
910 },
911
912
913 /**
914 * @param {?} val
915 * @return {?}
916 */
917 'log': function log(val) {
918 var _console4;
919
920 (_console4 = console).log.apply(_console4, arguments);
921 return val;
922 },
923
924
925 /**
926 * @param {?} val
927 * @return {?}
928 */
929 'table': function table(val) {
930 var _console5;
931
932 (_console5 = console).table.apply(_console5, arguments);
933 return val;
934 },
935
936
937 /**
938 * @param {?} val
939 * @return {?}
940 */
941 'warn': function warn(val) {
942 var _console6;
943
944 (_console6 = console).warn.apply(_console6, arguments);
945 return val;
946 }
947};
948
949var entityMap = {
950 '"': '&quot;',
951 '&': '&amp;',
952 '\'': '&#39;',
953 '<': '&lt;',
954 '>': '&gt;'
955};
956
957var escapeHTMLRgxp = /[<>"'/]|&(?!#|[a-z]+;)/g;
958var escapeHTML = function escapeHTML(s) {
959 return entityMap[s] || s;
960};
961
962var uentityMap = {
963 '&#39;': '\'',
964 '&#x2F;': '/',
965 '&amp;': '&',
966 '&gt;': '>',
967 '&lt;': '<',
968 '&quot;': '"'
969};
970
971var uescapeHTMLRgxp = /&amp;|&lt;|&gt;|&quot;|&#39;|&#x2F;/g;
972var uescapeHTML = function uescapeHTML(s) {
973 return uentityMap[s];
974};
975
976/**
977 * Escapes HTML entities from a string
978 *
979 * @param {?} val - source value
980 * @param {?=} [opt_Unsafe] - unsafe class constructor
981 * @param {?string=} [opt_attr] - type of attribute declaration
982 * @param {Object=} [opt_attrCache] - attribute cache object
983 * @param {?=} [opt_true] - true value
984 * @return {(string|!Snakeskin.HTMLObject|!Snakeskin.Node)}
985 */
986Filters['html'] = function (val, opt_Unsafe, opt_attr, opt_attrCache, opt_true) {
987 if (!val || val instanceof Snakeskin$1.Node) {
988 return val;
989 }
990
991 if (val instanceof Snakeskin$1.HTMLObject) {
992 Snakeskin$1.forEach(val.value, function (el, key, data) {
993 if (val.attr) {
994 opt_attrCache[key] = data[key] = el[0] !== opt_true ? [Filters['html'](el[0], opt_Unsafe, val.attr, opt_attrCache, opt_true)] : el;
995 } else {
996 data[key] = Filters['html'](el, opt_Unsafe);
997 }
998 });
999
1000 return val;
1001 }
1002
1003 if (isFunction(opt_Unsafe) && val instanceof opt_Unsafe) {
1004 return val.value;
1005 }
1006
1007 return String(opt_attr ? Filters[opt_attr](val) : val).replace(escapeHTMLRgxp, escapeHTML);
1008};
1009
1010Snakeskin$1.setFilterParams('html', {
1011 bind: ['Unsafe', '$attrType', function (o) {
1012 return o.getVar('$attrs');
1013 }, 'TRUE'],
1014 test: function test(val) {
1015 return isNotPrimitive(val);
1016 }
1017});
1018
1019Filters['htmlObject'] = function (val) {
1020 if (val instanceof Snakeskin$1.HTMLObject) {
1021 return '';
1022 }
1023
1024 return val;
1025};
1026
1027Snakeskin$1.setFilterParams('htmlObject', {
1028 test: function test(val) {
1029 return isNotPrimitive(val);
1030 }
1031});
1032
1033/**
1034 * Replaces undefined to ''
1035 *
1036 * @param {?} val - source value
1037 * @return {?}
1038 */
1039Filters['undef'] = function (val) {
1040 return val !== undefined ? val : '';
1041};
1042
1043Snakeskin$1.setFilterParams('undef', {
1044 test: function test(val) {
1045 return isNotPrimitive(val, { 'false': true, 'null': true, 'true': true });
1046 }
1047});
1048
1049/**
1050 * Replaces escaped HTML entities to real content
1051 *
1052 * @param {?} val - source value
1053 * @return {string}
1054 */
1055Filters['uhtml'] = function (val) {
1056 return String(val).replace(uescapeHTMLRgxp, uescapeHTML);
1057};
1058
1059var stripTagsRgxp = /<\/?[^>]+>/g;
1060
1061/**
1062 * Removes < > from a string
1063 *
1064 * @param {?} val - source value
1065 * @return {string}
1066 */
1067Filters['stripTags'] = function (val) {
1068 return String(val).replace(stripTagsRgxp, '');
1069};
1070
1071var uriO = /%5B/g;
1072var uriC = /%5D/g;
1073
1074/**
1075 * Encodes URL
1076 *
1077 * @see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/encodeURI
1078 * @param {?} val - source value
1079 * @return {string}
1080 */
1081Filters['uri'] = function (val) {
1082 return encodeURI(String(val)).replace(uriO, '[').replace(uriC, ']');
1083};
1084
1085Snakeskin$1.setFilterParams('uri', {
1086 safe: true
1087});
1088
1089/**
1090 * Converts a string to uppercase
1091 *
1092 * @param {?} val - source value
1093 * @return {string}
1094 */
1095Filters['upper'] = function (val) {
1096 return String(val).toUpperCase();
1097};
1098
1099Snakeskin$1.setFilterParams('upper', {
1100 safe: true
1101});
1102
1103/**
1104 * Converts the first letter of a string to uppercase
1105 *
1106 * @param {?} val - source value
1107 * @return {string}
1108 */
1109Filters['ucfirst'] = function (val) {
1110 val = String(val);
1111 return val.charAt(0).toUpperCase() + val.slice(1);
1112};
1113
1114Snakeskin$1.setFilterParams('ucfirst', {
1115 safe: true
1116});
1117
1118/**
1119 * Converts a string to lowercase
1120 *
1121 * @param {?} val - source value
1122 * @return {string}
1123 */
1124Filters['lower'] = function (val) {
1125 return String(val).toLowerCase();
1126};
1127
1128Snakeskin$1.setFilterParams('lower', {
1129 safe: true
1130});
1131
1132/**
1133 * Converts the first letter of a string to lowercase
1134 *
1135 * @param {?} val - source value
1136 * @return {string}
1137 */
1138Filters['lcfirst'] = function (val) {
1139 val = String(val);
1140 return val.charAt(0).toLowerCase() + val.slice(1);
1141};
1142
1143Snakeskin$1.setFilterParams('lcfirst', {
1144 safe: true
1145});
1146
1147/**
1148 * Removes whitespace from both ends of a string
1149 *
1150 * @param {?} val - source value
1151 * @return {string}
1152 */
1153Filters['trim'] = function (val) {
1154 return String(val).trim();
1155};
1156
1157Snakeskin$1.setFilterParams('trim', {
1158 safe: true
1159});
1160
1161var spaceCollapseRgxp = /\s{2,}/g;
1162
1163/**
1164 * Removes whitespace from both ends of a string
1165 * and collapses whitespace
1166 *
1167 * @param {?} val - source value
1168 * @return {string}
1169 */
1170Filters['collapse'] = function (val) {
1171 return String(val).replace(spaceCollapseRgxp, ' ').trim();
1172};
1173
1174Snakeskin$1.setFilterParams('collapse', {
1175 safe: true
1176});
1177
1178/**
1179 * Truncates a string to the specified length
1180 * (at the end puts three dots)
1181 *
1182 * @param {?} val - source value
1183 * @param {number} length - maximum length
1184 * @param {?boolean=} opt_wordOnly - if is false, then the string will be truncated without
1185 * taking into account the integrity of the words
1186 *
1187 * @param {?boolean=} opt_html - if is true, then the dots will be inserted as HTML-mnemonic
1188 * @return {string}
1189 */
1190Filters['truncate'] = function (val, length, opt_wordOnly, opt_html) {
1191 val = String(val);
1192 if (!val || val.length <= length) {
1193 return val;
1194 }
1195
1196 var tmp = val.slice(0, length - 1);
1197
1198 var i = tmp.length,
1199 lastInd = void 0;
1200
1201 while (i-- && opt_wordOnly) {
1202 if (tmp.charAt(i) === ' ') {
1203 lastInd = i;
1204 } else if (lastInd !== undefined) {
1205 break;
1206 }
1207 }
1208
1209 return (lastInd !== undefined ? tmp.slice(0, lastInd) : tmp) + (opt_html ? '&#8230;' : '…');
1210};
1211
1212/**
1213 * Returns a new string of repetitions of a string
1214 *
1215 * @param {?} val - source value
1216 * @param {?number=} opt_num - number of repetitions
1217 * @return {string}
1218 */
1219Filters['repeat'] = function (val, opt_num) {
1220 return new Array(opt_num != null ? opt_num + 1 : 3).join(val);
1221};
1222
1223Snakeskin$1.setFilterParams('repeat', {
1224 safe: true
1225});
1226
1227/**
1228 * Removes a slice from a string
1229 *
1230 * @param {?} val - source value
1231 * @param {(string|RegExp)} search - searching slice
1232 * @return {string}
1233 */
1234Filters['remove'] = function (val, search) {
1235 return String(val).replace(search, '');
1236};
1237
1238/**
1239 * Replaces a slice from a string to a new string
1240 *
1241 * @param {?} val - source value
1242 * @param {(string|!RegExp)} search - searching slice
1243 * @param {string} replace - string for replacing
1244 * @return {string}
1245 */
1246Filters['replace'] = function (val, search, replace) {
1247 return String(val).replace(search, replace);
1248};
1249
1250var tplRgxp = /\${(.*?)}/g;
1251
1252/**
1253 * Returns a string result of the specified template
1254 *
1255 * @example
1256 * 'hello ${name}' |tpl {name: 'Kobezzza'}
1257 *
1258 * @param {?} tpl - source template
1259 * @param {!Object} map - map of values
1260 * @return {string}
1261 */
1262Filters['tpl'] = function (tpl, map) {
1263 return String(tpl).replace(tplRgxp, function (str, $0) {
1264 return $0 in map ? map[$0] : '';
1265 });
1266};
1267
1268/**
1269 * Converts a value to JSON
1270 *
1271 * @param {(Object|Array|string|number|boolean)} val - source value
1272 * @return {string}
1273 */
1274Filters['json'] = function (val) {
1275 return JSON.stringify(val);
1276};
1277
1278/**
1279 * Converts a value to a string
1280 *
1281 * @param {(Object|Array|string|number|boolean)} val - source value
1282 * @return {string}
1283 */
1284Filters['string'] = function (val) {
1285 if ((typeof val === 'undefined' ? 'undefined' : _typeof(val)) === 'object' && val instanceof String === false) {
1286 return JSON.stringify(val);
1287 }
1288
1289 return String(val);
1290};
1291
1292/**
1293 * Parses a string as JSON
1294 *
1295 * @param {?} val - source value
1296 * @return {?}
1297 */
1298Filters['parse'] = function (val) {
1299 if (!isString(val)) {
1300 return val;
1301 }
1302
1303 return JSON.parse(val);
1304};
1305
1306/**
1307 * Sets a default value for the specified parameter
1308 *
1309 * @param {?} val - source value
1310 * @param {?} def - value
1311 * @return {?}
1312 */
1313Filters['default'] = function (val, def) {
1314 return val === undefined ? def : val;
1315};
1316
1317Snakeskin$1.setFilterParams('default', {
1318 '!undef': true
1319});
1320
1321var nl2brRgxp = /\r?\n|\n/g;
1322
1323/**
1324 * Replaces EOL symbols from a string to <br>
1325 *
1326 * @param {?} val - source value
1327 * @param {(!Snakeskin.DocumentFragment|!Snakeskin.Element|undefined)} node - source node
1328 * @param {string} renderMode - rendering mode of templates
1329 * @param {boolean} stringResult - if is true, then the output will be saved to __STRING_RESULT__ as a string
1330 * @param {string} doctype - document type
1331 * @return {?}
1332 */
1333Filters['nl2br'] = function (val, node, renderMode, stringResult, doctype) {
1334 var arr = val.split(nl2brRgxp);
1335
1336 var res = '';
1337 for (var i = 0; i < arr.length; i++) {
1338 var el = arr[i],
1339 last = i === arr.length - 1;
1340
1341 if (!stringResult && !stringRender[renderMode]) {
1342 Snakeskin$1.appendChild(any(node), el, renderMode);
1343 if (!last) {
1344 Snakeskin$1.appendChild(any(node), new Snakeskin$1.Element('br', renderMode), renderMode);
1345 }
1346 } else {
1347 res += Filters['html'](el);
1348 if (!last) {
1349 res += '<br' + (doctype === 'xml' ? '/' : '') + '>';
1350 }
1351 }
1352 }
1353
1354 return res;
1355};
1356
1357Snakeskin$1.setFilterParams('nl2br', {
1358 '!html': true,
1359 bind: ['$0', function (o) {
1360 return '\'' + o.renderMode + '\'';
1361 }, function (o) {
1362 return o.stringResult;
1363 }, '$0', function (o) {
1364 return '\'' + o.doctype + '\'';
1365 }]
1366});
1367
1368/**
1369 * @param str
1370 * @return {string}
1371 */
1372function dasherize(str) {
1373 var res = str[0].toLowerCase();
1374
1375 for (var i = 1; i < str.length; i++) {
1376 var el = str.charAt(i),
1377 up = el.toUpperCase();
1378
1379 if (up === el && up !== el.toLowerCase()) {
1380 res += '-' + el;
1381 } else {
1382 res += el;
1383 }
1384 }
1385
1386 return res.toLowerCase();
1387}
1388
1389/**
1390 * Escapes HTML entities from an attribute name
1391 *
1392 * @param {?} val - source value
1393 * @return {string}
1394 */
1395Filters['attrKey'] = function (val) {
1396 var tmp = attrKey.exec(String(val));
1397 return tmp && tmp[1] || 'undefined';
1398};
1399
1400/**
1401 * Escapes HTML entities from an attribute group
1402 *
1403 * @param {?} val - source value
1404 * @return {string}
1405 */
1406Filters['attrKeyGroup'] = function (val) {
1407 var tmp = attrKey.exec(String(val));
1408 return tmp && tmp[1] || '';
1409};
1410
1411var attrValRgxp = /(javascript)(:|;)/g;
1412
1413/**
1414 * Escapes HTML entities from an attribute value
1415 *
1416 * @param {?} val - source value
1417 * @return {string}
1418 */
1419Filters['attrValue'] = function (val) {
1420 return String(val).replace(attrValRgxp, '$1&#31;$2');
1421};
1422
1423/**
1424 * Sets attributes to a node
1425 *
1426 * @param {?} val - source value
1427 * @param {?} Unsafe - unsafe class constructor
1428 * @param {string} doctype - document type
1429 * @param {string} type - type of attribute declaration
1430 * @param {!Object} cache - attribute cache object
1431 * @param {!Boolean} TRUE - true value
1432 * @param {!Boolean} FALSE - false value
1433 * @return {(string|Unsafe|Snakeskin.HTMLObject)}
1434 */
1435Filters['attr'] = function (val, Unsafe, doctype, type, cache, TRUE, FALSE) {
1436 if (type !== 'attrKey' || !isObject(val)) {
1437 if (isFunction(Unsafe) && val instanceof Unsafe) {
1438 return val;
1439 }
1440
1441 return String(val);
1442 }
1443
1444 var localCache = {};
1445
1446 /**
1447 * @param {Object} obj
1448 * @param {?string=} opt_prfx
1449 * @return {Snakeskin.HTMLObject}
1450 */
1451 function convert(obj, opt_prfx) {
1452 opt_prfx = opt_prfx || '';
1453 Snakeskin$1.forEach(obj, function (el, key) {
1454 if (el === FALSE) {
1455 return;
1456 }
1457
1458 if (isObject(el)) {
1459 var group = Filters['attrKeyGroup'](key);
1460 return convert(el, opt_prfx + (!group.length || attrSeparators[group.slice(-1)] ? group : group + '-'));
1461 }
1462
1463 var tmp = dasherize(opt_prfx + key);
1464 cache[tmp] = localCache[tmp] = [el];
1465 });
1466
1467 return new Snakeskin$1.HTMLObject(localCache, 'attrValue');
1468 }
1469
1470 return convert(val);
1471};
1472
1473Snakeskin$1.setFilterParams('attr', {
1474 '!html': true,
1475 bind: ['Unsafe', function (o) {
1476 return '\'' + o.doctype + '\'';
1477 }, '$attrType', function (o) {
1478 return o.getVar('$attrs');
1479 }, 'TRUE', 'FALSE'],
1480 test: function test(val) {
1481 return isNotPrimitive(val);
1482 }
1483});
1484
1485return Snakeskin$1;
1486
1487})));