132 lines
3.9 KiB
Vue
132 lines
3.9 KiB
Vue
<template>
|
|
<div class="space-y-3" style="overflow: visible;">
|
|
<div style="overflow: visible;">
|
|
<label class="block text-sm font-medium text-foreground mb-1">
|
|
Текст <span class="text-danger">*</span>
|
|
</label>
|
|
<textarea
|
|
:id="editorId"
|
|
:value="modelValue.content"
|
|
rows="8"
|
|
required
|
|
class="w-full px-3 py-2 border border-layer-line rounded-lg bg-white text-foreground placeholder-muted-foreground-1 focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent resize-y"
|
|
></textarea>
|
|
<p v-if="loading" class="mt-1 text-xs text-primary">
|
|
Загрузка редактора...
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
let editorCounter = 0;
|
|
|
|
export default {
|
|
name: 'ParagraphBlock',
|
|
props: {
|
|
modelValue: {
|
|
type: Object,
|
|
required: true
|
|
}
|
|
},
|
|
emits: ['update:modelValue', 'update'],
|
|
data() {
|
|
return {
|
|
editorId: `paragraph-editor-${++editorCounter}`,
|
|
editor: null,
|
|
loading: true
|
|
};
|
|
},
|
|
mounted() {
|
|
this.waitForTinyMCE();
|
|
},
|
|
beforeUnmount() {
|
|
this.destroyEditor();
|
|
},
|
|
methods: {
|
|
update(field, value) {
|
|
this.$emit('update:modelValue', {
|
|
...this.modelValue,
|
|
[field]: value
|
|
});
|
|
this.$emit('update');
|
|
},
|
|
waitForTinyMCE() {
|
|
if (typeof tinymce !== 'undefined') {
|
|
this.initEditor();
|
|
return;
|
|
}
|
|
|
|
// Ждем загрузки TinyMCE с таймаутом
|
|
let attempts = 0;
|
|
const maxAttempts = 50; // 5 секунд
|
|
const interval = setInterval(() => {
|
|
attempts++;
|
|
if (typeof tinymce !== 'undefined') {
|
|
clearInterval(interval);
|
|
this.initEditor();
|
|
} else if (attempts >= maxAttempts) {
|
|
clearInterval(interval);
|
|
this.loading = false;
|
|
console.error('TinyMCE не загрузился в течение 5 секунд');
|
|
}
|
|
}, 100);
|
|
},
|
|
initEditor() {
|
|
this.loading = true;
|
|
|
|
tinymce.init({
|
|
selector: `#${this.editorId}`,
|
|
license_key: 'gpl',
|
|
min_height: 400,
|
|
autoresize_bottom_margin: 30,
|
|
autoresize_overflow_padding: 30,
|
|
menubar: false,
|
|
statusbar: true,
|
|
branding: false,
|
|
plugins: [
|
|
'advlist', 'autolink', 'lists', 'link', 'image', 'charmap', 'preview',
|
|
'anchor', 'searchreplace', 'visualblocks', 'code', 'fullscreen',
|
|
'insertdatetime', 'media', 'table', 'paste', 'code', 'help', 'wordcount',
|
|
'autoresize'
|
|
],
|
|
invalid_styles: 'all',
|
|
paste_as_text: true,
|
|
paste_remove_styles: true,
|
|
paste_remove_styles_if_webkit: true,
|
|
paste_remove_spans: true,
|
|
paste_strip_class_attributes: 'all',
|
|
paste_merge_formats: true,
|
|
paste_word_valid_elements: 'b,strong,i,em,p,br,ul,ol,li,span',
|
|
paste_data_images: false,
|
|
toolbar: 'undo redo | blocks | ' +
|
|
'bold italic forecolor link | alignleft aligncenter ' +
|
|
'alignright alignjustify | bullist numlist outdent indent | ' +
|
|
'removeformat | help | fullscreen',
|
|
content_style: 'body { font-family: Inter, -apple-system, sans-serif; font-size: 14px; }',
|
|
setup: (editor) => {
|
|
this.editor = editor;
|
|
editor.on('init', () => {
|
|
editor.setContent(this.modelValue.content || '');
|
|
this.loading = false;
|
|
this.update('content', editor.getContent());
|
|
});
|
|
editor.on('change', () => {
|
|
this.update('content', editor.getContent());
|
|
});
|
|
editor.on('Remove', () => {
|
|
this.editor = null;
|
|
});
|
|
}
|
|
});
|
|
},
|
|
destroyEditor() {
|
|
if (this.editor && typeof tinymce !== 'undefined') {
|
|
tinymce.remove(this.editor);
|
|
this.editor = null;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</script>
|