import { getRoot, types } from "mobx-state-tree"; import Utils from "../utils"; import Constants, { defaultStyle } from "../core/Constants"; import { highlightRange } from "../utils/html"; export default types .model() .views(() => ({})) .actions((self) => ({ updateSpansColor(bgcolor, opacity) { if (self._spans) { self._spans.forEach((span) => { if (bgcolor) { span.style.backgroundColor = bgcolor; } if (opacity) { span.style.backgroundColor = Utils.Colors.rgbaChangeAlpha(span.style.backgroundColor, opacity); } }); } }, updateAppearenceFromState() { const labelColor = self.getLabelColor(); self.updateSpansColor(labelColor, self.selected ? 0.8 : 0.3); self.applyCSSClass(self._lastSpan); }, createSpans() { const labelColor = self.getLabelColor(); const spans = highlightRange(self, "htx-highlight", { backgroundColor: labelColor }); const lastSpan = spans[spans.length - 1]; if (!lastSpan) return; self.applyCSSClass(lastSpan); self._lastSpan = lastSpan; self._spans = spans; return spans; }, getLabelColor() { let labelColor = self.parent.highlightcolor || (self.style || self.tag || defaultStyle).fillcolor; if (labelColor) { labelColor = Utils.Colors.convertToRGBA(labelColor, 0.3); } return labelColor; }, applyCSSClass(lastSpan) { if (!lastSpan) return; const classes = ["htx-highlight", "htx-highlight-last"]; const settings = getRoot(self).settings; if (!self.parent.showlabels && !settings?.showLabels) { classes.push("htx-no-label"); } else { // @todo multilabeling with different labels? const names = self.labeling?.mainValue; const cssCls = Utils.HTML.labelWithCSS(lastSpan, { index: self.region_index, labels: names, score: self.score, }); classes.push(cssCls); } lastSpan.className = classes.filter(Boolean).join(" "); }, addEventsToSpans(spans) { const addEvent = (s) => { s.onmouseover = (ev) => { if (self.hidden) return; if (self.annotation.isLinkingMode) { self.toggleHighlight(); s.style.cursor = Constants.LINKING_MODE_CURSOR; // only one span should be highlighted ev.stopPropagation(); } else { s.style.cursor = Constants.POINTER_CURSOR; } }; s.onmouseout = () => { if (self.hidden) return; self.setHighlight(false); }; s.onmousedown = function (ev) { if (self.hidden) return; // if we click to already selected span (=== this) // skip it to allow another span to be selected if (self.parent._currentSpan !== this) { ev.stopPropagation(); self.parent._currentSpan = this; } }; s.onclick = function () { if (self.hidden) return; // set above in `onmousedown`, can be nulled when new region created if (self.parent._currentSpan !== this) return; // reset for the case we just created new relation s.style.cursor = Constants.POINTER_CURSOR; self.onClickRegion(); }; return false; }; spans && spans.forEach((s) => addEvent(s)); }, selectRegion() { self.updateSpansColor(null, 0.8); const first = self._spans[0]; if (first) { if (first.scrollIntoViewIfNeeded) { first.scrollIntoViewIfNeeded(); } else { first.scrollIntoView({ block: "center", behavior: "smooth" }); } } }, /** * Unselect text region */ afterUnselectRegion() { self.updateSpansColor(null, 0.3); }, setHighlight(val) { self._highlighted = val; if (self._spans) { const len = self._spans.length; const fspan = self._spans[0]; const lspan = self._spans[len - 1]; const mspans = self._spans.slice(1, len - 1); const set = (span, s, { top = true, bottom = true, right = true, left = true } = {}) => { if (right) span.style.borderRight = s; if (left) span.style.borderLeft = s; if (top) span.style.borderTop = s; if (bottom) span.style.borderBottom = s; }; if (self.highlighted && !self.hidden) { const h = Constants.HIGHLIGHTED_CSS_BORDER; set(fspan, h, { right: false }); set(lspan, h, { left: false }); if (mspans.length) mspans.forEach((s) => set(s, h, { left: false, right: false })); } else { const zpx = "0px"; set(fspan, zpx); set(lspan, zpx); if (mspans.length) mspans.forEach((s) => set(s, zpx, { left: false, right: false })); } } }, toggleHidden(e) { self.hidden = !self.hidden; self.setHighlight(self.highlighted); if (self.hidden) { self.updateSpansColor("transparent", 0); if (self._spans) { self._spans.forEach((span) => { span.style.cursor = Constants.DEFAULT_CURSOR; }); } } else { self.updateAppearenceFromState(); } e?.stopPropagation(); }, find(span) { return self._spans && self._spans.indexOf(span) >= 0 ? self : undefined; }, }));