UNPKG

92.9 kBJavaScriptView Raw
1/* Riot v3.13.2, @license MIT */
2(function (global, factory) {
3 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
4 typeof define === 'function' && define.amd ? define(['exports'], factory) :
5 (factory((global.riot = {})));
6}(this, (function (exports) { 'use strict';
7
8 /**
9 * Shorter and fast way to select a single node in the DOM
10 * @param { String } selector - unique dom selector
11 * @param { Object } ctx - DOM node where the target of our search will is located
12 * @returns { Object } dom node found
13 */
14 function $(selector, ctx) {
15 return (ctx || document).querySelector(selector)
16 }
17
18 var
19 // be aware, internal usage
20 // ATTENTION: prefix the global dynamic variables with `__`
21 // tags instances cache
22 __TAGS_CACHE = [],
23 // tags implementation cache
24 __TAG_IMPL = {},
25 YIELD_TAG = 'yield',
26
27 /**
28 * Const
29 */
30 GLOBAL_MIXIN = '__global_mixin',
31
32 // riot specific prefixes or attributes
33 ATTRS_PREFIX = 'riot-',
34
35 // Riot Directives
36 REF_DIRECTIVES = ['ref', 'data-ref'],
37 IS_DIRECTIVE = 'data-is',
38 CONDITIONAL_DIRECTIVE = 'if',
39 LOOP_DIRECTIVE = 'each',
40 LOOP_NO_REORDER_DIRECTIVE = 'no-reorder',
41 SHOW_DIRECTIVE = 'show',
42 HIDE_DIRECTIVE = 'hide',
43 KEY_DIRECTIVE = 'key',
44 RIOT_EVENTS_KEY = '__riot-events__',
45
46 // for typeof == '' comparisons
47 T_STRING = 'string',
48 T_OBJECT = 'object',
49 T_UNDEF = 'undefined',
50 T_FUNCTION = 'function',
51
52 XLINK_NS = 'http://www.w3.org/1999/xlink',
53 SVG_NS = 'http://www.w3.org/2000/svg',
54 XLINK_REGEX = /^xlink:(\w+)/,
55
56 WIN = typeof window === T_UNDEF ? /* istanbul ignore next */ undefined : window,
57
58 // special native tags that cannot be treated like the others
59 RE_SPECIAL_TAGS = /^(?:t(?:body|head|foot|[rhd])|caption|col(?:group)?|opt(?:ion|group))$/,
60 RE_SPECIAL_TAGS_NO_OPTION = /^(?:t(?:body|head|foot|[rhd])|caption|col(?:group)?)$/,
61 RE_EVENTS_PREFIX = /^on/,
62 RE_HTML_ATTRS = /([-\w]+) ?= ?(?:"([^"]*)|'([^']*)|({[^}]*}))/g,
63 // some DOM attributes must be normalized
64 CASE_SENSITIVE_ATTRIBUTES = {
65 'viewbox': 'viewBox',
66 'preserveaspectratio': 'preserveAspectRatio'
67 },
68 /**
69 * Matches boolean HTML attributes in the riot tag definition.
70 * With a long list like this, a regex is faster than `[].indexOf` in most browsers.
71 * @const {RegExp}
72 * @see [attributes.md](https://github.com/riot/compiler/blob/dev/doc/attributes.md)
73 */
74 RE_BOOL_ATTRS = /^(?:disabled|checked|readonly|required|allowfullscreen|auto(?:focus|play)|compact|controls|default|formnovalidate|hidden|ismap|itemscope|loop|multiple|muted|no(?:resize|shade|validate|wrap)?|open|reversed|seamless|selected|sortable|truespeed|typemustmatch)$/,
75 // version# for IE 8-11, 0 for others
76 IE_VERSION = (WIN && WIN.document || /* istanbul ignore next */ {}).documentMode | 0;
77
78 /**
79 * Create a generic DOM node
80 * @param { String } name - name of the DOM node we want to create
81 * @returns { Object } DOM node just created
82 */
83 function makeElement(name) {
84 return name === 'svg' ? document.createElementNS(SVG_NS, name) : document.createElement(name)
85 }
86
87 /**
88 * Set any DOM attribute
89 * @param { Object } dom - DOM node we want to update
90 * @param { String } name - name of the property we want to set
91 * @param { String } val - value of the property we want to set
92 */
93 function setAttribute(dom, name, val) {
94 var xlink = XLINK_REGEX.exec(name);
95 if (xlink && xlink[1])
96 { dom.setAttributeNS(XLINK_NS, xlink[1], val); }
97 else
98 { dom.setAttribute(name, val); }
99 }
100
101 var styleNode;
102 // Create cache and shortcut to the correct property
103 var cssTextProp;
104 var byName = {};
105 var needsInject = false;
106
107 // skip the following code on the server
108 if (WIN) {
109 styleNode = ((function () {
110 // create a new style element with the correct type
111 var newNode = makeElement('style');
112 // replace any user node or insert the new one into the head
113 var userNode = $('style[type=riot]');
114
115 setAttribute(newNode, 'type', 'text/css');
116 /* istanbul ignore next */
117 if (userNode) {
118 if (userNode.id) { newNode.id = userNode.id; }
119 userNode.parentNode.replaceChild(newNode, userNode);
120 } else { document.head.appendChild(newNode); }
121
122 return newNode
123 }))();
124 cssTextProp = styleNode.styleSheet;
125 }
126
127 /**
128 * Object that will be used to inject and manage the css of every tag instance
129 */
130 var styleManager = {
131 styleNode: styleNode,
132 /**
133 * Save a tag style to be later injected into DOM
134 * @param { String } css - css string
135 * @param { String } name - if it's passed we will map the css to a tagname
136 */
137 add: function add(css, name) {
138 byName[name] = css;
139 needsInject = true;
140 },
141 /**
142 * Inject all previously saved tag styles into DOM
143 * innerHTML seems slow: http://jsperf.com/riot-insert-style
144 */
145 inject: function inject() {
146 if (!WIN || !needsInject) { return }
147 needsInject = false;
148 var style = Object.keys(byName)
149 .map(function (k) { return byName[k]; })
150 .join('\n');
151 /* istanbul ignore next */
152 if (cssTextProp) { cssTextProp.cssText = style; }
153 else { styleNode.innerHTML = style; }
154 },
155
156 /**
157 * Remove a tag style of injected DOM later.
158 * @param {String} name a registered tagname
159 */
160 remove: function remove(name) {
161 delete byName[name];
162 needsInject = true;
163 }
164 };
165
166 /**
167 * The riot template engine
168 * @version v3.0.8
169 */
170
171 /* istanbul ignore next */
172 var skipRegex = (function () { //eslint-disable-line no-unused-vars
173
174 var beforeReChars = '[{(,;:?=|&!^~>%*/';
175
176 var beforeReWords = [
177 'case',
178 'default',
179 'do',
180 'else',
181 'in',
182 'instanceof',
183 'prefix',
184 'return',
185 'typeof',
186 'void',
187 'yield'
188 ];
189
190 var wordsLastChar = beforeReWords.reduce(function (s, w) {
191 return s + w.slice(-1)
192 }, '');
193
194 var RE_REGEX = /^\/(?=[^*>/])[^[/\\]*(?:(?:\\.|\[(?:\\.|[^\]\\]*)*\])[^[\\/]*)*?\/[gimuy]*/;
195 var RE_VN_CHAR = /[$\w]/;
196
197 function prev (code, pos) {
198 while (--pos >= 0 && /\s/.test(code[pos])){ }
199 return pos
200 }
201
202 function _skipRegex (code, start) {
203
204 var re = /.*/g;
205 var pos = re.lastIndex = start++;
206 var match = re.exec(code)[0].match(RE_REGEX);
207
208 if (match) {
209 var next = pos + match[0].length;
210
211 pos = prev(code, pos);
212 var c = code[pos];
213
214 if (pos < 0 || ~beforeReChars.indexOf(c)) {
215 return next
216 }
217
218 if (c === '.') {
219
220 if (code[pos - 1] === '.') {
221 start = next;
222 }
223
224 } else if (c === '+' || c === '-') {
225
226 if (code[--pos] !== c ||
227 (pos = prev(code, pos)) < 0 ||
228 !RE_VN_CHAR.test(code[pos])) {
229 start = next;
230 }
231
232 } else if (~wordsLastChar.indexOf(c)) {
233
234 var end = pos + 1;
235
236 while (--pos >= 0 && RE_VN_CHAR.test(code[pos])){ }
237 if (~beforeReWords.indexOf(code.slice(pos + 1, end))) {
238 start = next;
239 }
240 }
241 }
242
243 return start
244 }
245
246 return _skipRegex
247
248 })();
249
250 /**
251 * riot.util.brackets
252 *
253 * - `brackets ` - Returns a string or regex based on its parameter
254 * - `brackets.set` - Change the current riot brackets
255 *
256 * @module
257 */
258
259 /* global riot */
260
261 /* istanbul ignore next */
262 var brackets = (function (UNDEF) {
263
264 var
265 REGLOB = 'g',
266
267 R_MLCOMMS = /\/\*[^*]*\*+(?:[^*\/][^*]*\*+)*\//g,
268
269 R_STRINGS = /"[^"\\]*(?:\\[\S\s][^"\\]*)*"|'[^'\\]*(?:\\[\S\s][^'\\]*)*'|`[^`\\]*(?:\\[\S\s][^`\\]*)*`/g,
270
271 S_QBLOCKS = R_STRINGS.source + '|' +
272 /(?:\breturn\s+|(?:[$\w\)\]]|\+\+|--)\s*(\/)(?![*\/]))/.source + '|' +
273 /\/(?=[^*\/])[^[\/\\]*(?:(?:\[(?:\\.|[^\]\\]*)*\]|\\.)[^[\/\\]*)*?([^<]\/)[gim]*/.source,
274
275 UNSUPPORTED = RegExp('[\\' + 'x00-\\x1F<>a-zA-Z0-9\'",;\\\\]'),
276
277 NEED_ESCAPE = /(?=[[\]()*+?.^$|])/g,
278
279 S_QBLOCK2 = R_STRINGS.source + '|' + /(\/)(?![*\/])/.source,
280
281 FINDBRACES = {
282 '(': RegExp('([()])|' + S_QBLOCK2, REGLOB),
283 '[': RegExp('([[\\]])|' + S_QBLOCK2, REGLOB),
284 '{': RegExp('([{}])|' + S_QBLOCK2, REGLOB)
285 },
286
287 DEFAULT = '{ }';
288
289 var _pairs = [
290 '{', '}',
291 '{', '}',
292 /{[^}]*}/,
293 /\\([{}])/g,
294 /\\({)|{/g,
295 RegExp('\\\\(})|([[({])|(})|' + S_QBLOCK2, REGLOB),
296 DEFAULT,
297 /^\s*{\^?\s*([$\w]+)(?:\s*,\s*(\S+))?\s+in\s+(\S.*)\s*}/,
298 /(^|[^\\]){=[\S\s]*?}/
299 ];
300
301 var
302 cachedBrackets = UNDEF,
303 _regex,
304 _cache = [],
305 _settings;
306
307 function _loopback (re) { return re }
308
309 function _rewrite (re, bp) {
310 if (!bp) { bp = _cache; }
311 return new RegExp(
312 re.source.replace(/{/g, bp[2]).replace(/}/g, bp[3]), re.global ? REGLOB : ''
313 )
314 }
315
316 function _create (pair) {
317 if (pair === DEFAULT) { return _pairs }
318
319 var arr = pair.split(' ');
320
321 if (arr.length !== 2 || UNSUPPORTED.test(pair)) {
322 throw new Error('Unsupported brackets "' + pair + '"')
323 }
324 arr = arr.concat(pair.replace(NEED_ESCAPE, '\\').split(' '));
325
326 arr[4] = _rewrite(arr[1].length > 1 ? /{[\S\s]*?}/ : _pairs[4], arr);
327 arr[5] = _rewrite(pair.length > 3 ? /\\({|})/g : _pairs[5], arr);
328 arr[6] = _rewrite(_pairs[6], arr);
329 arr[7] = RegExp('\\\\(' + arr[3] + ')|([[({])|(' + arr[3] + ')|' + S_QBLOCK2, REGLOB);
330 arr[8] = pair;
331 return arr
332 }
333
334 function _brackets (reOrIdx) {
335 return reOrIdx instanceof RegExp ? _regex(reOrIdx) : _cache[reOrIdx]
336 }
337
338 _brackets.split = function split (str, tmpl, _bp) {
339 // istanbul ignore next: _bp is for the compiler
340 if (!_bp) { _bp = _cache; }
341
342 var
343 parts = [],
344 match,
345 isexpr,
346 start,
347 pos,
348 re = _bp[6];
349
350 var qblocks = [];
351 var prevStr = '';
352 var mark, lastIndex;
353
354 isexpr = start = re.lastIndex = 0;
355
356 while ((match = re.exec(str))) {
357
358 lastIndex = re.lastIndex;
359 pos = match.index;
360
361 if (isexpr) {
362
363 if (match[2]) {
364
365 var ch = match[2];
366 var rech = FINDBRACES[ch];
367 var ix = 1;
368
369 rech.lastIndex = lastIndex;
370 while ((match = rech.exec(str))) {
371 if (match[1]) {
372 if (match[1] === ch) { ++ix; }
373 else if (!--ix) { break }
374 } else {
375 rech.lastIndex = pushQBlock(match.index, rech.lastIndex, match[2]);
376 }
377 }
378 re.lastIndex = ix ? str.length : rech.lastIndex;
379 continue
380 }
381
382 if (!match[3]) {
383 re.lastIndex = pushQBlock(pos, lastIndex, match[4]);
384 continue
385 }
386 }
387
388 if (!match[1]) {
389 unescapeStr(str.slice(start, pos));
390 start = re.lastIndex;
391 re = _bp[6 + (isexpr ^= 1)];
392 re.lastIndex = start;
393 }
394 }
395
396 if (str && start < str.length) {
397 unescapeStr(str.slice(start));
398 }
399
400 parts.qblocks = qblocks;
401
402 return parts
403
404 function unescapeStr (s) {
405 if (prevStr) {
406 s = prevStr + s;
407 prevStr = '';
408 }
409 if (tmpl || isexpr) {
410 parts.push(s && s.replace(_bp[5], '$1'));
411 } else {
412 parts.push(s);
413 }
414 }
415
416 function pushQBlock(_pos, _lastIndex, slash) { //eslint-disable-line
417 if (slash) {
418 _lastIndex = skipRegex(str, _pos);
419 }
420
421 if (tmpl && _lastIndex > _pos + 2) {
422 mark = '\u2057' + qblocks.length + '~';
423 qblocks.push(str.slice(_pos, _lastIndex));
424 prevStr += str.slice(start, _pos) + mark;
425 start = _lastIndex;
426 }
427 return _lastIndex
428 }
429 };
430
431 _brackets.hasExpr = function hasExpr (str) {
432 return _cache[4].test(str)
433 };
434
435 _brackets.loopKeys = function loopKeys (expr) {
436 var m = expr.match(_cache[9]);
437
438 return m
439 ? { key: m[1], pos: m[2], val: _cache[0] + m[3].trim() + _cache[1] }
440 : { val: expr.trim() }
441 };
442
443 _brackets.array = function array (pair) {
444 return pair ? _create(pair) : _cache
445 };
446
447 function _reset (pair) {
448 if ((pair || (pair = DEFAULT)) !== _cache[8]) {
449 _cache = _create(pair);
450 _regex = pair === DEFAULT ? _loopback : _rewrite;
451 _cache[9] = _regex(_pairs[9]);
452 }
453 cachedBrackets = pair;
454 }
455
456 function _setSettings (o) {
457 var b;
458
459 o = o || {};
460 b = o.brackets;
461 Object.defineProperty(o, 'brackets', {
462 set: _reset,
463 get: function () { return cachedBrackets },
464 enumerable: true
465 });
466 _settings = o;
467 _reset(b);
468 }
469
470 Object.defineProperty(_brackets, 'settings', {
471 set: _setSettings,
472 get: function () { return _settings }
473 });
474
475 /* istanbul ignore next: in the browser riot is always in the scope */
476 _brackets.settings = typeof riot !== 'undefined' && riot.settings || {};
477 _brackets.set = _reset;
478 _brackets.skipRegex = skipRegex;
479
480 _brackets.R_STRINGS = R_STRINGS;
481 _brackets.R_MLCOMMS = R_MLCOMMS;
482 _brackets.S_QBLOCKS = S_QBLOCKS;
483 _brackets.S_QBLOCK2 = S_QBLOCK2;
484
485 return _brackets
486
487 })();
488
489 /**
490 * @module tmpl
491 *
492 * tmpl - Root function, returns the template value, render with data
493 * tmpl.hasExpr - Test the existence of a expression inside a string
494 * tmpl.loopKeys - Get the keys for an 'each' loop (used by `_each`)
495 */
496
497 /* istanbul ignore next */
498 var tmpl = (function () {
499
500 var _cache = {};
501
502 function _tmpl (str, data) {
503 if (!str) { return str }
504
505 return (_cache[str] || (_cache[str] = _create(str))).call(
506 data, _logErr.bind({
507 data: data,
508 tmpl: str
509 })
510 )
511 }
512
513 _tmpl.hasExpr = brackets.hasExpr;
514
515 _tmpl.loopKeys = brackets.loopKeys;
516
517 // istanbul ignore next
518 _tmpl.clearCache = function () { _cache = {}; };
519
520 _tmpl.errorHandler = null;
521
522 function _logErr (err, ctx) {
523
524 err.riotData = {
525 tagName: ctx && ctx.__ && ctx.__.tagName,
526 _riot_id: ctx && ctx._riot_id //eslint-disable-line camelcase
527 };
528
529 if (_tmpl.errorHandler) { _tmpl.errorHandler(err); }
530 else if (
531 typeof console !== 'undefined' &&
532 typeof console.error === 'function'
533 ) {
534 console.error(err.message);
535 console.log('<%s> %s', err.riotData.tagName || 'Unknown tag', this.tmpl); // eslint-disable-line
536 console.log(this.data); // eslint-disable-line
537 }
538 }
539
540 function _create (str) {
541 var expr = _getTmpl(str);
542
543 if (expr.slice(0, 11) !== 'try{return ') { expr = 'return ' + expr; }
544
545 return new Function('E', expr + ';') // eslint-disable-line no-new-func
546 }
547
548 var RE_DQUOTE = /\u2057/g;
549 var RE_QBMARK = /\u2057(\d+)~/g;
550
551 function _getTmpl (str) {
552 var parts = brackets.split(str.replace(RE_DQUOTE, '"'), 1);
553 var qstr = parts.qblocks;
554 var expr;
555
556 if (parts.length > 2 || parts[0]) {
557 var i, j, list = [];
558
559 for (i = j = 0; i < parts.length; ++i) {
560
561 expr = parts[i];
562
563 if (expr && (expr = i & 1
564
565 ? _parseExpr(expr, 1, qstr)
566
567 : '"' + expr
568 .replace(/\\/g, '\\\\')
569 .replace(/\r\n?|\n/g, '\\n')
570 .replace(/"/g, '\\"') +
571 '"'
572
573 )) { list[j++] = expr; }
574
575 }
576
577 expr = j < 2 ? list[0]
578 : '[' + list.join(',') + '].join("")';
579
580 } else {
581
582 expr = _parseExpr(parts[1], 0, qstr);
583 }
584
585 if (qstr.length) {
586 expr = expr.replace(RE_QBMARK, function (_, pos) {
587 return qstr[pos]
588 .replace(/\r/g, '\\r')
589 .replace(/\n/g, '\\n')
590 });
591 }
592 return expr
593 }
594
595 var RE_CSNAME = /^(?:(-?[_A-Za-z\xA0-\xFF][-\w\xA0-\xFF]*)|\u2057(\d+)~):/;
596 var
597 RE_BREND = {
598 '(': /[()]/g,
599 '[': /[[\]]/g,
600 '{': /[{}]/g
601 };
602
603 function _parseExpr (expr, asText, qstr) {
604
605 expr = expr
606 .replace(/\s+/g, ' ').trim()
607 .replace(/\ ?([[\({},?\.:])\ ?/g, '$1');
608
609 if (expr) {
610 var
611 list = [],
612 cnt = 0,
613 match;
614
615 while (expr &&
616 (match = expr.match(RE_CSNAME)) &&
617 !match.index
618 ) {
619 var
620 key,
621 jsb,
622 re = /,|([[{(])|$/g;
623
624 expr = RegExp.rightContext;
625 key = match[2] ? qstr[match[2]].slice(1, -1).trim().replace(/\s+/g, ' ') : match[1];
626
627 while (jsb = (match = re.exec(expr))[1]) { skipBraces(jsb, re); }
628
629 jsb = expr.slice(0, match.index);
630 expr = RegExp.rightContext;
631
632 list[cnt++] = _wrapExpr(jsb, 1, key);
633 }
634
635 expr = !cnt ? _wrapExpr(expr, asText)
636 : cnt > 1 ? '[' + list.join(',') + '].join(" ").trim()' : list[0];
637 }
638 return expr
639
640 function skipBraces (ch, re) {
641 var
642 mm,
643 lv = 1,
644 ir = RE_BREND[ch];
645
646 ir.lastIndex = re.lastIndex;
647 while (mm = ir.exec(expr)) {
648 if (mm[0] === ch) { ++lv; }
649 else if (!--lv) { break }
650 }
651 re.lastIndex = lv ? expr.length : ir.lastIndex;
652 }
653 }
654
655 // istanbul ignore next: not both
656 var // eslint-disable-next-line max-len
657 JS_CONTEXT = '"in this?this:' + (typeof window !== 'object' ? 'global' : 'window') + ').',
658 JS_VARNAME = /[,{][\$\w]+(?=:)|(^ *|[^$\w\.{])(?!(?:typeof|true|false|null|undefined|in|instanceof|is(?:Finite|NaN)|void|NaN|new|Date|RegExp|Math)(?![$\w]))([$_A-Za-z][$\w]*)/g,
659 JS_NOPROPS = /^(?=(\.[$\w]+))\1(?:[^.[(]|$)/;
660
661 function _wrapExpr (expr, asText, key) {
662 var tb;
663
664 expr = expr.replace(JS_VARNAME, function (match, p, mvar, pos, s) {
665 if (mvar) {
666 pos = tb ? 0 : pos + match.length;
667
668 if (mvar !== 'this' && mvar !== 'global' && mvar !== 'window') {
669 match = p + '("' + mvar + JS_CONTEXT + mvar;
670 if (pos) { tb = (s = s[pos]) === '.' || s === '(' || s === '['; }
671 } else if (pos) {
672 tb = !JS_NOPROPS.test(s.slice(pos));
673 }
674 }
675 return match
676 });
677
678 if (tb) {
679 expr = 'try{return ' + expr + '}catch(e){E(e,this)}';
680 }
681
682 if (key) {
683
684 expr = (tb
685 ? 'function(){' + expr + '}.call(this)' : '(' + expr + ')'
686 ) + '?"' + key + '":""';
687
688 } else if (asText) {
689
690 expr = 'function(v){' + (tb
691 ? expr.replace('return ', 'v=') : 'v=(' + expr + ')'
692 ) + ';return v||v===0?v:""}.call(this)';
693 }
694
695 return expr
696 }
697
698 _tmpl.version = brackets.version = 'v3.0.8';
699
700 return _tmpl
701
702 })();
703
704 /* istanbul ignore next */
705 var observable = function(el) {
706
707 /**
708 * Extend the original object or create a new empty one
709 * @type { Object }
710 */
711
712 el = el || {};
713
714 /**
715 * Private variables
716 */
717 var callbacks = {},
718 slice = Array.prototype.slice;
719
720 /**
721 * Public Api
722 */
723
724 // extend the el object adding the observable methods
725 Object.defineProperties(el, {
726 /**
727 * Listen to the given `event` ands
728 * execute the `callback` each time an event is triggered.
729 * @param { String } event - event id
730 * @param { Function } fn - callback function
731 * @returns { Object } el
732 */
733 on: {
734 value: function(event, fn) {
735 if (typeof fn == 'function')
736 { (callbacks[event] = callbacks[event] || []).push(fn); }
737 return el
738 },
739 enumerable: false,
740 writable: false,
741 configurable: false
742 },
743
744 /**
745 * Removes the given `event` listeners
746 * @param { String } event - event id
747 * @param { Function } fn - callback function
748 * @returns { Object } el
749 */
750 off: {
751 value: function(event, fn) {
752 if (event == '*' && !fn) { callbacks = {}; }
753 else {
754 if (fn) {
755 var arr = callbacks[event];
756 for (var i = 0, cb; cb = arr && arr[i]; ++i) {
757 if (cb == fn) { arr.splice(i--, 1); }
758 }
759 } else { delete callbacks[event]; }
760 }
761 return el
762 },
763 enumerable: false,
764 writable: false,
765 configurable: false
766 },
767
768 /**
769 * Listen to the given `event` and
770 * execute the `callback` at most once
771 * @param { String } event - event id
772 * @param { Function } fn - callback function
773 * @returns { Object } el
774 */
775 one: {
776 value: function(event, fn) {
777 function on() {
778 el.off(event, on);
779 fn.apply(el, arguments);
780 }
781 return el.on(event, on)
782 },
783 enumerable: false,
784 writable: false,
785 configurable: false
786 },
787
788 /**
789 * Execute all callback functions that listen to
790 * the given `event`
791 * @param { String } event - event id
792 * @returns { Object } el
793 */
794 trigger: {
795 value: function(event) {
796 var arguments$1 = arguments;
797
798
799 // getting the arguments
800 var arglen = arguments.length - 1,
801 args = new Array(arglen),
802 fns,
803 fn,
804 i;
805
806 for (i = 0; i < arglen; i++) {
807 args[i] = arguments$1[i + 1]; // skip first argument
808 }
809
810 fns = slice.call(callbacks[event] || [], 0);
811
812 for (i = 0; fn = fns[i]; ++i) {
813 fn.apply(el, args);
814 }
815
816 if (callbacks['*'] && event != '*')
817 { el.trigger.apply(el, ['*', event].concat(args)); }
818
819 return el
820 },
821 enumerable: false,
822 writable: false,
823 configurable: false
824 }
825 });
826
827 return el
828
829 };
830
831 /**
832 * Short alias for Object.getOwnPropertyDescriptor
833 */
834 function getPropDescriptor (o, k) {
835 return Object.getOwnPropertyDescriptor(o, k)
836 }
837
838 /**
839 * Check if passed argument is undefined
840 * @param { * } value -
841 * @returns { Boolean } -
842 */
843 function isUndefined(value) {
844 return typeof value === T_UNDEF
845 }
846
847 /**
848 * Check whether object's property could be overridden
849 * @param { Object } obj - source object
850 * @param { String } key - object property
851 * @returns { Boolean } true if writable
852 */
853 function isWritable(obj, key) {
854 var descriptor = getPropDescriptor(obj, key);
855 return isUndefined(obj[key]) || descriptor && descriptor.writable
856 }
857
858 /**
859 * Extend any object with other properties
860 * @param { Object } src - source object
861 * @returns { Object } the resulting extended object
862 *
863 * var obj = { foo: 'baz' }
864 * extend(obj, {bar: 'bar', foo: 'bar'})
865 * console.log(obj) => {bar: 'bar', foo: 'bar'}
866 *
867 */
868 function extend(src) {
869 var obj;
870 var i = 1;
871 var args = arguments;
872 var l = args.length;
873
874 for (; i < l; i++) {
875 if (obj = args[i]) {
876 for (var key in obj) {
877 // check if this property of the source object could be overridden
878 if (isWritable(src, key))
879 { src[key] = obj[key]; }
880 }
881 }
882 }
883 return src
884 }
885
886 /**
887 * Alias for Object.create
888 */
889 function create(src) {
890 return Object.create(src)
891 }
892
893 var settings = extend(create(brackets.settings), {
894 skipAnonymousTags: true,
895 // the "value" attributes will be preserved
896 keepValueAttributes: false,
897 // handle the auto updates on any DOM event
898 autoUpdate: true
899 });
900
901 /**
902 * Shorter and fast way to select multiple nodes in the DOM
903 * @param { String } selector - DOM selector
904 * @param { Object } ctx - DOM node where the targets of our search will is located
905 * @returns { Object } dom nodes found
906 */
907 function $$(selector, ctx) {
908 return [].slice.call((ctx || document).querySelectorAll(selector))
909 }
910
911 /**
912 * Create a document text node
913 * @returns { Object } create a text node to use as placeholder
914 */
915 function createDOMPlaceholder() {
916 return document.createTextNode('')
917 }
918
919 /**
920 * Toggle the visibility of any DOM node
921 * @param { Object } dom - DOM node we want to hide
922 * @param { Boolean } show - do we want to show it?
923 */
924
925 function toggleVisibility(dom, show) {
926 dom.style.display = show ? '' : 'none';
927 dom.hidden = show ? false : true;
928 }
929
930 /**
931 * Get the value of any DOM attribute on a node
932 * @param { Object } dom - DOM node we want to parse
933 * @param { String } name - name of the attribute we want to get
934 * @returns { String | undefined } name of the node attribute whether it exists
935 */
936 function getAttribute(dom, name) {
937 return dom.getAttribute(name)
938 }
939
940 /**
941 * Remove any DOM attribute from a node
942 * @param { Object } dom - DOM node we want to update
943 * @param { String } name - name of the property we want to remove
944 */
945 function removeAttribute(dom, name) {
946 dom.removeAttribute(name);
947 }
948
949 /**
950 * Set the inner html of any DOM node SVGs included
951 * @param { Object } container - DOM node where we'll inject new html
952 * @param { String } html - html to inject
953 * @param { Boolean } isSvg - svg tags should be treated a bit differently
954 */
955 /* istanbul ignore next */
956 function setInnerHTML(container, html, isSvg) {
957 // innerHTML is not supported on svg tags so we neet to treat them differently
958 if (isSvg) {
959 var node = container.ownerDocument.importNode(
960 new DOMParser()
961 .parseFromString(("<svg xmlns=\"" + SVG_NS + "\">" + html + "</svg>"), 'application/xml')
962 .documentElement,
963 true
964 );
965
966 container.appendChild(node);
967 } else {
968 container.innerHTML = html;
969 }
970 }
971
972 /**
973 * Minimize risk: only zero or one _space_ between attr & value
974 * @param { String } html - html string we want to parse
975 * @param { Function } fn - callback function to apply on any attribute found
976 */
977 function walkAttributes(html, fn) {
978 if (!html) { return }
979 var m;
980 while (m = RE_HTML_ATTRS.exec(html))
981 { fn(m[1].toLowerCase(), m[2] || m[3] || m[4]); }
982 }
983
984 /**
985 * Create a document fragment
986 * @returns { Object } document fragment
987 */
988 function createFragment() {
989 return document.createDocumentFragment()
990 }
991
992 /**
993 * Insert safely a tag to fix #1962 #1649
994 * @param { HTMLElement } root - children container
995 * @param { HTMLElement } curr - node to insert
996 * @param { HTMLElement } next - node that should preceed the current node inserted
997 */
998 function safeInsert(root, curr, next) {
999 root.insertBefore(curr, next.parentNode && next);
1000 }
1001
1002 /**
1003 * Convert a style object to a string
1004 * @param { Object } style - style object we need to parse
1005 * @returns { String } resulting css string
1006 * @example
1007 * styleObjectToString({ color: 'red', height: '10px'}) // => 'color: red; height: 10px'
1008 */
1009 function styleObjectToString(style) {
1010 return Object.keys(style).reduce(function (acc, prop) {
1011 return (acc + " " + prop + ": " + (style[prop]) + ";")
1012 }, '')
1013 }
1014
1015 /**
1016 * Walk down recursively all the children tags starting dom node
1017 * @param { Object } dom - starting node where we will start the recursion
1018 * @param { Function } fn - callback to transform the child node just found
1019 * @param { Object } context - fn can optionally return an object, which is passed to children
1020 */
1021 function walkNodes(dom, fn, context) {
1022 if (dom) {
1023 var res = fn(dom, context);
1024 var next;
1025 // stop the recursion
1026 if (res === false) { return }
1027
1028 dom = dom.firstChild;
1029
1030 while (dom) {
1031 next = dom.nextSibling;
1032 walkNodes(dom, fn, res);
1033 dom = next;
1034 }
1035 }
1036 }
1037
1038
1039
1040 var dom = /*#__PURE__*/Object.freeze({
1041 $$: $$,
1042 $: $,
1043 createDOMPlaceholder: createDOMPlaceholder,
1044 mkEl: makeElement,
1045 setAttr: setAttribute,
1046 toggleVisibility: toggleVisibility,
1047 getAttr: getAttribute,
1048 remAttr: removeAttribute,
1049 setInnerHTML: setInnerHTML,
1050 walkAttrs: walkAttributes,
1051 createFrag: createFragment,
1052 safeInsert: safeInsert,
1053 styleObjectToString: styleObjectToString,
1054 walkNodes: walkNodes
1055 });
1056
1057 /**
1058 * Check against the null and undefined values
1059 * @param { * } value -
1060 * @returns {Boolean} -
1061 */
1062 function isNil(value) {
1063 return isUndefined(value) || value === null
1064 }
1065
1066 /**
1067 * Check if passed argument is empty. Different from falsy, because we dont consider 0 or false to be blank
1068 * @param { * } value -
1069 * @returns { Boolean } -
1070 */
1071 function isBlank(value) {
1072 return isNil(value) || value === ''
1073 }
1074
1075 /**
1076 * Check if passed argument is a function
1077 * @param { * } value -
1078 * @returns { Boolean } -
1079 */
1080 function isFunction(value) {
1081 return typeof value === T_FUNCTION
1082 }
1083
1084 /**
1085 * Check if passed argument is an object, exclude null
1086 * NOTE: use isObject(x) && !isArray(x) to excludes arrays.
1087 * @param { * } value -
1088 * @returns { Boolean } -
1089 */
1090 function isObject(value) {
1091 return value && typeof value === T_OBJECT // typeof null is 'object'
1092 }
1093
1094 /**
1095 * Check if a DOM node is an svg tag or part of an svg
1096 * @param { HTMLElement } el - node we want to test
1097 * @returns {Boolean} true if it's an svg node
1098 */
1099 function isSvg(el) {
1100 var owner = el.ownerSVGElement;
1101 return !!owner || owner === null
1102 }
1103
1104 /**
1105 * Check if passed argument is a kind of array
1106 * @param { * } value -
1107 * @returns { Boolean } -
1108 */
1109 function isArray(value) {
1110 return Array.isArray(value) || value instanceof Array
1111 }
1112
1113 /**
1114 * Check if the passed argument is a boolean attribute
1115 * @param { String } value -
1116 * @returns { Boolean } -
1117 */
1118 function isBoolAttr(value) {
1119 return RE_BOOL_ATTRS.test(value)
1120 }
1121
1122 /**
1123 * Check if passed argument is a string
1124 * @param { * } value -
1125 * @returns { Boolean } -
1126 */
1127 function isString(value) {
1128 return typeof value === T_STRING
1129 }
1130
1131
1132
1133 var check = /*#__PURE__*/Object.freeze({
1134 isBlank: isBlank,
1135 isFunction: isFunction,
1136 isObject: isObject,
1137 isSvg: isSvg,
1138 isWritable: isWritable,
1139 isArray: isArray,
1140 isBoolAttr: isBoolAttr,
1141 isNil: isNil,
1142 isString: isString,
1143 isUndefined: isUndefined
1144 });
1145
1146 /**
1147 * Check whether an array contains an item
1148 * @param { Array } array - target array
1149 * @param { * } item - item to test
1150 * @returns { Boolean } -
1151 */
1152 function contains(array, item) {
1153 return array.indexOf(item) !== -1
1154 }
1155
1156 /**
1157 * Specialized function for looping an array-like collection with `each={}`
1158 * @param { Array } list - collection of items
1159 * @param {Function} fn - callback function
1160 * @returns { Array } the array looped
1161 */
1162 function each(list, fn) {
1163 var len = list ? list.length : 0;
1164 var i = 0;
1165 for (; i < len; i++) { fn(list[i], i); }
1166 return list
1167 }
1168
1169 /**
1170 * Faster String startsWith alternative
1171 * @param { String } str - source string
1172 * @param { String } value - test string
1173 * @returns { Boolean } -
1174 */
1175 function startsWith(str, value) {
1176 return str.slice(0, value.length) === value
1177 }
1178
1179 /**
1180 * Function returning always a unique identifier
1181 * @returns { Number } - number from 0...n
1182 */
1183 var uid = (function uid() {
1184 var i = -1;
1185 return function () { return ++i; }
1186 })();
1187
1188 /**
1189 * Helper function to set an immutable property
1190 * @param { Object } el - object where the new property will be set
1191 * @param { String } key - object key where the new property will be stored
1192 * @param { * } value - value of the new property
1193 * @param { Object } options - set the propery overriding the default options
1194 * @returns { Object } - the initial object
1195 */
1196 function define(el, key, value, options) {
1197 Object.defineProperty(el, key, extend({
1198 value: value,
1199 enumerable: false,
1200 writable: false,
1201 configurable: true
1202 }, options));
1203 return el
1204 }
1205
1206 /**
1207 * Convert a string containing dashes to camel case
1208 * @param { String } str - input string
1209 * @returns { String } my-string -> myString
1210 */
1211 function toCamel(str) {
1212 return str.replace(/-(\w)/g, function (_, c) { return c.toUpperCase(); })
1213 }
1214
1215 /**
1216 * Warn a message via console
1217 * @param {String} message - warning message
1218 */
1219 function warn(message) {
1220 if (console && console.warn) { console.warn(message); }
1221 }
1222
1223
1224
1225 var misc = /*#__PURE__*/Object.freeze({
1226 contains: contains,
1227 each: each,
1228 getPropDescriptor: getPropDescriptor,
1229 startsWith: startsWith,
1230 uid: uid,
1231 defineProperty: define,
1232 objectCreate: create,
1233 extend: extend,
1234 toCamel: toCamel,
1235 warn: warn
1236 });
1237
1238 /**
1239 * Set the property of an object for a given key. If something already
1240 * exists there, then it becomes an array containing both the old and new value.
1241 * @param { Object } obj - object on which to set the property
1242 * @param { String } key - property name
1243 * @param { Object } value - the value of the property to be set
1244 * @param { Boolean } ensureArray - ensure that the property remains an array
1245 * @param { Number } index - add the new item in a certain array position
1246 */
1247 function arrayishAdd(obj, key, value, ensureArray, index) {
1248 var dest = obj[key];
1249 var isArr = isArray(dest);
1250 var hasIndex = !isUndefined(index);
1251
1252 if (dest && dest === value) { return }
1253
1254 // if the key was never set, set it once
1255 if (!dest && ensureArray) { obj[key] = [value]; }
1256 else if (!dest) { obj[key] = value; }
1257 // if it was an array and not yet set
1258 else {
1259 if (isArr) {
1260 var oldIndex = dest.indexOf(value);
1261 // this item never changed its position
1262 if (oldIndex === index) { return }
1263 // remove the item from its old position
1264 if (oldIndex !== -1) { dest.splice(oldIndex, 1); }
1265 // move or add the item
1266 if (hasIndex) {
1267 dest.splice(index, 0, value);
1268 } else {
1269 dest.push(value);
1270 }
1271 } else { obj[key] = [dest, value]; }
1272 }
1273 }
1274
1275 /**
1276 * Detect the tag implementation by a DOM node
1277 * @param { Object } dom - DOM node we need to parse to get its tag implementation
1278 * @returns { Object } it returns an object containing the implementation of a custom tag (template and boot function)
1279 */
1280 function get(dom) {
1281 return dom.tagName && __TAG_IMPL[getAttribute(dom, IS_DIRECTIVE) ||
1282 getAttribute(dom, IS_DIRECTIVE) || dom.tagName.toLowerCase()]
1283 }
1284
1285 /**
1286 * Get the tag name of any DOM node
1287 * @param { Object } dom - DOM node we want to parse
1288 * @param { Boolean } skipDataIs - hack to ignore the data-is attribute when attaching to parent
1289 * @returns { String } name to identify this dom node in riot
1290 */
1291 function getName(dom, skipDataIs) {
1292 var child = get(dom);
1293 var namedTag = !skipDataIs && getAttribute(dom, IS_DIRECTIVE);
1294 return namedTag && !tmpl.hasExpr(namedTag) ?
1295 namedTag : child ? child.name : dom.tagName.toLowerCase()
1296 }
1297
1298 /**
1299 * Return a temporary context containing also the parent properties
1300 * @this Tag
1301 * @param { Tag } - temporary tag context containing all the parent properties
1302 */
1303 function inheritParentProps() {
1304 if (this.parent) { return extend(create(this), this.parent) }
1305 return this
1306 }
1307
1308 /*
1309 Includes hacks needed for the Internet Explorer version 9 and below
1310 See: http://kangax.github.io/compat-table/es5/#ie8
1311 http://codeplanet.io/dropping-ie8/
1312 */
1313
1314 var
1315 reHasYield = /<yield\b/i,
1316 reYieldAll = /<yield\s*(?:\/>|>([\S\s]*?)<\/yield\s*>|>)/ig,
1317 reYieldSrc = /<yield\s+to=['"]([^'">]*)['"]\s*>([\S\s]*?)<\/yield\s*>/ig,
1318 reYieldDest = /<yield\s+from=['"]?([-\w]+)['"]?\s*(?:\/>|>([\S\s]*?)<\/yield\s*>)/ig,
1319 rootEls = { tr: 'tbody', th: 'tr', td: 'tr', col: 'colgroup' },
1320 tblTags = IE_VERSION && IE_VERSION < 10 ? RE_SPECIAL_TAGS : RE_SPECIAL_TAGS_NO_OPTION,
1321 GENERIC = 'div',
1322 SVG = 'svg';
1323
1324
1325 /*
1326 Creates the root element for table or select child elements:
1327 tr/th/td/thead/tfoot/tbody/caption/col/colgroup/option/optgroup
1328 */
1329 function specialTags(el, tmpl, tagName) {
1330
1331 var
1332 select = tagName[0] === 'o',
1333 parent = select ? 'select>' : 'table>';
1334
1335 // trim() is important here, this ensures we don't have artifacts,
1336 // so we can check if we have only one element inside the parent
1337 el.innerHTML = '<' + parent + tmpl.trim() + '</' + parent;
1338 parent = el.firstChild;
1339
1340 // returns the immediate parent if tr/th/td/col is the only element, if not
1341 // returns the whole tree, as this can include additional elements
1342 /* istanbul ignore next */
1343 if (select) {
1344 parent.selectedIndex = -1; // for IE9, compatible w/current riot behavior
1345 } else {
1346 // avoids insertion of cointainer inside container (ex: tbody inside tbody)
1347 var tname = rootEls[tagName];
1348 if (tname && parent.childElementCount === 1) { parent = $(tname, parent); }
1349 }
1350 return parent
1351 }
1352
1353 /*
1354 Replace the yield tag from any tag template with the innerHTML of the
1355 original tag in the page
1356 */
1357 function replaceYield(tmpl, html) {
1358 // do nothing if no yield
1359 if (!reHasYield.test(tmpl)) { return tmpl }
1360
1361 // be careful with #1343 - string on the source having `$1`
1362 var src = {};
1363
1364 html = html && html.replace(reYieldSrc, function (_, ref, text) {
1365 src[ref] = src[ref] || text; // preserve first definition
1366 return ''
1367 }).trim();
1368
1369 return tmpl
1370 .replace(reYieldDest, function (_, ref, def) { // yield with from - to attrs
1371 return src[ref] || def || ''
1372 })
1373 .replace(reYieldAll, function (_, def) { // yield without any "from"
1374 return html || def || ''
1375 })
1376 }
1377
1378 /**
1379 * Creates a DOM element to wrap the given content. Normally an `DIV`, but can be
1380 * also a `TABLE`, `SELECT`, `TBODY`, `TR`, or `COLGROUP` element.
1381 *
1382 * @param { String } tmpl - The template coming from the custom tag definition
1383 * @param { String } html - HTML content that comes from the DOM element where you
1384 * will mount the tag, mostly the original tag in the page
1385 * @param { Boolean } isSvg - true if the root node is an svg
1386 * @returns { HTMLElement } DOM element with _tmpl_ merged through `YIELD` with the _html_.
1387 */
1388 function mkdom(tmpl, html, isSvg) {
1389 var match = tmpl && tmpl.match(/^\s*<([-\w]+)/);
1390 var tagName = match && match[1].toLowerCase();
1391 var el = makeElement(isSvg ? SVG : GENERIC);
1392
1393 // replace all the yield tags with the tag inner html
1394 tmpl = replaceYield(tmpl, html);
1395
1396 /* istanbul ignore next */
1397 if (tblTags.test(tagName))
1398 { el = specialTags(el, tmpl, tagName); }
1399 else
1400 { setInnerHTML(el, tmpl, isSvg); }
1401
1402 return el
1403 }
1404
1405 var EVENT_ATTR_RE = /^on/;
1406
1407 /**
1408 * True if the event attribute starts with 'on'
1409 * @param { String } attribute - event attribute
1410 * @returns { Boolean }
1411 */
1412 function isEventAttribute(attribute) {
1413 return EVENT_ATTR_RE.test(attribute)
1414 }
1415
1416 /**
1417 * Loop backward all the parents tree to detect the first custom parent tag
1418 * @param { Object } tag - a Tag instance
1419 * @returns { Object } the instance of the first custom parent tag found
1420 */
1421 function getImmediateCustomParent(tag) {
1422 var ptag = tag;
1423 while (ptag.__.isAnonymous) {
1424 if (!ptag.parent) { break }
1425 ptag = ptag.parent;
1426 }
1427 return ptag
1428 }
1429
1430 /**
1431 * Trigger DOM events
1432 * @param { HTMLElement } dom - dom element target of the event
1433 * @param { Function } handler - user function
1434 * @param { Object } e - event object
1435 */
1436 function handleEvent(dom, handler, e) {
1437 var ptag = this.__.parent;
1438 var item = this.__.item;
1439
1440 if (!item)
1441 { while (ptag && !item) {
1442 item = ptag.__.item;
1443 ptag = ptag.__.parent;
1444 } }
1445
1446 // override the event properties
1447 /* istanbul ignore next */
1448 if (isWritable(e, 'currentTarget')) { e.currentTarget = dom; }
1449 /* istanbul ignore next */
1450 if (isWritable(e, 'target')) { e.target = e.srcElement; }
1451 /* istanbul ignore next */
1452 if (isWritable(e, 'which')) { e.which = e.charCode || e.keyCode; }
1453
1454 e.item = item;
1455
1456 handler.call(this, e);
1457
1458 // avoid auto updates
1459 if (!settings.autoUpdate) { return }
1460
1461 if (!e.preventUpdate) {
1462 var p = getImmediateCustomParent(this);
1463 // fixes #2083
1464 if (p.isMounted) { p.update(); }
1465 }
1466 }
1467
1468 /**
1469 * Attach an event to a DOM node
1470 * @param { String } name - event name
1471 * @param { Function } handler - event callback
1472 * @param { Object } dom - dom node
1473 * @param { Tag } tag - tag instance
1474 */
1475 function setEventHandler(name, handler, dom, tag) {
1476 var eventName;
1477 var cb = handleEvent.bind(tag, dom, handler);
1478
1479 // avoid to bind twice the same event
1480 // possible fix for #2332
1481 dom[name] = null;
1482
1483 // normalize event name
1484 eventName = name.replace(RE_EVENTS_PREFIX, '');
1485
1486 // cache the listener into the listeners array
1487 if (!contains(tag.__.listeners, dom)) { tag.__.listeners.push(dom); }
1488 if (!dom[RIOT_EVENTS_KEY]) { dom[RIOT_EVENTS_KEY] = {}; }
1489 if (dom[RIOT_EVENTS_KEY][name]) { dom.removeEventListener(eventName, dom[RIOT_EVENTS_KEY][name]); }
1490
1491 dom[RIOT_EVENTS_KEY][name] = cb;
1492 dom.addEventListener(eventName, cb, false);
1493 }
1494
1495 /**
1496 * Create a new child tag including it correctly into its parent
1497 * @param { Object } child - child tag implementation
1498 * @param { Object } opts - tag options containing the DOM node where the tag will be mounted
1499 * @param { String } innerHTML - inner html of the child node
1500 * @param { Object } parent - instance of the parent tag including the child custom tag
1501 * @returns { Object } instance of the new child tag just created
1502 */
1503 function initChild(child, opts, innerHTML, parent) {
1504 var tag = createTag(child, opts, innerHTML);
1505 var tagName = opts.tagName || getName(opts.root, true);
1506 var ptag = getImmediateCustomParent(parent);
1507 // fix for the parent attribute in the looped elements
1508 define(tag, 'parent', ptag);
1509 // store the real parent tag
1510 // in some cases this could be different from the custom parent tag
1511 // for example in nested loops
1512 tag.__.parent = parent;
1513
1514 // add this tag to the custom parent tag
1515 arrayishAdd(ptag.tags, tagName, tag);
1516
1517 // and also to the real parent tag
1518 if (ptag !== parent)
1519 { arrayishAdd(parent.tags, tagName, tag); }
1520
1521 return tag
1522 }
1523
1524 /**
1525 * Removes an item from an object at a given key. If the key points to an array,
1526 * then the item is just removed from the array.
1527 * @param { Object } obj - object on which to remove the property
1528 * @param { String } key - property name
1529 * @param { Object } value - the value of the property to be removed
1530 * @param { Boolean } ensureArray - ensure that the property remains an array
1531 */
1532 function arrayishRemove(obj, key, value, ensureArray) {
1533 if (isArray(obj[key])) {
1534 var index = obj[key].indexOf(value);
1535 if (index !== -1) { obj[key].splice(index, 1); }
1536 if (!obj[key].length) { delete obj[key]; }
1537 else if (obj[key].length === 1 && !ensureArray) { obj[key] = obj[key][0]; }
1538 } else if (obj[key] === value)
1539 { delete obj[key]; } // otherwise just delete the key
1540 }
1541
1542 /**
1543 * Adds the elements for a virtual tag
1544 * @this Tag
1545 * @param { Node } src - the node that will do the inserting or appending
1546 * @param { Tag } target - only if inserting, insert before this tag's first child
1547 */
1548 function makeVirtual(src, target) {
1549 var this$1 = this;
1550
1551 var head = createDOMPlaceholder();
1552 var tail = createDOMPlaceholder();
1553 var frag = createFragment();
1554 var sib;
1555 var el;
1556
1557 this.root.insertBefore(head, this.root.firstChild);
1558 this.root.appendChild(tail);
1559
1560 this.__.head = el = head;
1561 this.__.tail = tail;
1562
1563 while (el) {
1564 sib = el.nextSibling;
1565 frag.appendChild(el);
1566 this$1.__.virts.push(el); // hold for unmounting
1567 el = sib;
1568 }
1569
1570 if (target)
1571 { src.insertBefore(frag, target.__.head); }
1572 else
1573 { src.appendChild(frag); }
1574 }
1575
1576 /**
1577 * makes a tag virtual and replaces a reference in the dom
1578 * @this Tag
1579 * @param { tag } the tag to make virtual
1580 * @param { ref } the dom reference location
1581 */
1582 function makeReplaceVirtual(tag, ref) {
1583 if (!ref.parentNode) { return }
1584 var frag = createFragment();
1585 makeVirtual.call(tag, frag);
1586 ref.parentNode.replaceChild(frag, ref);
1587 }
1588
1589 /**
1590 * Update dynamically created data-is tags with changing expressions
1591 * @param { Object } expr - expression tag and expression info
1592 * @param { Tag } parent - parent for tag creation
1593 * @param { String } tagName - tag implementation we want to use
1594 */
1595 function updateDataIs(expr, parent, tagName) {
1596 var tag = expr.tag || expr.dom._tag;
1597 var ref;
1598
1599 var ref$1 = tag ? tag.__ : {};
1600 var head = ref$1.head;
1601 var isVirtual = expr.dom.tagName === 'VIRTUAL';
1602
1603 if (tag && expr.tagName === tagName) {
1604 tag.update();
1605 return
1606 }
1607
1608 // sync _parent to accommodate changing tagnames
1609 if (tag) {
1610 // need placeholder before unmount
1611 if(isVirtual) {
1612 ref = createDOMPlaceholder();
1613 head.parentNode.insertBefore(ref, head);
1614 }
1615
1616 tag.unmount(true);
1617 }
1618
1619 // unable to get the tag name
1620 if (!isString(tagName)) { return }
1621
1622 expr.impl = __TAG_IMPL[tagName];
1623
1624 // unknown implementation
1625 if (!expr.impl) { return }
1626
1627 expr.tag = tag = initChild(
1628 expr.impl, {
1629 root: expr.dom,
1630 parent: parent,
1631 tagName: tagName
1632 },
1633 expr.dom.innerHTML,
1634 parent
1635 );
1636
1637 each(expr.attrs, function (a) { return setAttribute(tag.root, a.name, a.value); });
1638 expr.tagName = tagName;
1639 tag.mount();
1640
1641 // root exist first time, after use placeholder
1642 if (isVirtual) { makeReplaceVirtual(tag, ref || tag.root); }
1643
1644 // parent is the placeholder tag, not the dynamic tag so clean up
1645 parent.__.onUnmount = function () {
1646 var delName = tag.opts.dataIs;
1647 arrayishRemove(tag.parent.tags, delName, tag);
1648 arrayishRemove(tag.__.parent.tags, delName, tag);
1649 tag.unmount();
1650 };
1651 }
1652
1653 /**
1654 * Nomalize any attribute removing the "riot-" prefix
1655 * @param { String } attrName - original attribute name
1656 * @returns { String } valid html attribute name
1657 */
1658 function normalizeAttrName(attrName) {
1659 if (!attrName) { return null }
1660 attrName = attrName.replace(ATTRS_PREFIX, '');
1661 if (CASE_SENSITIVE_ATTRIBUTES[attrName]) { attrName = CASE_SENSITIVE_ATTRIBUTES[attrName]; }
1662 return attrName
1663 }
1664
1665 /**
1666 * Update on single tag expression
1667 * @this Tag
1668 * @param { Object } expr - expression logic
1669 * @returns { undefined }
1670 */
1671 function updateExpression(expr) {
1672 if (this.root && getAttribute(this.root,'virtualized')) { return }
1673
1674 var dom = expr.dom;
1675 // remove the riot- prefix
1676 var attrName = normalizeAttrName(expr.attr);
1677 var isToggle = contains([SHOW_DIRECTIVE, HIDE_DIRECTIVE], attrName);
1678 var isVirtual = expr.root && expr.root.tagName === 'VIRTUAL';
1679 var ref = this.__;
1680 var isAnonymous = ref.isAnonymous;
1681 var parent = dom && (expr.parent || dom.parentNode);
1682 var keepValueAttributes = settings.keepValueAttributes;
1683 // detect the style attributes
1684 var isStyleAttr = attrName === 'style';
1685 var isClassAttr = attrName === 'class';
1686 var isValueAttr = attrName === 'value';
1687
1688 var value;
1689
1690 // if it's a tag we could totally skip the rest
1691 if (expr._riot_id) {
1692 if (expr.__.wasCreated) {
1693 expr.update();
1694 // if it hasn't been mounted yet, do that now.
1695 } else {
1696 expr.mount();
1697 if (isVirtual) {
1698 makeReplaceVirtual(expr, expr.root);
1699 }
1700 }
1701 return
1702 }
1703
1704 // if this expression has the update method it means it can handle the DOM changes by itself
1705 if (expr.update) { return expr.update() }
1706
1707 var context = isToggle && !isAnonymous ? inheritParentProps.call(this) : this;
1708
1709 // ...it seems to be a simple expression so we try to calculate its value
1710 value = tmpl(expr.expr, context);
1711
1712 var hasValue = !isBlank(value);
1713 var isObj = isObject(value);
1714
1715 // convert the style/class objects to strings
1716 if (isObj) {
1717 if (isClassAttr) {
1718 value = tmpl(JSON.stringify(value), this);
1719 } else if (isStyleAttr) {
1720 value = styleObjectToString(value);
1721 }
1722 }
1723
1724 // remove original attribute
1725 if (expr.attr &&
1726 (
1727 // the original attribute can be removed only if we are parsing the original expression
1728 !expr.wasParsedOnce ||
1729 // or its value is false
1730 value === false ||
1731 // or if its value is currently falsy...
1732 // We will keep the "value" attributes if the "keepValueAttributes"
1733 // is enabled though
1734 (!hasValue && (!isValueAttr || isValueAttr && !keepValueAttributes))
1735 )
1736 ) {
1737 // remove either riot-* attributes or just the attribute name
1738 removeAttribute(dom, getAttribute(dom, expr.attr) ? expr.attr : attrName);
1739 }
1740
1741 // for the boolean attributes we don't need the value
1742 // we can convert it to checked=true to checked=checked
1743 if (expr.bool) { value = value ? attrName : false; }
1744 if (expr.isRtag) { return updateDataIs(expr, this, value) }
1745 if (expr.wasParsedOnce && expr.value === value) { return }
1746
1747 // update the expression value
1748 expr.value = value;
1749 expr.wasParsedOnce = true;
1750
1751 // if the value is an object (and it's not a style or class attribute) we can not do much more with it
1752 if (isObj && !isClassAttr && !isStyleAttr && !isToggle) { return }
1753 // avoid to render undefined/null values
1754 if (!hasValue) { value = ''; }
1755
1756 // textarea and text nodes have no attribute name
1757 if (!attrName) {
1758 // about #815 w/o replace: the browser converts the value to a string,
1759 // the comparison by "==" does too, but not in the server
1760 value += '';
1761 // test for parent avoids error with invalid assignment to nodeValue
1762 if (parent) {
1763 // cache the parent node because somehow it will become null on IE
1764 // on the next iteration
1765 expr.parent = parent;
1766 if (parent.tagName === 'TEXTAREA') {
1767 parent.value = value; // #1113
1768 if (!IE_VERSION) { dom.nodeValue = value; } // #1625 IE throws here, nodeValue
1769 } // will be available on 'updated'
1770 else { dom.nodeValue = value; }
1771 }
1772 return
1773 }
1774
1775 switch (true) {
1776 // handle events binding
1777 case isFunction(value):
1778 if (isEventAttribute(attrName)) {
1779 setEventHandler(attrName, value, dom, this);
1780 }
1781 break
1782 // show / hide
1783 case isToggle:
1784 toggleVisibility(dom, attrName === HIDE_DIRECTIVE ? !value : value);
1785 break
1786 // handle attributes
1787 default:
1788 if (expr.bool) {
1789 dom[attrName] = value;
1790 }
1791
1792 if (isValueAttr && dom.value !== value) {
1793 dom.value = value;
1794 } else if (hasValue && value !== false) {
1795 setAttribute(dom, attrName, value);
1796 }
1797
1798 // make sure that in case of style changes
1799 // the element stays hidden
1800 if (isStyleAttr && dom.hidden) { toggleVisibility(dom, false); }
1801 }
1802 }
1803
1804 /**
1805 * Update all the expressions in a Tag instance
1806 * @this Tag
1807 * @param { Array } expressions - expression that must be re evaluated
1808 */
1809 function update(expressions) {
1810 each(expressions, updateExpression.bind(this));
1811 }
1812
1813 /**
1814 * We need to update opts for this tag. That requires updating the expressions
1815 * in any attributes on the tag, and then copying the result onto opts.
1816 * @this Tag
1817 * @param {Boolean} isLoop - is it a loop tag?
1818 * @param { Tag } parent - parent tag node
1819 * @param { Boolean } isAnonymous - is it a tag without any impl? (a tag not registered)
1820 * @param { Object } opts - tag options
1821 * @param { Array } instAttrs - tag attributes array
1822 */
1823 function updateOpts(isLoop, parent, isAnonymous, opts, instAttrs) {
1824 // isAnonymous `each` tags treat `dom` and `root` differently. In this case
1825 // (and only this case) we don't need to do updateOpts, because the regular parse
1826 // will update those attrs. Plus, isAnonymous tags don't need opts anyway
1827 if (isLoop && isAnonymous) { return }
1828 var ctx = isLoop ? inheritParentProps.call(this) : parent || this;
1829
1830 each(instAttrs, function (attr) {
1831 if (attr.expr) { updateExpression.call(ctx, attr.expr); }
1832 // normalize the attribute names
1833 opts[toCamel(attr.name).replace(ATTRS_PREFIX, '')] = attr.expr ? attr.expr.value : attr.value;
1834 });
1835 }
1836
1837 /**
1838 * Update the tag expressions and options
1839 * @param { Tag } tag - tag object
1840 * @param { * } data - data we want to use to extend the tag properties
1841 * @param { Array } expressions - component expressions array
1842 * @returns { Tag } the current tag instance
1843 */
1844 function componentUpdate(tag, data, expressions) {
1845 var __ = tag.__;
1846 var nextOpts = {};
1847 var canTrigger = tag.isMounted && !__.skipAnonymous;
1848
1849 // inherit properties from the parent tag
1850 if (__.isAnonymous && __.parent) { extend(tag, __.parent); }
1851 extend(tag, data);
1852
1853 updateOpts.apply(tag, [__.isLoop, __.parent, __.isAnonymous, nextOpts, __.instAttrs]);
1854
1855 if (
1856 canTrigger &&
1857 tag.isMounted &&
1858 isFunction(tag.shouldUpdate) && !tag.shouldUpdate(data, nextOpts)
1859 ) {
1860 return tag
1861 }
1862
1863 extend(tag.opts, nextOpts);
1864
1865 if (canTrigger) { tag.trigger('update', data); }
1866 update.call(tag, expressions);
1867 if (canTrigger) { tag.trigger('updated'); }
1868
1869 return tag
1870 }
1871
1872 /**
1873 * Get selectors for tags
1874 * @param { Array } tags - tag names to select
1875 * @returns { String } selector
1876 */
1877 function query(tags) {
1878 // select all tags
1879 if (!tags) {
1880 var keys = Object.keys(__TAG_IMPL);
1881 return keys + query(keys)
1882 }
1883
1884 return tags
1885 .filter(function (t) { return !/[^-\w]/.test(t); })
1886 .reduce(function (list, t) {
1887 var name = t.trim().toLowerCase();
1888 return list + ",[" + IS_DIRECTIVE + "=\"" + name + "\"]"
1889 }, '')
1890 }
1891
1892 /**
1893 * Another way to create a riot tag a bit more es6 friendly
1894 * @param { HTMLElement } el - tag DOM selector or DOM node/s
1895 * @param { Object } opts - tag logic
1896 * @returns { Tag } new riot tag instance
1897 */
1898 function Tag(el, opts) {
1899 // get the tag properties from the class constructor
1900 var ref = this;
1901 var name = ref.name;
1902 var tmpl = ref.tmpl;
1903 var css = ref.css;
1904 var attrs = ref.attrs;
1905 var onCreate = ref.onCreate;
1906 // register a new tag and cache the class prototype
1907 if (!__TAG_IMPL[name]) {
1908 tag(name, tmpl, css, attrs, onCreate);
1909 // cache the class constructor
1910 __TAG_IMPL[name].class = this.constructor;
1911 }
1912
1913 // mount the tag using the class instance
1914 mount$1(el, name, opts, this);
1915 // inject the component css
1916 if (css) { styleManager.inject(); }
1917
1918 return this
1919 }
1920
1921 /**
1922 * Create a new riot tag implementation
1923 * @param { String } name - name/id of the new riot tag
1924 * @param { String } tmpl - tag template
1925 * @param { String } css - custom tag css
1926 * @param { String } attrs - root tag attributes
1927 * @param { Function } fn - user function
1928 * @returns { String } name/id of the tag just created
1929 */
1930 function tag(name, tmpl, css, attrs, fn) {
1931 if (isFunction(attrs)) {
1932 fn = attrs;
1933
1934 if (/^[\w-]+\s?=/.test(css)) {
1935 attrs = css;
1936 css = '';
1937 } else
1938 { attrs = ''; }
1939 }
1940
1941 if (css) {
1942 if (isFunction(css))
1943 { fn = css; }
1944 else
1945 { styleManager.add(css, name); }
1946 }
1947
1948 name = name.toLowerCase();
1949 __TAG_IMPL[name] = { name: name, tmpl: tmpl, attrs: attrs, fn: fn };
1950
1951 return name
1952 }
1953
1954 /**
1955 * Create a new riot tag implementation (for use by the compiler)
1956 * @param { String } name - name/id of the new riot tag
1957 * @param { String } tmpl - tag template
1958 * @param { String } css - custom tag css
1959 * @param { String } attrs - root tag attributes
1960 * @param { Function } fn - user function
1961 * @returns { String } name/id of the tag just created
1962 */
1963 function tag2(name, tmpl, css, attrs, fn) {
1964 if (css) { styleManager.add(css, name); }
1965
1966 __TAG_IMPL[name] = { name: name, tmpl: tmpl, attrs: attrs, fn: fn };
1967
1968 return name
1969 }
1970
1971 /**
1972 * Mount a tag using a specific tag implementation
1973 * @param { * } selector - tag DOM selector or DOM node/s
1974 * @param { String } tagName - tag implementation name
1975 * @param { Object } opts - tag logic
1976 * @returns { Array } new tags instances
1977 */
1978 function mount(selector, tagName, opts) {
1979 var tags = [];
1980 var elem, allTags;
1981
1982 function pushTagsTo(root) {
1983 if (root.tagName) {
1984 var riotTag = getAttribute(root, IS_DIRECTIVE), tag;
1985
1986 // have tagName? force riot-tag to be the same
1987 if (tagName && riotTag !== tagName) {
1988 riotTag = tagName;
1989 setAttribute(root, IS_DIRECTIVE, tagName);
1990 }
1991
1992 tag = mount$1(
1993 root,
1994 riotTag || root.tagName.toLowerCase(),
1995 isFunction(opts) ? opts() : opts
1996 );
1997
1998 if (tag)
1999 { tags.push(tag); }
2000 } else if (root.length)
2001 { each(root, pushTagsTo); } // assume nodeList
2002 }
2003
2004 // inject styles into DOM
2005 styleManager.inject();
2006
2007 if (isObject(tagName) || isFunction(tagName)) {
2008 opts = tagName;
2009 tagName = 0;
2010 }
2011
2012 // crawl the DOM to find the tag
2013 if (isString(selector)) {
2014 selector = selector === '*' ?
2015 // select all registered tags
2016 // & tags found with the riot-tag attribute set
2017 allTags = query() :
2018 // or just the ones named like the selector
2019 selector + query(selector.split(/, */));
2020
2021 // make sure to pass always a selector
2022 // to the querySelectorAll function
2023 elem = selector ? $$(selector) : [];
2024 }
2025 else
2026 // probably you have passed already a tag or a NodeList
2027 { elem = selector; }
2028
2029 // select all the registered and mount them inside their root elements
2030 if (tagName === '*') {
2031 // get all custom tags
2032 tagName = allTags || query();
2033 // if the root els it's just a single tag
2034 if (elem.tagName)
2035 { elem = $$(tagName, elem); }
2036 else {
2037 // select all the children for all the different root elements
2038 var nodeList = [];
2039
2040 each(elem, function (_el) { return nodeList.push($$(tagName, _el)); });
2041
2042 elem = nodeList;
2043 }
2044 // get rid of the tagName
2045 tagName = 0;
2046 }
2047
2048 pushTagsTo(elem);
2049
2050 return tags
2051 }
2052
2053 // Create a mixin that could be globally shared across all the tags
2054 var mixins = {};
2055 var globals = mixins[GLOBAL_MIXIN] = {};
2056 var mixins_id = 0;
2057
2058 /**
2059 * Create/Return a mixin by its name
2060 * @param { String } name - mixin name (global mixin if object)
2061 * @param { Object } mix - mixin logic
2062 * @param { Boolean } g - is global?
2063 * @returns { Object } the mixin logic
2064 */
2065 function mixin(name, mix, g) {
2066 // Unnamed global
2067 if (isObject(name)) {
2068 mixin(("__" + (mixins_id++) + "__"), name, true);
2069 return
2070 }
2071
2072 var store = g ? globals : mixins;
2073
2074 // Getter
2075 if (!mix) {
2076 if (isUndefined(store[name]))
2077 { throw new Error(("Unregistered mixin: " + name)) }
2078
2079 return store[name]
2080 }
2081
2082 // Setter
2083 store[name] = isFunction(mix) ?
2084 extend(mix.prototype, store[name] || {}) && mix :
2085 extend(store[name] || {}, mix);
2086 }
2087
2088 /**
2089 * Update all the tags instances created
2090 * @returns { Array } all the tags instances
2091 */
2092 function update$1() {
2093 return each(__TAGS_CACHE, function (tag) { return tag.update(); })
2094 }
2095
2096 function unregister(name) {
2097 styleManager.remove(name);
2098 return delete __TAG_IMPL[name]
2099 }
2100
2101 var version = 'v3.13.2';
2102
2103 var core = /*#__PURE__*/Object.freeze({
2104 Tag: Tag,
2105 tag: tag,
2106 tag2: tag2,
2107 mount: mount,
2108 mixin: mixin,
2109 update: update$1,
2110 unregister: unregister,
2111 version: version
2112 });
2113
2114 /**
2115 * Add a mixin to this tag
2116 * @returns { Tag } the current tag instance
2117 */
2118 function componentMixin(tag$$1) {
2119 var mixins = [], len = arguments.length - 1;
2120 while ( len-- > 0 ) mixins[ len ] = arguments[ len + 1 ];
2121
2122 each(mixins, function (mix) {
2123 var instance;
2124 var obj;
2125 var props = [];
2126
2127 // properties blacklisted and will not be bound to the tag instance
2128 var propsBlacklist = ['init', '__proto__'];
2129
2130 mix = isString(mix) ? mixin(mix) : mix;
2131
2132 // check if the mixin is a function
2133 if (isFunction(mix)) {
2134 // create the new mixin instance
2135 instance = new mix();
2136 } else { instance = mix; }
2137
2138 var proto = Object.getPrototypeOf(instance);
2139
2140 // build multilevel prototype inheritance chain property list
2141 do { props = props.concat(Object.getOwnPropertyNames(obj || instance)); }
2142 while (obj = Object.getPrototypeOf(obj || instance))
2143
2144 // loop the keys in the function prototype or the all object keys
2145 each(props, function (key) {
2146 // bind methods to tag
2147 // allow mixins to override other properties/parent mixins
2148 if (!contains(propsBlacklist, key)) {
2149 // check for getters/setters
2150 var descriptor = getPropDescriptor(instance, key) || getPropDescriptor(proto, key);
2151 var hasGetterSetter = descriptor && (descriptor.get || descriptor.set);
2152
2153 // apply method only if it does not already exist on the instance
2154 if (!tag$$1.hasOwnProperty(key) && hasGetterSetter) {
2155 Object.defineProperty(tag$$1, key, descriptor);
2156 } else {
2157 tag$$1[key] = isFunction(instance[key]) ?
2158 instance[key].bind(tag$$1) :
2159 instance[key];
2160 }
2161 }
2162 });
2163
2164 // init method will be called automatically
2165 if (instance.init)
2166 { instance.init.bind(tag$$1)(tag$$1.opts); }
2167 });
2168
2169 return tag$$1
2170 }
2171
2172 /**
2173 * Move the position of a custom tag in its parent tag
2174 * @this Tag
2175 * @param { String } tagName - key where the tag was stored
2176 * @param { Number } newPos - index where the new tag will be stored
2177 */
2178 function moveChild(tagName, newPos) {
2179 var parent = this.parent;
2180 var tags;
2181 // no parent no move
2182 if (!parent) { return }
2183
2184 tags = parent.tags[tagName];
2185
2186 if (isArray(tags))
2187 { tags.splice(newPos, 0, tags.splice(tags.indexOf(this), 1)[0]); }
2188 else { arrayishAdd(parent.tags, tagName, this); }
2189 }
2190
2191 /**
2192 * Move virtual tag and all child nodes
2193 * @this Tag
2194 * @param { Node } src - the node that will do the inserting
2195 * @param { Tag } target - insert before this tag's first child
2196 */
2197 function moveVirtual(src, target) {
2198 var this$1 = this;
2199
2200 var el = this.__.head;
2201 var sib;
2202 var frag = createFragment();
2203
2204 while (el) {
2205 sib = el.nextSibling;
2206 frag.appendChild(el);
2207 el = sib;
2208 if (el === this$1.__.tail) {
2209 frag.appendChild(el);
2210 src.insertBefore(frag, target.__.head);
2211 break
2212 }
2213 }
2214 }
2215
2216 /**
2217 * Convert the item looped into an object used to extend the child tag properties
2218 * @param { Object } expr - object containing the keys used to extend the children tags
2219 * @param { * } key - value to assign to the new object returned
2220 * @param { * } val - value containing the position of the item in the array
2221 * @returns { Object } - new object containing the values of the original item
2222 *
2223 * The variables 'key' and 'val' are arbitrary.
2224 * They depend on the collection type looped (Array, Object)
2225 * and on the expression used on the each tag
2226 *
2227 */
2228 function mkitem(expr, key, val) {
2229 var item = {};
2230 item[expr.key] = key;
2231 if (expr.pos) { item[expr.pos] = val; }
2232 return item
2233 }
2234
2235 /**
2236 * Unmount the redundant tags
2237 * @param { Array } items - array containing the current items to loop
2238 * @param { Array } tags - array containing all the children tags
2239 */
2240 function unmountRedundant(items, tags, filteredItemsCount) {
2241 var i = tags.length;
2242 var j = items.length - filteredItemsCount;
2243
2244 while (i > j) {
2245 i--;
2246 remove.apply(tags[i], [tags, i]);
2247 }
2248 }
2249
2250
2251 /**
2252 * Remove a child tag
2253 * @this Tag
2254 * @param { Array } tags - tags collection
2255 * @param { Number } i - index of the tag to remove
2256 */
2257 function remove(tags, i) {
2258 tags.splice(i, 1);
2259 this.unmount();
2260 arrayishRemove(this.parent, this, this.__.tagName, true);
2261 }
2262
2263 /**
2264 * Move the nested custom tags in non custom loop tags
2265 * @this Tag
2266 * @param { Number } i - current position of the loop tag
2267 */
2268 function moveNestedTags(i) {
2269 var this$1 = this;
2270
2271 each(Object.keys(this.tags), function (tagName) {
2272 moveChild.apply(this$1.tags[tagName], [tagName, i]);
2273 });
2274 }
2275
2276 /**
2277 * Move a child tag
2278 * @this Tag
2279 * @param { HTMLElement } root - dom node containing all the loop children
2280 * @param { Tag } nextTag - instance of the next tag preceding the one we want to move
2281 * @param { Boolean } isVirtual - is it a virtual tag?
2282 */
2283 function move(root, nextTag, isVirtual) {
2284 if (isVirtual)
2285 { moveVirtual.apply(this, [root, nextTag]); }
2286 else
2287 { safeInsert(root, this.root, nextTag.root); }
2288 }
2289
2290 /**
2291 * Insert and mount a child tag
2292 * @this Tag
2293 * @param { HTMLElement } root - dom node containing all the loop children
2294 * @param { Tag } nextTag - instance of the next tag preceding the one we want to insert
2295 * @param { Boolean } isVirtual - is it a virtual tag?
2296 */
2297 function insert(root, nextTag, isVirtual) {
2298 if (isVirtual)
2299 { makeVirtual.apply(this, [root, nextTag]); }
2300 else
2301 { safeInsert(root, this.root, nextTag.root); }
2302 }
2303
2304 /**
2305 * Append a new tag into the DOM
2306 * @this Tag
2307 * @param { HTMLElement } root - dom node containing all the loop children
2308 * @param { Boolean } isVirtual - is it a virtual tag?
2309 */
2310 function append(root, isVirtual) {
2311 if (isVirtual)
2312 { makeVirtual.call(this, root); }
2313 else
2314 { root.appendChild(this.root); }
2315 }
2316
2317 /**
2318 * Return the value we want to use to lookup the postion of our items in the collection
2319 * @param { String } keyAttr - lookup string or expression
2320 * @param { * } originalItem - original item from the collection
2321 * @param { Object } keyedItem - object created by riot via { item, i in collection }
2322 * @param { Boolean } hasKeyAttrExpr - flag to check whether the key is an expression
2323 * @returns { * } value that we will use to figure out the item position via collection.indexOf
2324 */
2325 function getItemId(keyAttr, originalItem, keyedItem, hasKeyAttrExpr) {
2326 if (keyAttr) {
2327 return hasKeyAttrExpr ? tmpl(keyAttr, keyedItem) : originalItem[keyAttr]
2328 }
2329
2330 return originalItem
2331 }
2332
2333 /**
2334 * Manage tags having the 'each'
2335 * @param { HTMLElement } dom - DOM node we need to loop
2336 * @param { Tag } parent - parent tag instance where the dom node is contained
2337 * @param { String } expr - string contained in the 'each' attribute
2338 * @returns { Object } expression object for this each loop
2339 */
2340 function _each(dom, parent, expr) {
2341 var mustReorder = typeof getAttribute(dom, LOOP_NO_REORDER_DIRECTIVE) !== T_STRING || removeAttribute(dom, LOOP_NO_REORDER_DIRECTIVE);
2342 var keyAttr = getAttribute(dom, KEY_DIRECTIVE);
2343 var hasKeyAttrExpr = keyAttr ? tmpl.hasExpr(keyAttr) : false;
2344 var tagName = getName(dom);
2345 var impl = __TAG_IMPL[tagName];
2346 var parentNode = dom.parentNode;
2347 var placeholder = createDOMPlaceholder();
2348 var child = get(dom);
2349 var ifExpr = getAttribute(dom, CONDITIONAL_DIRECTIVE);
2350 var tags = [];
2351 var isLoop = true;
2352 var innerHTML = dom.innerHTML;
2353 var isAnonymous = !__TAG_IMPL[tagName];
2354 var isVirtual = dom.tagName === 'VIRTUAL';
2355 var oldItems = [];
2356
2357 // remove the each property from the original tag
2358 removeAttribute(dom, LOOP_DIRECTIVE);
2359 removeAttribute(dom, KEY_DIRECTIVE);
2360
2361 // parse the each expression
2362 expr = tmpl.loopKeys(expr);
2363 expr.isLoop = true;
2364
2365 if (ifExpr) { removeAttribute(dom, CONDITIONAL_DIRECTIVE); }
2366
2367 // insert a marked where the loop tags will be injected
2368 parentNode.insertBefore(placeholder, dom);
2369 parentNode.removeChild(dom);
2370
2371 expr.update = function updateEach() {
2372 // get the new items collection
2373 expr.value = tmpl(expr.val, parent);
2374
2375 var items = expr.value;
2376 var frag = createFragment();
2377 var isObject = !isArray(items) && !isString(items);
2378 var root = placeholder.parentNode;
2379 var tmpItems = [];
2380 var hasKeys = isObject && !!items;
2381
2382 // if this DOM was removed the update here is useless
2383 // this condition fixes also a weird async issue on IE in our unit test
2384 if (!root) { return }
2385
2386 // object loop. any changes cause full redraw
2387 if (isObject) {
2388 items = items ? Object.keys(items).map(function (key) { return mkitem(expr, items[key], key); }) : [];
2389 }
2390
2391 // store the amount of filtered items
2392 var filteredItemsCount = 0;
2393
2394 // loop all the new items
2395 each(items, function (_item, index) {
2396 var i = index - filteredItemsCount;
2397 var item = !hasKeys && expr.key ? mkitem(expr, _item, index) : _item;
2398
2399 // skip this item because it must be filtered
2400 if (ifExpr && !tmpl(ifExpr, extend(create(parent), item))) {
2401 filteredItemsCount ++;
2402 return
2403 }
2404
2405 var itemId = getItemId(keyAttr, _item, item, hasKeyAttrExpr);
2406 // reorder only if the items are not objects
2407 // or a key attribute has been provided
2408 var doReorder = !isObject && mustReorder && typeof _item === T_OBJECT || keyAttr;
2409 var oldPos = oldItems.indexOf(itemId);
2410 var isNew = oldPos === -1;
2411 var pos = !isNew && doReorder ? oldPos : i;
2412 // does a tag exist in this position?
2413 var tag = tags[pos];
2414 var mustAppend = i >= oldItems.length;
2415 var mustCreate = doReorder && isNew || !doReorder && !tag || !tags[i];
2416
2417 // new tag
2418 if (mustCreate) {
2419 tag = createTag(impl, {
2420 parent: parent,
2421 isLoop: isLoop,
2422 isAnonymous: isAnonymous,
2423 tagName: tagName,
2424 root: dom.cloneNode(isAnonymous),
2425 item: item,
2426 index: i,
2427 }, innerHTML);
2428
2429 // mount the tag
2430 tag.mount();
2431
2432 if (mustAppend)
2433 { append.apply(tag, [frag || root, isVirtual]); }
2434 else
2435 { insert.apply(tag, [root, tags[i], isVirtual]); }
2436
2437 if (!mustAppend) { oldItems.splice(i, 0, item); }
2438 tags.splice(i, 0, tag);
2439 if (child) { arrayishAdd(parent.tags, tagName, tag, true); }
2440 } else if (pos !== i && doReorder) {
2441 // move
2442 if (keyAttr || contains(items, oldItems[pos])) {
2443 move.apply(tag, [root, tags[i], isVirtual]);
2444 // move the old tag instance
2445 tags.splice(i, 0, tags.splice(pos, 1)[0]);
2446 // move the old item
2447 oldItems.splice(i, 0, oldItems.splice(pos, 1)[0]);
2448 }
2449
2450 // update the position attribute if it exists
2451 if (expr.pos) { tag[expr.pos] = i; }
2452
2453 // if the loop tags are not custom
2454 // we need to move all their custom tags into the right position
2455 if (!child && tag.tags) { moveNestedTags.call(tag, i); }
2456 }
2457
2458 // cache the original item to use it in the events bound to this node
2459 // and its children
2460 extend(tag.__, {
2461 item: item,
2462 index: i,
2463 parent: parent
2464 });
2465
2466 tmpItems[i] = itemId;
2467
2468 if (!mustCreate) { tag.update(item); }
2469 });
2470
2471 // remove the redundant tags
2472 unmountRedundant(items, tags, filteredItemsCount);
2473
2474 // clone the items array
2475 oldItems = tmpItems.slice();
2476
2477 root.insertBefore(frag, placeholder);
2478 };
2479
2480 expr.unmount = function () {
2481 each(tags, function (t) { t.unmount(); });
2482 };
2483
2484 return expr
2485 }
2486
2487 var RefExpr = {
2488 init: function init(dom, parent, attrName, attrValue) {
2489 this.dom = dom;
2490 this.attr = attrName;
2491 this.rawValue = attrValue;
2492 this.parent = parent;
2493 this.hasExp = tmpl.hasExpr(attrValue);
2494 return this
2495 },
2496 update: function update() {
2497 var old = this.value;
2498 var customParent = this.parent && getImmediateCustomParent(this.parent);
2499 // if the referenced element is a custom tag, then we set the tag itself, rather than DOM
2500 var tagOrDom = this.dom.__ref || this.tag || this.dom;
2501
2502 this.value = this.hasExp ? tmpl(this.rawValue, this.parent) : this.rawValue;
2503
2504 // the name changed, so we need to remove it from the old key (if present)
2505 if (!isBlank(old) && customParent) { arrayishRemove(customParent.refs, old, tagOrDom); }
2506 if (!isBlank(this.value) && isString(this.value)) {
2507 // add it to the refs of parent tag (this behavior was changed >=3.0)
2508 if (customParent) { arrayishAdd(
2509 customParent.refs,
2510 this.value,
2511 tagOrDom,
2512 // use an array if it's a looped node and the ref is not an expression
2513 null,
2514 this.parent.__.index
2515 ); }
2516
2517 if (this.value !== old) {
2518 setAttribute(this.dom, this.attr, this.value);
2519 }
2520 } else {
2521 removeAttribute(this.dom, this.attr);
2522 }
2523
2524 // cache the ref bound to this dom node
2525 // to reuse it in future (see also #2329)
2526 if (!this.dom.__ref) { this.dom.__ref = tagOrDom; }
2527 },
2528 unmount: function unmount() {
2529 var tagOrDom = this.tag || this.dom;
2530 var customParent = this.parent && getImmediateCustomParent(this.parent);
2531 if (!isBlank(this.value) && customParent)
2532 { arrayishRemove(customParent.refs, this.value, tagOrDom); }
2533 }
2534 };
2535
2536 /**
2537 * Create a new ref directive
2538 * @param { HTMLElement } dom - dom node having the ref attribute
2539 * @param { Tag } context - tag instance where the DOM node is located
2540 * @param { String } attrName - either 'ref' or 'data-ref'
2541 * @param { String } attrValue - value of the ref attribute
2542 * @returns { RefExpr } a new RefExpr object
2543 */
2544 function createRefDirective(dom, tag, attrName, attrValue) {
2545 return create(RefExpr).init(dom, tag, attrName, attrValue)
2546 }
2547
2548 /**
2549 * Trigger the unmount method on all the expressions
2550 * @param { Array } expressions - DOM expressions
2551 */
2552 function unmountAll(expressions) {
2553 each(expressions, function (expr) {
2554 if (expr.unmount) { expr.unmount(true); }
2555 else if (expr.tagName) { expr.tag.unmount(true); }
2556 else if (expr.unmount) { expr.unmount(); }
2557 });
2558 }
2559
2560 var IfExpr = {
2561 init: function init(dom, tag, expr) {
2562 removeAttribute(dom, CONDITIONAL_DIRECTIVE);
2563 extend(this, { tag: tag, expr: expr, stub: createDOMPlaceholder(), pristine: dom });
2564 var p = dom.parentNode;
2565 p.insertBefore(this.stub, dom);
2566 p.removeChild(dom);
2567
2568 return this
2569 },
2570 update: function update$$1() {
2571 this.value = tmpl(this.expr, this.tag);
2572
2573 if (!this.stub.parentNode) { return }
2574
2575 if (this.value && !this.current) { // insert
2576 this.current = this.pristine.cloneNode(true);
2577 this.stub.parentNode.insertBefore(this.current, this.stub);
2578 this.expressions = parseExpressions.apply(this.tag, [this.current, true]);
2579 } else if (!this.value && this.current) { // remove
2580 this.unmount();
2581 this.current = null;
2582 this.expressions = [];
2583 }
2584
2585 if (this.value) { update.call(this.tag, this.expressions); }
2586 },
2587 unmount: function unmount() {
2588 if (this.current) {
2589 if (this.current._tag) {
2590 this.current._tag.unmount();
2591 } else if (this.current.parentNode) {
2592 this.current.parentNode.removeChild(this.current);
2593 }
2594 }
2595
2596 unmountAll(this.expressions || []);
2597 }
2598 };
2599
2600 /**
2601 * Create a new if directive
2602 * @param { HTMLElement } dom - if root dom node
2603 * @param { Tag } context - tag instance where the DOM node is located
2604 * @param { String } attr - if expression
2605 * @returns { IFExpr } a new IfExpr object
2606 */
2607 function createIfDirective(dom, tag, attr) {
2608 return create(IfExpr).init(dom, tag, attr)
2609 }
2610
2611 /**
2612 * Walk the tag DOM to detect the expressions to evaluate
2613 * @this Tag
2614 * @param { HTMLElement } root - root tag where we will start digging the expressions
2615 * @param { Boolean } mustIncludeRoot - flag to decide whether the root must be parsed as well
2616 * @returns { Array } all the expressions found
2617 */
2618 function parseExpressions(root, mustIncludeRoot) {
2619 var this$1 = this;
2620
2621 var expressions = [];
2622
2623 walkNodes(root, function (dom) {
2624 var type = dom.nodeType;
2625 var attr;
2626 var tagImpl;
2627
2628 if (!mustIncludeRoot && dom === root) { return }
2629
2630 // text node
2631 if (type === 3 && dom.parentNode.tagName !== 'STYLE' && tmpl.hasExpr(dom.nodeValue))
2632 { expressions.push({dom: dom, expr: dom.nodeValue}); }
2633
2634 if (type !== 1) { return }
2635
2636 var isVirtual = dom.tagName === 'VIRTUAL';
2637
2638 // loop. each does it's own thing (for now)
2639 if (attr = getAttribute(dom, LOOP_DIRECTIVE)) {
2640 if(isVirtual) { setAttribute(dom, 'loopVirtual', true); } // ignore here, handled in _each
2641 expressions.push(_each(dom, this$1, attr));
2642 return false
2643 }
2644
2645 // if-attrs become the new parent. Any following expressions (either on the current
2646 // element, or below it) become children of this expression.
2647 if (attr = getAttribute(dom, CONDITIONAL_DIRECTIVE)) {
2648 expressions.push(createIfDirective(dom, this$1, attr));
2649 return false
2650 }
2651
2652 if (attr = getAttribute(dom, IS_DIRECTIVE)) {
2653 if (tmpl.hasExpr(attr)) {
2654 expressions.push({
2655 isRtag: true,
2656 expr: attr,
2657 dom: dom,
2658 attrs: [].slice.call(dom.attributes)
2659 });
2660
2661 return false
2662 }
2663 }
2664
2665 // if this is a tag, stop traversing here.
2666 // we ignore the root, since parseExpressions is called while we're mounting that root
2667 tagImpl = get(dom);
2668
2669 if(isVirtual) {
2670 if(getAttribute(dom, 'virtualized')) {dom.parentElement.removeChild(dom); } // tag created, remove from dom
2671 if(!tagImpl && !getAttribute(dom, 'virtualized') && !getAttribute(dom, 'loopVirtual')) // ok to create virtual tag
2672 { tagImpl = { tmpl: dom.outerHTML }; }
2673 }
2674
2675 if (tagImpl && (dom !== root || mustIncludeRoot)) {
2676 var hasIsDirective = getAttribute(dom, IS_DIRECTIVE);
2677 if(isVirtual && !hasIsDirective) { // handled in update
2678 // can not remove attribute like directives
2679 // so flag for removal after creation to prevent maximum stack error
2680 setAttribute(dom, 'virtualized', true);
2681 var tag = createTag(
2682 {tmpl: dom.outerHTML},
2683 {root: dom, parent: this$1},
2684 dom.innerHTML
2685 );
2686
2687 expressions.push(tag); // no return, anonymous tag, keep parsing
2688 } else {
2689 if (hasIsDirective && isVirtual)
2690 { warn(("Virtual tags shouldn't be used together with the \"" + IS_DIRECTIVE + "\" attribute - https://github.com/riot/riot/issues/2511")); }
2691
2692 expressions.push(
2693 initChild(
2694 tagImpl,
2695 {
2696 root: dom,
2697 parent: this$1
2698 },
2699 dom.innerHTML,
2700 this$1
2701 )
2702 );
2703 return false
2704 }
2705 }
2706
2707 // attribute expressions
2708 parseAttributes.apply(this$1, [dom, dom.attributes, function (attr, expr) {
2709 if (!expr) { return }
2710 expressions.push(expr);
2711 }]);
2712 });
2713
2714 return expressions
2715 }
2716
2717 /**
2718 * Calls `fn` for every attribute on an element. If that attr has an expression,
2719 * it is also passed to fn.
2720 * @this Tag
2721 * @param { HTMLElement } dom - dom node to parse
2722 * @param { Array } attrs - array of attributes
2723 * @param { Function } fn - callback to exec on any iteration
2724 */
2725 function parseAttributes(dom, attrs, fn) {
2726 var this$1 = this;
2727
2728 each(attrs, function (attr) {
2729 if (!attr) { return false }
2730
2731 var name = attr.name;
2732 var bool = isBoolAttr(name);
2733 var expr;
2734
2735 if (contains(REF_DIRECTIVES, name) && dom.tagName.toLowerCase() !== YIELD_TAG) {
2736 expr = createRefDirective(dom, this$1, name, attr.value);
2737 } else if (tmpl.hasExpr(attr.value)) {
2738 expr = {dom: dom, expr: attr.value, attr: name, bool: bool};
2739 }
2740
2741 fn(attr, expr);
2742 });
2743 }
2744
2745 /**
2746 * Manage the mount state of a tag triggering also the observable events
2747 * @this Tag
2748 * @param { Boolean } value - ..of the isMounted flag
2749 */
2750 function setMountState(value) {
2751 var ref = this.__;
2752 var isAnonymous = ref.isAnonymous;
2753 var skipAnonymous = ref.skipAnonymous;
2754
2755 define(this, 'isMounted', value);
2756
2757 if (!isAnonymous || !skipAnonymous) {
2758 if (value) { this.trigger('mount'); }
2759 else {
2760 this.trigger('unmount');
2761 this.off('*');
2762 this.__.wasCreated = false;
2763 }
2764 }
2765 }
2766
2767 /**
2768 * Mount the current tag instance
2769 * @returns { Tag } the current tag instance
2770 */
2771 function componentMount(tag$$1, dom, expressions, opts) {
2772 var __ = tag$$1.__;
2773 var root = __.root;
2774 root._tag = tag$$1; // keep a reference to the tag just created
2775
2776 // Read all the attrs on this instance. This give us the info we need for updateOpts
2777 parseAttributes.apply(__.parent, [root, root.attributes, function (attr, expr) {
2778 if (!__.isAnonymous && RefExpr.isPrototypeOf(expr)) { expr.tag = tag$$1; }
2779 attr.expr = expr;
2780 __.instAttrs.push(attr);
2781 }]);
2782
2783 // update the root adding custom attributes coming from the compiler
2784 walkAttributes(__.impl.attrs, function (k, v) { __.implAttrs.push({name: k, value: v}); });
2785 parseAttributes.apply(tag$$1, [root, __.implAttrs, function (attr, expr) {
2786 if (expr) { expressions.push(expr); }
2787 else { setAttribute(root, attr.name, attr.value); }
2788 }]);
2789
2790 // initialiation
2791 updateOpts.apply(tag$$1, [__.isLoop, __.parent, __.isAnonymous, opts, __.instAttrs]);
2792
2793 // add global mixins
2794 var globalMixin = mixin(GLOBAL_MIXIN);
2795
2796 if (globalMixin && !__.skipAnonymous) {
2797 for (var i in globalMixin) {
2798 if (globalMixin.hasOwnProperty(i)) {
2799 tag$$1.mixin(globalMixin[i]);
2800 }
2801 }
2802 }
2803
2804 if (__.impl.fn) { __.impl.fn.call(tag$$1, opts); }
2805
2806 if (!__.skipAnonymous) { tag$$1.trigger('before-mount'); }
2807
2808 // parse layout after init. fn may calculate args for nested custom tags
2809 each(parseExpressions.apply(tag$$1, [dom, __.isAnonymous]), function (e) { return expressions.push(e); });
2810
2811 tag$$1.update(__.item);
2812
2813 if (!__.isAnonymous && !__.isInline) {
2814 while (dom.firstChild) { root.appendChild(dom.firstChild); }
2815 }
2816
2817 define(tag$$1, 'root', root);
2818
2819 // if we need to wait that the parent "mount" or "updated" event gets triggered
2820 if (!__.skipAnonymous && tag$$1.parent) {
2821 var p = getImmediateCustomParent(tag$$1.parent);
2822 p.one(!p.isMounted ? 'mount' : 'updated', function () {
2823 setMountState.call(tag$$1, true);
2824 });
2825 } else {
2826 // otherwise it's not a child tag we can trigger its mount event
2827 setMountState.call(tag$$1, true);
2828 }
2829
2830 tag$$1.__.wasCreated = true;
2831
2832 return tag$$1
2833 }
2834
2835 /**
2836 * Unmount the tag instance
2837 * @param { Boolean } mustKeepRoot - if it's true the root node will not be removed
2838 * @returns { Tag } the current tag instance
2839 */
2840 function tagUnmount(tag, mustKeepRoot, expressions) {
2841 var __ = tag.__;
2842 var root = __.root;
2843 var tagIndex = __TAGS_CACHE.indexOf(tag);
2844 var p = root.parentNode;
2845
2846 if (!__.skipAnonymous) { tag.trigger('before-unmount'); }
2847
2848 // clear all attributes coming from the mounted tag
2849 walkAttributes(__.impl.attrs, function (name) {
2850 if (startsWith(name, ATTRS_PREFIX))
2851 { name = name.slice(ATTRS_PREFIX.length); }
2852
2853 removeAttribute(root, name);
2854 });
2855
2856 // remove all the event listeners
2857 tag.__.listeners.forEach(function (dom) {
2858 Object.keys(dom[RIOT_EVENTS_KEY]).forEach(function (eventName) {
2859 dom.removeEventListener(eventName, dom[RIOT_EVENTS_KEY][eventName]);
2860 });
2861 });
2862
2863 // remove tag instance from the global tags cache collection
2864 if (tagIndex !== -1) { __TAGS_CACHE.splice(tagIndex, 1); }
2865
2866 // clean up the parent tags object
2867 if (__.parent && !__.isAnonymous) {
2868 var ptag = getImmediateCustomParent(__.parent);
2869
2870 if (__.isVirtual) {
2871 Object
2872 .keys(tag.tags)
2873 .forEach(function (tagName) { return arrayishRemove(ptag.tags, tagName, tag.tags[tagName]); });
2874 } else {
2875 arrayishRemove(ptag.tags, __.tagName, tag);
2876 }
2877 }
2878
2879 // unmount all the virtual directives
2880 if (tag.__.virts) {
2881 each(tag.__.virts, function (v) {
2882 if (v.parentNode) { v.parentNode.removeChild(v); }
2883 });
2884 }
2885
2886 // allow expressions to unmount themselves
2887 unmountAll(expressions);
2888 each(__.instAttrs, function (a) { return a.expr && a.expr.unmount && a.expr.unmount(); });
2889
2890 // clear the tag html if it's necessary
2891 if (mustKeepRoot) { setInnerHTML(root, ''); }
2892 // otherwise detach the root tag from the DOM
2893 else if (p) { p.removeChild(root); }
2894
2895 // custom internal unmount function to avoid relying on the observable
2896 if (__.onUnmount) { __.onUnmount(); }
2897
2898 // weird fix for a weird edge case #2409 and #2436
2899 // some users might use your software not as you've expected
2900 // so I need to add these dirty hacks to mitigate unexpected issues
2901 if (!tag.isMounted) { setMountState.call(tag, true); }
2902
2903 setMountState.call(tag, false);
2904
2905 delete root._tag;
2906
2907 return tag
2908 }
2909
2910 /**
2911 * Tag creation factory function
2912 * @constructor
2913 * @param { Object } impl - it contains the tag template, and logic
2914 * @param { Object } conf - tag options
2915 * @param { String } innerHTML - html that eventually we need to inject in the tag
2916 */
2917 function createTag(impl, conf, innerHTML) {
2918 if ( impl === void 0 ) impl = {};
2919 if ( conf === void 0 ) conf = {};
2920
2921 var tag = conf.context || {};
2922 var opts = conf.opts || {};
2923 var parent = conf.parent;
2924 var isLoop = conf.isLoop;
2925 var isAnonymous = !!conf.isAnonymous;
2926 var skipAnonymous = settings.skipAnonymousTags && isAnonymous;
2927 var item = conf.item;
2928 // available only for the looped nodes
2929 var index = conf.index;
2930 // All attributes on the Tag when it's first parsed
2931 var instAttrs = [];
2932 // expressions on this type of Tag
2933 var implAttrs = [];
2934 var tmpl = impl.tmpl;
2935 var expressions = [];
2936 var root = conf.root;
2937 var tagName = conf.tagName || getName(root);
2938 var isVirtual = tagName === 'virtual';
2939 var isInline = !isVirtual && !tmpl;
2940 var dom;
2941
2942 if (isInline || isLoop && isAnonymous) {
2943 dom = root;
2944 } else {
2945 if (!isVirtual) { root.innerHTML = ''; }
2946 dom = mkdom(tmpl, innerHTML, isSvg(root));
2947 }
2948
2949 // make this tag observable
2950 if (!skipAnonymous) { observable(tag); }
2951
2952 // only call unmount if we have a valid __TAG_IMPL (has name property)
2953 if (impl.name && root._tag) { root._tag.unmount(true); }
2954
2955 define(tag, '__', {
2956 impl: impl,
2957 root: root,
2958 skipAnonymous: skipAnonymous,
2959 implAttrs: implAttrs,
2960 isAnonymous: isAnonymous,
2961 instAttrs: instAttrs,
2962 innerHTML: innerHTML,
2963 tagName: tagName,
2964 index: index,
2965 isLoop: isLoop,
2966 isInline: isInline,
2967 item: item,
2968 parent: parent,
2969 // tags having event listeners
2970 // it would be better to use weak maps here but we can not introduce breaking changes now
2971 listeners: [],
2972 // these vars will be needed only for the virtual tags
2973 virts: [],
2974 wasCreated: false,
2975 tail: null,
2976 head: null
2977 });
2978
2979 // tag protected properties
2980 return [
2981 ['isMounted', false],
2982 // create a unique id to this tag
2983 // it could be handy to use it also to improve the virtual dom rendering speed
2984 ['_riot_id', uid()],
2985 ['root', root],
2986 ['opts', opts, { writable: true, enumerable: true }],
2987 ['parent', parent || null],
2988 // protect the "tags" and "refs" property from being overridden
2989 ['tags', {}],
2990 ['refs', {}],
2991 ['update', function (data) { return componentUpdate(tag, data, expressions); }],
2992 ['mixin', function () {
2993 var mixins = [], len = arguments.length;
2994 while ( len-- ) mixins[ len ] = arguments[ len ];
2995
2996 return componentMixin.apply(void 0, [ tag ].concat( mixins ));
2997 }],
2998 ['mount', function () { return componentMount(tag, dom, expressions, opts); }],
2999 ['unmount', function (mustKeepRoot) { return tagUnmount(tag, mustKeepRoot, expressions); }]
3000 ].reduce(function (acc, ref) {
3001 var key = ref[0];
3002 var value = ref[1];
3003 var opts = ref[2];
3004
3005 define(tag, key, value, opts);
3006 return acc
3007 }, extend(tag, item))
3008 }
3009
3010 /**
3011 * Mount a tag creating new Tag instance
3012 * @param { Object } root - dom node where the tag will be mounted
3013 * @param { String } tagName - name of the riot tag we want to mount
3014 * @param { Object } opts - options to pass to the Tag instance
3015 * @param { Object } ctx - optional context that will be used to extend an existing class ( used in riot.Tag )
3016 * @returns { Tag } a new Tag instance
3017 */
3018 function mount$1(root, tagName, opts, ctx) {
3019 var impl = __TAG_IMPL[tagName];
3020 var implClass = __TAG_IMPL[tagName].class;
3021 var context = ctx || (implClass ? create(implClass.prototype) : {});
3022 // cache the inner HTML to fix #855
3023 var innerHTML = root._innerHTML = root._innerHTML || root.innerHTML;
3024 var conf = extend({ root: root, opts: opts, context: context }, { parent: opts ? opts.parent : null });
3025 var tag;
3026
3027 if (impl && root) { tag = createTag(impl, conf, innerHTML); }
3028
3029 if (tag && tag.mount) {
3030 tag.mount(true);
3031 // add this tag to the virtualDom variable
3032 if (!contains(__TAGS_CACHE, tag)) { __TAGS_CACHE.push(tag); }
3033 }
3034
3035 return tag
3036 }
3037
3038
3039
3040 var tags = /*#__PURE__*/Object.freeze({
3041 arrayishAdd: arrayishAdd,
3042 getTagName: getName,
3043 inheritParentProps: inheritParentProps,
3044 mountTo: mount$1,
3045 selectTags: query,
3046 arrayishRemove: arrayishRemove,
3047 getTag: get,
3048 initChildTag: initChild,
3049 moveChildTag: moveChild,
3050 makeReplaceVirtual: makeReplaceVirtual,
3051 getImmediateCustomParentTag: getImmediateCustomParent,
3052 makeVirtual: makeVirtual,
3053 moveVirtual: moveVirtual,
3054 unmountAll: unmountAll,
3055 createIfDirective: createIfDirective,
3056 createRefDirective: createRefDirective
3057 });
3058
3059 /**
3060 * Riot public api
3061 */
3062 var settings$1 = settings;
3063 var util = {
3064 tmpl: tmpl,
3065 brackets: brackets,
3066 styleManager: styleManager,
3067 vdom: __TAGS_CACHE,
3068 styleNode: styleManager.styleNode,
3069 // export the riot internal utils as well
3070 dom: dom,
3071 check: check,
3072 misc: misc,
3073 tags: tags
3074 };
3075
3076 // export the core props/methods
3077 var Tag$1 = Tag;
3078 var tag$1 = tag;
3079 var tag2$1 = tag2;
3080 var mount$2 = mount;
3081 var mixin$1 = mixin;
3082 var update$2 = update$1;
3083 var unregister$1 = unregister;
3084 var version$1 = version;
3085 var observable$1 = observable;
3086
3087 var riot$1 = extend({}, core, {
3088 observable: observable,
3089 settings: settings$1,
3090 util: util,
3091 });
3092
3093 exports.settings = settings$1;
3094 exports.util = util;
3095 exports.Tag = Tag$1;
3096 exports.tag = tag$1;
3097 exports.tag2 = tag2$1;
3098 exports.mount = mount$2;
3099 exports.mixin = mixin$1;
3100 exports.update = update$2;
3101 exports.unregister = unregister$1;
3102 exports.version = version$1;
3103 exports.observable = observable$1;
3104 exports.default = riot$1;
3105
3106 Object.defineProperty(exports, '__esModule', { value: true });
3107
3108})));