From e0a04acb067983efafbaf62132acdfa5367a8e3c Mon Sep 17 00:00:00 2001 From: Eva Date: Sun, 21 May 2023 14:28:14 +0200 Subject: [PATCH 1/3] client/search: fix js error when pressing esc key `this` became inaccessible from hide() when the function was called from outside. Note: I don't like the behavior of Escape and Delete, as pressing them more than once reverses their action. --- client/js/controls/auto_complete_control.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/js/controls/auto_complete_control.js b/client/js/controls/auto_complete_control.js index fb3792fc7..ac618d9cc 100644 --- a/client/js/controls/auto_complete_control.js +++ b/client/js/controls/auto_complete_control.js @@ -147,7 +147,9 @@ class AutoCompleteControl { let func = null; if (this._isVisible) { if (key === KEY_ESCAPE) { - func = this.hide; + func = () => { + this.hide(); + }; } else if (key === KEY_TAB && shift) { func = () => { this._selectPrevious(); From 337cdc091e605e7abee7e9763b5273f3c8923cea Mon Sep 17 00:00:00 2001 From: Eva Date: Mon, 6 May 2024 19:34:50 +0200 Subject: [PATCH 2/3] client: replace deprecated KeyboardEvent.which with KeyboardEvent.key Also fixes moving notes by arrow keys. Removed left click detection IE8 hack we inherited from the original visionmedia/page.js code (cf. https://unixpapa.com/js/mouse.html) as proper KeyboardEvent.key was introduced in IE9 and it's time to move on. ArrowUp/Down/Left/Right names have to be mangled to maintain IE9 compat. --- client/js/controls/auto_complete_control.js | 23 +++++-------- client/js/controls/file_dropper_control.js | 4 +-- client/js/controls/pool_input_control.js | 3 -- .../js/controls/post_notes_overlay_control.js | 34 +++++++------------ client/js/controls/tag_input_control.js | 5 +-- client/js/router.js | 7 +--- client/js/views/post_merge_view.js | 4 +-- 7 files changed, 25 insertions(+), 55 deletions(-) diff --git a/client/js/controls/auto_complete_control.js b/client/js/controls/auto_complete_control.js index ac618d9cc..ecd5baddf 100644 --- a/client/js/controls/auto_complete_control.js +++ b/client/js/controls/auto_complete_control.js @@ -2,13 +2,6 @@ const views = require("../util/views.js"); -const KEY_TAB = 9; -const KEY_RETURN = 13; -const KEY_DELETE = 46; -const KEY_ESCAPE = 27; -const KEY_UP = 38; -const KEY_DOWN = 40; - function _getSelectionStart(input) { if ("selectionStart" in input) { return input.selectionStart; @@ -142,36 +135,36 @@ class AutoCompleteControl { } _evtKeyDown(e) { - const key = e.which; + const key = (e.key || "").replace("Arrow", ""); const shift = e.shiftKey; let func = null; if (this._isVisible) { - if (key === KEY_ESCAPE) { + if (key === "Escape") { func = () => { this.hide(); }; - } else if (key === KEY_TAB && shift) { + } else if (key === "Tab" && shift) { func = () => { this._selectPrevious(); }; - } else if (key === KEY_TAB && !shift) { + } else if (key === "Tab" && !shift) { func = () => { this._selectNext(); }; - } else if (key === KEY_UP) { + } else if (key === "Up") { func = () => { this._selectPrevious(); }; - } else if (key === KEY_DOWN) { + } else if (key === "Down") { func = () => { this._selectNext(); }; - } else if (key === KEY_RETURN && this._activeResult >= 0) { + } else if (key === "Enter" && this._activeResult >= 0) { func = () => { this._confirm(this._getActiveSuggestion()); this.hide(); }; - } else if (key === KEY_DELETE && this._activeResult >= 0) { + } else if (key === "Delete" && this._activeResult >= 0) { func = () => { this._delete(this._getActiveSuggestion()); this.hide(); diff --git a/client/js/controls/file_dropper_control.js b/client/js/controls/file_dropper_control.js index 2dfb49229..579b39afa 100644 --- a/client/js/controls/file_dropper_control.js +++ b/client/js/controls/file_dropper_control.js @@ -5,8 +5,6 @@ const views = require("../util/views.js"); const template = views.getTemplate("file-dropper"); -const KEY_RETURN = 13; - class FileDropperControl extends events.EventTarget { constructor(target, options) { super(); @@ -130,7 +128,7 @@ class FileDropperControl extends events.EventTarget { } _evtUrlInputKeyDown(e) { - if (e.which !== KEY_RETURN) { + if (e.key !== "Enter") { return; } e.preventDefault(); diff --git a/client/js/controls/pool_input_control.js b/client/js/controls/pool_input_control.js index c8995da83..0d769d9b6 100644 --- a/client/js/controls/pool_input_control.js +++ b/client/js/controls/pool_input_control.js @@ -10,9 +10,6 @@ const events = require("../events.js"); const views = require("../util/views.js"); const PoolAutoCompleteControl = require("./pool_auto_complete_control.js"); -const KEY_SPACE = 32; -const KEY_RETURN = 13; - const SOURCE_INIT = "init"; const SOURCE_IMPLICATION = "implication"; const SOURCE_USER_INPUT = "user-input"; diff --git a/client/js/controls/post_notes_overlay_control.js b/client/js/controls/post_notes_overlay_control.js index e9aad045a..1be6cdd0d 100644 --- a/client/js/controls/post_notes_overlay_control.js +++ b/client/js/controls/post_notes_overlay_control.js @@ -11,15 +11,6 @@ const svgNS = "http://www.w3.org/2000/svg"; const snapThreshold = 10; const circleSize = 10; -const MOUSE_BUTTON_LEFT = 1; - -const KEY_LEFT = 37; -const KEY_UP = 38; -const KEY_RIGHT = 39; -const KEY_DOWN = 40; -const KEY_ESCAPE = 27; -const KEY_RETURN = 13; - function _getDistance(point1, point2) { return Math.sqrt( Math.pow(point1.x - point2.x, 2) + Math.pow(point1.y - point2.y, 2) @@ -188,16 +179,17 @@ class SelectedState extends ActiveState { evtCanvasKeyDown(e) { const delta = e.ctrlKey ? 10 : 1; const offsetMap = { - [KEY_LEFT]: [-delta, 0], - [KEY_UP]: [0, -delta], - [KEY_DOWN]: [0, delta], - [KEY_RIGHT]: [delta, 0], + ["Left"]: [-delta, 0], + ["Up"]: [0, -delta], + ["Down"]: [0, delta], + ["Right"]: [delta, 0], }; - if (Object.prototype.hasOwnProperty.call(offsetMap, e.witch)) { + const key = (e.key || "").replace("Arrow", ""); + if (Object.prototype.hasOwnProperty.call(offsetMap, key)) { e.stopPropagation(); e.stopImmediatePropagation(); e.preventDefault(); - const args = offsetMap[e.which]; + const args = offsetMap[key]; if (e.shiftKey) { this._scaleEditedNote(...args); } else { @@ -331,7 +323,7 @@ class MovingPointState extends ActiveState { } evtCanvasKeyDown(e) { - if (e.which === KEY_ESCAPE) { + if (e.key === "Escape") { this._notePoint.x = this._originalNotePoint.x; this._notePoint.y = this._originalNotePoint.y; this._control._state = new SelectedState( @@ -364,7 +356,7 @@ class MovingNoteState extends ActiveState { } evtCanvasKeyDown(e) { - if (e.which === KEY_ESCAPE) { + if (e.key === "Escape") { for (let i of misc.range(this._note.polygon.length)) { this._note.polygon.at(i).x = this._originalPolygon[i].x; this._note.polygon.at(i).y = this._originalPolygon[i].y; @@ -402,7 +394,7 @@ class ScalingNoteState extends ActiveState { } evtCanvasKeyDown(e) { - if (e.which === KEY_ESCAPE) { + if (e.key === "Escape") { for (let i of misc.range(this._note.polygon.length)) { this._note.polygon.at(i).x = this._originalPolygon[i].x; this._note.polygon.at(i).y = this._originalPolygon[i].y; @@ -516,12 +508,12 @@ class DrawingPolygonState extends ActiveState { } evtCanvasKeyDown(e) { - if (e.which === KEY_ESCAPE) { + if (e.key === "Escape") { this._note.polygon.remove(this._note.polygon.secondLastPoint); if (this._note.polygon.length === 1) { this._cancel(); } - } else if (e.which === KEY_RETURN) { + } else if (e.key === "Enter") { this._finish(); } } @@ -683,7 +675,7 @@ class PostNotesOverlayControl extends events.EventTarget { _evtCanvasMouseDown(e) { e.preventDefault(); - if (e.which !== MOUSE_BUTTON_LEFT) { + if (e.button !== 0) { return; } const hoveredNode = document.elementFromPoint(e.clientX, e.clientY); diff --git a/client/js/controls/tag_input_control.js b/client/js/controls/tag_input_control.js index cca58d5b7..6656abff8 100644 --- a/client/js/controls/tag_input_control.js +++ b/client/js/controls/tag_input_control.js @@ -10,9 +10,6 @@ const events = require("../events.js"); const views = require("../util/views.js"); const TagAutoCompleteControl = require("./tag_auto_complete_control.js"); -const KEY_SPACE = 32; -const KEY_RETURN = 13; - const SOURCE_INIT = "init"; const SOURCE_IMPLICATION = "implication"; const SOURCE_USER_INPUT = "user-input"; @@ -273,7 +270,7 @@ class TagInputControl extends events.EventTarget { } _evtInputKeyDown(e) { - if (e.which === KEY_RETURN || e.which === KEY_SPACE) { + if (e.key === "Enter" || e.key === " ") { e.preventDefault(); this._hideAutoComplete(); this.addTagByText(this._tagInputNode.value, SOURCE_USER_INPUT); diff --git a/client/js/router.js b/client/js/router.js index 460a64151..b55ca78c1 100644 --- a/client/js/router.js +++ b/client/js/router.js @@ -258,7 +258,7 @@ const _onPopState = (router) => { const _onClick = (router) => { return (e) => { - if (1 !== _which(e)) { + if (e.button !== 0) { return; } if (e.metaKey || e.ctrlKey || e.shiftKey) { @@ -310,11 +310,6 @@ const _onClick = (router) => { }; }; -function _which(e) { - e = e || window.event; - return e.which === null ? e.button : e.which; -} - Router.prototype.Context = Context; Router.prototype.Route = Route; module.exports = new Router(); diff --git a/client/js/views/post_merge_view.js b/client/js/views/post_merge_view.js index 20924d37e..6fe4210f8 100644 --- a/client/js/views/post_merge_view.js +++ b/client/js/views/post_merge_view.js @@ -3,7 +3,6 @@ const events = require("../events.js"); const views = require("../util/views.js"); -const KEY_RETURN = 13; const template = views.getTemplate("post-merge"); const sideTemplate = views.getTemplate("post-merge-side"); @@ -110,8 +109,7 @@ class PostMergeView extends events.EventTarget { } _evtPostSearchFieldKeyDown(e) { - const key = e.which; - if (key !== KEY_RETURN) { + if (e.key !== "Enter") { return; } e.target.blur(); From 5e54caf04c3cb5dd3794c560aec86830b2ec5a87 Mon Sep 17 00:00:00 2001 From: Eva Date: Mon, 6 May 2024 19:39:56 +0200 Subject: [PATCH 3/3] client/views: fix middle click prevention on buttons for modern browsers Browsers no longer fire the primary 'click' event for middle clicks. Old way kept for compatibility as it doesn't hurt anything. All browsers that support auxclick also have standardized MouseEvent.button values. --- client/js/util/views.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/client/js/util/views.js b/client/js/util/views.js index f6280a1c8..3ea3a336a 100644 --- a/client/js/util/views.js +++ b/client/js/util/views.js @@ -571,6 +571,11 @@ document.addEventListener("click", (e) => { e.preventDefault(); } }); +document.addEventListener("auxclick", (e) => { + if (e.target.getAttribute("href") === "" && e.button === 1) { + e.preventDefault(); + } +}); module.exports = { htmlToDom: htmlToDom,