Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 7ade796

Browse files
added readme
1 parent 28a74fe commit 7ade796

File tree

4 files changed

+292
-4
lines changed

4 files changed

+292
-4
lines changed

‎each day build day!/Day 11/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Drag & Drop images with vanilla JS
2+
3+
This projects aims to utilize the <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API">`Drag and Drop api` </a> It use four events `dragenter` `dragleave` `dragover` `drop`
4+
to handle files. As a fallback it use `input type = file`. It can handle multiple files at time, with letting user preview it before the upload. It is used by various browser based tools like imgeditor, canva etc.
5+
6+
7+
# Challenges
8+
- Drag and Drop Api
9+
- file previewing
10+
- Ajax
11+
- Async file handling
12+
- cross browser file upload
13+

‎each day build day!/Day 11/app.js

Lines changed: 228 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,230 @@
11
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;
310

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+
}

‎each day build day!/Day 11/index.html

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,20 @@
33
<head>
44
<meta charset="UTF-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6-
<title>Deag & Drop File upload 📁 </title>
6+
<title>Drag & Drop File upload 📁 </title>
7+
<link rel="stylesheet" href="style.css">
78
</head>
89
<body>
910

1011
<div class="container">
1112
<h1>Drag & Drop file upload using vanilla JS 📁 </h1>
1213

1314
<div id="drop-region">
15+
1416
<div class="drop-message">Drag & Drop files or click to upload</div>
1517
<div id="image-preview"></div>
1618
</div>
17-
19+
<buttonclass="btn" onclick="upload()">Upload 🔼 </button>
1820
</div>
1921

2022
<script src="app.js"></script>

‎each day build day!/Day 11/style.css

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
:root{
2-
font-size: 62.5%;
2+
font-size:80%;
3+
background-color: rgb(64, 66, 66);
34
}
45
.container{
56
min-height: 30rem;
@@ -8,4 +9,49 @@
89
justify-content: start;
910
align-items: center;
1011
}
12+
.btn{
13+
margin-top: 20px;
14+
background-color: grey;
15+
border: none;
16+
cursor: pointer;
17+
}
18+
#drop-region {
19+
background-color: #fff;
20+
border-radius:20px;
21+
box-shadow:0 0 35px rgba(0,0,0,0.05);
22+
width:400px;
23+
padding:60px 40px;
24+
text-align: center;
25+
cursor:pointer;
26+
transition:.3s;
27+
}
28+
#drop-region:hover {
29+
box-shadow:0 0 45px rgba(0,0,0,0.1);
30+
}
31+
32+
#image-preview {
33+
margin-top:20px;
34+
}
35+
#image-preview .image-view {
36+
display: inline-block;
37+
position:relative;
38+
margin-right: 13px;
39+
margin-bottom: 13px;
40+
}
41+
#image-preview .image-view img {
42+
max-width: 100px;
43+
max-height: 100px;
44+
}
45+
#image-preview .overlay {
46+
position: absolute;
47+
width: 100%;
48+
height: 100%;
49+
top: 0;
50+
right: 0;
51+
z-index: 2;
52+
background: rgba(255,255,255,0.5);
53+
}
1154

55+
.highlighted {
56+
background-color:grey;
57+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /