From 3d8ade3ebe6bf29a739f5a478594bec463a50a64 Mon Sep 17 00:00:00 2001 From: linonetwo Date: Sat, 16 Sep 2023 04:45:07 +0800 Subject: [PATCH] feat: redirect tm-focus-selector event to check parent or sibling --- boot/boot.js | 14 +++++++++ .../parsers/wikiparser/rules/blockid.js | 2 +- core/modules/startup/rootwidget.js | 2 ++ core/modules/widgets/blockid.js | 29 +++++++++++++++++-- core/modules/widgets/link.js | 8 +++++ themes/tiddlywiki/vanilla/base.tid | 13 +++++++++ 6 files changed, 65 insertions(+), 3 deletions(-) diff --git a/boot/boot.js b/boot/boot.js index 06d4628c0..2636cb8f4 100644 --- a/boot/boot.js +++ b/boot/boot.js @@ -2674,6 +2674,20 @@ $tw.hooks.addHook = function(hookName,definition) { } }; +/* +Delete hooks from the hashmap +*/ +$tw.hooks.removeHook = function(hookName,definition) { + if($tw.utils.hop($tw.hooks.names,hookName)) { + var index = $tw.hooks.names[hookName].findIndex(function(hook) { + return hook === definition; + }); + if(index !== -1) { + $tw.hooks.names[hookName].splice(index, 1); + } + } +}; + /* Invoke the hook by key */ diff --git a/core/modules/parsers/wikiparser/rules/blockid.js b/core/modules/parsers/wikiparser/rules/blockid.js index 84a0be41a..61438981b 100644 --- a/core/modules/parsers/wikiparser/rules/blockid.js +++ b/core/modules/parsers/wikiparser/rules/blockid.js @@ -39,7 +39,7 @@ exports.parse = function() { id: {type: "string", value: blockId || blockBeforeId}, // `true` means the block is before this node, in parent node's children list. // `false` means the block is this node's parent node. - before: {type: "boolean", value: Boolean(blockBeforeId)}, + previousSibling: {type: "boolean", value: Boolean(blockBeforeId)}, }, children: [] }]; diff --git a/core/modules/startup/rootwidget.js b/core/modules/startup/rootwidget.js index 716275cda..580c0e94d 100644 --- a/core/modules/startup/rootwidget.js +++ b/core/modules/startup/rootwidget.js @@ -72,6 +72,8 @@ exports.startup = function() { }); // Install the tm-focus-selector message $tw.rootWidget.addEventListener("tm-focus-selector",function(event) { + event = $tw.hooks.invokeHook("th-focus-selector",event); + if (!event) return; var selector = event.param || "", element, baseElement = event.event && event.event.target ? event.event.target.ownerDocument : document; diff --git a/core/modules/widgets/blockid.js b/core/modules/widgets/blockid.js index e5902ee35..0d915ab7a 100644 --- a/core/modules/widgets/blockid.js +++ b/core/modules/widgets/blockid.js @@ -18,9 +18,13 @@ BlockIdWidget.prototype.render = function(parent,nextSibling) { this.computeAttributes(); // Execute our logic this.execute(); + $tw.hooks.removeHook("th-focus-selector",this.hookFocusElementEvent); + this.hookFocusElementEvent = this.hookFocusElementEvent.bind(this); + $tw.hooks.addHook("th-focus-selector",this.hookFocusElementEvent); // Create an invisible DOM element with data that can be accessed from JS or CSS this.spanDomNode = this.document.createElement("span"); - this.spanDomNode.setAttribute("data-id",this.id); + this.spanDomNode.id = this.id; + this.spanDomNode.setAttribute("data-block-id",this.id); if(this.before) { this.spanDomNode.setAttribute("data-before","true"); } @@ -29,13 +33,34 @@ BlockIdWidget.prototype.render = function(parent,nextSibling) { this.domNodes.push(this.spanDomNode); }; +BlockIdWidget.prototype.hookFocusElementEvent = function(event) { + var id = event.param.replace('#',''); + if(id !== this.id) { + return event; + } + var element = this.parentDomNode; + // need to check if the block is before this node + if(this.previousSibling) { + element = element.previousSibling; + } + element.focus({ focusVisible: true }); + // toggle class to trigger highlight animation + $tw.utils.removeClass(element,"tc-focus-highlight"); + $tw.utils.addClass(element,"tc-focus-highlight"); + return false; +}; + +BlockIdWidget.prototype.removeChildDomNodes = function() { + $tw.hooks.removeHook("th-focus-selector",this.hookFocusElementEvent); +}; + /* Compute the internal state of the widget */ BlockIdWidget.prototype.execute = function() { // Get the id from the parse tree node or manually assigned attributes this.id = this.getAttribute("id"); - this.before = this.getAttribute("before"); + this.previousSibling = this.getAttribute("previousSibling"); // Make the child widgets this.makeChildWidgets(); }; diff --git a/core/modules/widgets/link.js b/core/modules/widgets/link.js index 6f199d395..12fc2da23 100755 --- a/core/modules/widgets/link.js +++ b/core/modules/widgets/link.js @@ -167,6 +167,13 @@ LinkWidget.prototype.handleClickEvent = function(event) { shiftKey: event.shiftKey, event: event }); + if(this.toBlockId) { + this.dispatchEvent({ + type: "tm-focus-selector", + param: "#" + this.toBlockId, + event: event, + }); + } if(this.domNodes[0].hasAttribute("href")) { event.preventDefault(); } @@ -180,6 +187,7 @@ Compute the internal state of the widget LinkWidget.prototype.execute = function() { // Pick up our attributes this.to = this.getAttribute("to",this.getVariable("currentTiddler")); + this.toBlockId = this.getAttribute("toBlockId"); this.tooltip = this.getAttribute("tooltip"); this["aria-label"] = this.getAttribute("aria-label"); this.linkClasses = this.getAttribute("class"); diff --git a/themes/tiddlywiki/vanilla/base.tid b/themes/tiddlywiki/vanilla/base.tid index 4603589ae..b7cb1a3fc 100644 --- a/themes/tiddlywiki/vanilla/base.tid +++ b/themes/tiddlywiki/vanilla/base.tid @@ -2413,6 +2413,19 @@ html body.tc-body.tc-single-tiddler-window { color: <>; } +@keyframes fadeHighlight { + 0% { + background-color: <>; + } + 100% { + background-color: transparent; + } +} + +.tc-focus-highlight { + animation: fadeHighlight 2s forwards; +} + @media (min-width: <>) { .tc-static-alert {