riot_js-rails 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,21 @@
1
+ (function(program, execJS) { execJS(program) })(function(module, exports, console) {
2
+ #{source}
3
+ }, function(program) {
4
+ var output, print = function(string) {
5
+ process.stdout.write('' + string);
6
+ };
7
+ try {
8
+ result = program();
9
+ if (typeof result == 'undefined' && result !== null) {
10
+ print('["ok"]');
11
+ } else {
12
+ try {
13
+ print(JSON.stringify(['ok', result]));
14
+ } catch (err) {
15
+ print('["err"]');
16
+ }
17
+ }
18
+ } catch (err) {
19
+ print(JSON.stringify(['err', '' + err]));
20
+ }
21
+ });
@@ -0,0 +1,32 @@
1
+ var parsers = {
2
+ html: {
3
+ jade: function(html) {
4
+ return require('jade').render(html, {pretty: true, doctype: 'html'})
5
+ }
6
+ },
7
+ css: {},
8
+ js: {
9
+ none: function(js) {
10
+ return js
11
+ },
12
+ livescript: function(js) {
13
+ return require('livescript').compile(js, { bare: true, header: false })
14
+ },
15
+ typescript: function(js) {
16
+ return require('typescript-simple')(js)
17
+ },
18
+ es6: function(js) {
19
+ return require('babel').transform(js, { blacklist: ['useStrict'] }).code
20
+ },
21
+ coffee: function(js) {
22
+ return require('coffee-script').compile(js, { bare: true })
23
+ }
24
+ }
25
+ }
26
+
27
+ // fix 913
28
+ parsers.js.javascript = parsers.js.none
29
+ // 4 the nostalgics
30
+ parsers.js.coffeescript = parsers.js.coffee
31
+
32
+ module.exports = parsers
@@ -0,0 +1,1370 @@
1
+ /* Riot v2.2.4, @license MIT, (c) 2015 Muut Inc. + contributors */
2
+
3
+ ;(function(window, undefined) {
4
+ 'use strict';
5
+ var riot = { version: 'v2.2.4', settings: {} },
6
+ //// be aware, internal usage
7
+
8
+ // counter to give a unique id to all the Tag instances
9
+ __uid = 0,
10
+
11
+ // riot specific prefixes
12
+ RIOT_PREFIX = 'riot-',
13
+ RIOT_TAG = RIOT_PREFIX + 'tag',
14
+
15
+ // for typeof == '' comparisons
16
+ T_STRING = 'string',
17
+ T_OBJECT = 'object',
18
+ T_UNDEF = 'undefined',
19
+ T_FUNCTION = 'function',
20
+ // special native tags that cannot be treated like the others
21
+ SPECIAL_TAGS_REGEX = /^(?:opt(ion|group)|tbody|col|t[rhd])$/,
22
+ RESERVED_WORDS_BLACKLIST = ['_item', '_id', 'update', 'root', 'mount', 'unmount', 'mixin', 'isMounted', 'isLoop', 'tags', 'parent', 'opts', 'trigger', 'on', 'off', 'one'],
23
+
24
+ // version# for IE 8-11, 0 for others
25
+ IE_VERSION = (window && window.document || {}).documentMode | 0,
26
+
27
+ // Array.isArray for IE8 is in the polyfills
28
+ isArray = Array.isArray
29
+
30
+ riot.observable = function(el) {
31
+
32
+ el = el || {}
33
+
34
+ var callbacks = {},
35
+ _id = 0
36
+
37
+ el.on = function(events, fn) {
38
+ if (isFunction(fn)) {
39
+ if (typeof fn.id === T_UNDEF) fn._id = _id++
40
+
41
+ events.replace(/\S+/g, function(name, pos) {
42
+ (callbacks[name] = callbacks[name] || []).push(fn)
43
+ fn.typed = pos > 0
44
+ })
45
+ }
46
+ return el
47
+ }
48
+
49
+ el.off = function(events, fn) {
50
+ if (events == '*') callbacks = {}
51
+ else {
52
+ events.replace(/\S+/g, function(name) {
53
+ if (fn) {
54
+ var arr = callbacks[name]
55
+ for (var i = 0, cb; (cb = arr && arr[i]); ++i) {
56
+ if (cb._id == fn._id) arr.splice(i--, 1)
57
+ }
58
+ } else {
59
+ callbacks[name] = []
60
+ }
61
+ })
62
+ }
63
+ return el
64
+ }
65
+
66
+ // only single event supported
67
+ el.one = function(name, fn) {
68
+ function on() {
69
+ el.off(name, on)
70
+ fn.apply(el, arguments)
71
+ }
72
+ return el.on(name, on)
73
+ }
74
+
75
+ el.trigger = function(name) {
76
+ var args = [].slice.call(arguments, 1),
77
+ fns = callbacks[name] || []
78
+
79
+ for (var i = 0, fn; (fn = fns[i]); ++i) {
80
+ if (!fn.busy) {
81
+ fn.busy = 1
82
+ fn.apply(el, fn.typed ? [name].concat(args) : args)
83
+ if (fns[i] !== fn) { i-- }
84
+ fn.busy = 0
85
+ }
86
+ }
87
+
88
+ if (callbacks.all && name != 'all') {
89
+ el.trigger.apply(el, ['all', name].concat(args))
90
+ }
91
+
92
+ return el
93
+ }
94
+
95
+ return el
96
+
97
+ }
98
+ riot.mixin = (function() {
99
+ var mixins = {}
100
+
101
+ return function(name, mixin) {
102
+ if (!mixin) return mixins[name]
103
+ mixins[name] = mixin
104
+ }
105
+
106
+ })()
107
+
108
+ ;(function(riot, evt, win) {
109
+
110
+ // browsers only
111
+ if (!win) return
112
+
113
+ var loc = win.location,
114
+ fns = riot.observable(),
115
+ started = false,
116
+ current
117
+
118
+ function hash() {
119
+ return loc.href.split('#')[1] || '' // why not loc.hash.splice(1) ?
120
+ }
121
+
122
+ function parser(path) {
123
+ return path.split('/')
124
+ }
125
+
126
+ function emit(path) {
127
+ if (path.type) path = hash()
128
+
129
+ if (path != current) {
130
+ fns.trigger.apply(null, ['H'].concat(parser(path)))
131
+ current = path
132
+ }
133
+ }
134
+
135
+ var r = riot.route = function(arg) {
136
+ // string
137
+ if (arg[0]) {
138
+ loc.hash = arg
139
+ emit(arg)
140
+
141
+ // function
142
+ } else {
143
+ fns.on('H', arg)
144
+ }
145
+ }
146
+
147
+ r.exec = function(fn) {
148
+ fn.apply(null, parser(hash()))
149
+ }
150
+
151
+ r.parser = function(fn) {
152
+ parser = fn
153
+ }
154
+
155
+ r.stop = function () {
156
+ if (started) {
157
+ if (win.removeEventListener) win.removeEventListener(evt, emit, false) //@IE8 - the if()
158
+ else win.detachEvent('on' + evt, emit) //@IE8
159
+ fns.off('*')
160
+ started = false
161
+ }
162
+ }
163
+
164
+ r.start = function () {
165
+ if (!started) {
166
+ if (win.addEventListener) win.addEventListener(evt, emit, false) //@IE8 - the if()
167
+ else win.attachEvent('on' + evt, emit) //IE8
168
+ started = true
169
+ }
170
+ }
171
+
172
+ // autostart the router
173
+ r.start()
174
+
175
+ })(riot, 'hashchange', window)
176
+ /*
177
+
178
+ //// How it works?
179
+
180
+
181
+ Three ways:
182
+
183
+ 1. Expressions: tmpl('{ value }', data).
184
+ Returns the result of evaluated expression as a raw object.
185
+
186
+ 2. Templates: tmpl('Hi { name } { surname }', data).
187
+ Returns a string with evaluated expressions.
188
+
189
+ 3. Filters: tmpl('{ show: !done, highlight: active }', data).
190
+ Returns a space separated list of trueish keys (mainly
191
+ used for setting html classes), e.g. "show highlight".
192
+
193
+
194
+ // Template examples
195
+
196
+ tmpl('{ title || "Untitled" }', data)
197
+ tmpl('Results are { results ? "ready" : "loading" }', data)
198
+ tmpl('Today is { new Date() }', data)
199
+ tmpl('{ message.length > 140 && "Message is too long" }', data)
200
+ tmpl('This item got { Math.round(rating) } stars', data)
201
+ tmpl('<h1>{ title }</h1>{ body }', data)
202
+
203
+
204
+ // Falsy expressions in templates
205
+
206
+ In templates (as opposed to single expressions) all falsy values
207
+ except zero (undefined/null/false) will default to empty string:
208
+
209
+ tmpl('{ undefined } - { false } - { null } - { 0 }', {})
210
+ // will return: " - - - 0"
211
+
212
+ */
213
+
214
+
215
+ var brackets = (function(orig) {
216
+
217
+ var cachedBrackets,
218
+ r,
219
+ b,
220
+ re = /[{}]/g
221
+
222
+ return function(x) {
223
+
224
+ // make sure we use the current setting
225
+ var s = riot.settings.brackets || orig
226
+
227
+ // recreate cached vars if needed
228
+ if (cachedBrackets !== s) {
229
+ cachedBrackets = s
230
+ b = s.split(' ')
231
+ r = b.map(function (e) { return e.replace(/(?=.)/g, '\\') })
232
+ }
233
+
234
+ // if regexp given, rewrite it with current brackets (only if differ from default)
235
+ return x instanceof RegExp ? (
236
+ s === orig ? x :
237
+ new RegExp(x.source.replace(re, function(b) { return r[~~(b === '}')] }), x.global ? 'g' : '')
238
+ ) :
239
+ // else, get specific bracket
240
+ b[x]
241
+ }
242
+ })('{ }')
243
+
244
+
245
+ var tmpl = (function() {
246
+
247
+ var cache = {},
248
+ OGLOB = '"in d?d:' + (window ? 'window).' : 'global).'),
249
+ reVars =
250
+ /(['"\/])(?:[^\\]*?|\\.|.)*?\1|\.\w*|\w*:|\b(?:(?:new|typeof|in|instanceof) |(?:this|true|false|null|undefined)\b|function\s*\()|([A-Za-z_$]\w*)/g
251
+
252
+ // build a template (or get it from cache), render with data
253
+ return function(str, data) {
254
+ return str && (cache[str] || (cache[str] = tmpl(str)))(data)
255
+ }
256
+
257
+
258
+ // create a template instance
259
+
260
+ function tmpl(s, p) {
261
+
262
+ if (s.indexOf(brackets(0)) < 0) {
263
+ // return raw text
264
+ s = s.replace(/\n|\r\n?/g, '\n')
265
+ return function () { return s }
266
+ }
267
+
268
+ // temporarily convert \{ and \} to a non-character
269
+ s = s
270
+ .replace(brackets(/\\{/g), '\uFFF0')
271
+ .replace(brackets(/\\}/g), '\uFFF1')
272
+
273
+ // split string to expression and non-expresion parts
274
+ p = split(s, extract(s, brackets(/{/), brackets(/}/)))
275
+
276
+ // is it a single expression or a template? i.e. {x} or <b>{x}</b>
277
+ s = (p.length === 2 && !p[0]) ?
278
+
279
+ // if expression, evaluate it
280
+ expr(p[1]) :
281
+
282
+ // if template, evaluate all expressions in it
283
+ '[' + p.map(function(s, i) {
284
+
285
+ // is it an expression or a string (every second part is an expression)
286
+ return i % 2 ?
287
+
288
+ // evaluate the expressions
289
+ expr(s, true) :
290
+
291
+ // process string parts of the template:
292
+ '"' + s
293
+
294
+ // preserve new lines
295
+ .replace(/\n|\r\n?/g, '\\n')
296
+
297
+ // escape quotes
298
+ .replace(/"/g, '\\"') +
299
+
300
+ '"'
301
+
302
+ }).join(',') + '].join("")'
303
+
304
+ return new Function('d', 'return ' + s
305
+ // bring escaped { and } back
306
+ .replace(/\uFFF0/g, brackets(0))
307
+ .replace(/\uFFF1/g, brackets(1)) + ';')
308
+
309
+ }
310
+
311
+
312
+ // parse { ... } expression
313
+
314
+ function expr(s, n) {
315
+ s = s
316
+
317
+ // convert new lines to spaces
318
+ .replace(/\n|\r\n?/g, ' ')
319
+
320
+ // trim whitespace, brackets, strip comments
321
+ .replace(brackets(/^[{ ]+|[ }]+$|\/\*.+?\*\//g), '')
322
+
323
+ // is it an object literal? i.e. { key : value }
324
+ return /^\s*[\w- "']+ *:/.test(s) ?
325
+
326
+ // if object literal, return trueish keys
327
+ // e.g.: { show: isOpen(), done: item.done } -> "show done"
328
+ '[' +
329
+
330
+ // extract key:val pairs, ignoring any nested objects
331
+ extract(s,
332
+
333
+ // name part: name:, "name":, 'name':, name :
334
+ /["' ]*[\w- ]+["' ]*:/,
335
+
336
+ // expression part: everything upto a comma followed by a name (see above) or end of line
337
+ /,(?=["' ]*[\w- ]+["' ]*:)|}|$/
338
+ ).map(function(pair) {
339
+
340
+ // get key, val parts
341
+ return pair.replace(/^[ "']*(.+?)[ "']*: *(.+?),? *$/, function(_, k, v) {
342
+
343
+ // wrap all conditional parts to ignore errors
344
+ return v.replace(/[^&|=!><]+/g, wrap) + '?"' + k + '":"",'
345
+
346
+ })
347
+
348
+ }).join('') +
349
+
350
+ '].join(" ").trim()' :
351
+
352
+ // if js expression, evaluate as javascript
353
+ wrap(s, n)
354
+
355
+ }
356
+
357
+
358
+ // execute js w/o breaking on errors or undefined vars
359
+
360
+ function wrap(s, nonull) {
361
+ s = s.trim()
362
+ return !s ? '' : '(function(v){try{v=' +
363
+
364
+ // prefix vars (name => data.name)
365
+ s.replace(reVars, function(s, _, v) { return v ? '(("' + v + OGLOB + v + ')' : s }) +
366
+
367
+ // default to empty string for falsy values except zero
368
+ '}catch(e){}return ' + (nonull === true ? '!v&&v!==0?"":v' : 'v') + '}).call(d)'
369
+ }
370
+
371
+
372
+ // split string by an array of substrings
373
+
374
+ function split(str, substrings) {
375
+ var parts = []
376
+ substrings.map(function(sub, i) {
377
+
378
+ // push matched expression and part before it
379
+ i = str.indexOf(sub)
380
+ parts.push(str.slice(0, i), sub)
381
+ str = str.slice(i + sub.length)
382
+ })
383
+ if (str) parts.push(str)
384
+
385
+ // push the remaining part
386
+ return parts
387
+ }
388
+
389
+
390
+ // match strings between opening and closing regexp, skipping any inner/nested matches
391
+
392
+ function extract(str, open, close) {
393
+
394
+ var start,
395
+ level = 0,
396
+ matches = [],
397
+ re = new RegExp('(' + open.source + ')|(' + close.source + ')', 'g')
398
+
399
+ str.replace(re, function(_, open, close, pos) {
400
+
401
+ // if outer inner bracket, mark position
402
+ if (!level && open) start = pos
403
+
404
+ // in(de)crease bracket level
405
+ level += open ? 1 : -1
406
+
407
+ // if outer closing bracket, grab the match
408
+ if (!level && close != null) matches.push(str.slice(start, pos + close.length))
409
+
410
+ })
411
+
412
+ return matches
413
+ }
414
+
415
+ })()
416
+
417
+ /*
418
+ lib/browser/tag/mkdom.js
419
+
420
+ Includes hacks needed for the Internet Explorer version 9 and bellow
421
+
422
+ */
423
+ // http://kangax.github.io/compat-table/es5/#ie8
424
+ // http://codeplanet.io/dropping-ie8/
425
+
426
+ var mkdom = (function (checkIE) {
427
+
428
+ var rootEls = {
429
+ 'tr': 'tbody',
430
+ 'th': 'tr',
431
+ 'td': 'tr',
432
+ 'tbody': 'table',
433
+ 'col': 'colgroup'
434
+ },
435
+ GENERIC = 'div'
436
+
437
+ checkIE = checkIE && checkIE < 10
438
+
439
+ // creates any dom element in a div, table, or colgroup container
440
+ function _mkdom(html) {
441
+
442
+ var match = html && html.match(/^\s*<([-\w]+)/),
443
+ tagName = match && match[1].toLowerCase(),
444
+ rootTag = rootEls[tagName] || GENERIC,
445
+ el = mkEl(rootTag)
446
+
447
+ el.stub = true
448
+
449
+ if (checkIE && tagName && (match = tagName.match(SPECIAL_TAGS_REGEX)))
450
+ ie9elem(el, html, tagName, !!match[1])
451
+ else
452
+ el.innerHTML = html
453
+
454
+ return el
455
+ }
456
+
457
+ // creates tr, th, td, option, optgroup element for IE8-9
458
+ /* istanbul ignore next */
459
+ function ie9elem(el, html, tagName, select) {
460
+
461
+ var div = mkEl(GENERIC),
462
+ tag = select ? 'select>' : 'table>',
463
+ child
464
+
465
+ div.innerHTML = '<' + tag + html + '</' + tag
466
+
467
+ child = div.getElementsByTagName(tagName)[0]
468
+ if (child)
469
+ el.appendChild(child)
470
+
471
+ }
472
+ // end ie9elem()
473
+
474
+ return _mkdom
475
+
476
+ })(IE_VERSION)
477
+
478
+ // { key, i in items} -> { key, i, items }
479
+ function loopKeys(expr) {
480
+ var b0 = brackets(0),
481
+ els = expr.trim().slice(b0.length).match(/^\s*(\S+?)\s*(?:,\s*(\S+))?\s+in\s+(.+)$/)
482
+ return els ? { key: els[1], pos: els[2], val: b0 + els[3] } : { val: expr }
483
+ }
484
+
485
+ function mkitem(expr, key, val) {
486
+ var item = {}
487
+ item[expr.key] = key
488
+ if (expr.pos) item[expr.pos] = val
489
+ return item
490
+ }
491
+
492
+
493
+ /* Beware: heavy stuff */
494
+ function _each(dom, parent, expr) {
495
+
496
+ remAttr(dom, 'each')
497
+
498
+ var tagName = getTagName(dom),
499
+ template = dom.outerHTML,
500
+ hasImpl = !!tagImpl[tagName],
501
+ impl = tagImpl[tagName] || {
502
+ tmpl: template
503
+ },
504
+ root = dom.parentNode,
505
+ placeholder = document.createComment('riot placeholder'),
506
+ tags = [],
507
+ child = getTag(dom),
508
+ checksum
509
+
510
+ root.insertBefore(placeholder, dom)
511
+
512
+ expr = loopKeys(expr)
513
+
514
+ // clean template code
515
+ parent
516
+ .one('premount', function () {
517
+ if (root.stub) root = parent.root
518
+ // remove the original DOM node
519
+ dom.parentNode.removeChild(dom)
520
+ })
521
+ .on('update', function () {
522
+ var items = tmpl(expr.val, parent)
523
+
524
+ // object loop. any changes cause full redraw
525
+ if (!isArray(items)) {
526
+
527
+ checksum = items ? JSON.stringify(items) : ''
528
+
529
+ items = !items ? [] :
530
+ Object.keys(items).map(function (key) {
531
+ return mkitem(expr, key, items[key])
532
+ })
533
+ }
534
+
535
+ var frag = document.createDocumentFragment(),
536
+ i = tags.length,
537
+ j = items.length
538
+
539
+ // unmount leftover items
540
+ while (i > j) {
541
+ tags[--i].unmount()
542
+ tags.splice(i, 1)
543
+ }
544
+
545
+ for (i = 0; i < j; ++i) {
546
+ var _item = !checksum && !!expr.key ? mkitem(expr, items[i], i) : items[i]
547
+
548
+ if (!tags[i]) {
549
+ // mount new
550
+ (tags[i] = new Tag(impl, {
551
+ parent: parent,
552
+ isLoop: true,
553
+ hasImpl: hasImpl,
554
+ root: SPECIAL_TAGS_REGEX.test(tagName) ? root : dom.cloneNode(),
555
+ item: _item
556
+ }, dom.innerHTML)
557
+ ).mount()
558
+
559
+ frag.appendChild(tags[i].root)
560
+ } else
561
+ tags[i].update(_item)
562
+
563
+ tags[i]._item = _item
564
+
565
+ }
566
+
567
+ root.insertBefore(frag, placeholder)
568
+
569
+ if (child) parent.tags[tagName] = tags
570
+
571
+ }).one('updated', function() {
572
+ var keys = Object.keys(parent)// only set new values
573
+ walk(root, function(node) {
574
+ // only set element node and not isLoop
575
+ if (node.nodeType == 1 && !node.isLoop && !node._looped) {
576
+ node._visited = false // reset _visited for loop node
577
+ node._looped = true // avoid set multiple each
578
+ setNamed(node, parent, keys)
579
+ }
580
+ })
581
+ })
582
+
583
+ }
584
+
585
+
586
+ function parseNamedElements(root, tag, childTags) {
587
+
588
+ walk(root, function(dom) {
589
+ if (dom.nodeType == 1) {
590
+ dom.isLoop = dom.isLoop || (dom.parentNode && dom.parentNode.isLoop || dom.getAttribute('each')) ? 1 : 0
591
+
592
+ // custom child tag
593
+ var child = getTag(dom)
594
+
595
+ if (child && !dom.isLoop) {
596
+ childTags.push(initChildTag(child, dom, tag))
597
+ }
598
+
599
+ if (!dom.isLoop)
600
+ setNamed(dom, tag, [])
601
+ }
602
+
603
+ })
604
+
605
+ }
606
+
607
+ function parseExpressions(root, tag, expressions) {
608
+
609
+ function addExpr(dom, val, extra) {
610
+ if (val.indexOf(brackets(0)) >= 0) {
611
+ var expr = { dom: dom, expr: val }
612
+ expressions.push(extend(expr, extra))
613
+ }
614
+ }
615
+
616
+ walk(root, function(dom) {
617
+ var type = dom.nodeType
618
+
619
+ // text node
620
+ if (type == 3 && dom.parentNode.tagName != 'STYLE') addExpr(dom, dom.nodeValue)
621
+ if (type != 1) return
622
+
623
+ /* element */
624
+
625
+ // loop
626
+ var attr = dom.getAttribute('each')
627
+
628
+ if (attr) { _each(dom, tag, attr); return false }
629
+
630
+ // attribute expressions
631
+ each(dom.attributes, function(attr) {
632
+ var name = attr.name,
633
+ bool = name.split('__')[1]
634
+
635
+ addExpr(dom, attr.value, { attr: bool || name, bool: bool })
636
+ if (bool) { remAttr(dom, name); return false }
637
+
638
+ })
639
+
640
+ // skip custom tags
641
+ if (getTag(dom)) return false
642
+
643
+ })
644
+
645
+ }
646
+ function Tag(impl, conf, innerHTML) {
647
+
648
+ var self = riot.observable(this),
649
+ opts = inherit(conf.opts) || {},
650
+ dom = mkdom(impl.tmpl),
651
+ parent = conf.parent,
652
+ isLoop = conf.isLoop,
653
+ hasImpl = conf.hasImpl,
654
+ item = cleanUpData(conf.item),
655
+ expressions = [],
656
+ childTags = [],
657
+ root = conf.root,
658
+ fn = impl.fn,
659
+ tagName = root.tagName.toLowerCase(),
660
+ attr = {},
661
+ propsInSyncWithParent = []
662
+
663
+ if (fn && root._tag) {
664
+ root._tag.unmount(true)
665
+ }
666
+
667
+ // not yet mounted
668
+ this.isMounted = false
669
+ root.isLoop = isLoop
670
+
671
+ // keep a reference to the tag just created
672
+ // so we will be able to mount this tag multiple times
673
+ root._tag = this
674
+
675
+ // create a unique id to this tag
676
+ // it could be handy to use it also to improve the virtual dom rendering speed
677
+ this._id = __uid++
678
+
679
+ extend(this, { parent: parent, root: root, opts: opts, tags: {} }, item)
680
+
681
+ // grab attributes
682
+ each(root.attributes, function(el) {
683
+ var val = el.value
684
+ // remember attributes with expressions only
685
+ if (brackets(/{.*}/).test(val)) attr[el.name] = val
686
+ })
687
+
688
+ if (dom.innerHTML && !/^(select|optgroup|table|tbody|tr|col(?:group)?)$/.test(tagName))
689
+ // replace all the yield tags with the tag inner html
690
+ dom.innerHTML = replaceYield(dom.innerHTML, innerHTML)
691
+
692
+ // options
693
+ function updateOpts() {
694
+ var ctx = hasImpl && isLoop ? self : parent || self
695
+
696
+ // update opts from current DOM attributes
697
+ each(root.attributes, function(el) {
698
+ opts[el.name] = tmpl(el.value, ctx)
699
+ })
700
+ // recover those with expressions
701
+ each(Object.keys(attr), function(name) {
702
+ opts[name] = tmpl(attr[name], ctx)
703
+ })
704
+ }
705
+
706
+ function normalizeData(data) {
707
+ for (var key in item) {
708
+ if (typeof self[key] !== T_UNDEF)
709
+ self[key] = data[key]
710
+ }
711
+ }
712
+
713
+ function inheritFromParent () {
714
+ if (!self.parent || !isLoop) return
715
+ each(Object.keys(self.parent), function(k) {
716
+ // some properties must be always in sync with the parent tag
717
+ var mustSync = !~RESERVED_WORDS_BLACKLIST.indexOf(k) && ~propsInSyncWithParent.indexOf(k)
718
+ if (typeof self[k] === T_UNDEF || mustSync) {
719
+ // track the property to keep in sync
720
+ // so we can keep it updated
721
+ if (!mustSync) propsInSyncWithParent.push(k)
722
+ self[k] = self.parent[k]
723
+ }
724
+ })
725
+ }
726
+
727
+ this.update = function(data) {
728
+ // make sure the data passed will not override
729
+ // the component core methods
730
+ data = cleanUpData(data)
731
+ // inherit properties from the parent
732
+ inheritFromParent()
733
+ // normalize the tag properties in case an item object was initially passed
734
+ if (data && typeof item === T_OBJECT) {
735
+ normalizeData(data)
736
+ item = data
737
+ }
738
+ extend(self, data)
739
+ updateOpts()
740
+ self.trigger('update', data)
741
+ update(expressions, self)
742
+ self.trigger('updated')
743
+ }
744
+
745
+ this.mixin = function() {
746
+ each(arguments, function(mix) {
747
+ mix = typeof mix === T_STRING ? riot.mixin(mix) : mix
748
+ each(Object.keys(mix), function(key) {
749
+ // bind methods to self
750
+ if (key != 'init')
751
+ self[key] = isFunction(mix[key]) ? mix[key].bind(self) : mix[key]
752
+ })
753
+ // init method will be called automatically
754
+ if (mix.init) mix.init.bind(self)()
755
+ })
756
+ }
757
+
758
+ this.mount = function() {
759
+
760
+ updateOpts()
761
+
762
+ // initialiation
763
+ if (fn) fn.call(self, opts)
764
+
765
+ // parse layout after init. fn may calculate args for nested custom tags
766
+ parseExpressions(dom, self, expressions)
767
+
768
+ // mount the child tags
769
+ toggle(true)
770
+
771
+ // update the root adding custom attributes coming from the compiler
772
+ // it fixes also #1087
773
+ if (impl.attrs || hasImpl) {
774
+ walkAttributes(impl.attrs, function (k, v) { root.setAttribute(k, v) })
775
+ parseExpressions(self.root, self, expressions)
776
+ }
777
+
778
+ if (!self.parent || isLoop) self.update(item)
779
+
780
+ // internal use only, fixes #403
781
+ self.trigger('premount')
782
+
783
+ if (isLoop && !hasImpl) {
784
+ // update the root attribute for the looped elements
785
+ self.root = root = dom.firstChild
786
+
787
+ } else {
788
+ while (dom.firstChild) root.appendChild(dom.firstChild)
789
+ if (root.stub) self.root = root = parent.root
790
+ }
791
+ // if it's not a child tag we can trigger its mount event
792
+ if (!self.parent || self.parent.isMounted) {
793
+ self.isMounted = true
794
+ self.trigger('mount')
795
+ }
796
+ // otherwise we need to wait that the parent event gets triggered
797
+ else self.parent.one('mount', function() {
798
+ // avoid to trigger the `mount` event for the tags
799
+ // not visible included in an if statement
800
+ if (!isInStub(self.root)) {
801
+ self.parent.isMounted = self.isMounted = true
802
+ self.trigger('mount')
803
+ }
804
+ })
805
+ }
806
+
807
+
808
+ this.unmount = function(keepRootTag) {
809
+ var el = root,
810
+ p = el.parentNode,
811
+ ptag
812
+
813
+ if (p) {
814
+
815
+ if (parent) {
816
+ ptag = getImmediateCustomParentTag(parent)
817
+ // remove this tag from the parent tags object
818
+ // if there are multiple nested tags with same name..
819
+ // remove this element form the array
820
+ if (isArray(ptag.tags[tagName]))
821
+ each(ptag.tags[tagName], function(tag, i) {
822
+ if (tag._id == self._id)
823
+ ptag.tags[tagName].splice(i, 1)
824
+ })
825
+ else
826
+ // otherwise just delete the tag instance
827
+ ptag.tags[tagName] = undefined
828
+ }
829
+
830
+ else
831
+ while (el.firstChild) el.removeChild(el.firstChild)
832
+
833
+ if (!keepRootTag)
834
+ p.removeChild(el)
835
+ else
836
+ // the riot-tag attribute isn't needed anymore, remove it
837
+ p.removeAttribute('riot-tag')
838
+ }
839
+
840
+
841
+ self.trigger('unmount')
842
+ toggle()
843
+ self.off('*')
844
+ // somehow ie8 does not like `delete root._tag`
845
+ root._tag = null
846
+
847
+ }
848
+
849
+ function toggle(isMount) {
850
+
851
+ // mount/unmount children
852
+ each(childTags, function(child) { child[isMount ? 'mount' : 'unmount']() })
853
+
854
+ // listen/unlisten parent (events flow one way from parent to children)
855
+ if (parent) {
856
+ var evt = isMount ? 'on' : 'off'
857
+
858
+ // the loop tags will be always in sync with the parent automatically
859
+ if (isLoop)
860
+ parent[evt]('unmount', self.unmount)
861
+ else
862
+ parent[evt]('update', self.update)[evt]('unmount', self.unmount)
863
+ }
864
+ }
865
+
866
+ // named elements available for fn
867
+ parseNamedElements(dom, this, childTags)
868
+
869
+
870
+ }
871
+
872
+ function setEventHandler(name, handler, dom, tag) {
873
+
874
+ dom[name] = function(e) {
875
+
876
+ var item = tag._item,
877
+ ptag = tag.parent,
878
+ el
879
+
880
+ if (!item)
881
+ while (ptag && !item) {
882
+ item = ptag._item
883
+ ptag = ptag.parent
884
+ }
885
+
886
+ // cross browser event fix
887
+ e = e || window.event
888
+
889
+ // ignore error on some browsers
890
+ try {
891
+ e.currentTarget = dom
892
+ if (!e.target) e.target = e.srcElement
893
+ if (!e.which) e.which = e.charCode || e.keyCode
894
+ } catch (ignored) { /**/ }
895
+
896
+ e.item = item
897
+
898
+ // prevent default behaviour (by default)
899
+ if (handler.call(tag, e) !== true && !/radio|check/.test(dom.type)) {
900
+ if (e.preventDefault) e.preventDefault()
901
+ e.returnValue = false
902
+ }
903
+
904
+ if (!e.preventUpdate) {
905
+ el = item ? getImmediateCustomParentTag(ptag) : tag
906
+ el.update()
907
+ }
908
+
909
+ }
910
+
911
+ }
912
+
913
+ // used by if- attribute
914
+ function insertTo(root, node, before) {
915
+ if (root) {
916
+ root.insertBefore(before, node)
917
+ root.removeChild(node)
918
+ }
919
+ }
920
+
921
+ function update(expressions, tag) {
922
+
923
+ each(expressions, function(expr, i) {
924
+
925
+ var dom = expr.dom,
926
+ attrName = expr.attr,
927
+ value = tmpl(expr.expr, tag),
928
+ parent = expr.dom.parentNode
929
+
930
+ if (expr.bool)
931
+ value = value ? attrName : false
932
+ else if (value == null)
933
+ value = ''
934
+
935
+ // leave out riot- prefixes from strings inside textarea
936
+ // fix #815: any value -> string
937
+ if (parent && parent.tagName == 'TEXTAREA') value = ('' + value).replace(/riot-/g, '')
938
+
939
+ // no change
940
+ if (expr.value === value) return
941
+ expr.value = value
942
+
943
+ // text node
944
+ if (!attrName) {
945
+ dom.nodeValue = '' + value // #815 related
946
+ return
947
+ }
948
+
949
+ // remove original attribute
950
+ remAttr(dom, attrName)
951
+ // event handler
952
+ if (isFunction(value)) {
953
+ setEventHandler(attrName, value, dom, tag)
954
+
955
+ // if- conditional
956
+ } else if (attrName == 'if') {
957
+ var stub = expr.stub,
958
+ add = function() { insertTo(stub.parentNode, stub, dom) },
959
+ remove = function() { insertTo(dom.parentNode, dom, stub) }
960
+
961
+ // add to DOM
962
+ if (value) {
963
+ if (stub) {
964
+ add()
965
+ dom.inStub = false
966
+ // avoid to trigger the mount event if the tags is not visible yet
967
+ // maybe we can optimize this avoiding to mount the tag at all
968
+ if (!isInStub(dom)) {
969
+ walk(dom, function(el) {
970
+ if (el._tag && !el._tag.isMounted) el._tag.isMounted = !!el._tag.trigger('mount')
971
+ })
972
+ }
973
+ }
974
+ // remove from DOM
975
+ } else {
976
+ stub = expr.stub = stub || document.createTextNode('')
977
+ // if the parentNode is defined we can easily replace the tag
978
+ if (dom.parentNode)
979
+ remove()
980
+ else
981
+ // otherwise we need to wait the updated event
982
+ (tag.parent || tag).one('updated', remove)
983
+
984
+ dom.inStub = true
985
+ }
986
+ // show / hide
987
+ } else if (/^(show|hide)$/.test(attrName)) {
988
+ if (attrName == 'hide') value = !value
989
+ dom.style.display = value ? '' : 'none'
990
+
991
+ // field value
992
+ } else if (attrName == 'value') {
993
+ dom.value = value
994
+
995
+ // <img src="{ expr }">
996
+ } else if (startsWith(attrName, RIOT_PREFIX) && attrName != RIOT_TAG) {
997
+ if (value)
998
+ dom.setAttribute(attrName.slice(RIOT_PREFIX.length), value)
999
+
1000
+ } else {
1001
+ if (expr.bool) {
1002
+ dom[attrName] = value
1003
+ if (!value) return
1004
+ }
1005
+
1006
+ if (typeof value !== T_OBJECT) dom.setAttribute(attrName, value)
1007
+
1008
+ }
1009
+
1010
+ })
1011
+
1012
+ }
1013
+ function each(els, fn) {
1014
+ for (var i = 0, len = (els || []).length, el; i < len; i++) {
1015
+ el = els[i]
1016
+ // return false -> remove current item during loop
1017
+ if (el != null && fn(el, i) === false) i--
1018
+ }
1019
+ return els
1020
+ }
1021
+
1022
+ function isFunction(v) {
1023
+ return typeof v === T_FUNCTION || false // avoid IE problems
1024
+ }
1025
+
1026
+ function remAttr(dom, name) {
1027
+ dom.removeAttribute(name)
1028
+ }
1029
+
1030
+ function getTag(dom) {
1031
+ return dom.tagName && tagImpl[dom.getAttribute(RIOT_TAG) || dom.tagName.toLowerCase()]
1032
+ }
1033
+
1034
+ function initChildTag(child, dom, parent) {
1035
+ var tag = new Tag(child, { root: dom, parent: parent }, dom.innerHTML),
1036
+ tagName = getTagName(dom),
1037
+ ptag = getImmediateCustomParentTag(parent),
1038
+ cachedTag
1039
+
1040
+ // fix for the parent attribute in the looped elements
1041
+ tag.parent = ptag
1042
+
1043
+ cachedTag = ptag.tags[tagName]
1044
+
1045
+ // if there are multiple children tags having the same name
1046
+ if (cachedTag) {
1047
+ // if the parent tags property is not yet an array
1048
+ // create it adding the first cached tag
1049
+ if (!isArray(cachedTag))
1050
+ ptag.tags[tagName] = [cachedTag]
1051
+ // add the new nested tag to the array
1052
+ if (!~ptag.tags[tagName].indexOf(tag))
1053
+ ptag.tags[tagName].push(tag)
1054
+ } else {
1055
+ ptag.tags[tagName] = tag
1056
+ }
1057
+
1058
+ // empty the child node once we got its template
1059
+ // to avoid that its children get compiled multiple times
1060
+ dom.innerHTML = ''
1061
+
1062
+ return tag
1063
+ }
1064
+
1065
+ function getImmediateCustomParentTag(tag) {
1066
+ var ptag = tag
1067
+ while (!getTag(ptag.root)) {
1068
+ if (!ptag.parent) break
1069
+ ptag = ptag.parent
1070
+ }
1071
+ return ptag
1072
+ }
1073
+
1074
+ function getTagName(dom) {
1075
+ var child = getTag(dom),
1076
+ namedTag = dom.getAttribute('name'),
1077
+ tagName = namedTag && namedTag.indexOf(brackets(0)) < 0 ? namedTag : child ? child.name : dom.tagName.toLowerCase()
1078
+
1079
+ return tagName
1080
+ }
1081
+
1082
+ function extend(src) {
1083
+ var obj, args = arguments
1084
+ for (var i = 1; i < args.length; ++i) {
1085
+ if ((obj = args[i])) {
1086
+ for (var key in obj) { // eslint-disable-line guard-for-in
1087
+ src[key] = obj[key]
1088
+ }
1089
+ }
1090
+ }
1091
+ return src
1092
+ }
1093
+
1094
+ // with this function we avoid that the current Tag methods get overridden
1095
+ function cleanUpData(data) {
1096
+ if (!(data instanceof Tag) && !(data && typeof data.trigger == T_FUNCTION)) return data
1097
+
1098
+ var o = {}
1099
+ for (var key in data) {
1100
+ if (!~RESERVED_WORDS_BLACKLIST.indexOf(key))
1101
+ o[key] = data[key]
1102
+ }
1103
+ return o
1104
+ }
1105
+
1106
+ function walk(dom, fn) {
1107
+ if (dom) {
1108
+ if (fn(dom) === false) return
1109
+ else {
1110
+ dom = dom.firstChild
1111
+
1112
+ while (dom) {
1113
+ walk(dom, fn)
1114
+ dom = dom.nextSibling
1115
+ }
1116
+ }
1117
+ }
1118
+ }
1119
+
1120
+ // minimize risk: only zero or one _space_ between attr & value
1121
+ function walkAttributes(html, fn) {
1122
+ var m,
1123
+ re = /([-\w]+) ?= ?(?:"([^"]*)|'([^']*)|({[^}]*}))/g
1124
+
1125
+ while ((m = re.exec(html))) {
1126
+ fn(m[1].toLowerCase(), m[2] || m[3] || m[4])
1127
+ }
1128
+ }
1129
+
1130
+ function isInStub(dom) {
1131
+ while (dom) {
1132
+ if (dom.inStub) return true
1133
+ dom = dom.parentNode
1134
+ }
1135
+ return false
1136
+ }
1137
+
1138
+ function mkEl(name) {
1139
+ return document.createElement(name)
1140
+ }
1141
+
1142
+ function replaceYield(tmpl, innerHTML) {
1143
+ return tmpl.replace(/<(yield)\/?>(<\/\1>)?/gi, innerHTML || '')
1144
+ }
1145
+
1146
+ function $$(selector, ctx) {
1147
+ return (ctx || document).querySelectorAll(selector)
1148
+ }
1149
+
1150
+ function $(selector, ctx) {
1151
+ return (ctx || document).querySelector(selector)
1152
+ }
1153
+
1154
+ function inherit(parent) {
1155
+ function Child() {}
1156
+ Child.prototype = parent
1157
+ return new Child()
1158
+ }
1159
+
1160
+ function setNamed(dom, parent, keys) {
1161
+ if (dom._visited) return
1162
+ var p,
1163
+ v = dom.getAttribute('id') || dom.getAttribute('name')
1164
+
1165
+ if (v) {
1166
+ if (keys.indexOf(v) < 0) {
1167
+ p = parent[v]
1168
+ if (!p)
1169
+ parent[v] = dom
1170
+ else if (isArray(p))
1171
+ p.push(dom)
1172
+ else
1173
+ parent[v] = [p, dom]
1174
+ }
1175
+ dom._visited = true
1176
+ }
1177
+ }
1178
+
1179
+ // faster String startsWith alternative
1180
+ function startsWith(src, str) {
1181
+ return src.slice(0, str.length) === str
1182
+ }
1183
+
1184
+ /*
1185
+ Virtual dom is an array of custom tags on the document.
1186
+ Updates and unmounts propagate downwards from parent to children.
1187
+ */
1188
+
1189
+ var virtualDom = [],
1190
+ tagImpl = {},
1191
+ styleNode
1192
+
1193
+ function injectStyle(css) {
1194
+
1195
+ if (riot.render) return // skip injection on the server
1196
+
1197
+ if (!styleNode) {
1198
+ styleNode = mkEl('style')
1199
+ styleNode.setAttribute('type', 'text/css')
1200
+ }
1201
+
1202
+ var head = document.head || document.getElementsByTagName('head')[0]
1203
+
1204
+ if (styleNode.styleSheet)
1205
+ styleNode.styleSheet.cssText += css
1206
+ else
1207
+ styleNode.innerHTML += css
1208
+
1209
+ if (!styleNode._rendered)
1210
+ if (styleNode.styleSheet) {
1211
+ document.body.appendChild(styleNode)
1212
+ } else {
1213
+ var rs = $('style[type=riot]')
1214
+ if (rs) {
1215
+ rs.parentNode.insertBefore(styleNode, rs)
1216
+ rs.parentNode.removeChild(rs)
1217
+ } else head.appendChild(styleNode)
1218
+
1219
+ }
1220
+
1221
+ styleNode._rendered = true
1222
+
1223
+ }
1224
+
1225
+ function mountTo(root, tagName, opts) {
1226
+ var tag = tagImpl[tagName],
1227
+ // cache the inner HTML to fix #855
1228
+ innerHTML = root._innerHTML = root._innerHTML || root.innerHTML
1229
+
1230
+ // clear the inner html
1231
+ root.innerHTML = ''
1232
+
1233
+ if (tag && root) tag = new Tag(tag, { root: root, opts: opts }, innerHTML)
1234
+
1235
+ if (tag && tag.mount) {
1236
+ tag.mount()
1237
+ virtualDom.push(tag)
1238
+ return tag.on('unmount', function() {
1239
+ virtualDom.splice(virtualDom.indexOf(tag), 1)
1240
+ })
1241
+ }
1242
+
1243
+ }
1244
+
1245
+ riot.tag = function(name, html, css, attrs, fn) {
1246
+ if (isFunction(attrs)) {
1247
+ fn = attrs
1248
+ if (/^[\w\-]+\s?=/.test(css)) {
1249
+ attrs = css
1250
+ css = ''
1251
+ } else attrs = ''
1252
+ }
1253
+ if (css) {
1254
+ if (isFunction(css)) fn = css
1255
+ else injectStyle(css)
1256
+ }
1257
+ tagImpl[name] = { name: name, tmpl: html, attrs: attrs, fn: fn }
1258
+ return name
1259
+ }
1260
+
1261
+ riot.mount = function(selector, tagName, opts) {
1262
+
1263
+ var els,
1264
+ allTags,
1265
+ tags = []
1266
+
1267
+ // helper functions
1268
+
1269
+ function addRiotTags(arr) {
1270
+ var list = ''
1271
+ each(arr, function (e) {
1272
+ list += ', *[' + RIOT_TAG + '="' + e.trim() + '"]'
1273
+ })
1274
+ return list
1275
+ }
1276
+
1277
+ function selectAllTags() {
1278
+ var keys = Object.keys(tagImpl)
1279
+ return keys + addRiotTags(keys)
1280
+ }
1281
+
1282
+ function pushTags(root) {
1283
+ var last
1284
+ if (root.tagName) {
1285
+ if (tagName && (!(last = root.getAttribute(RIOT_TAG)) || last != tagName))
1286
+ root.setAttribute(RIOT_TAG, tagName)
1287
+
1288
+ var tag = mountTo(root,
1289
+ tagName || root.getAttribute(RIOT_TAG) || root.tagName.toLowerCase(), opts)
1290
+
1291
+ if (tag) tags.push(tag)
1292
+ }
1293
+ else if (root.length) {
1294
+ each(root, pushTags) // assume nodeList
1295
+ }
1296
+ }
1297
+
1298
+ // ----- mount code -----
1299
+
1300
+ if (typeof tagName === T_OBJECT) {
1301
+ opts = tagName
1302
+ tagName = 0
1303
+ }
1304
+
1305
+ // crawl the DOM to find the tag
1306
+ if (typeof selector === T_STRING) {
1307
+ if (selector === '*')
1308
+ // select all the tags registered
1309
+ // and also the tags found with the riot-tag attribute set
1310
+ selector = allTags = selectAllTags()
1311
+ else
1312
+ // or just the ones named like the selector
1313
+ selector += addRiotTags(selector.split(','))
1314
+
1315
+ els = $$(selector)
1316
+ }
1317
+ else
1318
+ // probably you have passed already a tag or a NodeList
1319
+ els = selector
1320
+
1321
+ // select all the registered and mount them inside their root elements
1322
+ if (tagName === '*') {
1323
+ // get all custom tags
1324
+ tagName = allTags || selectAllTags()
1325
+ // if the root els it's just a single tag
1326
+ if (els.tagName)
1327
+ els = $$(tagName, els)
1328
+ else {
1329
+ // select all the children for all the different root elements
1330
+ var nodeList = []
1331
+ each(els, function (_el) {
1332
+ nodeList.push($$(tagName, _el))
1333
+ })
1334
+ els = nodeList
1335
+ }
1336
+ // get rid of the tagName
1337
+ tagName = 0
1338
+ }
1339
+
1340
+ if (els.tagName)
1341
+ pushTags(els)
1342
+ else
1343
+ each(els, pushTags)
1344
+
1345
+ return tags
1346
+ }
1347
+
1348
+ // update everything
1349
+ riot.update = function() {
1350
+ return each(virtualDom, function(tag) {
1351
+ tag.update()
1352
+ })
1353
+ }
1354
+
1355
+ // @deprecated
1356
+ riot.mountTo = riot.mount
1357
+
1358
+ // share methods for other riot parts, e.g. compiler
1359
+ riot.util = { brackets: brackets, tmpl: tmpl }
1360
+
1361
+ // support CommonJS, AMD & browser
1362
+ /* istanbul ignore next */
1363
+ if (typeof exports === T_OBJECT)
1364
+ module.exports = riot
1365
+ else if (typeof define === 'function' && define.amd)
1366
+ define(function() { return (window.riot = riot) })
1367
+ else
1368
+ window.riot = riot
1369
+
1370
+ })(typeof window != 'undefined' ? window : void 0);