Skip to content

Instantly share code, notes, and snippets.

@nfreear
Last active May 23, 2019 13:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nfreear/04edb91e7c53caa5bbfa5cae40f59029 to your computer and use it in GitHub Desktop.
Save nfreear/04edb91e7c53caa5bbfa5cae40f59029 to your computer and use it in GitHub Desktop.
Accessible keyboard/mouse drag, via Drag-on-drop | https://schne324.github.io/dragon-drop/demo
<!doctype html> <title> v-drag-on-drop </title>
<style>
body { margin: 1rem auto; max-width: 42rem; }
.demo > li,
.live-log {
background: #eee;
border: 1px dotted gray;
border-radius: .2rem;
margin: 1rem 0;
min-height: 1.5rem;
padding: 4px;
X-box-shadow: 0 0 2px #000;
}
.demo .dragon-active {
background: wheat;
}
.demo .handle {
background: orange;
border-radius: .3rem;
cursor: ns-resize;
font-size: 1.5rem;
min-height: 1rem;
min-width: 1rem;
padding: .1rem .6rem;
margin-right: .5rem;
}
/* Important !
*/
.offscreen {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px);
clip: rect(1px, 1px, 1px, 1px);
}
/* Below are styles for the dragula elements.
*/
.XX--gu-hide {
display: none !important;
}
.gu-unselectable {
-webkit-user-select: none !important;
-moz-user-select: none !important;
-ms-user-select: none !important;
user-select: none !important;
}
.gu-transit {
opacity: 0.2;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=20)";
filter: alpha(opacity=20);
list-style: none;
}
</style>
<h1> Dragon Drop, with Vue.js </h1>
<div id="app">
<p id="global-help">
Activate the reorder button and use the arrow keys to reorder the list or use your mouse to
drag/reorder. Press escape to cancel the reordering.
<span class="offscreen">Ensure screen reader is in focus mode.</span>
</p>
<h3 id="items-head"> Rank the bands </h3>
<p> With drag handle </p>
<drag-on-drop v-bind:items="items" v-console="items" />
</div>
<div class="live-log" id="live-log"></div>
<template id="drag-on-drop-template">
<ol class="demo" id="demo-1" aria-labelledby="items-head">
<li v-for="item in dataItems" v-bind:data-id="item.id" >
<button type="button" :title="'Reorder / drag item '+ item.id" class="fa fa-bars handle" v-bind:id="'item-btn-' + item.id"
:aria-describedby="globalHelpId" :aria-labelledby="'item-btn-' + item.id + ' item-text-'+ item.id"
v-html="handleContent"
>
</button>
<span :id="'item-text-' + item.id">Item {{ item.id }} <!-- Frank Zappa --></span>
</li>
<ol>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/drag-on-drop@3.3.2/dist/dragon-drop.min.js"></script>
<script id="filter-directive.js">
Vue.filter('raw', function (prefix, value) {
// console.warn('raw:', value)
return prefix + value;
})
Vue.directive('console', function (elem, binding) {
console.warn('v-console:', binding.value)
})
</script>
<script id="DragOnDrop.vue.js">
Vue.component('DragOnDrop', {
template: '#drag-on-drop-template',
props: { // Public!
items: {
type: Array,
required: true,
// validator: value => value.length <= MAX_COUNT, // Not applicable!
},
},
data () { // Private!
return {
DEBUG: false, // true,
DRAG_MOUNT_DELAY_MS: 50, // Milliseconds. IMPORTANT !!
dataItems: null, // Array,
dragonDrop: null, // Object.
handleLabel: '&#x2195;', // :arrow_up_down: ??
liveLog: document.querySelector('#live-log'),
globalHelpId: 'global-help',
}
},
computed: {
handleContent () {
return this.handleLabel + '<i class="offscreen"> Reorder </i>'
},
},
methods: {
onAnnouncement (msg) {
let $liveLog = this.liveLog;
let $elem = document.createElement('div');
$elem.innerHTML = msg;
$liveLog.appendChild($elem);
$liveLog.scrollTop = $liveLog.scrollHeight;
// clean it up after 7 seconds
window.setTimeout(() => {
$liveLog.removeChild($elem);
}, 7e3);
},
setupDragEvents () {
this.dragonDrop
.on('grabbed', (container, item) => console.log('Dragon.grabbed: ', item) )
.on('dropped', (container, item) => console.log('Dragon.dropped: ', item) )
.on('reorder', (container, item) => console.log('Dragon.reorder: ', item) )
.on('announcement', this.onAnnouncement)
.on('cancel', () => console.log('Dragon.reordering cancelled') );
this.dragonDrop.dragula
.on('drag', (el, source) => console.warn('Dragula.drag:', el, source))
.on('drop', (el, target, source, sibling) => console.warn('Dragula.drop', el, target, source, sibling)) // target === source;
},
},
mounted () {
this.dataItems = this.items;
if (this.DEBUG) {
localStorage.debug = 'drag-on-drop:*';
}
// Must wait ... !!
window.setTimeout(() => {
// Vue.nextTick(() => {
const DRAG = this.dragonDrop = new DragonDrop(this.$el, {
handle: '.handle',
// item: ':scope > li', // IMPORTANT! a selector that targets only a single list's items!
// Live log.
announcement: {
grabbed: el => el.querySelector('span').innerText + ' grabbed',
dropped: el => el.querySelector('span').innerText + ' dropped',
reorder: (el, items) => {
var pos = items.indexOf(el) + 1;
var text = el.querySelector('span').innerText;
return 'The rankings have been updated, ' + text + ' is now ranked #' + pos + ' of ' + items.length;
},
cancel: () => 'Reranking cancelled.',
}
})
this.setupDragEvents()
console.warn('DragOnDrop.mounted:', DRAG.items.length, DRAG.handles.length, this.dragonDrop, this)
}, this.DRAG_MOUNT_DELAY_MS);
},
})
</script>
<script id="App.js">
new Vue({
el: '#app',
data () { // Private!
return {
DEFAULT_COUNT: 8,
}
},
computed: {
items () {
let theItems = [];
// https://stackoverflow.com/questions/3746725/how-to-create-an-array-containing-1-n/54996234
const MAKE_ARRAY = Array.from(Array(this.DEFAULT_COUNT).keys())
MAKE_ARRAY.forEach((name, id) => theItems.push({ id: (id + 1), name }))
console.warn('App.theItems:', theItems);
return theItems.reverse()
},
},
})
</script>
<pre>
© Nick Freear, 17-May-2019.
* https://schne324.github.io/dragon-drop/demo/
* https://npmjs.com/package/drag-on-drop
* https://npmjs.com/package/dragula
* https://npmjs.com/package/vue-i18n-extract
* 2009, https://dev.opera.com/articles/accessible-drag-and-drop/example.html
</pre>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment