feat: use tinymce plugins from the npm package

This commit is contained in:
thecodrr
2021-07-28 12:00:15 +05:00
parent fb24df460b
commit cfd99004b9
19 changed files with 34 additions and 3558 deletions

View File

@@ -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",

View File

@@ -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;
}

View File

@@ -1 +0,0 @@
import "./plugin";

View File

@@ -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 = "";
}
});
});
})();

View File

@@ -1 +0,0 @@
import "./plugin";

View File

@@ -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, "") || "&nbsp;";
editor.undoManager.transact(function () {
editor.execCommand(
"mceInsertContent",
false,
`<code spellcheck="false">${content}</code>&nbsp;`
);
});
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 || "";
}

View File

@@ -1 +0,0 @@
import "./plugin";

View File

@@ -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);
}
});
});
})();

View File

@@ -1 +0,0 @@
import "./plugin";

File diff suppressed because it is too large Load Diff

View File

@@ -1 +0,0 @@
import "./plugin";

View File

@@ -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();
});
});
})();

View File

@@ -1 +0,0 @@
import "./plugins";

View File

@@ -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}`);
}
}
});
});
})();

View File

@@ -1 +0,0 @@
import "./plugin"

View File

@@ -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();
}());

View File

@@ -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);
}

View File

@@ -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) => {

View File

@@ -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"