Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 49 additions & 41 deletions src/FormsSubmit.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import type { FormsForm } from './models/Entities.d.ts'
import { subscribe, unsubscribe } from '@nextcloud/event-bus'
import { loadState } from '@nextcloud/initial-state'
import { defineComponent } from 'vue'
import { nextTick, onMounted, onUnmounted } from 'vue'
import NcContent from '@nextcloud/vue/components/NcContent'
import Submit from './views/Submit.vue'

Expand All @@ -33,45 +34,14 @@ export default defineComponent({
Submit,
},

data() {
return {
form: loadState(formsAppName, 'form') as FormsForm,
isLoggedIn: loadState(formsAppName, 'isLoggedIn') as boolean,
isEmbedded: loadState(formsAppName, 'isEmbedded', false) as boolean,
shareHash: loadState(formsAppName, 'shareHash') as string,
}
},

unmounted() {
unsubscribe('forms:last-updated:set', this.onSubmitMessageEvent)
},

mounted() {
if (this.isEmbedded) {
subscribe('forms:last-updated:set', this.onSubmitMessageEvent)

// Communicate window size to parent window in iframes
const resizeObserver = new ResizeObserver((entries) => {
this.emitResizeMessage(entries[0].target as HTMLElement)
})
this.$nextTick(() => {
const formEl = document.querySelector('.app-forms-embedded form')
if (formEl) {
resizeObserver.observe(formEl)
}
})
}
},
setup() {
const form = loadState(formsAppName, 'form') as FormsForm
const isLoggedIn = loadState(formsAppName, 'isLoggedIn') as boolean
const isEmbedded = loadState(formsAppName, 'isEmbedded', false) as boolean
const shareHash = loadState(formsAppName, 'shareHash') as string
let resizeObserver: ResizeObserver | undefined

methods: {
onSubmitMessageEvent(event: unknown): void {
const id = Number(event)
if (Number.isFinite(id)) {
this.emitSubmitMessage(id)
}
},

emitSubmitMessage(id: number): void {
const emitSubmitMessage = (id: number): void => {
window.parent?.postMessage(
{
type: 'form-saved',
Expand All @@ -81,12 +51,19 @@ export default defineComponent({
},
'*',
)
},
}

const onSubmitMessageEvent = (event: unknown): void => {
const id = Number(event)
if (Number.isFinite(id)) {
emitSubmitMessage(id)
}
}

/**
* @param target Target of which the size should be communicated
*/
emitResizeMessage(target: HTMLElement): void {
const emitResizeMessage = (target: HTMLElement): void => {
const rect = target.getBoundingClientRect()
let height = rect.top + target.scrollHeight
let width = target.scrollWidth
Expand Down Expand Up @@ -117,7 +94,38 @@ export default defineComponent({
},
'*',
)
},
}

onMounted(() => {
if (!isEmbedded) {
return
}

subscribe('forms:last-updated:set', onSubmitMessageEvent)

// Communicate window size to parent window in iframes
resizeObserver = new ResizeObserver((entries) => {
emitResizeMessage(entries[0].target as HTMLElement)
})
void nextTick(() => {
const formEl = document.querySelector('.app-forms-embedded form')
if (formEl) {
resizeObserver?.observe(formEl)
}
})
})

onUnmounted(() => {
unsubscribe('forms:last-updated:set', onSubmitMessageEvent)
resizeObserver?.disconnect()
})

return {
form,
isLoggedIn,
isEmbedded,
shareHash,
}
},
})
</script>
12 changes: 7 additions & 5 deletions src/components/AddQuestionMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
import IconPlus from '@material-symbols/svg-400/outlined/add.svg?raw'
import IconChevronLeft from '@material-symbols/svg-400/outlined/chevron_left.svg?raw'
import { t } from '@nextcloud/l10n'
import { defineComponent, ref, toRef, watch } from 'vue'
import { defineComponent, ref, watch } from 'vue'
import NcActionButton from '@nextcloud/vue/components/NcActionButton'
import NcActions from '@nextcloud/vue/components/NcActions'
import NcActionSeparator from '@nextcloud/vue/components/NcActionSeparator'
Expand Down Expand Up @@ -103,11 +103,13 @@ export default defineComponent({
setup(props, { emit }) {
const activeQuestionType = ref<string | null>(null)
const openLocal = ref<boolean>(props.open)
const open = toRef(props, 'open')

watch(open, (value: boolean) => {
openLocal.value = value
})
watch(
() => props.open,
(value: boolean) => {
openLocal.value = value
},
)

watch(openLocal, (value: boolean) => {
emit('update:open', value)
Expand Down
49 changes: 26 additions & 23 deletions src/components/Questions/AnswerInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
</template>

<script lang="ts">
import type { PropType } from 'vue'
import type { FormsOption } from '../../models/Entities.d.ts'

import IconPlus from '@material-symbols/svg-400/outlined/add.svg?raw'
Expand Down Expand Up @@ -118,7 +119,7 @@ export default defineComponent({

props: {
answer: {
type: Object,
type: Object as PropType<FormsOption>,
required: true,
},

Expand Down Expand Up @@ -180,18 +181,24 @@ export default defineComponent({
const buttonOptionDown = ref<{ $el?: HTMLElement } | null>(null)
const buttonOptionUp = ref<{ $el?: HTMLElement } | null>(null)
const isIMEComposing = ref(false)
const localText = ref((props.answer as FormsOption | undefined)?.text ?? '')
const answer = computed(() => props.answer)
const localText = ref(answer.value.text ?? '')

const getInputTarget = (
event: Event | { target: EventTarget | null },
): HTMLInputElement | null => {
return event.target instanceof HTMLInputElement ? event.target : null
}

const canCreateLocalAnswer = computed(() => {
if ((props.answer as FormsOption).local) {
if (answer.value.local) {
return !!localText.value.trim()
}
return !!(props.answer as FormsOption).text?.trim()
return !!answer.value.text?.trim()
})

const ariaLabel = computed(() => {
const answer = props.answer as FormsOption
if (answer.local) {
if (answer.value.local) {
if (props.optionType === OptionType.Column) {
return t('forms', 'Add a new column')
}
Expand Down Expand Up @@ -220,13 +227,11 @@ export default defineComponent({
})

const optionDragMenuId = computed(() => {
const answer = props.answer as FormsOption
return `q${answer.questionId}o${answer.id}o${props.optionType}__drag_menu`
return `q${answer.value.questionId}o${answer.value.id}o${props.optionType}__drag_menu`
})

const placeholder = computed(() => {
const answer = props.answer as FormsOption
if (answer.local) {
if (answer.value.local) {
if (props.optionType === OptionType.Column) {
return t('forms', 'Add a new column')
}
Expand All @@ -252,8 +257,7 @@ export default defineComponent({
})

const pseudoIcon = computed(() => {
const answer = props.answer as FormsOption
if (answer.local) {
if (answer.value.local) {
return IconPlus
}

Expand Down Expand Up @@ -305,20 +309,19 @@ export default defineComponent({
async function onInput(
event: InputEvent | { target: HTMLInputElement; isComposing?: boolean },
): Promise<void> {
const target = event.target as HTMLInputElement | null
const target = getInputTarget(event)
if (!target) {
return
}

const answer = props.answer as FormsOption
if (answer.local) {
if (answer.value.local) {
localText.value = target.value
return
}

if (!event.isComposing && !isIMEComposing.value && target.value !== '') {
// clone answer
const answerCopy = { ...answer }
const answerCopy = { ...answer.value }
if (!input.value) {
return
}
Expand All @@ -339,7 +342,7 @@ export default defineComponent({
* @param e The keyboard event.
*/
const onEnter = (e: KeyboardEvent): void => {
if ((props.answer as FormsOption).local) {
if (answer.value.local) {
void createLocalAnswer(e)
return
}
Expand All @@ -363,8 +366,8 @@ export default defineComponent({
return
}

const answer = {
...(props.answer as FormsOption),
const answerValue = {
...answer.value,
text: value,
local: false,
}
Expand All @@ -373,7 +376,7 @@ export default defineComponent({
try {
// Forward changes, but use current answer.text to avoid erasing
// any in-between changes while creating the answer
const newAnswer = await createAnswer(answer)
const newAnswer = await createAnswer(answerValue)
if (!input.value) {
return
}
Expand Down Expand Up @@ -413,7 +416,7 @@ export default defineComponent({
return
}

if ((props.answer as FormsOption).local) {
if (answer.value.local) {
return
}

Expand All @@ -424,7 +427,7 @@ export default defineComponent({
// Dismiss delete key action
e.preventDefault()
void queue.value.add(() => {
emit('delete', props.answer as FormsOption)
emit('delete', props.answer)
queue.value.pause()
queue.value.clear()
})
Expand Down Expand Up @@ -543,7 +546,7 @@ export default defineComponent({
const onCompositionEnd = (
event: CompositionEvent & { isComposing?: boolean },
): void => {
const target = event.target as HTMLInputElement | null
const target = getInputTarget(event)
isIMEComposing.value = false
if (!event.isComposing && target) {
void onInput({ target, isComposing: event.isComposing })
Expand Down
5 changes: 4 additions & 1 deletion src/components/Questions/QuestionColor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ export default defineComponent({

setup(props, { emit }) {
const question = useQuestion(props, { emit })
const values = computed(() => {
return props.values as Array<string | null | undefined>
})

const colorPickerPlaceholder = computed(() => {
return props.readOnly
Expand All @@ -82,7 +85,7 @@ export default defineComponent({
})

const pickedColor = computed(() => {
return (props.values[0] as string | null | undefined) ?? ''
return values.value[0] ?? ''
})

const validate = async (): Promise<boolean> => {
Expand Down
Loading
Loading