import {listenForDragAndPaste} from './drop-paste-handling';
import {getPrimaryToolbar, registerAdditionalToolbars} from './toolbars';
import {registerCustomIcons} from './icons';
+import {setupFilters} from './filters';
import {getPlugin as getCodeeditorPlugin} from './plugin-codeeditor';
import {getPlugin as getDrawioPlugin} from './plugin-drawio';
import {getPlugin as getAboutPlugin} from './plugins-about';
import {getPlugin as getDetailsPlugin} from './plugins-details';
import {getPlugin as getTasklistPlugin} from './plugins-tasklist';
+import {handleEmbedAlignmentChanges} from './fixes';
const styleFormats = [
{title: 'Large Header', format: 'h2', preview: 'color: blue;'},
];
const formats = {
- alignleft: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-left'},
- aligncenter: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-center'},
- alignright: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-right'},
+ alignleft: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img,iframe,video,span', classes: 'align-left'},
+ aligncenter: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img,iframe,video,span', classes: 'align-center'},
+ alignright: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img,iframe,video,span', classes: 'align-right'},
calloutsuccess: {block: 'p', exact: true, attributes: {class: 'callout success'}},
calloutinfo: {block: 'p', exact: true, attributes: {class: 'callout info'}},
calloutwarning: {block: 'p', exact: true, attributes: {class: 'callout warning'}},
if (meta.filetype === 'file') {
/** @type {EntitySelectorPopup} * */
const selector = window.$components.first('entity-selector-popup');
+ const selectionText = this.selection.getContent({format: 'text'}).trim();
selector.show(entity => {
callback(entity.link, {
text: entity.name,
title: entity.name,
});
+ }, {
+ initialValue: selectionText,
+ searchEndpoint: '/search/entity-selector',
+ entityTypes: 'page,book,chapter,bookshelf',
+ entityPermission: 'view',
});
}
}
/**
- * Fetch custom HTML head content from the parent page head into the editor.
+ * Fetch custom HTML head content nodes from the outer page head
+ * and add them to the given editor document.
+ * @param {Document} editorDoc
*/
-function fetchCustomHeadContent() {
+function addCustomHeadContent(editorDoc) {
const headContentLines = document.head.innerHTML.split('\n');
const startLineIndex = headContentLines.findIndex(line => line.trim() === '<!-- Start: custom user content -->');
const endLineIndex = headContentLines.findIndex(line => line.trim() === '<!-- End: custom user content -->');
if (startLineIndex === -1 || endLineIndex === -1) {
- return '';
+ return;
}
- return headContentLines.slice(startLineIndex + 1, endLineIndex).join('\n');
-}
-/**
- * Setup a serializer filter for <br> tags to ensure they're not rendered
- * within code blocks and that we use newlines there instead.
- * @param {Editor} editor
- */
-function setupBrFilter(editor) {
- editor.serializer.addNodeFilter('br', nodes => {
- for (const node of nodes) {
- if (node.parent && node.parent.name === 'code') {
- const newline = window.tinymce.html.Node.create('#text');
- newline.value = '\n';
- node.replace(newline);
- }
- }
- });
+ const customHeadHtml = headContentLines.slice(startLineIndex + 1, endLineIndex).join('\n');
+ const el = editorDoc.createElement('div');
+ el.innerHTML = customHeadHtml;
+
+ editorDoc.head.append(...el.children);
}
/**
});
editor.on('PreInit', () => {
- setupBrFilter(editor);
+ setupFilters(editor);
});
+ handleEmbedAlignmentChanges(editor);
+
// Custom handler hook
window.$events.emitPublic(options.containerElement, 'editor-tinymce::setup', {editor});
* @param {WysiwygConfigOptions} options
* @return {Object}
*/
-export function build(options) {
+export function buildForEditor(options) {
// Set language
window.tinymce.addI18n(options.language, options.translationMap);
'-doc-root[doc-root|#text]',
'-li[details]',
'+code-block[pre]',
- '+doc-root[p|h1|h2|h3|h4|h5|h6|blockquote|code-block|div]',
+ '+doc-root[p|h1|h2|h3|h4|h5|h6|blockquote|code-block|div|hr]',
].join(','),
plugins: gatherPlugins(options),
contextmenu: false,
}
},
init_instance_callback(editor) {
- const head = editor.getDoc().querySelector('head');
- head.innerHTML += fetchCustomHeadContent();
+ addCustomHeadContent(editor.getDoc());
},
setup(editor) {
registerCustomIcons(editor);
};
}
+/**
+ * @param {WysiwygConfigOptions} options
+ * @return {RawEditorOptions}
+ */
+export function buildForInput(options) {
+ // Set language
+ window.tinymce.addI18n(options.language, options.translationMap);
+
+ // BookStack Version
+ const version = document.querySelector('script[src*="/dist/app.js"]').getAttribute('src').split('?version=')[1];
+
+ // Return config object
+ return {
+ width: '100%',
+ height: '185px',
+ target: options.containerElement,
+ cache_suffix: `?version=${version}`,
+ content_css: [
+ window.baseUrl('/dist/styles.css'),
+ ],
+ branding: false,
+ skin: options.darkMode ? 'tinymce-5-dark' : 'tinymce-5',
+ body_class: 'wysiwyg-input',
+ browser_spellcheck: true,
+ relative_urls: false,
+ language: options.language,
+ directionality: options.textDirection,
+ remove_script_host: false,
+ document_base_url: window.baseUrl('/'),
+ end_container_on_empty_block: true,
+ remove_trailing_brs: false,
+ statusbar: false,
+ menubar: false,
+ plugins: 'link autolink lists',
+ contextmenu: false,
+ toolbar: 'bold italic link bullist numlist',
+ content_style: getContentStyle(options),
+ file_picker_types: 'file',
+ valid_elements: 'p,a[href|title],ol,ul,li,strong,em,br',
+ file_picker_callback: filePickerCallback,
+ init_instance_callback(editor) {
+ addCustomHeadContent(editor.getDoc());
+
+ editor.contentDocument.documentElement.classList.toggle('dark-mode', options.darkMode);
+ },
+ };
+}
+
/**
* @typedef {Object} WysiwygConfigOptions
* @property {Element} containerElement