riot_js-rails 0.4.0 → 0.4.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 80b0ba35335567e7fd7bbcf8817e9065ae6a22b3
4
- data.tar.gz: 4a1c402cab48fbd2abde9560987698c3e79f9873
3
+ metadata.gz: df3508dc1799dfbf259c92264868490c0fcc613d
4
+ data.tar.gz: 0de2937b97cad066642072c78e270f34359bde33
5
5
  SHA512:
6
- metadata.gz: 8c92c478dc4c74f8a0e34301173c4f3fa4fa6e36b9b2cee0fe9e93a269debb60ba0a655079a9352be55bb42c2dc8a36c7cfa33bf7487b5deb1fdaccca0fa93c7
7
- data.tar.gz: e589230ca36f8124f435f7ec815a5850519ad0a2c02d5dc34b02286671f1e42c6ce630005bdfb0181ade0e56551cad4699ded2e7f407e63d189eb7538c103596
6
+ metadata.gz: 54910c7eb889db79234749034943f5acae183b7d3e2c9d6fd2f8dd0f4a5372193245cf2e02fa7cd2c6481c830e5364a557868f129b5c949889f5158187133f00
7
+ data.tar.gz: 8da5cb92adeb951f47ece46d435a9831dd1661a85c6295645b54ca60c8480ef666f17fe4d03c0197a497b0bfc5b75428ffef2fcf353b81e670c6abe87e9aec19
data/.gitignore CHANGED
File without changes
data/Gemfile CHANGED
File without changes
data/README.md CHANGED
File without changes
data/Rakefile CHANGED
File without changes
data/lib/riot_js/rails.rb CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -1,5 +1,5 @@
1
1
  module RiotJs
2
2
  module Rails
3
- VERSION = '0.4.0'
3
+ VERSION = '0.4.1'
4
4
  end
5
5
  end
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
20
20
  spec.require_paths = ['lib']
21
21
 
22
22
 
23
- spec.add_dependency 'rails', '>= 3.0', '< 4.3'
23
+ spec.add_dependency 'rails', '>= 3.0', '<= 5.0'
24
24
  spec.add_dependency 'execjs', '~> 2'
25
25
 
26
26
  spec.add_development_dependency 'bundler', '~> 1.8'
File without changes
File without changes
File without changes
File without changes
@@ -1,8 +1,8 @@
1
- /* Riot v2.3.15, @license MIT, (c) 2015 Muut Inc. + contributors */
1
+ /* Riot v2.4.1, @license MIT */
2
2
 
3
3
  ;(function(window, undefined) {
4
4
  'use strict';
5
- var riot = { version: 'v2.3.15', settings: {} },
5
+ var riot = { version: 'v2.4.1', settings: {} },
6
6
  // be aware, internal usage
7
7
  // ATTENTION: prefix the global dynamic variables with `__`
8
8
 
@@ -16,9 +16,12 @@ var riot = { version: 'v2.3.15', settings: {} },
16
16
  /**
17
17
  * Const
18
18
  */
19
+ GLOBAL_MIXIN = '__global_mixin',
20
+
19
21
  // riot specific prefixes
20
22
  RIOT_PREFIX = 'riot-',
21
23
  RIOT_TAG = RIOT_PREFIX + 'tag',
24
+ RIOT_TAG_IS = 'data-is',
22
25
 
23
26
  // for typeof == '' comparisons
24
27
  T_STRING = 'string',
@@ -27,10 +30,15 @@ var riot = { version: 'v2.3.15', settings: {} },
27
30
  T_FUNCTION = 'function',
28
31
  // special native tags that cannot be treated like the others
29
32
  SPECIAL_TAGS_REGEX = /^(?:t(?:body|head|foot|[rhd])|caption|col(?:group)?|opt(?:ion|group))$/,
30
- RESERVED_WORDS_BLACKLIST = ['_item', '_id', '_parent', 'update', 'root', 'mount', 'unmount', 'mixin', 'isMounted', 'isLoop', 'tags', 'parent', 'opts', 'trigger', 'on', 'off', 'one'],
33
+ RESERVED_WORDS_BLACKLIST = /^(?:_(?:item|id|parent)|update|root|(?:un)?mount|mixin|is(?:Mounted|Loop)|tags|parent|opts|trigger|o(?:n|ff|ne))$/,
34
+ // SVG tags list https://www.w3.org/TR/SVG/attindex.html#PresentationAttributes
35
+ SVG_TAGS_LIST = ['altGlyph', 'animate', 'animateColor', 'circle', 'clipPath', 'defs', 'ellipse', 'feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feFlood', 'feGaussianBlur', 'feImage', 'feMerge', 'feMorphology', 'feOffset', 'feSpecularLighting', 'feTile', 'feTurbulence', 'filter', 'font', 'foreignObject', 'g', 'glyph', 'glyphRef', 'image', 'line', 'linearGradient', 'marker', 'mask', 'missing-glyph', 'path', 'pattern', 'polygon', 'polyline', 'radialGradient', 'rect', 'stop', 'svg', 'switch', 'symbol', 'text', 'textPath', 'tref', 'tspan', 'use'],
31
36
 
32
37
  // version# for IE 8-11, 0 for others
33
- IE_VERSION = (window && window.document || {}).documentMode | 0
38
+ IE_VERSION = (window && window.document || {}).documentMode | 0,
39
+
40
+ // detect firefox to fix #1374
41
+ FIREFOX = window && !!window.InstallTrigger
34
42
  /* istanbul ignore next */
35
43
  riot.observable = function(el) {
36
44
 
@@ -42,102 +50,146 @@ riot.observable = function(el) {
42
50
  el = el || {}
43
51
 
44
52
  /**
45
- * Private variables and methods
53
+ * Private variables
46
54
  */
47
55
  var callbacks = {},
48
- slice = Array.prototype.slice,
49
- onEachEvent = function(e, fn) { e.replace(/\S+/g, fn) },
50
- defineProperty = function (key, value) {
51
- Object.defineProperty(el, key, {
52
- value: value,
53
- enumerable: false,
54
- writable: false,
55
- configurable: false
56
- })
57
- }
56
+ slice = Array.prototype.slice
58
57
 
59
58
  /**
60
- * Listen to the given space separated list of `events` and execute the `callback` each time an event is triggered.
61
- * @param { String } events - events ids
62
- * @param { Function } fn - callback function
63
- * @returns { Object } el
59
+ * Private Methods
64
60
  */
65
- defineProperty('on', function(events, fn) {
66
- if (typeof fn != 'function') return el
67
-
68
- onEachEvent(events, function(name, pos) {
69
- (callbacks[name] = callbacks[name] || []).push(fn)
70
- fn.typed = pos > 0
71
- })
72
-
73
- return el
74
- })
75
61
 
76
62
  /**
77
- * Removes the given space separated list of `events` listeners
78
- * @param { String } events - events ids
79
- * @param { Function } fn - callback function
80
- * @returns { Object } el
63
+ * Helper function needed to get and loop all the events in a string
64
+ * @param { String } e - event string
65
+ * @param {Function} fn - callback
81
66
  */
82
- defineProperty('off', function(events, fn) {
83
- if (events == '*' && !fn) callbacks = {}
84
- else {
85
- onEachEvent(events, function(name) {
86
- if (fn) {
87
- var arr = callbacks[name]
88
- for (var i = 0, cb; cb = arr && arr[i]; ++i) {
89
- if (cb == fn) arr.splice(i--, 1)
90
- }
91
- } else delete callbacks[name]
92
- })
67
+ function onEachEvent(e, fn) {
68
+ var es = e.split(' '), l = es.length, i = 0, name, indx
69
+ for (; i < l; i++) {
70
+ name = es[i]
71
+ indx = name.indexOf('.')
72
+ if (name) fn( ~indx ? name.substring(0, indx) : name, i, ~indx ? name.slice(indx + 1) : null)
93
73
  }
94
- return el
95
- })
74
+ }
96
75
 
97
76
  /**
98
- * Listen to the given space separated list of `events` and execute the `callback` at most once
99
- * @param { String } events - events ids
100
- * @param { Function } fn - callback function
101
- * @returns { Object } el
77
+ * Public Api
102
78
  */
103
- defineProperty('one', function(events, fn) {
104
- function on() {
105
- el.off(events, on)
106
- fn.apply(el, arguments)
107
- }
108
- return el.on(events, on)
109
- })
110
79
 
111
- /**
112
- * Execute all callback functions that listen to the given space separated list of `events`
113
- * @param { String } events - events ids
114
- * @returns { Object } el
115
- */
116
- defineProperty('trigger', function(events) {
80
+ // extend the el object adding the observable methods
81
+ Object.defineProperties(el, {
82
+ /**
83
+ * Listen to the given space separated list of `events` and
84
+ * execute the `callback` each time an event is triggered.
85
+ * @param { String } events - events ids
86
+ * @param { Function } fn - callback function
87
+ * @returns { Object } el
88
+ */
89
+ on: {
90
+ value: function(events, fn) {
91
+ if (typeof fn != 'function') return el
92
+
93
+ onEachEvent(events, function(name, pos, ns) {
94
+ (callbacks[name] = callbacks[name] || []).push(fn)
95
+ fn.typed = pos > 0
96
+ fn.ns = ns
97
+ })
98
+
99
+ return el
100
+ },
101
+ enumerable: false,
102
+ writable: false,
103
+ configurable: false
104
+ },
117
105
 
118
- // getting the arguments
119
- // skipping the first one
120
- var args = slice.call(arguments, 1),
121
- fns
106
+ /**
107
+ * Removes the given space separated list of `events` listeners
108
+ * @param { String } events - events ids
109
+ * @param { Function } fn - callback function
110
+ * @returns { Object } el
111
+ */
112
+ off: {
113
+ value: function(events, fn) {
114
+ if (events == '*' && !fn) callbacks = {}
115
+ else {
116
+ onEachEvent(events, function(name, pos, ns) {
117
+ if (fn || ns) {
118
+ var arr = callbacks[name]
119
+ for (var i = 0, cb; cb = arr && arr[i]; ++i) {
120
+ if (cb == fn || ns && cb.ns == ns) arr.splice(i--, 1)
121
+ }
122
+ } else delete callbacks[name]
123
+ })
124
+ }
125
+ return el
126
+ },
127
+ enumerable: false,
128
+ writable: false,
129
+ configurable: false
130
+ },
131
+
132
+ /**
133
+ * Listen to the given space separated list of `events` and
134
+ * execute the `callback` at most once
135
+ * @param { String } events - events ids
136
+ * @param { Function } fn - callback function
137
+ * @returns { Object } el
138
+ */
139
+ one: {
140
+ value: function(events, fn) {
141
+ function on() {
142
+ el.off(events, on)
143
+ fn.apply(el, arguments)
144
+ }
145
+ return el.on(events, on)
146
+ },
147
+ enumerable: false,
148
+ writable: false,
149
+ configurable: false
150
+ },
122
151
 
123
- onEachEvent(events, function(name) {
152
+ /**
153
+ * Execute all callback functions that listen to
154
+ * the given space separated list of `events`
155
+ * @param { String } events - events ids
156
+ * @returns { Object } el
157
+ */
158
+ trigger: {
159
+ value: function(events) {
124
160
 
125
- fns = slice.call(callbacks[name] || [], 0)
161
+ // getting the arguments
162
+ var arglen = arguments.length - 1,
163
+ args = new Array(arglen),
164
+ fns
126
165
 
127
- for (var i = 0, fn; fn = fns[i]; ++i) {
128
- if (fn.busy) return
129
- fn.busy = 1
130
- fn.apply(el, fn.typed ? [name].concat(args) : args)
131
- if (fns[i] !== fn) { i-- }
132
- fn.busy = 0
133
- }
166
+ for (var i = 0; i < arglen; i++) {
167
+ args[i] = arguments[i + 1] // skip first argument
168
+ }
134
169
 
135
- if (callbacks['*'] && name != '*')
136
- el.trigger.apply(el, ['*', name].concat(args))
170
+ onEachEvent(events, function(name, pos, ns) {
137
171
 
138
- })
172
+ fns = slice.call(callbacks[name] || [], 0)
139
173
 
140
- return el
174
+ for (var i = 0, fn; fn = fns[i]; ++i) {
175
+ if (fn.busy) continue
176
+ fn.busy = 1
177
+ if (!ns || fn.ns == ns) fn.apply(el, fn.typed ? [name].concat(args) : args)
178
+ if (fns[i] !== fn) { i-- }
179
+ fn.busy = 0
180
+ }
181
+
182
+ if (callbacks['*'] && name != '*')
183
+ el.trigger.apply(el, ['*', name].concat(args))
184
+
185
+ })
186
+
187
+ return el
188
+ },
189
+ enumerable: false,
190
+ writable: false,
191
+ configurable: false
192
+ }
141
193
  })
142
194
 
143
195
  return el
@@ -152,7 +204,7 @@ riot.observable = function(el) {
152
204
  */
153
205
 
154
206
 
155
- var RE_ORIGIN = /^.+?\/+[^\/]+/,
207
+ var RE_ORIGIN = /^.+?\/\/+[^\/]+/,
156
208
  EVENT_LISTENER = 'EventListener',
157
209
  REMOVE_EVENT_LISTENER = 'remove' + EVENT_LISTENER,
158
210
  ADD_EVENT_LISTENER = 'add' + EVENT_LISTENER,
@@ -246,7 +298,7 @@ function isString(str) {
246
298
  * @returns {string} path from root
247
299
  */
248
300
  function getPathFromRoot(href) {
249
- return (href || loc.href || '')[REPLACE](RE_ORIGIN, '')
301
+ return (href || loc.href)[REPLACE](RE_ORIGIN, '')
250
302
  }
251
303
 
252
304
  /**
@@ -257,7 +309,7 @@ function getPathFromRoot(href) {
257
309
  function getPathFromBase(href) {
258
310
  return base[0] == '#'
259
311
  ? (href || loc.href || '').split(base)[1] || ''
260
- : getPathFromRoot(href)[REPLACE](base, '')
312
+ : (loc ? getPathFromRoot(href) : href || '')[REPLACE](base, '')
261
313
  }
262
314
 
263
315
  function emit(force) {
@@ -291,6 +343,7 @@ function click(e) {
291
343
 
292
344
  var el = e.target
293
345
  while (el && el.nodeName != 'A') el = el.parentNode
346
+
294
347
  if (
295
348
  !el || el.nodeName != 'A' // not A tag
296
349
  || el[HAS_ATTRIBUTE]('download') // has download attr
@@ -397,10 +450,11 @@ var route = mainRouter.m.bind(mainRouter)
397
450
  */
398
451
  route.create = function() {
399
452
  var newSubRouter = new Router()
453
+ // assign sub-router's main method
454
+ var router = newSubRouter.m.bind(newSubRouter)
400
455
  // stop only this sub-router
401
- newSubRouter.m.stop = newSubRouter.s.bind(newSubRouter)
402
- // return sub-router's main method
403
- return newSubRouter.m.bind(newSubRouter)
456
+ router.stop = newSubRouter.s.bind(newSubRouter)
457
+ return router
404
458
  }
405
459
 
406
460
  /**
@@ -484,9 +538,8 @@ riot.route = route
484
538
 
485
539
  /**
486
540
  * The riot template engine
487
- * @version v2.3.21
541
+ * @version v2.4.0
488
542
  */
489
-
490
543
  /**
491
544
  * riot.util.brackets
492
545
  *
@@ -549,7 +602,7 @@ var brackets = (function (UNDEF) {
549
602
 
550
603
  var arr = pair.split(' ')
551
604
 
552
- if (arr.length !== 2 || /[\x00-\x1F<>a-zA-Z0-9'",;\\]/.test(pair)) {
605
+ if (arr.length !== 2 || /[\x00-\x1F<>a-zA-Z0-9'",;\\]/.test(pair)) { // eslint-disable-line
553
606
  throw new Error('Unsupported brackets "' + pair + '"')
554
607
  }
555
608
  arr = arr.concat(pair.replace(/(?=[[\]()*+?.^$|])/g, '\\').split(' '))
@@ -580,7 +633,7 @@ var brackets = (function (UNDEF) {
580
633
 
581
634
  isexpr = start = re.lastIndex = 0
582
635
 
583
- while (match = re.exec(str)) {
636
+ while ((match = re.exec(str))) {
584
637
 
585
638
  pos = match.index
586
639
 
@@ -590,8 +643,9 @@ var brackets = (function (UNDEF) {
590
643
  re.lastIndex = skipBraces(str, match[2], re.lastIndex)
591
644
  continue
592
645
  }
593
- if (!match[3])
646
+ if (!match[3]) {
594
647
  continue
648
+ }
595
649
  }
596
650
 
597
651
  if (!match[1]) {
@@ -609,10 +663,11 @@ var brackets = (function (UNDEF) {
609
663
  return parts
610
664
 
611
665
  function unescapeStr (s) {
612
- if (tmpl || isexpr)
666
+ if (tmpl || isexpr) {
613
667
  parts.push(s && s.replace(_bp[5], '$1'))
614
- else
668
+ } else {
615
669
  parts.push(s)
670
+ }
616
671
  }
617
672
 
618
673
  function skipBraces (s, ch, ix) {
@@ -622,7 +677,7 @@ var brackets = (function (UNDEF) {
622
677
 
623
678
  recch.lastIndex = ix
624
679
  ix = 1
625
- while (match = recch.exec(s)) {
680
+ while ((match = recch.exec(s))) {
626
681
  if (match[1] &&
627
682
  !(match[1] === ch ? ++ix : --ix)) break
628
683
  }
@@ -636,15 +691,12 @@ var brackets = (function (UNDEF) {
636
691
 
637
692
  _brackets.loopKeys = function loopKeys (expr) {
638
693
  var m = expr.match(_cache[9])
694
+
639
695
  return m
640
696
  ? { key: m[1], pos: m[2], val: _cache[0] + m[3].trim() + _cache[1] }
641
697
  : { val: expr.trim() }
642
698
  }
643
699
 
644
- _brackets.hasRaw = function (src) {
645
- return _cache[10].test(src)
646
- }
647
-
648
700
  _brackets.array = function array (pair) {
649
701
  return pair ? _create(pair) : _cache
650
702
  }
@@ -654,13 +706,13 @@ var brackets = (function (UNDEF) {
654
706
  _cache = _create(pair)
655
707
  _regex = pair === DEFAULT ? _loopback : _rewrite
656
708
  _cache[9] = _regex(_pairs[9])
657
- _cache[10] = _regex(_pairs[10])
658
709
  }
659
710
  cachedBrackets = pair
660
711
  }
661
712
 
662
713
  function _setSettings (o) {
663
714
  var b
715
+
664
716
  o = o || {}
665
717
  b = o.brackets
666
718
  Object.defineProperty(o, 'brackets', {
@@ -728,22 +780,28 @@ var tmpl = (function () {
728
780
  }
729
781
 
730
782
  function _create (str) {
731
-
732
783
  var expr = _getTmpl(str)
784
+
733
785
  if (expr.slice(0, 11) !== 'try{return ') expr = 'return ' + expr
734
786
 
787
+ /* eslint-disable */
788
+
735
789
  return new Function('E', expr + ';')
790
+ /* eslint-enable */
736
791
  }
737
792
 
738
793
  var
794
+ CH_IDEXPR = '\u2057',
795
+ RE_CSNAME = /^(?:(-?[_A-Za-z\xA0-\xFF][-\w\xA0-\xFF]*)|\u2057(\d+)~):/,
739
796
  RE_QBLOCK = RegExp(brackets.S_QBLOCKS, 'g'),
740
- RE_QBMARK = /\x01(\d+)~/g
797
+ RE_DQUOTE = /\u2057/g,
798
+ RE_QBMARK = /\u2057(\d+)~/g
741
799
 
742
800
  function _getTmpl (str) {
743
801
  var
744
802
  qstr = [],
745
803
  expr,
746
- parts = brackets.split(str.replace(/\u2057/g, '"'), 1)
804
+ parts = brackets.split(str.replace(RE_DQUOTE, '"'), 1)
747
805
 
748
806
  if (parts.length > 2 || parts[0]) {
749
807
  var i, j, list = []
@@ -752,11 +810,11 @@ var tmpl = (function () {
752
810
 
753
811
  expr = parts[i]
754
812
 
755
- if (expr && (expr = i & 1 ?
813
+ if (expr && (expr = i & 1
756
814
 
757
- _parseExpr(expr, 1, qstr) :
815
+ ? _parseExpr(expr, 1, qstr)
758
816
 
759
- '"' + expr
817
+ : '"' + expr
760
818
  .replace(/\\/g, '\\\\')
761
819
  .replace(/\r\n?|\n/g, '\\n')
762
820
  .replace(/"/g, '\\"') +
@@ -766,21 +824,21 @@ var tmpl = (function () {
766
824
 
767
825
  }
768
826
 
769
- expr = j < 2 ? list[0] :
770
- '[' + list.join(',') + '].join("")'
827
+ expr = j < 2 ? list[0]
828
+ : '[' + list.join(',') + '].join("")'
771
829
 
772
830
  } else {
773
831
 
774
832
  expr = _parseExpr(parts[1], 0, qstr)
775
833
  }
776
834
 
777
- if (qstr[0])
835
+ if (qstr[0]) {
778
836
  expr = expr.replace(RE_QBMARK, function (_, pos) {
779
837
  return qstr[pos]
780
838
  .replace(/\r/g, '\\r')
781
839
  .replace(/\n/g, '\\n')
782
840
  })
783
-
841
+ }
784
842
  return expr
785
843
  }
786
844
 
@@ -789,16 +847,13 @@ var tmpl = (function () {
789
847
  '(': /[()]/g,
790
848
  '[': /[[\]]/g,
791
849
  '{': /[{}]/g
792
- },
793
- CS_IDENT = /^(?:(-?[_A-Za-z\xA0-\xFF][-\w\xA0-\xFF]*)|\x01(\d+)~):/
850
+ }
794
851
 
795
852
  function _parseExpr (expr, asText, qstr) {
796
853
 
797
- if (expr[0] === '=') expr = expr.slice(1)
798
-
799
854
  expr = expr
800
855
  .replace(RE_QBLOCK, function (s, div) {
801
- return s.length > 2 && !div ? '\x01' + (qstr.push(s) - 1) + '~' : s
856
+ return s.length > 2 && !div ? CH_IDEXPR + (qstr.push(s) - 1) + '~' : s
802
857
  })
803
858
  .replace(/\s+/g, ' ').trim()
804
859
  .replace(/\ ?([[\({},?\.:])\ ?/g, '$1')
@@ -810,7 +865,7 @@ var tmpl = (function () {
810
865
  match
811
866
 
812
867
  while (expr &&
813
- (match = expr.match(CS_IDENT)) &&
868
+ (match = expr.match(RE_CSNAME)) &&
814
869
  !match.index
815
870
  ) {
816
871
  var
@@ -829,8 +884,8 @@ var tmpl = (function () {
829
884
  list[cnt++] = _wrapExpr(jsb, 1, key)
830
885
  }
831
886
 
832
- expr = !cnt ? _wrapExpr(expr, asText) :
833
- cnt > 1 ? '[' + list.join(',') + '].join(" ").trim()' : list[0]
887
+ expr = !cnt ? _wrapExpr(expr, asText)
888
+ : cnt > 1 ? '[' + list.join(',') + '].join(" ").trim()' : list[0]
834
889
  }
835
890
  return expr
836
891
 
@@ -850,7 +905,7 @@ var tmpl = (function () {
850
905
  }
851
906
 
852
907
  // istanbul ignore next: not both
853
- var
908
+ var // eslint-disable-next-line max-len
854
909
  JS_CONTEXT = '"in this?this:' + (typeof window !== 'object' ? 'global' : 'window') + ').',
855
910
  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,
856
911
  JS_NOPROPS = /^(?=(\.[$\w]+))\1(?:[^.[(]|$)/
@@ -878,14 +933,14 @@ var tmpl = (function () {
878
933
 
879
934
  if (key) {
880
935
 
881
- expr = (tb ?
882
- 'function(){' + expr + '}.call(this)' : '(' + expr + ')'
936
+ expr = (tb
937
+ ? 'function(){' + expr + '}.call(this)' : '(' + expr + ')'
883
938
  ) + '?"' + key + '":""'
884
939
 
885
940
  } else if (asText) {
886
941
 
887
- expr = 'function(v){' + (tb ?
888
- expr.replace('return ', 'v=') : 'v=(' + expr + ')'
942
+ expr = 'function(v){' + (tb
943
+ ? expr.replace('return ', 'v=') : 'v=(' + expr + ')'
889
944
  ) + ';return v||v===0?v:""}.call(this)'
890
945
  }
891
946
 
@@ -895,7 +950,7 @@ var tmpl = (function () {
895
950
  // istanbul ignore next: compatibility fix for beta versions
896
951
  _tmpl.parse = function (s) { return s }
897
952
 
898
- _tmpl.version = brackets.version = 'v2.3.21'
953
+ _tmpl.version = brackets.version = 'v2.4.0'
899
954
 
900
955
  return _tmpl
901
956
 
@@ -908,41 +963,50 @@ var tmpl = (function () {
908
963
  See: http://kangax.github.io/compat-table/es5/#ie8
909
964
  http://codeplanet.io/dropping-ie8/
910
965
  */
911
- var mkdom = (function (checkIE) {
912
-
966
+ var mkdom = (function _mkdom() {
967
+ var
968
+ reHasYield = /<yield\b/i,
969
+ reYieldAll = /<yield\s*(?:\/>|>([\S\s]*?)<\/yield\s*>|>)/ig,
970
+ reYieldSrc = /<yield\s+to=['"]([^'">]*)['"]\s*>([\S\s]*?)<\/yield\s*>/ig,
971
+ reYieldDest = /<yield\s+from=['"]?([-\w]+)['"]?\s*(?:\/>|>([\S\s]*?)<\/yield\s*>)/ig
913
972
  var
914
- reToSrc = /<yield\s+to=(['"])?@\1\s*>([\S\s]+?)<\/yield\s*>/.source,
915
973
  rootEls = { tr: 'tbody', th: 'tr', td: 'tr', col: 'colgroup' },
916
- GENERIC = 'div'
917
-
918
- checkIE = checkIE && checkIE < 10
919
- var tblTags = checkIE
920
- ? SPECIAL_TAGS_REGEX : /^(?:t(?:body|head|foot|[rhd])|caption|col(?:group)?)$/
974
+ tblTags = IE_VERSION && IE_VERSION < 10
975
+ ? SPECIAL_TAGS_REGEX : /^(?:t(?:body|head|foot|[rhd])|caption|col(?:group)?)$/
921
976
 
922
- // creates any dom element in a div, table, or colgroup container
977
+ /**
978
+ * Creates a DOM element to wrap the given content. Normally an `DIV`, but can be
979
+ * also a `TABLE`, `SELECT`, `TBODY`, `TR`, or `COLGROUP` element.
980
+ *
981
+ * @param {string} templ - The template coming from the custom tag definition
982
+ * @param {string} [html] - HTML content that comes from the DOM element where you
983
+ * will mount the tag, mostly the original tag in the page
984
+ * @returns {HTMLElement} DOM element with _templ_ merged through `YIELD` with the _html_.
985
+ */
923
986
  function _mkdom(templ, html) {
924
-
925
- var match = templ && templ.match(/^\s*<([-\w]+)/),
987
+ var
988
+ match = templ && templ.match(/^\s*<([-\w]+)/),
926
989
  tagName = match && match[1].toLowerCase(),
927
- el = mkEl(GENERIC)
990
+ el = mkEl('div', isSVGTag(tagName))
928
991
 
929
992
  // replace all the yield tags with the tag inner html
930
- templ = replaceYield(templ, html || '')
993
+ templ = replaceYield(templ, html)
931
994
 
932
995
  /* istanbul ignore next */
933
- //if ((checkIE || !startsWith(tagName, 'opt')) && SPECIAL_TAGS_REGEX.test(tagName))
934
996
  if (tblTags.test(tagName))
935
997
  el = specialTags(el, templ, tagName)
936
998
  else
937
- el.innerHTML = templ
999
+ setInnerHTML(el, templ)
938
1000
 
939
1001
  el.stub = true
940
1002
 
941
1003
  return el
942
1004
  }
943
1005
 
944
- // creates the root element for table and select child elements
945
- // tr/th/td/thead/tfoot/tbody/caption/col/colgroup/option/optgroup
1006
+ /*
1007
+ Creates the root element for table or select child elements:
1008
+ tr/th/td/thead/tfoot/tbody/caption/col/colgroup/option/optgroup
1009
+ */
946
1010
  function specialTags(el, templ, tagName) {
947
1011
  var
948
1012
  select = tagName[0] === 'o',
@@ -958,39 +1022,41 @@ var mkdom = (function (checkIE) {
958
1022
  if (select) {
959
1023
  parent.selectedIndex = -1 // for IE9, compatible w/current riot behavior
960
1024
  } else {
1025
+ // avoids insertion of cointainer inside container (ex: tbody inside tbody)
961
1026
  var tname = rootEls[tagName]
962
- if (tname && parent.children.length === 1) parent = $(tname, parent)
1027
+ if (tname && parent.childElementCount === 1) parent = $(tname, parent)
963
1028
  }
964
1029
  return parent
965
1030
  }
966
1031
 
967
- /**
968
- * Replace the yield tag from any tag template with the innerHTML of the
969
- * original tag in the page
970
- * @param { String } templ - tag implementation template
971
- * @param { String } html - original content of the tag in the DOM
972
- * @returns { String } tag template updated without the yield tag
973
- */
1032
+ /*
1033
+ Replace the yield tag from any tag template with the innerHTML of the
1034
+ original tag in the page
1035
+ */
974
1036
  function replaceYield(templ, html) {
975
1037
  // do nothing if no yield
976
- if (!/<yield\b/i.test(templ)) return templ
1038
+ if (!reHasYield.test(templ)) return templ
977
1039
 
978
1040
  // be careful with #1343 - string on the source having `$1`
979
- var n = 0
980
- templ = templ.replace(/<yield\s+from=['"]([-\w]+)['"]\s*(?:\/>|>\s*<\/yield\s*>)/ig,
981
- function (str, ref) {
982
- var m = html.match(RegExp(reToSrc.replace('@', ref), 'i'))
983
- ++n
984
- return m && m[2] || ''
985
- })
1041
+ var src = {}
1042
+
1043
+ html = html && html.replace(reYieldSrc, function (_, ref, text) {
1044
+ src[ref] = src[ref] || text // preserve first definition
1045
+ return ''
1046
+ }).trim()
986
1047
 
987
- // yield without any "from", replace yield in templ with the innerHTML
988
- return n ? templ : templ.replace(/<yield\s*(?:\/>|>\s*<\/yield\s*>)/gi, html)
1048
+ return templ
1049
+ .replace(reYieldDest, function (_, ref, def) { // yield with from - to attrs
1050
+ return src[ref] || def || ''
1051
+ })
1052
+ .replace(reYieldAll, function (_, def) { // yield without any "from"
1053
+ return html || def || ''
1054
+ })
989
1055
  }
990
1056
 
991
1057
  return _mkdom
992
1058
 
993
- })(IE_VERSION)
1059
+ })()
994
1060
 
995
1061
  /**
996
1062
  * Convert the item looped into an object used to extend the child tag properties
@@ -1097,12 +1163,12 @@ function _each(dom, parent, expr) {
1097
1163
 
1098
1164
  var mustReorder = typeof getAttr(dom, 'no-reorder') !== T_STRING || remAttr(dom, 'no-reorder'),
1099
1165
  tagName = getTagName(dom),
1100
- impl = __tagImpl[tagName] || { tmpl: dom.outerHTML },
1166
+ impl = __tagImpl[tagName] || { tmpl: getOuterHTML(dom) },
1101
1167
  useRoot = SPECIAL_TAGS_REGEX.test(tagName),
1102
1168
  root = dom.parentNode,
1103
1169
  ref = document.createTextNode(''),
1104
1170
  child = getTag(dom),
1105
- isOption = /^option$/i.test(tagName), // the option tags must be treated differently
1171
+ isOption = tagName.toLowerCase() === 'option', // the option tags must be treated differently
1106
1172
  tags = [],
1107
1173
  oldItems = [],
1108
1174
  hasKeys,
@@ -1127,8 +1193,6 @@ function _each(dom, parent, expr) {
1127
1193
  // create a fragment to hold the new DOM nodes to inject in the parent tag
1128
1194
  frag = document.createDocumentFragment()
1129
1195
 
1130
-
1131
-
1132
1196
  // object loop. any changes cause full redraw
1133
1197
  if (!isArray(items)) {
1134
1198
  hasKeys = items || false
@@ -1139,9 +1203,14 @@ function _each(dom, parent, expr) {
1139
1203
  }
1140
1204
 
1141
1205
  // loop all the new items
1142
- items.forEach(function(item, i) {
1206
+ var i = 0,
1207
+ itemsLength = items.length
1208
+
1209
+ for (; i < itemsLength; i++) {
1143
1210
  // reorder only if the items are objects
1144
- var _mustReorder = mustReorder && item instanceof Object,
1211
+ var
1212
+ item = items[i],
1213
+ _mustReorder = mustReorder && typeof item == T_OBJECT && !hasKeys,
1145
1214
  oldPos = oldItems.indexOf(item),
1146
1215
  pos = ~oldPos && _mustReorder ? oldPos : i,
1147
1216
  // does a tag exist in this position?
@@ -1165,9 +1234,10 @@ function _each(dom, parent, expr) {
1165
1234
  }, dom.innerHTML)
1166
1235
 
1167
1236
  tag.mount()
1237
+
1168
1238
  if (isVirtual) tag._root = tag.root.firstChild // save reference for further moves or inserts
1169
1239
  // this tag must be appended
1170
- if (i == tags.length) {
1240
+ if (i == tags.length || !tags[i]) { // fix 1581
1171
1241
  if (isVirtual)
1172
1242
  addVirtual(tag, frag)
1173
1243
  else frag.appendChild(tag.root)
@@ -1176,16 +1246,19 @@ function _each(dom, parent, expr) {
1176
1246
  else {
1177
1247
  if (isVirtual)
1178
1248
  addVirtual(tag, root, tags[i])
1179
- else root.insertBefore(tag.root, tags[i].root)
1249
+ else root.insertBefore(tag.root, tags[i].root) // #1374 some browsers reset selected here
1180
1250
  oldItems.splice(i, 0, item)
1181
1251
  }
1182
1252
 
1183
1253
  tags.splice(i, 0, tag)
1184
1254
  pos = i // handled here so no move
1185
- } else tag.update(item)
1255
+ } else tag.update(item, true)
1186
1256
 
1187
1257
  // reorder the tag if it's not located in its previous position
1188
- if (pos !== i && _mustReorder) {
1258
+ if (
1259
+ pos !== i && _mustReorder &&
1260
+ tags[i] // fix 1581 unable to reproduce it in a test!
1261
+ ) {
1189
1262
  // update the DOM
1190
1263
  if (isVirtual)
1191
1264
  moveVirtual(tag, root, tags[i], dom.childNodes.length)
@@ -1207,14 +1280,26 @@ function _each(dom, parent, expr) {
1207
1280
  tag._item = item
1208
1281
  // cache the real parent tag internally
1209
1282
  defineProperty(tag, '_parent', parent)
1210
-
1211
- })
1283
+ }
1212
1284
 
1213
1285
  // remove the redundant tags
1214
1286
  unmountRedundant(items, tags)
1215
1287
 
1216
1288
  // insert the new nodes
1217
- if (isOption) root.appendChild(frag)
1289
+ if (isOption) {
1290
+ root.appendChild(frag)
1291
+
1292
+ // #1374 FireFox bug in <option selected={expression}>
1293
+ if (FIREFOX && !root.multiple) {
1294
+ for (var n = 0; n < root.length; n++) {
1295
+ if (root[n].__riot1374) {
1296
+ root.selectedIndex = n // clear other options
1297
+ delete root[n].__riot1374
1298
+ break
1299
+ }
1300
+ }
1301
+ }
1302
+ }
1218
1303
  else root.insertBefore(frag, ref)
1219
1304
 
1220
1305
  // set the 'tags' property of the parent tag
@@ -1367,13 +1452,13 @@ function Tag(impl, conf, innerHTML) {
1367
1452
  expressions = [],
1368
1453
  childTags = [],
1369
1454
  root = conf.root,
1370
- fn = impl.fn,
1371
1455
  tagName = root.tagName.toLowerCase(),
1372
1456
  attr = {},
1373
1457
  propsInSyncWithParent = [],
1374
1458
  dom
1375
1459
 
1376
- if (fn && root._tag) root._tag.unmount(true)
1460
+ // only call unmount if we have a valid __tagImpl (has name property)
1461
+ if (impl.name && root._tag) root._tag.unmount(true)
1377
1462
 
1378
1463
  // not yet mounted
1379
1464
  this.isMounted = false
@@ -1387,7 +1472,9 @@ function Tag(impl, conf, innerHTML) {
1387
1472
  // it could be handy to use it also to improve the virtual dom rendering speed
1388
1473
  defineProperty(this, '_riot_id', ++__uid) // base 1 allows test !t._riot_id
1389
1474
 
1390
- extend(this, { parent: parent, root: root, opts: opts, tags: {} }, item)
1475
+ extend(this, { parent: parent, root: root, opts: opts}, item)
1476
+ // protect the "tags" property from being overridden
1477
+ defineProperty(this, 'tags', {})
1391
1478
 
1392
1479
  // grab attributes
1393
1480
  each(root.attributes, function(el) {
@@ -1424,7 +1511,7 @@ function Tag(impl, conf, innerHTML) {
1424
1511
  if (!self.parent || !isLoop) return
1425
1512
  each(Object.keys(self.parent), function(k) {
1426
1513
  // some properties must be always in sync with the parent tag
1427
- var mustSync = !contains(RESERVED_WORDS_BLACKLIST, k) && contains(propsInSyncWithParent, k)
1514
+ var mustSync = !RESERVED_WORDS_BLACKLIST.test(k) && contains(propsInSyncWithParent, k)
1428
1515
  if (typeof self[k] === T_UNDEF || mustSync) {
1429
1516
  // track the property to keep in sync
1430
1517
  // so we can keep it updated
@@ -1434,7 +1521,13 @@ function Tag(impl, conf, innerHTML) {
1434
1521
  })
1435
1522
  }
1436
1523
 
1437
- defineProperty(this, 'update', function(data) {
1524
+ /**
1525
+ * Update the tag expressions and options
1526
+ * @param { * } data - data we want to use to extend the tag properties
1527
+ * @param { Boolean } isInherited - is this update coming from a parent tag?
1528
+ * @returns { self }
1529
+ */
1530
+ defineProperty(this, 'update', function(data, isInherited) {
1438
1531
 
1439
1532
  // make sure the data passed will not override
1440
1533
  // the component core methods
@@ -1442,7 +1535,7 @@ function Tag(impl, conf, innerHTML) {
1442
1535
  // inherit properties from the parent
1443
1536
  inheritFromParent()
1444
1537
  // normalize the tag properties in case an item object was initially passed
1445
- if (data && typeof item === T_OBJECT) {
1538
+ if (data && isObject(item)) {
1446
1539
  normalizeData(data)
1447
1540
  item = data
1448
1541
  }
@@ -1450,11 +1543,16 @@ function Tag(impl, conf, innerHTML) {
1450
1543
  updateOpts()
1451
1544
  self.trigger('update', data)
1452
1545
  update(expressions, self)
1546
+
1453
1547
  // the updated event will be triggered
1454
- // once the DOM will be ready and all the reflows are completed
1548
+ // once the DOM will be ready and all the re-flows are completed
1455
1549
  // this is useful if you want to get the "real" root properties
1456
1550
  // 4 ex: root.offsetWidth ...
1457
- rAF(function() { self.trigger('updated') })
1551
+ if (isInherited && self.parent)
1552
+ // closes #1599
1553
+ self.parent.one('updated', function() { self.trigger('updated') })
1554
+ else rAF(function() { self.trigger('updated') })
1555
+
1458
1556
  return this
1459
1557
  })
1460
1558
 
@@ -1491,8 +1589,15 @@ function Tag(impl, conf, innerHTML) {
1491
1589
 
1492
1590
  updateOpts()
1493
1591
 
1592
+ // add global mixins
1593
+ var globalMixin = riot.mixin(GLOBAL_MIXIN)
1594
+ if (globalMixin)
1595
+ for (var i in globalMixin)
1596
+ if (globalMixin.hasOwnProperty(i))
1597
+ self.mixin(globalMixin[i])
1598
+
1494
1599
  // initialiation
1495
- if (fn) fn.call(self, opts)
1600
+ if (impl.fn) impl.fn.call(self, opts)
1496
1601
 
1497
1602
  // parse layout after init. fn may calculate args for nested custom tags
1498
1603
  parseExpressions(dom, self, expressions)
@@ -1502,10 +1607,10 @@ function Tag(impl, conf, innerHTML) {
1502
1607
 
1503
1608
  // update the root adding custom attributes coming from the compiler
1504
1609
  // it fixes also #1087
1505
- if (impl.attrs || hasImpl) {
1610
+ if (impl.attrs)
1506
1611
  walkAttributes(impl.attrs, function (k, v) { setAttr(root, k, v) })
1612
+ if (impl.attrs || hasImpl)
1507
1613
  parseExpressions(self.root, self, expressions)
1508
- }
1509
1614
 
1510
1615
  if (!self.parent || isLoop) self.update(item)
1511
1616
 
@@ -1514,13 +1619,14 @@ function Tag(impl, conf, innerHTML) {
1514
1619
 
1515
1620
  if (isLoop && !hasImpl) {
1516
1621
  // update the root attribute for the looped elements
1517
- self.root = root = dom.firstChild
1518
-
1622
+ root = dom.firstChild
1519
1623
  } else {
1520
1624
  while (dom.firstChild) root.appendChild(dom.firstChild)
1521
- if (root.stub) self.root = root = parent.root
1625
+ if (root.stub) root = parent.root
1522
1626
  }
1523
1627
 
1628
+ defineProperty(self, 'root', root)
1629
+
1524
1630
  // parse the named dom nodes in the looped child
1525
1631
  // adding them to the parent as well
1526
1632
  if (isLoop)
@@ -1555,12 +1661,6 @@ function Tag(impl, conf, innerHTML) {
1555
1661
  if (~tagIndex)
1556
1662
  __virtualDom.splice(tagIndex, 1)
1557
1663
 
1558
- if (this._virts) {
1559
- each(this._virts, function(v) {
1560
- if (v.parentNode) v.parentNode.removeChild(v)
1561
- })
1562
- }
1563
-
1564
1664
  if (p) {
1565
1665
 
1566
1666
  if (parent) {
@@ -1583,11 +1683,19 @@ function Tag(impl, conf, innerHTML) {
1583
1683
 
1584
1684
  if (!keepRootTag)
1585
1685
  p.removeChild(el)
1586
- else
1587
- // the riot-tag attribute isn't needed anymore, remove it
1588
- remAttr(p, 'riot-tag')
1686
+ else {
1687
+ // the riot-tag and the data-is attributes aren't needed anymore, remove them
1688
+ remAttr(p, RIOT_TAG_IS)
1689
+ remAttr(p, RIOT_TAG) // this will be removed in riot 3.0.0
1690
+ }
1691
+
1589
1692
  }
1590
1693
 
1694
+ if (this._virts) {
1695
+ each(this._virts, function(v) {
1696
+ if (v.parentNode) v.parentNode.removeChild(v)
1697
+ })
1698
+ }
1591
1699
 
1592
1700
  self.trigger('unmount')
1593
1701
  toggle()
@@ -1597,6 +1705,10 @@ function Tag(impl, conf, innerHTML) {
1597
1705
 
1598
1706
  })
1599
1707
 
1708
+ // proxy function to bind updates
1709
+ // dispatched from a parent tag
1710
+ function onChildUpdate(data) { self.update(data, true) }
1711
+
1600
1712
  function toggle(isMount) {
1601
1713
 
1602
1714
  // mount/unmount children
@@ -1609,10 +1721,12 @@ function Tag(impl, conf, innerHTML) {
1609
1721
  // the loop tags will be always in sync with the parent automatically
1610
1722
  if (isLoop)
1611
1723
  parent[evt]('unmount', self.unmount)
1612
- else
1613
- parent[evt]('update', self.update)[evt]('unmount', self.unmount)
1724
+ else {
1725
+ parent[evt]('update', onChildUpdate)[evt]('unmount', self.unmount)
1726
+ }
1614
1727
  }
1615
1728
 
1729
+
1616
1730
  // named elements available for fn
1617
1731
  parseNamedElements(dom, this, childTags)
1618
1732
 
@@ -1690,31 +1804,44 @@ function update(expressions, tag) {
1690
1804
  value = tmpl(expr.expr, tag),
1691
1805
  parent = expr.dom.parentNode
1692
1806
 
1693
- if (expr.bool)
1694
- value = value ? attrName : false
1695
- else if (value == null)
1807
+ if (expr.bool) {
1808
+ value = !!value
1809
+ } else if (value == null) {
1696
1810
  value = ''
1697
-
1698
- // leave out riot- prefixes from strings inside textarea
1699
- // fix #815: any value -> string
1700
- if (parent && parent.tagName == 'TEXTAREA') {
1701
- value = ('' + value).replace(/riot-/g, '')
1702
- // change textarea's value
1703
- parent.value = value
1704
1811
  }
1705
1812
 
1706
- // no change
1707
- if (expr.value === value) return
1813
+ // #1638: regression of #1612, update the dom only if the value of the
1814
+ // expression was changed
1815
+ if (expr.value === value) {
1816
+ return
1817
+ }
1708
1818
  expr.value = value
1709
1819
 
1710
- // text node
1820
+ // textarea and text nodes has no attribute name
1711
1821
  if (!attrName) {
1712
- dom.nodeValue = '' + value // #815 related
1822
+ // about #815 w/o replace: the browser converts the value to a string,
1823
+ // the comparison by "==" does too, but not in the server
1824
+ value += ''
1825
+ // test for parent avoids error with invalid assignment to nodeValue
1826
+ if (parent) {
1827
+ if (parent.tagName === 'TEXTAREA') {
1828
+ parent.value = value // #1113
1829
+ if (!IE_VERSION) dom.nodeValue = value // #1625 IE throws here, nodeValue
1830
+ } // will be available on 'updated'
1831
+ else dom.nodeValue = value
1832
+ }
1833
+ return
1834
+ }
1835
+
1836
+ // ~~#1612: look for changes in dom.value when updating the value~~
1837
+ if (attrName === 'value') {
1838
+ dom.value = value
1713
1839
  return
1714
1840
  }
1715
1841
 
1716
1842
  // remove original attribute
1717
1843
  remAttr(dom, attrName)
1844
+
1718
1845
  // event handler
1719
1846
  if (isFunction(value)) {
1720
1847
  setEventHandler(attrName, value, dom, tag)
@@ -1751,28 +1878,25 @@ function update(expressions, tag) {
1751
1878
  dom.inStub = true
1752
1879
  }
1753
1880
  // show / hide
1754
- } else if (/^(show|hide)$/.test(attrName)) {
1755
- if (attrName == 'hide') value = !value
1881
+ } else if (attrName === 'show') {
1756
1882
  dom.style.display = value ? '' : 'none'
1757
1883
 
1758
- // field value
1759
- } else if (attrName == 'value') {
1760
- dom.value = value
1761
-
1762
- // <img src="{ expr }">
1763
- } else if (startsWith(attrName, RIOT_PREFIX) && attrName != RIOT_TAG) {
1764
- if (value)
1765
- setAttr(dom, attrName.slice(RIOT_PREFIX.length), value)
1884
+ } else if (attrName === 'hide') {
1885
+ dom.style.display = value ? 'none' : ''
1766
1886
 
1767
- } else {
1768
- if (expr.bool) {
1769
- dom[attrName] = value
1770
- if (!value) return
1887
+ } else if (expr.bool) {
1888
+ dom[attrName] = value
1889
+ if (value) setAttr(dom, attrName, attrName)
1890
+ if (FIREFOX && attrName === 'selected' && dom.tagName === 'OPTION') {
1891
+ dom.__riot1374 = value // #1374
1771
1892
  }
1772
1893
 
1773
- if (value === 0 || value && typeof value !== T_OBJECT)
1774
- setAttr(dom, attrName, value)
1775
-
1894
+ } else if (value === 0 || value && typeof value !== T_OBJECT) {
1895
+ // <img src="{ expr }">
1896
+ if (startsWith(attrName, RIOT_PREFIX) && attrName != RIOT_TAG) {
1897
+ attrName = attrName.slice(RIOT_PREFIX.length)
1898
+ }
1899
+ setAttr(dom, attrName, value)
1776
1900
  }
1777
1901
 
1778
1902
  })
@@ -1804,6 +1928,56 @@ function isFunction(v) {
1804
1928
  return typeof v === T_FUNCTION || false // avoid IE problems
1805
1929
  }
1806
1930
 
1931
+ /**
1932
+ * Get the outer html of any DOM node SVGs included
1933
+ * @param { Object } el - DOM node to parse
1934
+ * @returns { String } el.outerHTML
1935
+ */
1936
+ function getOuterHTML(el) {
1937
+ if (el.outerHTML) return el.outerHTML
1938
+ // some browsers do not support outerHTML on the SVGs tags
1939
+ else {
1940
+ var container = mkEl('div')
1941
+ container.appendChild(el.cloneNode(true))
1942
+ return container.innerHTML
1943
+ }
1944
+ }
1945
+
1946
+ /**
1947
+ * Set the inner html of any DOM node SVGs included
1948
+ * @param { Object } container - DOM node where we will inject the new html
1949
+ * @param { String } html - html to inject
1950
+ */
1951
+ function setInnerHTML(container, html) {
1952
+ if (typeof container.innerHTML != T_UNDEF) container.innerHTML = html
1953
+ // some browsers do not support innerHTML on the SVGs tags
1954
+ else {
1955
+ var doc = new DOMParser().parseFromString(html, 'application/xml')
1956
+ container.appendChild(
1957
+ container.ownerDocument.importNode(doc.documentElement, true)
1958
+ )
1959
+ }
1960
+ }
1961
+
1962
+ /**
1963
+ * Checks wether a DOM node must be considered part of an svg document
1964
+ * @param { String } name - tag name
1965
+ * @returns { Boolean } -
1966
+ */
1967
+ function isSVGTag(name) {
1968
+ return ~SVG_TAGS_LIST.indexOf(name)
1969
+ }
1970
+
1971
+ /**
1972
+ * Detect if the argument passed is an object, exclude null.
1973
+ * NOTE: Use isObject(x) && !isArray(x) to excludes arrays.
1974
+ * @param { * } v - whatever you want to pass to this function
1975
+ * @returns { Boolean } -
1976
+ */
1977
+ function isObject(v) {
1978
+ return v && typeof v === T_OBJECT // typeof null is 'object'
1979
+ }
1980
+
1807
1981
  /**
1808
1982
  * Remove any DOM attribute from a node
1809
1983
  * @param { Object } dom - DOM node we want to update
@@ -1850,7 +2024,8 @@ function setAttr(dom, name, val) {
1850
2024
  * @returns { Object } it returns an object containing the implementation of a custom tag (template and boot function)
1851
2025
  */
1852
2026
  function getTag(dom) {
1853
- return dom.tagName && __tagImpl[getAttr(dom, RIOT_TAG) || dom.tagName.toLowerCase()]
2027
+ return dom.tagName && __tagImpl[getAttr(dom, RIOT_TAG_IS) ||
2028
+ getAttr(dom, RIOT_TAG) || dom.tagName.toLowerCase()]
1854
2029
  }
1855
2030
  /**
1856
2031
  * Add a child tag to its parent into the `tags` object
@@ -1954,7 +2129,7 @@ function defineProperty(el, key, value, options) {
1954
2129
  value: value,
1955
2130
  enumerable: false,
1956
2131
  writable: false,
1957
- configurable: false
2132
+ configurable: true
1958
2133
  }, options))
1959
2134
  return el
1960
2135
  }
@@ -2038,8 +2213,7 @@ function cleanUpData(data) {
2038
2213
 
2039
2214
  var o = {}
2040
2215
  for (var key in data) {
2041
- if (!contains(RESERVED_WORDS_BLACKLIST, key))
2042
- o[key] = data[key]
2216
+ if (!RESERVED_WORDS_BLACKLIST.test(key)) o[key] = data[key]
2043
2217
  }
2044
2218
  return o
2045
2219
  }
@@ -2094,10 +2268,13 @@ function isInStub(dom) {
2094
2268
  /**
2095
2269
  * Create a generic DOM node
2096
2270
  * @param { String } name - name of the DOM node we want to create
2271
+ * @param { Boolean } isSvg - should we use a SVG as parent node?
2097
2272
  * @returns { Object } DOM node just created
2098
2273
  */
2099
- function mkEl(name) {
2100
- return document.createElement(name)
2274
+ function mkEl(name, isSvg) {
2275
+ return isSvg ?
2276
+ document.createElementNS('http://www.w3.org/2000/svg', 'svg') :
2277
+ document.createElement(name)
2101
2278
  }
2102
2279
 
2103
2280
  /**
@@ -2251,17 +2428,41 @@ riot.util = { brackets: brackets, tmpl: tmpl }
2251
2428
  * Create a mixin that could be globally shared across all the tags
2252
2429
  */
2253
2430
  riot.mixin = (function() {
2254
- var mixins = {}
2431
+ var mixins = {},
2432
+ globals = mixins[GLOBAL_MIXIN] = {},
2433
+ _id = 0
2255
2434
 
2256
2435
  /**
2257
2436
  * Create/Return a mixin by its name
2258
- * @param { String } name - mixin name
2259
- * @param { Object } mixin - mixin logic
2260
- * @returns { Object } the mixin logic
2437
+ * @param { String } name - mixin name (global mixin if object)
2438
+ * @param { Object } mixin - mixin logic
2439
+ * @param { Boolean } g - is global?
2440
+ * @returns { Object } the mixin logic
2261
2441
  */
2262
- return function(name, mixin) {
2263
- if (!mixin) return mixins[name]
2264
- mixins[name] = mixin
2442
+ return function(name, mixin, g) {
2443
+ // Unnamed global
2444
+ if (isObject(name)) {
2445
+ riot.mixin('__unnamed_'+_id++, name, true)
2446
+ return
2447
+ }
2448
+
2449
+ var store = g ? globals : mixins
2450
+
2451
+ // Getter
2452
+ if (!mixin) {
2453
+ if (typeof store[name] === T_UNDEF) {
2454
+ throw new Error('Unregistered mixin: ' + name)
2455
+ }
2456
+ return store[name]
2457
+ }
2458
+ // Setter
2459
+ if (isFunction(mixin)) {
2460
+ extend(mixin.prototype, store[name] || {})
2461
+ store[name] = mixin
2462
+ }
2463
+ else {
2464
+ store[name] = extend(store[name] || {}, mixin)
2465
+ }
2265
2466
  }
2266
2467
 
2267
2468
  })()
@@ -2287,6 +2488,7 @@ riot.tag = function(name, html, css, attrs, fn) {
2287
2488
  if (isFunction(css)) fn = css
2288
2489
  else styleManager.add(css)
2289
2490
  }
2491
+ name = name.toLowerCase()
2290
2492
  __tagImpl[name] = { name: name, tmpl: html, attrs: attrs, fn: fn }
2291
2493
  return name
2292
2494
  }
@@ -2298,10 +2500,9 @@ riot.tag = function(name, html, css, attrs, fn) {
2298
2500
  * @param { String } css - custom tag css
2299
2501
  * @param { String } attrs - root tag attributes
2300
2502
  * @param { Function } fn - user function
2301
- * @param { string } [bpair] - brackets used in the compilation
2302
2503
  * @returns { String } name/id of the tag just created
2303
2504
  */
2304
- riot.tag2 = function(name, html, css, attrs, fn, bpair) {
2505
+ riot.tag2 = function(name, html, css, attrs, fn) {
2305
2506
  if (css) styleManager.add(css)
2306
2507
  //if (bpair) riot.settings.brackets = bpair
2307
2508
  __tagImpl[name] = { name: name, tmpl: html, attrs: attrs, fn: fn }
@@ -2326,8 +2527,10 @@ riot.mount = function(selector, tagName, opts) {
2326
2527
  function addRiotTags(arr) {
2327
2528
  var list = ''
2328
2529
  each(arr, function (e) {
2329
- if (!/[^-\w]/.test(e))
2330
- list += ',*[' + RIOT_TAG + '=' + e.trim() + ']'
2530
+ if (!/[^-\w]/.test(e)) {
2531
+ e = e.trim().toLowerCase()
2532
+ list += ',[' + RIOT_TAG_IS + '="' + e + '"],[' + RIOT_TAG + '="' + e + '"]'
2533
+ }
2331
2534
  })
2332
2535
  return list
2333
2536
  }
@@ -2338,18 +2541,21 @@ riot.mount = function(selector, tagName, opts) {
2338
2541
  }
2339
2542
 
2340
2543
  function pushTags(root) {
2341
- var last
2342
-
2343
2544
  if (root.tagName) {
2344
- if (tagName && (!(last = getAttr(root, RIOT_TAG)) || last != tagName))
2345
- setAttr(root, RIOT_TAG, tagName)
2545
+ var riotTag = getAttr(root, RIOT_TAG_IS) || getAttr(root, RIOT_TAG)
2346
2546
 
2347
- var tag = mountTo(root, tagName || root.getAttribute(RIOT_TAG) || root.tagName.toLowerCase(), opts)
2547
+ // have tagName? force riot-tag to be the same
2548
+ if (tagName && riotTag !== tagName) {
2549
+ riotTag = tagName
2550
+ setAttr(root, RIOT_TAG_IS, tagName)
2551
+ setAttr(root, RIOT_TAG, tagName) // this will be removed in riot 3.0.0
2552
+ }
2553
+ var tag = mountTo(root, riotTag || root.tagName.toLowerCase(), opts)
2348
2554
 
2349
2555
  if (tag) tags.push(tag)
2350
- } else if (root.length)
2556
+ } else if (root.length) {
2351
2557
  each(root, pushTags) // assume nodeList
2352
-
2558
+ }
2353
2559
  }
2354
2560
 
2355
2561
  // ----- mount code -----
@@ -2357,7 +2563,7 @@ riot.mount = function(selector, tagName, opts) {
2357
2563
  // inject styles into DOM
2358
2564
  styleManager.inject()
2359
2565
 
2360
- if (typeof tagName === T_OBJECT) {
2566
+ if (isObject(tagName)) {
2361
2567
  opts = tagName
2362
2568
  tagName = 0
2363
2569
  }
@@ -2370,7 +2576,7 @@ riot.mount = function(selector, tagName, opts) {
2370
2576
  selector = allTags = selectAllTags()
2371
2577
  else
2372
2578
  // or just the ones named like the selector
2373
- selector += addRiotTags(selector.split(','))
2579
+ selector += addRiotTags(selector.split(/, */))
2374
2580
 
2375
2581
  // make sure to pass always a selector
2376
2582
  // to the querySelectorAll function
@@ -2399,10 +2605,7 @@ riot.mount = function(selector, tagName, opts) {
2399
2605
  tagName = 0
2400
2606
  }
2401
2607
 
2402
- if (els.tagName)
2403
- pushTags(els)
2404
- else
2405
- each(els, pushTags)
2608
+ pushTags(els)
2406
2609
 
2407
2610
  return tags
2408
2611
  }
@@ -2417,6 +2620,11 @@ riot.update = function() {
2417
2620
  })
2418
2621
  }
2419
2622
 
2623
+ /**
2624
+ * Export the Virtual DOM
2625
+ */
2626
+ riot.vdom = __virtualDom
2627
+
2420
2628
  /**
2421
2629
  * Export the Tag constructor
2422
2630
  */