Skip to content

Commit e10a4b8

Browse files
authored
Merge pull request #4 from PeterEsenwa/tobe/chore/imageUploadFunc
Upload image Functionality
2 parents 218512f + 209a6d4 commit e10a4b8

File tree

3 files changed

+102
-0
lines changed

3 files changed

+102
-0
lines changed

src/Demo/Demo.vue

+7
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import VueDocumentEditor from '../DocumentEditor/DocumentEditor.vue'; // set fro
2222
import InvoiceTemplate from './InvoiceTemplate.ce.vue';
2323
import { markRaw } from 'vue';
2424
import useDocument from "@/composables/useDocument.ts";
25+
import useImageUpload from "@/composables/useImageUpload";
26+
2527
2628
export default {
2729
components: { VueDocumentEditor, VueFileToolbarMenu },
@@ -127,6 +129,7 @@ export default {
127129
// Main commands
128130
{ text: "New", title: "New", icon: "description", click: () => { if(confirm("This will create an empty document. Are you sure?")){ this.content = [""]; this.resetContentHistory(); } } },
129131
{ text: "Print", title: "Print", icon: "print", click: () => window.print() },
132+
{ text: "Insert Image", icon: "image", disabled: !this.current_text_style, title: "Insert Image", click: () => this.addImage() },
130133
131134
{ is: "spacer" },
132135
@@ -384,9 +387,13 @@ export default {
384387
canUndo,
385388
} = useDocument();
386389
390+
const {
391+
addImage,
392+
} = useImageUpload();
387393
388394
return {
389395
content,
396+
addImage,
390397
undo,
391398
redo,
392399
canRedo,

src/composables/useImageUpload.ts

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import {insertHtmlAtCursor} from "@/utils/insertHTMLStCursor";
2+
3+
4+
interface UseImageUploadComposable {
5+
addImage: () => void;
6+
}
7+
8+
export default (): UseImageUploadComposable => {
9+
// Create a hidden file input element
10+
const addImage = () => {
11+
let fileInput = document.getElementById('fileInput') as HTMLInputElement;
12+
13+
if (!fileInput) {
14+
fileInput = document.createElement('input');
15+
fileInput.type = 'file';
16+
fileInput.accept = 'image/*';
17+
fileInput.id = 'fileInput';
18+
fileInput.style.display = 'none';
19+
document.body.appendChild(fileInput);
20+
}
21+
22+
// Trigger the click event on the file input element
23+
fileInput.click();
24+
25+
// When file input changes (user has selected a file),
26+
// read the image file and convert to a base64 string
27+
fileInput.onchange = (event: Event) => {
28+
const file = (event.target as HTMLInputElement).files?.[0]; // Get the selected file
29+
const reader = new FileReader();
30+
31+
reader.onloadend = () => {
32+
const base64String = reader.result as string;
33+
// Assume index is the location where the image tag is to be added
34+
let index = 0;
35+
36+
// Check if there is an element at this index
37+
insertHtmlAtCursor(`<img class="resizable-image" src="${base64String}" alt="User image" width="200px" height="200px">`);
38+
};
39+
40+
if (file) {
41+
reader.readAsDataURL(file);
42+
}
43+
}
44+
}
45+
return {
46+
addImage,
47+
};
48+
}

src/utils/insertHTMLStCursor.ts

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
export function insertHtmlAtCursor(html: string) {
2+
let sel: Selection | null, range: Range;
3+
4+
// Check if browser supports window.getSelection()
5+
if (window.getSelection) {
6+
sel = window.getSelection();
7+
8+
if (!sel) {
9+
return
10+
}
11+
12+
// If some text is already selected or cursor is somewhere in the document
13+
if (sel.getRangeAt && sel.rangeCount) {
14+
// Get the first range of the selection
15+
range = sel.getRangeAt(0);
16+
17+
// Delete any selected text
18+
range.deleteContents();
19+
20+
// Create a new div element and set its inner HTML to the passed HTML string
21+
let el: HTMLDivElement = document.createElement("div");
22+
el.innerHTML = html;
23+
24+
// Create an empty DocumentFragment that will hold the nodes for insertion
25+
let frag: DocumentFragment = document.createDocumentFragment(), node: ChildNode | null, lastNode: ChildNode | null = null;
26+
27+
// Move all child nodes of the div element to the DocumentFragment
28+
while ((node = el.firstChild)) {
29+
lastNode = frag.appendChild(node);
30+
}
31+
32+
// Insert the DocumentFragment at the current cursor position (i.e., where the range starts)
33+
range.insertNode(frag);
34+
35+
// If there is a last node after inserting the fragment, move the cursor after the last inserted node
36+
if (lastNode) {
37+
range = range.cloneRange();
38+
range.setStartAfter(lastNode);
39+
range.collapse(true);
40+
41+
// Clear all ranges from the selection and add the new range
42+
sel.removeAllRanges();
43+
sel.addRange(range);
44+
}
45+
}
46+
}
47+
}

0 commit comments

Comments
 (0)