Clickoutside: add test & improve vue-popper test (#577)

This commit is contained in:
cinwell.li 2016-10-21 23:21:54 +08:00 committed by FuryBean
parent 3317f1f7cd
commit 706d47b710
7 changed files with 308 additions and 16 deletions

View File

@ -8,7 +8,7 @@ Object.keys(Components).forEach(function(key) {
externals[`element-ui/packages/${key}/style.css`] = `element-ui/lib/${key}/style.css`;
});
Object.keys(dependencies).forEach(function (key) {
Object.keys(dependencies).forEach(function(key) {
externals[key] = key;
});

View File

@ -49,7 +49,7 @@ export default {
const popper = this.popper || this.$refs.popper;
if (!reference && this.$slots.reference && this.$slots.reference[0]) {
reference = this.$slots.reference[0].elm;
reference = this.referenceElm = this.$slots.reference[0].elm;
}
if (this.trigger === 'click') {
on(reference, 'click', () => { this.showPopper = !this.showPopper; });

View File

@ -1,8 +1,10 @@
import { on } from 'wind-dom/src/event';
const nodeList = [];
const ctx = '@@clickoutsideContext';
on(document, 'click', e => {
nodeList.forEach(node => node[clickoutsideContext].documentHandler(e));
nodeList.forEach(node => node[ctx].documentHandler(e));
});
/**
* v-clickoutside
@ -12,23 +14,24 @@ on(document, 'click', e => {
* <div v-element-clickoutside="handleClose">
* ```
*/
const clickoutsideContext = '@@clickoutsideContext';
export default {
bind(el, binding, vnode) {
const id = nodeList.push(el) - 1;
const documentHandler = function(e) {
if (!vnode.context ||
el.contains(e.target) ||
!vnode.context.popperElm ||
vnode.context.popperElm.contains(e.target)) return;
(vnode.context.popperElm &&
vnode.context.popperElm.contains(e.target))) return;
if (binding.expression) {
vnode.context[el[clickoutsideContext].methodName]();
el[ctx].methodName &&
vnode.context[el[ctx].methodName] &&
vnode.context[el[ctx].methodName]();
} else {
el[clickoutsideContext].bindingFn();
el[ctx].bindingFn && el[ctx].bindingFn();
}
};
el[clickoutsideContext] = {
el[ctx] = {
id,
documentHandler,
methodName: binding.expression,
@ -37,15 +40,17 @@ export default {
},
update(el, binding) {
el[clickoutsideContext].methodName = binding.expression;
el[clickoutsideContext].bindingFn = binding.value;
el[ctx].methodName = binding.expression;
el[ctx].bindingFn = binding.value;
},
unbind(el) {
nodeList.splice(el[clickoutsideContext].id, 1);
nodeList.splice(el[ctx].id, 1);
delete el[ctx];
},
install(Vue) {
/* istanbul ignore next */
Vue.directive('clickoutside', {
bind: this.bind,
unbind: this.unbind

View File

@ -4,6 +4,7 @@
* version: 0.5.3
**/
/* istanbul ignore next */
const requestFrame = (function() {
const raf = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame ||
function(fn) {
@ -14,6 +15,7 @@ const requestFrame = (function() {
};
})();
/* istanbul ignore next */
const cancelFrame = (function() {
const cancel = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame || window.clearTimeout;
return function(id) {
@ -21,6 +23,7 @@ const cancelFrame = (function() {
};
})();
/* istanbul ignore next */
const resetTrigger = function(element) {
const trigger = element.__resizeTrigger__;
const expand = trigger.firstElementChild;
@ -35,10 +38,12 @@ const resetTrigger = function(element) {
expand.scrollTop = expand.scrollHeight;
};
/* istanbul ignore next */
const checkTriggers = function(element) {
return element.offsetWidth !== element.__resizeLast__.width || element.offsetHeight !== element.__resizeLast__.height;
};
/* istanbul ignore next */
const scrollListener = function(event) {
resetTrigger(this);
if (this.__resizeRAF__) cancelFrame(this.__resizeRAF__);
@ -62,6 +67,7 @@ let animation = false;
let keyFramePrefix = '';
let animationStartEvent = 'animationstart';
/* istanbul ignore next */
if (!attachEvent) {
const testElement = document.createElement('fakeelement');
if (testElement.style.animationName !== undefined) {
@ -83,6 +89,7 @@ if (!attachEvent) {
}
let stylesCreated = false;
/* istanbul ignore next */
const createStyles = function() {
if (!stylesCreated) {
const animationKeyframes = `@${keyFramePrefix}keyframes ${RESIZE_ANIMATION_NAME} { from { opacity: 0; } to { opacity: 0; } } `;
@ -110,6 +117,7 @@ const createStyles = function() {
}
};
/* istanbul ignore next */
export const addResizeListener = function(element, fn) {
if (attachEvent) {
element.attachEvent('onresize', fn);
@ -143,6 +151,7 @@ export const addResizeListener = function(element, fn) {
}
};
/* istanbul ignore next */
export const removeResizeListener = function(element, fn) {
if (attachEvent) {
element.detachEvent('onresize', fn);

View File

@ -70,12 +70,17 @@ export default {
const options = this.options;
const popper = this.popperElm = this.popperElm || this.popper || this.$refs.popper;
const reference = this.referenceElm = this.referenceElm || this.reference || this.$refs.reference || this.$slots.reference[0].elm;
let reference = this.referenceElm = this.referenceElm || this.reference || this.$refs.reference;
if (!reference &&
this.$slots.reference &&
this.$slots.reference[0]) {
reference = this.referenceElm = this.$slots.reference[0].elm;
}
if (!popper || !reference) return;
if (this.visibleArrow) this.appendArrow(popper);
if (this.appendToBody) document.body.appendChild(this.popperElm);
if (this.popperJS && this.popperJS.hasOwnProperty('destroy')) {
if (this.popperJS && this.popperJS.destroy) {
this.popperJS.destroy();
}
@ -95,6 +100,7 @@ export default {
},
doDestroy() {
/* istanbul ignore if */
if (this.showPopper || !this.popperJS) return;
this.popperJS.destroy();
this.popperJS = null;
@ -110,7 +116,9 @@ export default {
let placementMap = { top: 'bottom', bottom: 'top', left: 'right', right: 'left' };
let placement = this.popperJS._popper.getAttribute('x-placement').split('-')[0];
let origin = placementMap[placement];
this.popperJS._popper.style.transformOrigin = ['top', 'bottom'].indexOf(placement) > -1 ? `center ${ origin }` : `${ origin } center`;
this.popperJS._popper.style.transformOrigin = ['top', 'bottom'].indexOf(placement) > -1
? `center ${ origin }`
: `${ origin } center`;
},
appendArrow(element) {

View File

@ -0,0 +1,148 @@
import Clickoutside from 'element-ui/src/utils/clickoutside';
const ctx = '@@clickoutsideContext';
describe('Utils:Clickoutside', () => {
it('create', () => {
let count = 0;
const el = document.createElement('div');
const vnode = {
context: {
handleClick: () => ++count
}
};
const binding = {
expression: 'handleClick'
};
Clickoutside.bind(el, binding, vnode);
expect(el[ctx]).to.exist;
});
it('cotext not exist', () => {
const el = document.createElement('div');
const vnode = {};
const binding = {
expression: 'handleClick'
};
Clickoutside.bind(el, binding, vnode);
expect(el[ctx]).to.exist;
});
it('binding expression', () => {
const el = document.createElement('div');
let count = 0;
const vnode = {
context: {
handleClick: () => ++count
}
};
const binding = {
expression: 'handleClick'
};
Clickoutside.bind(el, binding, vnode);
document.body.click();
expect(count).to.equal(1);
});
it('click inside', () => {
const el = document.createElement('div');
const insideElm = document.createElement('div');
let count = 0;
const vnode = {
context: {
handleClick: () => ++count
}
};
const binding = {
expression: 'handleClick'
};
el.appendChild(insideElm);
Clickoutside.bind(el, binding, vnode);
insideElm.click();
expect(count).to.equal(0);
document.body.click();
expect(count).to.equal(1);
});
it('tigger event in popperElm', () => {
const el = document.createElement('div');
const insideElm = document.createElement('div');
let count = 0;
const vnode = {
context: {
handleClick: () => ++count,
popperElm: document.createElement('div')
}
};
const binding = {
expression: 'handleClick'
};
vnode.context.popperElm.appendChild(insideElm);
Clickoutside.bind(el, binding, vnode);
insideElm.click();
expect(count).to.equal(0);
document.body.click();
expect(count).to.equal(1);
});
it('binding value', () => {
const el = document.createElement('div');
let count = 0;
const vnode = {
context: {}
};
const binding = {
value: () => ++count
};
Clickoutside.bind(el, binding, vnode);
expect(count).to.equal(0);
document.body.click();
expect(count).to.equal(1);
});
it('update', () => {
let count = 0;
const el = document.createElement('div');
const vnode = {
context: {
abc: () => ++count,
ddd: () => ++count
}
};
const binding = {
expression: 'abc'
};
const newBinding = {
expression: 'ddd'
};
Clickoutside.bind(el, binding, vnode);
expect(el[ctx].methodName).to.equal('abc');
Clickoutside.update(el, newBinding);
expect(el[ctx].methodName).to.equal('ddd');
});
it('unbind', () => {
const el = document.createElement('div');
let count = 0;
const vnode = {
context: {}
};
const binding = {
value: () => ++count
};
Clickoutside.bind(el, binding, vnode);
document.body.click();
Clickoutside.unbind(el);
document.body.click();
expect(count).to.equal(1);
expect(el[ctx]).to.not.exist;
});
});

View File

@ -12,13 +12,71 @@ const Popper = Object.assign({}, VuePopper, {
}
});
const CleanPopper = Object.assign({}, VuePopper, {
render(h) {
return h('div');
}
});
describe('Utils:VuePopper', () => {
it('set popper not reference', () => {
const vm = createTest(CleanPopper, {
popper: document.createElement('div')
});
vm.createPopper();
expect(vm.popperElm).to.exist;
expect(vm.referenceElm).to.not.exist;
expect(vm.popperJS).to.not.exist;
});
it('set reference not popper', () => {
const vm = createTest(CleanPopper, {
reference: document.createElement('div')
});
vm.createPopper();
expect(vm.referenceElm).to.exist;
expect(vm.popperElm).to.not.exist;
expect(vm.popperJS).to.not.exist;
});
it('set reference by slot', () => {
const vm = createTest(CleanPopper);
vm.$slots['reference'] = [{
elm: document.createElement('div')
}];
vm.createPopper();
expect(vm.referenceElm).to.exist;
expect(vm.popperElm).to.not.exist;
expect(vm.popperJS).to.not.exist;
});
it('createPopper', () => {
const vm = createTest(Popper, { placement: 'top' });
vm.createPopper();
expect(vm.popperJS._popper.getAttribute('x-placement')).to.equal('top');
});
it('destroy popper when calling createPopper twice', () => {
const vm = createTest(Popper);
vm.createPopper();
const popperJS = vm.popperJS;
expect(vm.popperJS).to.exist;
expect(vm.popperJS).to.equal(popperJS);
vm.createPopper();
expect(vm.popperJS).to.not.equal(popperJS);
});
it('updatePopper', () => {
const vm = createTest(Popper);
vm.updatePopper();
const popperJS = vm.popperJS;
expect(vm.popperJS).to.exist;
vm.updatePopper();
expect(vm.popperJS).to.equal(popperJS);
});
it('doDestroy', () => {
const vm = createTest(Popper, { placement: 'top' });
vm.createPopper();
@ -27,6 +85,15 @@ describe('Utils:VuePopper', () => {
expect(vm.popperJS).to.not.exist;
});
it('destroyPopper', () => {
const vm = createTest(Popper);
const vm2 = createTest(Popper);
vm.createPopper();
expect(() => vm.destroyPopper()).to.not.throw();
expect(() => vm2.destroyPopper()).to.not.throw();
});
it('placement', () => {
const vm = createTest(Popper, { placement: 'bottom-start' });
const vm2 = createTest(Popper, { placement: 'bottom-abc' });
@ -46,6 +113,61 @@ describe('Utils:VuePopper', () => {
expect(vm.popperJS._popper.querySelector('div[x-arrow]')).to.exist;
});
it('update showPopper', done => {
const vm = createTest(Popper);
expect(vm.popperJS).to.not.exist;
vm.showPopper = true;
setTimeout(_ => {
expect(vm.popperJS).to.exist;
vm.showPopper = false;
setTimeout(_ => {
expect(vm.popperJS).to.exist;
}, 50);
done();
}, 50);
});
it('resetTransformOrigin', () => {
const vm = createTest(Popper, {
placement: 'left'
});
vm.createPopper();
expect(vm.popperJS._popper.style.transformOrigin).to.include('right center');
});
it('appendArrow', () => {
const vm = createTest(Popper, {
visibleArrow: true
});
expect(vm.appended).to.empty;
vm.createPopper();
expect(vm.appended).to.true;
vm.appendArrow();
expect(vm.popperJS._popper.querySelector('[x-arrow]')).to.exist;
expect(vm.appended).to.true;
});
it('appendArrow: add scoped', () => {
const popper = document.createElement('div');
popper.setAttribute('_v-110', true);
const vm = createTest(CleanPopper, {
reference: document.createElement('div'),
visibleArrow: true,
popper
});
expect(vm.appended).to.empty;
vm.createPopper();
expect(vm.popperJS._popper.querySelector('[x-arrow][_v-110]')).to.exist;
});
it('appendToBody set false', () => {
const vm = createTest(Popper, {
appendToBody: false
});
vm.createPopper();
expect(document.body.contains(vm.popperElm)).to.false;
});
it('destroy', () => {
const vm = createTest(Popper, true);