From 486d53d03d65061894d4114c4c3f80fbb55ef865 Mon Sep 17 00:00:00 2001 From: hlomzik Date: Tue, 23 Nov 2021 12:38:29 +0300 Subject: [PATCH] Fix `showLabels` param and related settings (#360) * [fix] don't show null as label value * [fix] showLabels=false takes precedence * [fix] always show labels in NER until !showLabels previously NER labels were always shown despite the settings; but with showLabels=false labels depend on settings, so that was not `false` actually. * [fix] regions with and without label same height * [fix] showLabels unset by default; fix conditions very important thing: `label` is an array * [fix] settings couldn't affect explicit showLabels * [fix] ctrl+z with text regions' labels * comments about weird label type: array|string|null * [fix] copy .htx-no-label class from global.scss * [fix] add .htx-no-label to the generated styles * [fix] toggle labels also in every iframe Co-authored-by: niklub Co-authored-by: Nick Skriabin <767890+nicholasrq@users.noreply.github.com> --- src/mixins/HighlightMixin.js | 31 +++++++++++++++++++------- src/tags/object/RichText/RichText.styl | 7 +++++- src/tags/object/RichText/model.js | 2 +- src/utils/html.js | 22 +++++++++--------- src/utils/selection-tools.js | 7 +++--- 5 files changed, 46 insertions(+), 23 deletions(-) diff --git a/src/mixins/HighlightMixin.js b/src/mixins/HighlightMixin.js index 4c96fa562..2c2f94b1c 100644 --- a/src/mixins/HighlightMixin.js +++ b/src/mixins/HighlightMixin.js @@ -1,8 +1,9 @@ -import { getRoot, types } from "mobx-state-tree"; +import { types } from "mobx-state-tree"; import Utils from "../utils"; import { guidGenerator } from "../utils/unique"; import Constants, { defaultStyle } from "../core/Constants"; +import { isDefined } from "../utils/utilities"; export const HighlightMixin = types .model() @@ -47,10 +48,20 @@ export const HighlightMixin = types const labelColor = self.getLabelColor(); const identifier = guidGenerator(5); const stylesheet = createSpanStylesheet(root.ownerDocument, identifier, labelColor); + const classNames = ["htx-highlight", stylesheet.className]; + + if (!(self.parent.showlabels ?? self.store.settings.showLabels)) { + classNames.push("htx-no-label"); + } + + // in this case labels presence can't be changed from settings — manual mode + if (isDefined(self.parent.showlabels)) { + classNames.push("htx-manual-label"); + } self._stylesheet = stylesheet; self._spans = Utils.Selection.highlightRange(range, { - classNames: ["htx-highlight", stylesheet.className], + classNames, label: self.getLabels(), }); @@ -79,8 +90,11 @@ export const HighlightMixin = types updateSpans() { if (self._hasSpans) { const lastSpan = self._spans[self._spans.length - 1]; + const label = self.getLabels(); - lastSpan.setAttribute("data-label", self.getLabels()); + // label is array, string or null, so check for length + if (!label?.length) lastSpan.removeAttribute("data-label"); + else lastSpan.setAttribute("data-label", label); } }, @@ -100,7 +114,7 @@ export const HighlightMixin = types const lastSpan = self._spans[self._spans.length - 1]; self._stylesheet.setColor(self.getLabelColor()); - Utils.Selection.applySpanStyles(lastSpan, { label: "" }); + Utils.Selection.applySpanStyles(lastSpan, { label: self.getLabels() }); }, /** @@ -166,10 +180,6 @@ export const HighlightMixin = types }, getLabels() { - const settings = getRoot(self).settings; - - if (!self.parent.showlabels && !settings.showLabels) return null; - return self.labeling?.mainValue ?? []; }, @@ -228,6 +238,7 @@ const stateClass = { highlighted: "__highlighted", collapsed: "__collapsed", hidden: "__hidden", + noLabel: "htx-no-label", }; /** @@ -267,6 +278,7 @@ const createSpanStylesheet = (document, identifier, color) => { font-family: Monaco; vertical-align: super; content: attr(data-label); + line-height: 0; `, [classNames.active]: ` color: ${Utils.Colors.contrastColor(initialActiveColor)}; @@ -287,6 +299,9 @@ const createSpanStylesheet = (document, identifier, color) => { [`${className}.${stateClass.hidden}::after`]: ` display: none `, + [`${className}.${stateClass.noLabel}::after`]: ` + display: none + `, }; const styleTag = document.createElement("style"); diff --git a/src/tags/object/RichText/RichText.styl b/src/tags/object/RichText/RichText.styl index b10d4157a..a1dcbffd8 100644 --- a/src/tags/object/RichText/RichText.styl +++ b/src/tags/object/RichText/RichText.styl @@ -30,4 +30,9 @@ justify-content: center; align-items: center; background: rgba(125,125,125,.15); - font-size: 24px; \ No newline at end of file + font-size: 24px; + +// global.scss is not included to final build, so define it here +:global(.htx-no-label)::after { + display: none; +} diff --git a/src/tags/object/RichText/model.js b/src/tags/object/RichText/model.js index 4973a5383..e8785a0d2 100644 --- a/src/tags/object/RichText/model.js +++ b/src/tags/object/RichText/model.js @@ -65,7 +65,7 @@ const TagAttrs = types.model("RichTextModel", { highlightcolor: types.maybeNull(customTypes.color), - showlabels: types.optional(types.boolean, true), + showlabels: types.maybeNull(types.boolean), encoding: types.optional(types.enumeration(["none", "base64", "base64unicode"]), "none"), diff --git a/src/utils/html.js b/src/utils/html.js index 33c812d1c..fe6717f52 100644 --- a/src/utils/html.js +++ b/src/utils/html.js @@ -2,21 +2,23 @@ import insertAfter from "insert-after"; import * as Checkers from "./utilities"; import Canvas from "./canvas"; +// fast way to change labels visibility for all text regions function toggleLabelsAndScores(show) { - const els = document.getElementsByClassName("htx-highlight"); + const toggleInDocument = document => { + const els = document.getElementsByClassName("htx-highlight"); - Array.from(els).forEach(el => { - let foundCls = null; + Array.from(els).forEach(el => { + // labels presence controlled by explicit `showLabels` in the config + if (el.classList.contains("htx-manual-label")) return; - Array.from(el.classList).forEach(cls => { - if (cls.indexOf("htx-label-") !== -1) foundCls = cls; - }); - - if (foundCls !== null) { if (show) el.classList.remove("htx-no-label"); else el.classList.add("htx-no-label"); - } - }); + }); + }; + + toggleInDocument(document); + document.querySelectorAll("iframe.lsf-htx-richtext") + .forEach(iframe => toggleInDocument(iframe.contentWindow.document)); } const labelWithCSS = (function() { diff --git a/src/utils/selection-tools.js b/src/utils/selection-tools.js index acd53a5dc..bc70b6a10 100644 --- a/src/utils/selection-tools.js +++ b/src/utils/selection-tools.js @@ -362,7 +362,7 @@ export const highlightRange = (range, { label, classNames }) => { const lastLabel = highlights[highlights.length - 1]; - if (lastLabel) lastLabel.setAttribute("data-label", label); + if (lastLabel) lastLabel.setAttribute("data-label", label ?? ""); return highlights; }; @@ -454,8 +454,9 @@ export const applySpanStyles = (spanNode, { classNames, label }) => { spanNode.classList.add(...classNames); } - if (label === null) spanNode.removeAttribute("data-label"); - else if (label) spanNode.setAttribute("data-label", label); + // label is array, string or null, so check for length + if (!label?.length) spanNode.removeAttribute("data-label"); + else spanNode.setAttribute("data-label", label); }; /**