From 3a6072bc8f7b99777a441145dfa1ef63d24f5ba8 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Fri, 6 May 2022 13:58:55 +0200 Subject: [PATCH] :bug: Fix problem with RTL --- frontend/src/app/util/text_position_data.js | 66 ++++++++++++++++++++ frontend/src/app/util/text_svg_position.cljs | 55 +++++----------- 2 files changed, 81 insertions(+), 40 deletions(-) create mode 100644 frontend/src/app/util/text_position_data.js diff --git a/frontend/src/app/util/text_position_data.js b/frontend/src/app/util/text_position_data.js new file mode 100644 index 000000000..cb77fe8eb --- /dev/null +++ b/frontend/src/app/util/text_position_data.js @@ -0,0 +1,66 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright (c) UXBOX Labs SL + */ + +"use strict"; + +goog.provide("app.util.text_position_data"); + +goog.scope(function () { + const self = app.util.text_position_data; + const document = goog.global.document; + + function getRangeRects(node, start, end) { + const range = document.createRange(); + range.setStart(node, start); + range.setEnd(node, end); + return range.getClientRects(); + } + + self.parse_text_nodes = function(parent, direction, textNode) { + const content = textNode.textContent; + const textSize = content.length; + const rtl = direction === "rtl"; + + let from = 0; + let to = 0; + let current = ""; + let result = []; + + while (to < textSize) { + const rects = getRangeRects(textNode, from, to + 1); + + if (rects.length > 1) { + let position; + + if (rtl) { + position = rects[1]; + } else { + position = rects[0]; + } + + result.push({ + node: parent, + position: position, + text: current + }); + + from = to; + current = ""; + + } else { + current += content[to]; + to = to + 1; + } + } + + // to == textSize + const rects = getRangeRects(textNode, from, to); + result.push({node: parent, position: rects[0], text: current}); + return result; + }; +}); diff --git a/frontend/src/app/util/text_svg_position.cljs b/frontend/src/app/util/text_svg_position.cljs index d88039196..eff905a64 100644 --- a/frontend/src/app/util/text_svg_position.cljs +++ b/frontend/src/app/util/text_svg_position.cljs @@ -11,45 +11,20 @@ [app.common.transit :as transit] [app.main.store :as st] [app.util.dom :as dom] - [app.util.globals :as global])) + [app.util.text-position-data :as tpd])) -(defn get-range-rects - "Retrieve the rectangles that cover the selection given by a `node` adn - the start and end index `start-i`, `end-i`" - [^js node start-i end-i] - (let [^js range (.createRange global/document)] - (.setStart range node start-i) - (.setEnd range node end-i) - (.getClientRects range))) - -;; TODO: Evaluate to change this function to Javascript (defn parse-text-nodes "Given a text node retrieves the rectangles for everyone of its paragraphs and its text." - [parent-node rtl text-node] + [parent-node direction text-node] - (let [content (.-textContent text-node) - text-size (.-length content)] - - (loop [from-i 0 - to-i 0 - current "" - result []] - (if (>= to-i text-size) - (let [rects (get-range-rects text-node from-i to-i) - entry {:node parent-node - :position (dom/bounding-rect->rect (first rects)) - :text current}] - ;; We need to add the last element not closed yet - (conj result entry)) - - (let [rects (get-range-rects text-node from-i (inc to-i))] - ;; If the rects increase means we're in a new paragraph - (if (> (.-length rects) 1) - (let [entry {:node parent-node - :position (dom/bounding-rect->rect (if rtl (second rects) (first rects))) - :text current}] - (recur to-i to-i "" (conj result entry))) - (recur from-i (inc to-i) (str current (nth content to-i)) result))))))) + (letfn [(parse-entry [^js entry] + {:node (.-node entry) + :position (dom/bounding-rect->rect (.-position entry)) + :text (.-text entry)})] + (into + [] + (map parse-entry) + (tpd/parse-text-nodes parent-node direction text-node)))) (defn calc-text-node-positions @@ -87,9 +62,9 @@ (->> text-nodes (mapcat (fn [parent-node] - (let [rtl (= "rtl" (.-dir (.-parentElement parent-node)))] + (let [direction (.-direction (js/getComputedStyle parent-node))] (->> (.-childNodes parent-node) - (mapcat #(parse-text-nodes parent-node rtl %)))))) + (mapcat #(parse-text-nodes parent-node direction %)))))) (mapv #(update % :position translate-rect)))))) (defn calc-position-data @@ -102,15 +77,13 @@ (->> text-data (mapv (fn [{:keys [node position text]}] (let [{:keys [x y width height]} position - rtl (= "rtl" (.-dir (.-parentElement ^js node))) styles (js/getComputedStyle ^js node) get (fn [prop] (let [value (.getPropertyValue styles prop)] (when (and value (not= value "")) value)))] (d/without-nils - {:rtl rtl - :x (if rtl (+ x width) x) + {:x x :y (+ y height) :width width :height height @@ -123,3 +96,5 @@ :font-style (str (get "font-style")) :fills (transit/decode-str (get "--fills")) :text text})))))))))) + +