mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-07-27 06:01:54 +03:00
Lexical: Added new WYSIWYG to chapter/book/shelf descriptions
This commit is contained in:
@ -1,23 +0,0 @@
|
||||
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];
|
||||
});
|
||||
}
|
||||
|
||||
}
|
32
resources/js/components/wysiwyg-input.ts
Normal file
32
resources/js/components/wysiwyg-input.ts
Normal file
@ -0,0 +1,32 @@
|
||||
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;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
@ -310,54 +310,6 @@ export function buildForEditor(options) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
|
@ -123,6 +123,8 @@ export function createBasicEditorInstance(container: HTMLElement, htmlContent: s
|
||||
|
||||
export class SimpleWysiwygEditorInterface {
|
||||
protected context: EditorUiContext;
|
||||
protected onChangeListeners: (() => void)[] = [];
|
||||
protected editorListenerTeardown: (() => void)|null = null;
|
||||
|
||||
constructor(context: EditorUiContext) {
|
||||
this.context = context;
|
||||
@ -132,6 +134,11 @@ export class SimpleWysiwygEditorInterface {
|
||||
return await getEditorContentAsHtml(this.context.editor);
|
||||
}
|
||||
|
||||
onChange(listener: () => void) {
|
||||
this.onChangeListeners.push(listener);
|
||||
this.startListeningToChanges();
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
focusEditor(this.context.editor);
|
||||
}
|
||||
@ -139,5 +146,20 @@ export class SimpleWysiwygEditorInterface {
|
||||
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();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -1,7 +1,3 @@
|
||||
@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>
|
||||
|
@ -1,7 +1,3 @@
|
||||
@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>
|
||||
|
@ -1,5 +1,4 @@
|
||||
<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>
|
||||
|
@ -1,7 +1,3 @@
|
||||
@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>
|
||||
|
Reference in New Issue
Block a user