riot_js-rails 0.3.0 → 0.4.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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/lib/riot_js/rails/processors/sprockets_processor_v3.rb +4 -2
- data/lib/riot_js/rails/railtie.rb +2 -2
- data/lib/riot_js/rails/version.rb +1 -1
- data/vendor/assets/javascripts/compiler/brackets.js +252 -0
- data/vendor/assets/javascripts/compiler/compiler.js +968 -10
- data/vendor/assets/javascripts/compiler/parsers.js +195 -21
- data/vendor/assets/javascripts/riot.js +1632 -569
- metadata +3 -3
- data/vendor/assets/javascripts/compiler/compiler_core.js +0 -234
@@ -1,32 +1,206 @@
|
|
1
|
-
|
1
|
+
/**
|
2
|
+
* The compiler.parsers object holds the compiler's predefined parsers
|
3
|
+
* @module
|
4
|
+
*/
|
5
|
+
|
6
|
+
var path = require('path') // for sass
|
7
|
+
|
8
|
+
// dummy function for the none and javascript parsers
|
9
|
+
function _none (src) { return src }
|
10
|
+
|
11
|
+
/** Cache of required modules */
|
12
|
+
var _mods = {
|
13
|
+
none: _none,
|
14
|
+
javascript: _none
|
15
|
+
}
|
16
|
+
|
17
|
+
/**
|
18
|
+
* Returns the module name for the given parser's name.
|
19
|
+
*
|
20
|
+
* @param {string} name - one of the `html`, `css`, or `js` parsers.
|
21
|
+
* @returns {string} The module name for using with `require()`
|
22
|
+
* @static
|
23
|
+
*/
|
24
|
+
function _modname (name) {
|
25
|
+
switch (name) {
|
26
|
+
case 'es6':
|
27
|
+
return 'babel'
|
28
|
+
case 'babel':
|
29
|
+
return 'babel-core'
|
30
|
+
case 'javascript':
|
31
|
+
return 'none'
|
32
|
+
case 'coffee':
|
33
|
+
case 'coffeescript':
|
34
|
+
return 'coffee-script'
|
35
|
+
case 'scss':
|
36
|
+
case 'sass':
|
37
|
+
return 'node-sass'
|
38
|
+
case 'typescript':
|
39
|
+
return 'typescript-simple'
|
40
|
+
default:
|
41
|
+
return name
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
/**
|
46
|
+
* Loads a parser instance via `require`, without generating error.
|
47
|
+
*
|
48
|
+
* @param {string} name - one of the `html`, `css`, or `js` parsers.
|
49
|
+
* @param {string} [req=name] - name for `require()`
|
50
|
+
* @returns {function} parser function, or null if error
|
51
|
+
*/
|
52
|
+
function _try (name, req) {
|
53
|
+
|
54
|
+
function fn (r) {
|
55
|
+
try { return require(r) } catch (_) {/**/}
|
56
|
+
return null
|
57
|
+
}
|
58
|
+
|
59
|
+
var p = _mods[name] = fn(req || _modname(name))
|
60
|
+
|
61
|
+
// istanbul ignore next: babel-core v5.8.x is not loaded by CI
|
62
|
+
if (!p && name === 'es6') {
|
63
|
+
p = _mods[name] = fn('babel-core')
|
64
|
+
}
|
65
|
+
return p
|
66
|
+
}
|
67
|
+
|
68
|
+
/**
|
69
|
+
* Returns a parser instance by its name, require the module if necessary.
|
70
|
+
* Public through the `parsers._req` function.
|
71
|
+
*
|
72
|
+
* @param {string} name - The parser's name, as registered in the parsers object
|
73
|
+
* @param {string} [req] - To be used by `_try` with `require`
|
74
|
+
* @returns {function} The parser instance, null if the parser is not found
|
75
|
+
* @static
|
76
|
+
*/
|
77
|
+
function _req (name, req) {
|
78
|
+
return name in _mods ? _mods[name] : _try(name, req)
|
79
|
+
}
|
80
|
+
|
81
|
+
/**
|
82
|
+
* Merge the properties of the first object with the properties of the second.
|
83
|
+
*
|
84
|
+
* @param {object} target - Target object
|
85
|
+
* @param {object} source - Source of the extra properties
|
86
|
+
* @returns {object} Target object containing the new properties
|
87
|
+
*/
|
88
|
+
function extend (target, source) {
|
89
|
+
if (source) {
|
90
|
+
for (var prop in source) {
|
91
|
+
/* istanbul ignore next */
|
92
|
+
if (source.hasOwnProperty(prop)) {
|
93
|
+
target[prop] = source[prop]
|
94
|
+
}
|
95
|
+
}
|
96
|
+
}
|
97
|
+
return target
|
98
|
+
}
|
99
|
+
|
100
|
+
module.exports = {
|
101
|
+
/**
|
102
|
+
* The HTML parsers.
|
103
|
+
* @prop {function} jade - http://jade-lang.com
|
104
|
+
*/
|
2
105
|
html: {
|
3
|
-
jade: function(html) {
|
4
|
-
|
106
|
+
jade: function (html, opts, url) {
|
107
|
+
opts = extend({
|
108
|
+
pretty: true,
|
109
|
+
filename: url,
|
110
|
+
doctype: 'html'
|
111
|
+
}, opts)
|
112
|
+
return _req('jade').render(html, opts)
|
113
|
+
}
|
114
|
+
},
|
115
|
+
/**
|
116
|
+
* Style parsers. In browsers, only less is supported.
|
117
|
+
* @prop {function} sass - http://sass-lang.com
|
118
|
+
* @prop {function} scss - http://sass-lang.com
|
119
|
+
* @prop {function} less - http://lesscss.org
|
120
|
+
* @prop {function} stylus - http://stylus-lang.com
|
121
|
+
*/
|
122
|
+
css: {
|
123
|
+
sass: function (tag, css, opts, url) {
|
124
|
+
opts = extend({
|
125
|
+
data: css,
|
126
|
+
includePaths: [path.dirname(url)],
|
127
|
+
indentedSyntax: true,
|
128
|
+
omitSourceMapUrl: true,
|
129
|
+
outputStyle: 'compact'
|
130
|
+
}, opts)
|
131
|
+
return _req('sass').renderSync(opts).css + ''
|
132
|
+
},
|
133
|
+
scss: function (tag, css, opts, url) {
|
134
|
+
opts = extend({
|
135
|
+
data: css,
|
136
|
+
includePaths: [path.dirname(url)],
|
137
|
+
indentedSyntax: false,
|
138
|
+
omitSourceMapUrl: true,
|
139
|
+
outputStyle: 'compact'
|
140
|
+
}, opts)
|
141
|
+
return _req('scss').renderSync(opts).css + ''
|
142
|
+
},
|
143
|
+
less: function (tag, css, opts, url) {
|
144
|
+
var ret
|
145
|
+
|
146
|
+
opts = extend({
|
147
|
+
sync: true,
|
148
|
+
syncImport: true,
|
149
|
+
filename: url
|
150
|
+
}, opts)
|
151
|
+
_req('less').render(css, opts, function (err, result) {
|
152
|
+
/* istanbul ignore next */
|
153
|
+
if (err) throw err
|
154
|
+
ret = result.css
|
155
|
+
})
|
156
|
+
return ret
|
157
|
+
},
|
158
|
+
stylus: function (tag, css, opts, url) {
|
159
|
+
var
|
160
|
+
stylus = _req('stylus'),
|
161
|
+
nib = _req('nib') // optional nib support
|
162
|
+
|
163
|
+
opts = extend({ filename: url }, opts)
|
164
|
+
/* istanbul ignore next: can't run both */
|
165
|
+
return nib
|
166
|
+
? stylus(css, opts).use(nib()).import('nib').render() : stylus.render(css, opts)
|
5
167
|
}
|
6
168
|
},
|
7
|
-
|
169
|
+
/**
|
170
|
+
* The JavaScript parsers.
|
171
|
+
* @prop {function} es6 - https://babeljs.io - babel or babel-core up to v5.8
|
172
|
+
* @prop {function} babel - https://babeljs.io - for v6.x or later
|
173
|
+
* @prop {function} coffee - http://coffeescript.org
|
174
|
+
* @prop {function} livescript - http://livescript.net
|
175
|
+
* @prop {function} typescript - http://www.typescriptlang.org
|
176
|
+
*/
|
8
177
|
js: {
|
9
|
-
|
10
|
-
|
178
|
+
es6: function (js, opts) {
|
179
|
+
opts = extend({
|
180
|
+
blacklist: ['useStrict', 'strict', 'react'],
|
181
|
+
sourceMaps: false,
|
182
|
+
comments: false
|
183
|
+
}, opts)
|
184
|
+
return _req('es6').transform(js, opts).code
|
11
185
|
},
|
12
|
-
|
13
|
-
return
|
186
|
+
babel: function (js, opts, url) {
|
187
|
+
return _req('babel').transform(js, extend({ filename: url }, opts)).code
|
14
188
|
},
|
15
|
-
|
16
|
-
return
|
189
|
+
coffee: function (js, opts) {
|
190
|
+
return _req('coffee').compile(js, extend({ bare: true }, opts))
|
17
191
|
},
|
18
|
-
|
19
|
-
return
|
192
|
+
livescript: function (js, opts) {
|
193
|
+
return _req('livescript').compile(js, extend({ bare: true, header: false }, opts))
|
20
194
|
},
|
21
|
-
|
22
|
-
return
|
23
|
-
}
|
24
|
-
|
195
|
+
typescript: function (js, opts) {
|
196
|
+
return _req('typescript')(js, opts)
|
197
|
+
},
|
198
|
+
none: _none, javascript: _none
|
199
|
+
},
|
200
|
+
_modname: _modname,
|
201
|
+
_req: _req
|
25
202
|
}
|
26
203
|
|
27
|
-
|
28
|
-
|
29
|
-
// 4 the nostalgics
|
30
|
-
parsers.js.coffeescript = parsers.js.coffee
|
204
|
+
exports = module.exports
|
205
|
+
exports.js.coffeescript = exports.js.coffee // 4 the nostalgics
|
31
206
|
|
32
|
-
module.exports = parsers
|
@@ -1,13 +1,21 @@
|
|
1
|
-
/* Riot v2.
|
1
|
+
/* Riot v2.3.15, @license MIT, (c) 2015 Muut Inc. + contributors */
|
2
2
|
|
3
3
|
;(function(window, undefined) {
|
4
4
|
'use strict';
|
5
|
-
var riot = { version: 'v2.
|
6
|
-
|
5
|
+
var riot = { version: 'v2.3.15', settings: {} },
|
6
|
+
// be aware, internal usage
|
7
|
+
// ATTENTION: prefix the global dynamic variables with `__`
|
7
8
|
|
8
9
|
// counter to give a unique id to all the Tag instances
|
9
10
|
__uid = 0,
|
10
|
-
|
11
|
+
// tags instances cache
|
12
|
+
__virtualDom = [],
|
13
|
+
// tags implementation cache
|
14
|
+
__tagImpl = {},
|
15
|
+
|
16
|
+
/**
|
17
|
+
* Const
|
18
|
+
*/
|
11
19
|
// riot specific prefixes
|
12
20
|
RIOT_PREFIX = 'riot-',
|
13
21
|
RIOT_TAG = RIOT_PREFIX + 'tag',
|
@@ -18,470 +26,984 @@ var riot = { version: 'v2.2.4', settings: {} },
|
|
18
26
|
T_UNDEF = 'undefined',
|
19
27
|
T_FUNCTION = 'function',
|
20
28
|
// special native tags that cannot be treated like the others
|
21
|
-
SPECIAL_TAGS_REGEX = /^(?:
|
22
|
-
RESERVED_WORDS_BLACKLIST = ['_item', '_id', 'update', 'root', 'mount', 'unmount', 'mixin', 'isMounted', 'isLoop', 'tags', 'parent', 'opts', 'trigger', 'on', 'off', 'one'],
|
29
|
+
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'],
|
23
31
|
|
24
32
|
// 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
|
-
|
33
|
+
IE_VERSION = (window && window.document || {}).documentMode | 0
|
34
|
+
/* istanbul ignore next */
|
30
35
|
riot.observable = function(el) {
|
31
36
|
|
37
|
+
/**
|
38
|
+
* Extend the original object or create a new empty one
|
39
|
+
* @type { Object }
|
40
|
+
*/
|
41
|
+
|
32
42
|
el = el || {}
|
33
43
|
|
44
|
+
/**
|
45
|
+
* Private variables and methods
|
46
|
+
*/
|
34
47
|
var callbacks = {},
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
fn.typed = pos > 0
|
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
|
44
56
|
})
|
45
57
|
}
|
58
|
+
|
59
|
+
/**
|
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
|
64
|
+
*/
|
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
|
+
|
46
73
|
return el
|
47
|
-
}
|
74
|
+
})
|
48
75
|
|
49
|
-
|
50
|
-
|
76
|
+
/**
|
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
|
81
|
+
*/
|
82
|
+
defineProperty('off', function(events, fn) {
|
83
|
+
if (events == '*' && !fn) callbacks = {}
|
51
84
|
else {
|
52
|
-
events
|
85
|
+
onEachEvent(events, function(name) {
|
53
86
|
if (fn) {
|
54
87
|
var arr = callbacks[name]
|
55
|
-
for (var i = 0, cb;
|
56
|
-
if (cb
|
88
|
+
for (var i = 0, cb; cb = arr && arr[i]; ++i) {
|
89
|
+
if (cb == fn) arr.splice(i--, 1)
|
57
90
|
}
|
58
|
-
} else
|
59
|
-
callbacks[name] = []
|
60
|
-
}
|
91
|
+
} else delete callbacks[name]
|
61
92
|
})
|
62
93
|
}
|
63
94
|
return el
|
64
|
-
}
|
95
|
+
})
|
65
96
|
|
66
|
-
|
67
|
-
|
97
|
+
/**
|
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
|
102
|
+
*/
|
103
|
+
defineProperty('one', function(events, fn) {
|
68
104
|
function on() {
|
69
|
-
el.off(
|
105
|
+
el.off(events, on)
|
70
106
|
fn.apply(el, arguments)
|
71
107
|
}
|
72
|
-
return el.on(
|
73
|
-
}
|
108
|
+
return el.on(events, on)
|
109
|
+
})
|
110
|
+
|
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) {
|
117
|
+
|
118
|
+
// getting the arguments
|
119
|
+
// skipping the first one
|
120
|
+
var args = slice.call(arguments, 1),
|
121
|
+
fns
|
122
|
+
|
123
|
+
onEachEvent(events, function(name) {
|
74
124
|
|
75
|
-
|
76
|
-
var args = [].slice.call(arguments, 1),
|
77
|
-
fns = callbacks[name] || []
|
125
|
+
fns = slice.call(callbacks[name] || [], 0)
|
78
126
|
|
79
|
-
|
80
|
-
|
127
|
+
for (var i = 0, fn; fn = fns[i]; ++i) {
|
128
|
+
if (fn.busy) return
|
81
129
|
fn.busy = 1
|
82
130
|
fn.apply(el, fn.typed ? [name].concat(args) : args)
|
83
131
|
if (fns[i] !== fn) { i-- }
|
84
132
|
fn.busy = 0
|
85
133
|
}
|
86
|
-
}
|
87
134
|
|
88
|
-
|
89
|
-
|
90
|
-
|
135
|
+
if (callbacks['*'] && name != '*')
|
136
|
+
el.trigger.apply(el, ['*', name].concat(args))
|
137
|
+
|
138
|
+
})
|
91
139
|
|
92
140
|
return el
|
93
|
-
}
|
141
|
+
})
|
94
142
|
|
95
143
|
return el
|
96
144
|
|
97
145
|
}
|
98
|
-
|
99
|
-
|
146
|
+
/* istanbul ignore next */
|
147
|
+
;(function(riot) {
|
148
|
+
|
149
|
+
/**
|
150
|
+
* Simple client-side router
|
151
|
+
* @module riot-route
|
152
|
+
*/
|
153
|
+
|
154
|
+
|
155
|
+
var RE_ORIGIN = /^.+?\/+[^\/]+/,
|
156
|
+
EVENT_LISTENER = 'EventListener',
|
157
|
+
REMOVE_EVENT_LISTENER = 'remove' + EVENT_LISTENER,
|
158
|
+
ADD_EVENT_LISTENER = 'add' + EVENT_LISTENER,
|
159
|
+
HAS_ATTRIBUTE = 'hasAttribute',
|
160
|
+
REPLACE = 'replace',
|
161
|
+
POPSTATE = 'popstate',
|
162
|
+
HASHCHANGE = 'hashchange',
|
163
|
+
TRIGGER = 'trigger',
|
164
|
+
MAX_EMIT_STACK_LEVEL = 3,
|
165
|
+
win = typeof window != 'undefined' && window,
|
166
|
+
doc = typeof document != 'undefined' && document,
|
167
|
+
hist = win && history,
|
168
|
+
loc = win && (hist.location || win.location), // see html5-history-api
|
169
|
+
prot = Router.prototype, // to minify more
|
170
|
+
clickEvent = doc && doc.ontouchstart ? 'touchstart' : 'click',
|
171
|
+
started = false,
|
172
|
+
central = riot.observable(),
|
173
|
+
routeFound = false,
|
174
|
+
debouncedEmit,
|
175
|
+
base, current, parser, secondParser, emitStack = [], emitStackLevel = 0
|
176
|
+
|
177
|
+
/**
|
178
|
+
* Default parser. You can replace it via router.parser method.
|
179
|
+
* @param {string} path - current path (normalized)
|
180
|
+
* @returns {array} array
|
181
|
+
*/
|
182
|
+
function DEFAULT_PARSER(path) {
|
183
|
+
return path.split(/[/?#]/)
|
184
|
+
}
|
100
185
|
|
101
|
-
|
102
|
-
|
103
|
-
|
186
|
+
/**
|
187
|
+
* Default parser (second). You can replace it via router.parser method.
|
188
|
+
* @param {string} path - current path (normalized)
|
189
|
+
* @param {string} filter - filter string (normalized)
|
190
|
+
* @returns {array} array
|
191
|
+
*/
|
192
|
+
function DEFAULT_SECOND_PARSER(path, filter) {
|
193
|
+
var re = new RegExp('^' + filter[REPLACE](/\*/g, '([^/?#]+?)')[REPLACE](/\.\./, '.*') + '$'),
|
194
|
+
args = path.match(re)
|
195
|
+
|
196
|
+
if (args) return args.slice(1)
|
197
|
+
}
|
198
|
+
|
199
|
+
/**
|
200
|
+
* Simple/cheap debounce implementation
|
201
|
+
* @param {function} fn - callback
|
202
|
+
* @param {number} delay - delay in seconds
|
203
|
+
* @returns {function} debounced function
|
204
|
+
*/
|
205
|
+
function debounce(fn, delay) {
|
206
|
+
var t
|
207
|
+
return function () {
|
208
|
+
clearTimeout(t)
|
209
|
+
t = setTimeout(fn, delay)
|
104
210
|
}
|
211
|
+
}
|
105
212
|
|
106
|
-
|
213
|
+
/**
|
214
|
+
* Set the window listeners to trigger the routes
|
215
|
+
* @param {boolean} autoExec - see route.start
|
216
|
+
*/
|
217
|
+
function start(autoExec) {
|
218
|
+
debouncedEmit = debounce(emit, 1)
|
219
|
+
win[ADD_EVENT_LISTENER](POPSTATE, debouncedEmit)
|
220
|
+
win[ADD_EVENT_LISTENER](HASHCHANGE, debouncedEmit)
|
221
|
+
doc[ADD_EVENT_LISTENER](clickEvent, click)
|
222
|
+
if (autoExec) emit(true)
|
223
|
+
}
|
107
224
|
|
108
|
-
|
225
|
+
/**
|
226
|
+
* Router class
|
227
|
+
*/
|
228
|
+
function Router() {
|
229
|
+
this.$ = []
|
230
|
+
riot.observable(this) // make it observable
|
231
|
+
central.on('stop', this.s.bind(this))
|
232
|
+
central.on('emit', this.e.bind(this))
|
233
|
+
}
|
109
234
|
|
110
|
-
|
111
|
-
|
235
|
+
function normalize(path) {
|
236
|
+
return path[REPLACE](/^\/|\/$/, '')
|
237
|
+
}
|
112
238
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
current
|
239
|
+
function isString(str) {
|
240
|
+
return typeof str == 'string'
|
241
|
+
}
|
117
242
|
|
118
|
-
|
119
|
-
|
120
|
-
|
243
|
+
/**
|
244
|
+
* Get the part after domain name
|
245
|
+
* @param {string} href - fullpath
|
246
|
+
* @returns {string} path from root
|
247
|
+
*/
|
248
|
+
function getPathFromRoot(href) {
|
249
|
+
return (href || loc.href || '')[REPLACE](RE_ORIGIN, '')
|
250
|
+
}
|
121
251
|
|
122
|
-
|
123
|
-
|
124
|
-
|
252
|
+
/**
|
253
|
+
* Get the part after base
|
254
|
+
* @param {string} href - fullpath
|
255
|
+
* @returns {string} path from base
|
256
|
+
*/
|
257
|
+
function getPathFromBase(href) {
|
258
|
+
return base[0] == '#'
|
259
|
+
? (href || loc.href || '').split(base)[1] || ''
|
260
|
+
: getPathFromRoot(href)[REPLACE](base, '')
|
261
|
+
}
|
125
262
|
|
126
|
-
|
127
|
-
|
263
|
+
function emit(force) {
|
264
|
+
// the stack is needed for redirections
|
265
|
+
var isRoot = emitStackLevel == 0
|
266
|
+
if (MAX_EMIT_STACK_LEVEL <= emitStackLevel) return
|
128
267
|
|
129
|
-
|
130
|
-
|
268
|
+
emitStackLevel++
|
269
|
+
emitStack.push(function() {
|
270
|
+
var path = getPathFromBase()
|
271
|
+
if (force || path != current) {
|
272
|
+
central[TRIGGER]('emit', path)
|
131
273
|
current = path
|
132
274
|
}
|
133
|
-
}
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
loc.hash = arg
|
139
|
-
emit(arg)
|
140
|
-
|
141
|
-
// function
|
142
|
-
} else {
|
143
|
-
fns.on('H', arg)
|
275
|
+
})
|
276
|
+
if (isRoot) {
|
277
|
+
while (emitStack.length) {
|
278
|
+
emitStack[0]()
|
279
|
+
emitStack.shift()
|
144
280
|
}
|
281
|
+
emitStackLevel = 0
|
145
282
|
}
|
283
|
+
}
|
146
284
|
|
147
|
-
|
148
|
-
|
285
|
+
function click(e) {
|
286
|
+
if (
|
287
|
+
e.which != 1 // not left click
|
288
|
+
|| e.metaKey || e.ctrlKey || e.shiftKey // or meta keys
|
289
|
+
|| e.defaultPrevented // or default prevented
|
290
|
+
) return
|
291
|
+
|
292
|
+
var el = e.target
|
293
|
+
while (el && el.nodeName != 'A') el = el.parentNode
|
294
|
+
if (
|
295
|
+
!el || el.nodeName != 'A' // not A tag
|
296
|
+
|| el[HAS_ATTRIBUTE]('download') // has download attr
|
297
|
+
|| !el[HAS_ATTRIBUTE]('href') // has no href attr
|
298
|
+
|| el.target && el.target != '_self' // another window or frame
|
299
|
+
|| el.href.indexOf(loc.href.match(RE_ORIGIN)[0]) == -1 // cross origin
|
300
|
+
) return
|
301
|
+
|
302
|
+
if (el.href != loc.href) {
|
303
|
+
if (
|
304
|
+
el.href.split('#')[0] == loc.href.split('#')[0] // internal jump
|
305
|
+
|| base != '#' && getPathFromRoot(el.href).indexOf(base) !== 0 // outside of base
|
306
|
+
|| !go(getPathFromBase(el.href), el.title || doc.title) // route not found
|
307
|
+
) return
|
149
308
|
}
|
150
309
|
|
151
|
-
|
152
|
-
|
153
|
-
}
|
310
|
+
e.preventDefault()
|
311
|
+
}
|
154
312
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
313
|
+
/**
|
314
|
+
* Go to the path
|
315
|
+
* @param {string} path - destination path
|
316
|
+
* @param {string} title - page title
|
317
|
+
* @param {boolean} shouldReplace - use replaceState or pushState
|
318
|
+
* @returns {boolean} - route not found flag
|
319
|
+
*/
|
320
|
+
function go(path, title, shouldReplace) {
|
321
|
+
if (hist) { // if a browser
|
322
|
+
path = base + normalize(path)
|
323
|
+
title = title || doc.title
|
324
|
+
// browsers ignores the second parameter `title`
|
325
|
+
shouldReplace
|
326
|
+
? hist.replaceState(null, title, path)
|
327
|
+
: hist.pushState(null, title, path)
|
328
|
+
// so we need to set it manually
|
329
|
+
doc.title = title
|
330
|
+
routeFound = false
|
331
|
+
emit()
|
332
|
+
return routeFound
|
162
333
|
}
|
163
334
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
335
|
+
// Server-side usage: directly execute handlers for the path
|
336
|
+
return central[TRIGGER]('emit', getPathFromBase(path))
|
337
|
+
}
|
338
|
+
|
339
|
+
/**
|
340
|
+
* Go to path or set action
|
341
|
+
* a single string: go there
|
342
|
+
* two strings: go there with setting a title
|
343
|
+
* two strings and boolean: replace history with setting a title
|
344
|
+
* a single function: set an action on the default route
|
345
|
+
* a string/RegExp and a function: set an action on the route
|
346
|
+
* @param {(string|function)} first - path / action / filter
|
347
|
+
* @param {(string|RegExp|function)} second - title / action
|
348
|
+
* @param {boolean} third - replace flag
|
349
|
+
*/
|
350
|
+
prot.m = function(first, second, third) {
|
351
|
+
if (isString(first) && (!second || isString(second))) go(first, second, third || false)
|
352
|
+
else if (second) this.r(first, second)
|
353
|
+
else this.r('@', first)
|
354
|
+
}
|
355
|
+
|
356
|
+
/**
|
357
|
+
* Stop routing
|
358
|
+
*/
|
359
|
+
prot.s = function() {
|
360
|
+
this.off('*')
|
361
|
+
this.$ = []
|
362
|
+
}
|
363
|
+
|
364
|
+
/**
|
365
|
+
* Emit
|
366
|
+
* @param {string} path - path
|
367
|
+
*/
|
368
|
+
prot.e = function(path) {
|
369
|
+
this.$.concat('@').some(function(filter) {
|
370
|
+
var args = (filter == '@' ? parser : secondParser)(normalize(path), normalize(filter))
|
371
|
+
if (typeof args != 'undefined') {
|
372
|
+
this[TRIGGER].apply(null, [filter].concat(args))
|
373
|
+
return routeFound = true // exit from loop
|
169
374
|
}
|
375
|
+
}, this)
|
376
|
+
}
|
377
|
+
|
378
|
+
/**
|
379
|
+
* Register route
|
380
|
+
* @param {string} filter - filter for matching to url
|
381
|
+
* @param {function} action - action to register
|
382
|
+
*/
|
383
|
+
prot.r = function(filter, action) {
|
384
|
+
if (filter != '@') {
|
385
|
+
filter = '/' + normalize(filter)
|
386
|
+
this.$.push(filter)
|
170
387
|
}
|
388
|
+
this.on(filter, action)
|
389
|
+
}
|
171
390
|
|
172
|
-
|
173
|
-
|
391
|
+
var mainRouter = new Router()
|
392
|
+
var route = mainRouter.m.bind(mainRouter)
|
393
|
+
|
394
|
+
/**
|
395
|
+
* Create a sub router
|
396
|
+
* @returns {function} the method of a new Router object
|
397
|
+
*/
|
398
|
+
route.create = function() {
|
399
|
+
var newSubRouter = new Router()
|
400
|
+
// 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)
|
404
|
+
}
|
174
405
|
|
175
|
-
|
176
|
-
|
406
|
+
/**
|
407
|
+
* Set the base of url
|
408
|
+
* @param {(str|RegExp)} arg - a new base or '#' or '#!'
|
409
|
+
*/
|
410
|
+
route.base = function(arg) {
|
411
|
+
base = arg || '#'
|
412
|
+
current = getPathFromBase() // recalculate current path
|
413
|
+
}
|
177
414
|
|
178
|
-
|
415
|
+
/** Exec routing right now **/
|
416
|
+
route.exec = function() {
|
417
|
+
emit(true)
|
418
|
+
}
|
419
|
+
|
420
|
+
/**
|
421
|
+
* Replace the default router to yours
|
422
|
+
* @param {function} fn - your parser function
|
423
|
+
* @param {function} fn2 - your secondParser function
|
424
|
+
*/
|
425
|
+
route.parser = function(fn, fn2) {
|
426
|
+
if (!fn && !fn2) {
|
427
|
+
// reset parser for testing...
|
428
|
+
parser = DEFAULT_PARSER
|
429
|
+
secondParser = DEFAULT_SECOND_PARSER
|
430
|
+
}
|
431
|
+
if (fn) parser = fn
|
432
|
+
if (fn2) secondParser = fn2
|
433
|
+
}
|
434
|
+
|
435
|
+
/**
|
436
|
+
* Helper function to get url query as an object
|
437
|
+
* @returns {object} parsed query
|
438
|
+
*/
|
439
|
+
route.query = function() {
|
440
|
+
var q = {}
|
441
|
+
var href = loc.href || current
|
442
|
+
href[REPLACE](/[?&](.+?)=([^&]*)/g, function(_, k, v) { q[k] = v })
|
443
|
+
return q
|
444
|
+
}
|
445
|
+
|
446
|
+
/** Stop routing **/
|
447
|
+
route.stop = function () {
|
448
|
+
if (started) {
|
449
|
+
if (win) {
|
450
|
+
win[REMOVE_EVENT_LISTENER](POPSTATE, debouncedEmit)
|
451
|
+
win[REMOVE_EVENT_LISTENER](HASHCHANGE, debouncedEmit)
|
452
|
+
doc[REMOVE_EVENT_LISTENER](clickEvent, click)
|
453
|
+
}
|
454
|
+
central[TRIGGER]('stop')
|
455
|
+
started = false
|
456
|
+
}
|
457
|
+
}
|
179
458
|
|
459
|
+
/**
|
460
|
+
* Start routing
|
461
|
+
* @param {boolean} autoExec - automatically exec after starting if true
|
462
|
+
*/
|
463
|
+
route.start = function (autoExec) {
|
464
|
+
if (!started) {
|
465
|
+
if (win) {
|
466
|
+
if (document.readyState == 'complete') start(autoExec)
|
467
|
+
// the timeout is needed to solve
|
468
|
+
// a weird safari bug https://github.com/riot/route/issues/33
|
469
|
+
else win[ADD_EVENT_LISTENER]('load', function() {
|
470
|
+
setTimeout(function() { start(autoExec) }, 1)
|
471
|
+
})
|
472
|
+
}
|
473
|
+
started = true
|
474
|
+
}
|
475
|
+
}
|
180
476
|
|
181
|
-
|
477
|
+
/** Prepare the router **/
|
478
|
+
route.base()
|
479
|
+
route.parser()
|
480
|
+
|
481
|
+
riot.route = route
|
482
|
+
})(riot)
|
483
|
+
/* istanbul ignore next */
|
484
|
+
|
485
|
+
/**
|
486
|
+
* The riot template engine
|
487
|
+
* @version v2.3.21
|
488
|
+
*/
|
489
|
+
|
490
|
+
/**
|
491
|
+
* riot.util.brackets
|
492
|
+
*
|
493
|
+
* - `brackets ` - Returns a string or regex based on its parameter
|
494
|
+
* - `brackets.set` - Change the current riot brackets
|
495
|
+
*
|
496
|
+
* @module
|
497
|
+
*/
|
498
|
+
|
499
|
+
var brackets = (function (UNDEF) {
|
500
|
+
|
501
|
+
var
|
502
|
+
REGLOB = 'g',
|
503
|
+
|
504
|
+
R_MLCOMMS = /\/\*[^*]*\*+(?:[^*\/][^*]*\*+)*\//g,
|
505
|
+
|
506
|
+
R_STRINGS = /"[^"\\]*(?:\\[\S\s][^"\\]*)*"|'[^'\\]*(?:\\[\S\s][^'\\]*)*'/g,
|
507
|
+
|
508
|
+
S_QBLOCKS = R_STRINGS.source + '|' +
|
509
|
+
/(?:\breturn\s+|(?:[$\w\)\]]|\+\+|--)\s*(\/)(?![*\/]))/.source + '|' +
|
510
|
+
/\/(?=[^*\/])[^[\/\\]*(?:(?:\[(?:\\.|[^\]\\]*)*\]|\\.)[^[\/\\]*)*?(\/)[gim]*/.source,
|
511
|
+
|
512
|
+
FINDBRACES = {
|
513
|
+
'(': RegExp('([()])|' + S_QBLOCKS, REGLOB),
|
514
|
+
'[': RegExp('([[\\]])|' + S_QBLOCKS, REGLOB),
|
515
|
+
'{': RegExp('([{}])|' + S_QBLOCKS, REGLOB)
|
516
|
+
},
|
517
|
+
|
518
|
+
DEFAULT = '{ }'
|
519
|
+
|
520
|
+
var _pairs = [
|
521
|
+
'{', '}',
|
522
|
+
'{', '}',
|
523
|
+
/{[^}]*}/,
|
524
|
+
/\\([{}])/g,
|
525
|
+
/\\({)|{/g,
|
526
|
+
RegExp('\\\\(})|([[({])|(})|' + S_QBLOCKS, REGLOB),
|
527
|
+
DEFAULT,
|
528
|
+
/^\s*{\^?\s*([$\w]+)(?:\s*,\s*(\S+))?\s+in\s+(\S.*)\s*}/,
|
529
|
+
/(^|[^\\]){=[\S\s]*?}/
|
530
|
+
]
|
531
|
+
|
532
|
+
var
|
533
|
+
cachedBrackets = UNDEF,
|
534
|
+
_regex,
|
535
|
+
_cache = [],
|
536
|
+
_settings
|
537
|
+
|
538
|
+
function _loopback (re) { return re }
|
539
|
+
|
540
|
+
function _rewrite (re, bp) {
|
541
|
+
if (!bp) bp = _cache
|
542
|
+
return new RegExp(
|
543
|
+
re.source.replace(/{/g, bp[2]).replace(/}/g, bp[3]), re.global ? REGLOB : ''
|
544
|
+
)
|
545
|
+
}
|
182
546
|
|
183
|
-
|
184
|
-
|
547
|
+
function _create (pair) {
|
548
|
+
if (pair === DEFAULT) return _pairs
|
185
549
|
|
186
|
-
|
187
|
-
Returns a string with evaluated expressions.
|
550
|
+
var arr = pair.split(' ')
|
188
551
|
|
189
|
-
|
190
|
-
|
191
|
-
|
552
|
+
if (arr.length !== 2 || /[\x00-\x1F<>a-zA-Z0-9'",;\\]/.test(pair)) {
|
553
|
+
throw new Error('Unsupported brackets "' + pair + '"')
|
554
|
+
}
|
555
|
+
arr = arr.concat(pair.replace(/(?=[[\]()*+?.^$|])/g, '\\').split(' '))
|
556
|
+
|
557
|
+
arr[4] = _rewrite(arr[1].length > 1 ? /{[\S\s]*?}/ : _pairs[4], arr)
|
558
|
+
arr[5] = _rewrite(pair.length > 3 ? /\\({|})/g : _pairs[5], arr)
|
559
|
+
arr[6] = _rewrite(_pairs[6], arr)
|
560
|
+
arr[7] = RegExp('\\\\(' + arr[3] + ')|([[({])|(' + arr[3] + ')|' + S_QBLOCKS, REGLOB)
|
561
|
+
arr[8] = pair
|
562
|
+
return arr
|
563
|
+
}
|
192
564
|
|
565
|
+
function _brackets (reOrIdx) {
|
566
|
+
return reOrIdx instanceof RegExp ? _regex(reOrIdx) : _cache[reOrIdx]
|
567
|
+
}
|
193
568
|
|
194
|
-
|
569
|
+
_brackets.split = function split (str, tmpl, _bp) {
|
570
|
+
// istanbul ignore next: _bp is for the compiler
|
571
|
+
if (!_bp) _bp = _cache
|
195
572
|
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
573
|
+
var
|
574
|
+
parts = [],
|
575
|
+
match,
|
576
|
+
isexpr,
|
577
|
+
start,
|
578
|
+
pos,
|
579
|
+
re = _bp[6]
|
202
580
|
|
581
|
+
isexpr = start = re.lastIndex = 0
|
203
582
|
|
204
|
-
|
583
|
+
while (match = re.exec(str)) {
|
205
584
|
|
206
|
-
|
207
|
-
except zero (undefined/null/false) will default to empty string:
|
585
|
+
pos = match.index
|
208
586
|
|
209
|
-
|
210
|
-
// will return: " - - - 0"
|
587
|
+
if (isexpr) {
|
211
588
|
|
212
|
-
|
589
|
+
if (match[2]) {
|
590
|
+
re.lastIndex = skipBraces(str, match[2], re.lastIndex)
|
591
|
+
continue
|
592
|
+
}
|
593
|
+
if (!match[3])
|
594
|
+
continue
|
595
|
+
}
|
213
596
|
|
597
|
+
if (!match[1]) {
|
598
|
+
unescapeStr(str.slice(start, pos))
|
599
|
+
start = re.lastIndex
|
600
|
+
re = _bp[6 + (isexpr ^= 1)]
|
601
|
+
re.lastIndex = start
|
602
|
+
}
|
603
|
+
}
|
214
604
|
|
215
|
-
|
605
|
+
if (str && start < str.length) {
|
606
|
+
unescapeStr(str.slice(start))
|
607
|
+
}
|
216
608
|
|
217
|
-
|
218
|
-
r,
|
219
|
-
b,
|
220
|
-
re = /[{}]/g
|
609
|
+
return parts
|
221
610
|
|
222
|
-
|
611
|
+
function unescapeStr (s) {
|
612
|
+
if (tmpl || isexpr)
|
613
|
+
parts.push(s && s.replace(_bp[5], '$1'))
|
614
|
+
else
|
615
|
+
parts.push(s)
|
616
|
+
}
|
223
617
|
|
224
|
-
|
225
|
-
|
618
|
+
function skipBraces (s, ch, ix) {
|
619
|
+
var
|
620
|
+
match,
|
621
|
+
recch = FINDBRACES[ch]
|
226
622
|
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
623
|
+
recch.lastIndex = ix
|
624
|
+
ix = 1
|
625
|
+
while (match = recch.exec(s)) {
|
626
|
+
if (match[1] &&
|
627
|
+
!(match[1] === ch ? ++ix : --ix)) break
|
628
|
+
}
|
629
|
+
return ix ? s.length : recch.lastIndex
|
232
630
|
}
|
631
|
+
}
|
233
632
|
|
234
|
-
|
235
|
-
return
|
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]
|
633
|
+
_brackets.hasExpr = function hasExpr (str) {
|
634
|
+
return _cache[4].test(str)
|
241
635
|
}
|
242
|
-
})('{ }')
|
243
636
|
|
637
|
+
_brackets.loopKeys = function loopKeys (expr) {
|
638
|
+
var m = expr.match(_cache[9])
|
639
|
+
return m
|
640
|
+
? { key: m[1], pos: m[2], val: _cache[0] + m[3].trim() + _cache[1] }
|
641
|
+
: { val: expr.trim() }
|
642
|
+
}
|
244
643
|
|
245
|
-
|
644
|
+
_brackets.hasRaw = function (src) {
|
645
|
+
return _cache[10].test(src)
|
646
|
+
}
|
246
647
|
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
/(['"\/])(?:[^\\]*?|\\.|.)*?\1|\.\w*|\w*:|\b(?:(?:new|typeof|in|instanceof) |(?:this|true|false|null|undefined)\b|function\s*\()|([A-Za-z_$]\w*)/g
|
648
|
+
_brackets.array = function array (pair) {
|
649
|
+
return pair ? _create(pair) : _cache
|
650
|
+
}
|
251
651
|
|
252
|
-
|
253
|
-
|
254
|
-
|
652
|
+
function _reset (pair) {
|
653
|
+
if ((pair || (pair = DEFAULT)) !== _cache[8]) {
|
654
|
+
_cache = _create(pair)
|
655
|
+
_regex = pair === DEFAULT ? _loopback : _rewrite
|
656
|
+
_cache[9] = _regex(_pairs[9])
|
657
|
+
_cache[10] = _regex(_pairs[10])
|
658
|
+
}
|
659
|
+
cachedBrackets = pair
|
255
660
|
}
|
256
661
|
|
662
|
+
function _setSettings (o) {
|
663
|
+
var b
|
664
|
+
o = o || {}
|
665
|
+
b = o.brackets
|
666
|
+
Object.defineProperty(o, 'brackets', {
|
667
|
+
set: _reset,
|
668
|
+
get: function () { return cachedBrackets },
|
669
|
+
enumerable: true
|
670
|
+
})
|
671
|
+
_settings = o
|
672
|
+
_reset(b)
|
673
|
+
}
|
257
674
|
|
258
|
-
|
675
|
+
Object.defineProperty(_brackets, 'settings', {
|
676
|
+
set: _setSettings,
|
677
|
+
get: function () { return _settings }
|
678
|
+
})
|
259
679
|
|
260
|
-
|
680
|
+
/* istanbul ignore next: in the browser riot is always in the scope */
|
681
|
+
_brackets.settings = typeof riot !== 'undefined' && riot.settings || {}
|
682
|
+
_brackets.set = _reset
|
261
683
|
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
return function () { return s }
|
266
|
-
}
|
684
|
+
_brackets.R_STRINGS = R_STRINGS
|
685
|
+
_brackets.R_MLCOMMS = R_MLCOMMS
|
686
|
+
_brackets.S_QBLOCKS = S_QBLOCKS
|
267
687
|
|
268
|
-
|
269
|
-
s = s
|
270
|
-
.replace(brackets(/\\{/g), '\uFFF0')
|
271
|
-
.replace(brackets(/\\}/g), '\uFFF1')
|
688
|
+
return _brackets
|
272
689
|
|
273
|
-
|
274
|
-
p = split(s, extract(s, brackets(/{/), brackets(/}/)))
|
690
|
+
})()
|
275
691
|
|
276
|
-
|
277
|
-
|
692
|
+
/**
|
693
|
+
* @module tmpl
|
694
|
+
*
|
695
|
+
* tmpl - Root function, returns the template value, render with data
|
696
|
+
* tmpl.hasExpr - Test the existence of a expression inside a string
|
697
|
+
* tmpl.loopKeys - Get the keys for an 'each' loop (used by `_each`)
|
698
|
+
*/
|
278
699
|
|
279
|
-
|
280
|
-
expr(p[1]) :
|
700
|
+
var tmpl = (function () {
|
281
701
|
|
282
|
-
|
283
|
-
'[' + p.map(function(s, i) {
|
702
|
+
var _cache = {}
|
284
703
|
|
285
|
-
|
286
|
-
|
704
|
+
function _tmpl (str, data) {
|
705
|
+
if (!str) return str
|
287
706
|
|
288
|
-
|
289
|
-
|
707
|
+
return (_cache[str] || (_cache[str] = _create(str))).call(data, _logErr)
|
708
|
+
}
|
290
709
|
|
291
|
-
|
292
|
-
'"' + s
|
710
|
+
_tmpl.haveRaw = brackets.hasRaw
|
293
711
|
|
294
|
-
|
295
|
-
.replace(/\n|\r\n?/g, '\\n')
|
712
|
+
_tmpl.hasExpr = brackets.hasExpr
|
296
713
|
|
297
|
-
|
298
|
-
.replace(/"/g, '\\"') +
|
714
|
+
_tmpl.loopKeys = brackets.loopKeys
|
299
715
|
|
300
|
-
|
716
|
+
_tmpl.errorHandler = null
|
301
717
|
|
302
|
-
|
718
|
+
function _logErr (err, ctx) {
|
303
719
|
|
304
|
-
|
305
|
-
// bring escaped { and } back
|
306
|
-
.replace(/\uFFF0/g, brackets(0))
|
307
|
-
.replace(/\uFFF1/g, brackets(1)) + ';')
|
720
|
+
if (_tmpl.errorHandler) {
|
308
721
|
|
722
|
+
err.riotData = {
|
723
|
+
tagName: ctx && ctx.root && ctx.root.tagName,
|
724
|
+
_riot_id: ctx && ctx._riot_id //eslint-disable-line camelcase
|
725
|
+
}
|
726
|
+
_tmpl.errorHandler(err)
|
727
|
+
}
|
309
728
|
}
|
310
729
|
|
730
|
+
function _create (str) {
|
311
731
|
|
312
|
-
|
732
|
+
var expr = _getTmpl(str)
|
733
|
+
if (expr.slice(0, 11) !== 'try{return ') expr = 'return ' + expr
|
313
734
|
|
314
|
-
|
315
|
-
|
735
|
+
return new Function('E', expr + ';')
|
736
|
+
}
|
316
737
|
|
317
|
-
|
318
|
-
|
738
|
+
var
|
739
|
+
RE_QBLOCK = RegExp(brackets.S_QBLOCKS, 'g'),
|
740
|
+
RE_QBMARK = /\x01(\d+)~/g
|
319
741
|
|
320
|
-
|
321
|
-
|
742
|
+
function _getTmpl (str) {
|
743
|
+
var
|
744
|
+
qstr = [],
|
745
|
+
expr,
|
746
|
+
parts = brackets.split(str.replace(/\u2057/g, '"'), 1)
|
322
747
|
|
323
|
-
|
324
|
-
|
748
|
+
if (parts.length > 2 || parts[0]) {
|
749
|
+
var i, j, list = []
|
325
750
|
|
326
|
-
|
327
|
-
// e.g.: { show: isOpen(), done: item.done } -> "show done"
|
328
|
-
'[' +
|
751
|
+
for (i = j = 0; i < parts.length; ++i) {
|
329
752
|
|
330
|
-
|
331
|
-
extract(s,
|
753
|
+
expr = parts[i]
|
332
754
|
|
333
|
-
|
334
|
-
/["' ]*[\w- ]+["' ]*:/,
|
755
|
+
if (expr && (expr = i & 1 ?
|
335
756
|
|
336
|
-
|
337
|
-
/,(?=["' ]*[\w- ]+["' ]*:)|}|$/
|
338
|
-
).map(function(pair) {
|
757
|
+
_parseExpr(expr, 1, qstr) :
|
339
758
|
|
340
|
-
|
341
|
-
|
759
|
+
'"' + expr
|
760
|
+
.replace(/\\/g, '\\\\')
|
761
|
+
.replace(/\r\n?|\n/g, '\\n')
|
762
|
+
.replace(/"/g, '\\"') +
|
763
|
+
'"'
|
342
764
|
|
343
|
-
|
344
|
-
return v.replace(/[^&|=!><]+/g, wrap) + '?"' + k + '":"",'
|
765
|
+
)) list[j++] = expr
|
345
766
|
|
346
|
-
|
767
|
+
}
|
347
768
|
|
348
|
-
|
769
|
+
expr = j < 2 ? list[0] :
|
770
|
+
'[' + list.join(',') + '].join("")'
|
349
771
|
|
350
|
-
|
772
|
+
} else {
|
351
773
|
|
352
|
-
|
353
|
-
|
774
|
+
expr = _parseExpr(parts[1], 0, qstr)
|
775
|
+
}
|
354
776
|
|
777
|
+
if (qstr[0])
|
778
|
+
expr = expr.replace(RE_QBMARK, function (_, pos) {
|
779
|
+
return qstr[pos]
|
780
|
+
.replace(/\r/g, '\\r')
|
781
|
+
.replace(/\n/g, '\\n')
|
782
|
+
})
|
783
|
+
|
784
|
+
return expr
|
355
785
|
}
|
356
786
|
|
787
|
+
var
|
788
|
+
RE_BREND = {
|
789
|
+
'(': /[()]/g,
|
790
|
+
'[': /[[\]]/g,
|
791
|
+
'{': /[{}]/g
|
792
|
+
},
|
793
|
+
CS_IDENT = /^(?:(-?[_A-Za-z\xA0-\xFF][-\w\xA0-\xFF]*)|\x01(\d+)~):/
|
357
794
|
|
358
|
-
|
795
|
+
function _parseExpr (expr, asText, qstr) {
|
359
796
|
|
360
|
-
|
361
|
-
s = s.trim()
|
362
|
-
return !s ? '' : '(function(v){try{v=' +
|
797
|
+
if (expr[0] === '=') expr = expr.slice(1)
|
363
798
|
|
364
|
-
|
365
|
-
|
799
|
+
expr = expr
|
800
|
+
.replace(RE_QBLOCK, function (s, div) {
|
801
|
+
return s.length > 2 && !div ? '\x01' + (qstr.push(s) - 1) + '~' : s
|
802
|
+
})
|
803
|
+
.replace(/\s+/g, ' ').trim()
|
804
|
+
.replace(/\ ?([[\({},?\.:])\ ?/g, '$1')
|
366
805
|
|
367
|
-
|
368
|
-
|
369
|
-
|
806
|
+
if (expr) {
|
807
|
+
var
|
808
|
+
list = [],
|
809
|
+
cnt = 0,
|
810
|
+
match
|
370
811
|
|
812
|
+
while (expr &&
|
813
|
+
(match = expr.match(CS_IDENT)) &&
|
814
|
+
!match.index
|
815
|
+
) {
|
816
|
+
var
|
817
|
+
key,
|
818
|
+
jsb,
|
819
|
+
re = /,|([[{(])|$/g
|
371
820
|
|
372
|
-
|
821
|
+
expr = RegExp.rightContext
|
822
|
+
key = match[2] ? qstr[match[2]].slice(1, -1).trim().replace(/\s+/g, ' ') : match[1]
|
373
823
|
|
374
|
-
|
375
|
-
var parts = []
|
376
|
-
substrings.map(function(sub, i) {
|
824
|
+
while (jsb = (match = re.exec(expr))[1]) skipBraces(jsb, re)
|
377
825
|
|
378
|
-
|
379
|
-
|
380
|
-
parts.push(str.slice(0, i), sub)
|
381
|
-
str = str.slice(i + sub.length)
|
382
|
-
})
|
383
|
-
if (str) parts.push(str)
|
826
|
+
jsb = expr.slice(0, match.index)
|
827
|
+
expr = RegExp.rightContext
|
384
828
|
|
385
|
-
|
386
|
-
|
829
|
+
list[cnt++] = _wrapExpr(jsb, 1, key)
|
830
|
+
}
|
831
|
+
|
832
|
+
expr = !cnt ? _wrapExpr(expr, asText) :
|
833
|
+
cnt > 1 ? '[' + list.join(',') + '].join(" ").trim()' : list[0]
|
834
|
+
}
|
835
|
+
return expr
|
836
|
+
|
837
|
+
function skipBraces (ch, re) {
|
838
|
+
var
|
839
|
+
mm,
|
840
|
+
lv = 1,
|
841
|
+
ir = RE_BREND[ch]
|
842
|
+
|
843
|
+
ir.lastIndex = re.lastIndex
|
844
|
+
while (mm = ir.exec(expr)) {
|
845
|
+
if (mm[0] === ch) ++lv
|
846
|
+
else if (!--lv) break
|
847
|
+
}
|
848
|
+
re.lastIndex = lv ? expr.length : ir.lastIndex
|
849
|
+
}
|
387
850
|
}
|
388
851
|
|
852
|
+
// istanbul ignore next: not both
|
853
|
+
var
|
854
|
+
JS_CONTEXT = '"in this?this:' + (typeof window !== 'object' ? 'global' : 'window') + ').',
|
855
|
+
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
|
+
JS_NOPROPS = /^(?=(\.[$\w]+))\1(?:[^.[(]|$)/
|
389
857
|
|
390
|
-
|
858
|
+
function _wrapExpr (expr, asText, key) {
|
859
|
+
var tb
|
391
860
|
|
392
|
-
|
861
|
+
expr = expr.replace(JS_VARNAME, function (match, p, mvar, pos, s) {
|
862
|
+
if (mvar) {
|
863
|
+
pos = tb ? 0 : pos + match.length
|
393
864
|
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
865
|
+
if (mvar !== 'this' && mvar !== 'global' && mvar !== 'window') {
|
866
|
+
match = p + '("' + mvar + JS_CONTEXT + mvar
|
867
|
+
if (pos) tb = (s = s[pos]) === '.' || s === '(' || s === '['
|
868
|
+
} else if (pos) {
|
869
|
+
tb = !JS_NOPROPS.test(s.slice(pos))
|
870
|
+
}
|
871
|
+
}
|
872
|
+
return match
|
873
|
+
})
|
398
874
|
|
399
|
-
|
875
|
+
if (tb) {
|
876
|
+
expr = 'try{return ' + expr + '}catch(e){E(e,this)}'
|
877
|
+
}
|
400
878
|
|
401
|
-
|
402
|
-
if (!level && open) start = pos
|
879
|
+
if (key) {
|
403
880
|
|
404
|
-
|
405
|
-
|
881
|
+
expr = (tb ?
|
882
|
+
'function(){' + expr + '}.call(this)' : '(' + expr + ')'
|
883
|
+
) + '?"' + key + '":""'
|
406
884
|
|
407
|
-
|
408
|
-
if (!level && close != null) matches.push(str.slice(start, pos + close.length))
|
885
|
+
} else if (asText) {
|
409
886
|
|
410
|
-
|
887
|
+
expr = 'function(v){' + (tb ?
|
888
|
+
expr.replace('return ', 'v=') : 'v=(' + expr + ')'
|
889
|
+
) + ';return v||v===0?v:""}.call(this)'
|
890
|
+
}
|
411
891
|
|
412
|
-
return
|
892
|
+
return expr
|
413
893
|
}
|
414
894
|
|
895
|
+
// istanbul ignore next: compatibility fix for beta versions
|
896
|
+
_tmpl.parse = function (s) { return s }
|
897
|
+
|
898
|
+
_tmpl.version = brackets.version = 'v2.3.21'
|
899
|
+
|
900
|
+
return _tmpl
|
901
|
+
|
415
902
|
})()
|
416
903
|
|
417
904
|
/*
|
418
905
|
lib/browser/tag/mkdom.js
|
419
906
|
|
420
|
-
Includes hacks needed for the Internet Explorer version 9 and
|
421
|
-
|
907
|
+
Includes hacks needed for the Internet Explorer version 9 and below
|
908
|
+
See: http://kangax.github.io/compat-table/es5/#ie8
|
909
|
+
http://codeplanet.io/dropping-ie8/
|
422
910
|
*/
|
423
|
-
// http://kangax.github.io/compat-table/es5/#ie8
|
424
|
-
// http://codeplanet.io/dropping-ie8/
|
425
|
-
|
426
911
|
var mkdom = (function (checkIE) {
|
427
912
|
|
428
|
-
var
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
'tbody': 'table',
|
433
|
-
'col': 'colgroup'
|
434
|
-
},
|
435
|
-
GENERIC = 'div'
|
913
|
+
var
|
914
|
+
reToSrc = /<yield\s+to=(['"])?@\1\s*>([\S\s]+?)<\/yield\s*>/.source,
|
915
|
+
rootEls = { tr: 'tbody', th: 'tr', td: 'tr', col: 'colgroup' },
|
916
|
+
GENERIC = 'div'
|
436
917
|
|
437
918
|
checkIE = checkIE && checkIE < 10
|
919
|
+
var tblTags = checkIE
|
920
|
+
? SPECIAL_TAGS_REGEX : /^(?:t(?:body|head|foot|[rhd])|caption|col(?:group)?)$/
|
438
921
|
|
439
922
|
// creates any dom element in a div, table, or colgroup container
|
440
|
-
function _mkdom(html) {
|
923
|
+
function _mkdom(templ, html) {
|
441
924
|
|
442
|
-
var match =
|
443
|
-
|
444
|
-
|
445
|
-
el = mkEl(rootTag)
|
925
|
+
var match = templ && templ.match(/^\s*<([-\w]+)/),
|
926
|
+
tagName = match && match[1].toLowerCase(),
|
927
|
+
el = mkEl(GENERIC)
|
446
928
|
|
447
|
-
|
929
|
+
// replace all the yield tags with the tag inner html
|
930
|
+
templ = replaceYield(templ, html || '')
|
448
931
|
|
449
|
-
|
450
|
-
|
932
|
+
/* istanbul ignore next */
|
933
|
+
//if ((checkIE || !startsWith(tagName, 'opt')) && SPECIAL_TAGS_REGEX.test(tagName))
|
934
|
+
if (tblTags.test(tagName))
|
935
|
+
el = specialTags(el, templ, tagName)
|
451
936
|
else
|
452
|
-
el.innerHTML =
|
937
|
+
el.innerHTML = templ
|
938
|
+
|
939
|
+
el.stub = true
|
453
940
|
|
454
941
|
return el
|
455
942
|
}
|
456
943
|
|
457
|
-
// creates
|
458
|
-
|
459
|
-
function
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
944
|
+
// creates the root element for table and select child elements
|
945
|
+
// tr/th/td/thead/tfoot/tbody/caption/col/colgroup/option/optgroup
|
946
|
+
function specialTags(el, templ, tagName) {
|
947
|
+
var
|
948
|
+
select = tagName[0] === 'o',
|
949
|
+
parent = select ? 'select>' : 'table>'
|
950
|
+
|
951
|
+
// trim() is important here, this ensures we don't have artifacts,
|
952
|
+
// so we can check if we have only one element inside the parent
|
953
|
+
el.innerHTML = '<' + parent + templ.trim() + '</' + parent
|
954
|
+
parent = el.firstChild
|
955
|
+
|
956
|
+
// returns the immediate parent if tr/th/td/col is the only element, if not
|
957
|
+
// returns the whole tree, as this can include additional elements
|
958
|
+
if (select) {
|
959
|
+
parent.selectedIndex = -1 // for IE9, compatible w/current riot behavior
|
960
|
+
} else {
|
961
|
+
var tname = rootEls[tagName]
|
962
|
+
if (tname && parent.children.length === 1) parent = $(tname, parent)
|
963
|
+
}
|
964
|
+
return parent
|
965
|
+
}
|
466
966
|
|
467
|
-
|
468
|
-
|
469
|
-
|
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
|
+
*/
|
974
|
+
function replaceYield(templ, html) {
|
975
|
+
// do nothing if no yield
|
976
|
+
if (!/<yield\b/i.test(templ)) return templ
|
977
|
+
|
978
|
+
// 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
|
+
})
|
470
986
|
|
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)
|
471
989
|
}
|
472
|
-
// end ie9elem()
|
473
990
|
|
474
991
|
return _mkdom
|
475
992
|
|
476
993
|
})(IE_VERSION)
|
477
994
|
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
}
|
484
|
-
|
995
|
+
/**
|
996
|
+
* Convert the item looped into an object used to extend the child tag properties
|
997
|
+
* @param { Object } expr - object containing the keys used to extend the children tags
|
998
|
+
* @param { * } key - value to assign to the new object returned
|
999
|
+
* @param { * } val - value containing the position of the item in the array
|
1000
|
+
* @returns { Object } - new object containing the values of the original item
|
1001
|
+
*
|
1002
|
+
* The variables 'key' and 'val' are arbitrary.
|
1003
|
+
* They depend on the collection type looped (Array, Object)
|
1004
|
+
* and on the expression used on the each tag
|
1005
|
+
*
|
1006
|
+
*/
|
485
1007
|
function mkitem(expr, key, val) {
|
486
1008
|
var item = {}
|
487
1009
|
item[expr.key] = key
|
@@ -489,114 +1011,305 @@ function mkitem(expr, key, val) {
|
|
489
1011
|
return item
|
490
1012
|
}
|
491
1013
|
|
1014
|
+
/**
|
1015
|
+
* Unmount the redundant tags
|
1016
|
+
* @param { Array } items - array containing the current items to loop
|
1017
|
+
* @param { Array } tags - array containing all the children tags
|
1018
|
+
*/
|
1019
|
+
function unmountRedundant(items, tags) {
|
1020
|
+
|
1021
|
+
var i = tags.length,
|
1022
|
+
j = items.length,
|
1023
|
+
t
|
1024
|
+
|
1025
|
+
while (i > j) {
|
1026
|
+
t = tags[--i]
|
1027
|
+
tags.splice(i, 1)
|
1028
|
+
t.unmount()
|
1029
|
+
}
|
1030
|
+
}
|
492
1031
|
|
493
|
-
|
1032
|
+
/**
|
1033
|
+
* Move the nested custom tags in non custom loop tags
|
1034
|
+
* @param { Object } child - non custom loop tag
|
1035
|
+
* @param { Number } i - current position of the loop tag
|
1036
|
+
*/
|
1037
|
+
function moveNestedTags(child, i) {
|
1038
|
+
Object.keys(child.tags).forEach(function(tagName) {
|
1039
|
+
var tag = child.tags[tagName]
|
1040
|
+
if (isArray(tag))
|
1041
|
+
each(tag, function (t) {
|
1042
|
+
moveChildTag(t, tagName, i)
|
1043
|
+
})
|
1044
|
+
else
|
1045
|
+
moveChildTag(tag, tagName, i)
|
1046
|
+
})
|
1047
|
+
}
|
1048
|
+
|
1049
|
+
/**
|
1050
|
+
* Adds the elements for a virtual tag
|
1051
|
+
* @param { Tag } tag - the tag whose root's children will be inserted or appended
|
1052
|
+
* @param { Node } src - the node that will do the inserting or appending
|
1053
|
+
* @param { Tag } target - only if inserting, insert before this tag's first child
|
1054
|
+
*/
|
1055
|
+
function addVirtual(tag, src, target) {
|
1056
|
+
var el = tag._root, sib
|
1057
|
+
tag._virts = []
|
1058
|
+
while (el) {
|
1059
|
+
sib = el.nextSibling
|
1060
|
+
if (target)
|
1061
|
+
src.insertBefore(el, target._root)
|
1062
|
+
else
|
1063
|
+
src.appendChild(el)
|
1064
|
+
|
1065
|
+
tag._virts.push(el) // hold for unmounting
|
1066
|
+
el = sib
|
1067
|
+
}
|
1068
|
+
}
|
1069
|
+
|
1070
|
+
/**
|
1071
|
+
* Move virtual tag and all child nodes
|
1072
|
+
* @param { Tag } tag - first child reference used to start move
|
1073
|
+
* @param { Node } src - the node that will do the inserting
|
1074
|
+
* @param { Tag } target - insert before this tag's first child
|
1075
|
+
* @param { Number } len - how many child nodes to move
|
1076
|
+
*/
|
1077
|
+
function moveVirtual(tag, src, target, len) {
|
1078
|
+
var el = tag._root, sib, i = 0
|
1079
|
+
for (; i < len; i++) {
|
1080
|
+
sib = el.nextSibling
|
1081
|
+
src.insertBefore(el, target._root)
|
1082
|
+
el = sib
|
1083
|
+
}
|
1084
|
+
}
|
1085
|
+
|
1086
|
+
|
1087
|
+
/**
|
1088
|
+
* Manage tags having the 'each'
|
1089
|
+
* @param { Object } dom - DOM node we need to loop
|
1090
|
+
* @param { Tag } parent - parent tag instance where the dom node is contained
|
1091
|
+
* @param { String } expr - string contained in the 'each' attribute
|
1092
|
+
*/
|
494
1093
|
function _each(dom, parent, expr) {
|
495
1094
|
|
1095
|
+
// remove the each property from the original tag
|
496
1096
|
remAttr(dom, 'each')
|
497
1097
|
|
498
|
-
var
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
1098
|
+
var mustReorder = typeof getAttr(dom, 'no-reorder') !== T_STRING || remAttr(dom, 'no-reorder'),
|
1099
|
+
tagName = getTagName(dom),
|
1100
|
+
impl = __tagImpl[tagName] || { tmpl: dom.outerHTML },
|
1101
|
+
useRoot = SPECIAL_TAGS_REGEX.test(tagName),
|
1102
|
+
root = dom.parentNode,
|
1103
|
+
ref = document.createTextNode(''),
|
1104
|
+
child = getTag(dom),
|
1105
|
+
isOption = /^option$/i.test(tagName), // the option tags must be treated differently
|
1106
|
+
tags = [],
|
1107
|
+
oldItems = [],
|
1108
|
+
hasKeys,
|
1109
|
+
isVirtual = dom.tagName == 'VIRTUAL'
|
1110
|
+
|
1111
|
+
// parse the each expression
|
1112
|
+
expr = tmpl.loopKeys(expr)
|
1113
|
+
|
1114
|
+
// insert a marked where the loop tags will be injected
|
1115
|
+
root.insertBefore(ref, dom)
|
509
1116
|
|
510
|
-
|
1117
|
+
// clean template code
|
1118
|
+
parent.one('before-mount', function () {
|
511
1119
|
|
512
|
-
|
1120
|
+
// remove the original DOM node
|
1121
|
+
dom.parentNode.removeChild(dom)
|
1122
|
+
if (root.stub) root = parent.root
|
513
1123
|
|
514
|
-
|
515
|
-
|
516
|
-
.
|
517
|
-
|
518
|
-
|
519
|
-
dom.parentNode.removeChild(dom)
|
520
|
-
})
|
521
|
-
.on('update', function () {
|
522
|
-
var items = tmpl(expr.val, parent)
|
1124
|
+
}).on('update', function () {
|
1125
|
+
// get the new items collection
|
1126
|
+
var items = tmpl(expr.val, parent),
|
1127
|
+
// create a fragment to hold the new DOM nodes to inject in the parent tag
|
1128
|
+
frag = document.createDocumentFragment()
|
523
1129
|
|
524
|
-
// object loop. any changes cause full redraw
|
525
|
-
if (!isArray(items)) {
|
526
1130
|
|
527
|
-
checksum = items ? JSON.stringify(items) : ''
|
528
1131
|
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
1132
|
+
// object loop. any changes cause full redraw
|
1133
|
+
if (!isArray(items)) {
|
1134
|
+
hasKeys = items || false
|
1135
|
+
items = hasKeys ?
|
1136
|
+
Object.keys(items).map(function (key) {
|
1137
|
+
return mkitem(expr, key, items[key])
|
1138
|
+
}) : []
|
1139
|
+
}
|
534
1140
|
|
535
|
-
|
536
|
-
|
537
|
-
|
1141
|
+
// loop all the new items
|
1142
|
+
items.forEach(function(item, i) {
|
1143
|
+
// reorder only if the items are objects
|
1144
|
+
var _mustReorder = mustReorder && item instanceof Object,
|
1145
|
+
oldPos = oldItems.indexOf(item),
|
1146
|
+
pos = ~oldPos && _mustReorder ? oldPos : i,
|
1147
|
+
// does a tag exist in this position?
|
1148
|
+
tag = tags[pos]
|
1149
|
+
|
1150
|
+
item = !hasKeys && expr.key ? mkitem(expr, item, i) : item
|
1151
|
+
|
1152
|
+
// new tag
|
1153
|
+
if (
|
1154
|
+
!_mustReorder && !tag // with no-reorder we just update the old tags
|
1155
|
+
||
|
1156
|
+
_mustReorder && !~oldPos || !tag // by default we always try to reorder the DOM elements
|
1157
|
+
) {
|
1158
|
+
|
1159
|
+
tag = new Tag(impl, {
|
1160
|
+
parent: parent,
|
1161
|
+
isLoop: true,
|
1162
|
+
hasImpl: !!__tagImpl[tagName],
|
1163
|
+
root: useRoot ? root : dom.cloneNode(),
|
1164
|
+
item: item
|
1165
|
+
}, dom.innerHTML)
|
1166
|
+
|
1167
|
+
tag.mount()
|
1168
|
+
if (isVirtual) tag._root = tag.root.firstChild // save reference for further moves or inserts
|
1169
|
+
// this tag must be appended
|
1170
|
+
if (i == tags.length) {
|
1171
|
+
if (isVirtual)
|
1172
|
+
addVirtual(tag, frag)
|
1173
|
+
else frag.appendChild(tag.root)
|
1174
|
+
}
|
1175
|
+
// this tag must be insert
|
1176
|
+
else {
|
1177
|
+
if (isVirtual)
|
1178
|
+
addVirtual(tag, root, tags[i])
|
1179
|
+
else root.insertBefore(tag.root, tags[i].root)
|
1180
|
+
oldItems.splice(i, 0, item)
|
1181
|
+
}
|
538
1182
|
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
1183
|
+
tags.splice(i, 0, tag)
|
1184
|
+
pos = i // handled here so no move
|
1185
|
+
} else tag.update(item)
|
1186
|
+
|
1187
|
+
// reorder the tag if it's not located in its previous position
|
1188
|
+
if (pos !== i && _mustReorder) {
|
1189
|
+
// update the DOM
|
1190
|
+
if (isVirtual)
|
1191
|
+
moveVirtual(tag, root, tags[i], dom.childNodes.length)
|
1192
|
+
else root.insertBefore(tag.root, tags[i].root)
|
1193
|
+
// update the position attribute if it exists
|
1194
|
+
if (expr.pos)
|
1195
|
+
tag[expr.pos] = i
|
1196
|
+
// move the old tag instance
|
1197
|
+
tags.splice(i, 0, tags.splice(pos, 1)[0])
|
1198
|
+
// move the old item
|
1199
|
+
oldItems.splice(i, 0, oldItems.splice(pos, 1)[0])
|
1200
|
+
// if the loop tags are not custom
|
1201
|
+
// we need to move all their custom tags into the right position
|
1202
|
+
if (!child && tag.tags) moveNestedTags(tag, i)
|
543
1203
|
}
|
544
1204
|
|
545
|
-
|
546
|
-
|
1205
|
+
// cache the original item to use it in the events bound to this node
|
1206
|
+
// and its children
|
1207
|
+
tag._item = item
|
1208
|
+
// cache the real parent tag internally
|
1209
|
+
defineProperty(tag, '_parent', parent)
|
547
1210
|
|
548
|
-
|
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()
|
1211
|
+
})
|
558
1212
|
|
559
|
-
|
560
|
-
|
561
|
-
tags[i].update(_item)
|
1213
|
+
// remove the redundant tags
|
1214
|
+
unmountRedundant(items, tags)
|
562
1215
|
|
563
|
-
|
1216
|
+
// insert the new nodes
|
1217
|
+
if (isOption) root.appendChild(frag)
|
1218
|
+
else root.insertBefore(frag, ref)
|
564
1219
|
|
565
|
-
|
1220
|
+
// set the 'tags' property of the parent tag
|
1221
|
+
// if child is 'undefined' it means that we don't need to set this property
|
1222
|
+
// for example:
|
1223
|
+
// we don't need store the `myTag.tags['div']` property if we are looping a div tag
|
1224
|
+
// but we need to track the `myTag.tags['child']` property looping a custom child node named `child`
|
1225
|
+
if (child) parent.tags[tagName] = tags
|
566
1226
|
|
567
|
-
|
1227
|
+
// clone the items array
|
1228
|
+
oldItems = items.slice()
|
568
1229
|
|
569
|
-
|
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
|
-
})
|
1230
|
+
})
|
582
1231
|
|
583
1232
|
}
|
1233
|
+
/**
|
1234
|
+
* Object that will be used to inject and manage the css of every tag instance
|
1235
|
+
*/
|
1236
|
+
var styleManager = (function(_riot) {
|
1237
|
+
|
1238
|
+
if (!window) return { // skip injection on the server
|
1239
|
+
add: function () {},
|
1240
|
+
inject: function () {}
|
1241
|
+
}
|
1242
|
+
|
1243
|
+
var styleNode = (function () {
|
1244
|
+
// create a new style element with the correct type
|
1245
|
+
var newNode = mkEl('style')
|
1246
|
+
setAttr(newNode, 'type', 'text/css')
|
1247
|
+
|
1248
|
+
// replace any user node or insert the new one into the head
|
1249
|
+
var userNode = $('style[type=riot]')
|
1250
|
+
if (userNode) {
|
1251
|
+
if (userNode.id) newNode.id = userNode.id
|
1252
|
+
userNode.parentNode.replaceChild(newNode, userNode)
|
1253
|
+
}
|
1254
|
+
else document.getElementsByTagName('head')[0].appendChild(newNode)
|
584
1255
|
|
1256
|
+
return newNode
|
1257
|
+
})()
|
585
1258
|
|
586
|
-
|
1259
|
+
// Create cache and shortcut to the correct property
|
1260
|
+
var cssTextProp = styleNode.styleSheet,
|
1261
|
+
stylesToInject = ''
|
1262
|
+
|
1263
|
+
// Expose the style node in a non-modificable property
|
1264
|
+
Object.defineProperty(_riot, 'styleNode', {
|
1265
|
+
value: styleNode,
|
1266
|
+
writable: true
|
1267
|
+
})
|
1268
|
+
|
1269
|
+
/**
|
1270
|
+
* Public api
|
1271
|
+
*/
|
1272
|
+
return {
|
1273
|
+
/**
|
1274
|
+
* Save a tag style to be later injected into DOM
|
1275
|
+
* @param { String } css [description]
|
1276
|
+
*/
|
1277
|
+
add: function(css) {
|
1278
|
+
stylesToInject += css
|
1279
|
+
},
|
1280
|
+
/**
|
1281
|
+
* Inject all previously saved tag styles into DOM
|
1282
|
+
* innerHTML seems slow: http://jsperf.com/riot-insert-style
|
1283
|
+
*/
|
1284
|
+
inject: function() {
|
1285
|
+
if (stylesToInject) {
|
1286
|
+
if (cssTextProp) cssTextProp.cssText += stylesToInject
|
1287
|
+
else styleNode.innerHTML += stylesToInject
|
1288
|
+
stylesToInject = ''
|
1289
|
+
}
|
1290
|
+
}
|
1291
|
+
}
|
1292
|
+
|
1293
|
+
})(riot)
|
1294
|
+
|
1295
|
+
|
1296
|
+
function parseNamedElements(root, tag, childTags, forceParsingNamed) {
|
587
1297
|
|
588
1298
|
walk(root, function(dom) {
|
589
1299
|
if (dom.nodeType == 1) {
|
590
|
-
dom.isLoop = dom.isLoop ||
|
1300
|
+
dom.isLoop = dom.isLoop ||
|
1301
|
+
(dom.parentNode && dom.parentNode.isLoop || getAttr(dom, 'each'))
|
1302
|
+
? 1 : 0
|
591
1303
|
|
592
1304
|
// custom child tag
|
593
|
-
|
1305
|
+
if (childTags) {
|
1306
|
+
var child = getTag(dom)
|
594
1307
|
|
595
|
-
|
596
|
-
|
1308
|
+
if (child && !dom.isLoop)
|
1309
|
+
childTags.push(initChildTag(child, {root: dom, parent: tag}, dom.innerHTML, tag))
|
597
1310
|
}
|
598
1311
|
|
599
|
-
if (!dom.isLoop)
|
1312
|
+
if (!dom.isLoop || forceParsingNamed)
|
600
1313
|
setNamed(dom, tag, [])
|
601
1314
|
}
|
602
1315
|
|
@@ -607,14 +1320,14 @@ function parseNamedElements(root, tag, childTags) {
|
|
607
1320
|
function parseExpressions(root, tag, expressions) {
|
608
1321
|
|
609
1322
|
function addExpr(dom, val, extra) {
|
610
|
-
if (
|
611
|
-
|
612
|
-
expressions.push(extend(expr, extra))
|
1323
|
+
if (tmpl.hasExpr(val)) {
|
1324
|
+
expressions.push(extend({ dom: dom, expr: val }, extra))
|
613
1325
|
}
|
614
1326
|
}
|
615
1327
|
|
616
1328
|
walk(root, function(dom) {
|
617
|
-
var type = dom.nodeType
|
1329
|
+
var type = dom.nodeType,
|
1330
|
+
attr
|
618
1331
|
|
619
1332
|
// text node
|
620
1333
|
if (type == 3 && dom.parentNode.tagName != 'STYLE') addExpr(dom, dom.nodeValue)
|
@@ -623,7 +1336,7 @@ function parseExpressions(root, tag, expressions) {
|
|
623
1336
|
/* element */
|
624
1337
|
|
625
1338
|
// loop
|
626
|
-
|
1339
|
+
attr = getAttr(dom, 'each')
|
627
1340
|
|
628
1341
|
if (attr) { _each(dom, tag, attr); return false }
|
629
1342
|
|
@@ -646,23 +1359,21 @@ function parseExpressions(root, tag, expressions) {
|
|
646
1359
|
function Tag(impl, conf, innerHTML) {
|
647
1360
|
|
648
1361
|
var self = riot.observable(this),
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
if (fn && root._tag)
|
664
|
-
root._tag.unmount(true)
|
665
|
-
}
|
1362
|
+
opts = inherit(conf.opts) || {},
|
1363
|
+
parent = conf.parent,
|
1364
|
+
isLoop = conf.isLoop,
|
1365
|
+
hasImpl = conf.hasImpl,
|
1366
|
+
item = cleanUpData(conf.item),
|
1367
|
+
expressions = [],
|
1368
|
+
childTags = [],
|
1369
|
+
root = conf.root,
|
1370
|
+
fn = impl.fn,
|
1371
|
+
tagName = root.tagName.toLowerCase(),
|
1372
|
+
attr = {},
|
1373
|
+
propsInSyncWithParent = [],
|
1374
|
+
dom
|
1375
|
+
|
1376
|
+
if (fn && root._tag) root._tag.unmount(true)
|
666
1377
|
|
667
1378
|
// not yet mounted
|
668
1379
|
this.isMounted = false
|
@@ -674,7 +1385,7 @@ function Tag(impl, conf, innerHTML) {
|
|
674
1385
|
|
675
1386
|
// create a unique id to this tag
|
676
1387
|
// it could be handy to use it also to improve the virtual dom rendering speed
|
677
|
-
this
|
1388
|
+
defineProperty(this, '_riot_id', ++__uid) // base 1 allows test !t._riot_id
|
678
1389
|
|
679
1390
|
extend(this, { parent: parent, root: root, opts: opts, tags: {} }, item)
|
680
1391
|
|
@@ -682,12 +1393,10 @@ function Tag(impl, conf, innerHTML) {
|
|
682
1393
|
each(root.attributes, function(el) {
|
683
1394
|
var val = el.value
|
684
1395
|
// remember attributes with expressions only
|
685
|
-
if (
|
1396
|
+
if (tmpl.hasExpr(val)) attr[el.name] = val
|
686
1397
|
})
|
687
1398
|
|
688
|
-
|
689
|
-
// replace all the yield tags with the tag inner html
|
690
|
-
dom.innerHTML = replaceYield(dom.innerHTML, innerHTML)
|
1399
|
+
dom = mkdom(impl.tmpl, innerHTML)
|
691
1400
|
|
692
1401
|
// options
|
693
1402
|
function updateOpts() {
|
@@ -695,17 +1404,18 @@ function Tag(impl, conf, innerHTML) {
|
|
695
1404
|
|
696
1405
|
// update opts from current DOM attributes
|
697
1406
|
each(root.attributes, function(el) {
|
698
|
-
|
1407
|
+
var val = el.value
|
1408
|
+
opts[toCamel(el.name)] = tmpl.hasExpr(val) ? tmpl(val, ctx) : val
|
699
1409
|
})
|
700
1410
|
// recover those with expressions
|
701
1411
|
each(Object.keys(attr), function(name) {
|
702
|
-
opts[name] = tmpl(attr[name], ctx)
|
1412
|
+
opts[toCamel(name)] = tmpl(attr[name], ctx)
|
703
1413
|
})
|
704
1414
|
}
|
705
1415
|
|
706
1416
|
function normalizeData(data) {
|
707
1417
|
for (var key in item) {
|
708
|
-
if (typeof self[key] !== T_UNDEF)
|
1418
|
+
if (typeof self[key] !== T_UNDEF && isWritable(self, key))
|
709
1419
|
self[key] = data[key]
|
710
1420
|
}
|
711
1421
|
}
|
@@ -714,7 +1424,7 @@ function Tag(impl, conf, innerHTML) {
|
|
714
1424
|
if (!self.parent || !isLoop) return
|
715
1425
|
each(Object.keys(self.parent), function(k) {
|
716
1426
|
// some properties must be always in sync with the parent tag
|
717
|
-
var mustSync =
|
1427
|
+
var mustSync = !contains(RESERVED_WORDS_BLACKLIST, k) && contains(propsInSyncWithParent, k)
|
718
1428
|
if (typeof self[k] === T_UNDEF || mustSync) {
|
719
1429
|
// track the property to keep in sync
|
720
1430
|
// so we can keep it updated
|
@@ -724,7 +1434,8 @@ function Tag(impl, conf, innerHTML) {
|
|
724
1434
|
})
|
725
1435
|
}
|
726
1436
|
|
727
|
-
this
|
1437
|
+
defineProperty(this, 'update', function(data) {
|
1438
|
+
|
728
1439
|
// make sure the data passed will not override
|
729
1440
|
// the component core methods
|
730
1441
|
data = cleanUpData(data)
|
@@ -739,23 +1450,44 @@ function Tag(impl, conf, innerHTML) {
|
|
739
1450
|
updateOpts()
|
740
1451
|
self.trigger('update', data)
|
741
1452
|
update(expressions, self)
|
742
|
-
|
743
|
-
|
1453
|
+
// the updated event will be triggered
|
1454
|
+
// once the DOM will be ready and all the reflows are completed
|
1455
|
+
// this is useful if you want to get the "real" root properties
|
1456
|
+
// 4 ex: root.offsetWidth ...
|
1457
|
+
rAF(function() { self.trigger('updated') })
|
1458
|
+
return this
|
1459
|
+
})
|
744
1460
|
|
745
|
-
this
|
1461
|
+
defineProperty(this, 'mixin', function() {
|
746
1462
|
each(arguments, function(mix) {
|
1463
|
+
var instance
|
1464
|
+
|
747
1465
|
mix = typeof mix === T_STRING ? riot.mixin(mix) : mix
|
748
|
-
|
1466
|
+
|
1467
|
+
// check if the mixin is a function
|
1468
|
+
if (isFunction(mix)) {
|
1469
|
+
// create the new mixin instance
|
1470
|
+
instance = new mix()
|
1471
|
+
// save the prototype to loop it afterwards
|
1472
|
+
mix = mix.prototype
|
1473
|
+
} else instance = mix
|
1474
|
+
|
1475
|
+
// loop the keys in the function prototype or the all object keys
|
1476
|
+
each(Object.getOwnPropertyNames(mix), function(key) {
|
749
1477
|
// bind methods to self
|
750
1478
|
if (key != 'init')
|
751
|
-
self[key] = isFunction(
|
1479
|
+
self[key] = isFunction(instance[key]) ?
|
1480
|
+
instance[key].bind(self) :
|
1481
|
+
instance[key]
|
752
1482
|
})
|
1483
|
+
|
753
1484
|
// init method will be called automatically
|
754
|
-
if (
|
1485
|
+
if (instance.init) instance.init.bind(self)()
|
755
1486
|
})
|
756
|
-
|
1487
|
+
return this
|
1488
|
+
})
|
757
1489
|
|
758
|
-
this
|
1490
|
+
defineProperty(this, 'mount', function() {
|
759
1491
|
|
760
1492
|
updateOpts()
|
761
1493
|
|
@@ -771,14 +1503,14 @@ function Tag(impl, conf, innerHTML) {
|
|
771
1503
|
// update the root adding custom attributes coming from the compiler
|
772
1504
|
// it fixes also #1087
|
773
1505
|
if (impl.attrs || hasImpl) {
|
774
|
-
walkAttributes(impl.attrs, function (k, v) { root
|
1506
|
+
walkAttributes(impl.attrs, function (k, v) { setAttr(root, k, v) })
|
775
1507
|
parseExpressions(self.root, self, expressions)
|
776
1508
|
}
|
777
1509
|
|
778
1510
|
if (!self.parent || isLoop) self.update(item)
|
779
1511
|
|
780
1512
|
// internal use only, fixes #403
|
781
|
-
self.trigger('
|
1513
|
+
self.trigger('before-mount')
|
782
1514
|
|
783
1515
|
if (isLoop && !hasImpl) {
|
784
1516
|
// update the root attribute for the looped elements
|
@@ -788,6 +1520,12 @@ function Tag(impl, conf, innerHTML) {
|
|
788
1520
|
while (dom.firstChild) root.appendChild(dom.firstChild)
|
789
1521
|
if (root.stub) self.root = root = parent.root
|
790
1522
|
}
|
1523
|
+
|
1524
|
+
// parse the named dom nodes in the looped child
|
1525
|
+
// adding them to the parent as well
|
1526
|
+
if (isLoop)
|
1527
|
+
parseNamedElements(self.root, self.parent, null, true)
|
1528
|
+
|
791
1529
|
// if it's not a child tag we can trigger its mount event
|
792
1530
|
if (!self.parent || self.parent.isMounted) {
|
793
1531
|
self.isMounted = true
|
@@ -802,13 +1540,26 @@ function Tag(impl, conf, innerHTML) {
|
|
802
1540
|
self.trigger('mount')
|
803
1541
|
}
|
804
1542
|
})
|
805
|
-
}
|
1543
|
+
})
|
806
1544
|
|
807
1545
|
|
808
|
-
this
|
1546
|
+
defineProperty(this, 'unmount', function(keepRootTag) {
|
809
1547
|
var el = root,
|
810
|
-
|
811
|
-
|
1548
|
+
p = el.parentNode,
|
1549
|
+
ptag,
|
1550
|
+
tagIndex = __virtualDom.indexOf(self)
|
1551
|
+
|
1552
|
+
self.trigger('before-unmount')
|
1553
|
+
|
1554
|
+
// remove this tag instance from the global virtualDom variable
|
1555
|
+
if (~tagIndex)
|
1556
|
+
__virtualDom.splice(tagIndex, 1)
|
1557
|
+
|
1558
|
+
if (this._virts) {
|
1559
|
+
each(this._virts, function(v) {
|
1560
|
+
if (v.parentNode) v.parentNode.removeChild(v)
|
1561
|
+
})
|
1562
|
+
}
|
812
1563
|
|
813
1564
|
if (p) {
|
814
1565
|
|
@@ -819,7 +1570,7 @@ function Tag(impl, conf, innerHTML) {
|
|
819
1570
|
// remove this element form the array
|
820
1571
|
if (isArray(ptag.tags[tagName]))
|
821
1572
|
each(ptag.tags[tagName], function(tag, i) {
|
822
|
-
if (tag.
|
1573
|
+
if (tag._riot_id == self._riot_id)
|
823
1574
|
ptag.tags[tagName].splice(i, 1)
|
824
1575
|
})
|
825
1576
|
else
|
@@ -834,17 +1585,17 @@ function Tag(impl, conf, innerHTML) {
|
|
834
1585
|
p.removeChild(el)
|
835
1586
|
else
|
836
1587
|
// the riot-tag attribute isn't needed anymore, remove it
|
837
|
-
p
|
1588
|
+
remAttr(p, 'riot-tag')
|
838
1589
|
}
|
839
1590
|
|
840
1591
|
|
841
1592
|
self.trigger('unmount')
|
842
1593
|
toggle()
|
843
1594
|
self.off('*')
|
844
|
-
|
845
|
-
root._tag
|
1595
|
+
self.isMounted = false
|
1596
|
+
delete root._tag
|
846
1597
|
|
847
|
-
}
|
1598
|
+
})
|
848
1599
|
|
849
1600
|
function toggle(isMount) {
|
850
1601
|
|
@@ -852,46 +1603,48 @@ function Tag(impl, conf, innerHTML) {
|
|
852
1603
|
each(childTags, function(child) { child[isMount ? 'mount' : 'unmount']() })
|
853
1604
|
|
854
1605
|
// listen/unlisten parent (events flow one way from parent to children)
|
855
|
-
if (parent)
|
856
|
-
|
1606
|
+
if (!parent) return
|
1607
|
+
var evt = isMount ? 'on' : 'off'
|
857
1608
|
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
}
|
1609
|
+
// the loop tags will be always in sync with the parent automatically
|
1610
|
+
if (isLoop)
|
1611
|
+
parent[evt]('unmount', self.unmount)
|
1612
|
+
else
|
1613
|
+
parent[evt]('update', self.update)[evt]('unmount', self.unmount)
|
864
1614
|
}
|
865
1615
|
|
866
1616
|
// named elements available for fn
|
867
1617
|
parseNamedElements(dom, this, childTags)
|
868
1618
|
|
869
|
-
|
870
1619
|
}
|
871
|
-
|
1620
|
+
/**
|
1621
|
+
* Attach an event to a DOM node
|
1622
|
+
* @param { String } name - event name
|
1623
|
+
* @param { Function } handler - event callback
|
1624
|
+
* @param { Object } dom - dom node
|
1625
|
+
* @param { Tag } tag - tag instance
|
1626
|
+
*/
|
872
1627
|
function setEventHandler(name, handler, dom, tag) {
|
873
1628
|
|
874
1629
|
dom[name] = function(e) {
|
875
1630
|
|
876
|
-
var
|
877
|
-
|
878
|
-
|
1631
|
+
var ptag = tag._parent,
|
1632
|
+
item = tag._item,
|
1633
|
+
el
|
879
1634
|
|
880
1635
|
if (!item)
|
881
1636
|
while (ptag && !item) {
|
882
1637
|
item = ptag._item
|
883
|
-
ptag = ptag.
|
1638
|
+
ptag = ptag._parent
|
884
1639
|
}
|
885
1640
|
|
886
1641
|
// cross browser event fix
|
887
1642
|
e = e || window.event
|
888
1643
|
|
889
|
-
//
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
if (!e.which) e.which = e.charCode || e.keyCode
|
894
|
-
} catch (ignored) { /**/ }
|
1644
|
+
// override the event properties
|
1645
|
+
if (isWritable(e, 'currentTarget')) e.currentTarget = dom
|
1646
|
+
if (isWritable(e, 'target')) e.target = e.srcElement
|
1647
|
+
if (isWritable(e, 'which')) e.which = e.charCode || e.keyCode
|
895
1648
|
|
896
1649
|
e.item = item
|
897
1650
|
|
@@ -910,22 +1663,32 @@ function setEventHandler(name, handler, dom, tag) {
|
|
910
1663
|
|
911
1664
|
}
|
912
1665
|
|
913
|
-
|
1666
|
+
|
1667
|
+
/**
|
1668
|
+
* Insert a DOM node replacing another one (used by if- attribute)
|
1669
|
+
* @param { Object } root - parent node
|
1670
|
+
* @param { Object } node - node replaced
|
1671
|
+
* @param { Object } before - node added
|
1672
|
+
*/
|
914
1673
|
function insertTo(root, node, before) {
|
915
|
-
if (root)
|
916
|
-
|
917
|
-
|
918
|
-
}
|
1674
|
+
if (!root) return
|
1675
|
+
root.insertBefore(before, node)
|
1676
|
+
root.removeChild(node)
|
919
1677
|
}
|
920
1678
|
|
1679
|
+
/**
|
1680
|
+
* Update the expressions in a Tag instance
|
1681
|
+
* @param { Array } expressions - expression that must be re evaluated
|
1682
|
+
* @param { Tag } tag - tag instance
|
1683
|
+
*/
|
921
1684
|
function update(expressions, tag) {
|
922
1685
|
|
923
1686
|
each(expressions, function(expr, i) {
|
924
1687
|
|
925
1688
|
var dom = expr.dom,
|
926
|
-
|
927
|
-
|
928
|
-
|
1689
|
+
attrName = expr.attr,
|
1690
|
+
value = tmpl(expr.expr, tag),
|
1691
|
+
parent = expr.dom.parentNode
|
929
1692
|
|
930
1693
|
if (expr.bool)
|
931
1694
|
value = value ? attrName : false
|
@@ -934,7 +1697,11 @@ function update(expressions, tag) {
|
|
934
1697
|
|
935
1698
|
// leave out riot- prefixes from strings inside textarea
|
936
1699
|
// fix #815: any value -> string
|
937
|
-
if (parent && parent.tagName == 'TEXTAREA')
|
1700
|
+
if (parent && parent.tagName == 'TEXTAREA') {
|
1701
|
+
value = ('' + value).replace(/riot-/g, '')
|
1702
|
+
// change textarea's value
|
1703
|
+
parent.value = value
|
1704
|
+
}
|
938
1705
|
|
939
1706
|
// no change
|
940
1707
|
if (expr.value === value) return
|
@@ -955,8 +1722,8 @@ function update(expressions, tag) {
|
|
955
1722
|
// if- conditional
|
956
1723
|
} else if (attrName == 'if') {
|
957
1724
|
var stub = expr.stub,
|
958
|
-
|
959
|
-
|
1725
|
+
add = function() { insertTo(stub.parentNode, stub, dom) },
|
1726
|
+
remove = function() { insertTo(dom.parentNode, dom, stub) }
|
960
1727
|
|
961
1728
|
// add to DOM
|
962
1729
|
if (value) {
|
@@ -967,7 +1734,8 @@ function update(expressions, tag) {
|
|
967
1734
|
// maybe we can optimize this avoiding to mount the tag at all
|
968
1735
|
if (!isInStub(dom)) {
|
969
1736
|
walk(dom, function(el) {
|
970
|
-
if (el._tag && !el._tag.isMounted)
|
1737
|
+
if (el._tag && !el._tag.isMounted)
|
1738
|
+
el._tag.isMounted = !!el._tag.trigger('mount')
|
971
1739
|
})
|
972
1740
|
}
|
973
1741
|
}
|
@@ -977,9 +1745,8 @@ function update(expressions, tag) {
|
|
977
1745
|
// if the parentNode is defined we can easily replace the tag
|
978
1746
|
if (dom.parentNode)
|
979
1747
|
remove()
|
980
|
-
else
|
981
1748
|
// otherwise we need to wait the updated event
|
982
|
-
|
1749
|
+
else (tag.parent || tag).one('updated', remove)
|
983
1750
|
|
984
1751
|
dom.inStub = true
|
985
1752
|
}
|
@@ -995,7 +1762,7 @@ function update(expressions, tag) {
|
|
995
1762
|
// <img src="{ expr }">
|
996
1763
|
} else if (startsWith(attrName, RIOT_PREFIX) && attrName != RIOT_TAG) {
|
997
1764
|
if (value)
|
998
|
-
dom
|
1765
|
+
setAttr(dom, attrName.slice(RIOT_PREFIX.length), value)
|
999
1766
|
|
1000
1767
|
} else {
|
1001
1768
|
if (expr.bool) {
|
@@ -1003,65 +1770,168 @@ function update(expressions, tag) {
|
|
1003
1770
|
if (!value) return
|
1004
1771
|
}
|
1005
1772
|
|
1006
|
-
if (typeof value !== T_OBJECT)
|
1773
|
+
if (value === 0 || value && typeof value !== T_OBJECT)
|
1774
|
+
setAttr(dom, attrName, value)
|
1007
1775
|
|
1008
1776
|
}
|
1009
1777
|
|
1010
1778
|
})
|
1011
1779
|
|
1012
1780
|
}
|
1781
|
+
/**
|
1782
|
+
* Specialized function for looping an array-like collection with `each={}`
|
1783
|
+
* @param { Array } els - collection of items
|
1784
|
+
* @param {Function} fn - callback function
|
1785
|
+
* @returns { Array } the array looped
|
1786
|
+
*/
|
1013
1787
|
function each(els, fn) {
|
1014
|
-
|
1788
|
+
var len = els ? els.length : 0
|
1789
|
+
|
1790
|
+
for (var i = 0, el; i < len; i++) {
|
1015
1791
|
el = els[i]
|
1016
|
-
// return false ->
|
1792
|
+
// return false -> current item was removed by fn during the loop
|
1017
1793
|
if (el != null && fn(el, i) === false) i--
|
1018
1794
|
}
|
1019
1795
|
return els
|
1020
1796
|
}
|
1021
1797
|
|
1798
|
+
/**
|
1799
|
+
* Detect if the argument passed is a function
|
1800
|
+
* @param { * } v - whatever you want to pass to this function
|
1801
|
+
* @returns { Boolean } -
|
1802
|
+
*/
|
1022
1803
|
function isFunction(v) {
|
1023
1804
|
return typeof v === T_FUNCTION || false // avoid IE problems
|
1024
1805
|
}
|
1025
1806
|
|
1807
|
+
/**
|
1808
|
+
* Remove any DOM attribute from a node
|
1809
|
+
* @param { Object } dom - DOM node we want to update
|
1810
|
+
* @param { String } name - name of the property we want to remove
|
1811
|
+
*/
|
1026
1812
|
function remAttr(dom, name) {
|
1027
1813
|
dom.removeAttribute(name)
|
1028
1814
|
}
|
1029
1815
|
|
1030
|
-
|
1031
|
-
|
1816
|
+
/**
|
1817
|
+
* Convert a string containing dashes to camel case
|
1818
|
+
* @param { String } string - input string
|
1819
|
+
* @returns { String } my-string -> myString
|
1820
|
+
*/
|
1821
|
+
function toCamel(string) {
|
1822
|
+
return string.replace(/-(\w)/g, function(_, c) {
|
1823
|
+
return c.toUpperCase()
|
1824
|
+
})
|
1032
1825
|
}
|
1033
1826
|
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1827
|
+
/**
|
1828
|
+
* Get the value of any DOM attribute on a node
|
1829
|
+
* @param { Object } dom - DOM node we want to parse
|
1830
|
+
* @param { String } name - name of the attribute we want to get
|
1831
|
+
* @returns { String | undefined } name of the node attribute whether it exists
|
1832
|
+
*/
|
1833
|
+
function getAttr(dom, name) {
|
1834
|
+
return dom.getAttribute(name)
|
1835
|
+
}
|
1039
1836
|
|
1040
|
-
|
1041
|
-
|
1837
|
+
/**
|
1838
|
+
* Set any DOM attribute
|
1839
|
+
* @param { Object } dom - DOM node we want to update
|
1840
|
+
* @param { String } name - name of the property we want to set
|
1841
|
+
* @param { String } val - value of the property we want to set
|
1842
|
+
*/
|
1843
|
+
function setAttr(dom, name, val) {
|
1844
|
+
dom.setAttribute(name, val)
|
1845
|
+
}
|
1042
1846
|
|
1043
|
-
|
1847
|
+
/**
|
1848
|
+
* Detect the tag implementation by a DOM node
|
1849
|
+
* @param { Object } dom - DOM node we need to parse to get its tag implementation
|
1850
|
+
* @returns { Object } it returns an object containing the implementation of a custom tag (template and boot function)
|
1851
|
+
*/
|
1852
|
+
function getTag(dom) {
|
1853
|
+
return dom.tagName && __tagImpl[getAttr(dom, RIOT_TAG) || dom.tagName.toLowerCase()]
|
1854
|
+
}
|
1855
|
+
/**
|
1856
|
+
* Add a child tag to its parent into the `tags` object
|
1857
|
+
* @param { Object } tag - child tag instance
|
1858
|
+
* @param { String } tagName - key where the new tag will be stored
|
1859
|
+
* @param { Object } parent - tag instance where the new child tag will be included
|
1860
|
+
*/
|
1861
|
+
function addChildTag(tag, tagName, parent) {
|
1862
|
+
var cachedTag = parent.tags[tagName]
|
1044
1863
|
|
1045
1864
|
// if there are multiple children tags having the same name
|
1046
1865
|
if (cachedTag) {
|
1047
1866
|
// if the parent tags property is not yet an array
|
1048
1867
|
// create it adding the first cached tag
|
1049
1868
|
if (!isArray(cachedTag))
|
1050
|
-
|
1869
|
+
// don't add the same tag twice
|
1870
|
+
if (cachedTag !== tag)
|
1871
|
+
parent.tags[tagName] = [cachedTag]
|
1051
1872
|
// add the new nested tag to the array
|
1052
|
-
if (
|
1053
|
-
|
1873
|
+
if (!contains(parent.tags[tagName], tag))
|
1874
|
+
parent.tags[tagName].push(tag)
|
1054
1875
|
} else {
|
1055
|
-
|
1876
|
+
parent.tags[tagName] = tag
|
1056
1877
|
}
|
1878
|
+
}
|
1879
|
+
|
1880
|
+
/**
|
1881
|
+
* Move the position of a custom tag in its parent tag
|
1882
|
+
* @param { Object } tag - child tag instance
|
1883
|
+
* @param { String } tagName - key where the tag was stored
|
1884
|
+
* @param { Number } newPos - index where the new tag will be stored
|
1885
|
+
*/
|
1886
|
+
function moveChildTag(tag, tagName, newPos) {
|
1887
|
+
var parent = tag.parent,
|
1888
|
+
tags
|
1889
|
+
// no parent no move
|
1890
|
+
if (!parent) return
|
1891
|
+
|
1892
|
+
tags = parent.tags[tagName]
|
1893
|
+
|
1894
|
+
if (isArray(tags))
|
1895
|
+
tags.splice(newPos, 0, tags.splice(tags.indexOf(tag), 1)[0])
|
1896
|
+
else addChildTag(tag, tagName, parent)
|
1897
|
+
}
|
1057
1898
|
|
1899
|
+
/**
|
1900
|
+
* Create a new child tag including it correctly into its parent
|
1901
|
+
* @param { Object } child - child tag implementation
|
1902
|
+
* @param { Object } opts - tag options containing the DOM node where the tag will be mounted
|
1903
|
+
* @param { String } innerHTML - inner html of the child node
|
1904
|
+
* @param { Object } parent - instance of the parent tag including the child custom tag
|
1905
|
+
* @returns { Object } instance of the new child tag just created
|
1906
|
+
*/
|
1907
|
+
function initChildTag(child, opts, innerHTML, parent) {
|
1908
|
+
var tag = new Tag(child, opts, innerHTML),
|
1909
|
+
tagName = getTagName(opts.root),
|
1910
|
+
ptag = getImmediateCustomParentTag(parent)
|
1911
|
+
// fix for the parent attribute in the looped elements
|
1912
|
+
tag.parent = ptag
|
1913
|
+
// store the real parent tag
|
1914
|
+
// in some cases this could be different from the custom parent tag
|
1915
|
+
// for example in nested loops
|
1916
|
+
tag._parent = parent
|
1917
|
+
|
1918
|
+
// add this tag to the custom parent tag
|
1919
|
+
addChildTag(tag, tagName, ptag)
|
1920
|
+
// and also to the real parent tag
|
1921
|
+
if (ptag !== parent)
|
1922
|
+
addChildTag(tag, tagName, parent)
|
1058
1923
|
// empty the child node once we got its template
|
1059
1924
|
// to avoid that its children get compiled multiple times
|
1060
|
-
|
1925
|
+
opts.root.innerHTML = ''
|
1061
1926
|
|
1062
1927
|
return tag
|
1063
1928
|
}
|
1064
1929
|
|
1930
|
+
/**
|
1931
|
+
* Loop backward all the parents tree to detect the first custom parent tag
|
1932
|
+
* @param { Object } tag - a Tag instance
|
1933
|
+
* @returns { Object } the instance of the first custom parent tag found
|
1934
|
+
*/
|
1065
1935
|
function getImmediateCustomParentTag(tag) {
|
1066
1936
|
var ptag = tag
|
1067
1937
|
while (!getTag(ptag.root)) {
|
@@ -1071,40 +1941,117 @@ function getImmediateCustomParentTag(tag) {
|
|
1071
1941
|
return ptag
|
1072
1942
|
}
|
1073
1943
|
|
1944
|
+
/**
|
1945
|
+
* Helper function to set an immutable property
|
1946
|
+
* @param { Object } el - object where the new property will be set
|
1947
|
+
* @param { String } key - object key where the new property will be stored
|
1948
|
+
* @param { * } value - value of the new property
|
1949
|
+
* @param { Object } options - set the propery overriding the default options
|
1950
|
+
* @returns { Object } - the initial object
|
1951
|
+
*/
|
1952
|
+
function defineProperty(el, key, value, options) {
|
1953
|
+
Object.defineProperty(el, key, extend({
|
1954
|
+
value: value,
|
1955
|
+
enumerable: false,
|
1956
|
+
writable: false,
|
1957
|
+
configurable: false
|
1958
|
+
}, options))
|
1959
|
+
return el
|
1960
|
+
}
|
1961
|
+
|
1962
|
+
/**
|
1963
|
+
* Get the tag name of any DOM node
|
1964
|
+
* @param { Object } dom - DOM node we want to parse
|
1965
|
+
* @returns { String } name to identify this dom node in riot
|
1966
|
+
*/
|
1074
1967
|
function getTagName(dom) {
|
1075
1968
|
var child = getTag(dom),
|
1076
|
-
namedTag = dom
|
1077
|
-
tagName = namedTag &&
|
1969
|
+
namedTag = getAttr(dom, 'name'),
|
1970
|
+
tagName = namedTag && !tmpl.hasExpr(namedTag) ?
|
1971
|
+
namedTag :
|
1972
|
+
child ? child.name : dom.tagName.toLowerCase()
|
1078
1973
|
|
1079
1974
|
return tagName
|
1080
1975
|
}
|
1081
1976
|
|
1977
|
+
/**
|
1978
|
+
* Extend any object with other properties
|
1979
|
+
* @param { Object } src - source object
|
1980
|
+
* @returns { Object } the resulting extended object
|
1981
|
+
*
|
1982
|
+
* var obj = { foo: 'baz' }
|
1983
|
+
* extend(obj, {bar: 'bar', foo: 'bar'})
|
1984
|
+
* console.log(obj) => {bar: 'bar', foo: 'bar'}
|
1985
|
+
*
|
1986
|
+
*/
|
1082
1987
|
function extend(src) {
|
1083
1988
|
var obj, args = arguments
|
1084
1989
|
for (var i = 1; i < args.length; ++i) {
|
1085
|
-
if (
|
1086
|
-
for (var key in obj) {
|
1087
|
-
|
1990
|
+
if (obj = args[i]) {
|
1991
|
+
for (var key in obj) {
|
1992
|
+
// check if this property of the source object could be overridden
|
1993
|
+
if (isWritable(src, key))
|
1994
|
+
src[key] = obj[key]
|
1088
1995
|
}
|
1089
1996
|
}
|
1090
1997
|
}
|
1091
1998
|
return src
|
1092
1999
|
}
|
1093
2000
|
|
1094
|
-
|
2001
|
+
/**
|
2002
|
+
* Check whether an array contains an item
|
2003
|
+
* @param { Array } arr - target array
|
2004
|
+
* @param { * } item - item to test
|
2005
|
+
* @returns { Boolean } Does 'arr' contain 'item'?
|
2006
|
+
*/
|
2007
|
+
function contains(arr, item) {
|
2008
|
+
return ~arr.indexOf(item)
|
2009
|
+
}
|
2010
|
+
|
2011
|
+
/**
|
2012
|
+
* Check whether an object is a kind of array
|
2013
|
+
* @param { * } a - anything
|
2014
|
+
* @returns {Boolean} is 'a' an array?
|
2015
|
+
*/
|
2016
|
+
function isArray(a) { return Array.isArray(a) || a instanceof Array }
|
2017
|
+
|
2018
|
+
/**
|
2019
|
+
* Detect whether a property of an object could be overridden
|
2020
|
+
* @param { Object } obj - source object
|
2021
|
+
* @param { String } key - object property
|
2022
|
+
* @returns { Boolean } is this property writable?
|
2023
|
+
*/
|
2024
|
+
function isWritable(obj, key) {
|
2025
|
+
var props = Object.getOwnPropertyDescriptor(obj, key)
|
2026
|
+
return typeof obj[key] === T_UNDEF || props && props.writable
|
2027
|
+
}
|
2028
|
+
|
2029
|
+
|
2030
|
+
/**
|
2031
|
+
* With this function we avoid that the internal Tag methods get overridden
|
2032
|
+
* @param { Object } data - options we want to use to extend the tag instance
|
2033
|
+
* @returns { Object } clean object without containing the riot internal reserved words
|
2034
|
+
*/
|
1095
2035
|
function cleanUpData(data) {
|
1096
|
-
if (!(data instanceof Tag) && !(data && typeof data.trigger == T_FUNCTION))
|
2036
|
+
if (!(data instanceof Tag) && !(data && typeof data.trigger == T_FUNCTION))
|
2037
|
+
return data
|
1097
2038
|
|
1098
2039
|
var o = {}
|
1099
2040
|
for (var key in data) {
|
1100
|
-
if (
|
2041
|
+
if (!contains(RESERVED_WORDS_BLACKLIST, key))
|
1101
2042
|
o[key] = data[key]
|
1102
2043
|
}
|
1103
2044
|
return o
|
1104
2045
|
}
|
1105
2046
|
|
2047
|
+
/**
|
2048
|
+
* Walk down recursively all the children tags starting dom node
|
2049
|
+
* @param { Object } dom - starting node where we will start the recursion
|
2050
|
+
* @param { Function } fn - callback to transform the child node just found
|
2051
|
+
*/
|
1106
2052
|
function walk(dom, fn) {
|
1107
2053
|
if (dom) {
|
2054
|
+
// stop the recursion
|
1108
2055
|
if (fn(dom) === false) return
|
1109
2056
|
else {
|
1110
2057
|
dom = dom.firstChild
|
@@ -1117,16 +2064,25 @@ function walk(dom, fn) {
|
|
1117
2064
|
}
|
1118
2065
|
}
|
1119
2066
|
|
1120
|
-
|
2067
|
+
/**
|
2068
|
+
* Minimize risk: only zero or one _space_ between attr & value
|
2069
|
+
* @param { String } html - html string we want to parse
|
2070
|
+
* @param { Function } fn - callback function to apply on any attribute found
|
2071
|
+
*/
|
1121
2072
|
function walkAttributes(html, fn) {
|
1122
2073
|
var m,
|
1123
|
-
|
2074
|
+
re = /([-\w]+) ?= ?(?:"([^"]*)|'([^']*)|({[^}]*}))/g
|
1124
2075
|
|
1125
|
-
while (
|
2076
|
+
while (m = re.exec(html)) {
|
1126
2077
|
fn(m[1].toLowerCase(), m[2] || m[3] || m[4])
|
1127
2078
|
}
|
1128
2079
|
}
|
1129
2080
|
|
2081
|
+
/**
|
2082
|
+
* Check whether a DOM node is in stub mode, useful for the riot 'if' directive
|
2083
|
+
* @param { Object } dom - DOM node we want to parse
|
2084
|
+
* @returns { Boolean } -
|
2085
|
+
*/
|
1130
2086
|
function isInStub(dom) {
|
1131
2087
|
while (dom) {
|
1132
2088
|
if (dom.inStub) return true
|
@@ -1135,97 +2091,141 @@ function isInStub(dom) {
|
|
1135
2091
|
return false
|
1136
2092
|
}
|
1137
2093
|
|
2094
|
+
/**
|
2095
|
+
* Create a generic DOM node
|
2096
|
+
* @param { String } name - name of the DOM node we want to create
|
2097
|
+
* @returns { Object } DOM node just created
|
2098
|
+
*/
|
1138
2099
|
function mkEl(name) {
|
1139
2100
|
return document.createElement(name)
|
1140
2101
|
}
|
1141
2102
|
|
1142
|
-
|
1143
|
-
|
1144
|
-
}
|
1145
|
-
|
2103
|
+
/**
|
2104
|
+
* Shorter and fast way to select multiple nodes in the DOM
|
2105
|
+
* @param { String } selector - DOM selector
|
2106
|
+
* @param { Object } ctx - DOM node where the targets of our search will is located
|
2107
|
+
* @returns { Object } dom nodes found
|
2108
|
+
*/
|
1146
2109
|
function $$(selector, ctx) {
|
1147
2110
|
return (ctx || document).querySelectorAll(selector)
|
1148
2111
|
}
|
1149
2112
|
|
2113
|
+
/**
|
2114
|
+
* Shorter and fast way to select a single node in the DOM
|
2115
|
+
* @param { String } selector - unique dom selector
|
2116
|
+
* @param { Object } ctx - DOM node where the target of our search will is located
|
2117
|
+
* @returns { Object } dom node found
|
2118
|
+
*/
|
1150
2119
|
function $(selector, ctx) {
|
1151
2120
|
return (ctx || document).querySelector(selector)
|
1152
2121
|
}
|
1153
2122
|
|
2123
|
+
/**
|
2124
|
+
* Simple object prototypal inheritance
|
2125
|
+
* @param { Object } parent - parent object
|
2126
|
+
* @returns { Object } child instance
|
2127
|
+
*/
|
1154
2128
|
function inherit(parent) {
|
1155
2129
|
function Child() {}
|
1156
2130
|
Child.prototype = parent
|
1157
2131
|
return new Child()
|
1158
2132
|
}
|
1159
2133
|
|
2134
|
+
/**
|
2135
|
+
* Get the name property needed to identify a DOM node in riot
|
2136
|
+
* @param { Object } dom - DOM node we need to parse
|
2137
|
+
* @returns { String | undefined } give us back a string to identify this dom node
|
2138
|
+
*/
|
2139
|
+
function getNamedKey(dom) {
|
2140
|
+
return getAttr(dom, 'id') || getAttr(dom, 'name')
|
2141
|
+
}
|
2142
|
+
|
2143
|
+
/**
|
2144
|
+
* Set the named properties of a tag element
|
2145
|
+
* @param { Object } dom - DOM node we need to parse
|
2146
|
+
* @param { Object } parent - tag instance where the named dom element will be eventually added
|
2147
|
+
* @param { Array } keys - list of all the tag instance properties
|
2148
|
+
*/
|
1160
2149
|
function setNamed(dom, parent, keys) {
|
1161
|
-
|
1162
|
-
var
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1173
|
-
parent[
|
2150
|
+
// get the key value we want to add to the tag instance
|
2151
|
+
var key = getNamedKey(dom),
|
2152
|
+
isArr,
|
2153
|
+
// add the node detected to a tag instance using the named property
|
2154
|
+
add = function(value) {
|
2155
|
+
// avoid to override the tag properties already set
|
2156
|
+
if (contains(keys, key)) return
|
2157
|
+
// check whether this value is an array
|
2158
|
+
isArr = isArray(value)
|
2159
|
+
// if the key was never set
|
2160
|
+
if (!value)
|
2161
|
+
// set it once on the tag instance
|
2162
|
+
parent[key] = dom
|
2163
|
+
// if it was an array and not yet set
|
2164
|
+
else if (!isArr || isArr && !contains(value, dom)) {
|
2165
|
+
// add the dom node into the array
|
2166
|
+
if (isArr)
|
2167
|
+
value.push(dom)
|
2168
|
+
else
|
2169
|
+
parent[key] = [value, dom]
|
2170
|
+
}
|
1174
2171
|
}
|
1175
|
-
|
1176
|
-
|
2172
|
+
|
2173
|
+
// skip the elements with no named properties
|
2174
|
+
if (!key) return
|
2175
|
+
|
2176
|
+
// check whether this key has been already evaluated
|
2177
|
+
if (tmpl.hasExpr(key))
|
2178
|
+
// wait the first updated event only once
|
2179
|
+
parent.one('mount', function() {
|
2180
|
+
key = getNamedKey(dom)
|
2181
|
+
add(parent[key])
|
2182
|
+
})
|
2183
|
+
else
|
2184
|
+
add(parent[key])
|
2185
|
+
|
1177
2186
|
}
|
1178
2187
|
|
1179
|
-
|
2188
|
+
/**
|
2189
|
+
* Faster String startsWith alternative
|
2190
|
+
* @param { String } src - source string
|
2191
|
+
* @param { String } str - test string
|
2192
|
+
* @returns { Boolean } -
|
2193
|
+
*/
|
1180
2194
|
function startsWith(src, str) {
|
1181
2195
|
return src.slice(0, str.length) === str
|
1182
2196
|
}
|
1183
2197
|
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
*/
|
1188
|
-
|
1189
|
-
var
|
1190
|
-
|
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
|
2198
|
+
/**
|
2199
|
+
* requestAnimationFrame function
|
2200
|
+
* Adapted from https://gist.github.com/paulirish/1579671, license MIT
|
2201
|
+
*/
|
2202
|
+
var rAF = (function (w) {
|
2203
|
+
var raf = w.requestAnimationFrame ||
|
2204
|
+
w.mozRequestAnimationFrame || w.webkitRequestAnimationFrame
|
1208
2205
|
|
1209
|
-
if (!
|
1210
|
-
|
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)
|
2206
|
+
if (!raf || /iP(ad|hone|od).*OS 6/.test(w.navigator.userAgent)) { // buggy iOS6
|
2207
|
+
var lastTime = 0
|
1218
2208
|
|
2209
|
+
raf = function (cb) {
|
2210
|
+
var nowtime = Date.now(), timeout = Math.max(16 - (nowtime - lastTime), 0)
|
2211
|
+
setTimeout(function () { cb(lastTime = nowtime + timeout) }, timeout)
|
1219
2212
|
}
|
2213
|
+
}
|
2214
|
+
return raf
|
1220
2215
|
|
1221
|
-
|
1222
|
-
|
1223
|
-
}
|
2216
|
+
})(window || {})
|
1224
2217
|
|
2218
|
+
/**
|
2219
|
+
* Mount a tag creating new Tag instance
|
2220
|
+
* @param { Object } root - dom node where the tag will be mounted
|
2221
|
+
* @param { String } tagName - name of the riot tag we want to mount
|
2222
|
+
* @param { Object } opts - options to pass to the Tag instance
|
2223
|
+
* @returns { Tag } a new Tag instance
|
2224
|
+
*/
|
1225
2225
|
function mountTo(root, tagName, opts) {
|
1226
|
-
var tag =
|
1227
|
-
|
1228
|
-
|
2226
|
+
var tag = __tagImpl[tagName],
|
2227
|
+
// cache the inner HTML to fix #855
|
2228
|
+
innerHTML = root._innerHTML = root._innerHTML || root.innerHTML
|
1229
2229
|
|
1230
2230
|
// clear the inner html
|
1231
2231
|
root.innerHTML = ''
|
@@ -1234,14 +2234,47 @@ function mountTo(root, tagName, opts) {
|
|
1234
2234
|
|
1235
2235
|
if (tag && tag.mount) {
|
1236
2236
|
tag.mount()
|
1237
|
-
virtualDom
|
1238
|
-
|
1239
|
-
virtualDom.splice(virtualDom.indexOf(tag), 1)
|
1240
|
-
})
|
2237
|
+
// add this tag to the virtualDom variable
|
2238
|
+
if (!contains(__virtualDom, tag)) __virtualDom.push(tag)
|
1241
2239
|
}
|
1242
2240
|
|
2241
|
+
return tag
|
1243
2242
|
}
|
2243
|
+
/**
|
2244
|
+
* Riot public api
|
2245
|
+
*/
|
2246
|
+
|
2247
|
+
// share methods for other riot parts, e.g. compiler
|
2248
|
+
riot.util = { brackets: brackets, tmpl: tmpl }
|
2249
|
+
|
2250
|
+
/**
|
2251
|
+
* Create a mixin that could be globally shared across all the tags
|
2252
|
+
*/
|
2253
|
+
riot.mixin = (function() {
|
2254
|
+
var mixins = {}
|
1244
2255
|
|
2256
|
+
/**
|
2257
|
+
* 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
|
2261
|
+
*/
|
2262
|
+
return function(name, mixin) {
|
2263
|
+
if (!mixin) return mixins[name]
|
2264
|
+
mixins[name] = mixin
|
2265
|
+
}
|
2266
|
+
|
2267
|
+
})()
|
2268
|
+
|
2269
|
+
/**
|
2270
|
+
* Create a new riot tag implementation
|
2271
|
+
* @param { String } name - name/id of the new riot tag
|
2272
|
+
* @param { String } html - tag template
|
2273
|
+
* @param { String } css - custom tag css
|
2274
|
+
* @param { String } attrs - root tag attributes
|
2275
|
+
* @param { Function } fn - user function
|
2276
|
+
* @returns { String } name/id of the tag just created
|
2277
|
+
*/
|
1245
2278
|
riot.tag = function(name, html, css, attrs, fn) {
|
1246
2279
|
if (isFunction(attrs)) {
|
1247
2280
|
fn = attrs
|
@@ -1252,51 +2285,78 @@ riot.tag = function(name, html, css, attrs, fn) {
|
|
1252
2285
|
}
|
1253
2286
|
if (css) {
|
1254
2287
|
if (isFunction(css)) fn = css
|
1255
|
-
else
|
2288
|
+
else styleManager.add(css)
|
1256
2289
|
}
|
1257
|
-
|
2290
|
+
__tagImpl[name] = { name: name, tmpl: html, attrs: attrs, fn: fn }
|
2291
|
+
return name
|
2292
|
+
}
|
2293
|
+
|
2294
|
+
/**
|
2295
|
+
* Create a new riot tag implementation (for use by the compiler)
|
2296
|
+
* @param { String } name - name/id of the new riot tag
|
2297
|
+
* @param { String } html - tag template
|
2298
|
+
* @param { String } css - custom tag css
|
2299
|
+
* @param { String } attrs - root tag attributes
|
2300
|
+
* @param { Function } fn - user function
|
2301
|
+
* @param { string } [bpair] - brackets used in the compilation
|
2302
|
+
* @returns { String } name/id of the tag just created
|
2303
|
+
*/
|
2304
|
+
riot.tag2 = function(name, html, css, attrs, fn, bpair) {
|
2305
|
+
if (css) styleManager.add(css)
|
2306
|
+
//if (bpair) riot.settings.brackets = bpair
|
2307
|
+
__tagImpl[name] = { name: name, tmpl: html, attrs: attrs, fn: fn }
|
1258
2308
|
return name
|
1259
2309
|
}
|
1260
2310
|
|
2311
|
+
/**
|
2312
|
+
* Mount a tag using a specific tag implementation
|
2313
|
+
* @param { String } selector - tag DOM selector
|
2314
|
+
* @param { String } tagName - tag implementation name
|
2315
|
+
* @param { Object } opts - tag logic
|
2316
|
+
* @returns { Array } new tags instances
|
2317
|
+
*/
|
1261
2318
|
riot.mount = function(selector, tagName, opts) {
|
1262
2319
|
|
1263
2320
|
var els,
|
1264
|
-
|
1265
|
-
|
2321
|
+
allTags,
|
2322
|
+
tags = []
|
1266
2323
|
|
1267
2324
|
// helper functions
|
1268
2325
|
|
1269
2326
|
function addRiotTags(arr) {
|
1270
2327
|
var list = ''
|
1271
2328
|
each(arr, function (e) {
|
1272
|
-
|
2329
|
+
if (!/[^-\w]/.test(e))
|
2330
|
+
list += ',*[' + RIOT_TAG + '=' + e.trim() + ']'
|
1273
2331
|
})
|
1274
2332
|
return list
|
1275
2333
|
}
|
1276
2334
|
|
1277
2335
|
function selectAllTags() {
|
1278
|
-
var keys = Object.keys(
|
2336
|
+
var keys = Object.keys(__tagImpl)
|
1279
2337
|
return keys + addRiotTags(keys)
|
1280
2338
|
}
|
1281
2339
|
|
1282
2340
|
function pushTags(root) {
|
1283
2341
|
var last
|
2342
|
+
|
1284
2343
|
if (root.tagName) {
|
1285
|
-
if (tagName && (!(last = root
|
1286
|
-
root
|
2344
|
+
if (tagName && (!(last = getAttr(root, RIOT_TAG)) || last != tagName))
|
2345
|
+
setAttr(root, RIOT_TAG, tagName)
|
1287
2346
|
|
1288
|
-
var tag = mountTo(root,
|
1289
|
-
tagName || root.getAttribute(RIOT_TAG) || root.tagName.toLowerCase(), opts)
|
2347
|
+
var tag = mountTo(root, tagName || root.getAttribute(RIOT_TAG) || root.tagName.toLowerCase(), opts)
|
1290
2348
|
|
1291
2349
|
if (tag) tags.push(tag)
|
1292
|
-
}
|
1293
|
-
else if (root.length) {
|
2350
|
+
} else if (root.length)
|
1294
2351
|
each(root, pushTags) // assume nodeList
|
1295
|
-
|
2352
|
+
|
1296
2353
|
}
|
1297
2354
|
|
1298
2355
|
// ----- mount code -----
|
1299
2356
|
|
2357
|
+
// inject styles into DOM
|
2358
|
+
styleManager.inject()
|
2359
|
+
|
1300
2360
|
if (typeof tagName === T_OBJECT) {
|
1301
2361
|
opts = tagName
|
1302
2362
|
tagName = 0
|
@@ -1312,7 +2372,9 @@ riot.mount = function(selector, tagName, opts) {
|
|
1312
2372
|
// or just the ones named like the selector
|
1313
2373
|
selector += addRiotTags(selector.split(','))
|
1314
2374
|
|
1315
|
-
|
2375
|
+
// make sure to pass always a selector
|
2376
|
+
// to the querySelectorAll function
|
2377
|
+
els = selector ? $$(selector) : []
|
1316
2378
|
}
|
1317
2379
|
else
|
1318
2380
|
// probably you have passed already a tag or a NodeList
|
@@ -1345,25 +2407,26 @@ riot.mount = function(selector, tagName, opts) {
|
|
1345
2407
|
return tags
|
1346
2408
|
}
|
1347
2409
|
|
1348
|
-
|
2410
|
+
/**
|
2411
|
+
* Update all the tags instances created
|
2412
|
+
* @returns { Array } all the tags instances
|
2413
|
+
*/
|
1349
2414
|
riot.update = function() {
|
1350
|
-
return each(
|
2415
|
+
return each(__virtualDom, function(tag) {
|
1351
2416
|
tag.update()
|
1352
2417
|
})
|
1353
2418
|
}
|
1354
2419
|
|
1355
|
-
|
1356
|
-
|
1357
|
-
|
1358
|
-
|
1359
|
-
riot.util = { brackets: brackets, tmpl: tmpl }
|
1360
|
-
|
2420
|
+
/**
|
2421
|
+
* Export the Tag constructor
|
2422
|
+
*/
|
2423
|
+
riot.Tag = Tag
|
1361
2424
|
// support CommonJS, AMD & browser
|
1362
2425
|
/* istanbul ignore next */
|
1363
2426
|
if (typeof exports === T_OBJECT)
|
1364
2427
|
module.exports = riot
|
1365
|
-
else if (typeof define ===
|
1366
|
-
define(function() { return
|
2428
|
+
else if (typeof define === T_FUNCTION && typeof define.amd !== T_UNDEF)
|
2429
|
+
define(function() { return riot })
|
1367
2430
|
else
|
1368
2431
|
window.riot = riot
|
1369
2432
|
|