/*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"; const DRAG_NAME_TOUCH = "touchmove.discourse-widget-drag"; function cancelDrag() { $('body').removeClass('widget-dragging'); $(document).off(DRAG_NAME).off(DRAG_NAME_TOUCH); if (_dragging) { if (_dragging.dragEnd) { _dragging.dragEnd(); } _dragging = null; } } WidgetClickHook.setupDocumentCallback = function() { if (_watchingDocument) { return; } $(document).on('mousedown.discource-widget-drag, touchstart.discourse-widget-drag', e => { cancelDrag(); const widget = findWidget(e.target, DRAG_ATTRIBUTE_NAME); if (widget) { e.preventDefault(); e.stopPropagation(); _dragging = widget; $('body').addClass('widget-dragging'); $(document).on(DRAG_NAME, dragE => widget.drag(dragE)); $(document).on(DRAG_NAME_TOUCH, dragE => { const tt = dragE.originalEvent.targetTouches[0]; if (tt) { widget.drag(tt); } }); } }); $(document).on('mouseup.discourse-widget-drag, touchend.discourse-widget-drag', () => cancelDrag()); $(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 widget = outNode[CLICK_OUTSIDE_ATTRIBUTE_NAME]; if (widget) { widget.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; };