fix: contedtable
This commit is contained in:
37
bo/src/composable/useConteditable.ts
Normal file
37
bo/src/composable/useConteditable.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { ref, type Ref } from 'vue'
|
||||
import DOMPurify from 'dompurify'
|
||||
import { useProductStore } from '@/stores/product'
|
||||
|
||||
export function useEditable() {
|
||||
const isEditing = ref(false)
|
||||
const productStore = useProductStore()
|
||||
|
||||
const removeAttribute = (editableRef: HTMLElement | null) => {
|
||||
if (!editableRef) return
|
||||
isEditing.value = true
|
||||
Array.from(editableRef.children).forEach(item => {
|
||||
item.setAttribute('contenteditable', 'true')
|
||||
console.log('lllllll')
|
||||
})
|
||||
}
|
||||
|
||||
const setAttribute = async (editableRef: HTMLElement | null): Promise<string | undefined> => {
|
||||
if (!editableRef) return
|
||||
Array.from(editableRef.children).forEach(item => {
|
||||
item.setAttribute('contenteditable', 'false')
|
||||
})
|
||||
isEditing.value = false
|
||||
|
||||
const html = editableRef.innerHTML
|
||||
const cleanHtml = DOMPurify.sanitize(html)
|
||||
await productStore.saveProductDescription(cleanHtml)
|
||||
|
||||
return cleanHtml
|
||||
}
|
||||
|
||||
return {
|
||||
isEditing,
|
||||
removeAttribute,
|
||||
setAttribute
|
||||
}
|
||||
}
|
||||
@@ -49,9 +49,7 @@ export const useProductStore = defineStore('product', () => {
|
||||
currentProduct.value = null
|
||||
|
||||
try {
|
||||
const data = await useFetchJson<{ items: Product }>(`/api/v1/restricted/product-description?id=${id}`, {
|
||||
method: 'GET',
|
||||
})
|
||||
const data = await useFetchJson<{ items: Product }>(`/api/v1/restricted/product-description?id=${id}`)
|
||||
|
||||
const response = (data as any).items || data
|
||||
currentProduct.value = response.items?.[0] || response
|
||||
@@ -63,6 +61,34 @@ export const useProductStore = defineStore('product', () => {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function saveProductDescription(description: string) {
|
||||
try {
|
||||
const data = await useFetchJson(
|
||||
`/api/v1/restricted/product-description/save-product-description?productID=1&productShopID=1&productLangID=1`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
description: description,
|
||||
description_short: "<p>Test short</p>",
|
||||
meta_description: "This is a test",
|
||||
meta_title: "...",
|
||||
name: "...",
|
||||
available_now: "Test",
|
||||
available_later: "...",
|
||||
usage: "<p>test</p>"
|
||||
})
|
||||
}
|
||||
)
|
||||
return data
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
// Clear current product
|
||||
function clearCurrentProduct() {
|
||||
currentProduct.value = null
|
||||
@@ -76,5 +102,6 @@ export const useProductStore = defineStore('product', () => {
|
||||
getProductDescription,
|
||||
fetchProductById,
|
||||
clearCurrentProduct,
|
||||
saveProductDescription
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,34 +1,36 @@
|
||||
<template>
|
||||
<div class="container my-10 ">
|
||||
<div id="textDescriptionRef" ref="textDescriptionRef" v-html="productStore.productDescription.description"></div>
|
||||
<button @click="create">create</button>
|
||||
<button @click="save">Save</button>
|
||||
<div class="flex items-start gap-30">
|
||||
<div class="flex flex-col gap-10">
|
||||
<p class="p-60 bg-yellow-300">img</p>
|
||||
<div class="flex gap-3 mb-3">
|
||||
<button @click="removeAttribute(editableRef)"
|
||||
class="p-2 border border-(--border-light) dark:border-(--border-dark)">create</button>
|
||||
<button @click="setAttribute(editableRef)"
|
||||
class="p-2 border border-(--border-light) dark:border-(--border-dark)">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-[25px] font-bold">{{ productStore.productDescription.name }}</p>
|
||||
<p>{{ productStore.productDescription.available_now }}</p>
|
||||
<p ref="editableRef2" v-html="productStore.productDescription.usage"></p>
|
||||
</div>
|
||||
</div>
|
||||
<div ref="editableRef" v-html="productStore.productDescription.description"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { useProductStore } from '@/stores/product'
|
||||
import { useEditable } from '@/composable/useConteditable'
|
||||
import { ref } from 'vue'
|
||||
|
||||
|
||||
const productStore = useProductStore()
|
||||
const textDescriptionRef = ref<HTMLElement | null>(null)
|
||||
|
||||
await productStore.getProductDescription()
|
||||
|
||||
const save = () => {
|
||||
const myDiv = document.getElementById("textDescriptionRef");
|
||||
Array.from(myDiv.children).forEach(item => {
|
||||
item.setAttribute('contenteditable', 'false')
|
||||
})
|
||||
}
|
||||
|
||||
const create = () => {
|
||||
const myDiv = document.getElementById("textDescriptionRef");
|
||||
Array.from(myDiv.children).forEach(item => {
|
||||
item.setAttribute('contenteditable', 'true')
|
||||
})
|
||||
}
|
||||
const editableRef = ref<HTMLElement | null>(null)
|
||||
const { removeAttribute, setAttribute } = useEditable()
|
||||
|
||||
</script>
|
||||
|
||||
@@ -39,4 +41,5 @@ const create = () => {
|
||||
gap: 70px;
|
||||
margin: 20px 0 20px 0;
|
||||
}
|
||||
|
||||
</style>
|
||||
17
package-lock.json
generated
17
package-lock.json
generated
@@ -7,6 +7,7 @@
|
||||
"dependencies": {
|
||||
"@nuxt/ui": "^4.5.1",
|
||||
"chart.js": "^4.5.1",
|
||||
"dompurify": "^3.3.3",
|
||||
"vue-chartjs": "^5.3.3"
|
||||
}
|
||||
},
|
||||
@@ -1960,6 +1961,13 @@
|
||||
"integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/trusted-types": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
|
||||
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/@types/web-bluetooth": {
|
||||
"version": "0.0.21",
|
||||
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz",
|
||||
@@ -2441,6 +2449,15 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/dompurify": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.3.tgz",
|
||||
"integrity": "sha512-Oj6pzI2+RqBfFG+qOaOLbFXLQ90ARpcGG6UePL82bJLtdsa6CYJD7nmiU8MW9nQNOtCHV3lZ/Bzq1X0QYbBZCA==",
|
||||
"license": "(MPL-2.0 OR Apache-2.0)",
|
||||
"optionalDependencies": {
|
||||
"@types/trusted-types": "^2.0.7"
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "17.3.1",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.3.1.tgz",
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"dependencies": {
|
||||
"@nuxt/ui": "^4.5.1",
|
||||
"chart.js": "^4.5.1",
|
||||
"dompurify": "^3.3.3",
|
||||
"vue-chartjs": "^5.3.3"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user