uikit
Version:
UIkit is a lightweight and modular front-end framework for developing fast and powerful web interfaces.
536 lines (395 loc) • 17.8 kB
JavaScript
/*! UIkit 3.2.1 | http://www.getuikit.com | (c) 2014 - 2019 YOOtheme | MIT License */
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('uikit-util')) :
typeof define === 'function' && define.amd ? define('uikitsortable', ['uikit-util'], factory) :
(global = global || self, global.UIkitSortable = factory(global.UIkit.util));
}(this, function (uikitUtil) { 'use strict';
var targetClass = 'uk-animation-target';
var Animate = {
props: {
animation: Number
},
data: {
animation: 150
},
computed: {
target: function() {
return this.$el;
}
},
methods: {
animate: function(action) {
var this$1 = this;
addStyle();
var children = uikitUtil.toNodes(this.target.children);
var propsFrom = children.map(function (el) { return getProps(el, true); });
var oldHeight = uikitUtil.height(this.target);
var oldScrollY = window.pageYOffset;
action();
uikitUtil.Transition.cancel(this.target);
children.forEach(uikitUtil.Transition.cancel);
reset(this.target);
this.$update(this.target);
uikitUtil.fastdom.flush();
var newHeight = uikitUtil.height(this.target);
children = children.concat(uikitUtil.toNodes(this.target.children).filter(function (el) { return !uikitUtil.includes(children, el); }));
var propsTo = children.map(function (el, i) { return el.parentNode && i in propsFrom
? propsFrom[i]
? uikitUtil.isVisible(el)
? getPositionWithMargin(el)
: {opacity: 0}
: {opacity: uikitUtil.isVisible(el) ? 1 : 0}
: false; }
);
propsFrom = propsTo.map(function (props, i) {
var from = children[i].parentNode === this$1.target
? propsFrom[i] || getProps(children[i])
: false;
if (from) {
if (!props) {
delete from.opacity;
} else if (!('opacity' in props)) {
var opacity = from.opacity;
if (opacity % 1) {
props.opacity = 1;
} else {
delete from.opacity;
}
}
}
return from;
});
uikitUtil.addClass(this.target, targetClass);
children.forEach(function (el, i) { return propsFrom[i] && uikitUtil.css(el, propsFrom[i]); });
uikitUtil.css(this.target, 'height', oldHeight);
uikitUtil.scrollTop(window, oldScrollY);
return uikitUtil.Promise.all(children.map(function (el, i) { return propsFrom[i] && propsTo[i]
? uikitUtil.Transition.start(el, propsTo[i], this$1.animation, 'ease')
: uikitUtil.Promise.resolve(); }
).concat(uikitUtil.Transition.start(this.target, {height: newHeight}, this.animation, 'ease'))).then(function () {
children.forEach(function (el, i) { return uikitUtil.css(el, {display: propsTo[i].opacity === 0 ? 'none' : '', zIndex: ''}); });
reset(this$1.target);
this$1.$update(this$1.target);
uikitUtil.fastdom.flush(); // needed for IE11
}, uikitUtil.noop);
}
}
};
function getProps(el, opacity) {
var zIndex = uikitUtil.css(el, 'zIndex');
return uikitUtil.isVisible(el)
? uikitUtil.assign({
display: '',
opacity: opacity ? uikitUtil.css(el, 'opacity') : '0',
pointerEvents: 'none',
position: 'absolute',
zIndex: zIndex === 'auto' ? uikitUtil.index(el) : zIndex
}, getPositionWithMargin(el))
: false;
}
function reset(el) {
uikitUtil.css(el.children, {
height: '',
left: '',
opacity: '',
pointerEvents: '',
position: '',
top: '',
width: ''
});
uikitUtil.removeClass(el, targetClass);
uikitUtil.css(el, 'height', '');
}
function getPositionWithMargin(el) {
var ref = el.getBoundingClientRect();
var height = ref.height;
var width = ref.width;
var ref$1 = uikitUtil.position(el);
var top = ref$1.top;
var left = ref$1.left;
top += uikitUtil.toFloat(uikitUtil.css(el, 'marginTop'));
return {top: top, left: left, height: height, width: width};
}
var style;
function addStyle() {
if (style) {
return;
}
style = uikitUtil.append(document.head, '<style>').sheet;
style.insertRule(
("." + targetClass + " > * {\n margin-top: 0 !important;\n transform: none !important;\n }"), 0
);
}
var Class = {
connected: function() {
!uikitUtil.hasClass(this.$el, this.$name) && uikitUtil.addClass(this.$el, this.$name);
}
};
var Component = {
mixins: [Class, Animate],
props: {
group: String,
threshold: Number,
clsItem: String,
clsPlaceholder: String,
clsDrag: String,
clsDragState: String,
clsBase: String,
clsNoDrag: String,
clsEmpty: String,
clsCustom: String,
handle: String
},
data: {
group: false,
threshold: 5,
clsItem: 'uk-sortable-item',
clsPlaceholder: 'uk-sortable-placeholder',
clsDrag: 'uk-sortable-drag',
clsDragState: 'uk-drag',
clsBase: 'uk-sortable',
clsNoDrag: 'uk-sortable-nodrag',
clsEmpty: 'uk-sortable-empty',
clsCustom: '',
handle: false
},
created: function() {
var this$1 = this;
['init', 'start', 'move', 'end'].forEach(function (key) {
var fn = this$1[key];
this$1[key] = function (e) {
this$1.scrollY = window.pageYOffset;
var ref = uikitUtil.getEventPos(e, 'page');
var x = ref.x;
var y = ref.y;
this$1.pos = {x: x, y: y};
fn(e);
};
});
},
events: {
name: uikitUtil.pointerDown,
passive: false,
handler: 'init'
},
update: {
write: function() {
if (this.clsEmpty) {
uikitUtil.toggleClass(this.$el, this.clsEmpty, uikitUtil.isEmpty(this.$el.children));
}
uikitUtil.css(this.handle ? uikitUtil.$$(this.handle, this.$el) : this.$el.children, {touchAction: 'none', userSelect: 'none'});
if (this.drag) {
// clamp to viewport
var ref = uikitUtil.offset(window);
var right = ref.right;
var bottom = ref.bottom;
uikitUtil.offset(this.drag, {
top: uikitUtil.clamp(this.pos.y + this.origin.top, 0, bottom - this.drag.offsetHeight),
left: uikitUtil.clamp(this.pos.x + this.origin.left, 0, right - this.drag.offsetWidth)
});
trackScroll(this.pos);
}
}
},
methods: {
init: function(e) {
var target = e.target;
var button = e.button;
var defaultPrevented = e.defaultPrevented;
var ref = uikitUtil.toNodes(this.$el.children).filter(function (el) { return uikitUtil.within(target, el); });
var placeholder = ref[0];
if (!placeholder
|| defaultPrevented
|| button > 0
|| uikitUtil.isInput(target)
|| uikitUtil.within(target, ("." + (this.clsNoDrag)))
|| this.handle && !uikitUtil.within(target, this.handle)
) {
return;
}
e.preventDefault();
this.touched = [this];
this.placeholder = placeholder;
this.origin = uikitUtil.assign({target: target, index: uikitUtil.index(placeholder)}, this.pos);
uikitUtil.on(document, uikitUtil.pointerMove, this.move);
uikitUtil.on(document, uikitUtil.pointerUp, this.end);
uikitUtil.on(window, 'scroll', this.scroll);
if (!this.threshold) {
this.start(e);
}
},
start: function(e) {
this.drag = uikitUtil.append(this.$container, this.placeholder.outerHTML.replace(/^<li/i, '<div').replace(/li>$/i, 'div>'));
uikitUtil.css(this.drag, uikitUtil.assign({
boxSizing: 'border-box',
width: this.placeholder.offsetWidth,
height: this.placeholder.offsetHeight,
overflow: 'hidden'
}, uikitUtil.css(this.placeholder, ['paddingLeft', 'paddingRight', 'paddingTop', 'paddingBottom'])));
uikitUtil.attr(this.drag, 'uk-no-boot', '');
uikitUtil.addClass(this.drag, this.clsDrag, this.clsCustom);
uikitUtil.height(this.drag.firstElementChild, uikitUtil.height(this.placeholder.firstElementChild));
var ref = uikitUtil.offset(this.placeholder);
var left = ref.left;
var top = ref.top;
uikitUtil.assign(this.origin, {left: left - this.pos.x, top: top - this.pos.y});
uikitUtil.addClass(this.placeholder, this.clsPlaceholder);
uikitUtil.addClass(this.$el.children, this.clsItem);
uikitUtil.addClass(document.documentElement, this.clsDragState);
uikitUtil.trigger(this.$el, 'start', [this, this.placeholder]);
this.move(e);
},
move: function(e) {
if (!this.drag) {
if (Math.abs(this.pos.x - this.origin.x) > this.threshold || Math.abs(this.pos.y - this.origin.y) > this.threshold) {
this.start(e);
}
return;
}
this.$emit();
var target = e.type === 'mousemove' ? e.target : document.elementFromPoint(this.pos.x - window.pageXOffset, this.pos.y - window.pageYOffset);
var sortable = this.getSortable(target);
var previous = this.getSortable(this.placeholder);
var move = sortable !== previous;
if (!sortable || uikitUtil.within(target, this.placeholder) || move && (!sortable.group || sortable.group !== previous.group)) {
return;
}
target = sortable.$el === target.parentNode && target || uikitUtil.toNodes(sortable.$el.children).filter(function (element) { return uikitUtil.within(target, element); })[0];
if (move) {
previous.remove(this.placeholder);
} else if (!target) {
return;
}
sortable.insert(this.placeholder, target);
if (!uikitUtil.includes(this.touched, sortable)) {
this.touched.push(sortable);
}
},
end: function(e) {
uikitUtil.off(document, uikitUtil.pointerMove, this.move);
uikitUtil.off(document, uikitUtil.pointerUp, this.end);
uikitUtil.off(window, 'scroll', this.scroll);
if (!this.drag) {
if (e.type === 'touchend') {
e.target.click();
}
return;
}
untrackScroll();
var sortable = this.getSortable(this.placeholder);
if (this === sortable) {
if (this.origin.index !== uikitUtil.index(this.placeholder)) {
uikitUtil.trigger(this.$el, 'moved', [this, this.placeholder]);
}
} else {
uikitUtil.trigger(sortable.$el, 'added', [sortable, this.placeholder]);
uikitUtil.trigger(this.$el, 'removed', [this, this.placeholder]);
}
uikitUtil.trigger(this.$el, 'stop', [this, this.placeholder]);
uikitUtil.remove(this.drag);
this.drag = null;
var classes = this.touched.map(function (sortable) { return ((sortable.clsPlaceholder) + " " + (sortable.clsItem)); }).join(' ');
this.touched.forEach(function (sortable) { return uikitUtil.removeClass(sortable.$el.children, classes); });
uikitUtil.removeClass(document.documentElement, this.clsDragState);
},
scroll: function() {
var scroll = window.pageYOffset;
if (scroll !== this.scrollY) {
this.pos.y += scroll - this.scrollY;
this.scrollY = scroll;
this.$emit();
}
},
insert: function(element, target) {
var this$1 = this;
uikitUtil.addClass(this.$el.children, this.clsItem);
var insert = function () {
if (target) {
if (!uikitUtil.within(element, this$1.$el) || isPredecessor(element, target)) {
uikitUtil.before(target, element);
} else {
uikitUtil.after(target, element);
}
} else {
uikitUtil.append(this$1.$el, element);
}
};
if (this.animation) {
this.animate(insert);
} else {
insert();
}
},
remove: function(element) {
if (!uikitUtil.within(element, this.$el)) {
return;
}
uikitUtil.css(this.handle ? uikitUtil.$$(this.handle, element) : element, {touchAction: '', userSelect: ''});
if (this.animation) {
this.animate(function () { return uikitUtil.remove(element); });
} else {
uikitUtil.remove(element);
}
},
getSortable: function(element) {
return element && (this.$getComponent(element, 'sortable') || this.getSortable(element.parentNode));
}
}
};
function isPredecessor(element, target) {
return element.parentNode === target.parentNode && uikitUtil.index(element) > uikitUtil.index(target);
}
var trackTimer;
function trackScroll(ref) {
var x = ref.x;
var y = ref.y;
clearTimeout(trackTimer);
scrollParents(document.elementFromPoint(x - window.pageXOffset, y - window.pageYOffset)).some(function (scrollEl) {
var scroll = scrollEl.scrollTop;
var scrollHeight = scrollEl.scrollHeight;
if (getScrollingElement() === scrollEl) {
scrollEl = window;
scrollHeight -= window.innerHeight;
}
var ref = uikitUtil.offset(scrollEl);
var top = ref.top;
var bottom = ref.bottom;
if (top < y && top + 30 > y) {
scroll -= 5;
} else if (bottom > y && bottom - 20 < y) {
scroll += 5;
}
if (scroll > 0 && scroll < scrollHeight) {
return trackTimer = setTimeout(function () {
uikitUtil.scrollTop(scrollEl, scroll);
trackScroll({x: x, y: y});
}, 10);
}
});
}
function untrackScroll() {
clearTimeout(trackTimer);
}
var overflowRe = /auto|scroll/;
function scrollParents(element) {
var scrollEl = getScrollingElement();
return parents(element, function (parent) { return parent === scrollEl || overflowRe.test(uikitUtil.css(parent, 'overflow')); });
}
function parents(element, fn) {
var parents = [];
do {
if (fn(element)) {
parents.unshift(element);
}
} while (element && (element = element.parentElement));
return parents;
}
function getScrollingElement() {
return document.scrollingElement || document.documentElement;
}
/* global UIkit, 'sortable' */
if (typeof window !== 'undefined' && window.UIkit) {
window.UIkit.component('sortable', Component);
}
return Component;
}));