aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--package-lock.json183
-rw-r--r--package.json1
-rw-r--r--src/client/util/DictationManager.ts2
-rw-r--r--src/client/util/SelectionManager.ts6
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx24
-rw-r--r--src/client/views/nodes/DocumentView.tsx4
-rw-r--r--src/client/views/nodes/ImageBox.tsx17
-rw-r--r--src/client/views/nodes/LinkAnchorBox.tsx12
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.scss7
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx52
-rw-r--r--src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts10
-rw-r--r--src/client/views/nodes/formattedText/RichTextMenu.tsx36
-rw-r--r--src/client/views/nodes/formattedText/RichTextRules.ts2
-rw-r--r--src/client/views/nodes/formattedText/marks_rts.ts70
-rw-r--r--src/client/views/nodes/formattedText/nodes_rts.ts85
-rw-r--r--src/fields/RichTextUtils.ts2
16 files changed, 364 insertions, 149 deletions
diff --git a/package-lock.json b/package-lock.json
index c651bb29e..0070bb445 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -173,11 +173,42 @@
"@emotion/weak-memoize": "0.2.5"
}
},
+ "@emotion/core": {
+ "version": "10.0.28",
+ "resolved": "https://registry.npmjs.org/@emotion/core/-/core-10.0.28.tgz",
+ "integrity": "sha512-pH8UueKYO5jgg0Iq+AmCLxBsvuGtvlmiDCOuv8fGNYn3cowFpLN98L8zO56U0H1PjDIyAlXymgL3Wu7u7v6hbA==",
+ "requires": {
+ "@babel/runtime": "^7.5.5",
+ "@emotion/cache": "^10.0.27",
+ "@emotion/css": "^10.0.27",
+ "@emotion/serialize": "^0.11.15",
+ "@emotion/sheet": "0.9.4",
+ "@emotion/utils": "0.11.3"
+ }
+ },
+ "@emotion/css": {
+ "version": "10.0.27",
+ "resolved": "https://registry.npmjs.org/@emotion/css/-/css-10.0.27.tgz",
+ "integrity": "sha512-6wZjsvYeBhyZQYNrGoR5yPMYbMBNEnanDrqmsqS1mzDm1cOTu12shvl2j4QHNS36UaTE0USIJawCH9C8oW34Zw==",
+ "requires": {
+ "@emotion/serialize": "^0.11.15",
+ "@emotion/utils": "0.11.3",
+ "babel-plugin-emotion": "^10.0.27"
+ }
+ },
"@emotion/hash": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz",
"integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow=="
},
+ "@emotion/is-prop-valid": {
+ "version": "0.8.8",
+ "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz",
+ "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==",
+ "requires": {
+ "@emotion/memoize": "0.7.4"
+ }
+ },
"@emotion/memoize": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz",
@@ -200,6 +231,26 @@
"resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-0.9.4.tgz",
"integrity": "sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA=="
},
+ "@emotion/styled": {
+ "version": "10.0.27",
+ "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-10.0.27.tgz",
+ "integrity": "sha512-iK/8Sh7+NLJzyp9a5+vIQIXTYxfT4yB/OJbjzQanB2RZpvmzBQOHZWhpAMZWYEKRNNbsD6WfBw5sVWkb6WzS/Q==",
+ "requires": {
+ "@emotion/styled-base": "^10.0.27",
+ "babel-plugin-emotion": "^10.0.27"
+ }
+ },
+ "@emotion/styled-base": {
+ "version": "10.0.31",
+ "resolved": "https://registry.npmjs.org/@emotion/styled-base/-/styled-base-10.0.31.tgz",
+ "integrity": "sha512-wTOE1NcXmqMWlyrtwdkqg87Mu6Rj1MaukEoEmEkHirO5IoHDJ8LgCQL4MjJODgxWxXibGR3opGp1p7YvkNEdXQ==",
+ "requires": {
+ "@babel/runtime": "^7.5.5",
+ "@emotion/is-prop-valid": "0.8.8",
+ "@emotion/serialize": "^0.11.15",
+ "@emotion/utils": "0.11.3"
+ }
+ },
"@emotion/stylis": {
"version": "0.8.5",
"resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz",
@@ -2159,6 +2210,11 @@
}
}
},
+ "base16": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz",
+ "integrity": "sha1-4pf2DX7BAUp6lxo568ipjAtoHnA="
+ },
"base64-arraybuffer": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
@@ -2516,8 +2572,7 @@
"buffer-from": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
- "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
- "dev": true
+ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
},
"buffer-indexof": {
"version": "1.1.1",
@@ -3659,7 +3714,6 @@
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
"integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
- "dev": true,
"requires": {
"buffer-from": "^1.0.0",
"inherits": "^2.0.3",
@@ -3671,7 +3725,6 @@
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
- "dev": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
@@ -4774,6 +4827,11 @@
"resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
"integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA=="
},
+ "diff-match-patch": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz",
+ "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw=="
+ },
"diffie-hellman": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
@@ -6774,6 +6832,14 @@
}
}
},
+ "html": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/html/-/html-1.0.0.tgz",
+ "integrity": "sha1-pUT6nqVJK/s6LMqCEKEL57WvH2E=",
+ "requires": {
+ "concat-stream": "^1.4.7"
+ }
+ },
"html-encoding-sniffer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz",
@@ -7773,6 +7839,15 @@
"integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==",
"dev": true
},
+ "jsondiffpatch": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/jsondiffpatch/-/jsondiffpatch-0.4.1.tgz",
+ "integrity": "sha512-t0etAxTUk1w5MYdNOkZBZ8rvYYN5iL+2dHCCx/DpkFm/bW28M6y5nUS83D4XdZiHy35Fpaw6LBb+F88fHZnVCw==",
+ "requires": {
+ "chalk": "^2.3.0",
+ "diff-match-patch": "^1.0.0"
+ }
+ },
"jsonfile": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
@@ -8013,11 +8088,29 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
},
+ "lodash._getnative": {
+ "version": "3.9.1",
+ "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz",
+ "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U="
+ },
"lodash.chunk": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/lodash.chunk/-/lodash.chunk-4.2.0.tgz",
"integrity": "sha1-ZuXOH3btJ7QwPYxlEujRIW6BBrw="
},
+ "lodash.curry": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz",
+ "integrity": "sha1-JI42By7ekGUB11lmIAqG2riyMXA="
+ },
+ "lodash.debounce": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-3.1.1.tgz",
+ "integrity": "sha1-gSIRw3ipTMKdWqTjNGzwv846ffU=",
+ "requires": {
+ "lodash._getnative": "^3.0.0"
+ }
+ },
"lodash.defaults": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
@@ -8033,6 +8126,11 @@
"resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
"integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8="
},
+ "lodash.flow": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.flow/-/lodash.flow-3.5.0.tgz",
+ "integrity": "sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o="
+ },
"lodash.get": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
@@ -8768,6 +8866,11 @@
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz",
"integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw=="
},
+ "nanoid": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.10.tgz",
+ "integrity": "sha512-iZFMXKeXWkxzlfmMfM91gw7YhN2sdJtixY+eZh9V6QWJWTOiurhpKhBMgr82pfzgSqglQgqYSCowEYsz8D++6w=="
+ },
"nanomatch": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
@@ -13594,6 +13697,25 @@
"prosemirror-transform": "^1.0.0"
}
},
+ "prosemirror-dev-tools": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/prosemirror-dev-tools/-/prosemirror-dev-tools-3.0.0.tgz",
+ "integrity": "sha512-yW0qc9OMxvy6gYKIYK4FAqrfLWqAKnOcxuGszrCBjxJtGKe6APWaYqGJn+u943+QIByjO1oNHGz5h4x3ekP/lQ==",
+ "requires": {
+ "@emotion/core": "^10.0.28",
+ "@emotion/styled": "^10.0.27",
+ "emotion": "^10.0.27",
+ "html": "^1.0.0",
+ "jsondiffpatch": "^0.4.1",
+ "nanoid": "^3.1.6",
+ "prop-types": "^15.7.2",
+ "prosemirror-model": ">=1.0.0",
+ "prosemirror-state": ">=1.0.0",
+ "react-dock": "^0.2.4",
+ "react-json-tree": "^0.11.2",
+ "unstated": "^2.1.1"
+ }
+ },
"prosemirror-find-replace": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/prosemirror-find-replace/-/prosemirror-find-replace-0.9.0.tgz",
@@ -13917,6 +14039,11 @@
}
}
},
+ "pure-color": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/pure-color/-/pure-color-1.3.0.tgz",
+ "integrity": "sha1-H+Bk+wrIUfDeYTIKi/eWg2Qi8z4="
+ },
"q": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
@@ -14067,6 +14194,17 @@
"section-iterator": "^2.0.0"
}
},
+ "react-base16-styling": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.5.3.tgz",
+ "integrity": "sha1-OFjyTpxN2MvT9wLz901YHKKRcmk=",
+ "requires": {
+ "base16": "^1.0.0",
+ "lodash.curry": "^4.0.1",
+ "lodash.flow": "^3.3.0",
+ "pure-color": "^1.2.0"
+ }
+ },
"react-color": {
"version": "2.18.0",
"resolved": "https://registry.npmjs.org/react-color/-/react-color-2.18.0.tgz",
@@ -14091,6 +14229,15 @@
"warning": "^3.0.0"
}
},
+ "react-dock": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/react-dock/-/react-dock-0.2.4.tgz",
+ "integrity": "sha1-5yfcdVCztzEWY13LnA4E0Lev4Xw=",
+ "requires": {
+ "lodash.debounce": "^3.1.1",
+ "prop-types": "^15.5.8"
+ }
+ },
"react-dom": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.13.1.tgz",
@@ -14138,6 +14285,16 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
+ "react-json-tree": {
+ "version": "0.11.2",
+ "resolved": "https://registry.npmjs.org/react-json-tree/-/react-json-tree-0.11.2.tgz",
+ "integrity": "sha512-aYhUPj1y5jR3ZQ+G3N7aL8FbTyO03iLwnVvvEikLcNFqNTyabdljo9xDftZndUBFyyyL0aK3qGO9+8EilILHUw==",
+ "requires": {
+ "babel-runtime": "^6.6.1",
+ "prop-types": "^15.5.8",
+ "react-base16-styling": "^0.5.1"
+ }
+ },
"react-jsx-parser": {
"version": "1.23.0",
"resolved": "https://registry.npmjs.org/react-jsx-parser/-/react-jsx-parser-1.23.0.tgz",
@@ -16585,8 +16742,7 @@
"typedarray": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
- "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
- "dev": true
+ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
},
"typescript": {
"version": "3.8.3",
@@ -16838,6 +16994,21 @@
}
}
},
+ "unstated": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/unstated/-/unstated-2.1.1.tgz",
+ "integrity": "sha512-fORlTWMZxq7NuMJDxyIrrYIZKN7wEWYQ9SiaJfIRcSpsowr6Ph/JIfK2tgtXLW614JfPG/t5q9eEIhXRCf55xg==",
+ "requires": {
+ "create-react-context": "^0.1.5"
+ },
+ "dependencies": {
+ "create-react-context": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/create-react-context/-/create-react-context-0.1.6.tgz",
+ "integrity": "sha512-eCnYYEUEc5i32LHwpE/W7NlddOB9oHwsPaWtWzYtflNkkwa3IfindIcoXdVWs12zCbwaMCavKNu84EXogVIWHw=="
+ }
+ }
+ },
"unzip-response": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz",
diff --git a/package.json b/package.json
index a9f5d872a..096c26cd0 100644
--- a/package.json
+++ b/package.json
@@ -189,6 +189,7 @@
"pdfjs-dist": "^2.3.200",
"probe-image-size": "^4.0.0",
"prosemirror-commands": "^1.1.3",
+ "prosemirror-dev-tools": "^3.0.0",
"prosemirror-find-replace": "^0.9.0",
"prosemirror-history": "^1.1.3",
"prosemirror-inputrules": "^1.1.2",
diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts
index d8a5657c3..28b1ca6cf 100644
--- a/src/client/util/DictationManager.ts
+++ b/src/client/util/DictationManager.ts
@@ -335,7 +335,7 @@ export namespace DictationManager {
const prompt = "Press alt + r to start dictating here...";
const head = 3;
const anchor = head + prompt.length;
- const proseMirrorState = `{"doc":{"type":"doc","content":[{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"type":"text","text":"${prompt}"}]}]}]}]},"selection":{"type":"text","anchor":${anchor},"head":${head}}}`;
+ const proseMirrorState = `{"doc":{"type":"doc","content":[{"type":"ordered_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"type":"text","text":"${prompt}"}]}]}]}]},"selection":{"type":"text","anchor":${anchor},"head":${head}}}`;
proto.data = new RichTextField(proseMirrorState);
proto.backgroundColor = "#eeffff";
target.props.addDocTab(newBox, "onRight");
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index 05515e502..eb905d237 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -10,13 +10,17 @@ export namespace SelectionManager {
@observable IsDragging: boolean = false;
SelectedDocuments: ObservableMap<DocumentView, boolean> = new ObservableMap();
-
+ clearSelection() {
+ if (window.getSelection) { window.getSelection()?.removeAllRanges(); }
+ else if (document.getSelection()) { document.getSelection()?.empty(); }
+ }
@action
SelectDoc(docView: DocumentView, ctrlPressed: boolean): void {
// if doc is not in SelectedDocuments, add it
if (!manager.SelectedDocuments.get(docView)) {
if (!ctrlPressed) {
this.DeselectAll();
+ this.clearSelection();
}
manager.SelectedDocuments.set(docView, true);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 6cac39f77..b65a2486c 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -56,27 +56,27 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
const targetAhyperlink = linkEles.find((ele: any) => ele.getAttribute("targetids")?.includes(AanchorId));
const targetBhyperlink = linkEles.find((ele: any) => ele.getAttribute("targetids")?.includes(BanchorId));
if (!targetBhyperlink) {
- this.props.A.props.Document[afield + "_x"] = (apt.point.x - abounds.left) / abounds.width * 100;
- this.props.A.props.Document[afield + "_y"] = (apt.point.y - abounds.top) / abounds.height * 100;
+ this.props.A.rootDoc[afield + "_x"] = (apt.point.x - abounds.left) / abounds.width * 100;
+ this.props.A.rootDoc[afield + "_y"] = (apt.point.y - abounds.top) / abounds.height * 100;
} else {
setTimeout(() => {
- (this.props.A.props.Document[(this.props.A.props as any).fieldKey] as Doc);
+ (this.props.A.rootDoc[(this.props.A.props as any).fieldKey] as Doc);
const m = targetBhyperlink.getBoundingClientRect();
- const mp = this.props.A.props.ScreenToLocalTransform().transformPoint(m.right, m.top + 5);
- this.props.A.props.Document[afield + "_x"] = mp[0] / this.props.A.props.PanelWidth() * 100;
- this.props.A.props.Document[afield + "_y"] = mp[1] / this.props.A.props.PanelHeight() * 100;
+ const mp = this.props.A.props.ContainingCollectionView?.props.ScreenToLocalTransform().transformPoint(m.right, m.top + 5);
+ this.props.A.rootDoc[afield + "_x"] = Math.min(1, mp![0] / this.props.A.props.PanelWidth()) * 100;
+ this.props.A.rootDoc[afield + "_y"] = Math.min(1, mp![1] / this.props.A.props.PanelHeight()) * 100;
}, 0);
}
if (!targetAhyperlink) {
- this.props.A.props.Document[bfield + "_x"] = (bpt.point.x - bbounds.left) / bbounds.width * 100;
- this.props.A.props.Document[bfield + "_y"] = (bpt.point.y - bbounds.top) / bbounds.height * 100;
+ this.props.A.rootDoc[bfield + "_x"] = (bpt.point.x - bbounds.left) / bbounds.width * 100;
+ this.props.A.rootDoc[bfield + "_y"] = (bpt.point.y - bbounds.top) / bbounds.height * 100;
} else {
setTimeout(() => {
- (this.props.B.props.Document[(this.props.B.props as any).fieldKey] as Doc);
+ (this.props.B.rootDoc[(this.props.B.props as any).fieldKey] as Doc);
const m = targetAhyperlink.getBoundingClientRect();
- const mp = this.props.B.props.ScreenToLocalTransform().transformPoint(m.right, m.top + 5);
- this.props.B.props.Document[bfield + "_x"] = mp[0] / this.props.B.props.PanelWidth() * 100;
- this.props.B.props.Document[bfield + "_y"] = mp[1] / this.props.B.props.PanelHeight() * 100;
+ const mp = this.props.B.props.ContainingCollectionView?.props.ScreenToLocalTransform().transformPoint(m.right, m.top + 5);
+ this.props.B.rootDoc[bfield + "_x"] = Math.min(1, mp![0] / this.props.B.props.PanelWidth()) * 100;
+ this.props.B.rootDoc[bfield + "_y"] = Math.min(1, mp![1] / this.props.B.props.PanelHeight()) * 100;
}, 0);
}
})
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 3205e3050..345ca479f 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -995,7 +995,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
childScaling = () => (this.layoutDoc._fitWidth ? this.props.PanelWidth() / this.nativeWidth : this.props.ContentScaling());
@computed get contents() {
TraceMobx();
- return (<>
+ return (<div style={{ position: "absolute", width: "100%", height: "100%" }}>
<DocumentContentsView key={1}
docFilters={this.props.docFilters}
ContainingCollectionView={this.props.ContainingCollectionView}
@@ -1033,7 +1033,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
onClick={this.onClickHandler}
layoutKey={this.finalLayoutKey} />
{this.anchors}
- </>
+ </div>
);
}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 84d49681c..f0818c7b4 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -396,12 +396,23 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
const aspect = (rotation % 180) ? nativeHeight / nativeWidth : 1;
const shift = (rotation % 180) ? (nativeHeight - nativeWidth) * (1 - 1 / aspect) : 0;
this.resize(srcpath);
+ let transformOrigin = "center center";
+ let transform = `translate(0%, 0%) rotate(${rotation}deg) scale(${aspect})`
+ if (rotation === 90 || rotation === -270) {
+ transformOrigin = "top left";
+ transform = `translate(100%, 0%) rotate(${rotation}deg) scale(${aspect})`
+ } else if (rotation === 180) {
+ transform = `rotate(${rotation}deg) scale(${aspect})`
+ } else if (rotation === 270 || rotation === -90) {
+ transformOrigin = "right top";
+ transform = `translate(-100%, 0%) rotate(${rotation}deg) scale(${aspect})`
+ }
return <div className="imageBox-cont" key={this.layoutDoc[Id]} ref={this.createDropTarget}>
<div className="imageBox-fader" >
<img key={this._smallRetryCount + (this._mediumRetryCount << 4) + (this._largeRetryCount << 8)} // force cache to update on retrys
src={srcpath}
- style={{ transform: `scale(${aspect}) translate(0px, ${shift}px) rotate(${rotation}deg)` }}
+ style={{ transform, transformOrigin }}
width={nativeWidth}
ref={this._imgRef}
onError={this.onError} />
@@ -409,7 +420,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
<img className="imageBox-fadeaway"
key={"fadeaway" + this._smallRetryCount + (this._mediumRetryCount << 4) + (this._largeRetryCount << 8)} // force cache to update on retrys
src={fadepath}
- style={{ transform: `translate(0px, ${shift}px) rotate(${rotation}deg) scale(${aspect})`, }}
+ style={{ transform, transformOrigin }}
width={nativeWidth}
ref={this._imgRef}
onError={this.onError} /></div>}
@@ -447,7 +458,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
TraceMobx();
return (<div className={`imageBox`} onContextMenu={this.specificContextMenu}
style={{
- transform: this.props.PanelWidth() ? `translate(0px, ${this.ycenter}px)` : `scale(${this.props.ContentScaling()})`,
+ transform: this.props.PanelWidth() ? undefined : `scale(${this.props.ContentScaling()})`,
width: this.props.PanelWidth() ? undefined : `${100 / this.props.ContentScaling()}%`,
height: this.props.PanelWidth() ? undefined : `${100 / this.props.ContentScaling()}%`,
pointerEvents: this.layoutDoc.isBackground ? "none" : undefined,
diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx
index 3c232eff8..233acc481 100644
--- a/src/client/views/nodes/LinkAnchorBox.tsx
+++ b/src/client/views/nodes/LinkAnchorBox.tsx
@@ -17,6 +17,7 @@ import { LinkEditor } from "../linking/LinkEditor";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { SelectionManager } from "../../util/SelectionManager";
import { TraceMobx } from "../../../fields/util";
+import { Id } from "../../../fields/FieldSymbols";
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
@@ -55,8 +56,8 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps, LinkAnch
DragManager.StartDocumentDrag([this._ref.current!], dragData, down[0], down[1]);
return true;
} else if (dragdist > separation) {
- this.layoutDoc[this.fieldKey + "_x"] = (pt[0] - bounds.left) / bounds.width * 100;
- this.layoutDoc[this.fieldKey + "_y"] = (pt[1] - bounds.top) / bounds.height * 100;
+ this.rootDoc[this.fieldKey + "_x"] = (pt[0] - bounds.left) / bounds.width * 100;
+ this.rootDoc[this.fieldKey + "_y"] = (pt[1] - bounds.top) / bounds.height * 100;
}
}
return false;
@@ -113,8 +114,8 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps, LinkAnch
render() {
TraceMobx();
- const x = this.props.PanelWidth() > 1 ? NumCast(this.layoutDoc[this.fieldKey + "_x"], 100) : 0;
- const y = this.props.PanelWidth() > 1 ? NumCast(this.layoutDoc[this.fieldKey + "_y"], 100) : 0;
+ const x = this.props.PanelWidth() > 1 ? NumCast(this.rootDoc[this.fieldKey + "_x"], 100) : 0;
+ const y = this.props.PanelWidth() > 1 ? NumCast(this.rootDoc[this.fieldKey + "_y"], 100) : 0;
const c = StrCast(this.layoutDoc.backgroundColor, "lightblue");
const anchor = this.fieldKey === "anchor1" ? "anchor2" : "anchor1";
const anchorScale = (x === 0 || x === 100 || y === 0 || y === 100) ? 1 : .25;
@@ -130,7 +131,8 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps, LinkAnch
</div>
);
const small = this.props.PanelWidth() <= 1;
- return <div className={`linkAnchorBox-cont${small ? "-small" : ""}`} onPointerDown={this.onPointerDown} onClick={this.onClick} title={targetTitle} onContextMenu={this.specificContextMenu}
+ return <div className={`linkAnchorBox-cont${small ? "-small" : ""} ${this.rootDoc[Id]}`}
+ onPointerDown={this.onPointerDown} onClick={this.onClick} title={targetTitle} onContextMenu={this.specificContextMenu}
ref={this._ref} style={{
background: c,
left: !small ? `calc(${x}% - 7.5px)` : undefined,
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.scss b/src/client/views/nodes/formattedText/FormattedTextBox.scss
index 17421b1e3..348ed4ba5 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.scss
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.scss
@@ -295,6 +295,9 @@ footnote::after {
margin-left: 1em;
font-family: inherit;
}
+ .bullet { p {display: inline; font-family: inherit} margin-left: 0; }
+ .bullet1 { p {display: inline; font-family: inherit} }
+ .bullet2,.bullet3,.bullet4,.bullet5,.bullet6 { p {display: inline; font-family: inherit} font-size: smaller; }
.decimal1-ol { counter-reset: deci1; p {display: inline; font-family: inherit} margin-left: 0; }
.decimal2-ol { counter-reset: deci2; p {display: inline; font-family: inherit} font-size: smaller; padding-left: 1em;}
@@ -308,6 +311,8 @@ footnote::after {
.multi2-ol { counter-reset: multi2; p {display: inline; font-family: inherit} font-size: smaller; padding-left: 1.4em;}
.multi3-ol { counter-reset: multi3; p {display: inline; font-family: inherit} font-size: smaller; padding-left: 2em;}
.multi4-ol { counter-reset: multi4; p {display: inline; font-family: inherit} font-size: smaller; padding-left: 3.4em;}
+
+ .bullet:before, .bullet1:before, .bullet2:before, .bullet3:before, .bullet4:before, .bullet5:before { transition: 0.5s; display: inline-block; margin-left: -1em; width: 1em; content:" " }
.decimal1:before { transition: 0.5s;counter-increment: deci1; display: inline-block; margin-left: -1em; width: 1em; content: counter(deci1) ". "; }
.decimal2:before { transition: 0.5s;counter-increment: deci2; display: inline-block; margin-left: -2.1em; width: 2.1em; content: counter(deci1) "."counter(deci2) ". "; }
@@ -320,7 +325,7 @@ footnote::after {
.multi1:before { transition: 0.5s;counter-increment: multi1; display: inline-block; margin-left: -1em; width: 1.2em; content: counter(multi1, upper-alpha) ". "; }
.multi2:before { transition: 0.5s;counter-increment: multi2; display: inline-block; margin-left: -2em; width: 2em; content: counter(multi1, upper-alpha) "."counter(multi2, decimal) ". "; }
.multi3:before { transition: 0.5s;counter-increment: multi3; display: inline-block; margin-left: -2.85em; width:2.85em; content: counter(multi1, upper-alpha) "."counter(multi2, decimal) "."counter(multi3, lower-alpha) ". "; }
- .multi4:before { transition: 0.5s;counter-increment: multi4; display: inline-block; margin-left: -4.2em; width: 4.2em; content: counter(multi1, upper-alpha) "."counter(multi2, decimal) "."counter(multi3, lower-alpha) "."counter(multi4, lower-roman) ". "; }
+ .multi4:before { transition: 0.5s;counter-increment: multi4; display: inline-block; margin-left: -4.2em; width: 4.2em; content: counter(multi1, upper-alpha) "."counter(multi2, decimal) "."counter(multi3, lower-alpha) "."counter(multi4, lower-roman) ". "; }
}
.formattedTextBox-inner-rounded-selected,
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index c23ecb8ac..82334688b 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -15,6 +15,7 @@ import { EditorView } from "prosemirror-view";
import { DateField } from '../../../../fields/DateField';
import { DataSym, Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, WidthSym, AclSym } from "../../../../fields/Doc";
import { documentSchema } from '../../../../fields/documentSchemas';
+import applyDevTools = require("prosemirror-dev-tools");
import { Id } from '../../../../fields/FieldSymbols';
import { InkTool } from '../../../../fields/InkField';
import { PrefetchProxy } from '../../../../fields/Proxy';
@@ -57,6 +58,7 @@ import { FieldView, FieldViewProps } from "../FieldView";
import "./FormattedTextBox.scss";
import { FormattedTextBoxComment, formattedTextBoxCommentPlugin } from './FormattedTextBoxComment';
import React = require("react");
+import requestPromise = require('request-promise');
library.add(faEdit);
library.add(faSmile, faTextHeight, faUpload);
@@ -488,6 +490,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
});
changeItems.push({ description: "FreeForm", event: () => DocUtils.makeCustomViewClicked(this.rootDoc, Docs.Create.FreeformDocument, "freeform"), icon: "eye" });
!change && cm.addItem({ description: "Change Perspective...", subitems: changeItems, icon: "external-link-alt" });
+ this._downX = this._downY = Number.NaN;
}
recordDictation = () => {
@@ -920,6 +923,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
clipboardTextSerializer: this.clipboardTextSerializer,
handlePaste: this.handlePaste,
});
+ // applyDevTools.applyDevTools(this._editorView);
const startupText = !rtfField && this._editorView && Field.toString(this.dataDoc[fieldKey] as Field);
if (startupText) {
const { state: { tr }, dispatch } = this._editorView;
@@ -1008,7 +1012,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
if (e.buttons === 1 && this.props.isSelected(true) && !e.altKey) {
e.stopPropagation();
}
- this._downX = this._downY = Number.NaN;
}
@action
@@ -1073,38 +1076,35 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
// this hackiness handles clicking on the list item bullets to do expand/collapse. the bullets are ::before pseudo elements so there's no real way to hit test against them.
- hitBulletTargets(x: number, y: number, select: boolean, highlightOnly: boolean) {
+ hitBulletTargets(x: number, y: number, collapse: boolean, highlightOnly: boolean) {
clearStyleSheetRules(FormattedTextBox._bulletStyleSheet);
- const pos = this._editorView!.posAtCoords({ left: x, top: y });
- if (pos && this.props.isSelected(true)) {
- // let beforeEle = document.querySelector("." + hit.className) as Element; // const before = hit ? window.getComputedStyle(hit, ':before') : undefined;
- //const node = this._editorView!.state.doc.nodeAt(pos.pos);
- const $pos = this._editorView!.state.doc.resolve(pos.pos);
- let list_node = $pos.node().type === schema.nodes.list_item ? $pos.node() : undefined;
- if ($pos.node().type === schema.nodes.ordered_list) {
- for (let off = 1; off < 100; off++) {
- const pos = this._editorView!.posAtCoords({ left: x + off, top: y });
- const node = pos && this._editorView!.state.doc.nodeAt(pos.pos);
- if (node?.type === schema.nodes.list_item) {
- list_node = node;
- break;
- }
+ const clickPos = this._editorView!.posAtCoords({ left: x, top: y });
+ let olistPos = clickPos?.pos;
+ if (clickPos && olistPos && this.props.isSelected(true)) {
+ const clickNode = this._editorView?.state.doc.nodeAt(olistPos);
+ let nodeBef = this._editorView?.state.doc.nodeAt(Math.max(0, olistPos - 1));
+ olistPos = nodeBef?.type === this._editorView?.state.schema.nodes.ordered_list ? olistPos - 1 : olistPos;
+ let $olistPos = this._editorView?.state.doc.resolve(olistPos);
+ let olistNode = (nodeBef !== null || clickNode?.type === this._editorView?.state.schema.nodes.list_item) && olistPos === clickPos?.pos ? clickNode : nodeBef;
+ if (olistNode?.type === this._editorView?.state.schema.nodes.list_item) {
+ if ($olistPos && ($olistPos as any).path.length > 3) {
+ olistNode = $olistPos.parent;
+ $olistPos = this._editorView?.state.doc.resolve(($olistPos as any).path[($olistPos as any).path.length - 4]);
}
}
- if (list_node && pos.inside >= 0 && this._editorView!.state.doc.nodeAt(pos.inside)!.attrs.bulletStyle === list_node.attrs.bulletStyle) {
- if (select) {
- const $olist_pos = this._editorView!.state.doc.resolve($pos.pos - $pos.parentOffset - 1);
+ const listNode = this._editorView?.state.doc.nodeAt(clickPos.pos!);
+ if (olistNode && olistNode.type === this._editorView?.state.schema.nodes.ordered_list) {
+ if (!collapse) {
if (!highlightOnly) {
- this._editorView!.dispatch(this._editorView!.state.tr.setSelection(new NodeSelection($olist_pos)));
+ this._editorView!.dispatch(this._editorView!.state.tr.setSelection(new NodeSelection($olistPos!)));
}
- addStyleSheetRule(FormattedTextBox._bulletStyleSheet, list_node.attrs.mapStyle + list_node.attrs.bulletStyle + ":hover:before", { background: "lightgray" });
- } else if (Math.abs(pos.pos - pos.inside) < 2) {
+ addStyleSheetRule(FormattedTextBox._bulletStyleSheet, olistNode.attrs.mapStyle + olistNode.attrs.bulletStyle + ":hover:before", { background: "lightgray" });
+ } else if (listNode && listNode.type === this._editorView.state.schema.nodes.list_item) {
if (!highlightOnly) {
- const offset = this._editorView!.state.doc.nodeAt(pos.inside)?.type === schema.nodes.ordered_list ? 1 : 0;
- this._editorView!.dispatch(this._editorView!.state.tr.setNodeMarkup(pos.inside + offset, list_node.type, { ...list_node.attrs, visibility: !list_node.attrs.visibility }));
- this._editorView!.dispatch(this._editorView!.state.tr.setSelection(TextSelection.create(this._editorView!.state.doc, pos.inside + offset)));
+ this._editorView!.dispatch(this._editorView!.state.tr.setNodeMarkup(clickPos.pos!, listNode.type, { ...listNode.attrs, visibility: !listNode.attrs.visibility }));
+ this._editorView!.dispatch(this._editorView!.state.tr.setSelection(TextSelection.create(this._editorView!.state.doc, clickPos.pos!)));
}
- addStyleSheetRule(FormattedTextBox._bulletStyleSheet, list_node.attrs.mapStyle + list_node.attrs.bulletStyle + ":hover:before", { background: "lightgray" });
+ addStyleSheetRule(FormattedTextBox._bulletStyleSheet, olistNode.attrs.mapStyle + olistNode.attrs.bulletStyle + ":hover:before", { background: "lightgray" });
}
}
}
diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
index 0a4c52ef9..75cfe6bd1 100644
--- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
+++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts
@@ -16,16 +16,13 @@ const mac = typeof navigator !== "undefined" ? /Mac/.test(navigator.platform) :
export type KeyMap = { [key: string]: any };
-export let updateBullets = (tx2: Transaction, schema: Schema, mapStyle?: string) => {
- let fontSize: number | undefined = undefined;
+export let updateBullets = (tx2: Transaction, schema: Schema, mapStyle?: string, from?: number, to?: number) => {
tx2.doc.descendants((node: any, offset: any, index: any) => {
- if (node.type === schema.nodes.ordered_list || node.type === schema.nodes.list_item) {
+ if ((from === undefined || to === undefined || (from <= offset + node.nodeSize && to >= offset)) && (node.type === schema.nodes.ordered_list || node.type === schema.nodes.list_item)) {
const path = (tx2.doc.resolve(offset) as any).path;
let depth = Array.from(path).reduce((p: number, c: any) => p + (c.hasOwnProperty("type") && c.type === schema.nodes.ordered_list ? 1 : 0), 0);
if (node.type === schema.nodes.ordered_list) depth++;
- fontSize = depth === 1 && node.attrs.setFontSize ? Number(node.attrs.setFontSize) : fontSize;
- const fsize = fontSize && node.type === schema.nodes.ordered_list ? Math.max(6, fontSize - (depth - 1) * 4) : undefined;
- tx2.setNodeMarkup(offset, node.type, { ...node.attrs, mapStyle: mapStyle ? mapStyle : node.attrs.mapStyle, bulletStyle: depth, inheritedFontSize: fsize }, node.marks);
+ tx2.setNodeMarkup(offset, node.type, { ...node.attrs, mapStyle: mapStyle || node.attrs.mapStyle, bulletStyle: depth, }, node.marks);
}
});
return tx2;
@@ -62,7 +59,6 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, props: any
bind("Mod-U", toggleMark(schema.marks.underline));
//Commands for lists
- bind("Ctrl-.", wrapInList(schema.nodes.bullet_list));
bind("Ctrl-i", wrapInList(schema.nodes.ordered_list));
bind("Tab", (state: EditorState<S>, dispatch: (tx: Transaction<S>) => void) => {
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx
index 03d393cde..1e14b8237 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.tsx
+++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx
@@ -104,7 +104,7 @@ export default class RichTextMenu extends AntimodeMenu {
{ node: schema.nodes.ordered_list.create({ mapStyle: "bullet" }), title: "Set list type", label: ":", command: this.changeListType },
{ node: schema.nodes.ordered_list.create({ mapStyle: "decimal" }), title: "Set list type", label: "1.1", command: this.changeListType },
{ node: schema.nodes.ordered_list.create({ mapStyle: "multi" }), title: "Set list type", label: "1.A", command: this.changeListType },
- { node: undefined, title: "Set list type", label: "Remove", command: this.changeListType },
+ //{ node: undefined, title: "Set list type", label: "Remove", command: this.changeListType },
];
this.fontColors = [
@@ -189,9 +189,9 @@ export default class RichTextMenu extends AntimodeMenu {
const node = (state.selection as NodeSelection).node;
if (node?.type === schema.nodes.ordered_list) {
let attrs = node.attrs;
- if (mark.type === schema.marks.pFontFamily) attrs = { ...attrs, setFontFamily: mark.attrs.family };
- if (mark.type === schema.marks.pFontSize) attrs = { ...attrs, setFontSize: mark.attrs.fontSize };
- if (mark.type === schema.marks.pFontColor) attrs = { ...attrs, setFontColor: mark.attrs.color };
+ if (mark.type === schema.marks.pFontFamily) attrs = { ...attrs, fontFamily: mark.attrs.family };
+ if (mark.type === schema.marks.pFontSize) attrs = { ...attrs, fontSize: `${mark.attrs.fontSize}px` };
+ if (mark.type === schema.marks.pFontColor) attrs = { ...attrs, fontColor: mark.attrs.color };
const tr = updateBullets(state.tr.setNodeMarkup(state.selection.from, node.type, attrs), state.schema);
dispatch(tr.setSelection(new NodeSelection(tr.doc.resolve(state.selection.from))));
} else {
@@ -378,26 +378,24 @@ export default class RichTextMenu extends AntimodeMenu {
// TODO: remove doesn't work
//remove all node type and apply the passed-in one to the selected text
- changeListType = (nodeType: NodeType | undefined) => {
+ changeListType = (nodeType: Node | undefined) => {
if (!this.view) return;
- if (nodeType === schema.nodes.bullet_list) {
- wrapInList(nodeType)(this.view.state, this.view.dispatch);
- } else {
- const marks = this.view.state.storedMarks || (this.view.state.selection.$to.parentOffset && this.view.state.selection.$from.marks());
- if (!wrapInList(schema.nodes.ordered_list)(this.view.state, (tx2: any) => {
- const tx3 = updateBullets(tx2, schema, nodeType && (nodeType as any).attrs.mapStyle);
- marks && tx3.ensureMarks([...marks]);
- marks && tx3.setStoredMarks([...marks]);
-
- this.view!.dispatch(tx2);
- })) {
- const tx2 = this.view.state.tr;
- const tx3 = updateBullets(tx2, schema, nodeType && (nodeType as any).attrs.mapStyle);
+ const marks = this.view.state.storedMarks || (this.view.state.selection.$to.parentOffset && this.view.state.selection.$from.marks());
+ if (!wrapInList(schema.nodes.ordered_list)(this.view.state, (tx2: any) => {
+ const tx3 = updateBullets(tx2, schema, nodeType && (nodeType as any).attrs.mapStyle, this.view!.state.selection.from - 1, this.view!.state.selection.to + 1);
+ marks && tx3.ensureMarks([...marks]);
+ marks && tx3.setStoredMarks([...marks]);
+
+ this.view!.dispatch(tx2);
+ })) {
+ const tx2 = this.view.state.tr;
+ if (nodeType && this.view.state.selection.$from.nodeAfter?.type === schema.nodes.ordered_list) {
+ const tx3 = updateBullets(tx2, schema, nodeType && (nodeType as any).attrs.mapStyle, this.view.state.selection.from, this.view.state.selection.to);
marks && tx3.ensureMarks([...marks]);
marks && tx3.setStoredMarks([...marks]);
- this.view.dispatch(tx3);
+ this.view.dispatch(tx3.setSelection(new NodeSelection(tx3.doc.resolve(this.view.state.selection.$from.pos))));
}
}
}
diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts
index 91187edf9..e442149d6 100644
--- a/src/client/views/nodes/formattedText/RichTextRules.ts
+++ b/src/client/views/nodes/formattedText/RichTextRules.ts
@@ -59,7 +59,7 @@ export class RichTextRules {
),
// * + - create bullet list
- wrappingInputRule(/^\s*([-+*])\s$/, schema.nodes.bullet_list),
+ wrappingInputRule(/^\s*([-+*])\s$/, schema.nodes.ordered_list),
// ``` create code block
textblockTypeInputRule(/^```$/, schema.nodes.code_block),
diff --git a/src/client/views/nodes/formattedText/marks_rts.ts b/src/client/views/nodes/formattedText/marks_rts.ts
index 49d5c96a4..1de211f28 100644
--- a/src/client/views/nodes/formattedText/marks_rts.ts
+++ b/src/client/views/nodes/formattedText/marks_rts.ts
@@ -53,21 +53,45 @@ export const marks: { [index: string]: MarkSpec } = {
}
},
+ /** FONT SIZES */
+ pFontSize: {
+ attrs: { fontSize: { default: 10 } },
+ parseDOM: [{
+ tag: "span", getAttrs(dom: any) {
+ return { fontSize: dom.style.fontSize ? Number(dom.style.fontSize.replace("px", "")) : "" };
+ }
+ }],
+ toDOM: (node) => node.attrs.fontSize ? ['span', { style: `font-size: ${node.attrs.fontSize}px;` }] : ['span', 0]
+ },
+ /* FONTS */
+ pFontFamily: {
+ attrs: { family: { default: "" } },
+ parseDOM: [{
+ tag: "span", getAttrs(dom: any) {
+ const cstyle = getComputedStyle(dom);
+ if (cstyle.font) {
+ if (cstyle.font.indexOf("Times New Roman") !== -1) return { family: "Times New Roman" };
+ if (cstyle.font.indexOf("Arial") !== -1) return { family: "Arial" };
+ if (cstyle.font.indexOf("Georgia") !== -1) return { family: "Georgia" };
+ if (cstyle.font.indexOf("Comic Sans") !== -1) return { family: "Comic Sans MS" };
+ if (cstyle.font.indexOf("Tahoma") !== -1) return { family: "Tahoma" };
+ if (cstyle.font.indexOf("Crimson") !== -1) return { family: "Crimson Text" };
+ }
+ }
+ }],
+ toDOM: (node) => node.attrs.family ? ['span', { style: `font-family: "${node.attrs.family}";` }] : ['span', 0]
+ },
// :: MarkSpec Coloring on text. Has `color` attribute that defined the color of the marked text.
pFontColor: {
- attrs: {
- color: { default: "#000" }
- },
+ attrs: { color: { default: "" } },
inclusive: true,
parseDOM: [{
tag: "span", getAttrs(dom: any) {
return { color: dom.getAttribute("color") };
}
}],
- toDOM(node: any) {
- return node.attrs.color ? ['span', { style: 'color:' + node.attrs.color }] : ['span', 0];
- }
+ toDOM: (node) => node.attrs.color ? ['span', { style: 'color:' + node.attrs.color }] : ['span', 0]
},
marker: {
@@ -277,38 +301,4 @@ export const marks: { [index: string]: MarkSpec } = {
parseDOM: [{ tag: "code" }],
toDOM() { return codeDOM; }
},
-
- /* FONTS */
- pFontFamily: {
- attrs: {
- family: { default: "Crimson Text" },
- },
- parseDOM: [{
- tag: "span", getAttrs(dom: any) {
- const cstyle = getComputedStyle(dom);
- if (cstyle.font) {
- if (cstyle.font.indexOf("Times New Roman") !== -1) return { family: "Times New Roman" };
- if (cstyle.font.indexOf("Arial") !== -1) return { family: "Arial" };
- if (cstyle.font.indexOf("Georgia") !== -1) return { family: "Georgia" };
- if (cstyle.font.indexOf("Comic Sans") !== -1) return { family: "Comic Sans MS" };
- if (cstyle.font.indexOf("Tahoma") !== -1) return { family: "Tahoma" };
- if (cstyle.font.indexOf("Crimson") !== -1) return { family: "Crimson Text" };
- }
- }
- }],
- toDOM: (node) => ['span', {
- style: `font-family: "${node.attrs.family}";`
- }]
- },
-
- /** FONT SIZES */
- pFontSize: {
- attrs: {
- fontSize: { default: 10 }
- },
- parseDOM: [{ style: 'font-size: 10px;' }],
- toDOM: (node) => ['span', {
- style: `font-size: ${node.attrs.fontSize}px;`
- }]
- },
};
diff --git a/src/client/views/nodes/formattedText/nodes_rts.ts b/src/client/views/nodes/formattedText/nodes_rts.ts
index af39ef9c7..b37e61d3f 100644
--- a/src/client/views/nodes/formattedText/nodes_rts.ts
+++ b/src/client/views/nodes/formattedText/nodes_rts.ts
@@ -218,48 +218,85 @@ export const nodes: { [index: string]: NodeSpec } = {
group: 'block',
attrs: {
bulletStyle: { default: 0 },
- mapStyle: { default: "decimal" },
- setFontSize: { default: undefined },
- setFontFamily: { default: "inherit" },
- setFontColor: { default: "inherit" },
- inheritedFontSize: { default: undefined },
+ mapStyle: { default: "decimal" },// "decimal", "multi", "bullet"
+ fontColor: { default: "inherit" },
+ fontSize: { default: undefined },
+ fontFamily: { default: undefined },
visibility: { default: true },
indent: { default: undefined }
},
+ parseDOM: [
+ {
+ tag: "ul", getAttrs(dom: any) {
+ return {
+ bulletStyle: dom.getAttribute("data-bulletStyle"),
+ mapStyle: dom.getAttribute("data-mapStyle"),
+ fontColor: dom.style.color,
+ fontSize: dom.style["font-size"],
+ fontFamily: dom.style["font-family"],
+ indent: dom.style["margin-left"]
+ };
+ }
+ },
+ {
+ style: 'list-style-type=disc', getAttrs(dom: any) {
+ return { mapStyle: "bullet" }
+ }
+ },
+ {
+ tag: "ol", getAttrs(dom: any) {
+ return {
+ bulletStyle: dom.getAttribute("data-bulletStyle"),
+ mapStyle: dom.getAttribute("data-mapStyle"),
+ fontColor: dom.style.color,
+ fontSize: dom.style["font-size"],
+ fontFamily: dom.style["font-family"],
+ indent: dom.style["margin-left"]
+ };
+ }
+ }],
toDOM(node: Node<any>) {
- if (node.attrs.mapStyle === "bullet") return ['ul', 0];
const map = node.attrs.bulletStyle ? node.attrs.mapStyle + node.attrs.bulletStyle : "";
- const fsize = node.attrs.setFontSize ? node.attrs.setFontSize : node.attrs.inheritedFontSize;
- const ffam = node.attrs.setFontFamily;
- const color = node.attrs.setFontColor;
+ const fsize = node.attrs.fontSize ? `font-size: ${node.attrs.fontSize};` : "";
+ const ffam = node.attrs.fontFamily ? `font-family:${node.attrs.fontFamily};` : "";
+ const fcol = node.attrs.fontColor ? `color: ${node.attrs.fontColor};` : "";
+ const marg = node.attrs.indent ? `margin-left: ${node.attrs.indent};` : "";
+ if (node.attrs.mapStyle === "bullet") {
+ return ['ul', {
+ "data-mapStyle": node.attrs.mapStyle,
+ "data-bulletStyle": node.attrs.bulletStyle,
+ style: `${fsize} ${ffam} ${fcol} ${marg}`
+ }, 0];
+ }
return node.attrs.visibility ?
- ['ol', { class: `${map}-ol`, style: `list-style: none; font-size: ${fsize}; font-family: ${ffam}; color:${color}; margin-left: ${node.attrs.indent}` }, 0] :
+ ['ol', {
+ class: `${map}-ol`,
+ "data-mapStyle": node.attrs.mapStyle,
+ "data-bulletStyle": node.attrs.bulletStyle,
+ style: `list-style: none; ${fsize} ${ffam} ${fcol} ${marg}`
+ }, 0] :
['ol', { class: `${map}-ol`, style: `list-style: none;` }];
}
},
- bullet_list: {
- ...bulletList,
- content: 'list_item+',
- group: 'block',
- // parseDOM: [{ tag: "ul" }, { style: 'list-style-type=disc' }],
- toDOM(node: Node<any>) {
- return ['ul', 0];
- }
- },
-
list_item: {
+ ...listItem,
attrs: {
bulletStyle: { default: 0 },
- mapStyle: { default: "decimal" },
+ mapStyle: { default: "decimal" }, // "decimal", "multi", "bullet"
visibility: { default: true }
},
- ...listItem,
content: 'paragraph block*',
+ parseDOM: [{
+ tag: "li", getAttrs(dom: any) {
+ return { mapStyle: dom.getAttribute("data-mapStyle"), bulletStyle: dom.getAttribute("data-bulletStyle") };
+ }
+ }],
toDOM(node: any) {
const map = node.attrs.bulletStyle ? node.attrs.mapStyle + node.attrs.bulletStyle : "";
- return node.attrs.visibility ? ["li", { class: `${map}` }, 0] : ["li", { class: `${map}` }, "..."];
- //return ["li", { class: `${map}` }, 0];
+ return node.attrs.visibility ?
+ ["li", { class: `${map}`, "data-mapStyle": node.attrs.mapStyle, "data-bulletStyle": node.attrs.bulletStyle }, 0] :
+ ["li", { class: `${map}`, "data-mapStyle": node.attrs.mapStyle, "data-bulletStyle": node.attrs.bulletStyle }, "..."];
}
},
}; \ No newline at end of file
diff --git a/src/fields/RichTextUtils.ts b/src/fields/RichTextUtils.ts
index 66959882d..7c7bf3e12 100644
--- a/src/fields/RichTextUtils.ts
+++ b/src/fields/RichTextUtils.ts
@@ -256,7 +256,7 @@ export namespace RichTextUtils {
};
const list = (schema: any, items: Node[]): Node => {
- return schema.node("bullet_list", null, items);
+ return schema.node("ordered_list", { mapStyle: "bullet" }, items);
};
const paragraphNode = (schema: any, runs: docs_v1.Schema$TextRun[]): Node => {