Webpage Editor functionality

This commit is contained in:
paoloar77
2022-11-10 19:32:56 +01:00
parent 2bd31200b4
commit 9fe37c9f3c
38 changed files with 1387 additions and 384 deletions

View File

@@ -520,7 +520,7 @@ export default defineComponent({
}
}
// console.log('sortBy', sortBy)
console.log('sortBy', sortBy)
const filtersearch: any[] = []
const filtersearch2: any[] = []
@@ -867,7 +867,7 @@ export default defineComponent({
pagination.value.sortBy = sortBy
pagination.value.descending = descending
// console.log('pagination', pagination)
console.log('pagination', pagination)
// ...and turn of loading indicator
loading.value = false

View File

@@ -359,6 +359,7 @@
:columns="mycolumns"
:filter="myfilter"
v-model:pagination="pagination"
@request="onRequest"
virtual-scroll
:row-key="colkey"
:loading="loading"

View File

@@ -15,25 +15,52 @@ import { CCardCarousel } from '@src/components/CCardCarousel'
import { CMyPage } from '@src/components/CMyPage'
import { CMyPageIntro } from '@src/components/CMyPageIntro'
import { CEventsCalendar } from '@src/components/CEventsCalendar'
import { CMyEditor } from '@src/components/CMyEditor'
import MixinMetaTags from '@/mixins/mixin-metatags'
import { useQuasar } from 'quasar'
import { useI18n } from '@/boot/i18n'
export default defineComponent({
name: 'CMyElem',
components: { CImgTitle, CTitle, LandingFooter, CEventsCalendar, CCardCarousel, COpenStreetMap, CMyPage, CMyPageIntro },
components: { CImgTitle, CTitle, LandingFooter, CEventsCalendar, CCardCarousel, COpenStreetMap, CMyPage, CMyPageIntro, CMyEditor },
props: {
myelem: {
type: Object as PropType<IMyElem>,
required: true,
},
editOn: {
type: Boolean,
required: false,
default: false,
},
addOn: {
type: Boolean,
required: false,
default: false,
}
},
setup(props) {
const globalStore = useGlobalStore()
const { setmeta, getsrcbyimg } = MixinMetaTags()
const $q = useQuasar()
const { t } = useI18n()
const animare = ref(0)
const slide = ref(0)
const slide2 = ref(0)
const disableSave = ref(true)
const neworder = ref(<number|undefined>0)
const myel = toRef(props, 'myelem')
const newtype = ref(<any>'')
watch(() => myel.value.order, (value, oldval) => {
mounted()
})
function getArrDisciplines() {
return globalStore.disciplines.filter((rec: any) => rec.showinhome)
@@ -46,6 +73,69 @@ export default defineComponent({
return '600px'
}
function saveElem() {
// Save Elem record
const myelem = props.myelem
myelem.order = neworder.value
globalStore.saveMyElem($q, t, myelem).then((ris) => {
if (ris) {
// OK
disableSave.value = true
}
})
}
function addNewElem(order?: number) {
const newrec: IMyElem = {
_id: undefined,
type: newtype.value,
path: props.myelem.path,
order: order ? order : 1000,
active: true,
container: ''
}
globalStore.addNewElem($q, t, newrec)
}
function delElem() {
$q.dialog({
message: 'Eliminare ' + props.myelem.container + ' ?',
html: true,
ok: {
label: 'Elimina',
push: true,
},
title: '',
cancel: true,
persistent: false,
}).onOk(async () => {
// Save Elem record
await globalStore.delMyElem($q, t, props.myelem).then((ris) => {
if (ris) {
// OK
disableSave.value = true
}
})
})
}
function modifElem(value: any) {
disableSave.value = false
}
function mounted() {
neworder.value = props.myelem.order
if (props.myelem)
newtype.value = props.myelem.type
}
onMounted(mounted)
return {
tools,
shared_consts,
@@ -56,6 +146,14 @@ export default defineComponent({
animare,
setmeta,
getsrcbyimg,
saveElem,
myel,
disableSave,
modifElem,
delElem,
addNewElem,
newtype,
neworder,
}
},

View File

@@ -1,56 +1,287 @@
<template>
<div v-if="myelem">
<div v-if="myelem.type === shared_consts.ELEMTYPE.TEXT">
<div :class="myelem.class">{{ myelem.container }}</div>
</div>
<div v-if="myelem.type === shared_consts.ELEMTYPE.MARGINI">
<div :style="`margin: ` + myelem.size"></div>
</div>
<div v-else-if="myelem.type === shared_consts.ELEMTYPE.TITLE">
<CTitle
:imgbackground="myelem.imgback"
:headtitle="myelem.title" :sizes="myelem.size" :styleadd="myelem.styleadd">
</CTitle>
</div>
<div v-else-if="myelem.type === shared_consts.ELEMTYPE.IMGTITLE">
<CImgTitle v-if="myelem.container" :src="myelem.container" :title="myelem.title">
</CImgTitle>
</div>
<div v-else-if="myelem.type === shared_consts.ELEMTYPE.HTML">
<div :class="myelem.class" v-html="myelem.containerHtml"></div>
</div>
<div v-else-if="myelem.type === shared_consts.ELEMTYPE.IMAGE">
<div class="text-center">
<q-img :src="myelem.container" class="img" :width="myelem.width" :height="myelem.height"></q-img>
<div v-if="myel">
<q-bar v-if="editOn" dense class="bg-blue-1 text-white q-px-sm">
<q-input
style="max-width: 60px"
hide-bottom-space
borderless
dense
@update:model-value="modifElem"
v-model="neworder"
v-on:keyup.enter="saveElem"
type="number"
>
</q-input>
<q-space/>
<q-btn
icon="fas fa-trash-alt"
color="negative"
dense
flat
size="sm"
@click="delElem">
</q-btn>
<q-select v-if="addOn"
v-model="newtype"
dense
style="width: 150px;"
:options="shared_consts.TypesElem"
emit-value map-options>
</q-select>
<q-btn
v-if="addOn"
size="sm"
dense
flat
icon="fas fa-plus"
color="positive"
@click="addNewElem(myelem.order-10)">
</q-btn>
</q-bar>
<div v-if="myel.type === shared_consts.ELEMTYPE.TEXT">
<div v-if="editOn">
<q-input
class="fa-border"
@update:model-value="modifElem"
v-model="myel.container"
filled
v-on:keyup.enter="saveElem"
>
</q-input>
</div>
<div v-else
:class="myel.class">{{ myel.container }}
</div>
</div>
<div v-else-if="myelem.type === shared_consts.ELEMTYPE.VIDEO">
<div v-if="myel.type === shared_consts.ELEMTYPE.MARGINI">
<div v-if="editOn">
<q-input
label="Margine:"
class="fa-border"
@update:model-value="modifElem"
v-model="myel.size"
filled
v-on:keyup.enter="saveElem"
>
</q-input>
</div>
<div :style="`margin: ` + myel.size"></div>
</div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.TITLE">
<div v-if="editOn">
<q-input
class="fa-border"
@update:model-value="modifElem"
v-model="myel.title"
filled
v-on:keyup.enter="saveElem"
>
</q-input>
</div>
<div v-else>
<CTitle
:imgbackground="myel.imgback"
:headtitle="myel.title" :sizes="myel.size" :styleadd="myel.styleadd">
</CTitle>
</div>
</div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.IMGTITLE">
<div v-if="editOn">
<q-input
label="Img"
class="fa-border"
@update:model-value="modifElem"
v-model="myel.container"
filled
v-on:keyup.enter="saveElem"
>
</q-input>
<q-input
label="Title"
class="fa-border"
@update:model-value="modifElem"
v-model="myel.container"
filled
v-on:keyup.enter="saveElem"
>
</q-input>
</div>
<div v-else>
<CImgTitle v-if="myel.container" :src="myel.container" :title="myel.title">
</CImgTitle>
</div>
</div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.HTML">
<div v-if="editOn">
<q-input
label="Classe:"
@update:model-value="modifElem"
v-model="myel.class"
filled
v-on:keyup.enter="saveElem"
>
</q-input>
<CMyEditor
v-model:value="myel.containerHtml" title="" @keyup.enter.stop
:showButtons="false"
:canModify="true"
@update:value="modifElem"
@showandsave="saveElem"
>
</CMyEditor>
</div>
<div v-else>
<div :class="myel.class" v-html="myel.containerHtml"></div>
</div>
</div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.IMAGE">
<div v-if="editOn">
<q-input
label="NomeFile Img:"
@update:model-value="modifElem"
v-model="myel.container"
filled
v-on:keyup.enter="saveElem"
>
</q-input>
<div class="row">
<q-input
label="Width:"
type="number"
@update:model-value="modifElem"
v-model="myel.width"
filled
v-on:keyup.enter="saveElem"
>
</q-input>
<q-input
label="Height:"
type="number"
@update:model-value="modifElem"
v-model="myel.height"
filled
v-on:keyup.enter="saveElem"
>
</q-input>
</div>
</div>
<div class="text-center">
<q-img :src="myel.container" class="img" :width="myel.width.toString()" :height="myel.height.toString()"></q-img>
</div>
</div>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.VIDEO">
<div v-if="editOn" class="row">
<q-input
label="NomeFile Video:"
@update:model-value="modifElem"
v-model="myel.container"
filled
v-on:keyup.enter="saveElem"
>
</q-input>
<q-input
label="Ratio:"
type="number"
@update:model-value="modifElem"
v-model="myel.ratio"
filled
v-on:keyup.enter="saveElem"
>
</q-input>
</div>
<q-video v-if="!!rec.container" :src="rec.container" :ratio="rec.ratio">
</q-video>
</div>
<div v-else-if="myelem.type === shared_consts.ELEMTYPE.FOOTER">
<div v-else-if="myel.type === shared_consts.ELEMTYPE.FOOTER">
<LandingFooter></LandingFooter>
</div>
<div v-else-if="myelem.type === shared_consts.ELEMTYPE.PAGE">
<CMyPage :mypath="myelem.container"></CMyPage>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.PAGE">
<div v-if="editOn" class="row">
<q-input
label="Nome Pagina:"
@update:model-value="modifElem"
v-model="myel.container"
filled
v-on:keyup.enter="saveElem"
>
</q-input>
</div>
<CMyPage :mypath="myel.container"></CMyPage>
</div>
<div v-else-if="myelem.type === shared_consts.ELEMTYPE.PAGEINTRO">
<CMyPageIntro :mypath="myelem.container" :maxheightimg="myelem.heightimg" :maxwidthimg="myelem.widthimg" :link="myelem.link"></CMyPageIntro>
<div v-else-if="myel.type === shared_consts.ELEMTYPE.PAGEINTRO">
<div v-if="editOn" class="row">
<q-input
label="NomeFile Img:"
@update:model-value="modifElem"
v-model="myel.container"
filled
v-on:keyup.enter="saveElem"
>
</q-input>
<q-input
label="Width:"
type="number"
@update:model-value="modifElem"
v-model="myel.widthimg"
filled
v-on:keyup.enter="saveElem"
>
</q-input>
<q-input
label="Height:"
type="number"
@update:model-value="modifElem"
v-model="myel.heightimg"
filled
v-on:keyup.enter="saveElem"
>
</q-input>
<q-input
label="Link:"
@update:model-value="modifElem"
v-model="myel.link"
filled
v-on:keyup.enter="saveElem"
>
</q-input>
</div>
<CMyPageIntro :mypath="myel.container" :maxheightimg="myel.heightimg" :maxwidthimg="myel.widthimg" :link="myel.link"></CMyPageIntro>
</div>
<div v-else-if="myelem.type === shared_consts.ELEMTYPE.CAROUSEL_IDISCIPLINE">
<div v-else-if="myel.type === shared_consts.ELEMTYPE.CAROUSEL_IDISCIPLINE">
<CCardCarousel :myarr="getArrDisciplines()">
</CCardCarousel>
</div>
<div v-else-if="myelem.type === shared_consts.ELEMTYPE.OPENSTREETMAP">
<div v-else-if="myel.type === shared_consts.ELEMTYPE.OPENSTREETMAP">
<!-- Da Fare -->
<COpenStreetMap :imgmap="getValDb('IMGMAP', false)" :urlmap="getValDb('URLMAP', false)" :title="getValDb('MAP_TITLE', false)"
:coordinates="getValDb('COORD_MAP_1', false)" :coord_big="getValDb('COORD_MAP_BIG', false)">
</COpenStreetMap>
</div>
<div v-else-if="myelem.type === shared_consts.ELEMTYPE.CAROUSEL_IMGS">
<section class="maxwidth padding_gallery bg-white text-grey-10 text-center" >
<div v-else-if="myel.type === shared_consts.ELEMTYPE.CAROUSEL_IMGS">
<section class="maxwidth padding_gallery bg-white text-grey-10 text-center">
<div v-if="editOn" class="row">
<q-input
label="lista:"
@update:model-value="modifElem"
v-model="myel.list"
filled
v-on:keyup.enter="saveElem"
>
</q-input>
</div>
<q-carousel
swipeable
@@ -61,42 +292,43 @@
thumbnails
infinite
height="600">
<q-carousel-slide v-for="(rec, index) in myelem.list" :key="index" :name="index"
<q-carousel-slide v-for="(rec, index) in myel.list" :key="index" :name="index"
:img-src="getsrcbyimg(`images/`+ rec.imagefile)"
:alt="rec.alt"
class="carousel_slide">
<div class="absolute-bottom custom-caption" style="margin-bottom: 70px">
<div class="text-h5"><span
class="text-h6 text-grey-1 shadow-max">{{index + 1}}. </span>
class="text-h6 text-grey-1 shadow-max">{{ index + 1 }}. </span>
<span v-if="rec.alt"
class="text-h6 text-grey-2 shadow">{{rec.alt}}</span></div>
<div class="text-subtitle1" v-if="rec.description"><span class="text-grey-4 shadow">{{rec.description}}</span>
class="text-h6 text-grey-2 shadow">{{ rec.alt }}</span></div>
<div class="text-subtitle1" v-if="rec.description"><span class="text-grey-4 shadow">{{ rec.description }}</span>
</div>
</div>
</q-carousel-slide>
</q-carousel>
</section>
</div>
<div v-else-if="myelem.type === shared_consts.ELEMTYPE.CAROUSEL_HOME">
<div v-else-if="myel.type === shared_consts.ELEMTYPE.CAROUSEL_HOME">
<section>
<div class="landing">
<div class="landing__hero maxwidth1200 text-white">
<q-carousel
animated
:autoplay="animare"
swipeable
infinite
navigation
transition-next="slide-left"
transition-prev="slide-right"
v-model="slide"
:height="getheightgallery()"
width="100%"
>
<q-carousel-slide
v-for="(myrec, ind) in myelem.list" :key="ind"
:name="ind"
:img-src="getsrcbyimg(`images/`+ myrec.imagefile)">
<q-carousel
animated
:autoplay="animare"
swipeable
infinite
navigation
transition-next="slide-left"
transition-prev="slide-right"
v-model="slide"
:height="getheightgallery()"
width="100%"
>
<q-carousel-slide
v-for="(myrec, ind) in myel.list" :key="ind"
:name="ind"
:img-src="getsrcbyimg(`images/`+ myrec.imagefile)">
<div class="landing__header"></div>
<div class="landing__hero-content row justify-center q-gutter-xs clgutter">
@@ -107,13 +339,13 @@
<div class="q-gutter-xs testo-banda clgutter">
<h1 class="text-h1 shadow-max">{{ tools.getappname() }}</h1>
<div class="text-subtitle1 shadow text-italic q-pl-sm">
{{myelem.container}}&nbsp;
{{ myel.container }}&nbsp;
</div>
<div class="text-subtitle1 shadow-max big text-italic q-pl-sm">
{{myelem.container2}}
{{ myel.container2 }}
</div>
<div class="text-subtitle2 shadow text-italic q-pl-sm">
{{myelem.container3}}
{{ myel.container3 }}
</div>
<div>
<br><br>
@@ -129,23 +361,34 @@
class="q-icon text-h2 text-white material-icons">expand_more</i>
</div>-->
</q-carousel-slide>
</q-carousel>
</div>
</q-carousel>
</div>
</div>
</section>
</div>
<div v-else-if="myelem.type === shared_consts.ELEMTYPE.CALENDAR">
<CEventsCalendar :mysingleevent="null" :showfirstN="myelem.number || 3">
<div v-else-if="myel.type === shared_consts.ELEMTYPE.CALENDAR">
<CEventsCalendar :mysingleevent="null" :showfirstN="myel.number || 3">
</CEventsCalendar>
</div>
<div v-else-if="myelem.type === shared_consts.ELEMTYPE.CHECK_EMAIL">
<div v-else-if="myel.type === shared_consts.ELEMTYPE.CHECK_EMAIL">
<div class="q-pa-md q-gutter-md">
<div v-if="tools.isLogged() && !isVerified" class="text-verified">{{
$t('components.authentication.email_verification.link_sent') }}
$t('components.authentication.email_verification.link_sent')
}}
</div>
</div>
</div>
<q-btn
v-if="editOn && !disableSave"
icon="fas fa-check"
color="positive"
label="Salva"
size="sm"
:disable="disableSave"
@click="saveElem">
</q-btn>
</div>
</template>

View File

@@ -66,7 +66,9 @@ export default defineComponent({
load()
return { rec }
return {
rec, globalStore
}
},
})

View File

@@ -24,9 +24,7 @@
<div v-if="!!rec.content3" v-html="rec.content3"></div>
<q-video v-if="!!rec.video3" :src="rec.video3" :ratio="rec.ratio3"></q-video>
<div v-if="!!rec.content4" v-html="rec.content4"></div>
</div>
</div>
<div v-else>

View File

View File

@@ -0,0 +1,98 @@
import {
computed,
defineComponent, onMounted, ref, toRef, watch,
} from 'vue'
import { IMyElem, IMyPage } from '@src/model'
import { useGlobalStore } from '@store/globalStore'
import { LandingFooter } from '@/components/LandingFooter'
import { CMyElem } from '@/components/CMyElem'
import { CImgTitle } from '../CImgTitle/index'
import { CTitle } from '../CTitle/index'
import { tools } from '@store/Modules/tools'
import { useQuasar } from 'quasar'
import { useI18n } from '@/boot/i18n'
import { shared_consts } from '@/common/shared_vuejs'
export default defineComponent({
name: 'CMyPageElem',
components: { LandingFooter, CImgTitle, CTitle, CMyElem },
props: {
title: String,
mypath: {
type: String,
required: true,
},
img: {
type: String,
required: false,
default: '',
},
imgbackground: {
type: String,
required: false,
default: '',
},
sizes: {
type: String,
required: false,
default: '',
},
styleadd: {
type: String,
required: false,
default: '',
},
nofooter: {
type: Boolean,
required: false,
default: false,
},
},
setup(props) {
const rec = ref<IMyPage | null>(null)
const mypathin = toRef(props, 'mypath')
const $q = useQuasar()
const { t } = useI18n()
const editOn = ref(false)
const addOn = ref(false)
const globalStore = useGlobalStore()
const myelems = computed(() => {
if (mypathin.value)
return globalStore.getMyElems(mypathin.value)
else
return null
})
const load = async (): Promise<void> => {
// console.log('load', mypathin.value)
if (mypathin.value !== '') rec.value = await globalStore.loadPage('/' + mypathin.value)
}
watch(() => props.mypath, async (to: string, from: string) => {
console.log('... load', mypathin.value, props.mypath)
await load()
})
onMounted(load)
return {
rec, myelems,
mypathin,
editOn,
addOn,
tools,
shared_consts,
}
},
})

View File

@@ -0,0 +1,75 @@
<template>
<div>
<div v-if="mypathin && !!rec">
<q-toolbar>
<q-toggle v-if="tools.isManager()"
v-model="editOn"
icon="fas fa-pencil-alt"
>
</q-toggle>
<q-toggle v-if="tools.isManager()"
v-model="addOn"
icon="fas fa-plus"
>
</q-toggle>
</q-toolbar>
<div class="q-ma-sm q-gutter-sm q-pa-xs">
<div v-if="!!rec.img1" class="text-center">
<q-img :src="``+ rec.img1" class="img"></q-img>
</div>
<div v-if="!!rec.content" v-html="rec.content"></div>
<q-video v-if="!!rec.video1" :src="rec.video1" :ratio="rec.ratio1">
</q-video>
<div v-if="!!rec.img2" class="text-center">
<q-img :src="``+ rec.img2" class="img"></q-img>
</div>
<div v-if="!!rec.content2" v-html="rec.content2"></div>
<q-video v-if="!!rec.video2" :src="rec.video2" :ratio="rec.ratio2"></q-video>
<div v-if="!!rec.img3" class="text-center">
<q-img :src="``+ rec.img2" class="img"></q-img>
</div>
<div v-if="!!rec.content3" v-html="rec.content3"></div>
<q-video v-if="!!rec.video3" :src="rec.video3" :ratio="rec.ratio3"></q-video>
<div v-if="!!rec.content4" v-html="rec.content4"></div>
<span v-for="(myelem, ind) in myelems" :key="ind">
<CMyElem v-if="myelem.active" :myelem="myelem" :editOn="editOn" :addOn="addOn">
</CMyElem>
</span>
</div>
</div>
<div v-else>
<div v-if="!!title">
<CTitle
v-if="imgbackground" :imgbackground="imgbackground"
:headtitle="title" :sizes="sizes" :styleadd="styleadd"></CTitle>
<div v-if="!imgbackground">
<CImgTitle v-if="img" :src="img" :title="title">
</CImgTitle>
</div>
<slot></slot>
<div v-if="!nofooter">
<LandingFooter></LandingFooter>
</div>
</div>
</div>
</div>
</template>
<script lang="ts" src="./CMyPageElem.ts">
</script>
<style lang="scss" scoped>
@import './CMyPageElem.scss';
</style>

View File

@@ -0,0 +1 @@
export { default as CMyPageElem } from './CMyPageElem.vue'

View File

@@ -0,0 +1,4 @@
Con la mia contribuzione, dopo l'approvazione dell'assemblea generale entro a far parte del Comitato, con la mia
presenza morale, spirituale, intellettuale e/o contribuendo alle attività pratiche necessarie alla creazione ed
attuazione degli scopi costitutivi.

View File

@@ -16,6 +16,7 @@ export * from './CMyCart'
export * from './CMyFieldDb'
export * from './CMyFieldRec'
export * from './CMyPage'
export * from './CMyPageElem'
export * from './CMyPageIntro'
export * from './CMyElem'
export * from './CMyTeacher'