mirror of
https://github.com/penpot/penpot.git
synced 2025-02-13 10:38:13 -05:00
✨ Allow to unselect the text alignment.
Defaulting to 'start' (rtl friendly).
This commit is contained in:
parent
ca52f4f8ea
commit
7bc91e7224
7 changed files with 298 additions and 216 deletions
|
@ -454,7 +454,6 @@
|
|||
(if (empty? rch-operations) rch (conj rch rchg))
|
||||
(if (empty? uch-operations) uch (conj uch uchg)))))))))))
|
||||
|
||||
|
||||
(defn update-shapes-recursive
|
||||
[ids f]
|
||||
(us/assert ::coll-of-uuid ids)
|
||||
|
|
|
@ -121,8 +121,8 @@
|
|||
;; --- TEXT EDITION IMPL
|
||||
|
||||
(defn- update-shape
|
||||
[shape pred-fn attrs]
|
||||
(let [merge-attrs #(attrs/merge % attrs)
|
||||
[shape pred-fn merge-fn attrs]
|
||||
(let [merge-attrs #(merge-fn % attrs)
|
||||
transform #(txt/transform-nodes pred-fn merge-attrs %)]
|
||||
(update shape :content transform)))
|
||||
|
||||
|
@ -134,7 +134,7 @@
|
|||
(let [objects (dwc/lookup-page-objects state)
|
||||
shape (get objects id)
|
||||
|
||||
update-fn #(update-shape % txt/is-root-node? attrs)
|
||||
update-fn #(update-shape % txt/is-root-node? attrs/merge attrs)
|
||||
shape-ids (cond (= (:type shape) :text) [id]
|
||||
(= (:type shape) :group) (cp/get-children id objects))]
|
||||
|
||||
|
@ -154,7 +154,15 @@
|
|||
(let [objects (dwc/lookup-page-objects state)
|
||||
shape (get objects id)
|
||||
|
||||
update-fn #(update-shape % txt/is-paragraph-node? attrs)
|
||||
merge-fn (fn [node attrs]
|
||||
(reduce-kv (fn [node k v]
|
||||
(if (= (get node k) v)
|
||||
(dissoc node k)
|
||||
(assoc node k v)))
|
||||
node
|
||||
attrs))
|
||||
|
||||
update-fn #(update-shape % txt/is-paragraph-node? merge-fn attrs)
|
||||
shape-ids (cond (= (:type shape) :text) [id]
|
||||
(= (:type shape) :group) (cp/get-children id objects))]
|
||||
|
||||
|
@ -174,7 +182,7 @@
|
|||
(let [objects (dwc/lookup-page-objects state)
|
||||
shape (get objects id)
|
||||
|
||||
update-fn #(update-shape % txt/is-text-node? attrs)
|
||||
update-fn #(update-shape % txt/is-text-node? attrs/merge attrs)
|
||||
shape-ids (cond (= (:type shape) :text) [id]
|
||||
(= (:type shape) :group) (cp/get-children id objects))]
|
||||
(rx/of (dwc/update-shapes shape-ids update-fn))))))))
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
(defn generate-paragraph-styles
|
||||
[shape data]
|
||||
(let [line-height (:line-height data)
|
||||
text-align (:text-align data)
|
||||
text-align (:text-align data "start")
|
||||
grow-type (:grow-type shape)
|
||||
|
||||
base #js {:fontSize (str (:font-size txt/default-text-attrs) "px")
|
||||
|
|
|
@ -26,34 +26,62 @@
|
|||
[cuerdas.core :as str]
|
||||
[rumext.alpha :as mf]))
|
||||
|
||||
(def text-typography-attrs [:typography-ref-id :typography-ref-file])
|
||||
(def text-fill-attrs [:fill-color :fill-opacity :fill-color-ref-id :fill-color-ref-file :fill-color-gradient :fill :opacity ])
|
||||
(def text-font-attrs [:font-id :font-family :font-variant-id :font-size :font-weight :font-style])
|
||||
(def text-align-attrs [:text-align])
|
||||
(def text-spacing-attrs [:line-height :letter-spacing])
|
||||
(def text-valign-attrs [:vertical-align])
|
||||
(def text-decoration-attrs [:text-decoration])
|
||||
(def text-transform-attrs [:text-transform])
|
||||
(def text-typography-attrs
|
||||
[:typography-ref-id
|
||||
:typography-ref-file])
|
||||
|
||||
(def shape-attrs [:grow-type])
|
||||
(def root-attrs (d/concat text-valign-attrs
|
||||
text-align-attrs))
|
||||
(def paragraph-attrs text-align-attrs)
|
||||
(def text-attrs (d/concat text-typography-attrs
|
||||
text-font-attrs
|
||||
text-align-attrs
|
||||
text-spacing-attrs
|
||||
text-decoration-attrs
|
||||
text-transform-attrs))
|
||||
(def text-fill-attrs
|
||||
[:fill-color
|
||||
:fill-opacity
|
||||
:fill-color-ref-id
|
||||
:fill-color-ref-file
|
||||
:fill-color-gradient])
|
||||
|
||||
(def text-font-attrs
|
||||
[:font-id
|
||||
:font-family
|
||||
:font-variant-id
|
||||
:font-size
|
||||
:font-weight
|
||||
:font-style])
|
||||
|
||||
(def text-align-attrs
|
||||
[:text-align])
|
||||
|
||||
(def text-spacing-attrs
|
||||
[:line-height
|
||||
:letter-spacing])
|
||||
|
||||
(def text-valign-attrs
|
||||
[:vertical-align])
|
||||
|
||||
(def text-decoration-attrs
|
||||
[:text-decoration])
|
||||
|
||||
(def text-transform-attrs
|
||||
[:text-transform])
|
||||
|
||||
(def shape-attrs
|
||||
[:grow-type])
|
||||
|
||||
(def root-attrs
|
||||
(d/concat text-valign-attrs text-align-attrs))
|
||||
|
||||
(def paragraph-attrs
|
||||
text-align-attrs)
|
||||
|
||||
(def text-attrs
|
||||
(d/concat text-typography-attrs
|
||||
text-font-attrs
|
||||
text-spacing-attrs
|
||||
text-decoration-attrs
|
||||
text-transform-attrs))
|
||||
|
||||
(def attrs (d/concat #{} shape-attrs root-attrs paragraph-attrs text-attrs))
|
||||
|
||||
(mf/defc text-align-options
|
||||
[{:keys [ids values on-change] :as props}]
|
||||
(let [{:keys [text-align]} values
|
||||
|
||||
text-align (or text-align "left")
|
||||
|
||||
handle-change
|
||||
(fn [event new-align]
|
||||
(on-change {:text-align new-align}))]
|
||||
|
@ -169,13 +197,13 @@
|
|||
{::mf/wrap [mf/memo]}
|
||||
[{:keys [ids type values] :as props}]
|
||||
|
||||
(let [current-file-id (mf/use-ctx ctx/current-file-id)
|
||||
(let [file-id (mf/use-ctx ctx/current-file-id)
|
||||
typographies (mf/deref refs/workspace-file-typography)
|
||||
shared-libs (mf/deref refs/workspace-libraries)
|
||||
label (case type
|
||||
:multiple (tr "workspace.options.text-options.title-selection")
|
||||
:group (tr "workspace.options.text-options.title-group")
|
||||
(tr "workspace.options.text-options.title"))
|
||||
shared-libs (mf/deref refs/workspace-libraries)
|
||||
label (case type
|
||||
:multiple (tr "workspace.options.text-options.title-selection")
|
||||
:group (tr "workspace.options.text-options.title-group")
|
||||
(tr "workspace.options.text-options.title"))
|
||||
|
||||
emit-update!
|
||||
(fn [id attrs]
|
||||
|
@ -194,14 +222,14 @@
|
|||
typography (cond
|
||||
(and (:typography-ref-id values)
|
||||
(not= (:typography-ref-id values) :multiple)
|
||||
(not= (:typography-ref-file values) current-file-id))
|
||||
(not= (:typography-ref-file values) file-id))
|
||||
(-> shared-libs
|
||||
(get-in [(:typography-ref-file values) :data :typographies (:typography-ref-id values)])
|
||||
(assoc :file-id (:typography-ref-file values)))
|
||||
|
||||
(and (:typography-ref-id values)
|
||||
(not= (:typography-ref-id values) :multiple)
|
||||
(= (:typography-ref-file values) current-file-id))
|
||||
(= (:typography-ref-file values) file-id))
|
||||
(get typographies (:typography-ref-id values)))
|
||||
|
||||
on-convert-to-typography
|
||||
|
@ -218,7 +246,7 @@
|
|||
(let [id (uuid/next)]
|
||||
(st/emit! (dwl/add-typography (assoc typography :id id) false))
|
||||
(run! #(emit-update! % {:typography-ref-id id
|
||||
:typography-ref-file current-file-id}) ids)))))
|
||||
:typography-ref-file file-id}) ids)))))
|
||||
|
||||
handle-detach-typography
|
||||
(fn []
|
||||
|
@ -228,7 +256,7 @@
|
|||
|
||||
handle-change-typography
|
||||
(fn [changes]
|
||||
(st/emit! (dwl/update-typography (merge typography changes) current-file-id)))
|
||||
(st/emit! (dwl/update-typography (merge typography changes) file-id)))
|
||||
|
||||
opts #js {:ids ids
|
||||
:values values
|
||||
|
@ -244,7 +272,7 @@
|
|||
(cond
|
||||
typography
|
||||
[:& typography-entry {:typography typography
|
||||
:read-only? (not= (:typography-ref-file values) current-file-id)
|
||||
:read-only? (not= (:typography-ref-file values) file-id)
|
||||
:file (get shared-libs (:typography-ref-file values))
|
||||
:on-detach handle-detach-typography
|
||||
:on-change handle-change-typography}]
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) UXBOX Labs SL
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
import {CharacterMetadata} from "draft-js";
|
||||
import {Map} from "immutable";
|
||||
|
||||
function removeStylePrefix(chmeta, stylePrefix) {
|
||||
var withoutStyle = chmeta.set('style', chmeta.getStyle().filter((s) => !s.startsWith(stylePrefix)))
|
||||
return CharacterMetadata.create(withoutStyle);
|
||||
};
|
||||
|
||||
export function removeInlineStylePrefix(contentState, selectionState, stylePrefix) {
|
||||
var blockMap = contentState.getBlockMap();
|
||||
var startKey = selectionState.getStartKey();
|
||||
var startOffset = selectionState.getStartOffset();
|
||||
var endKey = selectionState.getEndKey();
|
||||
var endOffset = selectionState.getEndOffset();
|
||||
var newBlocks = blockMap.skipUntil(function (_, k) {
|
||||
return k === startKey;
|
||||
}).takeUntil(function (_, k) {
|
||||
return k === endKey;
|
||||
}).concat(Map([[endKey, blockMap.get(endKey)]])).map(function (block, blockKey) {
|
||||
var sliceStart;
|
||||
var sliceEnd;
|
||||
|
||||
if (startKey === endKey) {
|
||||
sliceStart = startOffset;
|
||||
sliceEnd = endOffset;
|
||||
} else {
|
||||
sliceStart = blockKey === startKey ? startOffset : 0;
|
||||
sliceEnd = blockKey === endKey ? endOffset : block.getLength();
|
||||
}
|
||||
|
||||
var chars = block.getCharacterList();
|
||||
var current;
|
||||
|
||||
while (sliceStart < sliceEnd) {
|
||||
current = chars.get(sliceStart);
|
||||
chars = chars.set(sliceStart, removeStylePrefix(current, stylePrefix));
|
||||
sliceStart++;
|
||||
}
|
||||
|
||||
return block.set('characterList', chars);
|
||||
});
|
||||
|
||||
return contentState.merge({
|
||||
blockMap: blockMap.merge(newBlocks),
|
||||
selectionBefore: selectionState,
|
||||
selectionAfter: selectionState
|
||||
});
|
||||
}
|
|
@ -11,7 +11,7 @@
|
|||
"Draft related abstraction functions."
|
||||
(:require
|
||||
["draft-js" :as draft]
|
||||
["./draft_helpers.js" :as helpers]
|
||||
["./text_editor_impl.js" :as impl]
|
||||
[app.common.attrs :as attrs]
|
||||
[app.common.text :as txt]
|
||||
[app.common.data :as d]
|
||||
|
@ -206,27 +206,15 @@
|
|||
|
||||
(defn create-editor-state
|
||||
([]
|
||||
(.createEmpty ^js draft/EditorState))
|
||||
(impl/createEditorState nil nil))
|
||||
([content]
|
||||
(.createWithContent ^js draft/EditorState content))
|
||||
(impl/createEditorState content nil))
|
||||
([content decorator]
|
||||
(if (some? content)
|
||||
(.createWithContent ^js draft/EditorState content decorator)
|
||||
(.createEmpty ^js draft/EditorState decorator))))
|
||||
(impl/createEditorState content decorator)))
|
||||
|
||||
(defn create-decorator
|
||||
[type component]
|
||||
(letfn [(find-entity [block callback content]
|
||||
(.findEntityRanges ^js block
|
||||
(fn [cmeta]
|
||||
(let [ekey (.getEntity ^js cmeta)]
|
||||
(boolean
|
||||
(and (some? ekey)
|
||||
(= type (.. ^js content (getEntity ekey) (getType)))))))
|
||||
callback))]
|
||||
(draft/CompositeDecorator.
|
||||
#js [#js {:strategy find-entity
|
||||
:component component}])))
|
||||
(impl/createDecorator type component))
|
||||
|
||||
(defn import-content
|
||||
[content]
|
||||
|
@ -248,18 +236,7 @@
|
|||
|
||||
(defn editor-select-all
|
||||
[state]
|
||||
(let [content (get-editor-current-content state)
|
||||
fblock (.. ^js content getBlockMap first)
|
||||
lblock (.. ^js content getBlockMap last)
|
||||
fbk (.getKey ^js fblock)
|
||||
lbk (.getKey ^js lblock)
|
||||
lbl (.getLength ^js lblock)
|
||||
params #js {:anchorKey fbk
|
||||
:anchorOffset 0
|
||||
:focusKey lbk
|
||||
:focusOffset lbl}
|
||||
selection (draft/SelectionState. params)]
|
||||
(.forceSelection ^js draft/EditorState state selection)))
|
||||
(impl/selectAll state))
|
||||
|
||||
(defn get-editor-block-data
|
||||
[block]
|
||||
|
@ -272,9 +249,7 @@
|
|||
|
||||
(defn get-editor-current-block-data
|
||||
[state]
|
||||
(let [content (.getCurrentContent ^js state)
|
||||
key (.. ^js state getSelection getStartKey)
|
||||
block (.getBlockForKey ^js content key)]
|
||||
(let [block (impl/getCurrentBlock state)]
|
||||
(get-editor-block-data block)))
|
||||
|
||||
(defn get-editor-current-inline-styles
|
||||
|
@ -284,103 +259,20 @@
|
|||
|
||||
(defn update-editor-current-block-data
|
||||
[state attrs]
|
||||
(loop [selection (.getSelection ^js state)
|
||||
start-key (.getStartKey ^js selection)
|
||||
end-key (.getEndKey ^js selection)
|
||||
content (.getCurrentContent ^js state)
|
||||
target selection]
|
||||
(if (and (not= start-key end-key)
|
||||
(zero? (.getEndOffset ^js selection)))
|
||||
(let [before-block (.getBlockBefore ^js content end-key)]
|
||||
(recur selection
|
||||
start-key
|
||||
(.getKey ^js before-block)
|
||||
content
|
||||
(.merge ^js target
|
||||
#js {:anchorKey start-key
|
||||
:anchorOffset (.getStartOffset ^js selection)
|
||||
:focusKey end-key
|
||||
:focusOffset (.getLength ^js before-block)
|
||||
:isBackward false})))
|
||||
(.push ^js draft/EditorState
|
||||
state
|
||||
(.mergeBlockData ^js draft/Modifier content target (clj->js attrs))
|
||||
"change-block-data"))))
|
||||
|
||||
(defn get-editor-current-entity-key
|
||||
[state]
|
||||
(let [content (.getCurrentContent ^js state)
|
||||
selection (.getSelection ^js state)
|
||||
start-key (.getStartKey ^js selection)
|
||||
start-offset (.getStartOffset ^js selection)
|
||||
block (.getBlockForKey ^js content start-key)]
|
||||
(.getEntityAt ^js block start-offset)))
|
||||
(impl/updateCurrentBlockData state (clj->js attrs)))
|
||||
|
||||
(defn update-editor-current-inline-styles
|
||||
[state attrs]
|
||||
(let [selection (.getSelection ^js state)
|
||||
styles (attrs-to-styles attrs)]
|
||||
(reduce (fn [state style]
|
||||
(let [[sk sv] (decode-style style)
|
||||
prefix (encode-style-prefix sk)
|
||||
|
||||
content (.getCurrentContent ^js state)
|
||||
content (helpers/removeInlineStylePrefix content
|
||||
selection
|
||||
prefix)
|
||||
|
||||
content (.applyInlineStyle ^js draft/Modifier
|
||||
content
|
||||
selection
|
||||
style)]
|
||||
(.push ^js draft/EditorState state content "change-inline-style")))
|
||||
state
|
||||
styles)))
|
||||
(impl/applyInlineStyle state (attrs-to-styles attrs)))
|
||||
|
||||
(defn editor-split-block
|
||||
[state]
|
||||
(let [content (.getCurrentContent ^js state)
|
||||
selection (.getSelection ^js state)
|
||||
content (.splitBlock ^js draft/Modifier content selection)
|
||||
block-data (.. ^js content -blockMap (get (.. content -selectionBefore getStartKey)) getData)
|
||||
block-key (.. ^js content -selectionAfter getStartKey)
|
||||
block-map (.. ^js content -blockMap (update block-key (fn [block] (.set ^js block "data" block-data))))]
|
||||
(.push ^js draft/EditorState state (.set ^js content "blockMap" block-map) "split-block")))
|
||||
(impl/splitBlockPreservingData state))
|
||||
|
||||
(defn add-editor-blur-selection
|
||||
[state]
|
||||
(let [content (.getCurrentContent ^js state)
|
||||
selection (.getSelection ^js state)
|
||||
content (.createEntity ^js content "PENPOT_SELECTION" "MUTABLE")
|
||||
ekey (.getLastCreatedEntityKey ^js content)
|
||||
content (.applyEntity draft/Modifier
|
||||
content
|
||||
selection
|
||||
ekey)]
|
||||
(.push draft/EditorState state content "apply-entity")))
|
||||
|
||||
(impl/addBlurSelectionEntity state))
|
||||
|
||||
(defn remove-editor-blur-selection
|
||||
[state]
|
||||
(let [content (get-editor-current-content state)
|
||||
fblock (.. ^js content getBlockMap first)
|
||||
lblock (.. ^js content getBlockMap last)
|
||||
fbk (.getKey ^js fblock)
|
||||
lbk (.getKey ^js lblock)
|
||||
lbl (.getLength ^js lblock)
|
||||
params #js {:anchorKey fbk
|
||||
:anchorOffset 0
|
||||
:focusKey lbk
|
||||
:focusOffset lbl}
|
||||
|
||||
prev-selection (.getSelection state)
|
||||
|
||||
selection (draft/SelectionState. params)
|
||||
content (.applyEntity draft/Modifier
|
||||
content
|
||||
selection
|
||||
nil)]
|
||||
(as-> state $
|
||||
(.push draft/EditorState $ content "apply-entity")
|
||||
(.forceSelection ^js draft/EditorState $ prev-selection))))
|
||||
|
||||
(impl/removeBlurSelectionEntity state))
|
||||
|
|
212
frontend/src/app/util/text_editor_impl.js
Normal file
212
frontend/src/app/util/text_editor_impl.js
Normal file
|
@ -0,0 +1,212 @@
|
|||
/**
|
||||
* 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/.
|
||||
*
|
||||
* This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
* defined by the Mozilla Public License, v. 2.0.
|
||||
*
|
||||
* Copyright (c) UXBOX Labs SL
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import {
|
||||
CharacterMetadata,
|
||||
EditorState,
|
||||
CompositeDecorator,
|
||||
SelectionState,
|
||||
Modifier
|
||||
} from "draft-js";
|
||||
|
||||
import {Map} from "immutable";
|
||||
|
||||
function isDefined(v) {
|
||||
return v !== undefined && v !== null;
|
||||
}
|
||||
|
||||
export function createEditorState(content, decorator) {
|
||||
if (content === null) {
|
||||
return EditorState.createEmpty(decorator);
|
||||
} else {
|
||||
return EditorState.createWithContent(content, decorator);
|
||||
}
|
||||
}
|
||||
|
||||
export function createDecorator(type, component) {
|
||||
const strategy = (block, callback, content) => {
|
||||
return block.findEntityRanges((cmeta) => {
|
||||
const entityKey = cmeta.getEntity();
|
||||
return isDefined(entityKey) && (type === content.getEntity(entityKey).getType());
|
||||
}, callback);
|
||||
};
|
||||
|
||||
return new CompositeDecorator([
|
||||
{strategy, component}
|
||||
]);
|
||||
}
|
||||
|
||||
function getSelectAllSelection(state) {
|
||||
const content = state.getCurrentContent();
|
||||
const firstBlock = content.getBlockMap().first();
|
||||
const lastBlock = content.getBlockMap().last();
|
||||
|
||||
return new SelectionState({
|
||||
"anchorKey": firstBlock.getKey(),
|
||||
"anchorOffset": 0,
|
||||
"focusKey": lastBlock.getKey(),
|
||||
"focusOffset": lastBlock.getLength()
|
||||
});
|
||||
}
|
||||
|
||||
export function selectAll(state) {
|
||||
return EditorState.forceSelection(state, getSelectAllSelection(state));
|
||||
}
|
||||
|
||||
function modifySelectedBlocks(contentState, selectionState, operation) {
|
||||
var startKey = selectionState.getStartKey();
|
||||
var endKey = selectionState.getEndKey();
|
||||
var blockMap = contentState.getBlockMap();
|
||||
|
||||
var newBlocks = blockMap.toSeq().skipUntil(function (_, k) {
|
||||
return k === startKey;
|
||||
}).takeUntil(function (_, k) {
|
||||
return k === endKey;
|
||||
}).concat(Map([[endKey, blockMap.get(endKey)]])).map(operation);
|
||||
|
||||
return contentState.merge({
|
||||
blockMap: blockMap.merge(newBlocks),
|
||||
selectionBefore: selectionState,
|
||||
selectionAfter: selectionState
|
||||
});
|
||||
}
|
||||
|
||||
export function updateCurrentBlockData(state, attrs) {
|
||||
const selection = state.getSelection();
|
||||
let content = state.getCurrentContent();
|
||||
|
||||
content = modifySelectedBlocks(content, selection, (block) => {
|
||||
let data = block.getData();
|
||||
for (let key of Object.keys(attrs)) {
|
||||
const oldVal = data.get(key);
|
||||
if (oldVal === attrs[key]) {
|
||||
data = data.delete(key);
|
||||
} else {
|
||||
data = data.set(key, attrs[key]);
|
||||
}
|
||||
}
|
||||
|
||||
return block.merge({
|
||||
data: data
|
||||
});
|
||||
});
|
||||
|
||||
return EditorState.push(state, content, "change-block-data");
|
||||
}
|
||||
|
||||
export function applyInlineStyle(state, styles) {
|
||||
const selection = state.getSelection();
|
||||
|
||||
let state = state;
|
||||
let content = null;
|
||||
|
||||
for (let style of styles) {
|
||||
const [p, k, _] = style.split("$$$");
|
||||
const prefix = [p, k, ""].join("$$$");
|
||||
|
||||
content = state.getCurrentContent();
|
||||
content = removeInlineStylePrefix(content, selection, prefix);
|
||||
content = Modifier.applyInlineStyle(content, selection, style);
|
||||
state = EditorState.push(state, content, "change-inline-style");
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
export function splitBlockPreservingData(state) {
|
||||
let content = state.getCurrentContent();
|
||||
const selection = state.getSelection();
|
||||
|
||||
content = Modifier.splitBlock(content, selection);
|
||||
|
||||
const blockData = content.blockMap.get(content.selectionBefore.getStartKey()).getData();
|
||||
const blockKey = content.selectionAfter.getStartKey();
|
||||
const blockMap = content.blockMap.update(blockKey, (block) => {
|
||||
return block.set("data", blockData);
|
||||
});
|
||||
|
||||
content = content.set("blockMap", blockMap);
|
||||
|
||||
return EditorState.push(state, content, "split-block");
|
||||
}
|
||||
|
||||
export function addBlurSelectionEntity(state) {
|
||||
let content = state.getCurrentContent(state);
|
||||
const selection = state.getSelection();
|
||||
|
||||
content = content.createEntity("PENPOT_SELECTION", "MUTABLE");
|
||||
const entityKey = content.getLastCreatedEntityKey();
|
||||
|
||||
content = Modifier.applyEntity(content, selection, entityKey);
|
||||
return EditorState.push(state, content, "apply-entity");
|
||||
}
|
||||
|
||||
export function removeBlurSelectionEntity(state) {
|
||||
const selectionAll = getSelectAllSelection(state);
|
||||
const selection = state.getSelection();
|
||||
|
||||
let content = state.getCurrentContent();
|
||||
content = Modifier.applyEntity(content, selectionAll, null);
|
||||
|
||||
state = EditorState.push(state, content, "apply-entity");
|
||||
state = EditorState.forceSelection(state, selection);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
export function getCurrentBlock(state) {
|
||||
const content = state.getCurrentContent();
|
||||
const selection = state.getSelection();
|
||||
const startKey = selection.getStartKey();
|
||||
return content.getBlockForKey(startKey);
|
||||
}
|
||||
|
||||
export function getCurrentEntityKey(state) {
|
||||
const block = getCurrentBlock(state);
|
||||
const selection = state.getSelection();
|
||||
const startOffset = selection.getStartOffset();
|
||||
return block.getEntityAt(startOffset);
|
||||
}
|
||||
|
||||
export function removeInlineStylePrefix(contentState, selectionState, stylePrefix) {
|
||||
const startKey = selectionState.getStartKey();
|
||||
const startOffset = selectionState.getStartOffset();
|
||||
const endKey = selectionState.getEndKey();
|
||||
const endOffset = selectionState.getEndOffset();
|
||||
|
||||
return modifySelectedBlocks(contentState, selectionState, (block, blockKey) => {
|
||||
let sliceStart;
|
||||
let sliceEnd;
|
||||
|
||||
if (startKey === endKey) {
|
||||
sliceStart = startOffset;
|
||||
sliceEnd = endOffset;
|
||||
} else {
|
||||
sliceStart = blockKey === startKey ? startOffset : 0;
|
||||
sliceEnd = blockKey === endKey ? endOffset : block.getLength();
|
||||
}
|
||||
|
||||
let chars = block.getCharacterList();
|
||||
let current;
|
||||
|
||||
while (sliceStart < sliceEnd) {
|
||||
current = chars.get(sliceStart);
|
||||
current = current.set("style", current.getStyle().filter((s) => !s.startsWith(stylePrefix)))
|
||||
chars = chars.set(sliceStart, CharacterMetadata.create(current));
|
||||
|
||||
sliceStart++;
|
||||
}
|
||||
|
||||
return block.set('characterList', chars);
|
||||
});
|
||||
}
|
Loading…
Add table
Reference in a new issue