This repository has been archived on 2023-03-18. You can view files and clone it, but cannot push or open issues or pull requests.
osr-discourse-src/app/assets/javascripts/discourse/widgets/hooks.js.es6

131 lines
3.5 KiB
JavaScript

/*eslint no-loop-func:0*/
const CLICK_ATTRIBUTE_NAME = '_discourse_click_widget';
const CLICK_OUTSIDE_ATTRIBUTE_NAME = '_discourse_click_outside_widget';
const KEY_UP_ATTRIBUTE_NAME = '_discourse_key_up_widget';
const KEY_DOWN_ATTRIBUTE_NAME = '_discourse_key_down_widget';
const DRAG_ATTRIBUTE_NAME = '_discourse_drag_widget';
function buildHook(attributeName, setAttr) {
return class {
constructor(widget) {
this.widget = widget;
}
hook(node) {
if (setAttr) {
node.setAttribute(setAttr, true);
}
node[attributeName] = this.widget;
}
unhook(node) {
if (setAttr) {
node.removeAttribute(setAttr, true);
}
node[attributeName] = null;
}
};
}
export const WidgetClickHook = buildHook(CLICK_ATTRIBUTE_NAME);
export const WidgetClickOutsideHook = buildHook(CLICK_OUTSIDE_ATTRIBUTE_NAME, 'data-click-outside');
export const WidgetKeyUpHook = buildHook(KEY_UP_ATTRIBUTE_NAME);
export const WidgetKeyDownHook = buildHook(KEY_DOWN_ATTRIBUTE_NAME);
export const WidgetDragHook = buildHook(DRAG_ATTRIBUTE_NAME);
function nodeCallback(node, attrName, cb) {
const widget = findWidget(node, attrName);
if (widget) {
widget.rerenderResult(() => cb(widget));
}
}
function findWidget(node, attrName) {
while (node) {
const widget = node[attrName];
if (widget) { return widget; }
node = node.parentNode;
}
}
let _watchingDocument = false;
let _dragging;
const DRAG_NAME = "mousemove.discourse-widget-drag";
function cancelDrag(e, onDrag) {
$('body').removeClass('widget-dragging');
document.removeEventListener('touchmove', onDrag);
if (_dragging) {
if (_dragging.dragEnd) { _dragging.dragEnd(e); }
_dragging = null;
}
}
WidgetClickHook.setupDocumentCallback = function() {
if (_watchingDocument) { return; }
document.addEventListener('touchmove', e => {
e.preventDefault();
e.stopPropagation();
}, { passive: false, capture: true });
let widget;
let onDrag = dragE => {
const tt = dragE.targetTouches[0];
if (tt) {
dragE.preventDefault();
dragE.stopPropagation();
widget.drag(tt);
}
};
$(document).on('mousedown.discource-widget-drag, touchstart.discourse-widget-drag', e => {
cancelDrag(e, onDrag);
widget = findWidget(e.target, DRAG_ATTRIBUTE_NAME);
if (widget) {
e.preventDefault();
e.stopPropagation();
_dragging = widget;
$('body').addClass('widget-dragging');
$(document).on(DRAG_NAME, dragE => {
if (widget) {
widget.drag(dragE);
}
});
document.addEventListener('touchmove', onDrag, { passive: false, capture: true });
}
});
$(document).on('mouseup.discourse-widget-drag, touchend.discourse-widget-drag', e => cancelDrag(e, onDrag));
$(document).on('click.discourse-widget', e => {
nodeCallback(e.target, CLICK_ATTRIBUTE_NAME, w => w.click(e));
let node = e.target;
const $outside = $('[data-click-outside]');
$outside.each((i, outNode) => {
if (outNode.contains(node)) { return; }
const widget2 = outNode[CLICK_OUTSIDE_ATTRIBUTE_NAME];
if (widget2) {
widget2.clickOutside(e);
}
});
});
$(document).on('keyup.discourse-widget', e => {
nodeCallback(e.target, KEY_UP_ATTRIBUTE_NAME, w => w.keyUp(e));
});
$(document).on('keydown.discourse-widget', e => {
nodeCallback(e.target, KEY_DOWN_ATTRIBUTE_NAME, w => w.keyDown(e));
});
_watchingDocument = true;
};