|
1 | 1 | const dropRegion = document.getElementById('drop-region');
|
2 |
| -const previewRegion = document.getElementById('image-preview'); |
| 2 | +const imagePreviewRegion = document.getElementById('image-preview'); |
| 3 | +const overlay = document.createElement("div"); |
| 4 | +let imagetoUpload; |
| 5 | +// open file selector when clicked on the drop region |
| 6 | +const fakeInput = document.createElement("input"); |
| 7 | +fakeInput.type = "file"; |
| 8 | +fakeInput.accept = "image/*"; //multiple values like image/png, image/jpeg. |
| 9 | +fakeInput.multiple = true; |
3 | 10 |
|
| 11 | + |
| 12 | +dropRegion.addEventListener('click', function () { |
| 13 | + fakeInput.click(); |
| 14 | +}); |
| 15 | + |
| 16 | +fakeInput.addEventListener("change", function () { |
| 17 | + const files = fakeInput.files; |
| 18 | + handleFiles(files); |
| 19 | +}); |
| 20 | + |
| 21 | + |
| 22 | + |
| 23 | +function preventDefault(e) { |
| 24 | + e.preventDefault(); |
| 25 | + e.stopPropagation(); |
| 26 | +} |
| 27 | + |
| 28 | +/* |
| 29 | +The Drag & Drop API defines 8 events: 4 events for the draggable element and 4 events for the droppable element. We will only need the latter 4 when developing a drag & drop image uploading. |
| 30 | +
|
| 31 | + dragenter: a dragged item enters a valid drop target. |
| 32 | + dragleave: a dragged item leaves a valid drop target. |
| 33 | + dragover: a dragged item is being dragged over a valid drop target. Triggered every few hundred milliseconds. |
| 34 | + drop: an item is dropped on a valid drop target. |
| 35 | +
|
| 36 | +*/ |
| 37 | +dropRegion.addEventListener('dragenter', preventDefault, false); |
| 38 | +dropRegion.addEventListener('dragleave', preventDefault, false); |
| 39 | +dropRegion.addEventListener('dragover', preventDefault, false); |
| 40 | +dropRegion.addEventListener('drop', preventDefault, false); |
| 41 | + |
| 42 | +//handle drop event |
| 43 | +function handleDrop(e) { |
| 44 | + const dt = e.dataTransfer, |
| 45 | + files = dt.files; |
| 46 | + |
| 47 | + if (files.length) { |
| 48 | + |
| 49 | + handleFiles(files); |
| 50 | + |
| 51 | + } else { |
| 52 | + |
| 53 | + // check for img |
| 54 | + const html = dt.getData('text/html'), |
| 55 | + match = html && /\bsrc="?([^"\s]+)"?\s*/.exec(html), |
| 56 | + url = match && match[1]; |
| 57 | + |
| 58 | + |
| 59 | + |
| 60 | + if (url) { |
| 61 | + uploadImageFromURL(url); |
| 62 | + return; |
| 63 | + } |
| 64 | + |
| 65 | + } |
| 66 | + |
| 67 | + |
| 68 | + function uploadImageFromURL(url) { |
| 69 | + let img = new Image; |
| 70 | + let c = document.createElement("canvas"); |
| 71 | + let ctx = c.getContext("2d"); |
| 72 | + |
| 73 | + img.onload = function () { |
| 74 | + c.width = this.naturalWidth; // update canvas size to match image |
| 75 | + c.height = this.naturalHeight; |
| 76 | + ctx.drawImage(this, 0, 0); // draw in image |
| 77 | + c.toBlob(function (blob) { // get content as PNG blob |
| 78 | + |
| 79 | + // call our main function |
| 80 | + handleFiles([blob]); |
| 81 | + |
| 82 | + }, "image/png"); |
| 83 | + }; |
| 84 | + img.onerror = function () { |
| 85 | + alert("Error in uploading"); |
| 86 | + } |
| 87 | + img.crossOrigin = ""; // if from different origin |
| 88 | + img.src = url; |
| 89 | + } |
| 90 | + |
| 91 | +} |
| 92 | + |
| 93 | +dropRegion.addEventListener('drop', handleDrop, false); |
| 94 | + |
| 95 | +/* |
| 96 | +handleFiles() function which gets a File List and upload each item. |
| 97 | +
|
| 98 | +*/ |
| 99 | +function handleFiles(files) { |
| 100 | + for (let i = 0, len = files.length; i < len; i++) { |
| 101 | + if (validateImage(files[i])) |
| 102 | + previewImage(files[i]); |
| 103 | + |
| 104 | + } |
| 105 | + |
| 106 | + imagetoUpload = [...files]; |
| 107 | +} |
| 108 | + |
| 109 | +/* |
| 110 | +check if the file is 'MIME' type and file size is < 10MB |
| 111 | +--> validation on client-side equals better user XP |
| 112 | +*/ |
| 113 | +function validateImage(image) { |
| 114 | + // check the type |
| 115 | + const validTypes = ['image/jpeg', 'image/png', 'image/gif']; |
| 116 | + if (validTypes.indexOf(image.type) === -1) { |
| 117 | + alert("Invalid File Type"); |
| 118 | + return false; |
| 119 | + } |
| 120 | + |
| 121 | + // check the size |
| 122 | + const maxSizeInBytes = 10e6; // 10MB |
| 123 | + if (image.size > maxSizeInBytes) { |
| 124 | + alert("File too large"); |
| 125 | + return false; |
| 126 | + } |
| 127 | + |
| 128 | + return true; |
| 129 | +} |
| 130 | + |
| 131 | + |
| 132 | +/* |
| 133 | +Previewing |
| 134 | +1. after upload |
| 135 | +2. before upload -> fast and efficient |
| 136 | +*/ |
| 137 | + |
| 138 | +function previewImage(image) { |
| 139 | + |
| 140 | + // container |
| 141 | + const imgView = document.createElement("div"); |
| 142 | + imgView.className = "image-view"; |
| 143 | + imagePreviewRegion.appendChild(imgView); |
| 144 | + |
| 145 | + // previewing image |
| 146 | + const img = document.createElement("img"); |
| 147 | + imgView.appendChild(img); |
| 148 | + |
| 149 | + // progress overlay |
| 150 | + |
| 151 | + overlay.className = "overlay"; |
| 152 | + imgView.appendChild(overlay); |
| 153 | + |
| 154 | + // read the image... |
| 155 | + const reader = new FileReader(); |
| 156 | + reader.onload = function (e) { |
| 157 | + img.src = e.target.result; |
| 158 | + } |
| 159 | + reader.readAsDataURL(image); |
| 160 | + |
| 161 | + //Uploading to the server, create a FormData Object and use Ajax or fetch |
| 162 | + |
| 163 | + return image; |
| 164 | +} |
| 165 | + |
| 166 | + |
| 167 | + |
| 168 | +function upload(imagetoUpload){ |
| 169 | + console.log('function called') |
| 170 | + // create FormData |
| 171 | + const formData = new FormData(); |
| 172 | + formData.append('image', imagetoUpload); |
| 173 | + |
| 174 | + // upload the image |
| 175 | + const uploadLocation = 'UPLOAD_LOCATION'; |
| 176 | + |
| 177 | + const ajax = new XMLHttpRequest(); |
| 178 | + ajax.open("POST", uploadLocation, true); |
| 179 | + |
| 180 | + ajax.onreadystatechange = function(e) { |
| 181 | + if (ajax.readyState === 4) { |
| 182 | + if (ajax.status === 200) { |
| 183 | + // done! |
| 184 | + } else { |
| 185 | + // error! |
| 186 | + } |
| 187 | + } |
| 188 | + } |
| 189 | + |
| 190 | + ajax.upload.onprogress = function(e) { |
| 191 | + |
| 192 | + // change progress |
| 193 | + // (reduce the width of overlay) |
| 194 | + |
| 195 | + const perc = (e.loaded / e.total * 100) || 100, |
| 196 | + width = 100 - perc; |
| 197 | + |
| 198 | + overlay.style.width = width; |
| 199 | + } |
| 200 | + |
| 201 | + ajax.send(formData); |
| 202 | +} |
| 203 | + |
| 204 | + |
| 205 | +//for detecting file upload |
| 206 | + |
| 207 | +dropRegion.addEventListener('dragenter', highlight, false); |
| 208 | +dropRegion.addEventListener('dragover', highlight, false); |
| 209 | +dropRegion.addEventListener('dragleave', unhighlight, false); |
| 210 | +dropRegion.addEventListener('drop', unhighlight, false); |
| 211 | + |
| 212 | +function highlight() { |
| 213 | + dropRegion.classList.add('highlighted'); |
| 214 | +} |
| 215 | +function unhighlight() { |
| 216 | + dropRegion.classList.remove("highlighted"); |
| 217 | +} |
| 218 | + |
| 219 | + |
| 220 | +//for no bowser support |
| 221 | +function detectDragDrop() { |
| 222 | + const div = document.createElement('div'); |
| 223 | + return ('draggable' in div) || ('ondragstart' in div && 'ondrop' in div) |
| 224 | +} |
| 225 | + |
| 226 | +// change the message |
| 227 | +const dragSupported = detectDragDrop(); |
| 228 | +if (!dragSupported) { |
| 229 | + document.getElementsByClassName("drop-message")[0].innerHTML = 'Click to upload'; |
| 230 | +} |
0 commit comments