From c177aaa901a9388bbce5341b3e6fdb41195dcbe2 Mon Sep 17 00:00:00 2001 From: zadam Date: Sun, 4 Jun 2023 17:46:37 +0200 Subject: [PATCH] refactoring of highlight list --- src/public/app/layouts/desktop_layout.js | 4 +- ...highlighted_text.js => highlights_list.js} | 174 +++++++++--------- .../options/text_notes/highlighted_text.js | 26 +-- 3 files changed, 104 insertions(+), 100 deletions(-) rename src/public/app/widgets/{highlighted_text.js => highlights_list.js} (51%) diff --git a/src/public/app/layouts/desktop_layout.js b/src/public/app/layouts/desktop_layout.js index e5c440cdc..cd5bb1912 100644 --- a/src/public/app/layouts/desktop_layout.js +++ b/src/public/app/layouts/desktop_layout.js @@ -44,7 +44,7 @@ import BacklinksWidget from "../widgets/floating_buttons/zpetne_odkazy.js"; import SharedInfoWidget from "../widgets/shared_info.js"; import FindWidget from "../widgets/find.js"; import TocWidget from "../widgets/toc.js"; -import HighlightedTextWidget from "../widgets/highlighted_text.js"; +import HighlightsListWidget from "../widgets/highlights_list.js"; import BulkActionsDialog from "../widgets/dialogs/bulk_actions.js"; import AboutDialog from "../widgets/dialogs/about.js"; import HelpDialog from "../widgets/dialogs/help.js"; @@ -185,7 +185,7 @@ export default class DesktopLayout { ) .child(new RightPaneContainer() .child(new TocWidget()) - .child(new HighlightedTextWidget()) + .child(new HighlightsListWidget()) .child(...this.customWidgets.get('right-pane')) ) ) diff --git a/src/public/app/widgets/highlighted_text.js b/src/public/app/widgets/highlights_list.js similarity index 51% rename from src/public/app/widgets/highlighted_text.js rename to src/public/app/widgets/highlights_list.js index daced39d4..4e88e9e45 100644 --- a/src/public/app/widgets/highlighted_text.js +++ b/src/public/app/widgets/highlights_list.js @@ -1,7 +1,7 @@ /** * Widget: Show highlighted text in the right pane * - * By design there's no support for nonsensical or malformed constructs: + * By design, there's no support for nonsensical or malformed constructs: * - For example, if there is a formula in the middle of the highlighted text, the two ends of the formula will be regarded as two entries */ @@ -10,20 +10,20 @@ import RightPanelWidget from "./right_panel_widget.js"; import options from "../services/options.js"; import OnClickButtonWidget from "./buttons/onclick_button.js"; -const TPL = `
+const TPL = `
- +
`; -export default class HighlightedTextWidget extends RightPanelWidget { +export default class HighlightsListWidget extends RightPanelWidget { constructor() { super(); @@ -67,38 +67,38 @@ export default class HighlightedTextWidget extends RightPanelWidget { async doRenderBody() { this.$body.empty().append($(TPL)); - this.$hlt = this.$body.find('.highlighted-text'); - this.$body.find('.highlighted-text-widget').append(this.closeHltButton.render()); + this.$highlightsList = this.$body.find('.highlists-list'); + this.$body.find('.highlists-list-widget').append(this.closeHltButton.render()); } async refreshWithNote(note) { - /*The reason for adding highlightedTextPreviousVisible is to record whether the previous state of the highlightedText is hidden or displayed, - * and then let it be displayed/hidden at the initial time. - * If there is no such value, when the right panel needs to display toc but not highlighttext, every time the note content is changed, - * highlighttext Widget will appear and then close immediately, because getHlt function will consume time*/ - if (this.noteContext.viewScope.highlightedTextPreviousVisible == true) { + /* The reason for adding highlightedTextPreviousVisible is to record whether the previous state + of the highlightedText is hidden or displayed, and then let it be displayed/hidden at the initial time. + If there is no such value, when the right panel needs to display toc but not highlighttext, + every time the note content is changed, highlighttext Widget will appear and then close immediately, + because getHlt function will consume time */ + if (this.noteContext.viewScope.highlightedTextPreviousVisible) { this.toggleInt(true); } else { this.toggleInt(false); } - const hltLabel = note.getLabel('hideHighlightWidget'); const optionsHlt = JSON.parse(options.get('highlightedText')); - if (hltLabel?.value == "" || hltLabel?.value === "true" || optionsHlt == "") { + if (note.isLabelTruthy('hideHighlightWidget') || !optionsHlt) { this.toggleInt(false); this.triggerCommand("reEvaluateRightPaneVisibility"); return; } - let $hlt = "", hltLiCount = -1; + let $highlightsList = "", hltLiCount = -1; // Check for type text unconditionally in case alwaysShowWidget is set if (this.note.type === 'text') { - const { content } = await note.getNoteComplement(); - ({ $hlt, hltLiCount } = await this.getHlt(content, optionsHlt)); + const {content} = await note.getNoteComplement(); + ({$highlightsList, hltLiCount} = this.getHighlightList(content, optionsHlt)); } - this.$hlt.html($hlt); - if ([undefined, "false"].includes(hltLabel?.value) && hltLiCount > 0) { + this.$highlightsList.empty().append($highlightsList); + if (hltLiCount > 0) { this.toggleInt(true); this.noteContext.viewScope.highlightedTextPreviousVisible = true; } else { @@ -109,12 +109,9 @@ export default class HighlightedTextWidget extends RightPanelWidget { this.triggerCommand("reEvaluateRightPaneVisibility"); } - /** - * Builds a table of helight text. - */ - getHlt(html, optionsHlt) { + getHighlightList(content, optionsHlt) { // matches a span containing background-color - const regex1 = /]*style\s*=\s*[^>]*background-color:[^>]*?>[\s\S]*?<\/span>/gi; + const regex1 = /]*style\s*=\s*[^>]*background-color:[^>]*?>[\s\S]*?<\/span>/gi; // matches a span containing color const regex2 = /]*style\s*=\s*[^>]*[^-]color:[^>]*?>[\s\S]*?<\/span>/gi; // match italics @@ -125,97 +122,103 @@ export default class HighlightedTextWidget extends RightPanelWidget { const regex5 = /[\s\S]*?<\/u>/g; // Possible values in optionsHlt: '["bold","italic","underline","color","bgColor"]' // element priority: span>i>strong>u - let findSubStr="", combinedRegexStr = ""; - if (optionsHlt.indexOf("bgColor") >= 0){ - findSubStr+=`,span[style*="background-color"]`; - combinedRegexStr+=`|${regex1.source}`; + let findSubStr = "", combinedRegexStr = ""; + if (optionsHlt.includes("bgColor")) { + findSubStr += `,span[style*="background-color"]`; + combinedRegexStr += `|${regex1.source}`; } - if (optionsHlt.indexOf("color") >= 0){ - findSubStr+=`,span[style*="color"]`; - combinedRegexStr+=`|${regex2.source}`; + if (optionsHlt.includes("color")) { + findSubStr += `,span[style*="color"]`; + combinedRegexStr += `|${regex2.source}`; } - if (optionsHlt.indexOf("italic") >= 0){ - findSubStr+=`,i`; - combinedRegexStr+=`|${regex3.source}`; + if (optionsHlt.includes("italic")) { + findSubStr += `,i`; + combinedRegexStr += `|${regex3.source}`; } - if (optionsHlt.indexOf("bold") >= 0){ - findSubStr+=`,strong`; - combinedRegexStr+=`|${regex4.source}`; + if (optionsHlt.indexOf("bold")) { + findSubStr += `,strong`; + combinedRegexStr += `|${regex4.source}`; } - if (optionsHlt.indexOf("underline") >= 0){ - findSubStr+=`,u`; - combinedRegexStr+=`|${regex5.source}`; + if (optionsHlt.includes("underline")) { + findSubStr += `,u`; + combinedRegexStr += `|${regex5.source}`; } findSubStr = findSubStr.substring(1) combinedRegexStr = `(` + combinedRegexStr.substring(1) + `)`; const combinedRegex = new RegExp(combinedRegexStr, 'gi'); - let $hlt = $("
    "); + const $highlightsList = $("
      "); let prevEndIndex = -1, hltLiCount = 0; - for (let match = null, hltIndex=0; ((match = combinedRegex.exec(html)) !== null); hltIndex++) { - var subHtml = match[0]; + for (let match = null, hltIndex = 0; ((match = combinedRegex.exec(content)) !== null); hltIndex++) { + const subHtml = match[0]; const startIndex = match.index; const endIndex = combinedRegex.lastIndex; - if (prevEndIndex != -1 && startIndex === prevEndIndex) { - //If the previous element is connected to this element in HTML, then concatenate them into one. - $hlt.children().last().append(subHtml); + if (prevEndIndex !== -1 && startIndex === prevEndIndex) { + // If the previous element is connected to this element in HTML, then concatenate them into one. + $highlightsList.children().last().append(subHtml); } else { - //hide li if its text content is empty - if ([...subHtml.matchAll(/(?<=^|>)[^><]+?(?=<|$)/g)].map(matchTmp => matchTmp[0]).join('').trim() != ""){ - var $li = $('
    1. '); - $li.html(subHtml); - $li.on("click", () => this.jumpToHlt(findSubStr,hltIndex)); - $hlt.append($li); + // TODO: can't be done with $(subHtml).text()? + const hasText = [...subHtml.matchAll(/(?<=^|>)[^><]+?(?=<|$)/g)].map(matchTmp => matchTmp[0]).join('').trim(); + + if (hasText) { + $highlightsList.append( + $('
    2. ') + .html(subHtml) + .on("click", () => this.jumpToHighlightedText(findSubStr, hltIndex)) + ); + hltLiCount++; - }else{ - continue + } else { + // hide li if its text content is empty + continue; } } prevEndIndex = endIndex; } return { - $hlt, + $highlightsList, hltLiCount }; } - async jumpToHlt(findSubStr,hltIndex) { + + async jumpToHighlightedText(findSubStr, itemIndex) { const isReadOnly = await this.noteContext.isReadOnly(); let targetElement; if (isReadOnly) { const $container = await this.noteContext.getContentElement(); - targetElement=$container.find(findSubStr).filter(function() { - if (findSubStr.indexOf("color")>=0 && findSubStr.indexOf("background-color")<0){ + targetElement = $container.find(findSubStr).filter(function () { + if (findSubStr.indexOf("color") >= 0 && findSubStr.indexOf("background-color") < 0) { let color = this.style.color; - return $(this).prop('tagName')=="SPAN" && color==""?false:true; - }else{ + return !($(this).prop('tagName') === "SPAN" && color === ""); + } else { return true; - } - }).filter(function() { - return $(this).parent(findSubStr).length === 0 - && $(this).parent().parent(findSubStr).length === 0 - && $(this).parent().parent().parent(findSubStr).length === 0 - && $(this).parent().parent().parent().parent(findSubStr).length === 0; + } + }).filter(function () { + return $(this).parent(findSubStr).length === 0 + && $(this).parent().parent(findSubStr).length === 0 + && $(this).parent().parent().parent(findSubStr).length === 0 + && $(this).parent().parent().parent().parent(findSubStr).length === 0; }) } else { const textEditor = await this.noteContext.getTextEditor(); - targetElement=$(textEditor.editing.view.domRoots.values().next().value).find(findSubStr).filter(function() { - // When finding span[style*="color"] but not looking for span[style*="background-color"], + targetElement = $(textEditor.editing.view.domRoots.values().next().value).find(findSubStr).filter(function () { + // When finding span[style*="color"] but not looking for span[style*="background-color"], // the background-color error will be regarded as color, so it needs to be filtered - if (findSubStr.indexOf("color")>=0 && findSubStr.indexOf("background-color")<0){ + if (findSubStr.indexOf("color") >= 0 && findSubStr.indexOf("background-color") < 0) { let color = this.style.color; - return $(this).prop('tagName')=="SPAN" && color==""?false:true; - }else{ + return !($(this).prop('tagName') === "SPAN" && color === ""); + } else { return true; - } - }).filter(function() { - //Need to filter out the child elements of the element that has been found - return $(this).parent(findSubStr).length === 0 - && $(this).parent().parent(findSubStr).length === 0 - && $(this).parent().parent().parent(findSubStr).length === 0 - && $(this).parent().parent().parent().parent(findSubStr).length === 0; + } + }).filter(function () { + // Need to filter out the child elements of the element that has been found + return $(this).parent(findSubStr).length === 0 + && $(this).parent().parent(findSubStr).length === 0 + && $(this).parent().parent().parent(findSubStr).length === 0 + && $(this).parent().parent().parent().parent(findSubStr).length === 0; }) } - targetElement[hltIndex].scrollIntoView({ + targetElement[itemIndex].scrollIntoView({ behavior: "smooth", block: "center" }); } @@ -226,7 +229,7 @@ export default class HighlightedTextWidget extends RightPanelWidget { this.triggerCommand('reEvaluateRightPaneVisibility'); } - async entitiesReloadedEvent({ loadResults }) { + async entitiesReloadedEvent({loadResults}) { if (loadResults.isNoteContentReloaded(this.noteId)) { await this.refresh(); } else if (loadResults.getAttributes().find(attr => attr.type === 'label' @@ -237,7 +240,6 @@ export default class HighlightedTextWidget extends RightPanelWidget { } } - class CloseHltButton extends OnClickButtonWidget { constructor() { super(); @@ -250,6 +252,6 @@ class CloseHltButton extends OnClickButtonWidget { widget.triggerCommand("closeHlt"); }) - .class("icon-action close-highlighted-text"); + .class("icon-action close-highlists-list"); } } diff --git a/src/public/app/widgets/type_widgets/options/text_notes/highlighted_text.js b/src/public/app/widgets/type_widgets/options/text_notes/highlighted_text.js index 4f96999cc..72d0ccd49 100644 --- a/src/public/app/widgets/type_widgets/options/text_notes/highlighted_text.js +++ b/src/public/app/widgets/type_widgets/options/text_notes/highlighted_text.js @@ -4,13 +4,15 @@ const TPL = `

      Highlighted Text

      - You can customize the highlighted text displayed in the right panel:
      +

      You can customize the highlighted text displayed in the right panel:

      - - - - - +
      + + + + + +
`; export default class HighlightedTextOptions extends OptionsWidget { @@ -18,20 +20,20 @@ export default class HighlightedTextOptions extends OptionsWidget { this.$widget = $(TPL); this.$hlt = this.$widget.find("input.highlighted-text-check"); this.$hlt.on('change', () => { - const hltVals=this.$widget.find('input.highlighted-text-check[type="checkbox"]:checked').map(function() { + const hltVals = this.$widget.find('input.highlighted-text-check[type="checkbox"]:checked').map(function () { return this.value; - }).get(); + }).get(); this.updateOption('highlightedText', JSON.stringify(hltVals)); - }); + }); } async optionsLoaded(options) { - const hltVals=JSON.parse(options.highlightedText); + const hltVals = JSON.parse(options.highlightedText); this.$widget.find('input.highlighted-text-check[type="checkbox"]').each(function () { if ($.inArray($(this).val(), hltVals) !== -1) { - $(this).prop("checked", true); + $(this).prop("checked", true); } else { - $(this).prop("checked", false); + $(this).prop("checked", false); } }); }