mirror of
https://github.com/tenrok/vue-select.git
synced 2026-06-19 09:50:33 +03:00
remove wrapper, start add tests
This commit is contained in:
+70
-49
@@ -119,8 +119,8 @@
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="dropdown v-select" :class="dropdownClasses">
|
<div class="dropdown v-select" :class="dropdownClasses">
|
||||||
<div v-el:toggle @mousedown.prevent="toggleDropdown" class="dropdown-toggle clearfix" type="button">
|
<div v-el:toggle @mousedown.prevent="toggleDropdown" class="dropdown-toggle clearfix" type="button">
|
||||||
<span class="form-control" v-if="!searchable && isValueEmpty">
|
<span class="form-control" v-if="!searchable && isValueEmpty">
|
||||||
{{ placeholder }}
|
{{ placeholder }}
|
||||||
</span>
|
</span>
|
||||||
@@ -132,40 +132,38 @@
|
|||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<input
|
<input
|
||||||
v-el:search
|
v-el:search
|
||||||
v-show="searchable"
|
v-show="searchable"
|
||||||
v-model="search"
|
v-model="search"
|
||||||
@keydown.delete="maybeDeleteValue"
|
@keydown.delete="maybeDeleteValue"
|
||||||
@keyup.esc="onEscape"
|
@keyup.esc="onEscape"
|
||||||
@keyup.up.prevent="typeAheadUp"
|
@keyup.up.prevent="typeAheadUp"
|
||||||
@keyup.down.prevent="typeAheadDown"
|
@keyup.down.prevent="typeAheadDown"
|
||||||
@keyup.enter.prevent="typeAheadSelect"
|
@keyup.enter.prevent="typeAheadSelect"
|
||||||
@blur="open = false"
|
@blur="open = false"
|
||||||
@focus="open = true"
|
@focus="open = true"
|
||||||
type="search"
|
type="search"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
:placeholder="searchPlaceholder"
|
:placeholder="searchPlaceholder"
|
||||||
:style="{ width: isValueEmpty ? '100%' : 'auto' }"
|
:style="{ width: isValueEmpty ? '100%' : 'auto' }"
|
||||||
>
|
>
|
||||||
|
|
||||||
<i v-el:open-indicator role="presentation" class="open-indicator"></i>
|
<i v-el:open-indicator role="presentation" class="open-indicator"></i>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-el:dropdown-wrapper v-show="open" :transition="transition" class="dropdown-menu" :style="{ 'max-height': maxHeight }">
|
<ul v-el:dropdown-menu v-show="open" :transition="transition" class="dropdown-menu" :style="{ 'max-height': maxHeight }">
|
||||||
<ul class="options" v-el:dropdown-menu>
|
<li v-for="option in filteredOptions" track-by="$index" :class="{ active: isOptionSelected(option), highlight: $index === typeAheadPointer }" @mouseover="typeAheadPointer = $index">
|
||||||
<li v-for="option in filteredOptions" track-by="$index" :class="{ active: isOptionSelected(option), highlight: $index === typeAheadPointer }" @mouseover="typeAheadPointer = $index">
|
<a @mousedown.prevent="select(option)">
|
||||||
<a @mousedown.prevent="select(option)">
|
{{ getOptionLabel(option) }}
|
||||||
{{ getOptionLabel(option) }}
|
</a>
|
||||||
</a>
|
</li>
|
||||||
</li>
|
<li transition="fade" v-if="!filteredOptions.length" class="divider"></li>
|
||||||
<li transition="fade" v-if="!filteredOptions.length" class="divider"></li>
|
<li transition="fade" v-if="!filteredOptions.length" class="text-center">
|
||||||
<li transition="fade" v-if="!filteredOptions.length" class="text-center">
|
<slot name="no-options">Sorry, no matching options.</slot>
|
||||||
<slot name="no-options">Sorry, no matching options.</slot>
|
</li>
|
||||||
</li>
|
</ul>
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
@@ -478,25 +476,52 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
maybeAdjustScrollPosition() {
|
maybeAdjustScrollPosition() {
|
||||||
let pointerHeight = this.$els.dropdownMenu.children[this.typeAheadPointer].offsetHeight
|
let bounds = this.viewport()
|
||||||
let pixelsToPointerTop = 0
|
let pixelsToPointerTop = this.pixelsToPointerTop()
|
||||||
|
let pixelsToPointerBottom = this.pixelsToPointerBottom()
|
||||||
|
let pointerHeight = this.pointerHeight()
|
||||||
|
|
||||||
for ( let i = 0; i < this.typeAheadPointer; i++ ) {
|
if (pixelsToPointerTop <= bounds.top) {
|
||||||
|
return this.scrollTo(pixelsToPointerTop)
|
||||||
|
} else if (pixelsToPointerBottom >= bounds.bottom) {
|
||||||
|
// return this.scrollTo(( this.pixelsToPointerCenter() - this.$els.dropdownMenu.offsetHeight ) + ( pointerHeight / 2))
|
||||||
|
return this.scrollTo(( this.pixelsToPointerCenter() - this.$els.dropdownMenu.offsetHeight ) + pointerHeight)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
pixelsToPointerTop() {
|
||||||
|
let pixelsToPointerTop = 0
|
||||||
|
for (let i = 0; i < this.typeAheadPointer; i++) {
|
||||||
pixelsToPointerTop += this.$els.dropdownMenu.children[i].offsetHeight
|
pixelsToPointerTop += this.$els.dropdownMenu.children[i].offsetHeight
|
||||||
}
|
}
|
||||||
|
return pixelsToPointerTop
|
||||||
|
},
|
||||||
|
|
||||||
let pixelsToPointerBottom = pixelsToPointerTop + pointerHeight
|
pixelsToPointerBottom() {
|
||||||
|
return this.pixelsToPointerTop() + this.pointerHeight()
|
||||||
|
},
|
||||||
|
|
||||||
let bounds = {
|
pixelsToPointerCenter() {
|
||||||
top: this.$els.dropdownWrapper.scrollTop,
|
return this.pixelsToPointerTop() + ( this.pointerHeight() / 2 )
|
||||||
bottom: this.$els.dropdownWrapper.offsetHeight + this.$els.dropdownWrapper.scrollTop
|
},
|
||||||
|
|
||||||
|
pointerHeight() {
|
||||||
|
return this.$els.dropdownMenu.children[this.typeAheadPointer].offsetHeight
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The viewport is the currently viewable
|
||||||
|
* portion of the dropdown menu
|
||||||
|
*/
|
||||||
|
viewport() {
|
||||||
|
return {
|
||||||
|
top: this.$els.dropdownMenu.scrollTop,
|
||||||
|
bottom: this.$els.dropdownMenu.offsetHeight + this.$els.dropdownMenu.scrollTop
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
if( pixelsToPointerTop <= bounds.top ) {
|
scrollTo(position) {
|
||||||
this.$els.dropdownWrapper.scrollTop = pixelsToPointerTop
|
return this.$els.dropdownMenu.scrollTop = position
|
||||||
} else if ( pixelsToPointerBottom >= bounds.bottom) {
|
|
||||||
this.$els.dropdownWrapper.scrollTop = ( pixelsToPointerBottom - this.$els.dropdownWrapper.offsetHeight ) + pointerHeight
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -547,10 +572,6 @@
|
|||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
|
|
||||||
scrollTop() {
|
|
||||||
return [this.$els.dropdownMenu.scrollTop,this.$el.scrollTop]
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Classes to be output on .dropdown
|
* Classes to be output on .dropdown
|
||||||
* @return {Object}
|
* @return {Object}
|
||||||
|
|||||||
@@ -365,6 +365,79 @@ describe('Select.vue', () => {
|
|||||||
vm.$children[0].typeAheadDown()
|
vm.$children[0].typeAheadDown()
|
||||||
expect(vm.$children[0].typeAheadPointer).toEqual(2)
|
expect(vm.$children[0].typeAheadPointer).toEqual(2)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should check if the scroll position needs to be adjusted on up arrow keyup', () => {
|
||||||
|
const vm = new Vue({
|
||||||
|
template: '<div><v-select :options="options"></v-select></div>',
|
||||||
|
components: {vSelect},
|
||||||
|
data: {
|
||||||
|
options: ['one', 'two', 'three']
|
||||||
|
}
|
||||||
|
}).$mount()
|
||||||
|
|
||||||
|
vm.$children[0].typeAheadPointer = 1
|
||||||
|
spyOn(vm.$children[0], 'maybeAdjustScrollPosition')
|
||||||
|
trigger(vm.$children[0].$els.search, 'keyup', (e) => e.keyCode = 38)
|
||||||
|
expect(vm.$children[0].maybeAdjustScrollPosition).toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should check if the scroll position needs to be adjusted on down arrow keyup', () => {
|
||||||
|
const vm = new Vue({
|
||||||
|
template: '<div><v-select :options="options" max-height="10"></v-select></div>',
|
||||||
|
components: {vSelect},
|
||||||
|
data: {
|
||||||
|
options: ['one', 'two', 'three']
|
||||||
|
}
|
||||||
|
}).$mount()
|
||||||
|
|
||||||
|
spyOn(vm.$children[0], 'maybeAdjustScrollPosition')
|
||||||
|
|
||||||
|
vm.$children[0].$els.search.focus()
|
||||||
|
|
||||||
|
trigger(vm.$children[0].$els.search, 'keyup', (e) => e.keyCode = 40)
|
||||||
|
expect(vm.$children[0].maybeAdjustScrollPosition).toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should scroll up if the new pointer is above the current viewport bounds', () => {
|
||||||
|
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Measuring pixel distances', () => {
|
||||||
|
it('should calculate pixelsToPointerTop as the sum of the height all options above the pointer', () => {
|
||||||
|
const vm = new Vue({
|
||||||
|
template: '<div><v-select :options="options"></v-select></div>',
|
||||||
|
components: {vSelect},
|
||||||
|
data: {
|
||||||
|
options: ['one', 'two', 'three']
|
||||||
|
}
|
||||||
|
}).$mount()
|
||||||
|
|
||||||
|
vm.$children[0].typeAheadPointer = 1
|
||||||
|
let lineHeight = vm.$children[0].$els.dropdownMenu.children[0].offsetHeight
|
||||||
|
expect(vm.$children[0].pixelsToPointerTop()).toEqual( lineHeight * 2 )
|
||||||
|
})
|
||||||
|
it('should calculate pixelsToPointerBottom as the sum of the height all options above the pointer plus the height of the pointer', () => {
|
||||||
|
const vm = new Vue({
|
||||||
|
template: '<div><v-select :options="options"></v-select></div>',
|
||||||
|
components: {vSelect},
|
||||||
|
data: {
|
||||||
|
options: ['one', 'two', 'three']
|
||||||
|
}
|
||||||
|
}).$mount()
|
||||||
|
|
||||||
|
vm.$children[0].typeAheadPointer = 1
|
||||||
|
let lineHeight = vm.$children[0].$els.dropdownMenu.children[0].offsetHeight
|
||||||
|
console.log(lineHeight)
|
||||||
|
expect(vm.$children[0].pixelsToPointerTop()).toEqual( lineHeight * 10 + lineHeight)
|
||||||
|
})
|
||||||
|
it('should calculate pixelsToPointerCenter', () => {
|
||||||
|
|
||||||
|
})
|
||||||
|
it('should calculate pointerHeight', () => {
|
||||||
|
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('Removing values', () => {
|
describe('Removing values', () => {
|
||||||
@@ -611,4 +684,4 @@ describe('Select.vue', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// also see example testing a component with mocks at
|
// also see example testing a component with mocks at
|
||||||
// https://github.com/vuejs/vueify-example/blob/master/test/unit/a.spec.js#L22-L43
|
// http://vue-loader.vuejs.org/en/workflow/testing-with-mocks.html
|
||||||
|
|||||||
Reference in New Issue
Block a user