riot_js-rails 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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);