123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- (function() {
- "use strict";
- function buildDraggable(Sortable) {
- function removeNode (node) {
- node.parentElement.removeChild(node)
- }
- function insertNodeAt (fatherNode, node, position) {
- if (position < fatherNode.children.length) {
- fatherNode.insertBefore(node, fatherNode.children[position])
- } else {
- fatherNode.appendChild(node)
- }
- }
- function computeVmIndex (vnodes, element) {
- return vnodes.map(elt => elt.elm).indexOf(element)
- }
- function computeIndexes (slots, children) {
- return (!slots)? [] : Array.prototype.map.call(children, elt => computeVmIndex(slots, elt))
- }
- function emit (evtName, evtData) {
- this.$emit( evtName.toLowerCase(), evtData)
- }
- function delegateAndEmit (evtName) {
- return (evtData) => {
- if (this.list!==null) {
- this['onDrag' + evtName](evtData)
- }
- emit.call(this, evtName, evtData)
- }
- }
- const eventsListened = ['Start', 'Add', 'Remove', 'Update', 'End']
- const eventsToEmit = ['Choose', 'Sort', 'Filter', 'Clone']
- const readonlyProperties = ['Move', ...eventsListened, ...eventsToEmit].map(evt => 'on'+evt)
- var draggingElement = null
-
- const props = {
- options: Object,
- list: {
- type: Array,
- required: false,
- default: null
- },
- clone: {
- type: Function,
- default : (original) => { return original;}
- },
- element: {
- type: String,
- default: 'div'
- },
- move: {
- type: Function,
- default: null
- }
- }
- const draggableComponent = {
- props,
- data() {
- return {
- transitionMode: false
- }
- },
- render (h) {
- if (this.$slots.default && this.$slots.default.length===1) {
- const child = this.$slots.default[0]
- if (child.componentOptions && child.componentOptions.tag==="transition-group") {
- this.transitionMode = true
- }
- }
- return h(this.element, null, this.$slots.default);
- },
- mounted () {
- var optionsAdded = {};
- eventsListened.forEach( elt => {
- optionsAdded['on' + elt] = delegateAndEmit.call(this, elt)
- });
- eventsToEmit.forEach( elt => {
- optionsAdded['on' + elt] = emit.bind(this, elt)
- });
- const options = Object.assign({}, this.options, optionsAdded, { onMove: evt => {return this.onDragMove(evt);} })
- this._sortable = new Sortable(this.rootContainer, options)
- this.computeIndexes()
- },
- beforeDestroy () {
- this._sortable.destroy()
- },
- computed : {
- rootContainer () {
- return this.transitionMode? this.$el.children[0] : this.$el;
- }
- },
- watch: {
- options (newOptionValue){
- for(var property in newOptionValue) {
- if (readonlyProperties.indexOf(property)==-1) {
- this._sortable.option(property, newOptionValue[property] );
- }
- }
- },
- list(){
- this.computeIndexes()
- }
- },
- methods: {
- getChildrenNodes () {
- const rawNodes = this.$slots.default
- return this.transitionMode? rawNodes[0].child.$slots.default : rawNodes
- },
- computeIndexes () {
- this.$nextTick( () => {
- this.visibleIndexes = computeIndexes(this.getChildrenNodes(), this.rootContainer.children)
- })
- },
- getUnderlyingVm (htmlElt) {
- const index = computeVmIndex(this.getChildrenNodes(), htmlElt)
- const element = this.list[index]
- return {index, element}
- },
- getUnderlyingPotencialDraggableComponent ({__vue__}) {
- if (!__vue__ || !__vue__.$options || __vue__.$options._componentTag!=="transition-group"){
- return __vue__
- }
- return __vue__.$parent
- },
- emitChanges (evt) {
- this.$nextTick( ()=>{
- this.$emit('change', evt)
- });
- },
- spliceList () {
- this.list.splice(...arguments)
- },
- updatePosition (oldIndex, newIndex) {
- this.list.splice(newIndex, 0, this.list.splice(oldIndex, 1)[0])
- },
- getRelatedContextFromMoveEvent({to, related}) {
- const component = this.getUnderlyingPotencialDraggableComponent(to)
- if (!component) {
- return {component}
- }
- const list = component.list
- const context = {list, component}
- if (to !== related && list && component.getUnderlyingVm) {
- const destination = component.getUnderlyingVm(related)
- return Object.assign(destination, context)
- }
- return context
- },
- getVmIndex (domIndex) {
- const indexes = this.visibleIndexes
- const numberIndexes = indexes.length
- return (domIndex > numberIndexes - 1) ? numberIndexes : indexes[domIndex]
- },
- onDragStart (evt) {
- this.context = this.getUnderlyingVm(evt.item)
- evt.item._underlying_vm_ = this.clone(this.context.element)
- draggingElement = evt.item
- },
- onDragAdd (evt) {
- const element = evt.item._underlying_vm_
- if (element === undefined) {
- return
- }
- removeNode(evt.item)
- const newIndex = this.getVmIndex(evt.newIndex)
- this.spliceList(newIndex, 0, element)
- this.computeIndexes()
- const added = {element, newIndex}
- this.emitChanges({added})
- },
- onDragRemove (evt) {
- insertNodeAt(this.rootContainer, evt.item, evt.oldIndex)
- const isCloning = !!evt.clone
- if (isCloning) {
- removeNode(evt.clone)
- return
- }
- const oldIndex = this.context.index
- this.spliceList(oldIndex, 1)
- const removed = {element: this.context.element, oldIndex}
- this.emitChanges({removed})
- },
- onDragUpdate (evt) {
- removeNode(evt.item)
- insertNodeAt(evt.from, evt.item, evt.oldIndex)
- const oldIndex = this.context.index
- const newIndex = this.getVmIndex(evt.newIndex)
- this.updatePosition(oldIndex, newIndex)
- const moved = {element: this.context.element, oldIndex, newIndex}
- this.emitChanges({moved})
- },
- computeFutureIndex (relatedContext, evt) {
- if (!relatedContext.element){
- return 0
- }
- const domChildren = [...evt.to.children]
- const currentDOMIndex = domChildren.indexOf(evt.related)
- const currentIndex = relatedContext.component.getVmIndex(currentDOMIndex)
- const draggedInList = domChildren.indexOf(draggingElement) != -1
- return draggedInList? currentIndex : currentIndex+1
- },
- onDragMove (evt) {
- const onMove = this.move
- if (!onMove || !this.list) {
- return true
- }
- const relatedContext = this.getRelatedContextFromMoveEvent(evt)
- const draggedContext = this.context
- const futureIndex = this.computeFutureIndex(relatedContext, evt)
- Object.assign(draggedContext, { futureIndex })
- Object.assign(evt, {relatedContext, draggedContext})
- return onMove(evt)
- },
- onDragEnd (evt) {
- this.computeIndexes()
- draggingElement = null
- }
- }
- }
- return draggableComponent
- }
-
-
-
- if (typeof exports == "object") {
- var Sortable = require("sortablejs")
- module.exports = buildDraggable(Sortable)
- } else if (typeof define == "function" && define.amd) {
- define(['sortablejs'], function(Sortable) {return buildDraggable(Sortable);});
- } else if ( window && (window.Vue) && (window.Sortable)) {
- var draggable = buildDraggable(window.Sortable)
- Vue.component('draggable', draggable)
- }
-
- })();
|