mirror of
https://github.com/discourse/discourse.git
synced 2025-01-29 14:03:18 +08:00
116 lines
3.2 KiB
JavaScript
116 lines
3.2 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";
|
|
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;
|
|
};
|