(function() {
/**
* enables drag and drop
*
* parameters:
* - object: defines the DOM object to be moved
* - area (optional): defines the area that should be reactive to pointer events; if no area is provided the object is used
* - remoteMode (optional): defines whether the WA is used by the DA to adopt behavior
*
* @augments Help4.jscore.Base
*/
Help4.jscore.DragDrop = class extends Help4.jscore.Base {
/**
* @override
* @param {Help4.control2.DragDropParams} params
*/
constructor(params) {
super({
statics: {
_params: {init: params, destroy: false},
_ctl: {init: {x: 0, y: 0}, destroy: false},
_pos: {init: {x: 0, y: 0}, destroy: false},
_min: {init: {x: 0, y: 0}, destroy: false},
_max: {init: {x: 0, y: 0}, destroy: false},
_ps: {init: event => event.target === dom || Help4.Element.isDescendant(dom, event.target) ? _start.call(this, event) : true, destroy: false},
_pm: {init: event => void _move.call(this, event), destroy: false},
_pe: {init: event => void _end.call(this, event), destroy: false},
onStart: {init: new Help4.EmbeddedEvent()},
onMove: {init: new Help4.EmbeddedEvent()},
onEnd: {init: new Help4.EmbeddedEvent()}
}
});
const {_params, _ps} = this;
const {area, object} = _params;
const dom = area || object;
Help4.Element.addClass(dom, 'dnd');
dom.onselectstart = () => false;
dom.ondragstart = () => false;
Help4.Event.observe(dom, {manual: true, eventType: 'pointerdown', callback: _ps});
}
/** destroys the control */
destroy() {
const {Event, Element} = Help4;
const {_params, _ps} = this;
const {area, object} = _params;
const dom = area || object;
Event.stopObserving(dom, {manual: true, eventType: 'pointerdown', callback: _ps});
Element.removeClass(dom, 'dnd');
dom.onselectstart = null;
dom.ondragstart = null;
_end.call(this);
super.destroy();
}
}
/**
* @methodOf Help4.jscore.DragDrop#
* @param {PointerEvent} event
* @returns {boolean}
* @private
*/
function _start(event) {
const {_params, _pm, _pe} = this;
if (!_params.remoteMode) {
if (event.preventDefault) event.preventDefault();
event.target.setPointerCapture(event.pointerId);
}
this._doss = document.onselectstart;
document.onselectstart = () => false;
const {Element, Event} = Help4;
if ((event = Help4.Event.normalize(event))) {
const {object, min, max} = _params;
const s = getComputedStyle(object);
const r = object.getBoundingClientRect();
this._ctl = {x: parseFloat(s.left) - r.left, y: parseFloat(s.top) - r.top};
this._pos = {x: event.clientX - r.left, y: event.clientY - r.top};
this._max = max || {x: window.innerWidth - r.width, y: window.innerHeight - r.height};
if (min != null) this._min = min;
Element.addClass(object, 'no-transition');
this._started = true;
this.onStart.onEvent({data: event});
}
Event.observe(window, {manual: true, eventType: 'pointermove', callback: _pm});
Event.observe(window, {manual: true, eventType: 'pointerup', callback: _pe});
return false;
}
/**
* @methodOf Help4.jscore.DragDrop#
* @param {PointerEvent} event
* @private
*/
function _move(event) {
if (!(event = Help4.Event.normalize(event))) return;
this._moved = true;
this.onMove.onEvent({data: event});
const {_pos: {x: posX, y: posY}, _min: {x: minX, y: minY}, _max: {x: maxX, y: maxY}} = this;
const x = Math.max(minX, Math.min(event.clientX - posX, maxX));
const y = Math.max(minY, Math.min(event.clientY - posY, maxY));
const {_params: {object: {style}}, _ctl: {x: ctlX, y: ctlY}} = this;
style.left = ctlX + x + 'px';
style.top = ctlY + y + 'px';
}
/**
* @methodOf Help4.jscore.DragDrop#
* @param {PointerEvent} [event]
* @private
*/
function _end(event) {
const {Event, Element} = Help4;
const {_pm, _pe} = this;
Event.stopObserving(window, {manual: true, eventType: 'pointermove', callback: _pm});
Event.stopObserving(window, {manual: true, eventType: 'pointerup', callback: _pe});
const {_params} = this;
if (event && !_params.remoteMode) event.target.releasePointerCapture(event.pointerId);
document.onselectstart = this._doss;
delete this._doss;
delete this._moved;
Element.removeClass(_params.object, 'no-transition');
if (this._started) {
this.onEnd.onEvent({data: null});
delete this._started;
}
}
})();