aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--package.json332
-rw-r--r--src/client/util/RichTextSchema.tsx507
-rw-r--r--src/client/util/TooltipTextMenu.scss238
-rw-r--r--src/client/util/TooltipTextMenu.tsx173
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx7
5 files changed, 830 insertions, 427 deletions
diff --git a/package.json b/package.json
index 135bd4a91..11eb6f0f5 100644
--- a/package.json
+++ b/package.json
@@ -1,168 +1,168 @@
{
- "name": "dash",
- "version": "1.0.0",
- "description": "",
- "main": "index.js",
- "scripts": {
- "start": "nodemon --watch src/server/**/*.ts --exec ts-node src/server/index.ts",
- "build": "webpack --env production",
- "test": "mocha -r ts-node/register test/**/*.ts",
- "tsc": "tsc"
- },
- "devDependencies": {
- "@types/chai": "^4.1.7",
- "@types/mocha": "^5.2.6",
- "@types/react-dom": "^16.8.2",
- "@types/webpack-dev-middleware": "^2.0.2",
- "@types/webpack-hot-middleware": "^2.16.4",
- "awesome-typescript-loader": "^5.2.1",
- "chai": "^4.2.0",
- "copy-webpack-plugin": "^4.6.0",
- "css-loader": "^2.1.1",
- "file-loader": "^3.0.1",
- "mocha": "^5.2.0",
- "sass-loader": "^7.1.0",
- "scss-loader": "0.0.1",
- "style-loader": "^0.23.1",
- "ts-node": "^7.0.1",
- "typescript": "^3.4.1",
- "webpack": "^4.29.6",
- "webpack-cli": "^3.2.3",
- "webpack-dev-middleware": "^3.6.1",
- "webpack-dev-server": "^3.2.1",
- "webpack-hot-middleware": "^2.24.3"
- },
- "dependencies": {
- "@fortawesome/fontawesome-free-solid": "^5.0.13",
- "@fortawesome/fontawesome-svg-core": "^1.2.15",
- "@fortawesome/free-solid-svg-icons": "^5.7.2",
- "@fortawesome/react-fontawesome": "^0.1.4",
- "@hig/flyout": "^1.0.3",
- "@hig/theme-context": "^2.1.3",
- "@hig/theme-data": "^2.3.3",
- "@trendmicro/react-dropdown": "^1.3.0",
- "@types/async": "^2.4.1",
- "@types/bcrypt-nodejs": "0.0.30",
- "@types/bluebird": "^3.5.25",
- "@types/body-parser": "^1.17.0",
- "@types/connect-flash": "0.0.34",
- "@types/cookie-parser": "^1.4.1",
- "@types/cookie-session": "^2.0.36",
- "@types/d3-format": "^1.3.1",
- "@types/express": "^4.16.1",
- "@types/express-flash": "0.0.0",
- "@types/express-session": "^1.15.12",
- "@types/express-validator": "^3.0.0",
- "@types/formidable": "^1.0.31",
- "@types/jquery": "^3.3.29",
- "@types/jsonwebtoken": "^8.3.2",
- "@types/lodash": "^4.14.121",
- "@types/mobile-detect": "^1.3.4",
- "@types/mongodb": "^3.1.22",
- "@types/mongoose": "^5.3.21",
- "@types/node": "^10.12.30",
- "@types/nodemailer": "^4.6.6",
- "@types/passport": "^1.0.0",
- "@types/passport-local": "^1.0.33",
- "@types/prosemirror-commands": "^1.0.1",
- "@types/prosemirror-history": "^1.0.1",
- "@types/prosemirror-inputrules": "^1.0.2",
- "@types/prosemirror-keymap": "^1.0.1",
- "@types/prosemirror-menu": "^1.0.1",
- "@types/prosemirror-model": "^1.7.0",
- "@types/prosemirror-schema-basic": "^1.0.1",
- "@types/prosemirror-schema-list": "^1.0.1",
- "@types/prosemirror-state": "^1.2.3",
- "@types/prosemirror-transform": "^1.1.0",
- "@types/prosemirror-view": "^1.3.1",
- "@types/pug": "^2.0.4",
- "@types/react": "^16.8.7",
- "@types/react-color": "^2.14.1",
- "@types/react-measure": "^2.0.4",
- "@types/react-table": "^6.7.22",
- "@types/request": "^2.48.1",
- "@types/request-promise": "^4.1.42",
- "@types/socket.io": "^2.1.2",
- "@types/socket.io-client": "^1.4.32",
- "@types/typescript": "^2.0.0",
- "@types/uuid": "^3.4.4",
- "@types/webpack": "^4.4.25",
- "async": "^2.6.2",
- "babel-runtime": "^6.26.0",
- "bcrypt-nodejs": "0.0.3",
- "bluebird": "^3.5.3",
- "body-parser": "^1.18.3",
- "bootstrap": "^4.3.1",
- "class-transformer": "^0.2.0",
- "connect-flash": "^0.1.1",
- "connect-mongo": "^2.0.3",
- "cookie-parser": "^1.4.4",
- "cookie-session": "^2.0.0-beta.3",
- "crypto-browserify": "^3.11.0",
- "d3-format": "^1.3.2",
- "express": "^4.16.4",
- "express-flash": "0.0.2",
- "express-session": "^1.15.6",
- "express-validator": "^5.3.1",
- "expressjs": "^1.0.1",
- "flexlayout-react": "^0.3.3",
- "font-awesome": "^4.7.0",
- "formidable": "^1.2.1",
- "golden-layout": "^1.5.9",
- "html-to-image": "^0.1.0",
- "i": "^0.3.6",
- "jsonwebtoken": "^8.5.0",
- "jsx-to-string": "^1.4.0",
- "lodash": "^4.17.11",
- "mobile-detect": "^1.4.3",
- "mobx": "^5.9.0",
- "mobx-react": "^5.3.5",
- "mobx-react-devtools": "^6.1.1",
- "mongodb": "^3.1.13",
- "mongoose": "^5.4.18",
- "node-sass": "^4.11.0",
- "nodemailer": "^5.1.1",
- "nodemon": "^1.18.10",
- "normalize.css": "^8.0.1",
- "npm": "^6.9.0",
- "passport": "^0.4.0",
- "passport-local": "^1.0.0",
- "prosemirror-commands": "^1.0.7",
- "prosemirror-example-setup": "^1.0.1",
- "prosemirror-history": "^1.0.4",
- "prosemirror-keymap": "^1.0.1",
- "prosemirror-model": "^1.7.0",
- "prosemirror-schema-basic": "^1.0.0",
- "prosemirror-schema-list": "^1.0.2",
- "prosemirror-state": "^1.2.2",
- "prosemirror-transform": "^1.1.3",
- "prosemirror-view": "^1.8.3",
- "pug": "^2.0.3",
- "raw-loader": "^1.0.0",
- "react": "^16.8.4",
- "react-bootstrap": "^1.0.0-beta.5",
- "react-bootstrap-dropdown-menu": "^1.1.15",
- "react-color": "^2.17.0",
- "react-dimensions": "^1.3.1",
- "react-dom": "^16.8.4",
- "react-golden-layout": "^1.0.6",
- "react-image-lightbox": "^5.1.0",
- "react-jsx-parser": "^1.15.0",
- "react-measure": "^2.2.4",
- "react-mosaic": "0.0.20",
- "react-pdf": "^4.0.2",
- "react-pdf-highlighter": "^2.1.2",
- "react-pdf-js": "^4.0.2",
- "react-simple-dropdown": "^3.2.3",
- "react-split-pane": "^0.1.85",
- "react-table": "^6.9.2",
- "request": "^2.88.0",
- "request-promise": "^4.2.4",
- "socket.io": "^2.2.0",
- "socket.io-client": "^2.2.0",
- "typescript-collections": "^1.3.2",
- "url-loader": "^1.1.2",
- "uuid": "^3.3.2",
- "xoauth2": "^1.2.0"
- }
+ "name": "dash",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "start": "nodemon --watch src/server/**/*.ts --exec ts-node src/server/index.ts",
+ "build": "webpack --env production",
+ "test": "mocha -r ts-node/register test/**/*.ts",
+ "tsc": "tsc"
+ },
+ "devDependencies": {
+ "@types/chai": "^4.1.7",
+ "@types/mocha": "^5.2.6",
+ "@types/react-dom": "^16.8.2",
+ "@types/webpack-dev-middleware": "^2.0.2",
+ "@types/webpack-hot-middleware": "^2.16.4",
+ "awesome-typescript-loader": "^5.2.1",
+ "chai": "^4.2.0",
+ "copy-webpack-plugin": "^4.6.0",
+ "css-loader": "^2.1.1",
+ "file-loader": "^3.0.1",
+ "mocha": "^5.2.0",
+ "sass-loader": "^7.1.0",
+ "scss-loader": "0.0.1",
+ "style-loader": "^0.23.1",
+ "ts-node": "^7.0.1",
+ "typescript": "^3.4.1",
+ "webpack": "^4.29.6",
+ "webpack-cli": "^3.2.3",
+ "webpack-dev-middleware": "^3.6.1",
+ "webpack-dev-server": "^3.2.1",
+ "webpack-hot-middleware": "^2.24.3"
+ },
+ "dependencies": {
+ "@fortawesome/fontawesome-free-solid": "^5.0.13",
+ "@fortawesome/fontawesome-svg-core": "^1.2.15",
+ "@fortawesome/free-solid-svg-icons": "^5.7.2",
+ "@fortawesome/react-fontawesome": "^0.1.4",
+ "@hig/flyout": "^1.0.3",
+ "@hig/theme-context": "^2.1.3",
+ "@hig/theme-data": "^2.3.3",
+ "@trendmicro/react-dropdown": "^1.3.0",
+ "@types/async": "^2.4.1",
+ "@types/bcrypt-nodejs": "0.0.30",
+ "@types/bluebird": "^3.5.25",
+ "@types/body-parser": "^1.17.0",
+ "@types/connect-flash": "0.0.34",
+ "@types/cookie-parser": "^1.4.1",
+ "@types/cookie-session": "^2.0.36",
+ "@types/d3-format": "^1.3.1",
+ "@types/express": "^4.16.1",
+ "@types/express-flash": "0.0.0",
+ "@types/express-session": "^1.15.12",
+ "@types/express-validator": "^3.0.0",
+ "@types/formidable": "^1.0.31",
+ "@types/jquery": "^3.3.29",
+ "@types/jsonwebtoken": "^8.3.2",
+ "@types/lodash": "^4.14.121",
+ "@types/mobile-detect": "^1.3.4",
+ "@types/mongodb": "^3.1.22",
+ "@types/mongoose": "^5.3.21",
+ "@types/node": "^10.12.30",
+ "@types/nodemailer": "^4.6.6",
+ "@types/passport": "^1.0.0",
+ "@types/passport-local": "^1.0.33",
+ "@types/prosemirror-commands": "^1.0.1",
+ "@types/prosemirror-history": "^1.0.1",
+ "@types/prosemirror-inputrules": "^1.0.2",
+ "@types/prosemirror-keymap": "^1.0.1",
+ "@types/prosemirror-menu": "^1.0.1",
+ "@types/prosemirror-model": "^1.7.0",
+ "@types/prosemirror-schema-basic": "^1.0.1",
+ "@types/prosemirror-schema-list": "^1.0.1",
+ "@types/prosemirror-state": "^1.2.3",
+ "@types/prosemirror-transform": "^1.1.0",
+ "@types/prosemirror-view": "^1.3.1",
+ "@types/pug": "^2.0.4",
+ "@types/react": "^16.8.7",
+ "@types/react-color": "^2.14.1",
+ "@types/react-measure": "^2.0.4",
+ "@types/react-table": "^6.7.22",
+ "@types/request": "^2.48.1",
+ "@types/request-promise": "^4.1.42",
+ "@types/socket.io": "^2.1.2",
+ "@types/socket.io-client": "^1.4.32",
+ "@types/typescript": "^2.0.0",
+ "@types/uuid": "^3.4.4",
+ "@types/webpack": "^4.4.25",
+ "async": "^2.6.2",
+ "babel-runtime": "^6.26.0",
+ "bcrypt-nodejs": "0.0.3",
+ "bluebird": "^3.5.3",
+ "body-parser": "^1.18.3",
+ "bootstrap": "^4.3.1",
+ "class-transformer": "^0.2.0",
+ "connect-flash": "^0.1.1",
+ "connect-mongo": "^2.0.3",
+ "cookie-parser": "^1.4.4",
+ "cookie-session": "^2.0.0-beta.3",
+ "crypto-browserify": "^3.11.0",
+ "d3-format": "^1.3.2",
+ "express": "^4.16.4",
+ "express-flash": "0.0.2",
+ "express-session": "^1.15.6",
+ "express-validator": "^5.3.1",
+ "expressjs": "^1.0.1",
+ "flexlayout-react": "^0.3.3",
+ "font-awesome": "^4.7.0",
+ "formidable": "^1.2.1",
+ "golden-layout": "^1.5.9",
+ "html-to-image": "^0.1.0",
+ "i": "^0.3.6",
+ "jsonwebtoken": "^8.5.0",
+ "jsx-to-string": "^1.4.0",
+ "lodash": "^4.17.11",
+ "mobile-detect": "^1.4.3",
+ "mobx": "^5.9.0",
+ "mobx-react": "^5.3.5",
+ "mobx-react-devtools": "^6.1.1",
+ "mongodb": "^3.1.13",
+ "mongoose": "^5.4.18",
+ "node-sass": "^4.11.0",
+ "nodemailer": "^5.1.1",
+ "nodemon": "^1.18.10",
+ "normalize.css": "^8.0.1",
+ "npm": "^6.9.0",
+ "passport": "^0.4.0",
+ "passport-local": "^1.0.0",
+ "prosemirror-commands": "^1.0.7",
+ "prosemirror-example-setup": "^1.0.1",
+ "prosemirror-history": "^1.0.4",
+ "prosemirror-keymap": "^1.0.1",
+ "prosemirror-model": "^1.7.0",
+ "prosemirror-schema-basic": "^1.0.0",
+ "prosemirror-schema-list": "^1.0.2",
+ "prosemirror-state": "^1.2.2",
+ "prosemirror-transform": "^1.1.3",
+ "prosemirror-view": "^1.8.3",
+ "pug": "^2.0.3",
+ "raw-loader": "^1.0.0",
+ "react": "^16.8.4",
+ "react-bootstrap": "^1.0.0-beta.5",
+ "react-bootstrap-dropdown-menu": "^1.1.15",
+ "react-color": "^2.17.0",
+ "react-dimensions": "^1.3.1",
+ "react-dom": "^16.8.4",
+ "react-golden-layout": "^1.0.6",
+ "react-image-lightbox": "^5.1.0",
+ "react-jsx-parser": "^1.15.0",
+ "react-measure": "^2.2.4",
+ "react-mosaic": "0.0.20",
+ "react-pdf": "^4.0.2",
+ "react-pdf-highlighter": "^2.1.2",
+ "react-pdf-js": "^4.0.2",
+ "react-simple-dropdown": "^3.2.3",
+ "react-split-pane": "^0.1.85",
+ "react-table": "^6.9.2",
+ "request": "^2.88.0",
+ "request-promise": "^4.2.4",
+ "socket.io": "^2.2.0",
+ "socket.io-client": "^2.2.0",
+ "typescript-collections": "^1.3.2",
+ "url-loader": "^1.1.2",
+ "uuid": "^3.3.2",
+ "xoauth2": "^1.2.0"
+ }
}
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 489c22a57..765ac0ae3 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -7,134 +7,134 @@ import { EditorState, Transaction, NodeSelection, } from "prosemirror-state";
import { EditorView, } from "prosemirror-view";
const pDOM: DOMOutputSpecArray = ["p", 0], blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"],
- preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0]
+ preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0]
// :: Object
// [Specs](#model.NodeSpec) for the nodes defined in this schema.
export const nodes: { [index: string]: NodeSpec } = {
- // :: NodeSpec The top level document node.
- doc: {
- content: "block+"
- },
-
- // :: NodeSpec A plain paragraph textblock. Represented in the DOM
- // as a `<p>` element.
- paragraph: {
- content: "inline*",
- group: "block",
- parseDOM: [{ tag: "p" }],
- toDOM() { return pDOM }
- },
-
- // :: NodeSpec A blockquote (`<blockquote>`) wrapping one or more blocks.
- blockquote: {
- content: "block+",
- group: "block",
- defining: true,
- parseDOM: [{ tag: "blockquote" }],
- toDOM() { return blockquoteDOM }
- },
-
- // :: NodeSpec A horizontal rule (`<hr>`).
- horizontal_rule: {
- group: "block",
- parseDOM: [{ tag: "hr" }],
- toDOM() { return hrDOM }
- },
-
- // :: NodeSpec A heading textblock, with a `level` attribute that
- // should hold the number 1 to 6. Parsed and serialized as `<h1>` to
- // `<h6>` elements.
- heading: {
- attrs: { level: { default: 1 } },
- content: "inline*",
- group: "block",
- defining: true,
- parseDOM: [{ tag: "h1", attrs: { level: 1 } },
- { tag: "h2", attrs: { level: 2 } },
- { tag: "h3", attrs: { level: 3 } },
- { tag: "h4", attrs: { level: 4 } },
- { tag: "h5", attrs: { level: 5 } },
- { tag: "h6", attrs: { level: 6 } }],
- toDOM(node: any) { return ["h" + node.attrs.level, 0] }
- },
-
- // :: NodeSpec A code listing. Disallows marks or non-text inline
- // nodes by default. Represented as a `<pre>` element with a
- // `<code>` element inside of it.
- code_block: {
- content: "text*",
- marks: "",
- group: "block",
- code: true,
- defining: true,
- parseDOM: [{ tag: "pre", preserveWhitespace: "full" }],
- toDOM() { return preDOM }
- },
-
- // :: NodeSpec The text node.
- text: {
- group: "inline"
- },
-
- // :: NodeSpec An inline image (`<img>`) node. Supports `src`,
- // `alt`, and `href` attributes. The latter two default to the empty
- // string.
- image: {
- inline: true,
- attrs: {
- src: {},
- alt: { default: null },
- title: { default: null }
- },
- group: "inline",
- draggable: true,
- parseDOM: [{
- tag: "img[src]", getAttrs(dom: any) {
- return {
- src: dom.getAttribute("src"),
- title: dom.getAttribute("title"),
- alt: dom.getAttribute("alt")
- }
- }
- }],
- toDOM(node: any) { return ["img", node.attrs] }
- },
-
- // :: NodeSpec A hard line break, represented in the DOM as `<br>`.
- hard_break: {
- inline: true,
- group: "inline",
- selectable: false,
- parseDOM: [{ tag: "br" }],
- toDOM() { return brDOM }
- },
-
- ordered_list: {
- ...orderedList,
- content: 'list_item+',
- group: 'block'
- },
- //this doesn't currently work for some reason
- bullet_list: {
- ...bulletList,
- content: 'list_item+',
- group: 'block',
- // parseDOM: [{ tag: "ul" }, { style: 'list-style-type=disc' }],
- // toDOM() { return ulDOM }
- },
- //bullet_list: {
- // content: 'list_item+',
- // group: 'block',
- //active: blockActive(schema.nodes.bullet_list),
- //enable: wrapInList(schema.nodes.bullet_list),
- //run: wrapInList(schema.nodes.bullet_list),
- //select: state => true,
- // },
- list_item: {
- ...listItem,
- content: 'paragraph block*'
- }
+ // :: NodeSpec The top level document node.
+ doc: {
+ content: "block+"
+ },
+
+ // :: NodeSpec A plain paragraph textblock. Represented in the DOM
+ // as a `<p>` element.
+ paragraph: {
+ content: "inline*",
+ group: "block",
+ parseDOM: [{ tag: "p" }],
+ toDOM() { return pDOM }
+ },
+
+ // :: NodeSpec A blockquote (`<blockquote>`) wrapping one or more blocks.
+ blockquote: {
+ content: "block+",
+ group: "block",
+ defining: true,
+ parseDOM: [{ tag: "blockquote" }],
+ toDOM() { return blockquoteDOM }
+ },
+
+ // :: NodeSpec A horizontal rule (`<hr>`).
+ horizontal_rule: {
+ group: "block",
+ parseDOM: [{ tag: "hr" }],
+ toDOM() { return hrDOM }
+ },
+
+ // :: NodeSpec A heading textblock, with a `level` attribute that
+ // should hold the number 1 to 6. Parsed and serialized as `<h1>` to
+ // `<h6>` elements.
+ heading: {
+ attrs: { level: { default: 1 } },
+ content: "inline*",
+ group: "block",
+ defining: true,
+ parseDOM: [{ tag: "h1", attrs: { level: 1 } },
+ { tag: "h2", attrs: { level: 2 } },
+ { tag: "h3", attrs: { level: 3 } },
+ { tag: "h4", attrs: { level: 4 } },
+ { tag: "h5", attrs: { level: 5 } },
+ { tag: "h6", attrs: { level: 6 } }],
+ toDOM(node: any) { return ["h" + node.attrs.level, 0] }
+ },
+
+ // :: NodeSpec A code listing. Disallows marks or non-text inline
+ // nodes by default. Represented as a `<pre>` element with a
+ // `<code>` element inside of it.
+ code_block: {
+ content: "text*",
+ marks: "",
+ group: "block",
+ code: true,
+ defining: true,
+ parseDOM: [{ tag: "pre", preserveWhitespace: "full" }],
+ toDOM() { return preDOM }
+ },
+
+ // :: NodeSpec The text node.
+ text: {
+ group: "inline"
+ },
+
+ // :: NodeSpec An inline image (`<img>`) node. Supports `src`,
+ // `alt`, and `href` attributes. The latter two default to the empty
+ // string.
+ image: {
+ inline: true,
+ attrs: {
+ src: {},
+ alt: { default: null },
+ title: { default: null }
+ },
+ group: "inline",
+ draggable: true,
+ parseDOM: [{
+ tag: "img[src]", getAttrs(dom: any) {
+ return {
+ src: dom.getAttribute("src"),
+ title: dom.getAttribute("title"),
+ alt: dom.getAttribute("alt")
+ }
+ }
+ }],
+ toDOM(node: any) { return ["img", node.attrs] }
+ },
+
+ // :: NodeSpec A hard line break, represented in the DOM as `<br>`.
+ hard_break: {
+ inline: true,
+ group: "inline",
+ selectable: false,
+ parseDOM: [{ tag: "br" }],
+ toDOM() { return brDOM }
+ },
+
+ ordered_list: {
+ ...orderedList,
+ content: 'list_item+',
+ group: 'block'
+ },
+ //this doesn't currently work for some reason
+ bullet_list: {
+ ...bulletList,
+ content: 'list_item+',
+ group: 'block',
+ // parseDOM: [{ tag: "ul" }, { style: 'list-style-type=disc' }],
+ // toDOM() { return ulDOM }
+ },
+ //bullet_list: {
+ // content: 'list_item+',
+ // group: 'block',
+ //active: blockActive(schema.nodes.bullet_list),
+ //enable: wrapInList(schema.nodes.bullet_list),
+ //run: wrapInList(schema.nodes.bullet_list),
+ //select: state => true,
+ // },
+ list_item: {
+ ...listItem,
+ content: 'paragraph block*'
+ }
}
const emDOM: DOMOutputSpecArray = ["em", 0];
@@ -144,92 +144,179 @@ const underlineDOM: DOMOutputSpecArray = ["underline", 0];
// :: Object [Specs](#model.MarkSpec) for the marks in the schema.
export const marks: { [index: string]: MarkSpec } = {
- // :: MarkSpec A link. Has `href` and `title` attributes. `title`
- // defaults to the empty string. Rendered and parsed as an `<a>`
- // element.
- link: {
- attrs: {
- href: {},
- title: { default: null }
- },
- inclusive: false,
- parseDOM: [{
- tag: "a[href]", getAttrs(dom: any) {
- return { href: dom.getAttribute("href"), title: dom.getAttribute("title") }
- }
- }],
- toDOM(node: any) { return ["a", node.attrs, 0] }
- },
-
- // :: MarkSpec An emphasis mark. Rendered as an `<em>` element.
- // Has parse rules that also match `<i>` and `font-style: italic`.
- em: {
- parseDOM: [{ tag: "i" }, { tag: "em" }, { style: "font-style=italic" }],
- toDOM() { return emDOM }
- },
-
- // :: MarkSpec A strong mark. Rendered as `<strong>`, parse rules
- // also match `<b>` and `font-weight: bold`.
- strong: {
- parseDOM: [{ tag: "strong" },
- { tag: "b" },
- { style: "font-weight" }],
- toDOM() { return strongDOM }
- },
-
- underline: {
- parseDOM: [
- { tag: 'u' },
- { style: 'text-decoration=underline' }
- ],
- toDOM: () => ['span', {
- style: 'text-decoration:underline'
- }]
- },
-
- strikethrough: {
- parseDOM: [
- { tag: 'strike' },
- { style: 'text-decoration=line-through' },
- { style: 'text-decoration-line=line-through' }
- ],
- toDOM: () => ['span', {
- style: 'text-decoration-line:line-through'
- }]
- },
-
- subscript: {
- excludes: 'superscript',
- parseDOM: [
- { tag: 'sub' },
- { style: 'vertical-align=sub' }
- ],
- toDOM: () => ['sub']
- },
-
- superscript: {
- excludes: 'subscript',
- parseDOM: [
- { tag: 'sup' },
- { style: 'vertical-align=super' }
- ],
- toDOM: () => ['sup']
- },
-
-
- // :: MarkSpec Code font mark. Represented as a `<code>` element.
- code: {
- parseDOM: [{ tag: "code" }],
- toDOM() { return codeDOM }
- },
-
-
- timesNewRoman: {
- parseDOM: [{ style: 'font-family: "Times New Roman", Times, serif;' }],
- toDOM: () => ['span', {
- style: 'font-family: "Times New Roman", Times, serif;'
- }]
- },
+ // :: MarkSpec A link. Has `href` and `title` attributes. `title`
+ // defaults to the empty string. Rendered and parsed as an `<a>`
+ // element.
+ link: {
+ attrs: {
+ href: {},
+ title: { default: null }
+ },
+ inclusive: false,
+ parseDOM: [{
+ tag: "a[href]", getAttrs(dom: any) {
+ return { href: dom.getAttribute("href"), title: dom.getAttribute("title") }
+ }
+ }],
+ toDOM(node: any) { return ["a", node.attrs, 0] }
+ },
+
+ // :: MarkSpec An emphasis mark. Rendered as an `<em>` element.
+ // Has parse rules that also match `<i>` and `font-style: italic`.
+ em: {
+ parseDOM: [{ tag: "i" }, { tag: "em" }, { style: "font-style=italic" }],
+ toDOM() { return emDOM }
+ },
+
+ // :: MarkSpec A strong mark. Rendered as `<strong>`, parse rules
+ // also match `<b>` and `font-weight: bold`.
+ strong: {
+ parseDOM: [{ tag: "strong" },
+ { tag: "b" },
+ { style: "font-weight" }],
+ toDOM() { return strongDOM }
+ },
+
+ underline: {
+ parseDOM: [
+ { tag: 'u' },
+ { style: 'text-decoration=underline' }
+ ],
+ toDOM: () => ['span', {
+ style: 'text-decoration:underline'
+ }]
+ },
+
+ strikethrough: {
+ parseDOM: [
+ { tag: 'strike' },
+ { style: 'text-decoration=line-through' },
+ { style: 'text-decoration-line=line-through' }
+ ],
+ toDOM: () => ['span', {
+ style: 'text-decoration-line:line-through'
+ }]
+ },
+
+ subscript: {
+ excludes: 'superscript',
+ parseDOM: [
+ { tag: 'sub' },
+ { style: 'vertical-align=sub' }
+ ],
+ toDOM: () => ['sub']
+ },
+
+ superscript: {
+ excludes: 'subscript',
+ parseDOM: [
+ { tag: 'sup' },
+ { style: 'vertical-align=super' }
+ ],
+ toDOM: () => ['sup']
+ },
+
+
+ // :: MarkSpec Code font mark. Represented as a `<code>` element.
+ code: {
+ parseDOM: [{ tag: "code" }],
+ toDOM() { return codeDOM }
+ },
+
+
+ /* FONTS */
+ timesNewRoman: {
+ parseDOM: [{ style: 'font-family: "Times New Roman", Times, serif;' }],
+ toDOM: () => ['span', {
+ style: 'font-family: "Times New Roman", Times, serif;'
+ }]
+ },
+
+ arial: {
+ parseDOM: [{ style: 'font-family: Arial, Helvetica, sans-serif;' }],
+ toDOM: () => ['span', {
+ style: 'font-family: Arial, Helvetica, sans-serif;'
+ }]
+ },
+
+ georgia: {
+ parseDOM: [{ style: 'font-family: Georgia, serif;' }],
+ toDOM: () => ['span', {
+ style: 'font-family: Georgia, serif;'
+ }]
+ },
+
+ comicSans: {
+ parseDOM: [{ style: 'font-family: "Comic Sans MS", cursive, sans-serif;' }],
+ toDOM: () => ['span', {
+ style: 'font-family: "Comic Sans MS", cursive, sans-serif;'
+ }]
+ },
+
+ tahoma: {
+ parseDOM: [{ style: 'font-family: Tahoma, Geneva, sans-serif;' }],
+ toDOM: () => ['span', {
+ style: 'font-family: Tahoma, Geneva, sans-serif;'
+ }]
+ },
+
+ impact: {
+ parseDOM: [{ style: 'font-family: Impact, Charcoal, sans-serif;' }],
+ toDOM: () => ['span', {
+ style: 'font-family: Impact, Charcoal, sans-serif;'
+ }]
+ },
+
+ /** FONT SIZES */
+
+ p10: {
+ parseDOM: [{ style: 'font-size: 10px;' }],
+ toDOM: () => ['span', {
+ style: 'font-size: 10px;'
+ }]
+ },
+
+ p12: {
+ parseDOM: [{ style: 'font-size: 12px;' }],
+ toDOM: () => ['span', {
+ style: 'font-size: 12px;'
+ }]
+ },
+
+ p16: {
+ parseDOM: [{ style: 'font-size: 16px;' }],
+ toDOM: () => ['span', {
+ style: 'font-size: 16px;'
+ }]
+ },
+
+ p24: {
+ parseDOM: [{ style: 'font-size: 24px;' }],
+ toDOM: () => ['span', {
+ style: 'font-size: 24px;'
+ }]
+ },
+
+ p32: {
+ parseDOM: [{ style: 'font-size: 32px;' }],
+ toDOM: () => ['span', {
+ style: 'font-size: 32px;'
+ }]
+ },
+
+ p48: {
+ parseDOM: [{ style: 'font-size: 48px;' }],
+ toDOM: () => ['span', {
+ style: 'font-size: 48px;'
+ }]
+ },
+
+ p72: {
+ parseDOM: [{ style: 'font-size: 72px;' }],
+ toDOM: () => ['span', {
+ style: 'font-size: 72px;'
+ }]
+ },
}
// :: Schema
diff --git a/src/client/util/TooltipTextMenu.scss b/src/client/util/TooltipTextMenu.scss
index ea580d104..b23074239 100644
--- a/src/client/util/TooltipTextMenu.scss
+++ b/src/client/util/TooltipTextMenu.scss
@@ -1,5 +1,241 @@
@import "../views/global_variables";
+.ProseMirror-textblock-dropdown {
+ min-width: 3em;
+ }
+
+ .ProseMirror-menu {
+ margin: 0 -4px;
+ line-height: 1;
+ }
+
+ .ProseMirror-tooltip .ProseMirror-menu {
+ width: -webkit-fit-content;
+ width: fit-content;
+ white-space: pre;
+ }
+
+ .ProseMirror-menuitem {
+ margin-right: 3px;
+ display: inline-block;
+ }
+
+ .ProseMirror-menuseparator {
+ // border-right: 1px solid #ddd;
+ margin-right: 3px;
+ }
+
+ .ProseMirror-menu-dropdown, .ProseMirror-menu-dropdown-menu {
+ font-size: 90%;
+ white-space: nowrap;
+ }
+
+ .ProseMirror-menu-dropdown {
+ vertical-align: 1px;
+ cursor: pointer;
+ position: relative;
+ padding-right: 15px;
+ }
+
+ .ProseMirror-menu-dropdown-wrap {
+ padding: 1px 0 1px 4px;
+ display: inline-block;
+ position: relative;
+ }
+
+ .ProseMirror-menu-dropdown:after {
+ content: "";
+ border-left: 4px solid transparent;
+ border-right: 4px solid transparent;
+ border-top: 4px solid currentColor;
+ opacity: .6;
+ position: absolute;
+ right: 4px;
+ top: calc(50% - 2px);
+ }
+
+ .ProseMirror-menu-dropdown-menu, .ProseMirror-menu-submenu {
+ position: absolute;
+ background: $dark-color;
+ color:white;
+ border: 1px solid #aaa;
+ padding: 2px;
+ }
+
+ .ProseMirror-menu-dropdown-menu {
+ z-index: 15;
+ min-width: 6em;
+ }
+
+ .ProseMirror-menu-dropdown-item {
+ cursor: pointer;
+ padding: 2px 8px 2px 4px;
+ width: auto;
+ }
+
+ .ProseMirror-menu-dropdown-item:hover {
+ background: #2e2b2b;
+ }
+
+ .ProseMirror-menu-submenu-wrap {
+ position: relative;
+ margin-right: -4px;
+ }
+
+ .ProseMirror-menu-submenu-label:after {
+ content: "";
+ border-top: 4px solid transparent;
+ border-bottom: 4px solid transparent;
+ border-left: 4px solid currentColor;
+ opacity: .6;
+ position: absolute;
+ right: 4px;
+ top: calc(50% - 4px);
+ }
+
+ .ProseMirror-menu-submenu {
+ display: none;
+ min-width: 4em;
+ left: 100%;
+ top: -3px;
+ }
+
+ .ProseMirror-menu-active {
+ background: #eee;
+ border-radius: 4px;
+ }
+
+ .ProseMirror-menu-active {
+ background: #eee;
+ border-radius: 4px;
+ }
+
+ .ProseMirror-menu-disabled {
+ opacity: .3;
+ }
+
+ .ProseMirror-menu-submenu-wrap:hover .ProseMirror-menu-submenu, .ProseMirror-menu-submenu-wrap-active .ProseMirror-menu-submenu {
+ display: block;
+ }
+
+ .ProseMirror-menubar {
+ border-top-left-radius: inherit;
+ border-top-right-radius: inherit;
+ position: relative;
+ min-height: 1em;
+ color: white;
+ padding: 1px 6px;
+ top: 0; left: 0; right: 0;
+ border-bottom: 1px solid silver;
+ background:$dark-color;
+ z-index: 10;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ overflow: visible;
+ }
+
+ .ProseMirror-icon {
+ display: inline-block;
+ line-height: .8;
+ vertical-align: -2px; /* Compensate for padding */
+ padding: 2px 8px;
+ cursor: pointer;
+ }
+
+ .ProseMirror-menu-disabled.ProseMirror-icon {
+ cursor: default;
+ }
+
+ .ProseMirror-icon svg {
+ fill: currentColor;
+ height: 1em;
+ }
+
+ .ProseMirror-icon span {
+ vertical-align: text-top;
+ }
+.ProseMirror-example-setup-style hr {
+ padding: 2px 10px;
+ border: none;
+ margin: 1em 0;
+ }
+
+ .ProseMirror-example-setup-style hr:after {
+ content: "";
+ display: block;
+ height: 1px;
+ background-color: silver;
+ line-height: 2px;
+ }
+
+ .ProseMirror ul, .ProseMirror ol {
+ padding-left: 30px;
+ }
+
+ .ProseMirror blockquote {
+ padding-left: 1em;
+ border-left: 3px solid #eee;
+ margin-left: 0; margin-right: 0;
+ }
+
+ .ProseMirror-example-setup-style img {
+ cursor: default;
+ }
+
+ .ProseMirror-prompt {
+ background: white;
+ padding: 5px 10px 5px 15px;
+ border: 1px solid silver;
+ position: fixed;
+ border-radius: 3px;
+ z-index: 11;
+ box-shadow: -.5px 2px 5px rgba(0, 0, 0, .2);
+ }
+
+ .ProseMirror-prompt h5 {
+ margin: 0;
+ font-weight: normal;
+ font-size: 100%;
+ color: #444;
+ }
+
+ .ProseMirror-prompt input[type="text"],
+ .ProseMirror-prompt textarea {
+ background: #eee;
+ border: none;
+ outline: none;
+ }
+
+ .ProseMirror-prompt input[type="text"] {
+ padding: 0 4px;
+ }
+
+ .ProseMirror-prompt-close {
+ position: absolute;
+ left: 2px; top: 1px;
+ color: #666;
+ border: none; background: transparent; padding: 0;
+ }
+
+ .ProseMirror-prompt-close:after {
+ content: "✕";
+ font-size: 12px;
+ }
+
+ .ProseMirror-invalid {
+ background: #ffc;
+ border: 1px solid #cc7;
+ border-radius: 4px;
+ padding: 5px 10px;
+ position: absolute;
+ min-width: 10em;
+ }
+
+ .ProseMirror-prompt-buttons {
+ margin-top: 5px;
+ display: none;
+ }
+
.tooltipMenu {
position: absolute;
z-index: 20;
@@ -39,7 +275,7 @@
display: inline-block;
border-right: 1px solid rgba(0, 0, 0, 0.2);
//color: rgb(19, 18, 18);
- color: $light-color;
+ color: white;
line-height: 1;
padding: 0px 2px;
margin: 1px;
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index 82e9d1bac..777abe030 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -1,12 +1,12 @@
import { action, IReactionDisposer, reaction } from "mobx";
-import { Dropdown, DropdownSubmenu, MenuItem } from "prosemirror-menu";
+import { Dropdown, DropdownSubmenu, MenuItem, MenuItemSpec, renderGrouped, icons, } from "prosemirror-menu"; //no import css
import { baseKeymap, lift } from "prosemirror-commands";
import { history, redo, undo } from "prosemirror-history";
import { keymap } from "prosemirror-keymap";
-import { EditorState, Transaction, NodeSelection } from "prosemirror-state";
+import { EditorState, Transaction, NodeSelection, TextSelection } from "prosemirror-state";
import { EditorView } from "prosemirror-view";
import { schema } from "./RichTextSchema";
-import { Schema, NodeType } from "prosemirror-model";
+import { Schema, NodeType, MarkType } from "prosemirror-model";
import React = require("react");
import "./TooltipTextMenu.scss";
const { toggleMark, setBlockType, wrapIn } = require("prosemirror-commands");
@@ -24,8 +24,12 @@ export class TooltipTextMenu {
private tooltip: HTMLElement;
private num_icons = 0;
+ private view: EditorView;
+ private fontStyles: MarkType[];
+ private fontSizes: MarkType[];
constructor(view: EditorView) {
+ this.view = view;
this.tooltip = document.createElement("div");
this.tooltip.className = "tooltipMenu";
@@ -34,7 +38,6 @@ export class TooltipTextMenu {
//add additional icons
library.add(faListUl);
-
//add the buttons to the tooltip
let items = [
{ command: toggleMark(schema.marks.strong), dom: this.icon("B", "strong") },
@@ -44,44 +47,142 @@ export class TooltipTextMenu {
{ command: toggleMark(schema.marks.superscript), dom: this.icon("s", "superscript") },
{ command: toggleMark(schema.marks.subscript), dom: this.icon("s", "subscript") },
{ command: wrapInList(schema.nodes.bullet_list), dom: this.icon(":", "bullets") },
- { command: toggleMark(schema.marks.timesNewRoman), dom: this.icon("x", "TNR") },
{ command: lift, dom: this.icon("<", "lift") },
]
//add menu items
items.forEach(({ dom, command }) => {
this.tooltip.appendChild(dom);
- });
- //add dropdowns
-
- //pointer down handler to activate button effects
- this.tooltip.addEventListener("pointerdown", e => {
- e.preventDefault();
- view.focus();
- //update view of icons
- this.num_icons = 0;
- items.forEach(({ command, dom }) => {
- if (e.srcElement && dom.contains(e.srcElement as Node)) {
- //let active = command(view.state, view.dispatch, view);
- let active = command(view.state, view.dispatch, view);
- //uncomment this if we want the bullet button to disappear if current selection is bulleted
- //dom.style.display = active ? "" : "none";
- }
+ //pointer down handler to activate button effects
+ dom.addEventListener("pointerdown", e => {
+ e.preventDefault();
+ view.focus();
+ command(view.state, view.dispatch, view);
})
- })
+
+ });
+
+ //dropdowns
+ //list of font btns to add
+ this.fontStyles = [
+ schema.marks.timesNewRoman,
+ schema.marks.arial,
+ schema.marks.georgia,
+ schema.marks.comicSans,
+ schema.marks.tahoma,
+ schema.marks.impact,
+ ]
+ this.fontSizes = [
+ schema.marks.p10,
+ schema.marks.p12,
+ schema.marks.p16,
+ schema.marks.p24,
+ schema.marks.p32,
+ schema.marks.p48,
+ schema.marks.p72,
+ ]
+ this.addFontDropdowns();
this.update(view, undefined);
}
+ //adds font size and font style dropdowns
+ addFontDropdowns() {
+ //filtering function - might be unecessary
+ let cut = (arr: MenuItem[]) => arr.filter(x => x);
+ let fontBtns = [
+ this.dropdownBtn("Times New Roman", "font-family: Times New Roman, Times, serif; width: 120px;", schema.marks.timesNewRoman, this.view, this.changeToMarkInGroup, this.fontStyles),
+ this.dropdownBtn("Arial", "font-family: Arial, Helvetica, sans-serif; width: 120px;", schema.marks.arial, this.view, this.changeToMarkInGroup, this.fontStyles),
+ this.dropdownBtn("Georgia", "font-family: Georgia, serif; width: 120px; width: 120px;", schema.marks.georgia, this.view, this.changeToMarkInGroup, this.fontStyles),
+ this.dropdownBtn("ComicSans", "font-family: Comic Sans MS, cursive, sans-serif; width: 120px;", schema.marks.comicSans, this.view, this.changeToMarkInGroup, this.fontStyles),
+ this.dropdownBtn("Tahoma", "font-family: Tahoma, Geneva, sans-serif; width: 120px;", schema.marks.tahoma, this.view, this.changeToMarkInGroup, this.fontStyles),
+ this.dropdownBtn("Impact", "font-family: Impact, Charcoal, sans-serif; width: 120px;", schema.marks.impact, this.view, this.changeToMarkInGroup, this.fontStyles),
+ ]
+
+ let fontSizeBtns = [
+ this.dropdownBtn("10", "width: 50px;", schema.marks.p10, this.view, this.changeToMarkInGroup, this.fontSizes),
+ this.dropdownBtn("12", "width: 50px;", schema.marks.p12, this.view, this.changeToMarkInGroup, this.fontSizes),
+ this.dropdownBtn("16", "width: 50px;", schema.marks.p16, this.view, this.changeToMarkInGroup, this.fontSizes),
+ this.dropdownBtn("24", "width: 50px;", schema.marks.p24, this.view, this.changeToMarkInGroup, this.fontSizes),
+ this.dropdownBtn("32", "width: 50px;", schema.marks.p32, this.view, this.changeToMarkInGroup, this.fontSizes),
+ this.dropdownBtn("48", "width: 50px;", schema.marks.p48, this.view, this.changeToMarkInGroup, this.fontSizes),
+ this.dropdownBtn("72", "width: 50px;", schema.marks.p72, this.view, this.changeToMarkInGroup, this.fontSizes),
+ ]
+
+ //dropdown to hold font btns
+ let dd_fontStyle = new Dropdown(cut(fontBtns), { label: "Font Style", css: "color:white;" }) as MenuItem;
+ let dd_fontSize = new Dropdown(cut(fontSizeBtns), { label: "Font Size", css: "color:white;" }) as MenuItem;
+ this.tooltip.appendChild(dd_fontStyle.render(this.view).dom);
+ this.tooltip.appendChild(dd_fontSize.render(this.view).dom);
+ }
+
+ //for a specific grouping of marks (passed in), remove all and apply the passed-in one to the selected text
+ changeToMarkInGroup(markType: MarkType, view: EditorView, fontMarks: MarkType[]) {
+ let { empty, $cursor, ranges } = view.state.selection as TextSelection;
+ let state = view.state;
+ let dispatch = view.dispatch;
+
+ //remove all other active font marks
+ fontMarks.forEach((type) => {
+ if (dispatch) {
+ if ($cursor) {
+ if (type.isInSet(state.storedMarks || $cursor.marks())) {
+ dispatch(state.tr.removeStoredMark(type));
+ }
+ } else {
+ let has = false, tr = state.tr
+ for (let i = 0; !has && i < ranges.length; i++) {
+ let { $from, $to } = ranges[i]
+ has = state.doc.rangeHasMark($from.pos, $to.pos, type)
+ }
+ for (let i = 0; i < ranges.length; i++) {
+ let { $from, $to } = ranges[i]
+ if (has) {
+ toggleMark(type)(view.state, view.dispatch, view);
+ }
+ }
+ }
+ }
+ }); //actually apply font
+ return toggleMark(markType)(view.state, view.dispatch, view);
+ }
+
+ //makes a button for the drop down
+ //css is the style you want applied to the button
+ dropdownBtn(label: string, css: string, markType: MarkType, view: EditorView, changeToMarkInGroup: (markType: MarkType<any>, view: EditorView, groupMarks: MarkType[]) => any, groupMarks: MarkType[]) {
+ return new MenuItem({
+ title: "",
+ label: label,
+ execEvent: "",
+ class: "menuicon",
+ css: css,
+ enable(state) { return true; },
+ run() {
+ changeToMarkInGroup(markType, view, groupMarks);
+ }
+ });
+ }
// Helper function to create menu icons
icon(text: string, name: string) {
let span = document.createElement("span");
span.className = "menuicon " + name;
span.title = name;
span.textContent = text;
+ span.style.color = "white";
return span;
}
+ //method for checking whether node can be inserted
+ canInsert(state: EditorState, nodeType: NodeType<Schema<string, string>>) {
+ let $from = state.selection.$from
+ for (let d = $from.depth; d >= 0; d--) {
+ let index = $from.index(d)
+ if ($from.node(d).canReplaceWith(index, index, nodeType)) return true
+ }
+ return false
+ }
+
+
//adapted this method - use it to check if block has a tag (ie bulleting)
blockActive(type: NodeType<Schema<string, string>>, state: EditorState) {
let attrs = {};
@@ -100,30 +201,6 @@ export class TooltipTextMenu {
}
}
- //this doesn't currently work but could be used to use icons for buttons
- unorderedListIcon(): HTMLSpanElement {
- let span = document.createElement("span");
- //let icon = document.createElement("FontAwesomeIcon");
- //icon.className = "menuicon";
- //icon.style.color = "white";
- //span.appendChild(<i style={{ color: "white" }} icon="list-ul" size="lg" />);
- let i = document.createElement("i");
- i.className = "fa falist-ul";
- span.appendChild(i);
- //span.appendChild(icon);
- //return liftItem.spec.icon.sty
-
- //let sym = document.createElementNS(SVG, "symbol")
- // sym.id = name
- //sym.style.color = "white";
- //width then height
- //sym.setAttribute("viewBox", "0 0 " + 1024 + " " + 1024);
- //let path = sym.appendChild(document.createElementNS(SVG, "path"));
- //path.setAttribute("d", "M219 310v329q0 7-5 12t-12 5q-8 0-13-5l-164-164q-5-5-5-13t5-13l164-164q5-5 13-5 7 0 12 5t5 12zM1024 749v109q0 7-5 12t-12 5h-987q-7 0-12-5t-5-12v-109q0-7 5-12t12-5h987q7 0 12 5t5 12zM1024 530v109q0 7-5 12t-12 5h-621q-7 0-12-5t-5-12v-109q0-7 5-12t12-5h621q7 0 12 5t5 12zM1024 310v109q0 7-5 12t-12 5h-621q-7 0-12-5t-5-12v-109q0-7 5-12t12-5h621q7 0 12 5t5 12zM1024 91v109q0 7-5 12t-12 5h-987q-7 0-12-5t-5-12v-109q0-7 5-12t12-5h987q7 0 12 5t5 12z");
- //span.appendChild(sym);
- return span;
- }
-
// Create an icon for a heading at the given level
heading(level: number) {
return {
@@ -156,10 +233,8 @@ export class TooltipTextMenu {
let left = Math.max((start.left + end.left) / 2, start.left + 3)
this.tooltip.style.left = (left - box.left) + "px"
//let width = Math.abs(start.left - end.left) / 2;
- let width = 8 * 16 + 15;
+ let width = 220;
let mid = Math.min(start.left, end.left) + width;
-
- //THIS WIDTH IS 15 * NUMBER OF ICONS + 15
this.tooltip.style.width = width + "px";
this.tooltip.style.bottom = (box.bottom - start.top) + "px";
}
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index e59179874..fdb1b97be 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -74,7 +74,12 @@ export class FormattedTextBox extends React.Component<FieldViewProps> {
history(),
keymap({ "Mod-z": undo, "Mod-y": redo }),
keymap(baseKeymap),
- this.tooltipMenuPlugin()
+ this.tooltipMenuPlugin(),
+ new Plugin({
+ props: {
+ attributes: { class: "ProseMirror-example-setup-style" }
+ }
+ })
]
};