mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-23 23:19:40 +01:00
feat: use tinymce plugins from the npm package
This commit is contained in:
@@ -11,6 +11,7 @@
|
|||||||
"@mdi/react": "^1.4.0",
|
"@mdi/react": "^1.4.0",
|
||||||
"@notesnook/desktop": "./desktop/",
|
"@notesnook/desktop": "./desktop/",
|
||||||
"@rebass/forms": "^4.0.6",
|
"@rebass/forms": "^4.0.6",
|
||||||
|
"@streetwritersco/tinymce-plugins": "^1.0.0",
|
||||||
"@tinymce/tinymce-react": "^3.12.6",
|
"@tinymce/tinymce-react": "^3.12.6",
|
||||||
"clipboard": "^2.0.6",
|
"clipboard": "^2.0.6",
|
||||||
"cogo-toast": "^4.2.3",
|
"cogo-toast": "^4.2.3",
|
||||||
|
|||||||
@@ -84,77 +84,3 @@ tox-tbtn tox-tbtn--select {
|
|||||||
.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before {
|
.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before {
|
||||||
margin-top: 1em !important;
|
margin-top: 1em !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mce-content-body h2::before,
|
|
||||||
h3::before,
|
|
||||||
h4::before,
|
|
||||||
h5::before,
|
|
||||||
h6::before {
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: normal;
|
|
||||||
color: var(--fontTertiary);
|
|
||||||
letter-spacing: 1.2px;
|
|
||||||
padding: 1px 3px 1px 3px;
|
|
||||||
margin-left: -31px;
|
|
||||||
margin-right: 7px;
|
|
||||||
cursor: row-resize;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mce-content-body h2::before {
|
|
||||||
content: "H2";
|
|
||||||
}
|
|
||||||
|
|
||||||
.mce-content-body h3::before {
|
|
||||||
content: "H3";
|
|
||||||
}
|
|
||||||
|
|
||||||
.mce-content-body h4::before {
|
|
||||||
content: "H4";
|
|
||||||
}
|
|
||||||
|
|
||||||
.mce-content-body h5::before {
|
|
||||||
content: "H5";
|
|
||||||
}
|
|
||||||
|
|
||||||
.mce-content-body .c::before {
|
|
||||||
color: var(--static);
|
|
||||||
background-color: var(--primary);
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.h {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tox-menu.tox-collection.tox-collection--list.tox-selected-menu {
|
|
||||||
max-height: 190px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mce-content-body pre {
|
|
||||||
overflow: auto;
|
|
||||||
max-height: 600px;
|
|
||||||
line-height: 1.5 !important;
|
|
||||||
padding: 15px;
|
|
||||||
border: 1px solid var(--border);
|
|
||||||
border-radius: 5px;
|
|
||||||
border: 1px solid var(--border);
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mce-content-body code[data-mce-selected="inline-boundary"] {
|
|
||||||
background-color: rgb(27 31 35 / 5%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.mce-content-body code {
|
|
||||||
background-color: rgb(27 31 35 / 5%);
|
|
||||||
border: 1px solid var(--border);
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
code,
|
|
||||||
pre,
|
|
||||||
pre * {
|
|
||||||
font-family: ui-monospace, SFMono-Regular, SF Mono, Consolas, Liberation Mono,
|
|
||||||
Menlo, monospace !important;
|
|
||||||
font-size: 14px !important;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
import "./plugin";
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
import tinymce from "tinymce/tinymce";
|
|
||||||
|
|
||||||
(function () {
|
|
||||||
tinymce.PluginManager.add("checklist", function (editor, url) {
|
|
||||||
/**
|
|
||||||
* Plugin behaviour for when the Toolbar or Menu item is selected
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
function _onAction() {
|
|
||||||
var content = `<ul class="tox-checklist"><li></li></ul>`;
|
|
||||||
editor.undoManager.transact(function () {
|
|
||||||
editor.insertContent(content);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
editor.addCommand("InsertCheckList", function (ui, value) {
|
|
||||||
_onAction();
|
|
||||||
});
|
|
||||||
|
|
||||||
editor.ui.registry.addButton("checklist", {
|
|
||||||
icon: "checklist",
|
|
||||||
tooltip: "Insert check list",
|
|
||||||
onAction: _onAction,
|
|
||||||
});
|
|
||||||
|
|
||||||
editor.on(
|
|
||||||
"mousedown",
|
|
||||||
function (event) {
|
|
||||||
var node = event.target;
|
|
||||||
var parent = node.parentElement;
|
|
||||||
if (event.offsetX > 0 || parent.className !== "tox-checklist") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//editor.selection.setRng(range_selection);
|
|
||||||
|
|
||||||
editor.undoManager.transact(function () {
|
|
||||||
event.preventDefault();
|
|
||||||
if (parent.className === "tox-checklist") {
|
|
||||||
if (
|
|
||||||
node.nodeName === "LI" &&
|
|
||||||
node.className === "tox-checklist--checked"
|
|
||||||
) {
|
|
||||||
node.className = "";
|
|
||||||
} else if (node.nodeName === "LI" && node.className === "") {
|
|
||||||
node.className = "tox-checklist--checked";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//editor.fire("input",)
|
|
||||||
//editor.selection.setRng(range_selection);
|
|
||||||
},
|
|
||||||
{ capture: true, passive: false }
|
|
||||||
);
|
|
||||||
|
|
||||||
editor.on(
|
|
||||||
"touchstart",
|
|
||||||
function (event) {
|
|
||||||
var node = event.target;
|
|
||||||
var parent = node.parentElement;
|
|
||||||
if (
|
|
||||||
event.targetTouches.length > 0 ||
|
|
||||||
event.targetTouches[0].clientX > 45 ||
|
|
||||||
parent.className !== "tox-checklist"
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//editor.selection.setRng(range_selection);
|
|
||||||
editor.undoManager.transact(function () {
|
|
||||||
event.preventDefault();
|
|
||||||
if (parent.className === "tox-checklist") {
|
|
||||||
node.scrollIntoView(false);
|
|
||||||
if (
|
|
||||||
node.nodeName === "LI" &&
|
|
||||||
node.className === "tox-checklist--checked"
|
|
||||||
) {
|
|
||||||
node.className = "";
|
|
||||||
} else if (node.nodeName === "LI" && node.className === "") {
|
|
||||||
node.className = "tox-checklist--checked";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//editor.fire("input",)
|
|
||||||
//editor.selection.setRng(range_selection);
|
|
||||||
},
|
|
||||||
{ capture: true, passive: false }
|
|
||||||
);
|
|
||||||
|
|
||||||
editor.on("NodeChange", function (event) {
|
|
||||||
var node = event.target;
|
|
||||||
var parent = node?.parentElement;
|
|
||||||
if (!parent) return;
|
|
||||||
if (parent.className === "tox-checklist") {
|
|
||||||
if (
|
|
||||||
node.nodeName === "LI" &&
|
|
||||||
node.className === "tox-checklist--checked"
|
|
||||||
) {
|
|
||||||
node.className = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
editor.on("NewBlock", function (event) {
|
|
||||||
if (
|
|
||||||
event.newBlock.nodeName === "LI" &&
|
|
||||||
event.newBlock.className === "tox-checklist--checked"
|
|
||||||
) {
|
|
||||||
event.newBlock.className = "";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
import "./plugin";
|
|
||||||
@@ -1,379 +0,0 @@
|
|||||||
import tinymce from "tinymce/tinymce";
|
|
||||||
import hljs from "highlight.js/lib/common";
|
|
||||||
import { getCharacterRange, moveCaretTo, persistSelection } from "../utils";
|
|
||||||
|
|
||||||
const TAB = " ";
|
|
||||||
const LANGUAGE_SELECT_LABEL_SELECTOR =
|
|
||||||
".tox-pop__dialog span.tox-tbtn__select-label";
|
|
||||||
const state = {
|
|
||||||
activeBlock: null,
|
|
||||||
languages: [{ type: "choiceitem", text: "Auto detect", value: "autodetect" }],
|
|
||||||
};
|
|
||||||
languagesToItems();
|
|
||||||
|
|
||||||
(function () {
|
|
||||||
var global = tinymce.util.Tools.resolve("tinymce.PluginManager");
|
|
||||||
|
|
||||||
var replaceContent = function (editor, content) {
|
|
||||||
editor.undoManager.transact(function () {
|
|
||||||
editor.execCommand("mceInsertContent", false, content("<br>"));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
function createPreBlock(content) {
|
|
||||||
const pre = document.createElement("pre");
|
|
||||||
pre.spellcheck = false;
|
|
||||||
pre.classList.add("hljs");
|
|
||||||
pre.innerHTML = content;
|
|
||||||
return pre;
|
|
||||||
}
|
|
||||||
|
|
||||||
function insertPreBlock(editor, content) {
|
|
||||||
editor.undoManager.transact(function () {
|
|
||||||
const pre = createPreBlock(content);
|
|
||||||
editor.dom.setAttrib(pre, "data-mce-id", "__mcenew");
|
|
||||||
editor.focus();
|
|
||||||
editor.insertContent(`${pre.outerHTML}<p><br></p>`);
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
const insertedPre = editor.dom.select('*[data-mce-id="__mcenew"]')[0];
|
|
||||||
editor.dom.setAttrib(insertedPre, "data-mce-id", null);
|
|
||||||
editor.selection.select(insertedPre, true);
|
|
||||||
editor.selection.collapse(true);
|
|
||||||
editor.nodeChanged({ selectionChange: true });
|
|
||||||
}, 0);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function exitPreBlock(editor, block) {
|
|
||||||
editor.undoManager.transact(function () {
|
|
||||||
const p = document.createElement("p");
|
|
||||||
p.innerHTML = "<br>";
|
|
||||||
editor.focus();
|
|
||||||
editor.dom.insertAfter(p, block);
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
editor.selection.select(p, true);
|
|
||||||
editor.selection.collapse(true);
|
|
||||||
editor.nodeChanged({ selectionChange: true });
|
|
||||||
}, 0);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var addCodeBlock = function (editor, api, type) {
|
|
||||||
if (api && api.isActive && api.isActive()) {
|
|
||||||
let node = editor.selection.getNode();
|
|
||||||
const innerText = node.textContent;
|
|
||||||
if (innerText.length <= 0) {
|
|
||||||
replaceContent(
|
|
||||||
editor,
|
|
||||||
(html) => `<p>${html.replace(/\n/gm, "<br>")}</p>`
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
exitPreBlock(editor, node);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
var content = editor.selection.getContent({ format: "text" }); //.replace(/^\n/gm, "");
|
|
||||||
if (type === "shortcut") content = "<br>";
|
|
||||||
insertPreBlock(editor, content);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var addInlineCode = function (editor) {
|
|
||||||
var content = editor.selection.getContent({ format: "text" });
|
|
||||||
content = content.replace(/^\n/gm, "") || " ";
|
|
||||||
|
|
||||||
editor.undoManager.transact(function () {
|
|
||||||
editor.execCommand(
|
|
||||||
"mceInsertContent",
|
|
||||||
false,
|
|
||||||
`<code spellcheck="false">${content}</code> `
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
editor.nodeChanged({ selectionChange: true });
|
|
||||||
};
|
|
||||||
|
|
||||||
var register = function (editor) {
|
|
||||||
editor.addCommand("mceInsertCodeBlock", function (api, args) {
|
|
||||||
addCodeBlock(editor, api, args);
|
|
||||||
});
|
|
||||||
|
|
||||||
editor.addCommand("mceCode", function (api, value) {
|
|
||||||
addInlineCode(editor);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
var register$1 = function (editor) {
|
|
||||||
editor.ui.registry.addToggleButton("codeblock", {
|
|
||||||
icon: "code-sample",
|
|
||||||
tooltip: "Codeblock",
|
|
||||||
onAction: function (api) {
|
|
||||||
return addCodeBlock(editor, api);
|
|
||||||
},
|
|
||||||
onSetup: getNodeChangeHandler(editor),
|
|
||||||
});
|
|
||||||
editor.ui.registry.addToggleButton("inlinecode", {
|
|
||||||
icon: "sourcecode",
|
|
||||||
tooltip: "Inline code",
|
|
||||||
onAction: function (api) {
|
|
||||||
return addInlineCode(editor);
|
|
||||||
},
|
|
||||||
onSetup: function (api) {
|
|
||||||
var nodeChangeHandler = function (e) {
|
|
||||||
if (e.element.tagName === "CODE") {
|
|
||||||
if (!e.element.innerHTML.trim().length) {
|
|
||||||
e.element.remove();
|
|
||||||
}
|
|
||||||
api.setActive(e.element.tagName === "PRE");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
editor.on("NodeChange", nodeChangeHandler);
|
|
||||||
return function () {
|
|
||||||
return editor.off("NodeChange", nodeChangeHandler);
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
var getNodeChangeHandler = function (editor) {
|
|
||||||
return function (api) {
|
|
||||||
var nodeChangeHandler = function (e) {
|
|
||||||
if (e.element.tagName === "CODE") {
|
|
||||||
if (!e.element.innerHTML.trim().length) {
|
|
||||||
e.element.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
api.setActive(e.element.tagName === "PRE");
|
|
||||||
};
|
|
||||||
|
|
||||||
var setContentHandler = function (e) {
|
|
||||||
if (e.content === "<pre></pre>") {
|
|
||||||
e.preventDefault();
|
|
||||||
editor.creatingCodeBlock = true;
|
|
||||||
addCodeBlock(editor, undefined, "shortcut");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var beforeExecCommandHandler = function (e) {
|
|
||||||
const node = editor.selection.getNode();
|
|
||||||
if (
|
|
||||||
node?.tagName === "PRE" &&
|
|
||||||
e.command === "mceInsertContent" &&
|
|
||||||
e.value?.paste
|
|
||||||
) {
|
|
||||||
e.value.content = e.value.content
|
|
||||||
.replace(/<p>/gm, "")
|
|
||||||
.replace(/<\/p>|<br \/>/gm, "\n");
|
|
||||||
}
|
|
||||||
if (editor.creatingCodeBlock && e.command === "mceInsertNewLine") {
|
|
||||||
e.preventDefault();
|
|
||||||
editor.creatingCodeBlock = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function handleKeyDown(e) {
|
|
||||||
if (state.activeBlock) {
|
|
||||||
if (e.code === "Tab") {
|
|
||||||
e.preventDefault();
|
|
||||||
const isDeindent = e.shiftKey;
|
|
||||||
const text = state.activeBlock.textContent;
|
|
||||||
const characterRange = getCharacterRange(state.activeBlock);
|
|
||||||
if (!characterRange) return;
|
|
||||||
|
|
||||||
if (text.substring(characterRange.start).length > 0) {
|
|
||||||
if (characterRange.start === characterRange.end) {
|
|
||||||
state.activeBlock.textContent = insertAt(
|
|
||||||
text,
|
|
||||||
TAB,
|
|
||||||
characterRange.start
|
|
||||||
);
|
|
||||||
moveCaretTo(
|
|
||||||
state.activeBlock,
|
|
||||||
characterRange.start + TAB.length,
|
|
||||||
characterRange.end + TAB.length
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
let content = text.substring(0, characterRange.start);
|
|
||||||
const lines = text
|
|
||||||
.substring(characterRange.start, characterRange.end)
|
|
||||||
.split("\n");
|
|
||||||
for (var i = 0; i < lines.length; ++i) {
|
|
||||||
const line = lines[i];
|
|
||||||
lines[i] = isDeindent
|
|
||||||
? line.replace(TAB, "")
|
|
||||||
: `${TAB}${line}`;
|
|
||||||
}
|
|
||||||
content += lines.join("\n");
|
|
||||||
content += text.substring(characterRange.end);
|
|
||||||
state.activeBlock.textContent = content;
|
|
||||||
|
|
||||||
const endIndex = isDeindent
|
|
||||||
? characterRange.end - TAB.length * lines.length
|
|
||||||
: characterRange.end + TAB.length * lines.length;
|
|
||||||
moveCaretTo(state.activeBlock, characterRange.start, endIndex);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
editor.insertContent(TAB);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleKeyUp(e) {
|
|
||||||
if (
|
|
||||||
e.code === "Enter" ||
|
|
||||||
e.code === "Space" ||
|
|
||||||
e.code === "Backspace" ||
|
|
||||||
e.code === "Tab"
|
|
||||||
)
|
|
||||||
applyHighlighting(editor, null, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
editor.on("BeforeExecCommand", beforeExecCommandHandler);
|
|
||||||
editor.on("BeforeSetContent", setContentHandler);
|
|
||||||
editor.on("NodeChange", nodeChangeHandler);
|
|
||||||
editor.on("keydown", handleKeyDown);
|
|
||||||
editor.on("keyup", handleKeyUp);
|
|
||||||
return function () {
|
|
||||||
editor.off("BeforeExecCommand", beforeExecCommandHandler);
|
|
||||||
editor.off("BeforeSetContent", setContentHandler);
|
|
||||||
editor.off("keydown", handleKeyDown);
|
|
||||||
editor.off("keyup", handleKeyUp);
|
|
||||||
editor.off("NodeChange", nodeChangeHandler);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
function Plugin() {
|
|
||||||
global.add("code", function (editor) {
|
|
||||||
setupChangeLanguageButton(editor);
|
|
||||||
setupPreToolbar(editor);
|
|
||||||
|
|
||||||
register(editor);
|
|
||||||
register$1(editor);
|
|
||||||
|
|
||||||
return {};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Plugin();
|
|
||||||
})();
|
|
||||||
|
|
||||||
function languagesToItems() {
|
|
||||||
const languages = hljs.listLanguages();
|
|
||||||
languages.forEach((lang) => {
|
|
||||||
const language = hljs.getLanguage(lang);
|
|
||||||
state.languages.push({
|
|
||||||
type: "choiceitem",
|
|
||||||
text: language.name,
|
|
||||||
value: language,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function setupPreToolbar(editor) {
|
|
||||||
editor.ui.registry.addContextToolbar("preselection", {
|
|
||||||
predicate: function (node) {
|
|
||||||
if (node.nodeName === "PRE") {
|
|
||||||
state.activeBlock = node;
|
|
||||||
const language = detectCodeblockLanguage(node);
|
|
||||||
changeSelectedLanguage(editor, language, true);
|
|
||||||
return true;
|
|
||||||
} else if (
|
|
||||||
node.parentElement.nodeName !== "PRE" &&
|
|
||||||
node.className !== "line"
|
|
||||||
) {
|
|
||||||
state.activeBlock = null;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
items: "copy hljs-languages",
|
|
||||||
position: "node",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function setupChangeLanguageButton(editor, text) {
|
|
||||||
editor.ui.registry.addSplitButton("hljs-languages", {
|
|
||||||
text: text || "Auto detect",
|
|
||||||
onAction: function () {
|
|
||||||
const isAutoDetect = text === "Auto detect" || !text;
|
|
||||||
if (!isAutoDetect) applyHighlighting(editor, null, true);
|
|
||||||
else applyHighlighting(editor, null, false, true);
|
|
||||||
},
|
|
||||||
onItemAction: function (_buttonApi, value) {
|
|
||||||
changeSelectedLanguage(editor, value);
|
|
||||||
},
|
|
||||||
select: (value) => value?.name === text,
|
|
||||||
fetch: (callback) => {
|
|
||||||
callback(state.languages);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function changeSelectedLanguage(editor, value, highlighted = false) {
|
|
||||||
if (!highlighted) applyHighlighting(editor, value);
|
|
||||||
|
|
||||||
const label = document.querySelector(LANGUAGE_SELECT_LABEL_SELECTOR);
|
|
||||||
if (!label || label?.textContent === value?.name) return;
|
|
||||||
label.textContent = value?.name || "Auto detect";
|
|
||||||
|
|
||||||
setupChangeLanguageButton(editor, value?.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
function detectCodeblockLanguage(node, auto = false) {
|
|
||||||
if (node?.tagName !== "PRE") return;
|
|
||||||
|
|
||||||
const languageAliases = getLanguageFromClassName(node.className).split("-");
|
|
||||||
if (languageAliases.length > 1) {
|
|
||||||
return hljs.getLanguage(languageAliases[1]);
|
|
||||||
} else if (auto) {
|
|
||||||
const result = hljs.highlightAuto(node.innerText);
|
|
||||||
if (result.errorRaised) {
|
|
||||||
console.error(result.errorRaised);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return hljs.getLanguage(result.language);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function applyHighlighting(editor, language, refresh = false, auto = false) {
|
|
||||||
const node = state.activeBlock;
|
|
||||||
const detectedLanguage = detectCodeblockLanguage(node, auto);
|
|
||||||
|
|
||||||
const isDifferentLanguage = detectedLanguage?.name !== language?.name;
|
|
||||||
const shouldHighlight = refresh || !detectedLanguage || isDifferentLanguage;
|
|
||||||
if (!shouldHighlight) return;
|
|
||||||
|
|
||||||
if (refresh || auto) language = detectedLanguage;
|
|
||||||
if (!language || !language.aliases?.length) return;
|
|
||||||
|
|
||||||
const alias = language.aliases[0];
|
|
||||||
|
|
||||||
persistSelection(node, () => {
|
|
||||||
node.innerHTML = hljs.highlight(node.innerText, {
|
|
||||||
language: alias,
|
|
||||||
}).value;
|
|
||||||
editor.save();
|
|
||||||
});
|
|
||||||
|
|
||||||
if (refresh) return;
|
|
||||||
|
|
||||||
node.className = node.className.replace(
|
|
||||||
getLanguageFromClassName(node.className),
|
|
||||||
` language-${alias} `
|
|
||||||
);
|
|
||||||
|
|
||||||
if (auto) changeSelectedLanguage(editor, language, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function insertAt(str, token, index) {
|
|
||||||
return str.substring(0, index) + token + str.substring(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getLanguageFromClassName(className) {
|
|
||||||
const classes = className.split(" ");
|
|
||||||
const languageKey = classes.find((c) => c.startsWith("lang"));
|
|
||||||
return languageKey || "";
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
import "./plugin";
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
import tinymce from "tinymce/tinymce";
|
|
||||||
|
|
||||||
const COLLAPSED_KEY = "c";
|
|
||||||
const HIDDEN_KEY = "h";
|
|
||||||
const collapsibleTags = { HR: 1, H2: 2, H3: 3, H4: 4, H5: 5 };
|
|
||||||
|
|
||||||
function toggleElementVisibility(element, toggleState) {
|
|
||||||
if (!toggleState) element.classList.remove(HIDDEN_KEY);
|
|
||||||
else element.classList.add(HIDDEN_KEY);
|
|
||||||
}
|
|
||||||
|
|
||||||
function collapseElement(target) {
|
|
||||||
let sibling = target.nextSibling;
|
|
||||||
const isTargetCollapsed = target.classList.contains(COLLAPSED_KEY);
|
|
||||||
let skip = false;
|
|
||||||
|
|
||||||
while (
|
|
||||||
sibling &&
|
|
||||||
(!collapsibleTags[sibling.tagName] ||
|
|
||||||
collapsibleTags[sibling.tagName] > collapsibleTags[target.tagName])
|
|
||||||
) {
|
|
||||||
const isCollapsed = sibling.classList.contains(COLLAPSED_KEY);
|
|
||||||
if (!isTargetCollapsed) {
|
|
||||||
if (isCollapsed) {
|
|
||||||
skip = true;
|
|
||||||
toggleElementVisibility(sibling, isTargetCollapsed);
|
|
||||||
} else if (skip && collapsibleTags[sibling.tagName]) {
|
|
||||||
skip = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!skip) {
|
|
||||||
toggleElementVisibility(sibling, isTargetCollapsed);
|
|
||||||
}
|
|
||||||
if (!sibling.nextSibling) break;
|
|
||||||
sibling = sibling.nextSibling;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(function () {
|
|
||||||
tinymce.PluginManager.add("collapsibleheaders", function (editor, url) {
|
|
||||||
editor.on(
|
|
||||||
"mousedown touchstart",
|
|
||||||
function (e) {
|
|
||||||
const { target } = e;
|
|
||||||
if (
|
|
||||||
e.offsetX < 0 &&
|
|
||||||
collapsibleTags[target.tagName] &&
|
|
||||||
target.parentElement.tagName === "DIV"
|
|
||||||
) {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopImmediatePropagation();
|
|
||||||
e.stopPropagation();
|
|
||||||
editor.undoManager.transact(() => {
|
|
||||||
if (target.classList.contains(COLLAPSED_KEY)) {
|
|
||||||
target.classList.remove(COLLAPSED_KEY);
|
|
||||||
} else {
|
|
||||||
target.classList.add(COLLAPSED_KEY);
|
|
||||||
}
|
|
||||||
collapseElement(target);
|
|
||||||
// onSave();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ capture: true, passive: false }
|
|
||||||
);
|
|
||||||
|
|
||||||
editor.on("NewBlock", function (event) {
|
|
||||||
const { newBlock } = event;
|
|
||||||
const target = newBlock?.previousElementSibling;
|
|
||||||
if (target?.classList.contains(COLLAPSED_KEY)) {
|
|
||||||
target.classList.remove(COLLAPSED_KEY);
|
|
||||||
collapseElement(target);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
import "./plugin";
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
|||||||
import "./plugin";
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
import tinymce from "tinymce/tinymce";
|
|
||||||
import Compressor from "compressorjs";
|
|
||||||
|
|
||||||
(function () {
|
|
||||||
tinymce.PluginManager.add("quickimage", function (editor, url) {
|
|
||||||
/**
|
|
||||||
* Plugin behaviour for when the Toolbar or Menu item is selected
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
function _onAction() {
|
|
||||||
var input = document.createElement("input");
|
|
||||||
input.setAttribute("type", "file");
|
|
||||||
input.setAttribute("accept", "image/*");
|
|
||||||
input.onchange = function () {
|
|
||||||
var file = this.files[0];
|
|
||||||
if (!file) return null;
|
|
||||||
|
|
||||||
new Compressor(file, {
|
|
||||||
quality: 0.6,
|
|
||||||
mimeType: "image/jpeg",
|
|
||||||
width: 1024,
|
|
||||||
success(result) {
|
|
||||||
var reader = new FileReader();
|
|
||||||
reader.readAsDataURL(result);
|
|
||||||
|
|
||||||
reader.onloadend = function () {
|
|
||||||
var base64data = reader.result;
|
|
||||||
var content = `<img src="${base64data}"/>`;
|
|
||||||
editor.insertContent(content);
|
|
||||||
};
|
|
||||||
},
|
|
||||||
error(err) {
|
|
||||||
console.error(err.message);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
input.dispatchEvent(new MouseEvent("click"));
|
|
||||||
}
|
|
||||||
|
|
||||||
editor.ui.registry.addButton("image", {
|
|
||||||
icon: "image",
|
|
||||||
tooltip: "Insert image",
|
|
||||||
onAction: _onAction,
|
|
||||||
});
|
|
||||||
|
|
||||||
editor.addCommand("InsertImage", function (ui, value) {
|
|
||||||
_onAction();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
import "./plugins";
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
import tinymce from "tinymce/tinymce";
|
|
||||||
import {
|
|
||||||
getCharacterRange,
|
|
||||||
getNextCharacter,
|
|
||||||
getPreviousCharacter,
|
|
||||||
moveCaretTo,
|
|
||||||
} from "../utils";
|
|
||||||
|
|
||||||
const WRAP_CHARS = {
|
|
||||||
'"': { start: '"', end: '"' },
|
|
||||||
"[": { start: "[", end: "]" },
|
|
||||||
"(": { start: "(", end: ")" },
|
|
||||||
"{": { start: "{", end: "}" },
|
|
||||||
"|": { start: "|", end: "|" },
|
|
||||||
"`": { start: "`", end: "`" },
|
|
||||||
};
|
|
||||||
|
|
||||||
(function () {
|
|
||||||
tinymce.PluginManager.add("shortcuts", function (editor, url) {
|
|
||||||
editor.on("keydown", function (e) {
|
|
||||||
const content = editor.selection.getContent();
|
|
||||||
const node = editor.selection.getNode();
|
|
||||||
if (node?.nodeName === "PRE") return;
|
|
||||||
|
|
||||||
if (content) {
|
|
||||||
if (e.key === "`") {
|
|
||||||
e.preventDefault();
|
|
||||||
editor.execCommand("mceCode");
|
|
||||||
} else if (!!WRAP_CHARS[e.key]) {
|
|
||||||
e.preventDefault();
|
|
||||||
const char = WRAP_CHARS[e.key];
|
|
||||||
editor.selection.setContent(`${char.start}${content}${char.end}`);
|
|
||||||
}
|
|
||||||
} else if (e.code === "Backspace") {
|
|
||||||
const characterRange = getCharacterRange(node);
|
|
||||||
const nextChar = getNextCharacter(node, characterRange);
|
|
||||||
const prevChar = getPreviousCharacter(node, characterRange);
|
|
||||||
const isWrapChar = !!WRAP_CHARS[nextChar];
|
|
||||||
if (isWrapChar && nextChar === prevChar) {
|
|
||||||
e.preventDefault();
|
|
||||||
editor.execCommand("ForwardDelete");
|
|
||||||
editor.execCommand("Delete");
|
|
||||||
}
|
|
||||||
} else if (!!WRAP_CHARS[e.key]) {
|
|
||||||
e.preventDefault();
|
|
||||||
const char = WRAP_CHARS[e.key];
|
|
||||||
const characterRange = getCharacterRange(node);
|
|
||||||
const nextChar = getNextCharacter(node, characterRange);
|
|
||||||
const prevChar = getPreviousCharacter(node, characterRange);
|
|
||||||
|
|
||||||
if (nextChar === e.key) {
|
|
||||||
moveCaretTo(node, characterRange.start + 1, characterRange.end + 1);
|
|
||||||
} else if (!prevChar.trim()) {
|
|
||||||
editor.selection.setContent(`${char.start}${char.end}`);
|
|
||||||
characterRange.start += char.start.length + char.end.length;
|
|
||||||
characterRange.end += char.start.length + char.end.length;
|
|
||||||
moveCaretTo(node, characterRange.start - 1, characterRange.end - 1);
|
|
||||||
} else {
|
|
||||||
editor.selection.setContent(`${e.key}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
import "./plugin"
|
|
||||||
@@ -1,725 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
|
|
||||||
* Licensed under the LGPL or a commercial license.
|
|
||||||
* For LGPL see License.txt in the project root for license information.
|
|
||||||
* For commercial licenses see https://www.tiny.cloud/
|
|
||||||
*
|
|
||||||
* Version: 5.6.2 (2020-12-08)
|
|
||||||
*/
|
|
||||||
import tinymce from "tinymce/tinymce";
|
|
||||||
|
|
||||||
(function () {
|
|
||||||
var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
|
|
||||||
|
|
||||||
var global$1 = tinymce.util.Tools.resolve('tinymce.util.VK');
|
|
||||||
|
|
||||||
var typeOf = function (x) {
|
|
||||||
var t = typeof x;
|
|
||||||
if (x === null) {
|
|
||||||
return 'null';
|
|
||||||
// eslint-disable-next-line no-mixed-operators
|
|
||||||
} else if (t === 'object' && (Array.prototype.isPrototypeOf(x) || x.constructor && x.constructor.name === 'Array')) {
|
|
||||||
return 'array';
|
|
||||||
// eslint-disable-next-line no-mixed-operators
|
|
||||||
} else if (t === 'object' && (String.prototype.isPrototypeOf(x) || x.constructor && x.constructor.name === 'String')) {
|
|
||||||
return 'string';
|
|
||||||
} else {
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var isType = function (type) {
|
|
||||||
return function (value) {
|
|
||||||
return typeOf(value) === type;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
var isSimpleType = function (type) {
|
|
||||||
return function (value) {
|
|
||||||
return typeof value === type;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
var eq = function (t) {
|
|
||||||
return function (a) {
|
|
||||||
return t === a;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
var isString = isType('string');
|
|
||||||
var isNull = eq(null);
|
|
||||||
var isBoolean = isSimpleType('boolean');
|
|
||||||
|
|
||||||
var assumeExternalTargets = function (editor) {
|
|
||||||
var externalTargets = editor.getParam('link_assume_external_targets', false);
|
|
||||||
if (isBoolean(externalTargets) && externalTargets) {
|
|
||||||
return 1;
|
|
||||||
} else if (isString(externalTargets) && (externalTargets === 'http' || externalTargets === 'https')) {
|
|
||||||
return externalTargets;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
var hasContextToolbar = function (editor) {
|
|
||||||
return editor.getParam('link_context_toolbar', false, 'boolean');
|
|
||||||
};
|
|
||||||
var getDefaultLinkTarget = function (editor) {
|
|
||||||
return editor.getParam('default_link_target');
|
|
||||||
};
|
|
||||||
var allowUnsafeLinkTarget = function (editor) {
|
|
||||||
return editor.getParam('allow_unsafe_link_target', false, 'boolean');
|
|
||||||
};
|
|
||||||
|
|
||||||
var appendClickRemove = function (link, evt) {
|
|
||||||
document.body.appendChild(link);
|
|
||||||
link.dispatchEvent(evt);
|
|
||||||
document.body.removeChild(link);
|
|
||||||
};
|
|
||||||
var open = function (url) {
|
|
||||||
var link = document.createElement('a');
|
|
||||||
link.target = '_blank';
|
|
||||||
link.href = url;
|
|
||||||
link.rel = 'noreferrer noopener';
|
|
||||||
var evt = document.createEvent('MouseEvents');
|
|
||||||
evt.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
|
|
||||||
appendClickRemove(link, evt);
|
|
||||||
};
|
|
||||||
|
|
||||||
var __assign = function () {
|
|
||||||
__assign = Object.assign || function __assign(t) {
|
|
||||||
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
||||||
s = arguments[i];
|
|
||||||
for (var p in s)
|
|
||||||
if (Object.prototype.hasOwnProperty.call(s, p))
|
|
||||||
t[p] = s[p];
|
|
||||||
}
|
|
||||||
return t;
|
|
||||||
};
|
|
||||||
return __assign.apply(this, arguments);
|
|
||||||
};
|
|
||||||
|
|
||||||
var noop = function () {
|
|
||||||
};
|
|
||||||
var constant = function (value) {
|
|
||||||
return function () {
|
|
||||||
return value;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
var never = constant(false);
|
|
||||||
var always = constant(true);
|
|
||||||
|
|
||||||
var none = function () {
|
|
||||||
return NONE;
|
|
||||||
};
|
|
||||||
var NONE = function () {
|
|
||||||
var eq = function (o) {
|
|
||||||
return o.isNone();
|
|
||||||
};
|
|
||||||
var call = function (thunk) {
|
|
||||||
return thunk();
|
|
||||||
};
|
|
||||||
var id = function (n) {
|
|
||||||
return n;
|
|
||||||
};
|
|
||||||
var me = {
|
|
||||||
fold: function (n, _s) {
|
|
||||||
return n();
|
|
||||||
},
|
|
||||||
is: never,
|
|
||||||
isSome: never,
|
|
||||||
isNone: always,
|
|
||||||
getOr: id,
|
|
||||||
getOrThunk: call,
|
|
||||||
getOrDie: function (msg) {
|
|
||||||
throw new Error(msg || 'error: getOrDie called on none.');
|
|
||||||
},
|
|
||||||
getOrNull: constant(null),
|
|
||||||
getOrUndefined: constant(undefined),
|
|
||||||
or: id,
|
|
||||||
orThunk: call,
|
|
||||||
map: none,
|
|
||||||
each: noop,
|
|
||||||
bind: none,
|
|
||||||
exists: never,
|
|
||||||
forall: always,
|
|
||||||
filter: none,
|
|
||||||
equals: eq,
|
|
||||||
equals_: eq,
|
|
||||||
toArray: function () {
|
|
||||||
return [];
|
|
||||||
},
|
|
||||||
toString: constant('none()')
|
|
||||||
};
|
|
||||||
return me;
|
|
||||||
}();
|
|
||||||
var some = function (a) {
|
|
||||||
var constant_a = constant(a);
|
|
||||||
var self = function () {
|
|
||||||
return me;
|
|
||||||
};
|
|
||||||
var bind = function (f) {
|
|
||||||
return f(a);
|
|
||||||
};
|
|
||||||
var me = {
|
|
||||||
fold: function (n, s) {
|
|
||||||
return s(a);
|
|
||||||
},
|
|
||||||
is: function (v) {
|
|
||||||
return a === v;
|
|
||||||
},
|
|
||||||
isSome: always,
|
|
||||||
isNone: never,
|
|
||||||
getOr: constant_a,
|
|
||||||
getOrThunk: constant_a,
|
|
||||||
getOrDie: constant_a,
|
|
||||||
getOrNull: constant_a,
|
|
||||||
getOrUndefined: constant_a,
|
|
||||||
or: self,
|
|
||||||
orThunk: self,
|
|
||||||
map: function (f) {
|
|
||||||
return some(f(a));
|
|
||||||
},
|
|
||||||
each: function (f) {
|
|
||||||
f(a);
|
|
||||||
},
|
|
||||||
bind: bind,
|
|
||||||
exists: bind,
|
|
||||||
forall: bind,
|
|
||||||
filter: function (f) {
|
|
||||||
return f(a) ? me : NONE;
|
|
||||||
},
|
|
||||||
toArray: function () {
|
|
||||||
return [a];
|
|
||||||
},
|
|
||||||
toString: function () {
|
|
||||||
return 'some(' + a + ')';
|
|
||||||
},
|
|
||||||
equals: function (o) {
|
|
||||||
return o.is(a);
|
|
||||||
},
|
|
||||||
equals_: function (o, elementEq) {
|
|
||||||
return o.fold(never, function (b) {
|
|
||||||
return elementEq(a, b);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return me;
|
|
||||||
};
|
|
||||||
var from = function (value) {
|
|
||||||
return value === null || value === undefined ? NONE : some(value);
|
|
||||||
};
|
|
||||||
var Optional = {
|
|
||||||
some: some,
|
|
||||||
none: none,
|
|
||||||
from: from
|
|
||||||
};
|
|
||||||
|
|
||||||
var each = function (xs, f) {
|
|
||||||
for (var i = 0, len = xs.length; i < len; i++) {
|
|
||||||
var x = xs[i];
|
|
||||||
f(x, i);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var foldl = function (xs, f, acc) {
|
|
||||||
each(xs, function (x) {
|
|
||||||
acc = f(acc, x);
|
|
||||||
});
|
|
||||||
return acc;
|
|
||||||
};
|
|
||||||
|
|
||||||
var keys = Object.keys;
|
|
||||||
var hasOwnProperty = Object.hasOwnProperty;
|
|
||||||
var each$1 = function (obj, f) {
|
|
||||||
var props = keys(obj);
|
|
||||||
for (var k = 0, len = props.length; k < len; k++) {
|
|
||||||
var i = props[k];
|
|
||||||
var x = obj[i];
|
|
||||||
f(x, i);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var objAcc = function (r) {
|
|
||||||
return function (x, i) {
|
|
||||||
r[i] = x;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
var internalFilter = function (obj, pred, onTrue, onFalse) {
|
|
||||||
var r = {};
|
|
||||||
each$1(obj, function (x, i) {
|
|
||||||
(pred(x, i) ? onTrue : onFalse)(x, i);
|
|
||||||
});
|
|
||||||
return r;
|
|
||||||
};
|
|
||||||
var filter = function (obj, pred) {
|
|
||||||
var t = {};
|
|
||||||
internalFilter(obj, pred, objAcc(t), noop);
|
|
||||||
return t;
|
|
||||||
};
|
|
||||||
var has = function (obj, key) {
|
|
||||||
return hasOwnProperty.call(obj, key);
|
|
||||||
};
|
|
||||||
|
|
||||||
var global$2 = tinymce.util.Tools.resolve('tinymce.dom.TreeWalker');
|
|
||||||
|
|
||||||
var global$3 = tinymce.util.Tools.resolve('tinymce.util.Tools');
|
|
||||||
|
|
||||||
var isAnchor = function (elm) {
|
|
||||||
return elm && elm.nodeName.toLowerCase() === 'a';
|
|
||||||
};
|
|
||||||
var isLink = function (elm) {
|
|
||||||
return isAnchor(elm) && !!getHref(elm);
|
|
||||||
};
|
|
||||||
var collectNodesInRange = function (rng, predicate) {
|
|
||||||
if (rng.collapsed) {
|
|
||||||
return [];
|
|
||||||
} else {
|
|
||||||
var contents = rng.cloneContents();
|
|
||||||
var walker = new global$2(contents.firstChild, contents);
|
|
||||||
var elements = [];
|
|
||||||
var current = contents.firstChild;
|
|
||||||
do {
|
|
||||||
if (predicate(current)) {
|
|
||||||
elements.push(current);
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line no-cond-assign
|
|
||||||
} while (current = walker.next());
|
|
||||||
return elements;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var hasProtocol = function (url) {
|
|
||||||
return /^\w+:/i.test(url);
|
|
||||||
};
|
|
||||||
var getHref = function (elm) {
|
|
||||||
var href = elm.getAttribute('data-mce-href');
|
|
||||||
return href ? href : elm.getAttribute('href');
|
|
||||||
};
|
|
||||||
var applyRelTargetRules = function (rel, isUnsafe) {
|
|
||||||
var rules = ['noopener'];
|
|
||||||
var rels = rel ? rel.split(/\s+/) : [];
|
|
||||||
var toString = function (rels) {
|
|
||||||
return global$3.trim(rels.sort().join(' '));
|
|
||||||
};
|
|
||||||
var addTargetRules = function (rels) {
|
|
||||||
rels = removeTargetRules(rels);
|
|
||||||
return rels.length > 0 ? rels.concat(rules) : rules;
|
|
||||||
};
|
|
||||||
var removeTargetRules = function (rels) {
|
|
||||||
return rels.filter(function (val) {
|
|
||||||
return global$3.inArray(rules, val) === -1;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
var newRels = isUnsafe ? addTargetRules(rels) : removeTargetRules(rels);
|
|
||||||
return newRels.length > 0 ? toString(newRels) : '';
|
|
||||||
};
|
|
||||||
var trimCaretContainers = function (text) {
|
|
||||||
return text.replace(/\uFEFF/g, '');
|
|
||||||
};
|
|
||||||
var getAnchorElement = function (editor, selectedElm) {
|
|
||||||
selectedElm = selectedElm || editor.selection.getNode();
|
|
||||||
if (isImageFigure(selectedElm)) {
|
|
||||||
return editor.dom.select('a[href]', selectedElm)[0];
|
|
||||||
} else {
|
|
||||||
return editor.dom.getParent(selectedElm, 'a[href]');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var getAnchorText = function (selection, anchorElm) {
|
|
||||||
var text = anchorElm ? anchorElm.innerText || anchorElm.textContent : selection.getContent({ format: 'text' });
|
|
||||||
return trimCaretContainers(text);
|
|
||||||
};
|
|
||||||
var hasLinks = function (elements) {
|
|
||||||
return global$3.grep(elements, isLink).length > 0;
|
|
||||||
};
|
|
||||||
var hasLinksInSelection = function (rng) {
|
|
||||||
return collectNodesInRange(rng, isLink).length > 0;
|
|
||||||
};
|
|
||||||
var isOnlyTextSelected = function (editor) {
|
|
||||||
var inlineTextElements = editor.schema.getTextInlineElements();
|
|
||||||
var isElement = function (elm) {
|
|
||||||
return elm.nodeType === 1 && !isAnchor(elm) && !has(inlineTextElements, elm.nodeName.toLowerCase());
|
|
||||||
};
|
|
||||||
var elements = collectNodesInRange(editor.selection.getRng(), isElement);
|
|
||||||
return elements.length === 0;
|
|
||||||
};
|
|
||||||
var isImageFigure = function (elm) {
|
|
||||||
return elm && elm.nodeName === 'FIGURE' && /\bimage\b/i.test(elm.className);
|
|
||||||
};
|
|
||||||
var getLinkAttrs = function (data) {
|
|
||||||
return foldl([
|
|
||||||
'title',
|
|
||||||
'rel',
|
|
||||||
'class',
|
|
||||||
'target'
|
|
||||||
], function (acc, key) {
|
|
||||||
data[key].each(function (value) {
|
|
||||||
acc[key] = value.length > 0 ? value : null;
|
|
||||||
});
|
|
||||||
return acc;
|
|
||||||
}, { href: data.href });
|
|
||||||
};
|
|
||||||
var handleExternalTargets = function (href, assumeExternalTargets) {
|
|
||||||
if ((assumeExternalTargets === 'http' || assumeExternalTargets === 'https') && !hasProtocol(href)) {
|
|
||||||
return assumeExternalTargets + '://' + href;
|
|
||||||
}
|
|
||||||
return href;
|
|
||||||
};
|
|
||||||
var applyLinkOverrides = function (editor, linkAttrs) {
|
|
||||||
var newLinkAttrs = __assign({}, linkAttrs);
|
|
||||||
if (allowUnsafeLinkTarget(editor) === false) {
|
|
||||||
var newRel = applyRelTargetRules(newLinkAttrs.rel, newLinkAttrs.target === '_blank');
|
|
||||||
newLinkAttrs.rel = newRel ? newRel : null;
|
|
||||||
}
|
|
||||||
if (Optional.from(newLinkAttrs.target).isNone()) {
|
|
||||||
newLinkAttrs.target = getDefaultLinkTarget(editor);
|
|
||||||
}
|
|
||||||
newLinkAttrs.href = handleExternalTargets(newLinkAttrs.href, assumeExternalTargets(editor));
|
|
||||||
return newLinkAttrs;
|
|
||||||
};
|
|
||||||
var updateLink = function (editor, anchorElm, text, linkAttrs) {
|
|
||||||
text.each(function (text) {
|
|
||||||
if (anchorElm.hasOwnProperty('innerText')) {
|
|
||||||
anchorElm.innerText = text;
|
|
||||||
} else {
|
|
||||||
anchorElm.textContent = text;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
editor.dom.setAttribs(anchorElm, linkAttrs);
|
|
||||||
editor.selection.select(anchorElm);
|
|
||||||
};
|
|
||||||
var createLink = function (editor, selectedElm, text, linkAttrs) {
|
|
||||||
if (isImageFigure(selectedElm)) {
|
|
||||||
linkImageFigure(editor, selectedElm, linkAttrs);
|
|
||||||
} else {
|
|
||||||
text.fold(function () {
|
|
||||||
editor.execCommand('mceInsertLink', false, linkAttrs);
|
|
||||||
}, function (text) {
|
|
||||||
editor.insertContent(editor.dom.createHTML('a', linkAttrs, editor.dom.encode(text)));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var linkDomMutation = function (editor, attachState, data) {
|
|
||||||
var selectedElm = editor.selection.getNode();
|
|
||||||
var anchorElm = getAnchorElement(editor, selectedElm);
|
|
||||||
var linkAttrs = applyLinkOverrides(editor, getLinkAttrs(data));
|
|
||||||
editor.undoManager.transact(function () {
|
|
||||||
if (data.href === attachState.href) {
|
|
||||||
attachState.attach();
|
|
||||||
}
|
|
||||||
if (anchorElm) {
|
|
||||||
editor.focus();
|
|
||||||
updateLink(editor, anchorElm, data.text, linkAttrs);
|
|
||||||
} else {
|
|
||||||
createLink(editor, selectedElm, data.text, linkAttrs);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
var unlinkSelection = function (editor) {
|
|
||||||
var dom = editor.dom, selection = editor.selection;
|
|
||||||
var bookmark = selection.getBookmark();
|
|
||||||
var rng = selection.getRng().cloneRange();
|
|
||||||
var startAnchorElm = dom.getParent(rng.startContainer, 'a[href]', editor.getBody());
|
|
||||||
var endAnchorElm = dom.getParent(rng.endContainer, 'a[href]', editor.getBody());
|
|
||||||
if (startAnchorElm) {
|
|
||||||
rng.setStartBefore(startAnchorElm);
|
|
||||||
}
|
|
||||||
if (endAnchorElm) {
|
|
||||||
rng.setEndAfter(endAnchorElm);
|
|
||||||
}
|
|
||||||
selection.setRng(rng);
|
|
||||||
editor.execCommand('unlink');
|
|
||||||
selection.moveToBookmark(bookmark);
|
|
||||||
};
|
|
||||||
var unlinkDomMutation = function (editor) {
|
|
||||||
editor.undoManager.transact(function () {
|
|
||||||
var node = editor.selection.getNode();
|
|
||||||
if (isImageFigure(node)) {
|
|
||||||
unlinkImageFigure(editor, node);
|
|
||||||
} else {
|
|
||||||
unlinkSelection(editor);
|
|
||||||
}
|
|
||||||
editor.focus();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
var unwrapOptions = function (data) {
|
|
||||||
var cls = data.class, href = data.href, rel = data.rel, target = data.target, text = data.text, title = data.title;
|
|
||||||
return filter({
|
|
||||||
class: cls.getOrNull(),
|
|
||||||
href: href,
|
|
||||||
rel: rel.getOrNull(),
|
|
||||||
target: target.getOrNull(),
|
|
||||||
text: text.getOrNull(),
|
|
||||||
title: title.getOrNull()
|
|
||||||
}, function (v, _k) {
|
|
||||||
return isNull(v) === false;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
var link = function (editor, attachState, data) {
|
|
||||||
editor.hasPlugin('rtc', true) ? editor.execCommand('createlink', false, unwrapOptions(data)) : linkDomMutation(editor, attachState, data);
|
|
||||||
};
|
|
||||||
var unlink = function (editor) {
|
|
||||||
editor.hasPlugin('rtc', true) ? editor.execCommand('unlink') : unlinkDomMutation(editor);
|
|
||||||
};
|
|
||||||
var unlinkImageFigure = function (editor, fig) {
|
|
||||||
var img = editor.dom.select('img', fig)[0];
|
|
||||||
if (img) {
|
|
||||||
var a = editor.dom.getParents(img, 'a[href]', fig)[0];
|
|
||||||
if (a) {
|
|
||||||
a.parentNode.insertBefore(img, a);
|
|
||||||
editor.dom.remove(a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var linkImageFigure = function (editor, fig, attrs) {
|
|
||||||
var img = editor.dom.select('img', fig)[0];
|
|
||||||
if (img) {
|
|
||||||
var a = editor.dom.create('a', attrs);
|
|
||||||
img.parentNode.insertBefore(a, img);
|
|
||||||
a.appendChild(img);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var getLink = function (editor, elm) {
|
|
||||||
return editor.dom.getParent(elm, 'a[href]');
|
|
||||||
};
|
|
||||||
var getSelectedLink = function (editor) {
|
|
||||||
return getLink(editor, editor.selection.getStart());
|
|
||||||
};
|
|
||||||
var hasOnlyAltModifier = function (e) {
|
|
||||||
return e.altKey === true && e.shiftKey === false && e.ctrlKey === false && e.metaKey === false;
|
|
||||||
};
|
|
||||||
var gotoLink = function (editor, a) {
|
|
||||||
if (a) {
|
|
||||||
var href = getHref(a);
|
|
||||||
if (/^#/.test(href)) {
|
|
||||||
var targetEl = editor.$(href);
|
|
||||||
if (targetEl.length) {
|
|
||||||
editor.selection.scrollIntoView(targetEl[0], true);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
open(a.href);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var openDialog = function (editor) {
|
|
||||||
return function () {
|
|
||||||
editor.fire('contexttoolbar-show', { toolbarKey: 'quicklink' });
|
|
||||||
};
|
|
||||||
};
|
|
||||||
var gotoSelectedLink = function (editor) {
|
|
||||||
return function () {
|
|
||||||
gotoLink(editor, getSelectedLink(editor));
|
|
||||||
};
|
|
||||||
};
|
|
||||||
var setupGotoLinks = function (editor) {
|
|
||||||
editor.on('click', function (e) {
|
|
||||||
var link = getLink(editor, e.target);
|
|
||||||
if (link && global$1.metaKeyPressed(e)) {
|
|
||||||
e.preventDefault();
|
|
||||||
gotoLink(editor, link);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
editor.on('keydown', function (e) {
|
|
||||||
var link = getSelectedLink(editor);
|
|
||||||
if (link && e.keyCode === 13 && hasOnlyAltModifier(e)) {
|
|
||||||
e.preventDefault();
|
|
||||||
gotoLink(editor, link);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
var toggleState = function (editor, toggler) {
|
|
||||||
editor.on('NodeChange', toggler);
|
|
||||||
return function () {
|
|
||||||
return editor.off('NodeChange', toggler);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
var toggleActiveState = function (editor) {
|
|
||||||
return function (api) {
|
|
||||||
return toggleState(editor, function () {
|
|
||||||
api.setActive(!editor.mode.isReadOnly() && getAnchorElement(editor, editor.selection.getNode()) !== null);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
};
|
|
||||||
var toggleEnabledState = function (editor) {
|
|
||||||
return function (api) {
|
|
||||||
var updateState = function () {
|
|
||||||
return api.setDisabled(getAnchorElement(editor, editor.selection.getNode()) === null);
|
|
||||||
};
|
|
||||||
updateState();
|
|
||||||
return toggleState(editor, updateState);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
var toggleUnlinkState = function (editor) {
|
|
||||||
return function (api) {
|
|
||||||
var hasLinks$1 = function (parents) {
|
|
||||||
return hasLinks(parents) || hasLinksInSelection(editor.selection.getRng());
|
|
||||||
};
|
|
||||||
var parents = editor.dom.getParents(editor.selection.getStart());
|
|
||||||
api.setDisabled(!hasLinks$1(parents));
|
|
||||||
return toggleState(editor, function (e) {
|
|
||||||
return api.setDisabled(!hasLinks$1(e.parents));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
var register = function (editor) {
|
|
||||||
editor.addCommand('mceLink', function () {
|
|
||||||
openDialog(editor)();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
var setup = function (editor) {
|
|
||||||
editor.addShortcut('Meta+K', '', function () {
|
|
||||||
editor.execCommand('mceLink');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
var setupButtons = function (editor) {
|
|
||||||
editor.ui.registry.addToggleButton('link', {
|
|
||||||
icon: 'link',
|
|
||||||
tooltip: 'Insert/edit link',
|
|
||||||
onAction: openDialog(editor),
|
|
||||||
onSetup: toggleActiveState(editor)
|
|
||||||
});
|
|
||||||
editor.ui.registry.addButton('openlink', {
|
|
||||||
icon: 'new-tab',
|
|
||||||
tooltip: 'Open link',
|
|
||||||
onAction: gotoSelectedLink(editor),
|
|
||||||
onSetup: toggleEnabledState(editor)
|
|
||||||
});
|
|
||||||
editor.ui.registry.addButton('unlink', {
|
|
||||||
icon: 'unlink',
|
|
||||||
tooltip: 'Remove link',
|
|
||||||
onAction: function () {
|
|
||||||
return unlink(editor);
|
|
||||||
},
|
|
||||||
onSetup: toggleUnlinkState(editor)
|
|
||||||
});
|
|
||||||
};
|
|
||||||
var setupMenuItems = function (editor) {
|
|
||||||
editor.ui.registry.addMenuItem('openlink', {
|
|
||||||
text: 'Open link',
|
|
||||||
icon: 'new-tab',
|
|
||||||
onAction: gotoSelectedLink(editor),
|
|
||||||
onSetup: toggleEnabledState(editor)
|
|
||||||
});
|
|
||||||
editor.ui.registry.addMenuItem('link', {
|
|
||||||
icon: 'link',
|
|
||||||
text: 'Link...',
|
|
||||||
shortcut: 'Meta+K',
|
|
||||||
onAction: openDialog(editor)
|
|
||||||
});
|
|
||||||
editor.ui.registry.addMenuItem('unlink', {
|
|
||||||
icon: 'unlink',
|
|
||||||
text: 'Remove link',
|
|
||||||
onAction: function () {
|
|
||||||
return unlink(editor);
|
|
||||||
},
|
|
||||||
onSetup: toggleUnlinkState(editor)
|
|
||||||
});
|
|
||||||
};
|
|
||||||
var setupContextMenu = function (editor) {
|
|
||||||
var inLink = 'link unlink openlink';
|
|
||||||
var noLink = 'link';
|
|
||||||
editor.ui.registry.addContextMenu('link', {
|
|
||||||
update: function (element) {
|
|
||||||
return hasLinks(editor.dom.getParents(element, 'a')) ? inLink : noLink;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
var setupContextToolbars = function (editor) {
|
|
||||||
var collapseSelectionToEnd = function (editor) {
|
|
||||||
editor.selection.collapse(false);
|
|
||||||
};
|
|
||||||
var onSetupLink = function (buttonApi) {
|
|
||||||
var node = editor.selection.getNode();
|
|
||||||
buttonApi.setDisabled(!getAnchorElement(editor, node));
|
|
||||||
return noop;
|
|
||||||
};
|
|
||||||
editor.ui.registry.addContextForm('quicklink', {
|
|
||||||
launch: {
|
|
||||||
type: 'contextformtogglebutton',
|
|
||||||
icon: 'link',
|
|
||||||
tooltip: 'Link',
|
|
||||||
onSetup: toggleActiveState(editor)
|
|
||||||
},
|
|
||||||
label: 'Link',
|
|
||||||
predicate: function (node) {
|
|
||||||
return !!getAnchorElement(editor, node) && hasContextToolbar(editor);
|
|
||||||
},
|
|
||||||
initValue: function () {
|
|
||||||
var elm = getAnchorElement(editor);
|
|
||||||
return !!elm ? getHref(elm) : '';
|
|
||||||
},
|
|
||||||
commands: [
|
|
||||||
{
|
|
||||||
type: 'contextformtogglebutton',
|
|
||||||
icon: 'link',
|
|
||||||
tooltip: 'Link',
|
|
||||||
primary: true,
|
|
||||||
onSetup: function (buttonApi) {
|
|
||||||
var node = editor.selection.getNode();
|
|
||||||
buttonApi.setActive(!!getAnchorElement(editor, node));
|
|
||||||
return toggleActiveState(editor)(buttonApi);
|
|
||||||
},
|
|
||||||
onAction: function (formApi) {
|
|
||||||
var anchor = getAnchorElement(editor);
|
|
||||||
var value = formApi.getValue();
|
|
||||||
if (!anchor) {
|
|
||||||
var attachState = {
|
|
||||||
href: value,
|
|
||||||
attach: noop
|
|
||||||
};
|
|
||||||
var onlyText = isOnlyTextSelected(editor);
|
|
||||||
var text = onlyText ? Optional.some(getAnchorText(editor.selection, anchor)).filter(function (t) {
|
|
||||||
return t.length > 0;
|
|
||||||
}).or(Optional.from(value)) : Optional.none();
|
|
||||||
link(editor, attachState, {
|
|
||||||
href: value,
|
|
||||||
text: text,
|
|
||||||
title: Optional.none(),
|
|
||||||
rel: Optional.none(),
|
|
||||||
target: Optional.none(),
|
|
||||||
class: Optional.none()
|
|
||||||
});
|
|
||||||
formApi.hide();
|
|
||||||
} else {
|
|
||||||
editor.undoManager.transact(function () {
|
|
||||||
editor.dom.setAttrib(anchor, 'href', value);
|
|
||||||
collapseSelectionToEnd(editor);
|
|
||||||
formApi.hide();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'contextformbutton',
|
|
||||||
icon: 'unlink',
|
|
||||||
tooltip: 'Remove link',
|
|
||||||
onSetup: onSetupLink,
|
|
||||||
onAction: function (formApi) {
|
|
||||||
unlink(editor);
|
|
||||||
formApi.hide();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'contextformbutton',
|
|
||||||
icon: 'new-tab',
|
|
||||||
tooltip: 'Open link',
|
|
||||||
onSetup: onSetupLink,
|
|
||||||
onAction: function (formApi) {
|
|
||||||
gotoSelectedLink(editor)();
|
|
||||||
formApi.hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
function Plugin () {
|
|
||||||
global.add('shortlink', function (editor) {
|
|
||||||
setupButtons(editor);
|
|
||||||
setupMenuItems(editor);
|
|
||||||
setupContextMenu(editor);
|
|
||||||
setupContextToolbars(editor);
|
|
||||||
setupGotoLinks(editor);
|
|
||||||
register(editor);
|
|
||||||
setup(editor);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Plugin();
|
|
||||||
|
|
||||||
}());
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
import rangy from "rangy/lib/rangy-textrange";
|
|
||||||
|
|
||||||
export function getCharacterRange(node) {
|
|
||||||
if (!node) return;
|
|
||||||
const ranges = rangy.getSelection().saveCharacterRanges(node);
|
|
||||||
if (!ranges || !ranges.length) return;
|
|
||||||
const { characterRange } = ranges[0];
|
|
||||||
return characterRange;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getNextCharacter(node, range) {
|
|
||||||
if (!range) return "";
|
|
||||||
return (node.textContent || node.innerText).substring(
|
|
||||||
range.end,
|
|
||||||
range.end + 1
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getPreviousCharacter(node, range) {
|
|
||||||
if (!range) return "";
|
|
||||||
return (node.textContent || node.innerText).substring(
|
|
||||||
range.start,
|
|
||||||
range.start - 1
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function moveCaretTo(node, index, endIndex) {
|
|
||||||
const newCharacterRange = {
|
|
||||||
characterRange: {
|
|
||||||
start: index,
|
|
||||||
end: endIndex || index,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
rangy.getSelection().restoreCharacterRanges(node, [newCharacterRange]);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function persistSelection(node, action) {
|
|
||||||
let saved = rangy.getSelection().saveCharacterRanges(node);
|
|
||||||
action();
|
|
||||||
rangy.getSelection().restoreCharacterRanges(node, saved);
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,8 @@
|
|||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
|
import "./editor.css";
|
||||||
|
import "@streetwritersco/tinymce-plugins/codeblock/styles.css";
|
||||||
|
import "@streetwritersco/tinymce-plugins/inlinecode/styles.css";
|
||||||
|
import "@streetwritersco/tinymce-plugins/collapsibleheaders/styles.css";
|
||||||
import "tinymce/tinymce";
|
import "tinymce/tinymce";
|
||||||
import "tinymce/icons/default";
|
import "tinymce/icons/default";
|
||||||
import "tinymce/themes/silver";
|
import "tinymce/themes/silver";
|
||||||
@@ -18,14 +22,14 @@ import "tinymce/plugins/noneditable";
|
|||||||
import "tinymce/plugins/table";
|
import "tinymce/plugins/table";
|
||||||
import "tinymce/plugins/directionality";
|
import "tinymce/plugins/directionality";
|
||||||
import "tinymce/plugins/media";
|
import "tinymce/plugins/media";
|
||||||
import "./plugins/code";
|
import { processPastedContent } from "@streetwritersco/tinymce-plugins/codeblock";
|
||||||
import "./plugins/shortlink";
|
import "@streetwritersco/tinymce-plugins/inlinecode";
|
||||||
import "./plugins/quickimage";
|
import "@streetwritersco/tinymce-plugins/shortlink";
|
||||||
import "./plugins/checklist";
|
import "@streetwritersco/tinymce-plugins/quickimage";
|
||||||
import "./plugins/collapsibleheaders";
|
import "@streetwritersco/tinymce-plugins/checklist";
|
||||||
import "./plugins/paste";
|
import "@streetwritersco/tinymce-plugins/collapsibleheaders";
|
||||||
import "./plugins/shortcuts";
|
import "@streetwritersco/tinymce-plugins/paste";
|
||||||
import "./editor.css";
|
import "@streetwritersco/tinymce-plugins/shortcuts";
|
||||||
import { Editor } from "@tinymce/tinymce-react";
|
import { Editor } from "@tinymce/tinymce-react";
|
||||||
import { showBuyDialog } from "../../common/dialog-controller";
|
import { showBuyDialog } from "../../common/dialog-controller";
|
||||||
import { useStore as useThemeStore } from "../../stores/theme-store";
|
import { useStore as useThemeStore } from "../../stores/theme-store";
|
||||||
@@ -40,7 +44,7 @@ const markdownPatterns = [
|
|||||||
{ start: "_", end: "_", format: "italic" },
|
{ start: "_", end: "_", format: "italic" },
|
||||||
{ start: "**", end: "**", format: "bold" },
|
{ start: "**", end: "**", format: "bold" },
|
||||||
{ start: "~~", end: "~~", format: "strikethrough" },
|
{ start: "~~", end: "~~", format: "strikethrough" },
|
||||||
{ start: "`", end: "`", cmd: "mceCode" },
|
{ start: "`", end: "`", cmd: "mceInsertInlineCode" },
|
||||||
{ start: "## ", format: "h2" },
|
{ start: "## ", format: "h2" },
|
||||||
{ start: "### ", format: "h3" },
|
{ start: "### ", format: "h3" },
|
||||||
{ start: "#### ", format: "h4" },
|
{ start: "#### ", format: "h4" },
|
||||||
@@ -101,8 +105,14 @@ function useSkin() {
|
|||||||
: [host + "/skins/notesnook-dark", host + "/skins/notesnook"];
|
: [host + "/skins/notesnook-dark", host + "/skins/notesnook"];
|
||||||
}
|
}
|
||||||
|
|
||||||
const plugins =
|
const plugins = {
|
||||||
"shortcuts checklist paste importcss searchreplace autolink directionality code quickimage shortlink media table hr advlist lists imagetools noneditable quickbars autoresize collapsibleheaders";
|
default:
|
||||||
|
"importcss searchreplace autolink directionality media table hr advlist lists imagetools noneditable quickbars autoresize",
|
||||||
|
custom:
|
||||||
|
"collapsibleheaders shortlink quickimage paste codeblock inlinecode shortcuts checklist",
|
||||||
|
pro: "textpattern",
|
||||||
|
};
|
||||||
|
|
||||||
function TinyMCE(props) {
|
function TinyMCE(props) {
|
||||||
const {
|
const {
|
||||||
changeInterval,
|
changeInterval,
|
||||||
@@ -148,7 +158,9 @@ function TinyMCE(props) {
|
|||||||
statusbar: false,
|
statusbar: false,
|
||||||
link_quicklink: true,
|
link_quicklink: true,
|
||||||
width: "100%",
|
width: "100%",
|
||||||
plugins: isUserPremium ? `${plugins} textpattern` : plugins,
|
plugins: isUserPremium
|
||||||
|
? `${plugins.default} ${plugins.custom} ${plugins.pro}`
|
||||||
|
: plugins.default,
|
||||||
toolbar_mode: isTablet() ? "scrolling" : "sliding",
|
toolbar_mode: isTablet() ? "scrolling" : "sliding",
|
||||||
contextmenu: false,
|
contextmenu: false,
|
||||||
quickbars_insert_toolbar: false,
|
quickbars_insert_toolbar: false,
|
||||||
@@ -211,15 +223,7 @@ function TinyMCE(props) {
|
|||||||
fixed_toolbar_container: "#editorToolbar",
|
fixed_toolbar_container: "#editorToolbar",
|
||||||
paste_postprocess: function (_, args) {
|
paste_postprocess: function (_, args) {
|
||||||
const { node } = args;
|
const { node } = args;
|
||||||
if (node.childNodes) {
|
processPastedContent(node);
|
||||||
for (let childNode of node.childNodes) {
|
|
||||||
if (childNode.tagName === "PRE") {
|
|
||||||
childNode.className = "hljs";
|
|
||||||
const code = childNode.textContent || childNode.innerText;
|
|
||||||
childNode.innerHTML = code;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
onBeforeExecCommand={async (command) => {
|
onBeforeExecCommand={async (command) => {
|
||||||
|
|||||||
@@ -2079,6 +2079,14 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@stablelib/wipe/-/wipe-1.0.1.tgz#d21401f1d59ade56a62e139462a97f104ed19a36"
|
resolved "https://registry.yarnpkg.com/@stablelib/wipe/-/wipe-1.0.1.tgz#d21401f1d59ade56a62e139462a97f104ed19a36"
|
||||||
integrity sha512-WfqfX/eXGiAd3RJe4VU2snh/ZPwtSjLG4ynQ/vYzvghTh7dHFcI1wl+nrkWG6lGhukOxOsUHfv8dUXr58D0ayg==
|
integrity sha512-WfqfX/eXGiAd3RJe4VU2snh/ZPwtSjLG4ynQ/vYzvghTh7dHFcI1wl+nrkWG6lGhukOxOsUHfv8dUXr58D0ayg==
|
||||||
|
|
||||||
|
"@streetwritersco/tinymce-plugins@^1.0.0":
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@streetwritersco/tinymce-plugins/-/tinymce-plugins-1.0.0.tgz#05a5889a9cdad79b9ff01fc3f6d28febcebf2912"
|
||||||
|
integrity sha512-CBRQSF+6N2hIXb9mPnerkTb5Zr1qdQGzhNDcMT1l4ugUyvB2Yeb6dBy+tBgdeoJ3046jODDjPxUmQmSoGo3BGw==
|
||||||
|
dependencies:
|
||||||
|
highlight.js "^11.1.0"
|
||||||
|
rangy "^1.3.0"
|
||||||
|
|
||||||
"@styled-system/background@^5.1.2":
|
"@styled-system/background@^5.1.2":
|
||||||
version "5.1.2"
|
version "5.1.2"
|
||||||
resolved "https://registry.npmjs.org/@styled-system/background/-/background-5.1.2.tgz"
|
resolved "https://registry.npmjs.org/@styled-system/background/-/background-5.1.2.tgz"
|
||||||
@@ -8608,19 +8616,6 @@ normalize-url@^3.0.0:
|
|||||||
resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz"
|
resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz"
|
||||||
integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==
|
integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==
|
||||||
|
|
||||||
notes-core@../notes-core/:
|
|
||||||
version "6.8.0"
|
|
||||||
dependencies:
|
|
||||||
"@stablelib/blake2s" "^1.0.1"
|
|
||||||
dayjs "^1.10.6"
|
|
||||||
fast-sort "^2.0.1"
|
|
||||||
lean-he "^2.1.2"
|
|
||||||
no-internet "^1.5.2"
|
|
||||||
qclone "^1.0.4"
|
|
||||||
quill-delta-to-html "^0.12.0"
|
|
||||||
showdown "https://github.com/thecodrr/showdown"
|
|
||||||
spark-md5 "^3.0.1"
|
|
||||||
|
|
||||||
"notes-core@git+https://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:x-oauth-basic@github.com/streetwriters/notesnook-core.git":
|
"notes-core@git+https://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:x-oauth-basic@github.com/streetwriters/notesnook-core.git":
|
||||||
version "6.8.0"
|
version "6.8.0"
|
||||||
resolved "git+https://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:x-oauth-basic@github.com/streetwriters/notesnook-core.git#f3cc6b5dacac443966bccace43a7f98f13e367be"
|
resolved "git+https://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:x-oauth-basic@github.com/streetwriters/notesnook-core.git#f3cc6b5dacac443966bccace43a7f98f13e367be"
|
||||||
|
|||||||
Reference in New Issue
Block a user