fix: escape HTML in forms

This commit is contained in:
Jannat Patel
2025-11-11 12:17:26 +05:30
parent c951732eb4
commit ab366837a2
10 changed files with 514 additions and 456 deletions

View File

@@ -20,8 +20,6 @@
}
"
autocomplete="off"
@focus="() => togglePopover()"
@keydown.delete.capture.stop="removeLastValue"
/>
</template>
<template #body="{ isOpen, close }">
@@ -58,7 +56,7 @@
<div class="h-10"></div>
<div
v-if="attrs.onCreate"
class="absolute bottom-2 left-1 w-[99%] pt-2 bg-white border-t"
class="absolute bottom-2 left-1 w-[95%] pt-2 bg-white border-t"
>
<Button
variant="ghost"
@@ -180,6 +178,7 @@ const filterOptions = createResource({
})
const options = computed(() => {
setFocus()
return filterOptions.data || []
})
@@ -225,25 +224,6 @@ const removeValue = (value) => {
values.value = values.value.filter((v) => v !== value)
}
const removeLastValue = () => {
if (query.value) return
let emailRef = emails.value[emails.value.length - 1]?.$el
if (document.activeElement === emailRef) {
values.value.pop()
nextTick(() => {
if (values.value.length) {
emailRef = emails.value[emails.value.length - 1].$el
emailRef?.focus()
} else {
setFocus()
}
})
} else {
emailRef?.focus()
}
}
function setFocus() {
search.value.$el.focus()
}

View File

@@ -66,6 +66,7 @@
<script setup lang="ts">
import { Button, Dialog, FormControl, TextEditor, toast } from 'frappe-ui'
import { computed, reactive, watch } from 'vue'
import { escapeHTML } from '@/utils'
const show = defineModel()
const assignments = defineModel<Assignments>('assignments')
@@ -121,35 +122,48 @@ watch(show, (newVal) => {
}
})
const validateTitle = () => {
assignment.title = escapeHTML(assignment.title.trim())
}
const saveAssignment = () => {
validateTitle()
if (props.assignmentID == 'new') {
assignments.value.insert.submit(
{
...assignment,
},
{
onSuccess() {
show.value = false
toast.success(__('Assignment created successfully'))
},
}
)
createAssignment()
} else {
assignments.value.setValue.submit(
{
...assignment,
name: props.assignmentID,
},
{
onSuccess() {
show.value = false
toast.success(__('Assignment updated successfully'))
},
}
)
updateAssignment()
}
}
const createAssignment = () => {
assignments.value.insert.submit(
{
...assignment,
},
{
onSuccess() {
show.value = false
toast.success(__('Assignment created successfully'))
},
}
)
}
const updateAssignment = () => {
assignments.value.setValue.submit(
{
...assignment,
name: props.assignmentID,
},
{
onSuccess() {
show.value = false
toast.success(__('Assignment updated successfully'))
},
}
)
}
const assignmentOptions = computed(() => {
return [
{ label: 'PDF', value: 'PDF' },

View File

@@ -344,6 +344,7 @@ import {
getMetaInfo,
updateMetaInfo,
validateFile,
escapeHTML,
} from '@/utils'
const router = useRouter()
@@ -500,7 +501,16 @@ const imageResource = createResource({
},
})
const validateFields = () => {
Object.keys(batch).forEach((key) => {
if (key != 'description' && typeof batch[key] === 'string') {
batch[key] = escapeHTML(batch[key])
}
})
}
const saveBatch = () => {
validateFields()
if (batchDetail.data) {
editBatchDetails()
} else {

View File

@@ -357,6 +357,7 @@ import {
getMetaInfo,
updateMetaInfo,
validateFile,
escapeHTML,
} from '@/utils'
import Link from '@/components/Controls/Link.vue'
import CourseOutline from '@/components/CourseOutline.vue'
@@ -537,7 +538,16 @@ const imageResource = createResource({
},
})
const validateFields = () => {
Object.keys(course).forEach((key) => {
if (key != 'description' && typeof course[key] === 'string') {
course[key] = escapeHTML(course[key])
}
})
}
const submitCourse = () => {
validateFields()
if (courseResource.data) {
editCourse()
} else {

View File

@@ -105,6 +105,8 @@
</Dialog>
</template>
<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import { escapeHTML } from '@/utils'
import {
Button,
createListResource,
@@ -113,14 +115,13 @@ import {
TextEditor,
toast,
} from 'frappe-ui'
import { computed, ref, watch } from 'vue'
import {
ProgrammingExercise,
ProgrammingExercises,
TestCase,
} from '@/types/programming-exercise'
import ChildTable from '@/components/Controls/ChildTable.vue'
import { ClipboardList, Play, Trash2 } from 'lucide-vue-next'
import ChildTable from '@/components/Controls/ChildTable.vue'
const show = defineModel()
const exercises = defineModel<ProgrammingExercises>('exercises')
@@ -194,7 +195,12 @@ const fetchTestCases = () => {
testCases.reload()
}
const validateTitle = () => {
exercise.value.title = escapeHTML(exercise.value.title.trim())
}
const saveExercise = (close: () => void) => {
validateTitle()
if (props.exerciseID == 'new') createNewExercise(close)
else updateExercise(close)
}

View File

@@ -255,7 +255,7 @@ import {
import { computed, ref, watch } from 'vue'
import { Plus, Trash2, TrendingUp } from 'lucide-vue-next'
import { Programs, Program } from '@/types/programs'
import { openSettings } from '@/utils'
import { escapeHTML, openSettings } from '@/utils'
import Link from '@/components/Controls/Link.vue'
import Draggable from 'vuedraggable'
import ProgramProgressSummary from '@/pages/Programs/ProgramProgressSummary.vue'
@@ -362,7 +362,12 @@ const fetchMembers = () => {
programMembers.reload()
}
const validateTitle = () => {
program.value.name = escapeHTML(program.value.name.trim())
}
const saveProgram = (close: () => void) => {
validateTitle()
if (props.programName === 'new') createNewProgram(close)
else updateProgram(close)
dirty.value = false

View File

@@ -231,6 +231,7 @@ import {
import { sessionStore } from '../stores/session'
import { ClipboardList, ListChecks, Plus, Trash2 } from 'lucide-vue-next'
import { useRouter } from 'vue-router'
import { escapeHTML } from '@/utils'
import Question from '@/components/Modals/Question.vue'
const { brand } = sessionStore()
@@ -294,7 +295,12 @@ const quizDetails = createDocumentResource({
},
})
const validateTitle = () => {
quizDetails.doc.title = escapeHTML(quizDetails.doc.title.trim())
}
const submitQuiz = () => {
validateTitle()
quizDetails.setValue.submit(
{
...quizDetails.doc,

View File

@@ -138,6 +138,7 @@ import { useRouter } from 'vue-router'
import { computed, inject, onMounted, ref, watch } from 'vue'
import { Plus } from 'lucide-vue-next'
import { sessionStore } from '@/stores/session'
import { escapeHTML } from '@/utils'
import EmptyState from '@/components/EmptyState.vue'
const { brand } = sessionStore()
@@ -191,7 +192,12 @@ const quizzes = createListResource({
},
})
const validateTitle = () => {
title.value = escapeHTML(title.value.trim())
}
const insertQuiz = (close) => {
validateTitle()
quizzes.insert.submit(
{
title: title.value,