Files
notesnook/apps/mobile/html/Web.bundle/site/init.js
2022-03-23 11:14:28 +05:00

681 lines
16 KiB
JavaScript
Executable File

attachTitleInputListeners();
autosize();
function reactNativeEventHandler(type, value) {
if (window.ReactNativeWebView) {
window.ReactNativeWebView.postMessage(
JSON.stringify({
type: type,
value: value,
sessionId: sessionId
})
);
}
}
let DEFAULT_FONT_SIZE = '12pt';
let EDITOR_SETTINGS = {
fontSize: 12,
directionality: 'ltr'
};
function loadSettings() {
let settings = localStorage.getItem('editorSettings');
if (settings) {
settings = JSON.parse(settings);
EDITOR_SETTINGS = settings;
}
}
function changeDirection(rtl) {
loadSettings();
EDITOR_SETTINGS.directionality = 'ltr';
if (rtl) {
EDITOR_SETTINGS.directionality = 'rtl';
}
localStorage.setItem('editorSettings', JSON.stringify(EDITOR_SETTINGS));
if (rtl) {
tinymce.activeEditor.execCommand('mceDirectionRTL');
} else {
tinymce.activeEditor.execCommand('mceDirectionLTR');
}
reactNativeEventHandler('editorSettings', EDITOR_SETTINGS);
}
function changeFontSize(size) {
loadSettings();
DEFAULT_FONT_SIZE = `${size}pt`;
EDITOR_SETTINGS.fontSize = size;
localStorage.setItem('editorSettings', JSON.stringify(EDITOR_SETTINGS));
addStyle();
reactNativeEventHandler('editorSettings', EDITOR_SETTINGS);
}
function loadFontSize() {
loadSettings();
DEFAULT_FONT_SIZE = EDITOR_SETTINGS.fontSize + 'pt';
reactNativeEventHandler('editorSettings', EDITOR_SETTINGS);
}
let changeTimer = null;
let styleElement;
function addStyle() {
if (!tinymce.activeEditor) return;
if (!styleElement) {
let doc = tinymce.activeEditor.dom.doc;
styleElement = doc.head.appendChild(document.createElement('style'));
}
styleElement.innerHTML = `
body {
font-size:${DEFAULT_FONT_SIZE} !important;
}
`;
}
let undoTimer = null;
function onUndoChange() {
clearTimeout(undoTimer);
undoTimer = setTimeout(function () {
reactNativeEventHandler('history', {
undo: tinymce.activeEditor.undoManager.hasUndo(),
redo: tinymce.activeEditor.undoManager.hasRedo()
});
}, 1000);
}
function init_callback(_editor) {
editor = _editor;
setTheme();
editor.on('SelectionChange', function (e) {
selectchange();
});
editor.on('ClearUndos', onUndoChange);
editor.on('Undo', onUndoChange);
editor.on('Redo', onUndoChange);
editor.on('TypingUndos', onUndoChange);
editor.on('BeforeAddUndo', onUndoChange);
editor.on('AddUndo', onUndoChange);
editor.on('cut', function () {
onChange({ type: 'cut' });
onUndoChange();
});
editor.on('copy', onUndoChange);
editor.on('paste', function () {
onChange({ type: 'paste' });
});
editor.on('focus', function () {
reactNativeEventHandler('focus', 'editor');
});
editor.on('tap', function (e) {
if (e.target.classList.contains('mce-content-body') && !e.target.innerText.length > 0) {
e.preventDefault();
}
});
editor.on('ScrollIntoView', function (e) {
e.preventDefault();
e.elm.scrollIntoView({
behavior: 'smooth',
block: 'nearest'
});
});
editor.on('input ExecCommand ObjectResized Redo Undo ListMutation', onChange);
editor.on('keyup', function (e) {
if (e.key !== 'Backspace') return;
onChange(e);
});
}
const plugins = [
'checklist advlist autolink textpattern hr lists link noneditable image bettertable',
'searchreplace codeblock inlinecode keyboardquirks attachmentshandler collapsibleheaders',
'media imagetools table paste wordcount autoresize directionality blockescape contenthandler'
];
let isSafari = navigator.vendor.match(/apple/i);
let margins = '';
if (isSafari) {
margins = `margin-left:12px !important;
margin-right:12px !important;`;
}
const content_style = `
body {
font-family:"Open Sans";
overflow-x: hidden !important;
${margins}
}
span.diff-del {
background-color: #FDB0C0;
}
span.diff-ins {
background-color: #CAFFFB;
}
pre.codeblock {
overflow-x:auto;
}
img,
video {
max-width:100% !important;
height:auto !important;
border-radius:5px !important;
margin-bottom:10px;
}
.tox .tox-edit-area__iframe {
background-color:transparent !important;
}
.tox .tox-tbtn--select {
min-width: 120px;
}
body {
background-color:transparent !important;
font-size:${DEFAULT_FONT_SIZE}
}
.mce-preview-object,
iframe {
max-width:100% !important;
background-color:transparent !important;
height:auto !important;
border-radius:5px !important;
}
h1,
h2,
h3,
h4,
h5,
h6,
strong {
font-weight:600 !important;
position:relative;
padding-left:10px;
}
h1::before,
h2::before,
h3::before,
h4::before,
h5::before,
h6::before {
opacity: 1;
cursor: row-resize;
margin-right: 7px;
margin-left: -15px;
width: 24px;
height: 24px;
display: inline-block;
border: none;
position:absolute;
margin-left: -25px;
}
h1::before {
top:2px;
}
h2::before {
top:5px;
}
h3::before {
top:2px;
}
h4::before {
top:0px;
}
h5::before {
top:0px;
width: 20px;
height: 20px;
}
h6::before {
top:-1px;
width: 18px;
height: 18px;
}
.h {
display: none !important;
}
`;
function tableCellNodeOptions() {
let node = findNodeParent('td');
if (!node) {
node = findNodeParent('th');
}
if (!node) return;
let properties = {
width: node.style.width,
height: node.style.height,
backgroundColor: node.style.backgroundColor,
cellType: tinymce.activeEditor.queryCommandValue('mceTableCellType'),
colType: tinymce.activeEditor.queryCommandValue('mceTableColType')
};
reactNativeEventHandler('tablecelloptions', properties);
}
function findNodeParent(nodeName) {
let node = editor.selection.getNode();
let levels = 5;
for (let i = 0; i < levels; i++) {
if (!node) return;
if (node.nodeName.toLowerCase() === nodeName) {
return node;
} else {
node = node.parentNode;
}
}
return null;
}
function tableRowNodeOptions() {
let node = findNodeParent('tr');
if (node) {
let properties = {
backgroundColor: node.style.backgroundColor,
rowType: tinymce.activeEditor.queryCommandValue('mceTableRowType')
};
reactNativeEventHandler('tablerowoptions', properties);
}
}
function init_tiny(size) {
loadFontSize();
tinymce.init({
selector: '#tiny_textarea',
menubar: false,
min_height: size,
directionality: EDITOR_SETTINGS.directionality,
skin_url: 'dist/skins/notesnook',
content_css: 'dist/skins/notesnook',
attachmenthandler_download_attachment: function (hash) {
reactNativeEventHandler('attachment_download', hash);
},
custom_undo_redo_levels: 10,
plugins: plugins,
toolbar: false,
keep_styles: false,
paste_data_images: true,
statusbar: false,
textpattern_patterns: markdownPatterns,
contextmenu: false,
extended_valid_elements: `img[*|src=placeholder.svg]`,
invalid_styles: {
span: `--progress`
},
content_style: content_style,
browser_spellcheck: true,
autoresize_bottom_margin: 120,
table_toolbar:
'tcellprops trowprops | tableinsertrowafter tableinsertcolafter tabledeleterow tabledeletecol | tableconfig',
imagetools_toolbar: 'imagedownload | rotateleft rotateright flipv fliph | imageopts ',
placeholder: 'Start writing your note here',
object_resizing: true,
table_responsive_width: false,
table_sizing_mode: 'fixed',
table_column_resizing: 'resizetable',
resize: true,
mobile: {
resize: false,
object_resizing: false
},
image_description: false,
image_caption: false,
media_dimensions: false,
font_formats:
'Times New Roman=times new roman,times;' +
'Serif=serif;' +
'Open Sans=open sans;' +
'Classic=courier new;' +
'Mono=monospace;',
paste_postprocess: function (_, args) {
try {
window.processPastedContent(args.node);
} catch (e) {
console.error(e);
}
},
init_instance_callback: init_callback,
setup: setup_tiny
});
}
function setup_tiny(_editor) {
editor = _editor;
editor.ui.registry.addButton('deleteimage', {
icon: 'remove',
tooltip: 'Remove image',
onAction: function () {
editor.undoManager.transact(function () {
tinymce.activeEditor.execCommand('Delete');
});
},
onclick: function () {
editor.undoManager.transact(function () {
tinymce.activeEditor.execCommand('Delete');
});
}
});
editor.on('init', function (e) {
reactNativeEventHandler('status', true);
});
editor.ui.registry.addButton('deletevideo', {
icon: 'remove',
tooltip: 'Remove iframe',
onAction: function () {
editor.undoManager.transact(function () {
tinymce.activeEditor.execCommand('Delete');
});
},
onclick: function () {
editor.undoManager.transact(function () {
tinymce.activeEditor.execCommand('Delete');
});
}
});
editor.ui.registry.addContextToolbar('iframecontrols', {
predicate: function (node) {
return node.getAttribute('data-mce-object') === 'iframe';
},
items: 'deletevideo',
position: 'node',
scope: 'node'
});
editor.ui.registry.addButton('imageopts', {
icon: 'image-options',
tooltip: 'Image properties',
onAction: function () {
reactNativeEventHandler('imageoptions');
}
});
editor.ui.registry.addButton('tableconfig', {
icon: 'more-drawer',
tooltip: 'Table properties',
onAction: function (e) {
reactNativeEventHandler('tableconfig');
}
});
editor.ui.registry.addButton('trowprops', {
icon: 'table-row-properties',
tooltip: 'Row properties',
onAction: function (e) {
tableRowNodeOptions();
editor.blur();
}
});
editor.ui.registry.addButton('tcellprops', {
icon: 'table-cell-properties',
tooltip: 'Cell properties',
onAction: function (e) {
tableCellNodeOptions();
editor.blur();
}
});
editor.ui.registry.addButton('imagedownload', {
icon: 'save',
tooltip: 'Download image',
onAction: function (e) {
let node = tinymce.activeEditor.selection.getNode();
if (node.tagName === 'IMG' && node.dataset && node.dataset.hash) {
window.ReactNativeWebView.postMessage(
JSON.stringify({
type: 'attachment_download',
value: node.dataset.hash,
sessionId: sessionId
})
);
}
}
});
editor.ui.registry.addButton('imagepreview', {
icon: 'fullscreen',
tooltip: 'Preview image',
onAction: function () {
if (tinymce.activeEditor.selection.getNode().tagName === 'IMG') {
var xhr = new XMLHttpRequest();
xhr.responseType = 'blob';
xhr.onload = function () {
var recoveredBlob = xhr.response;
var reader = new FileReader();
reader.onload = function () {
var blobAsDataUrl = reader.result;
reactNativeEventHandler('imagepreview', blobAsDataUrl);
reader.abort();
xhr.abort();
};
reader.readAsDataURL(recoveredBlob);
};
xhr.open('GET', tinymce.activeEditor.selection.getNode().getAttribute('src'));
xhr.send();
}
}
});
}
let prevCount = 0;
function delay(base = 0) {
if (prevCount < 20000) return base + 100;
if (prevCount > 20000 && prevCount < 40000) return base + 250;
if (prevCount > 40000 && prevCount < 70000) return base + 500;
if (prevCount > 70000) return base + 1000;
}
let inputKeyTimer = 0;
function scrollSelectionIntoView(event) {
if (navigator.vendor.match(/apple/i)) return;
if (
event.type === 'input' &&
event.inputType !== 'deleteContentBackward' &&
event.data &&
event.data.endsWith('\n')
) {
clearTimeout(inputKeyTimer);
inputKeyTimer = setTimeout(function () {
let node = editor.selection.getNode();
if (node) {
node.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
}, 1);
}
}
let noteedited = false;
const onChange = function (event) {
if (event.type && event.type.toLowerCase() === 'execcommand') {
if (
event.command.toLowerCase() === 'mcefocus' ||
event.command.toLowerCase() === 'mcerepaint' ||
event.command.toLowerCase() === 'mcedirectionrtl' ||
event.command.toLowerCase() === 'mcedirectionltr'
) {
return;
}
}
scrollSelectionIntoView(event);
if (isLoading) {
isLoading = false;
}
if (prevCount === 0) {
updateCount(0);
}
if (prevCount === 0 && event.type !== 'paste') return;
if (event.type !== 'compositionend') {
if (!noteedited) {
noteedited = true;
reactNativeEventHandler('noteedited');
}
}
clearTimeout(changeTimer);
changeTimer = null;
changeTimer = setTimeout(function () {
editor
.getHTML()
.then(function (html) {
reactNativeEventHandler('tiny', html);
})
.catch(function (e) {
reactNativeEventHandler('tinyerror', {
message: e?.message,
stack: e?.stack
});
});
onUndoChange();
selectchange();
}, delay());
};
let countTimer;
function updateCount(timer = 1000) {
countTimer = null;
if (!timer) {
let count = editor.countWords() || 0;
info = document.querySelector('.info-bar');
info.querySelector('#infowords').innerText = count + ' words';
prevCount = count;
} else {
countTimer = setTimeout(function () {
let count = editor.countWords() | 0;
info = document.querySelector('.info-bar');
info.querySelector('#infowords').innerText = count + ' words';
prevCount = count;
}, delay(timer));
}
}
function getNodeColor(element) {
if (element.style.color && element.style.color !== '') {
return element.style.color;
}
return null;
}
function getNodeBg(element) {
if (element.style.backgroundColor && element.style.backgroundColor !== '') {
return element.style.backgroundColor;
}
return null;
}
let selectionTimer = null;
function selectchange() {
clearTimeout(selectionTimer);
selectionTimer = null;
selectionTimer = setTimeout(function () {
updateCount();
let formats = Object.keys(editor.formatter.get());
let currentFormats = {};
editor.formatter.matchAll(formats).forEach(function (format) {
currentFormats[format] = true;
});
let node = editor.selection.getNode();
currentFormats.hilitecolor = getNodeBg(node);
currentFormats.forecolor = getNodeColor(node);
if (!currentFormats.hilitecolor || !currentFormats.forecolor) {
if (!/^(LI|UL|OL|DL|P|DIV)$/.test(node.nodeName)) {
for (var i = 0; i < node.children.length; i++) {
let item = editor.selection.getNode().children.item(i);
currentFormats.hilitecolor = getNodeBg(item);
currentFormats.forecolor = getNodeColor(item);
}
}
}
let range = editor.selection.getRng();
currentFormats.current = {
index: range.startOffset,
length: range.endOffset - range.startOffset
};
currentFormats.fontsize = editor.selection.getNode().style.fontSize;
if (currentFormats.fontsize === '') {
currentFormats.fontsize = DEFAULT_FONT_SIZE;
if (currentFormats.h2) {
currentFormats.fontsize = '18pt';
}
if (currentFormats.h3) {
currentFormats.fontsize = '14pt';
}
if (currentFormats.h4) {
currentFormats.fontsize = '12pt';
}
if (currentFormats.h5) {
currentFormats.fontsize = '10pt';
}
if (currentFormats.h6) {
currentFormats.fontsize = '8pt';
}
}
if (node.nodeName === 'A') {
currentFormats.link = node.getAttribute('href');
}
let isLinkNode = node.closest('a');
if (isLinkNode) {
currentFormats.link = isLinkNode.getAttribute('href');
}
currentFormats.fontname = editor.selection.getNode().style.fontFamily;
if (/^(LI|UL|OL|DL)$/.test(node.nodeName)) {
let listElm = editor.selection.getNode();
if (listElm.nodeName === 'LI') {
listElm = editor.dom.getParent(listElm, 'ol,ul');
}
let style = editor.dom.getStyle(listElm, 'listStyleType');
if (style === '') {
style = 'default';
}
if (listElm.nodeName === 'OL') {
currentFormats.ol = style;
} else {
if (!listElm) return;
if (listElm.className === 'tox-checklist') {
currentFormats.cl = true;
} else {
currentFormats.ul = style;
}
}
}
currentFormats.node = editor.selection.getNode().nodeName;
reactNativeEventHandler('selectionchange', currentFormats);
}, 50);
}