NewsletterCreator / src / components / NewsletterElements / AppointmentElement.vue
AppointmentElement.vue
Raw
<template>
  <BoilerplateElement :id="this.id">
    <template #german>
          <q-input :lazy-rules="true" rounded outlined v-model="elementData.dateTime" :label="$t('appointmentElement.dateTime')" :rules="validation.dateTime" bg-color="white">
            <template v-slot:prepend>
              <q-icon name="event" class="cursor-pointer" >
                <q-popup-proxy cover transition-show="scale" transition-hide="scale">
                  <q-date v-model="elementData.dateTime" mask="DD.MM.YYYY HH:mm">
                    <div class="row items-center justify-end">
                      <q-btn v-close-popup :label="$t('appointmentElement.close')" color="primary" flat ref="dateCloseButton" />
                    </div>
                  </q-date>
                </q-popup-proxy>
              </q-icon>
            </template>

            <template v-slot:append>
              <q-icon name="access_time" class="cursor-pointer">
                <q-popup-proxy cover transition-show="scale" transition-hide="scale">
                  <q-time v-model="elementData.dateTime" mask="DD.MM.YYYY HH:mm" format24h>
                    <div class="row items-center justify-end">
                      <q-btn v-close-popup :label="$t('appointmentElement.close')" color="primary" flat ref="timeCloseButton"/>
                    </div>
                  </q-time>
                </q-popup-proxy>
              </q-icon>
            </template>
          </q-input>
          <q-badge color="primary">
            {{ $t('appointmentElement.duration') }}:  {{ elementData.duration > 0 ? elementData.duration + ' ' + $t('appointmentElement.hours') : $t('appointmentElement.notSpecified')}}
          </q-badge>
          <q-slider v-model="elementData.duration" :min="0" :max="10" :step="0.25"/>
          <q-input :lazy-rules="true" rounded outlined v-model="elementData.german.title" :label="$t('appointmentElement.title')" bg-color="white" :rules="validation.title" />
          <q-input :lazy-rules="true" rounded outlined v-model="elementData.german.place" :label="$t('appointmentElement.place')" bg-color="white" :rules="validation.place" />
          <q-input :lazy-rules="true" rounded outlined v-model="elementData.german.person" :label="$t('appointmentElement.person')" bg-color="white" :rules="validation.person" />
          <h3 class="elipsis q-field__label">Freitext</h3>
          <q-editor v-model="elementData.german.freeText"
            ref="germanEditor"
            :toolbar="[
              ['left', 'center', 'right', 'justify'],
              ['bold', 'italic', 'underline', 'strike'],
              ['link', 'unordered'],
              ['removeFormat'],
              ['undo', 'redo']
            ]"
            @paste="(event) => removeUnwantedFormatting(event, $refs.germanEditor)"
          ></q-editor>
    </template>
    <template #english>
          <q-input :lazy-rules="true" rounded outlined v-model="elementData.dateTime" :label="$t('appointmentElement.dateTime')" :rules="validation.dateTime" bg-color="white">
            <template v-slot:prepend>
              <q-icon name="event" class="cursor-pointer">
                <q-popup-proxy cover transition-show="scale" transition-hide="scale">
                  <q-date v-model="elementData.dateTime" mask="DD.MM.YYYY HH:mm">
                    <div class="row items-center justify-end">
                      <q-btn v-close-popup :label="$t('appointmentElement.close')" color="primary" flat ref="dateCloseButton"/>
                    </div>
                  </q-date>
                </q-popup-proxy>
              </q-icon>
            </template>

            <template v-slot:append>
              <q-icon name="access_time" class="cursor-pointer">
                <q-popup-proxy cover transition-show="scale" transition-hide="scale">
                  <q-time v-model="elementData.dateTime" mask="DD.MM.YYYY HH:mm" format24h>
                    <div class="row items-center justify-end">
                      <q-btn v-close-popup :label="$t('appointmentElement.close')" color="primary" flat ref="timeCloseButton"/>
                    </div>
                  </q-time>
                </q-popup-proxy>
              </q-icon>
            </template>
          </q-input>
          <q-badge color="primary">
            {{ $t('appointmentElement.duration') }}:  {{ elementData.duration > 0 ? elementData.duration + ' ' + $t('appointmentElement.hours') : $t('appointmentElement.notSpecified')}}
          </q-badge>
          <q-slider v-model="elementData.duration" :min="0" :max="10" :step="0.25"/>
          <q-input :lazy-rules="true" rounded outlined v-model="elementData.english.title" :label="$t('appointmentElement.title')" bg-color="white" :rules="validation.title" />
          <q-input :lazy-rules="true" rounded outlined v-model="elementData.english.place" :label="$t('appointmentElement.place')" bg-color="white" :rules="validation.place" />
          <q-input :lazy-rules="true" rounded outlined v-model="elementData.english.person" :label="$t('appointmentElement.person')" bg-color="white" :rules="validation.person" />
          <h3 class="elipsis q-field__label">Freitext</h3>
          <q-editor v-model="elementData.english.freeText"
            ref="englishEditor"
            :toolbar="[
              ['left', 'center', 'right', 'justify'],
              ['bold', 'italic', 'underline', 'strike'],
              ['link', 'unordered'],
              ['removeFormat'],
              ['undo', 'redo']
            ]"
            @paste="(event) => removeUnwantedFormatting(event, $refs.englishEditor)"
          ></q-editor>
    </template>
  </BoilerplateElement>
