fluentd-ui 0.3.8 → 0.3.9

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.

Potentially problematic release.


This version of fluentd-ui might be problematic. Click here for more details.

Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog +9 -0
  3. data/Gemfile +1 -0
  4. data/Gemfile.lock +4 -1
  5. data/app/assets/javascripts/vue/fluent_log.js +4 -4
  6. data/app/assets/javascripts/vue/in_tail_format.js +43 -49
  7. data/app/assets/javascripts/{alert.js → vue/notification.js} +21 -7
  8. data/app/assets/javascripts/vue/settings.js +121 -0
  9. data/app/assets/javascripts/vue/treeview.js +3 -3
  10. data/app/assets/stylesheets/common.css.scss +7 -1
  11. data/app/controllers/api/settings_controller.rb +55 -0
  12. data/app/controllers/api_controller.rb +6 -2
  13. data/app/controllers/concerns/setting_concern.rb +2 -2
  14. data/app/controllers/fluentd/settings_controller.rb +17 -2
  15. data/app/models/fluentd/setting/config.rb +39 -0
  16. data/app/views/api/settings/_element.json.jbuilder +6 -0
  17. data/app/views/api/settings/index.json.jbuilder +3 -0
  18. data/app/views/api/settings/show.json.jbuilder +1 -0
  19. data/app/views/fluentd/settings/edit.html.haml +3 -0
  20. data/app/views/fluentd/settings/source_and_output.html.haml +19 -2
  21. data/app/views/layouts/application.html.erb +1 -30
  22. data/app/views/shared/vue/_in_tail_format.html.erb +11 -36
  23. data/app/views/shared/vue/_notification.html.erb +31 -0
  24. data/app/views/shared/vue/_setting.html.erb +23 -0
  25. data/app/views/shared/vue/_treeview.html.erb +2 -2
  26. data/bower.json +1 -1
  27. data/config/application.rb +1 -0
  28. data/config/locales/translation_en.yml +11 -7
  29. data/config/locales/translation_ja.yml +4 -0
  30. data/config/routes.rb +2 -0
  31. data/lib/fluentd-ui/version.rb +1 -1
  32. data/spec/features/fluentd/setting/source_and_output_spec.rb +157 -0
  33. data/spec/spec_helper.rb +1 -0
  34. data/spec/support/javascript_macro.rb +21 -0
  35. data/vendor/assets/javascripts/bower/vue/.bower.json +7 -7
  36. data/vendor/assets/javascripts/bower/vue/LICENSE +1 -1
  37. data/vendor/assets/javascripts/bower/vue/dist/vue.js +7822 -4768
  38. data/vendor/assets/javascripts/bower/vue/dist/vue.min.js +7 -7
  39. data/vendor/assets/javascripts/bower/vue/src/api/child.js +53 -0
  40. data/vendor/assets/javascripts/bower/vue/src/api/data.js +161 -0
  41. data/vendor/assets/javascripts/bower/vue/src/api/dom.js +211 -0
  42. data/vendor/assets/javascripts/bower/vue/src/api/events.js +176 -0
  43. data/vendor/assets/javascripts/bower/vue/src/api/global.js +146 -0
  44. data/vendor/assets/javascripts/bower/vue/src/api/lifecycle.js +144 -0
  45. data/vendor/assets/javascripts/bower/vue/src/batcher.js +52 -32
  46. data/vendor/assets/javascripts/bower/vue/src/cache.js +112 -0
  47. data/vendor/assets/javascripts/bower/vue/src/compiler/compile.js +549 -0
  48. data/vendor/assets/javascripts/bower/vue/src/compiler/transclude.js +163 -0
  49. data/vendor/assets/javascripts/bower/vue/src/config.js +74 -14
  50. data/vendor/assets/javascripts/bower/vue/src/directive.js +179 -219
  51. data/vendor/assets/javascripts/bower/vue/src/directives/attr.js +32 -0
  52. data/vendor/assets/javascripts/bower/vue/src/directives/class.js +18 -0
  53. data/vendor/assets/javascripts/bower/vue/src/directives/cloak.js +12 -0
  54. data/vendor/assets/javascripts/bower/vue/src/directives/component.js +214 -0
  55. data/vendor/assets/javascripts/bower/vue/src/directives/el.js +13 -0
  56. data/vendor/assets/javascripts/bower/vue/src/directives/html.js +30 -34
  57. data/vendor/assets/javascripts/bower/vue/src/directives/if.js +77 -46
  58. data/vendor/assets/javascripts/bower/vue/src/directives/index.js +22 -129
  59. data/vendor/assets/javascripts/bower/vue/src/directives/model/checkbox.js +25 -0
  60. data/vendor/assets/javascripts/bower/vue/src/directives/model/default.js +123 -0
  61. data/vendor/assets/javascripts/bower/vue/src/directives/model/index.js +56 -0
  62. data/vendor/assets/javascripts/bower/vue/src/directives/model/radio.js +26 -0
  63. data/vendor/assets/javascripts/bower/vue/src/directives/model/select.js +166 -0
  64. data/vendor/assets/javascripts/bower/vue/src/directives/on.js +51 -50
  65. data/vendor/assets/javascripts/bower/vue/src/directives/partial.js +36 -42
  66. data/vendor/assets/javascripts/bower/vue/src/directives/ref.js +24 -0
  67. data/vendor/assets/javascripts/bower/vue/src/directives/repeat.js +477 -226
  68. data/vendor/assets/javascripts/bower/vue/src/directives/show.js +8 -0
  69. data/vendor/assets/javascripts/bower/vue/src/directives/style.js +49 -37
  70. data/vendor/assets/javascripts/bower/vue/src/directives/text.js +15 -0
  71. data/vendor/assets/javascripts/bower/vue/src/directives/transition.js +12 -0
  72. data/vendor/assets/javascripts/bower/vue/src/directives/with.js +38 -41
  73. data/vendor/assets/javascripts/bower/vue/src/filters/array-filters.js +87 -0
  74. data/vendor/assets/javascripts/bower/vue/src/filters/index.js +135 -0
  75. data/vendor/assets/javascripts/bower/vue/src/instance/compile.js +71 -0
  76. data/vendor/assets/javascripts/bower/vue/src/instance/events.js +122 -0
  77. data/vendor/assets/javascripts/bower/vue/src/instance/init.js +76 -0
  78. data/vendor/assets/javascripts/bower/vue/src/instance/scope.js +217 -0
  79. data/vendor/assets/javascripts/bower/vue/src/observer/array.js +90 -0
  80. data/vendor/assets/javascripts/bower/vue/src/observer/dep.js +50 -0
  81. data/vendor/assets/javascripts/bower/vue/src/observer/index.js +235 -0
  82. data/vendor/assets/javascripts/bower/vue/src/observer/object.js +75 -0
  83. data/vendor/assets/javascripts/bower/vue/src/parsers/directive.js +159 -0
  84. data/vendor/assets/javascripts/bower/vue/src/parsers/expression.js +226 -0
  85. data/vendor/assets/javascripts/bower/vue/src/parsers/path.js +300 -0
  86. data/vendor/assets/javascripts/bower/vue/src/parsers/template.js +246 -0
  87. data/vendor/assets/javascripts/bower/vue/src/parsers/text.js +178 -0
  88. data/vendor/assets/javascripts/bower/vue/src/transition/css.js +189 -0
  89. data/vendor/assets/javascripts/bower/vue/src/transition/index.js +151 -0
  90. data/vendor/assets/javascripts/bower/vue/src/transition/js.js +43 -0
  91. data/vendor/assets/javascripts/bower/vue/src/util/debug.js +50 -0
  92. data/vendor/assets/javascripts/bower/vue/src/util/dom.js +176 -0
  93. data/vendor/assets/javascripts/bower/vue/src/util/env.js +74 -0
  94. data/vendor/assets/javascripts/bower/vue/src/util/filter.js +72 -0
  95. data/vendor/assets/javascripts/bower/vue/src/util/index.js +8 -0
  96. data/vendor/assets/javascripts/bower/vue/src/util/lang.js +175 -0
  97. data/vendor/assets/javascripts/bower/vue/src/util/merge-option.js +258 -0
  98. data/vendor/assets/javascripts/bower/vue/src/vue.js +84 -0
  99. data/vendor/assets/javascripts/bower/vue/src/watcher.js +240 -0
  100. metadata +65 -20
  101. data/app/assets/javascripts/setting_format.js +0 -15
  102. data/vendor/assets/javascripts/bower/vue/src/binding.js +0 -103
  103. data/vendor/assets/javascripts/bower/vue/src/compiler.js +0 -1037
  104. data/vendor/assets/javascripts/bower/vue/src/deps-parser.js +0 -65
  105. data/vendor/assets/javascripts/bower/vue/src/directives/model.js +0 -174
  106. data/vendor/assets/javascripts/bower/vue/src/directives/view.js +0 -56
  107. data/vendor/assets/javascripts/bower/vue/src/emitter.js +0 -97
  108. data/vendor/assets/javascripts/bower/vue/src/exp-parser.js +0 -190
  109. data/vendor/assets/javascripts/bower/vue/src/filters.js +0 -191
  110. data/vendor/assets/javascripts/bower/vue/src/fragment.js +0 -67
  111. data/vendor/assets/javascripts/bower/vue/src/main.js +0 -188
  112. data/vendor/assets/javascripts/bower/vue/src/observer.js +0 -446
  113. data/vendor/assets/javascripts/bower/vue/src/template-parser.js +0 -46
  114. data/vendor/assets/javascripts/bower/vue/src/text-parser.js +0 -96
  115. data/vendor/assets/javascripts/bower/vue/src/transition.js +0 -228
  116. data/vendor/assets/javascripts/bower/vue/src/utils.js +0 -326
  117. data/vendor/assets/javascripts/bower/vue/src/viewmodel.js +0 -190
