import { tools } from '@tools'; import { CTitleBanner } from '../CTitleBanner'; import { defineComponent, onMounted, onUnmounted, ref, toRef, watch } from 'vue'; import { useQuasar } from 'quasar'; import { useI18n } from 'vue-i18n'; export default defineComponent({ name: 'CMyEditor', components: { CTitleBanner }, props: { title: { type: String, required: false, default: '', }, value: { type: String, required: false, default: '', }, myclass: { type: String, required: false, default: '', }, customStyles: { type: String, required: false, default: '', }, showButtons: { type: Boolean, required: false, default: true, }, canModify: { type: Boolean, required: false, default: false, }, hideTools: { type: Boolean, required: false, default: false, }, maxlength: { type: Number, required: false, default: 0, }, startInCodeMode: { type: Boolean, required: false, default: false, }, }, setup(props, { emit }) { const $q = useQuasar(); const { t } = useI18n(); const editorRef = ref(null); const editor = ref(''); const characterCount = ref(0); //const myvalue = toRef(props, 'value') const myvalue = ref(''); const mycolor = ref(''); const editorId = ref( `editor-${Date.now()}-${Math.random().toString(36).substr(2, 9)}` ); const styleElement = ref(null); // Watch per applicare stili personalizzati watch( () => props.customStyles, (newStyles) => { if (newStyles && editorRef.value) { applyCustomStyles(newStyles); } } ); const myfonts = ref({ arial: 'Arial', arial_black: 'Arial Black', AGaramondProRegular: 'AGaramondPro-Regular', comic_sans: 'Comic Sans MS', courier_new: 'Courier New', impact: 'Impact', lucida_grande: 'Lucida Grande', times_new_roman: 'Times New Roman', verdana: 'Verdana', }); const showtools = ref(false); const toolbarcomp = ref([ ['left', 'center', 'right', 'justify'], ['bold', 'italic', 'underline', 'strike'], ['token', 'hr', 'link', 'custom_btn', 'print', 'fullscreen'], [ { label: $q.lang.editor.formatting, icon: $q.iconSet.editor.formatting, list: 'no-icons', options: ['p', 'h4', 'h5', 'h6', 'code'], }, { label: $q.lang.editor.fontSize, icon: $q.iconSet.editor.fontSize, fixedLabel: true, fixedIcon: true, list: 'no-icons', options: ['size-1', 'size-2', 'size-3', 'size-4', 'size-5', 'size-6', 'size-7'], }, { label: $q.lang.editor.defaultFont, icon: $q.iconSet.editor.font, fixedIcon: true, list: 'no-icons', options: [ 'default_font', 'arial', 'arial_black', 'comic_sans', 'courier_new', 'impact', 'lucida_grande', 'times_new_roman', 'verdana', ], }, 'removeFormat', ], ['quote', 'unordered', 'ordered', 'outdent', 'indent'], ['undo', 'redo', 'viewsource'], ]); watch( () => props.value, (newval, oldval) => { if (props.value === undefined) myvalue.value = ''; else myvalue.value = props.value; } ); // Funzione per applicare stili custom // ALTERNATIVA: Se vuoi applicare gli stili solo al contenuto dell'editor (più sicuro) function applyCustomStyles(styles: string) { // console.log('Applying custom styles:', styles); // Rimuovi style precedente if (styleElement.value && styleElement.value.parentNode) { styleElement.value.parentNode.removeChild(styleElement.value); } if (!styles) return; // Crea style element nel HEAD styleElement.value = document.createElement('style'); styleElement.value.setAttribute('type', 'text/css'); styleElement.value.setAttribute('data-editor-styles', editorId.value); // CSS con selettori super specifici usando l'ID univoco const css = ` [data-editor-id="${editorId.value}"] .q-editor__content { ${styles} } [data-editor-id="${editorId.value}"] .q-editor__content * { ${styles} } /* Selettori per classi custom nel contenuto */ [data-editor-id="${editorId.value}"] .q-editor__content .prova1 { color: red !important; } `; styleElement.value.textContent = css; document.head.appendChild(styleElement.value); // console.log('Style injected:', css); } function getTextLength(html: string) { // Crea un elemento temporaneo per convertire HTML in testo const div = document.createElement('div'); div.innerHTML = html; // Imposta l'HTML return div.innerText.length; // Restituisce la lunghezza del testo } function changeval(newval: any) { // console.log('myEditor: changeval', newval) characterCount.value = getTextLength(newval); // newval = newval.replace(/ /g, ' ') emit('update:value', newval); } function annulla() { emit('annulla', true); } function saveval() { // Converti i in myvalue.value = tools.convertinbspInSpazi(myvalue.value); // myvalue.value = tools.convertiTagHTMLPerBOT(myvalue.value) console.log('saveval', myvalue.value); emit('showandsave', myvalue.value); // emit('update:value', myvalue) } function setcolor() { document.execCommand('foreColor', false, mycolor.value); } /** * Capture the paste event, only allow plain-text, no images. * * see: https://stackoverflow.com/a/28213320 * * @param {object} evt - array of files * @author Daniel Thompson-Yvetot * @license MIT */ function pasteCapture(evt: any) { // let text, onPasteStripFormattingIEPaste // evt.preventDefault() // if (evt.originalEvent && evt.originalEvent.clipboardData.getData) { // text = evt.originalEvent.clipboardData.getData('text/plain') // $refs.editor_ref.runCmd('insertText', text) // } // else if (evt.clipboardData && evt.clipboardData.getData) { // text = evt.clipboardData.getData('text/plain') // $refs.editor_ref.runCmd('insertText', text) // } // else if (window.clipboardData && window.clipboardData.getData) { // if (!onPasteStripFormattingIEPaste) { // onPasteStripFormattingIEPaste = true // $refs.editor_ref.runCmd('ms-pasteTextOnly', text) // } // onPasteStripFormattingIEPaste = false // } } function mounted() { if (props.value === undefined) myvalue.value = ''; else myvalue.value = props.value; showtools.value = tools.getCookie('showtools', '0') === '1'; characterCount.value = getTextLength(myvalue.value); if (props.customStyles) { setTimeout(() => { applyCustomStyles(props.customStyles); }, 300); } if (props.startInCodeMode) { // Attiva modalità codice di default setTimeout(() => { if (editorRef.value) { editorRef.value.runCmd('viewsource'); } }, 100); } } function onPaste(evt: any) { // Let inputs do their thing, so we don't break pasting of links. if (evt.target.nodeName === 'INPUT') return; let text, onPasteStripFormattingIEPaste; evt.preventDefault(); evt.stopPropagation(); if (evt.originalEvent && evt.originalEvent.clipboardData.getData) { text = evt.originalEvent.clipboardData.getData('text/plain'); editorRef.value.runCmd('insertText', text); } else if (evt.clipboardData && evt.clipboardData.getData) { text = evt.clipboardData.getData('text/plain'); editorRef.value.runCmd('insertText', text); } /*else if (ClipboardEvent.clipboardData && ClipboardEvent.clipboardData.getData) { if (!onPasteStripFormattingIEPaste) { onPasteStripFormattingIEPaste = true editorRef.value.runCmd('ms-pasteTextOnly', text) } onPasteStripFormattingIEPaste = false }*/ } onMounted(mounted); // Cleanup quando componente viene distrutto onUnmounted(() => { if (styleElement.value && styleElement.value.parentNode) { styleElement.value.parentNode.removeChild(styleElement.value); } }); return { myfonts, toolbarcomp, editor, myvalue, mycolor, changeval, annulla, saveval, setcolor, pasteCapture, tools, onPaste, editorRef, showtools, characterCount, t, applyCustomStyles, editorId, }; }, });