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,58 +1,59 @@
1
- var utils = require('../utils')
1
+ var _ = require('../util')
2
2
 
3
- /**
4
- * Binding for event listeners
5
- */
6
3
  module.exports = {
7
4
 
8
- isFn: true,
5
+ acceptStatement: true,
6
+ priority: 700,
9
7
 
10
- bind: function () {
11
- this.context = this.binding.isExp
12
- ? this.vm
13
- : this.binding.compiler.vm
14
- if (this.el.tagName === 'IFRAME' && this.arg !== 'load') {
15
- var self = this
16
- this.iframeBind = function () {
17
- self.el.contentWindow.addEventListener(self.arg, self.handler)
18
- }
19
- this.el.addEventListener('load', this.iframeBind)
20
- }
21
- },
22
-
23
- update: function (handler) {
24
- if (typeof handler !== 'function') {
25
- utils.warn('Directive "v-on:' + this.expression + '" expects a method.')
26
- return
27
- }
28
- this.reset()
29
- var vm = this.vm,
30
- context = this.context
31
- this.handler = function (e) {
32
- e.targetVM = vm
33
- context.$event = e
34
- var res = handler.call(context, e)
35
- context.$event = null
36
- return res
37
- }
38
- if (this.iframeBind) {
39
- this.iframeBind()
40
- } else {
41
- this.el.addEventListener(this.arg, this.handler)
42
- }
43
- },
8
+ bind: function () {
9
+ // deal with iframes
10
+ if (
11
+ this.el.tagName === 'IFRAME' &&
12
+ this.arg !== 'load'
13
+ ) {
14
+ var self = this
15
+ this.iframeBind = function () {
16
+ _.on(self.el.contentWindow, self.arg, self.handler)
17
+ }
18
+ _.on(this.el, 'load', this.iframeBind)
19
+ }
20
+ },
44
21
 
45
- reset: function () {
46
- var el = this.iframeBind
47
- ? this.el.contentWindow
48
- : this.el
49
- if (this.handler) {
50
- el.removeEventListener(this.arg, this.handler)
51
- }
52
- },
22
+ update: function (handler) {
23
+ if (typeof handler !== 'function') {
24
+ _.warn(
25
+ 'Directive "v-on:' + this.expression + '" ' +
26
+ 'expects a function value.'
27
+ )
28
+ return
29
+ }
30
+ this.reset()
31
+ var vm = this.vm
32
+ this.handler = function (e) {
33
+ e.targetVM = vm
34
+ vm.$event = e
35
+ var res = handler(e)
36
+ vm.$event = null
37
+ return res
38
+ }
39
+ if (this.iframeBind) {
40
+ this.iframeBind()
41
+ } else {
42
+ _.on(this.el, this.arg, this.handler)
43
+ }
44
+ },
53
45
 
54
- unbind: function () {
55
- this.reset()
56
- this.el.removeEventListener('load', this.iframeBind)
46
+ reset: function () {
47
+ var el = this.iframeBind
48
+ ? this.el.contentWindow
49
+ : this.el
50
+ if (this.handler) {
51
+ _.off(el, this.arg, this.handler)
57
52
  }
53
+ },
54
+
55
+ unbind: function () {
56
+ this.reset()
57
+ _.off(this.el, 'load', this.iframeBind)
58
+ }
58
59
  }
@@ -1,50 +1,44 @@
1
- var utils = require('../utils')
1
+ var _ = require('../util')
2
+ var templateParser = require('../parsers/template')
3
+ var vIf = require('./if')
2
4
 
3
- /**
4
- * Binding for partials
5
- */
6
5
  module.exports = {
7
6
 
8
- isLiteral: true,
7
+ isLiteral: true,
9
8
 
10
- bind: function () {
9
+ // same logic reuse from v-if
10
+ compile: vIf.compile,
11
+ teardown: vIf.teardown,
11
12
 
12
- var id = this.expression
13
- if (!id) return
14
-
15
- var el = this.el,
16
- compiler = this.compiler,
17
- partial = compiler.getOption('partials', id)
18
-
19
- if (!partial) {
20
- if (id === 'yield') {
21
- utils.warn('{{>yield}} syntax has been deprecated. Use <content> tag instead.')
22
- }
23
- return
24
- }
25
-
26
- partial = partial.cloneNode(true)
27
-
28
- // comment ref node means inline partial
29
- if (el.nodeType === 8) {
30
-
31
- // keep a ref for the partial's content nodes
32
- var nodes = [].slice.call(partial.childNodes),
33
- parent = el.parentNode
34
- parent.insertBefore(partial, el)
35
- parent.removeChild(el)
36
- // compile partial after appending, because its children's parentNode
37
- // will change from the fragment to the correct parentNode.
38
- // This could affect directives that need access to its element's parentNode.
39
- nodes.forEach(compiler.compile, compiler)
40
-
41
- } else {
42
-
43
- // just set innerHTML...
44
- el.innerHTML = ''
45
- el.appendChild(partial)
46
-
47
- }
13
+ bind: function () {
14
+ var el = this.el
15
+ this.start = document.createComment('v-partial-start')
16
+ this.end = document.createComment('v-partial-end')
17
+ if (el.nodeType !== 8) {
18
+ el.innerHTML = ''
19
+ }
20
+ if (el.tagName === 'TEMPLATE' || el.nodeType === 8) {
21
+ _.replace(el, this.end)
22
+ } else {
23
+ el.appendChild(this.end)
24
+ }
25
+ _.before(this.start, this.end)
26
+ if (!this._isDynamicLiteral) {
27
+ this.insert(this.expression)
28
+ }
29
+ },
30
+
31
+ update: function (id) {
32
+ this.teardown()
33
+ this.insert(id)
34
+ },
35
+
36
+ insert: function (id) {
37
+ var partial = this.vm.$options.partials[id]
38
+ _.assertAsset(partial, 'partial', id)
39
+ if (partial) {
40
+ this.compile(templateParser.parse(partial))
48
41
  }
42
+ }
49
43
 
50
44
  }
@@ -0,0 +1,24 @@
1
+ var _ = require('../util')
2
+
3
+ module.exports = {
4
+
5
+ isLiteral: true,
6
+
7
+ bind: function () {
8
+ if (this.el !== this.vm.$el) {
9
+ _.warn(
10
+ 'v-ref should only be used on instance root nodes.'
11
+ )
12
+ return
13
+ }
14
+ this.owner = this.vm.$parent
15
+ this.owner.$[this.expression] = this.vm
16
+ },
17
+
18
+ unbind: function () {
19
+ if (this.owner.$[this.expression] === this.vm) {
20
+ delete this.owner.$[this.expression]
21
+ }
22
+ }
23
+
24
+ }
@@ -1,246 +1,497 @@
1
- var utils = require('../utils'),
2
- config = require('../config')
1
+ var _ = require('../util')
2
+ var isObject = _.isObject
3
+ var textParser = require('../parsers/text')
4
+ var expParser = require('../parsers/expression')
5
+ var templateParser = require('../parsers/template')
6
+ var compile = require('../compiler/compile')
7
+ var transclude = require('../compiler/transclude')
8
+ var mergeOptions = require('../util/merge-option')
9
+ var uid = 0
3
10
 
4
- /**
5
- * Binding that manages VMs based on an Array
6
- */
7
11
  module.exports = {
8
12
 
9
- bind: function () {
10
-
11
- this.identifier = '$r' + this.id
12
-
13
- // a hash to cache the same expressions on repeated instances
14
- // so they don't have to be compiled for every single instance
15
- this.expCache = utils.hash()
16
-
17
- var el = this.el,
18
- ctn = this.container = el.parentNode
19
-
20
- // extract child Id, if any
21
- this.childId = this.compiler.eval(utils.attr(el, 'ref'))
22
-
23
- // create a comment node as a reference node for DOM insertions
24
- this.ref = document.createComment(config.prefix + '-repeat-' + this.key)
25
- ctn.insertBefore(this.ref, el)
26
- ctn.removeChild(el)
27
-
28
- this.collection = null
29
- this.vms = null
30
-
31
- },
32
-
33
- update: function (collection) {
34
-
35
- if (!Array.isArray(collection)) {
36
- if (utils.isObject(collection)) {
37
- collection = utils.objectToArray(collection)
38
- } else {
39
- utils.warn('v-repeat only accepts Array or Object values.')
40
- }
13
+ /**
14
+ * Setup.
15
+ */
16
+
17
+ bind: function () {
18
+ // uid as a cache identifier
19
+ this.id = '__v_repeat_' + (++uid)
20
+ // we need to insert the objToArray converter
21
+ // as the first read filter.
22
+ if (!this.filters) {
23
+ this.filters = {}
24
+ }
25
+ // add the object -> array convert filter
26
+ var objectConverter = _.bind(objToArray, this)
27
+ if (!this.filters.read) {
28
+ this.filters.read = [objectConverter]
29
+ } else {
30
+ this.filters.read.unshift(objectConverter)
31
+ }
32
+ // setup ref node
33
+ this.ref = document.createComment('v-repeat')
34
+ _.replace(this.el, this.ref)
35
+ // check if this is a block repeat
36
+ this.template = this.el.tagName === 'TEMPLATE'
37
+ ? templateParser.parse(this.el, true)
38
+ : this.el
39
+ // check other directives that need to be handled
40
+ // at v-repeat level
41
+ this.checkIf()
42
+ this.checkRef()
43
+ this.checkComponent()
44
+ // check for trackby param
45
+ this.idKey =
46
+ this._checkParam('track-by') ||
47
+ this._checkParam('trackby') // 0.11.0 compat
48
+ // cache for primitive value instances
49
+ this.cache = Object.create(null)
50
+ },
51
+
52
+ /**
53
+ * Warn against v-if usage.
54
+ */
55
+
56
+ checkIf: function () {
57
+ if (_.attr(this.el, 'if') !== null) {
58
+ _.warn(
59
+ 'Don\'t use v-if with v-repeat. ' +
60
+ 'Use v-show or the "filterBy" filter instead.'
61
+ )
62
+ }
63
+ },
64
+
65
+ /**
66
+ * Check if v-ref/ v-el is also present.
67
+ */
68
+
69
+ checkRef: function () {
70
+ var childId = _.attr(this.el, 'ref')
71
+ this.childId = childId
72
+ ? this.vm.$interpolate(childId)
73
+ : null
74
+ var elId = _.attr(this.el, 'el')
75
+ this.elId = elId
76
+ ? this.vm.$interpolate(elId)
77
+ : null
78
+ },
79
+
80
+ /**
81
+ * Check the component constructor to use for repeated
82
+ * instances. If static we resolve it now, otherwise it
83
+ * needs to be resolved at build time with actual data.
84
+ */
85
+
86
+ checkComponent: function () {
87
+ var id = _.attr(this.el, 'component')
88
+ var options = this.vm.$options
89
+ if (!id) {
90
+ this.Ctor = _.Vue // default constructor
91
+ this.inherit = true // inline repeats should inherit
92
+ // important: transclude with no options, just
93
+ // to ensure block start and block end
94
+ this.template = transclude(this.template)
95
+ this._linker = compile(this.template, options)
96
+ } else {
97
+ var tokens = textParser.parse(id)
98
+ if (!tokens) { // static component
99
+ var Ctor = this.Ctor = options.components[id]
100
+ _.assertAsset(Ctor, 'component', id)
101
+ if (Ctor) {
102
+ // merge an empty object with owner vm as parent
103
+ // so child vms can access parent assets.
104
+ var merged = mergeOptions(
105
+ Ctor.options,
106
+ {},
107
+ { $parent: this.vm }
108
+ )
109
+ this.template = transclude(this.template, merged)
110
+ this._linker = compile(this.template, merged)
41
111
  }
42
-
43
- // keep reference of old data and VMs
44
- // so we can reuse them if possible
45
- this.oldVMs = this.vms
46
- this.oldCollection = this.collection
47
- collection = this.collection = collection || []
48
-
49
- var isObject = collection[0] && utils.isObject(collection[0])
50
- this.vms = this.oldCollection
51
- ? this.diff(collection, isObject)
52
- : this.init(collection, isObject)
53
-
54
- if (this.childId) {
55
- this.vm.$[this.childId] = this.vms
112
+ } else {
113
+ // to be resolved later
114
+ var ctorExp = textParser.tokensToExp(tokens)
115
+ this.ctorGetter = expParser.parse(ctorExp).get
116
+ }
117
+ }
118
+ },
119
+
120
+ /**
121
+ * Update.
122
+ * This is called whenever the Array mutates.
123
+ *
124
+ * @param {Array} data
125
+ */
126
+
127
+ update: function (data) {
128
+ if (typeof data === 'number') {
129
+ data = range(data)
130
+ }
131
+ this.vms = this.diff(data || [], this.vms)
132
+ // update v-ref
133
+ if (this.childId) {
134
+ this.vm.$[this.childId] = this.vms
135
+ }
136
+ if (this.elId) {
137
+ this.vm.$$[this.elId] = this.vms.map(function (vm) {
138
+ return vm.$el
139
+ })
140
+ }
141
+ },
142
+
143
+ /**
144
+ * Diff, based on new data and old data, determine the
145
+ * minimum amount of DOM manipulations needed to make the
146
+ * DOM reflect the new data Array.
147
+ *
148
+ * The algorithm diffs the new data Array by storing a
149
+ * hidden reference to an owner vm instance on previously
150
+ * seen data. This allows us to achieve O(n) which is
151
+ * better than a levenshtein distance based algorithm,
152
+ * which is O(m * n).
153
+ *
154
+ * @param {Array} data
155
+ * @param {Array} oldVms
156
+ * @return {Array}
157
+ */
158
+
159
+ diff: function (data, oldVms) {
160
+ var idKey = this.idKey
161
+ var converted = this.converted
162
+ var ref = this.ref
163
+ var alias = this.arg
164
+ var init = !oldVms
165
+ var vms = new Array(data.length)
166
+ var obj, raw, vm, i, l
167
+ // First pass, go through the new Array and fill up
168
+ // the new vms array. If a piece of data has a cached
169
+ // instance for it, we reuse it. Otherwise build a new
170
+ // instance.
171
+ for (i = 0, l = data.length; i < l; i++) {
172
+ obj = data[i]
173
+ raw = converted ? obj.value : obj
174
+ vm = !init && this.getVm(raw)
175
+ if (vm) { // reusable instance
176
+ vm._reused = true
177
+ vm.$index = i // update $index
178
+ if (converted) {
179
+ vm.$key = obj.key // update $key
56
180
  }
57
-
58
- },
59
-
60
- init: function (collection, isObject) {
61
- var vm, vms = []
62
- for (var i = 0, l = collection.length; i < l; i++) {
63
- vm = this.build(collection[i], i, isObject)
64
- vms.push(vm)
65
- if (this.compiler.init) {
66
- this.container.insertBefore(vm.$el, this.ref)
67
- } else {
68
- vm.$before(this.ref)
69
- }
181
+ if (idKey) { // swap track by id data
182
+ if (alias) {
183
+ vm[alias] = raw
184
+ } else {
185
+ vm._setData(raw)
186
+ }
70
187
  }
71
- return vms
72
- },
73
-
74
- /**
75
- * Diff the new array with the old
76
- * and determine the minimum amount of DOM manipulations.
77
- */
78
- diff: function (newCollection, isObject) {
79
-
80
- var i, l, item, vm,
81
- oldIndex,
82
- targetNext,
83
- currentNext,
84
- nextEl,
85
- ctn = this.container,
86
- oldVMs = this.oldVMs,
87
- vms = []
88
-
89
- vms.length = newCollection.length
90
-
91
- // first pass, collect new reused and new created
92
- for (i = 0, l = newCollection.length; i < l; i++) {
93
- item = newCollection[i]
94
- if (isObject) {
95
- item.$index = i
96
- if (item.__emitter__ && item.__emitter__[this.identifier]) {
97
- // this piece of data is being reused.
98
- // record its final position in reused vms
99
- item.$reused = true
100
- } else {
101
- vms[i] = this.build(item, i, isObject)
102
- }
103
- } else {
104
- // we can't attach an identifier to primitive values
105
- // so have to do an indexOf...
106
- oldIndex = indexOf(oldVMs, item)
107
- if (oldIndex > -1) {
108
- // record the position on the existing vm
109
- oldVMs[oldIndex].$reused = true
110
- oldVMs[oldIndex].$data.$index = i
111
- } else {
112
- vms[i] = this.build(item, i, isObject)
113
- }
114
- }
188
+ } else { // new instance
189
+ vm = this.build(obj, i)
190
+ vm._new = true
191
+ }
192
+ vms[i] = vm
193
+ // insert if this is first run
194
+ if (init) {
195
+ vm.$before(ref)
196
+ }
197
+ }
198
+ // if this is the first run, we're done.
199
+ if (init) {
200
+ return vms
201
+ }
202
+ // Second pass, go through the old vm instances and
203
+ // destroy those who are not reused (and remove them
204
+ // from cache)
205
+ for (i = 0, l = oldVms.length; i < l; i++) {
206
+ vm = oldVms[i]
207
+ if (!vm._reused) {
208
+ this.uncacheVm(vm)
209
+ vm.$destroy(true)
210
+ }
211
+ }
212
+ // final pass, move/insert new instances into the
213
+ // right place. We're going in reverse here because
214
+ // insertBefore relies on the next sibling to be
215
+ // resolved.
216
+ var targetNext, currentNext
217
+ i = vms.length
218
+ while (i--) {
219
+ vm = vms[i]
220
+ // this is the vm that we should be in front of
221
+ targetNext = vms[i + 1]
222
+ if (!targetNext) {
223
+ // This is the last item. If it's reused then
224
+ // everything else will eventually be in the right
225
+ // place, so no need to touch it. Otherwise, insert
226
+ // it.
227
+ if (!vm._reused) {
228
+ vm.$before(ref)
115
229
  }
116
-
117
- // second pass, collect old reused and destroy unused
118
- for (i = 0, l = oldVMs.length; i < l; i++) {
119
- vm = oldVMs[i]
120
- item = this.arg
121
- ? vm.$data[this.arg]
122
- : vm.$data
123
- if (item.$reused) {
124
- vm.$reused = true
125
- delete item.$reused
126
- }
127
- if (vm.$reused) {
128
- // update the index to latest
129
- vm.$index = item.$index
130
- // the item could have had a new key
131
- if (item.$key && item.$key !== vm.$key) {
132
- vm.$key = item.$key
133
- }
134
- vms[vm.$index] = vm
135
- } else {
136
- // this one can be destroyed.
137
- if (item.__emitter__) {
138
- delete item.__emitter__[this.identifier]
139
- }
140
- vm.$destroy()
141
- }
230
+ } else {
231
+ if (vm._reused) {
232
+ // this is the vm we are actually in front of
233
+ currentNext = findNextVm(vm, ref)
234
+ // we only need to move if we are not in the right
235
+ // place already.
236
+ if (currentNext !== targetNext) {
237
+ vm.$before(targetNext.$el, null, false)
238
+ }
239
+ } else {
240
+ // new instance, insert to existing next
241
+ vm.$before(targetNext.$el)
142
242
  }
143
-
144
- // final pass, move/insert DOM elements
145
- i = vms.length
146
- while (i--) {
147
- vm = vms[i]
148
- item = vm.$data
149
- targetNext = vms[i + 1]
150
- if (vm.$reused) {
151
- nextEl = vm.$el.nextSibling
152
- // destroyed VMs' element might still be in the DOM
153
- // due to transitions
154
- while (!nextEl.vue_vm && nextEl !== this.ref) {
155
- nextEl = nextEl.nextSibling
156
- }
157
- currentNext = nextEl.vue_vm
158
- if (currentNext !== targetNext) {
159
- if (!targetNext) {
160
- ctn.insertBefore(vm.$el, this.ref)
161
- } else {
162
- nextEl = targetNext.$el
163
- // new VMs' element might not be in the DOM yet
164
- // due to transitions
165
- while (!nextEl.parentNode) {
166
- targetNext = vms[nextEl.vue_vm.$index + 1]
167
- nextEl = targetNext
168
- ? targetNext.$el
169
- : this.ref
170
- }
171
- ctn.insertBefore(vm.$el, nextEl)
172
- }
173
- }
174
- delete vm.$reused
175
- delete item.$index
176
- delete item.$key
177
- } else { // a new vm
178
- vm.$before(targetNext ? targetNext.$el : this.ref)
179
- }
243
+ }
244
+ vm._new = false
245
+ vm._reused = false
246
+ }
247
+ return vms
248
+ },
249
+
250
+ /**
251
+ * Build a new instance and cache it.
252
+ *
253
+ * @param {Object} data
254
+ * @param {Number} index
255
+ */
256
+
257
+ build: function (data, index) {
258
+ var original = data
259
+ var meta = { $index: index }
260
+ if (this.converted) {
261
+ meta.$key = original.key
262
+ }
263
+ var raw = this.converted ? data.value : data
264
+ var alias = this.arg
265
+ var hasAlias = !isObject(raw) || alias
266
+ // wrap the raw data with alias
267
+ data = hasAlias ? {} : raw
268
+ if (alias) {
269
+ data[alias] = raw
270
+ } else if (hasAlias) {
271
+ meta.$value = raw
272
+ }
273
+ // resolve constructor
274
+ var Ctor = this.Ctor || this.resolveCtor(data, meta)
275
+ var vm = this.vm.$addChild({
276
+ el: templateParser.clone(this.template),
277
+ _linker: this._linker,
278
+ _meta: meta,
279
+ data: data,
280
+ inherit: this.inherit
281
+ }, Ctor)
282
+ // cache instance
283
+ this.cacheVm(raw, vm)
284
+ return vm
285
+ },
286
+
287
+ /**
288
+ * Resolve a contructor to use for an instance.
289
+ * The tricky part here is that there could be dynamic
290
+ * components depending on instance data.
291
+ *
292
+ * @param {Object} data
293
+ * @param {Object} meta
294
+ * @return {Function}
295
+ */
296
+
297
+ resolveCtor: function (data, meta) {
298
+ // create a temporary context object and copy data
299
+ // and meta properties onto it.
300
+ // use _.define to avoid accidentally overwriting scope
301
+ // properties.
302
+ var context = Object.create(this.vm)
303
+ var key
304
+ for (key in data) {
305
+ _.define(context, key, data[key])
306
+ }
307
+ for (key in meta) {
308
+ _.define(context, key, meta[key])
309
+ }
310
+ var id = this.ctorGetter.call(context, context)
311
+ var Ctor = this.vm.$options.components[id]
312
+ _.assertAsset(Ctor, 'component', id)
313
+ return Ctor
314
+ },
315
+
316
+ /**
317
+ * Unbind, teardown everything
318
+ */
319
+
320
+ unbind: function () {
321
+ if (this.childId) {
322
+ delete this.vm.$[this.childId]
323
+ }
324
+ if (this.vms) {
325
+ var i = this.vms.length
326
+ var vm
327
+ while (i--) {
328
+ vm = this.vms[i]
329
+ this.uncacheVm(vm)
330
+ vm.$destroy()
331
+ }
332
+ }
333
+ },
334
+
335
+ /**
336
+ * Cache a vm instance based on its data.
337
+ *
338
+ * If the data is an object, we save the vm's reference on
339
+ * the data object as a hidden property. Otherwise we
340
+ * cache them in an object and for each primitive value
341
+ * there is an array in case there are duplicates.
342
+ *
343
+ * @param {Object} data
344
+ * @param {Vue} vm
345
+ */
346
+
347
+ cacheVm: function (data, vm) {
348
+ var idKey = this.idKey
349
+ var cache = this.cache
350
+ var id
351
+ if (idKey) {
352
+ id = data[idKey]
353
+ if (!cache[id]) {
354
+ cache[id] = vm
355
+ } else {
356
+ _.warn('Duplicate ID in v-repeat: ' + id)
357
+ }
358
+ } else if (isObject(data)) {
359
+ id = this.id
360
+ if (data.hasOwnProperty(id)) {
361
+ if (data[id] === null) {
362
+ data[id] = vm
363
+ } else {
364
+ _.warn(
365
+ 'Duplicate objects are not supported in v-repeat.'
366
+ )
180
367
  }
368
+ } else {
369
+ _.define(data, this.id, vm)
370
+ }
371
+ } else {
372
+ if (!cache[data]) {
373
+ cache[data] = [vm]
374
+ } else {
375
+ cache[data].push(vm)
376
+ }
377
+ }
378
+ vm._raw = data
379
+ },
380
+
381
+ /**
382
+ * Try to get a cached instance from a piece of data.
383
+ *
384
+ * @param {Object} data
385
+ * @return {Vue|undefined}
386
+ */
387
+
388
+ getVm: function (data) {
389
+ if (this.idKey) {
390
+ return this.cache[data[this.idKey]]
391
+ } else if (isObject(data)) {
392
+ return data[this.id]
393
+ } else {
394
+ var cached = this.cache[data]
395
+ if (cached) {
396
+ var i = 0
397
+ var vm = cached[i]
398
+ // since duplicated vm instances might be a reused
399
+ // one OR a newly created one, we need to return the
400
+ // first instance that is neither of these.
401
+ while (vm && (vm._reused || vm._new)) {
402
+ vm = cached[++i]
403
+ }
404
+ return vm
405
+ }
406
+ }
407
+ },
408
+
409
+ /**
410
+ * Delete a cached vm instance.
411
+ *
412
+ * @param {Vue} vm
413
+ */
414
+
415
+ uncacheVm: function (vm) {
416
+ var data = vm._raw
417
+ if (this.idKey) {
418
+ this.cache[data[this.idKey]] = null
419
+ } else if (isObject(data)) {
420
+ data[this.id] = null
421
+ vm._raw = null
422
+ } else {
423
+ this.cache[data].pop()
424
+ }
425
+ }
181
426
 
182
- return vms
183
- },
184
-
185
- build: function (data, index, isObject) {
427
+ }
186
428
 
187
- // wrap non-object values
188
- var raw, alias,
189
- wrap = !isObject || this.arg
190
- if (wrap) {
191
- raw = data
192
- alias = this.arg || '$value'
193
- data = {}
194
- data[alias] = raw
195
- }
196
- data.$index = index
197
-
198
- var el = this.el.cloneNode(true),
199
- Ctor = this.compiler.resolveComponent(el, data),
200
- vm = new Ctor({
201
- el: el,
202
- data: data,
203
- parent: this.vm,
204
- compilerOptions: {
205
- repeat: true,
206
- expCache: this.expCache
207
- }
208
- })
209
-
210
- if (isObject) {
211
- // attach an ienumerable identifier to the raw data
212
- (raw || data).__emitter__[this.identifier] = true
213
- }
429
+ /**
430
+ * Helper to find the next element that is an instance
431
+ * root node. This is necessary because a destroyed vm's
432
+ * element could still be lingering in the DOM before its
433
+ * leaving transition finishes, but its __vue__ reference
434
+ * should have been removed so we can skip them.
435
+ *
436
+ * @param {Vue} vm
437
+ * @param {CommentNode} ref
438
+ * @return {Vue}
439
+ */
214
440
 
215
- return vm
441
+ function findNextVm (vm, ref) {
442
+ var el = (vm._blockEnd || vm.$el).nextSibling
443
+ while (!el.__vue__ && el !== ref) {
444
+ el = el.nextSibling
445
+ }
446
+ return el.__vue__
447
+ }
216
448
 
217
- },
449
+ /**
450
+ * Attempt to convert non-Array objects to array.
451
+ * This is the default filter installed to every v-repeat
452
+ * directive.
453
+ *
454
+ * It will be called with **the directive** as `this`
455
+ * context so that we can mark the repeat array as converted
456
+ * from an object.
457
+ *
458
+ * @param {*} obj
459
+ * @return {Array}
460
+ * @private
461
+ */
218
462
 
219
- unbind: function () {
220
- if (this.childId) {
221
- delete this.vm.$[this.childId]
222
- }
223
- if (this.vms) {
224
- var i = this.vms.length
225
- while (i--) {
226
- this.vms[i].$destroy()
227
- }
228
- }
463
+ function objToArray (obj) {
464
+ if (!_.isPlainObject(obj)) {
465
+ return obj
466
+ }
467
+ var keys = Object.keys(obj)
468
+ var i = keys.length
469
+ var res = new Array(i)
470
+ var key
471
+ while (i--) {
472
+ key = keys[i]
473
+ res[i] = {
474
+ key: key,
475
+ value: obj[key]
229
476
  }
477
+ }
478
+ // `this` points to the repeat directive instance
479
+ this.converted = true
480
+ return res
230
481
  }
231
482
 
232
- // Helpers --------------------------------------------------------------------
233
-
234
483
  /**
235
- * Find an object or a wrapped data object
236
- * from an Array
484
+ * Create a range array from given number.
485
+ *
486
+ * @param {Number} n
487
+ * @return {Array}
237
488
  */
238
- function indexOf (vms, obj) {
239
- for (var vm, i = 0, l = vms.length; i < l; i++) {
240
- vm = vms[i]
241
- if (!vm.$reused && vm.$value === obj) {
242
- return i
243
- }
244
- }
245
- return -1
489
+
490
+ function range (n) {
491
+ var i = -1
492
+ var ret = new Array(n)
493
+ while (++i < n) {
494
+ ret[i] = i
495
+ }
496
+ return ret
246
497
  }