@@ -1,65 +0,0 @@
1
- var Emitter = require('./emitter'),
2
- utils = require('./utils'),
3
- Observer = require('./observer'),
4
- catcher = new Emitter()
5
-
6
- /**
7
- * Auto-extract the dependencies of a computed property
8
- * by recording the getters triggered when evaluating it.
9
- */
10
- function catchDeps (binding) {
11
- if (binding.isFn) return
12
- utils.log('\n- ' + binding.key)
13
- var got = utils.hash()
14
- binding.deps = []
15
- catcher.on('get', function (dep) {
16
- var has = got[dep.key]
17
- if (
18
- // avoid duplicate bindings
19
- (has && has.compiler === dep.compiler) ||
20
- // avoid repeated items as dependency
21
- // only when the binding is from self or the parent chain
22
- (dep.compiler.repeat && !isParentOf(dep.compiler, binding.compiler))
23
- ) {
24
- return
25
- }
26
- got[dep.key] = dep
27
- utils.log(' - ' + dep.key)
28
- binding.deps.push(dep)
29
- dep.subs.push(binding)
30
- })
31
- binding.value.$get()
32
- catcher.off('get')
33
- }
34
-
35
- /**
36
- * Test if A is a parent of or equals B
37
- */
38
- function isParentOf (a, b) {
39
- while (b) {
40
- if (a === b) {
41
- return true
42
- }
43
- b = b.parent
44
- }
45
- }
46
-
47
- module.exports = {
48
-
49
- /**
50
- * the observer that catches events triggered by getters
51
- */
52
- catcher: catcher,
53
-
54
- /**
55
- * parse a list of computed property bindings
56
- */
57
- parse: function (bindings) {
58
- utils.log('\nparsing dependencies...')
59
- Observer.shouldGet = true
60
- bindings.forEach(catchDeps)
61
- Observer.shouldGet = false
62
- utils.log('\ndone.')
63
- }
64
-
65
- }
@@ -1,174 +0,0 @@
1
- var utils = require('../utils'),
2
- isIE9 = navigator.userAgent.indexOf('MSIE 9.0') > 0,
3
- filter = [].filter
4
-
5
- /**
6
- * Returns an array of values from a multiple select
7
- */
8
- function getMultipleSelectOptions (select) {
9
- return filter
10
- .call(select.options, function (option) {
11
- return option.selected
12
- })
13
- .map(function (option) {
14
- return option.value || option.text
15
- })
16
- }
17
-
18
- /**
19
- * Two-way binding for form input elements
20
- */
21
- module.exports = {
22
-
23
- bind: function () {
24
-
25
- var self = this,
26
- el = self.el,
27
- type = el.type,
28
- tag = el.tagName
29
-
30
- self.lock = false
31
- self.ownerVM = self.binding.compiler.vm
32
-
33
- // determine what event to listen to
34
- self.event =
35
- (self.compiler.options.lazy ||
36
- tag === 'SELECT' ||
37
- type === 'checkbox' || type === 'radio')
38
- ? 'change'
39
- : 'input'
40
-
41
- // determine the attribute to change when updating
42
- self.attr = type === 'checkbox'
43
- ? 'checked'
44
- : (tag === 'INPUT' || tag === 'SELECT' || tag === 'TEXTAREA')
45
- ? 'value'
46
- : 'innerHTML'
47
-
48
- // select[multiple] support
49
- if(tag === 'SELECT' && el.hasAttribute('multiple')) {
50
- this.multi = true
51
- }
52
-
53
- var compositionLock = false
54
- self.cLock = function () {
55
- compositionLock = true
56
- }
57
- self.cUnlock = function () {
58
- compositionLock = false
59
- }
60
- el.addEventListener('compositionstart', this.cLock)
61
- el.addEventListener('compositionend', this.cUnlock)
62
-
63
- // attach listener
64
- self.set = self.filters
65
- ? function () {
66
- if (compositionLock) return
67
- // if this directive has filters
68
- // we need to let the vm.$set trigger
69
- // update() so filters are applied.
70
- // therefore we have to record cursor position
71
- // so that after vm.$set changes the input
72
- // value we can put the cursor back at where it is
73
- var cursorPos
74
- try { cursorPos = el.selectionStart } catch (e) {}
75
-
76
- self._set()
77
-
78
- // since updates are async
79
- // we need to reset cursor position async too
80
- utils.nextTick(function () {
81
- if (cursorPos !== undefined) {
82
- el.setSelectionRange(cursorPos, cursorPos)
83
- }
84
- })
85
- }
86
- : function () {
87
- if (compositionLock) return
88
- // no filters, don't let it trigger update()
89
- self.lock = true
90
-
91
- self._set()
92
-
93
- utils.nextTick(function () {
94
- self.lock = false
95
- })
96
- }
97
- el.addEventListener(self.event, self.set)
98
-
99
- // fix shit for IE9
100
- // since it doesn't fire input on backspace / del / cut
101
- if (isIE9) {
102
- self.onCut = function () {
103
- // cut event fires before the value actually changes
104
- utils.nextTick(function () {
105
- self.set()
106
- })
107
- }
108
- self.onDel = function (e) {
109
- if (e.keyCode === 46 || e.keyCode === 8) {
110
- self.set()
111
- }
112
- }
113
- el.addEventListener('cut', self.onCut)
114
- el.addEventListener('keyup', self.onDel)
115
- }
116
- },
117
-
118
- _set: function () {
119
- this.ownerVM.$set(
120
- this.key, this.multi
121
- ? getMultipleSelectOptions(this.el)
122
- : this.el[this.attr]
123
- )
124
- },
125
-
126
- update: function (value, init) {
127
- /* jshint eqeqeq: false */
128
- // sync back inline value if initial data is undefined
129
- if (init && value === undefined) {
130
- return this._set()
131
- }
132
- if (this.lock) return
133
- var el = this.el
134
- if (el.tagName === 'SELECT') { // select dropdown
135
- el.selectedIndex = -1
136
- if(this.multi && Array.isArray(value)) {
137
- value.forEach(this.updateSelect, this)
138
- } else {
139
- this.updateSelect(value)
140
- }
141
- } else if (el.type === 'radio') { // radio button
142
- el.checked = value == el.value
143
- } else if (el.type === 'checkbox') { // checkbox
144
- el.checked = !!value
145
- } else {
146
- el[this.attr] = utils.guard(value)
147
- }
148
- },
149
-
150
- updateSelect: function (value) {
151
- /* jshint eqeqeq: false */
152
- // setting <select>'s value in IE9 doesn't work
153
- // we have to manually loop through the options
154
- var options = this.el.options,
155
- i = options.length
156
- while (i--) {
157
- if (options[i].value == value) {
158
- options[i].selected = true
159
- break
160
- }
161
- }
162
- },
163
-
164
- unbind: function () {
165
- var el = this.el
166
- el.removeEventListener(this.event, this.set)
167
- el.removeEventListener('compositionstart', this.cLock)
168
- el.removeEventListener('compositionend', this.cUnlock)
169
- if (isIE9) {
170
- el.removeEventListener('cut', this.onCut)
171
- el.removeEventListener('keyup', this.onDel)
172
- }
173
- }
174
- }
@@ -1,56 +0,0 @@
1
- /**
2
- * Manages a conditional child VM using the
3
- * binding's value as the component ID.
4
- */
5
- module.exports = {
6
-
7
- bind: function () {
8
-
9
- // track position in DOM with a ref node
10
- var el = this.raw = this.el,
11
- parent = el.parentNode,
12
- ref = this.ref = document.createComment('v-view')
13
- parent.insertBefore(ref, el)
14
- parent.removeChild(el)
15
-
16
- // cache original content
17
- /* jshint boss: true */
18
- var node,
19
- frag = this.inner = document.createElement('div')
20
- while (node = el.firstChild) {
21
- frag.appendChild(node)
22
- }
23
-
24
- },
25
-
26
- update: function(value) {
27
-
28
- this.unbind()
29
-
30
- var Ctor = this.compiler.getOption('components', value)
31
- if (!Ctor) return
32
-
33
- this.childVM = new Ctor({
34
- el: this.raw.cloneNode(true),
35
- parent: this.vm,
36
- compilerOptions: {
37
- rawContent: this.inner.cloneNode(true)
38
- }
39
- })
40
-
41
- this.el = this.childVM.$el
42
- if (this.compiler.init) {
43
- this.ref.parentNode.insertBefore(this.el, this.ref)
44
- } else {
45
- this.childVM.$before(this.ref)
46
- }
47
-
48
- },
49
-
50
- unbind: function() {
51
- if (this.childVM) {
52
- this.childVM.$destroy()
53
- }
54
- }
55
-
56
- }
@@ -1,97 +0,0 @@
1
- var slice = [].slice
2
-
3
- function Emitter (ctx) {
4
- this._ctx = ctx || this
5
- }
6
-
7
- var EmitterProto = Emitter.prototype
8
-
9
- EmitterProto.on = function (event, fn) {
10
- this._cbs = this._cbs || {}
11
- ;(this._cbs[event] = this._cbs[event] || [])
12
- .push(fn)
13
- return this
14
- }
15
-
16
- EmitterProto.once = function (event, fn) {
17
- var self = this
18
- this._cbs = this._cbs || {}
19
-
20
- function on () {
21
- self.off(event, on)
22
- fn.apply(this, arguments)
23
- }
24
-
25
- on.fn = fn
26
- this.on(event, on)
27
- return this
28
- }
29
-
30
- EmitterProto.off = function (event, fn) {
31
- this._cbs = this._cbs || {}
32
-
33
- // all
34
- if (!arguments.length) {
35
- this._cbs = {}
36
- return this
37
- }
38
-
39
- // specific event
40
- var callbacks = this._cbs[event]
41
- if (!callbacks) return this
42
-
43
- // remove all handlers
44
- if (arguments.length === 1) {
45
- delete this._cbs[event]
46
- return this
47
- }
48
-
49
- // remove specific handler
50
- var cb
51
- for (var i = 0; i < callbacks.length; i++) {
52
- cb = callbacks[i]
53
- if (cb === fn || cb.fn === fn) {
54
- callbacks.splice(i, 1)
55
- break
56
- }
57
- }
58
- return this
59
- }
60
-
61
- /**
62
- * The internal, faster emit with fixed amount of arguments
63
- * using Function.call
64
- */
65
- EmitterProto.emit = function (event, a, b, c) {
66
- this._cbs = this._cbs || {}
67
- var callbacks = this._cbs[event]
68
-
69
- if (callbacks) {
70
- callbacks = callbacks.slice(0)
71
- for (var i = 0, len = callbacks.length; i < len; i++) {
72
- callbacks[i].call(this._ctx, a, b, c)
73
- }
74
- }
75
-
76
- return this
77
- }
78
-
79
- /**
80
- * The external emit using Function.apply
81
- */
82
- EmitterProto.applyEmit = function (event) {
83
- this._cbs = this._cbs || {}
84
- var callbacks = this._cbs[event], args
85
-
86
- if (callbacks) {
87
- callbacks = callbacks.slice(0)
88
- args = slice.call(arguments, 1)
89
- for (var i = 0, len = callbacks.length; i < len; i++) {
90
- callbacks[i].apply(this._ctx, args)
91
- }
92
- }
93
-
94
- return this
95
- }
96
-
97
- module.exports = Emitter
@@ -1,190 +0,0 @@
1
- var utils = require('./utils'),
2
- STR_SAVE_RE = /"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'/g,
3
- STR_RESTORE_RE = /"(\d+)"/g,
4
- NEWLINE_RE = /\n/g,
5
- CTOR_RE = new RegExp('constructor'.split('').join('[\'"+, ]*')),
6
- UNICODE_RE = /\\u\d\d\d\d/
7
-
8
- // Variable extraction scooped from https://github.com/RubyLouvre/avalon
9
-
10
- var KEYWORDS =
11
- // keywords
12
- 'break,case,catch,continue,debugger,default,delete,do,else,false' +
13
- ',finally,for,function,if,in,instanceof,new,null,return,switch,this' +
14
- ',throw,true,try,typeof,var,void,while,with,undefined' +
15
- // reserved
16
- ',abstract,boolean,byte,char,class,const,double,enum,export,extends' +
17
- ',final,float,goto,implements,import,int,interface,long,native' +
18
- ',package,private,protected,public,short,static,super,synchronized' +
19
- ',throws,transient,volatile' +
20
- // ECMA 5 - use strict
21
- ',arguments,let,yield' +
22
- // allow using Math in expressions
23
- ',Math',
24
-
25
- KEYWORDS_RE = new RegExp(["\\b" + KEYWORDS.replace(/,/g, '\\b|\\b') + "\\b"].join('|'), 'g'),
26
- REMOVE_RE = /\/\*(?:.|\n)*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|'[^']*'|"[^"]*"|[\s\t\n]*\.[\s\t\n]*[$\w\.]+|[\{,]\s*[\w\$_]+\s*:/g,
27
- SPLIT_RE = /[^\w$]+/g,
28
- NUMBER_RE = /\b\d[^,]*/g,
29
- BOUNDARY_RE = /^,+|,+$/g
30
-
31
- /**
32
- * Strip top level variable names from a snippet of JS expression
33
- */
34
- function getVariables (code) {
35
- code = code
36
- .replace(REMOVE_RE, '')
37
- .replace(SPLIT_RE, ',')
38
- .replace(KEYWORDS_RE, '')
39
- .replace(NUMBER_RE, '')
40
- .replace(BOUNDARY_RE, '')
41
- return code
42
- ? code.split(/,+/)
43
- : []
44
- }
45
-
46
- /**
47
- * A given path could potentially exist not on the
48
- * current compiler, but up in the parent chain somewhere.
49
- * This function generates an access relationship string
50
- * that can be used in the getter function by walking up
51
- * the parent chain to check for key existence.
52
- *
53
- * It stops at top parent if no vm in the chain has the
54
- * key. It then creates any missing bindings on the
55
- * final resolved vm.
56
- */
57
- function traceScope (path, compiler, data) {
58
- var rel = '',
59
- dist = 0,
60
- self = compiler
61
-
62
- if (data && utils.get(data, path) !== undefined) {
63
- // hack: temporarily attached data
64
- return '$temp.'
65
- }
66
-
67
- while (compiler) {
68
- if (compiler.hasKey(path)) {
69
- break
70
- } else {
71
- compiler = compiler.parent
72
- dist++
73
- }
74
- }
75
- if (compiler) {
76
- while (dist--) {
77
- rel += '$parent.'
78
- }
79
- if (!compiler.bindings[path] && path.charAt(0) !== '$') {
80
- compiler.createBinding(path)
81
- }
82
- } else {
83
- self.createBinding(path)
84
- }
85
- return rel
86
- }
87
-
88
- /**
89
- * Create a function from a string...
90
- * this looks like evil magic but since all variables are limited
91
- * to the VM's data it's actually properly sandboxed
92
- */
93
- function makeGetter (exp, raw) {
94
- var fn
95
- try {
96
- fn = new Function(exp)
97
- } catch (e) {
98
- utils.warn('Error parsing expression: ' + raw)
99
- }
100
- return fn
101
- }
102
-
103
- /**
104
- * Escape a leading dollar sign for regex construction
105
- */
106
- function escapeDollar (v) {
107
- return v.charAt(0) === '$'
108
- ? '\\' + v
109
- : v
110
- }
111
-
112
- /**
113
- * Parse and return an anonymous computed property getter function
114
- * from an arbitrary expression, together with a list of paths to be
115
- * created as bindings.
116
- */
117
- exports.parse = function (exp, compiler, data) {
118
- // unicode and 'constructor' are not allowed for XSS security.
119
- if (UNICODE_RE.test(exp) || CTOR_RE.test(exp)) {
120
- utils.warn('Unsafe expression: ' + exp)
121
- return
122
- }
123
- // extract variable names
124
- var vars = getVariables(exp)
125
- if (!vars.length) {
126
- return makeGetter('return ' + exp, exp)
127
- }
128
- vars = utils.unique(vars)
129
-
130
- var accessors = '',
131
- has = utils.hash(),
132
- strings = [],
133
- // construct a regex to extract all valid variable paths
134
- // ones that begin with "$" are particularly tricky
135
- // because we can't use \b for them
136
- pathRE = new RegExp(
137
- "[^$\\w\\.](" +
138
- vars.map(escapeDollar).join('|') +
139
- ")[$\\w\\.]*\\b", 'g'
140
- ),
141
- body = (' ' + exp)
142
- .replace(STR_SAVE_RE, saveStrings)
143
- .replace(pathRE, replacePath)
144
- .replace(STR_RESTORE_RE, restoreStrings)
145
-
146
- body = accessors + 'return ' + body
147
-
148
- function saveStrings (str) {
149
- var i = strings.length
150
- // escape newlines in strings so the expression
151
- // can be correctly evaluated
152
- strings[i] = str.replace(NEWLINE_RE, '\\n')
153
- return '"' + i + '"'
154
- }
155
-
156
- function replacePath (path) {
157
- // keep track of the first char
158
- var c = path.charAt(0)
159
- path = path.slice(1)
160
- var val = 'this.' + traceScope(path, compiler, data) + path
161
- if (!has[path]) {
162
- accessors += val + ';'
163
- has[path] = 1
164
- }
165
- // don't forget to put that first char back
166
- return c + val
167
- }
168
-
169
- function restoreStrings (str, i) {
170
- return strings[i]
171
- }
172
-
173
- return makeGetter(body, exp)
174
- }
175
-
176
- /**
177
- * Evaluate an expression in the context of a compiler.
178
- * Accepts additional data.
179
- */
180
- exports.eval = function (exp, compiler, data) {
181
- var getter = exports.parse(exp, compiler, data), res
182
- if (getter) {
183
- // hack: temporarily attach the additional data so
184
- // it can be accessed in the getter
185
- compiler.vm.$temp = data
186
- res = getter.call(compiler.vm)
187
- delete compiler.vm.$temp
188
- }
189
- return res
190
- }