From 29a704cd0c43e3a65db6685bfd4cf1188fb4d8ad Mon Sep 17 00:00:00 2001 From: Paul Pflugradt Date: Sun, 3 Apr 2016 12:59:10 +0200 Subject: [PATCH 1/6] WIP: plugin param for slot --- src/directives/element/slot.js | 38 +++++++++++++++++-- .../specs/directives/element/slot_spec.js | 30 +++++++++++++++ 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/src/directives/element/slot.js b/src/directives/element/slot.js index cb9aa6d8394..8597bc93781 100644 --- a/src/directives/element/slot.js +++ b/src/directives/element/slot.js @@ -2,13 +2,14 @@ import { SLOT } from '../priorities' import { extractContent, replace, - remove + remove, + defineReactive } from '../../util/index' export default { priority: SLOT, - params: ['name'], + params: ['name','plugin'], bind () { // this was resolved during component transclusion @@ -38,9 +39,40 @@ export default { elseBlock._context = this.vm content.appendChild(elseBlock) } - const scope = host + let scope = host ? host._scope : this._scope + + if (this.params.plugin) { + // copy all remaining attributes from slot to all direct children + let attrs = this.el.attributes + for(let i = attrs.length - 1; i >= 0; i--) { + let name = attrs[i].name, + value = attrs[i].value, + children = content.children + // prefix value + // TODO properly handle v-bind + if (name[0]===':') { + value = '__'+value + } + for(let j = 0, len = children.length; j < len; j++) { + // TODO warn if child can't have attributes? + children[j].setAttribute(name,value) + } + } + if (!scope) { + scope = {} + } + // add all data from context to scope + for(let data in context._data) { + defineReactive(scope,data,context._data[data]) + } + // add all data from host to scope with prefixed names + for(let data in host._data) { + defineReactive(scope,'__'+data,host._data[data]) + } + } + this.unlink = context.$compile( content, host, scope, this._frag ) diff --git a/test/unit/specs/directives/element/slot_spec.js b/test/unit/specs/directives/element/slot_spec.js index 1007c4d1016..32d4ac2a87a 100644 --- a/test/unit/specs/directives/element/slot_spec.js +++ b/test/unit/specs/directives/element/slot_spec.js @@ -457,4 +457,34 @@ describe('Slot Distribution', function () { }) expect('"slot" attribute must be static').toHaveBeenWarned() }) + + it('plugin directive', function () { + console.log("---------------------------------") + var vm = new Vue({ + el: el, + template: '{{text}}', + data: { + text:'main' + }, + components: { + comp1: { + template: '
', + data: function(){ + return { + text:'comp1' + } + } + }, + comp2: { + props: { + text: { + type: String + } + }, + template: '
{{text}}
' + } + } + }) + expect(vm.$el.textContent).toBe('comp1main') + }) }) From 15072ef2d6b5ec25f2a6f12a014bb18ef63d38db Mon Sep 17 00:00:00 2001 From: Paul Pflugradt Date: Sun, 3 Apr 2016 13:15:56 +0200 Subject: [PATCH 2/6] added tests for slot child relations --- .../specs/directives/element/slot_spec.js | 55 ++++++++++++++++++- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/test/unit/specs/directives/element/slot_spec.js b/test/unit/specs/directives/element/slot_spec.js index 32d4ac2a87a..5f54c2f110d 100644 --- a/test/unit/specs/directives/element/slot_spec.js +++ b/test/unit/specs/directives/element/slot_spec.js @@ -458,8 +458,7 @@ describe('Slot Distribution', function () { expect('"slot" attribute must be static').toHaveBeenWarned() }) - it('plugin directive', function () { - console.log("---------------------------------") + it('plugin directive - scoped data', function () { var vm = new Vue({ el: el, template: '{{text}}', @@ -487,4 +486,56 @@ describe('Slot Distribution', function () { }) expect(vm.$el.textContent).toBe('comp1main') }) + + it('plugin directive - child relations', function () { + var vm = new Vue({ + el: el, + template: '', + data: { + text:'main' + }, + components: { + comp1: { + template: '
', + components: { + comp11: { + template: '
' + } + } + }, + comp2: { + template: '
' + } + } + }) + expect(vm.$children[0].$children.length).toBe(1) + expect(vm.$children[0].$children[0].$options.name).toBe("comp11") + expect(vm.$children[0].$children[0].$children[0].$options.name).toBe("comp2") + }) + + it('child relations', function () { + var vm = new Vue({ + el: el, + template: '', + data: { + text:'main' + }, + components: { + comp1: { + template: '
', + components: { + comp11: { + template: '
' + } + } + }, + comp2: { + template: '
' + } + } + }) + expect(vm.$children[0].$children.length).toBe(2) + expect(vm.$children[0].$children[0].$children.length).toBe(0) + expect(vm.$children[0].$children[1].$children.length).toBe(0) + }) }) From ea2bfaa204e0e2fa3a5558722415f81220d5b208 Mon Sep 17 00:00:00 2001 From: Paul Pflugradt Date: Sun, 3 Apr 2016 15:51:02 +0200 Subject: [PATCH 3/6] added test and first though for v-for behavior --- src/directives/element/slot.js | 7 +++++ .../specs/directives/element/slot_spec.js | 30 ++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/directives/element/slot.js b/src/directives/element/slot.js index 8597bc93781..994e9dbbd49 100644 --- a/src/directives/element/slot.js +++ b/src/directives/element/slot.js @@ -44,6 +44,7 @@ export default { : this._scope if (this.params.plugin) { + console.log(this) // copy all remaining attributes from slot to all direct children let attrs = this.el.attributes for(let i = attrs.length - 1; i >= 0; i--) { @@ -55,6 +56,7 @@ export default { if (name[0]===':') { value = '__'+value } + // TODO properly handle v-on for(let j = 0, len = children.length; j < len; j++) { // TODO warn if child can't have attributes? children[j].setAttribute(name,value) @@ -71,6 +73,11 @@ export default { for(let data in host._data) { defineReactive(scope,'__'+data,host._data[data]) } + // add all data from v-for + if (this._frag) { + // TODO how to get the data out of the v-for scope? + defineReactive(scope,'__item',this._frag.scope.item) + } } this.unlink = context.$compile( diff --git a/test/unit/specs/directives/element/slot_spec.js b/test/unit/specs/directives/element/slot_spec.js index 5f54c2f110d..11e93bf1865 100644 --- a/test/unit/specs/directives/element/slot_spec.js +++ b/test/unit/specs/directives/element/slot_spec.js @@ -522,7 +522,7 @@ describe('Slot Distribution', function () { }, components: { comp1: { - template: '
', + template: '
', components: { comp11: { template: '
' @@ -538,4 +538,32 @@ describe('Slot Distribution', function () { expect(vm.$children[0].$children[0].$children.length).toBe(0) expect(vm.$children[0].$children[1].$children.length).toBe(0) }) + + it('plugin directive - v-for', function () { + var vm = new Vue({ + el: el, + template: '', + data: { + text:'main' + }, + components: { + comp1: { + template: '
', + data: function() { + return {data:[{name:"foo"},{name:"bar"}]} + } + }, + comp2: { + props: { + item: { + type: Object + } + }, + template: '
{{item.name}}
' + } + } + }) + console.log(vm.$el) + expect(vm.$el.textContent).toBe('foobar') + }) }) From 77c359f7900cba01397664cc32466e8a33e8fa35 Mon Sep 17 00:00:00 2001 From: Paul Pflugradt Date: Tue, 5 Apr 2016 03:15:09 +0200 Subject: [PATCH 4/6] some small improvements --- src/directives/element/slot.js | 50 +++-- .../specs/directives/element/slot_spec.js | 183 +++++++++++------- 2 files changed, 130 insertions(+), 103 deletions(-) diff --git a/src/directives/element/slot.js b/src/directives/element/slot.js index 994e9dbbd49..b8d4a2aca84 100644 --- a/src/directives/element/slot.js +++ b/src/directives/element/slot.js @@ -9,14 +9,14 @@ import { export default { priority: SLOT, - params: ['name','plugin'], + params: ['name','plugin',''], bind () { // this was resolved during component transclusion var name = this.params.name || 'default' var content = this.vm._slotContents && this.vm._slotContents[name] if (!content || !content.hasChildNodes()) { - this.fallback() + this.compile(extractContent(this.el, true), this.vm) } else { this.compile(content.cloneNode(true), this.vm._context, this.vm) } @@ -44,45 +44,43 @@ export default { : this._scope if (this.params.plugin) { - console.log(this) + if (!host) { + // TODO warn to use plugin only within components + } // copy all remaining attributes from slot to all direct children let attrs = this.el.attributes for(let i = attrs.length - 1; i >= 0; i--) { let name = attrs[i].name, value = attrs[i].value, children = content.children - // prefix value - // TODO properly handle v-bind - if (name[0]===':') { - value = '__'+value - } - // TODO properly handle v-on for(let j = 0, len = children.length; j < len; j++) { // TODO warn if child can't have attributes? - children[j].setAttribute(name,value) + if (!(children[j].hasAttribute(name) || + (name[0]===':' && children[j].hasAttribute('v-bind'+name)) || + (name[0]==='@' && children[j].hasAttribute('v-on:'+name.slice(1))) + )) { + children[j].setAttribute(name,value) + } } } - if (!scope) { - scope = {} - } + // use v-for scope when available + scope = this._frag ? this._frag.scope : scope || {} + // add all data from context to scope for(let data in context._data) { - defineReactive(scope,data,context._data[data]) + if (scope[data] == null) { + defineReactive(scope,data,context._data[data]) + } } // add all data from host to scope with prefixed names for(let data in host._data) { - defineReactive(scope,'__'+data,host._data[data]) - } - // add all data from v-for - if (this._frag) { - // TODO how to get the data out of the v-for scope? - defineReactive(scope,'__item',this._frag.scope.item) + defineReactive(scope,'_'+data,host._data[data]) } + // child relations test: how to get the slot content to be comp11 child? + this.unlink = context.$compile(content, host, scope, this._frag) + } else { + this.unlink = context.$compile(content, host, scope, this._frag) } - - this.unlink = context.$compile( - content, host, scope, this._frag - ) } if (content) { replace(this.el, content) @@ -91,10 +89,6 @@ export default { } }, - fallback () { - this.compile(extractContent(this.el, true), this.vm) - }, - unbind () { if (this.unlink) { this.unlink() diff --git a/test/unit/specs/directives/element/slot_spec.js b/test/unit/specs/directives/element/slot_spec.js index 11e93bf1865..a160c9135ef 100644 --- a/test/unit/specs/directives/element/slot_spec.js +++ b/test/unit/specs/directives/element/slot_spec.js @@ -458,61 +458,6 @@ describe('Slot Distribution', function () { expect('"slot" attribute must be static').toHaveBeenWarned() }) - it('plugin directive - scoped data', function () { - var vm = new Vue({ - el: el, - template: '{{text}}', - data: { - text:'main' - }, - components: { - comp1: { - template: '
', - data: function(){ - return { - text:'comp1' - } - } - }, - comp2: { - props: { - text: { - type: String - } - }, - template: '
{{text}}
' - } - } - }) - expect(vm.$el.textContent).toBe('comp1main') - }) - - it('plugin directive - child relations', function () { - var vm = new Vue({ - el: el, - template: '', - data: { - text:'main' - }, - components: { - comp1: { - template: '
', - components: { - comp11: { - template: '
' - } - } - }, - comp2: { - template: '
' - } - } - }) - expect(vm.$children[0].$children.length).toBe(1) - expect(vm.$children[0].$children[0].$options.name).toBe("comp11") - expect(vm.$children[0].$children[0].$children[0].$options.name).toBe("comp2") - }) - it('child relations', function () { var vm = new Vue({ el: el, @@ -539,31 +484,119 @@ describe('Slot Distribution', function () { expect(vm.$children[0].$children[1].$children.length).toBe(0) }) - it('plugin directive - v-for', function () { - var vm = new Vue({ - el: el, - template: '', - data: { - text:'main' - }, - components: { - comp1: { - template: '
', - data: function() { - return {data:[{name:"foo"},{name:"bar"}]} + + describe('plugin directive', function() { + + it('scoped data', function () { + var vm = new Vue({ + el: el, + template: '{{text}}', + data: { + text:'main' + }, + components: { + comp1: { + template: '
', + data: function(){ + return { + text:'comp1' + } } + }, + comp2: { + props: { + text: { + type: String + } + }, + template: '
{{text}}
' + } + } + }) + expect(vm.$el.textContent).toBe('comp1main') + }) + + it('scoped data hierarchy', function () { + var vm = new Vue({ + el: el, + template: '{{text}}', + data: { + text:'main' }, - comp2: { - props: { - item: { - type: Object + components: { + comp1: { + template: '
', + data: function(){ + return { + text:'comp1' + } } }, - template: '
{{item.name}}
' + comp2: { + props: { + text: { + type: String + } + }, + template: '
{{text}}
' + } } - } + }) + expect(vm.$el.textContent).toBe('mainmain') + }) + + it('child relations', function () { + var vm = new Vue({ + el: el, + template: '', + data: { + text:'main' + }, + components: { + comp1: { + template: '
', + components: { + comp11: { + template: '
' + } + } + }, + comp2: { + template: '
' + } + } + }) + expect(vm.$children[0].$children.length).toBe(1) + expect(vm.$children[0].$children[0].$options.name).toBe("comp11") + expect(vm.$children[0].$children[0].$children[0].$options.name).toBe("comp2") + }) + + it('v-for', function () { + var vm = new Vue({ + el: el, + template: '', + data: { + text:'main' + }, + components: { + comp1: { + template: '
', + data: function() { + return {data:[{name:"foo"},{name:"bar"}]} + } + }, + comp2: { + props: { + item: { + type: Object + } + }, + template: '
{{item.name}}
' + } + } + }) + expect(vm.$el.textContent).toBe('foobar') }) - console.log(vm.$el) - expect(vm.$el.textContent).toBe('foobar') }) + }) From af2db5745e9c68609b3e6750266b0c78b0d9d298 Mon Sep 17 00:00:00 2001 From: Paul Pflugradt Date: Tue, 5 Apr 2016 03:34:37 +0200 Subject: [PATCH 5/6] added test for validating plugin child --- src/directives/element/slot.js | 6 +++++- .../specs/directives/element/slot_spec.js | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/directives/element/slot.js b/src/directives/element/slot.js index b8d4a2aca84..a2b1312890b 100644 --- a/src/directives/element/slot.js +++ b/src/directives/element/slot.js @@ -9,7 +9,7 @@ import { export default { priority: SLOT, - params: ['name','plugin',''], + params: ['name','plugin'], bind () { // this was resolved during component transclusion @@ -78,6 +78,10 @@ export default { } // child relations test: how to get the slot content to be comp11 child? this.unlink = context.$compile(content, host, scope, this._frag) + if (this.params.plugin !== true) { + // should check on the newly created vm if it is valid + } + } else { this.unlink = context.$compile(content, host, scope, this._frag) } diff --git a/test/unit/specs/directives/element/slot_spec.js b/test/unit/specs/directives/element/slot_spec.js index a160c9135ef..1cea4affdef 100644 --- a/test/unit/specs/directives/element/slot_spec.js +++ b/test/unit/specs/directives/element/slot_spec.js @@ -597,6 +597,25 @@ describe('Slot Distribution', function () { }) expect(vm.$el.textContent).toBe('foobar') }) + + it('validate child', function () { + var vm = new Vue({ + el: el, + template: '', + data: { + text:'main' + }, + components: { + comp1: { + template: '
' + }, + comp2: { + template: '
foo
' + } + } + }) + expect(vm.$el.textContent).toBe('') + }) }) }) From ee986470364a5e32f5ede0f68ec5bba38e38fbd9 Mon Sep 17 00:00:00 2001 From: Paul Pflugradt Date: Tue, 5 Apr 2016 03:34:54 +0200 Subject: [PATCH 6/6] cleaned up tests --- test/unit/specs/directives/element/slot_spec.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/test/unit/specs/directives/element/slot_spec.js b/test/unit/specs/directives/element/slot_spec.js index 1cea4affdef..ca4095bd31b 100644 --- a/test/unit/specs/directives/element/slot_spec.js +++ b/test/unit/specs/directives/element/slot_spec.js @@ -462,9 +462,6 @@ describe('Slot Distribution', function () { var vm = new Vue({ el: el, template: '', - data: { - text:'main' - }, components: { comp1: { template: '
', @@ -549,9 +546,6 @@ describe('Slot Distribution', function () { var vm = new Vue({ el: el, template: '', - data: { - text:'main' - }, components: { comp1: { template: '
', @@ -575,9 +569,6 @@ describe('Slot Distribution', function () { var vm = new Vue({ el: el, template: '', - data: { - text:'main' - }, components: { comp1: { template: '
', @@ -602,9 +593,6 @@ describe('Slot Distribution', function () { var vm = new Vue({ el: el, template: '', - data: { - text:'main' - }, components: { comp1: { template: '
'