mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-07-25 18:42:01 +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
|
* @typedef {Object} WysiwygConfigOptions
|
||||||
* @property {Element} containerElement
|
* @property {Element} containerElement
|
||||||
|
@ -123,6 +123,8 @@ export function createBasicEditorInstance(container: HTMLElement, htmlContent: s
|
|||||||
|
|
||||||
export class SimpleWysiwygEditorInterface {
|
export class SimpleWysiwygEditorInterface {
|
||||||
protected context: EditorUiContext;
|
protected context: EditorUiContext;
|
||||||
|
protected onChangeListeners: (() => void)[] = [];
|
||||||
|
protected editorListenerTeardown: (() => void)|null = null;
|
||||||
|
|
||||||
constructor(context: EditorUiContext) {
|
constructor(context: EditorUiContext) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
@ -132,6 +134,11 @@ export class SimpleWysiwygEditorInterface {
|
|||||||
return await getEditorContentAsHtml(this.context.editor);
|
return await getEditorContentAsHtml(this.context.editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onChange(listener: () => void) {
|
||||||
|
this.onChangeListeners.push(listener);
|
||||||
|
this.startListeningToChanges();
|
||||||
|
}
|
||||||
|
|
||||||
focus(): void {
|
focus(): void {
|
||||||
focusEditor(this.context.editor);
|
focusEditor(this.context.editor);
|
||||||
}
|
}
|
||||||
@ -139,5 +146,20 @@ export class SimpleWysiwygEditorInterface {
|
|||||||
remove() {
|
remove() {
|
||||||
this.context.editorDOM.remove();
|
this.context.editorDOM.remove();
|
||||||
this.context.manager.teardown();
|
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() }}
|
{{ csrf_field() }}
|
||||||
<div class="form-group title-input">
|
<div class="form-group title-input">
|
||||||
<label for="name">{{ trans('common.name') }}</label>
|
<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() }}
|
{{ csrf_field() }}
|
||||||
<div class="form-group title-input">
|
<div class="form-group title-input">
|
||||||
<label for="name">{{ trans('common.name') }}</label>
|
<label for="name">{{ trans('common.name') }}</label>
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
<textarea component="wysiwyg-input"
|
<textarea component="wysiwyg-input"
|
||||||
option:wysiwyg-input:language="{{ $locale->htmlLang() }}"
|
|
||||||
option:wysiwyg-input:text-direction="{{ $locale->htmlDirection() }}"
|
option:wysiwyg-input:text-direction="{{ $locale->htmlDirection() }}"
|
||||||
id="description_html" name="description_html" rows="5"
|
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>
|
@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() }}
|
{{ csrf_field() }}
|
||||||
<div class="form-group title-input">
|
<div class="form-group title-input">
|
||||||
<label for="name">{{ trans('common.name') }}</label>
|
<label for="name">{{ trans('common.name') }}</label>
|
||||||
|
Reference in New Issue
Block a user