- creato editor di Pagine (iniziato)
- fix: mancano i "t," su alcuni componenti...
This commit is contained in:
194
src/components/PageEditor/PageEditor.ts
Normal file
194
src/components/PageEditor/PageEditor.ts
Normal file
@@ -0,0 +1,194 @@
|
||||
import {
|
||||
defineComponent,
|
||||
ref,
|
||||
computed,
|
||||
onMounted,
|
||||
watch,
|
||||
onBeforeUnmount,
|
||||
toRaw,
|
||||
nextTick,
|
||||
} from 'vue';
|
||||
|
||||
import { useUserStore } from '@store/UserStore';
|
||||
import { useQuasar } from 'quasar';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { tools } from '@tools';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { reactive } from 'vue';
|
||||
import { IMyPage } from 'app/src/model';
|
||||
import IconPicker from '../IconPicker/IconPicker.vue';
|
||||
import { useGlobalStore } from 'app/src/store';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'PageEditor',
|
||||
components: { IconPicker },
|
||||
props: {
|
||||
modelValue: {
|
||||
type: Object as () => IMyPage,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
emits: ['update:modelValue', 'apply'],
|
||||
setup(props, { emit }) {
|
||||
const $q = useQuasar();
|
||||
const globalStore = useGlobalStore();
|
||||
const { mypage } = storeToRefs(globalStore);
|
||||
|
||||
// DRaft locale
|
||||
const draft = reactive<IMyPage>({ ...props.modelValue });
|
||||
|
||||
// UI helper: path mostrato con "/" iniziale
|
||||
const ui = reactive({
|
||||
pathText: toUiPath(draft.path),
|
||||
});
|
||||
|
||||
const saving = ref(false)
|
||||
const syncingFromProps = ref(false) // <-- FLAG anti-loop
|
||||
|
||||
// --- Watch input esterno: ricarica draft e UI path
|
||||
// --- Watch input esterno: ricarica draft e UI path (NO scritture nello store qui!)
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
async (v) => {
|
||||
syncingFromProps.value = true;
|
||||
Object.assign(draft, v || {});
|
||||
ui.pathText = toUiPath(draft.path);
|
||||
await nextTick();
|
||||
syncingFromProps.value = false;
|
||||
},
|
||||
{ deep: false }
|
||||
);
|
||||
|
||||
// --- Ogni modifica del draft: aggiorna store.mypage e emetti update:modelValue (solo se modifica nasce da UI)
|
||||
watch(
|
||||
draft,
|
||||
(val) => {
|
||||
if (syncingFromProps.value) return; // evita ricorsione
|
||||
upsertIntoStore(val, mypage.value);
|
||||
emit('update:modelValue', { ...val });
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
// --- Helpers path
|
||||
function toUiPath(storePath?: string) {
|
||||
const p = (storePath || '').trim();
|
||||
if (!p) return '/';
|
||||
return p.startsWith('/') ? p : `/${p}`;
|
||||
}
|
||||
function toStorePath(uiPath?: string) {
|
||||
const p = (uiPath || '').trim();
|
||||
if (!p) return '';
|
||||
return p.startsWith('/') ? p.slice(1) : p;
|
||||
}
|
||||
|
||||
function normalizeAndApplyPath() {
|
||||
// normalizza: niente spazi, minuscole, trattini
|
||||
let p = (ui.pathText || '/').trim();
|
||||
p = p.replace(/\s+/g, '-');
|
||||
if (!p.startsWith('/')) p = '/' + p;
|
||||
ui.pathText = p;
|
||||
draft.path = toStorePath(p);
|
||||
}
|
||||
|
||||
function pathRule(v: string) {
|
||||
if (!v) return 'Percorso richiesto';
|
||||
if (!v.startsWith('/')) return 'Deve iniziare con /';
|
||||
if (/\s/.test(v)) return 'Nessuno spazio nel path';
|
||||
return true;
|
||||
}
|
||||
|
||||
// --- Upsert nello store.mypage
|
||||
function upsertIntoStore(page: IMyPage, arr: IMyPage[]) {
|
||||
if (!page) return;
|
||||
// chiave di matching: prima _id, altrimenti path
|
||||
const keyId = page._id;
|
||||
const keyPath = page.path || '';
|
||||
let idx = -1;
|
||||
if (keyId) {
|
||||
idx = arr.findIndex((p) => p._id === keyId);
|
||||
}
|
||||
if (idx < 0 && keyPath) {
|
||||
idx = arr.findIndex((p) => (p.path || '') === keyPath);
|
||||
}
|
||||
if (idx >= 0) {
|
||||
// merge preservando reattività
|
||||
arr[idx] = { ...arr[idx], ...toRaw(page) };
|
||||
} else {
|
||||
arr.push({ ...toRaw(page) });
|
||||
}
|
||||
}
|
||||
async function save () {
|
||||
try {
|
||||
saving.value = true
|
||||
normalizeAndApplyPath() // assicura path coerente
|
||||
|
||||
const payload: IMyPage = { ...toRaw(draft), path: draft.path || '' }
|
||||
const saved = await globalStore.savePage(payload)
|
||||
if (saved && typeof saved === 'object') {
|
||||
syncingFromProps.value = true
|
||||
Object.assign(draft, saved)
|
||||
upsertIntoStore(draft, mypage.value)
|
||||
await nextTick()
|
||||
syncingFromProps.value = false
|
||||
}
|
||||
emit('apply', { ...draft })
|
||||
$q.notify({ type: 'positive', message: 'Pagina salvata' })
|
||||
} catch (err: any) {
|
||||
console.error(err)
|
||||
$q.notify({ type: 'negative', message: 'Errore nel salvataggio' })
|
||||
} finally {
|
||||
saving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// --- Ricarica da sorgente
|
||||
async function reloadFromStore () {
|
||||
try {
|
||||
const absolute = ui.pathText || '/'
|
||||
const page = await globalStore.loadPage(absolute, '', true)
|
||||
if (page) {
|
||||
syncingFromProps.value = true
|
||||
Object.assign(draft, page)
|
||||
ui.pathText = toUiPath(draft.path)
|
||||
upsertIntoStore(draft, mypage.value)
|
||||
console.log('page', draft)
|
||||
emit('update:modelValue', { ...draft })
|
||||
await nextTick()
|
||||
syncingFromProps.value = false
|
||||
$q.notify({ type: 'info', message: 'Pagina ricaricata' })
|
||||
} else {
|
||||
$q.notify({ type: 'warning', message: 'Pagina non trovata' })
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
$q.notify({ type: 'negative', message: 'Errore nel ricaricare la pagina' })
|
||||
}
|
||||
}
|
||||
|
||||
function resetDraft() {
|
||||
console.log('resetDraft')
|
||||
syncingFromProps.value = true
|
||||
Object.assign(draft, props.modelValue || {})
|
||||
ui.pathText = toUiPath(draft.path)
|
||||
// aggiorna i componenti
|
||||
emit('update:modelValue', { ...draft })
|
||||
nextTick(() => { syncingFromProps.value = false })
|
||||
}
|
||||
|
||||
const absolutePath = computed(() => toUiPath(draft.path))
|
||||
|
||||
return {
|
||||
draft,
|
||||
ui,
|
||||
saving,
|
||||
pathRule,
|
||||
normalizeAndApplyPath,
|
||||
save,
|
||||
reloadFromStore,
|
||||
resetDraft,
|
||||
absolutePath,
|
||||
};
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user