diff --git a/src/Demo/Demo.vue b/src/Demo/Demo.vue index ad5a55b..9e79846 100644 --- a/src/Demo/Demo.vue +++ b/src/Demo/Demo.vue @@ -22,6 +22,8 @@ import VueDocumentEditor from '../DocumentEditor/DocumentEditor.vue'; // set fro import InvoiceTemplate from './InvoiceTemplate.ce.vue'; import { markRaw } from 'vue'; import useDocument from "@/composables/useDocument.ts"; +import useImageUpload from "@/composables/useImageUpload"; + export default { components: { VueDocumentEditor, VueFileToolbarMenu }, @@ -127,6 +129,7 @@ export default { // Main commands { text: "New", title: "New", icon: "description", click: () => { if(confirm("This will create an empty document. Are you sure?")){ this.content = [""]; this.resetContentHistory(); } } }, { text: "Print", title: "Print", icon: "print", click: () => window.print() }, + { text: "Insert Image", icon: "image", disabled: !this.current_text_style, title: "Insert Image", click: () => this.addImage() }, { is: "spacer" }, @@ -384,9 +387,13 @@ export default { canUndo, } = useDocument(); + const { + addImage, + } = useImageUpload(); return { content, + addImage, undo, redo, canRedo, diff --git a/src/composables/useImageUpload.ts b/src/composables/useImageUpload.ts new file mode 100644 index 0000000..df90ea5 --- /dev/null +++ b/src/composables/useImageUpload.ts @@ -0,0 +1,48 @@ +import {insertHtmlAtCursor} from "@/utils/insertHTMLStCursor"; + + +interface UseImageUploadComposable { + addImage: () => void; +} + +export default (): UseImageUploadComposable => { + // Create a hidden file input element + const addImage = () => { + let fileInput = document.getElementById('fileInput') as HTMLInputElement; + + if (!fileInput) { + fileInput = document.createElement('input'); + fileInput.type = 'file'; + fileInput.accept = 'image/*'; + fileInput.id = 'fileInput'; + fileInput.style.display = 'none'; + document.body.appendChild(fileInput); + } + + // Trigger the click event on the file input element + fileInput.click(); + + // When file input changes (user has selected a file), + // read the image file and convert to a base64 string + fileInput.onchange = (event: Event) => { + const file = (event.target as HTMLInputElement).files?.[0]; // Get the selected file + const reader = new FileReader(); + + reader.onloadend = () => { + const base64String = reader.result as string; + // Assume index is the location where the image tag is to be added + let index = 0; + + // Check if there is an element at this index + insertHtmlAtCursor(`User image`); + }; + + if (file) { + reader.readAsDataURL(file); + } + } + } + return { + addImage, + }; +} \ No newline at end of file diff --git a/src/utils/insertHTMLStCursor.ts b/src/utils/insertHTMLStCursor.ts new file mode 100644 index 0000000..f37769a --- /dev/null +++ b/src/utils/insertHTMLStCursor.ts @@ -0,0 +1,47 @@ +export function insertHtmlAtCursor(html: string) { + let sel: Selection | null, range: Range; + + // Check if browser supports window.getSelection() + if (window.getSelection) { + sel = window.getSelection(); + + if (!sel) { + return + } + + // If some text is already selected or cursor is somewhere in the document + if (sel.getRangeAt && sel.rangeCount) { + // Get the first range of the selection + range = sel.getRangeAt(0); + + // Delete any selected text + range.deleteContents(); + + // Create a new div element and set its inner HTML to the passed HTML string + let el: HTMLDivElement = document.createElement("div"); + el.innerHTML = html; + + // Create an empty DocumentFragment that will hold the nodes for insertion + let frag: DocumentFragment = document.createDocumentFragment(), node: ChildNode | null, lastNode: ChildNode | null = null; + + // Move all child nodes of the div element to the DocumentFragment + while ((node = el.firstChild)) { + lastNode = frag.appendChild(node); + } + + // Insert the DocumentFragment at the current cursor position (i.e., where the range starts) + range.insertNode(frag); + + // If there is a last node after inserting the fragment, move the cursor after the last inserted node + if (lastNode) { + range = range.cloneRange(); + range.setStartAfter(lastNode); + range.collapse(true); + + // Clear all ranges from the selection and add the new range + sel.removeAllRanges(); + sel.addRange(range); + } + } + } +} \ No newline at end of file