From 1821f8859312e6934c60e6e3971dcbae3bb43750 Mon Sep 17 00:00:00 2001 From: Niels Thole Date: Fri, 1 Jun 2018 10:47:00 +0200 Subject: [PATCH 1/4] Update to polymer 3.0 --- .idea/modules.xml | 8 + .idea/sortable-list.iml | 12 ++ .idea/vcs.xml | 6 + .idea/workspace.xml | 26 +++ bower.json | 13 -- demo/index.html | 36 ++-- package.json | 19 ++ sortable-list.html | 348 ---------------------------------- sortable-list.js | 349 +++++++++++++++++++++++++++++++++++ test/sortable-list_test.html | 22 +-- 10 files changed, 452 insertions(+), 387 deletions(-) create mode 100644 .idea/modules.xml create mode 100644 .idea/sortable-list.iml create mode 100644 .idea/vcs.xml create mode 100644 .idea/workspace.xml delete mode 100644 bower.json create mode 100644 package.json delete mode 100644 sortable-list.html create mode 100644 sortable-list.js diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..6abf975 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/sortable-list.iml b/.idea/sortable-list.iml new file mode 100644 index 0000000..24643cc --- /dev/null +++ b/.idea/sortable-list.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..fde18bf --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,26 @@ + + + + true + + false + true + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bower.json b/bower.json deleted file mode 100644 index 4e8134c..0000000 --- a/bower.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "sortable-list", - "authors": [ - "Pedro Garcia " - ], - "main": "sortable-list.html", - "dependencies": { - "polymer": "Polymer/polymer#^2.0.0" - }, - "devDependencies": { - "web-component-tester": "v6.0.0" - } -} diff --git a/demo/index.html b/demo/index.html index c30b1bd..24434a5 100644 --- a/demo/index.html +++ b/demo/index.html @@ -6,8 +6,8 @@ sortable-list demo - - + + - -
- -
- - - - - diff --git a/sortable-list.js b/sortable-list.js new file mode 100644 index 0000000..d8c8430 --- /dev/null +++ b/sortable-list.js @@ -0,0 +1,349 @@ +/** +`sortable-list` + + +@demo demo/index.html +*/ +/* + FIXME(polymer-modulizer): the above comments were extracted + from HTML and may be out of place here. Review them and + then delete this comment! +*/ +import '../../@polymer/polymer/polymer-element.js'; + +import '../../@polymer/polymer/lib/mixins/gesture-event-listeners.js'; +import { html } from '../../@polymer/polymer/lib/utils/html-tag.js'; +import { idlePeriod } from '../../@polymer/polymer/lib/utils/async.js'; +import { addListener, removeListener } from '../../@polymer/polymer/lib/utils/gestures.js'; + +class SortableList extends Polymer.GestureEventListeners(Polymer.Element) { + static get template() { + return html` + + +
+ +
+`; + } + + static get is() {return 'sortable-list';} + + static get properties() { + return { + + /** + * This is a CSS selector string. If this is set, only items that + * match the CSS selector are sortable. + */ + sortable: String, + + /** + * The list of sortable items. + */ + items: { + type: Array, + notify: true, + readOnly: true + }, + + /** + * Returns true when an item is being drag. + */ + dragging: { + type: Boolean, + notify: true, + readOnly: true, + reflectToAttribute: true, + value: false + }, + + /** + * Disables the draggable if set to true. + */ + disabled: { + type: Boolean, + reflectToAttribute: true, + value: false + } + + }; + } + + constructor() { + super(); + this._observer = null; + this._target = null; + this._targetRect = null; + this._rects = null; + this._onTrack = this._onTrack.bind(this); + this._onDragStart = this._onDragStart.bind(this); + this._onTransitionEnd = this._onTransitionEnd.bind(this); + this._onContextMenu = this._onContextMenu.bind(this); + this._onTouchMove = this._onTouchMove.bind(this); + } + + connectedCallback() { + super.connectedCallback(); + idlePeriod.run(_ => { + this._observeItems(); + this._updateItems(); + this._toggleListeners({enable: true}); + }); + } + + disconnectedCallback() { + super.disconnectedCallback(); + this._unobserveItems(); + this._toggleListeners({enable: false}); + } + + _toggleListeners({enable}) { + const m = enable ? 'addEventListener' : 'removeEventListener'; + this.$.items[m]('dragstart', this._onDragStart); + this.$.items[m]('transitionend', this._onTransitionEnd); + this.$.items[m]('contextmenu', this._onContextMenu); + this.$.items[m]('touchmove', this._onTouchMove); + if (enable) { + addListener(this, 'track', this._onTrack); + } else { + removeListener(this, 'track', this._onTrack); + } + } + + _onTrack(event) { + switch(event.detail.state) { + case 'start': this._trackStart(event); break; + case 'track': this._track(event); break; + case 'end': this._trackEnd(event); break; + } + } + + _trackStart(event) { + if (this.disabled) { + return; + } + this._target = this._itemFromEvent(event); + if (!this._target) { + return; + } + event.stopPropagation(); + this._rects = this._getItemsRects(); + this._targetRect = this._rects[this.items.indexOf(this._target)]; + this._target.classList.add('item--dragged', 'item--pressed'); + if ('vibrate' in navigator) { + navigator.vibrate(30); + } + const rect = this.getBoundingClientRect(); + this.style.height = rect.height + 'px'; + this.style.width = rect.width + 'px'; + this.items.forEach((item, idx) => { + const rect = this._rects[idx]; + item.classList.add('item--transform'); + item.style.transition = 'none'; + item.__originalWidth = item.style.width; + item.__originalHeight = item.style.height; + item.style.width = rect.width + 'px'; + item.style.height = rect.height + 'px'; + this._translate3d(rect.left, rect.top, 1, item); + setTimeout(_ => { + item.style.transition = null; + }, 20); + }); + this._setDragging(true); + } + + _track(event) { + if (!this.dragging) { + return; + } + const left = this._targetRect.left + event.detail.dx; + const top = this._targetRect.top + event.detail.dy; + this._translate3d(left, top, 1, this._target); + const overItem = this._itemFromCoords(event.detail); + if (overItem && overItem !== this._target) { + const overItemIndex = this.items.indexOf(overItem); + const targetIndex = this.items.indexOf(this._target); + this._moveItemArray(this.items, targetIndex, overItemIndex); + for(let i = 0; i < this.items.length; i++) { + if (this.items[i] !== this._target) { + const rect = this._rects[i]; + requestAnimationFrame(_ => { + this._translate3d(rect.left, rect.top, 1, this.items[i]); + }); + } + } + } + } + + // The track really ends + _trackEnd(event) { + if (!this.dragging) { + return; + } + const rect = this._rects[this.items.indexOf(this._target)]; + this._target.classList.remove('item--pressed'); + this._setDragging(false); + this._translate3d(rect.left, rect.top, 1, this._target); + } + + _onTransitionEnd() { + if (this.dragging || !this._target) { + return; + } + const fragment = document.createDocumentFragment(); + this.items.forEach(item => { + item.style.transform = ''; + item.style.width = item.__originalWidth; + item.style.height = item.__originalHeight; + item.classList.remove('item--transform'); + fragment.appendChild(item); + }); + if (this.children[0]) { + this.insertBefore(fragment, this.children[0]); + } else { + this.appendChild(fragment); + } + this.style.height = ''; + this._target.classList.remove('item--dragged'); + this._rects = null; + this._targetRect = null; + this._updateItems(); + this.dispatchEvent(new CustomEvent('sort-finish', { + composed: true, + detail: { + target: this._target + } + })); + this._target = null; + } + + _onDragStart(event) { + event.preventDefault(); + } + + _onContextMenu(event) { + if (this.dragging) { + event.preventDefault(); + this._trackEnd(); + } + } + + _onTouchMove(event) { + event.preventDefault(); + } + + _updateItems() { + if (this.dragging) { + return; + } + const items = this.$.slot.assignedNodes().filter(node => { + if ((node.nodeType === Node.ELEMENT_NODE) && + (!this.sortable || node.matches(this.sortable))) { + return true; + } + }); + this._setItems(items); + } + + _itemFromCoords({x, y}) { + if (!this._rects) {return;} + let match = null; + this._rects.forEach((rect, i) => { + if ((x >= rect.left) && + (x <= rect.left + rect.width) && + (y >= rect.top) && + (y <= rect.top + rect.height)) { + match = this.items[i]; + } + }); + return match; + } + + _itemFromEvent(event) { + const path = event.composedPath(); + for (var i = 0; i < path.length; i++) { + if (this.items.indexOf(path[i]) > -1) { + return path[i]; + } + } + } + + _getItemsRects() { + return this.items.map(item => { + return item.getBoundingClientRect(); + }) + } + + _observeItems() { + if (!this._observer) { + this._observer = new MutationObserver(_ => { + this._updateItems(); + }); + this._observer.observe(this, {childList: true}); + } + } + + _unobserveItems() { + if (this._observer) { + this._observer.disconnect(); + this._observer = null; + } + } + + /** + * Move an array item from one position to another. + * Source: http://stackoverflow.com/questions/5306680/move-an-array-element-from-one-array-position-to-another + */ + _moveItemArray(array, oldIndex, newIndex) { + if (newIndex >= array.length) { + var k = newIndex - array.length; + while ((k--) + 1) { + array.push(undefined); + } + } + array.splice(newIndex, 0, array.splice(oldIndex, 1)[0]); + return array; + } + + _translate3d(x, y, z, el) { + el.style.transform = `translate3d(${x}px, ${y}px, ${z}px)`; + } +} + +customElements.define(SortableList.is, SortableList); diff --git a/test/sortable-list_test.html b/test/sortable-list_test.html index 11cd414..e37227b 100644 --- a/test/sortable-list_test.html +++ b/test/sortable-list_test.html @@ -6,10 +6,7 @@ - - - - + @@ -22,11 +19,14 @@ suite('sortable-list', function() { test('instantiating the element works', function() { - var element = fixture('basic'); - assert.equal(element.is, 'sortable-list'); - }); + - - +}); + \ No newline at end of file From c1320f828f369a5fa2dae894c59a08ffe3e0c0a0 Mon Sep 17 00:00:00 2001 From: Niels Thole Date: Fri, 1 Jun 2018 10:53:23 +0200 Subject: [PATCH 2/4] Fix import --- sortable-list.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sortable-list.js b/sortable-list.js index d8c8430..812c0e8 100644 --- a/sortable-list.js +++ b/sortable-list.js @@ -9,12 +9,12 @@ from HTML and may be out of place here. Review them and then delete this comment! */ -import '../../@polymer/polymer/polymer-element.js'; +import '@polymer/polymer/polymer-element.js'; -import '../../@polymer/polymer/lib/mixins/gesture-event-listeners.js'; -import { html } from '../../@polymer/polymer/lib/utils/html-tag.js'; -import { idlePeriod } from '../../@polymer/polymer/lib/utils/async.js'; -import { addListener, removeListener } from '../../@polymer/polymer/lib/utils/gestures.js'; +import '@polymer/polymer/lib/mixins/gesture-event-listeners.js'; +import { html } from '@polymer/polymer/lib/utils/html-tag.js'; +import { idlePeriod } from '@polymer/polymer/lib/utils/async.js'; +import { addListener, removeListener } from '@polymer/polymer/lib/utils/gestures.js'; class SortableList extends Polymer.GestureEventListeners(Polymer.Element) { static get template() { From a7a67d7522939bd45b6e62691c7745e2b58b6329 Mon Sep 17 00:00:00 2001 From: Niels Thole Date: Fri, 1 Jun 2018 10:57:42 +0200 Subject: [PATCH 3/4] Remove accidently added webstorm files --- .idea/modules.xml | 8 -------- .idea/sortable-list.iml | 12 ------------ .idea/vcs.xml | 6 ------ .idea/workspace.xml | 26 -------------------------- 4 files changed, 52 deletions(-) delete mode 100644 .idea/modules.xml delete mode 100644 .idea/sortable-list.iml delete mode 100644 .idea/vcs.xml delete mode 100644 .idea/workspace.xml diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 6abf975..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/sortable-list.iml b/.idea/sortable-list.iml deleted file mode 100644 index 24643cc..0000000 --- a/.idea/sortable-list.iml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml deleted file mode 100644 index fde18bf..0000000 --- a/.idea/workspace.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - true - - false - true - - - - - - - - - - - - - - - \ No newline at end of file From 77875271257f5611d7459963eca47f8b52aabe53 Mon Sep 17 00:00:00 2001 From: Niels Thole Date: Fri, 1 Jun 2018 11:08:41 +0200 Subject: [PATCH 4/4] Fix more imports --- sortable-list.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sortable-list.js b/sortable-list.js index 812c0e8..7f9006a 100644 --- a/sortable-list.js +++ b/sortable-list.js @@ -9,14 +9,14 @@ from HTML and may be out of place here. Review them and then delete this comment! */ -import '@polymer/polymer/polymer-element.js'; +import { PolymerElement } from '@polymer/polymer/polymer-element.js'; -import '@polymer/polymer/lib/mixins/gesture-event-listeners.js'; +import { GestureEventListeners } from '@polymer/polymer/lib/mixins/gesture-event-listeners.js'; import { html } from '@polymer/polymer/lib/utils/html-tag.js'; import { idlePeriod } from '@polymer/polymer/lib/utils/async.js'; import { addListener, removeListener } from '@polymer/polymer/lib/utils/gestures.js'; -class SortableList extends Polymer.GestureEventListeners(Polymer.Element) { +class SortableList extends GestureEventListeners(PolymerElement) { static get template() { return html`