+++ /dev/null
-import {Component} from './component';
-import {buildForInput} from '../wysiwyg-tinymce/config';
-
-export class WysiwygInput extends Component {
-
- setup() {
- this.elem = this.$el;
-
- const config = buildForInput({
- language: this.$opts.language,
- containerElement: this.elem,
- darkMode: document.documentElement.classList.contains('dark-mode'),
- textDirection: this.$opts.textDirection,
- translations: {},
- translationMap: window.editor_translations,
- });
-
- window.tinymce.init(config).then(editors => {
- this.editor = editors[0];
- });
- }
-
-}
--- /dev/null
+import {Component} from './component';
+import {el} from "../wysiwyg/utils/dom";
+import {SimpleWysiwygEditorInterface} from "../wysiwyg";
+
+export class WysiwygInput extends Component {
+ private elem!: HTMLTextAreaElement;
+ private wysiwygEditor!: SimpleWysiwygEditorInterface;
+ private textDirection!: string;
+
+ async setup() {
+ this.elem = this.$el as HTMLTextAreaElement;
+ this.textDirection = this.$opts.textDirection;
+
+ type WysiwygModule = typeof import('../wysiwyg');
+ const wysiwygModule = (await window.importVersioned('wysiwyg')) as WysiwygModule;
+ const container = el('div', {class: 'comment-editor-container'});
+ this.elem.parentElement?.appendChild(container);
+ this.elem.hidden = true;
+
+ this.wysiwygEditor = wysiwygModule.createBasicEditorInstance(container as HTMLElement, this.elem.value, {
+ darkMode: document.documentElement.classList.contains('dark-mode'),
+ textDirection: this.textDirection,
+ translations: (window as unknown as Record<string, Object>).editor_translations,
+ });
+
+ this.wysiwygEditor.onChange(() => {
+ this.wysiwygEditor.getContentAsHtml().then(html => {
+ this.elem.value = html;
+ });
+ });
+ }
+}
};
}
-/**
- * @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|target],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
export class SimpleWysiwygEditorInterface {
protected context: EditorUiContext;
+ protected onChangeListeners: (() => void)[] = [];
+ protected editorListenerTeardown: (() => void)|null = null;
constructor(context: EditorUiContext) {
this.context = context;
return await getEditorContentAsHtml(this.context.editor);
}
+ onChange(listener: () => void) {
+ this.onChangeListeners.push(listener);
+ this.startListeningToChanges();
+ }
+
focus(): void {
focusEditor(this.context.editor);
}
remove() {
this.context.editorDOM.remove();
this.context.manager.teardown();
+ if (this.editorListenerTeardown) {
+ this.editorListenerTeardown();
+ }
+ }
+
+ protected startListeningToChanges(): void {
+ if (this.editorListenerTeardown) {
+ return;
+ }
+
+ this.editorListenerTeardown = this.context.editor.registerUpdateListener(() => {
+ for (const listener of this.onChangeListeners) {
+ listener();
+ }
+ });
}
}
\ No newline at end of file
-@push('head')
- <script src="{{ versioned_asset('libs/tinymce/tinymce.min.js') }}" nonce="{{ $cspNonce }}"></script>
-@endpush
-
{{ csrf_field() }}
<div class="form-group title-input">
<label for="name">{{ trans('common.name') }}</label>
-@push('head')
- <script src="{{ versioned_asset('libs/tinymce/tinymce.min.js') }}" nonce="{{ $cspNonce }}"></script>
-@endpush
-
{{ csrf_field() }}
<div class="form-group title-input">
<label for="name">{{ trans('common.name') }}</label>
<textarea component="wysiwyg-input"
- option:wysiwyg-input:language="{{ $locale->htmlLang() }}"
option:wysiwyg-input:text-direction="{{ $locale->htmlDirection() }}"
id="description_html" name="description_html" rows="5"
@if($errors->has('description_html')) class="text-neg" @endif>@if(isset($model) || old('description_html')){{ old('description_html') ?? $model->descriptionHtml()}}@endif</textarea>
-@push('head')
- <script src="{{ versioned_asset('libs/tinymce/tinymce.min.js') }}" nonce="{{ $cspNonce }}"></script>
-@endpush
-
{{ csrf_field() }}
<div class="form-group title-input">
<label for="name">{{ trans('common.name') }}</label>