</template>

<script>
import BoilerplateElement from 'src/components/BoilerplateElement.vue'

export default {
  data () {
    return {
      elementData: this.data,
      validation: {
        dateTime: [
          (v) => {
            // error: dateTime is required
            const eId = 1
            const errorExists = this.elementData.errors.some(error => error.id === eId)
            // using Date and Time close button to determin if popup is currently open (exists) if so ongoing selection and therefore no error and erly return true
            if (this.$refs.dateCloseButton != null || this.$refs.timeCloseButton != null) {
              return true
            }
            if (v) {
              this.elementData.errors = this.elementData.errors.filter((error) => error.id !== eId)
              return true
            } else {
              if (!errorExists) {
                this.elementData.errors.push({ id: eId, message: this.$t('appointmentElement.error1') })
              }
              return this.$t('appointmentElement.error1')
            }
          },
          (v) => {
            // error: incorrect dateTime format
            const eId = 2
            const errorExists = this.elementData.errors.some(error => error.id === eId)
            // using Date and Time close button to determin if popup is currently open (exists) if so ongoing selection and therefore no error and erly return true
            if (this.$refs.dateCloseButton != null || this.$refs.timeCloseButton != null) {
              return true
            }
            if (v && v.match(/^\d{2}\.\d{2}\.\d{4} \d{2}:\d{2}$/)) {
              this.elementData.errors = this.elementData.errors.filter((error) => error.id !== eId)
              return true
            } else {
              if (!errorExists) {
                this.elementData.errors.push({ id: eId, message: this.$t('appointmentElement.error2') })
              }
              return this.$t('appointmentElement.error2')
            }
          }
        ],
        title: [
          (v) => {
            // error: title is required
            const eId = 3
            const errorExists = this.elementData.errors.some(error => error.id === eId)
            if (v) {
              this.elementData.errors = this.elementData.errors.filter((error) => error.id !== eId)
              return true
            } else {
              if (!errorExists) {
                this.elementData.errors.push({ id: eId, message: this.$t('appointmentElement.error3') })
              }
              return this.$t('appointmentElement.error3')
            }
          }
        ],
        place: [
          (v) => {
            // error: place is required
            const eId = 4
            const errorExists = this.elementData.errors.some(error => error.id === eId)
            if (v) {
              this.elementData.errors = this.elementData.errors.filter((error) => error.id !== eId)
              return true
            } else {
              if (!errorExists) {
                this.elementData.errors.push({ id: eId, message: this.$t('appointmentElement.error4') })
              }
              return this.$t('appointmentElement.error4')
            }
          }
        ],
        person: [
          (v) => {
            // error: person is required
            const eId = 5
            const errorExists = this.elementData.errors.some(error => error.id === eId)
            if (v) {
              this.elementData.errors = this.elementData.errors.filter((error) => error.id !== eId)
              return true
            } else {
              if (!errorExists) {
                this.elementData.errors.push({ id: eId, message: this.$t('appointmentElement.error5') })
              }
              return this.$t('appointmentElement.error5')
            }
          }
        ]
      }
    }
  },
  props: {
    id: {
      required: true
    },
    data: {
      type: Object,
      required: true
    }
  },
  components: {
    BoilerplateElement
  },
  methods: {
    // Remove unwanted formatting when pasting text based on official quasar docs modified with chatgpt
    removeUnwantedFormatting (evt, editor) {
      // Let inputs do their thing, so we don't break pasting of links.
      if (evt.target.nodeName === 'INPUT') return

      let text, html, onPasteStripFormattingIEPaste
      evt.preventDefault()
      evt.stopPropagation()

      if (evt.originalEvent && evt.originalEvent.clipboardData) {
        // Check if HTML data is available in the clipboard
        if (evt.originalEvent.clipboardData.types.includes('text/html')) {
          html = evt.originalEvent.clipboardData.getData('text/html')
          // Remove font size-related styles
          html = html.replace(/font-size:\s*\d+(\.\d+)?(px|pt|em|rem|%);?/gi, '')
          editor.runCmd('insertHTML', html)
        } else {
        // If no HTML, fall back to plain text
          text = evt.originalEvent.clipboardData.getData('text/plain')
          editor.runCmd('insertText', text)
        }
      } else if (evt.clipboardData) {
        if (evt.clipboardData.types.includes('text/html')) {
          html = evt.clipboardData.getData('text/html')
          // Remove font size-related styles
          html = html.replace(/font-size:\s*\d+(\.\d+)?(px|pt|em|rem|%);?/gi, '')
          editor.runCmd('insertHTML', html)
        } else {
          text = evt.clipboardData.getData('text/plain')
          editor.runCmd('insertText', text)
        }
      } else if (window.clipboardData) {
        // Internet Explorer handling
        if (!onPasteStripFormattingIEPaste) {
          onPasteStripFormattingIEPaste = true
          html = window.clipboardData.getData('Text')
          // Apply a similar approach to remove font size styles if IE supports HTML
          html = html.replace(/font-size:\s*\d+(\.\d+)?(px|pt|em|rem|%);?/gi, '')
          editor.runCmd('ms-pasteHTML', html)
        }
        onPasteStripFormattingIEPaste = false
      }
    }
  }
}
</script>