Created
November 14, 2018 08:31
-
-
Save jotaelesalinas/d0f86aa1692e362f349417b48ccd34ea to your computer and use it in GitHub Desktop.
Javascript script for easy drag and drop on an HTML element
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Configures an element to receive files via drag'n'drop. | |
* - el: drop element, either id string or HTMLElement object. | |
* - cb_ok: callback, accepts: contents or data returned by preprocessor, file and index; called once per successfully preprocessed file. | |
* - cb_fail: callback, accepts error, file and index; called once per failed file. | |
* - preprocessor: function that accepts the contents of the file and can return any data; accepts: contents, file, index; called once per dropped file. | |
* - cb_start: callback, called before preprocessing all files, accepts the files, can throw, e.g. if wrong filetypes | |
* - cb_finished: callback, called after handling all files, no matter is failed or not | |
* - css: CSS styles to be applied to the drop element | |
*/ | |
var dragndrop = function (el, cb_ok, cb_fail, options) { | |
var defaults = { | |
preprocessor: function (file, content) { return content; }, | |
cb_start: function () {}, | |
cb_finished: function () {}, | |
css: null | |
}; | |
var options = Object.assign({}, defaults, options); | |
var prev_styles = false; | |
/* What to do when dragging over the element -- change the cursor | |
*/ | |
var handleDragOver = function (evt) { | |
evt.stopPropagation(); | |
evt.preventDefault(); | |
evt.dataTransfer.dropEffect = 'copy'; | |
}; | |
/* What to do when the files are dropped | |
*/ | |
var handleFileSelect = function (evt) { | |
evt.stopPropagation(); | |
evt.preventDefault(); | |
startProcessingFiles(evt.dataTransfer.files); | |
}; | |
/* Processes the list of dropped files. | |
* - creates a list of pending files | |
* - runs the handler for each file | |
*/ | |
var startProcessingFiles = function (filelist) { | |
files = Array.from(filelist); | |
pending_files = {}; | |
try { | |
options.cb_start(files); | |
} catch (err) { | |
console.log('ERROR in cb_start():', err); | |
throw err; | |
} | |
files.forEach(f => pending_files[f.name] = true); | |
files.forEach((f, idx) => processFile(f, idx, options.preprocessor, cb_ok, cb_fail, whenFinished)); | |
}; | |
/* Runs cb_finished after the last file is handled. | |
* This function is called after each file is habdled. | |
*/ | |
var whenFinished = function (file) { | |
pending_files[file.name] = false; | |
for ( var idx in pending_files ) { | |
if ( pending_files[idx] ) { | |
// there are still pending files | |
return; | |
} | |
} | |
files = null; | |
pending_files = null; | |
options.cb_finished(); | |
}; | |
/* Reads a file using the borwser's File API. | |
* file: File from File API | |
* cb_ok: callback, accepts file and content | |
* cb_fail: callback, accepts file and event | |
*/ | |
var readFile = function (file, cb_ok, cb_fail) { | |
var fr = new window.FileReader(); | |
fr.onload = function (evt) { | |
cb_ok(file, evt.target.result); | |
}; | |
fr.onerror = function (evt) { | |
cb_fail(file, evt); | |
}; | |
//fr.readAsText(file); | |
fr.readAsBinaryString(file); | |
}; | |
/* Process a file using a provided handling function | |
* - file: File from File API | |
* - handler: function that accepts the binary content of the file and returns anything | |
* - cb_ok: callback, accepts file and content | |
* - cb_fail: callback, accepts file and event | |
* - cb_always: callback, called after handling, no matter is failed or not | |
*/ | |
var processFile = function (file, idx, handler, cb_ok, cb_fail, cb_always) { | |
readFile(file, function (file, contents) { | |
var text; | |
try { | |
text = handler(contents, file, idx); | |
cb_ok(text, file, idx); | |
} catch (err) { | |
cb_fail(err, file, idx); | |
} | |
cb_always(file, idx); | |
}, function (file) { | |
cb_always(file, idx); | |
}); | |
}; | |
/* Setup the listeners for the drag'n'drop | |
*/ | |
var drop_element = typeof el === 'string' ? document.getElementById(el) : el; | |
drop_element.addEventListener('dragover', handleDragOver, false); | |
drop_element.addEventListener('drop', handleFileSelect, false); | |
if ( options.css ) { | |
for ( var idx in options.css ) { | |
drop_element.style[idx] = options.css[idx]; | |
} | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html> | |
<head> | |
<title>dragndrop test</title> | |
<meta charset="utf-8"> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<style> | |
html, body { | |
font-family: 'segoe ui', calibri, arial, sans-serif; | |
font-size: 15px; | |
} | |
body { | |
margin: 2em; | |
} | |
#drop-zone { | |
margin: 1em; | |
margin-bottom: 0; | |
padding: 2em; | |
text-align: center; | |
font-size: 200%; | |
font-weight: bold; | |
font-family: serif; | |
} | |
.use-mozilla { | |
color: crimson; | |
} | |
@media print { | |
#drop-zone { | |
display:none; | |
} | |
} | |
#output { | |
margin: 2em; | |
padding: 2em; | |
background-color: darkslategray; | |
color: whitesmoke; | |
} | |
.test { | |
margin: 2em; | |
margin-bottom: 0; | |
padding: 0; | |
border: 2px solid CornflowerBlue; | |
} | |
.test .name { | |
margin: 0; | |
background-color: CornflowerBlue; | |
color: white; | |
padding: 15px; | |
font-weight: normal; | |
} | |
.test .qas { | |
margin: 0; | |
padding: 1em 2em; | |
} | |
.test .qa { | |
margin: 0; | |
margin-bottom: 1em; | |
} | |
.test .qa.noanswer { | |
display: none; | |
} | |
.test .q { | |
margin: 0; | |
} | |
.test .a { | |
margin: 0; | |
} | |
.test .a:before { | |
content: " \2192\00a0"; | |
} | |
</style> | |
</head> | |
<body> | |
<h1>dragndrop test</h1> | |
<div id="drop-zone"> | |
Drop one or more files here. | |
<br> | |
Use Mozilla Firefox or Google Chrome. It does NOT work with Internet Explorer. | |
</div> | |
<pre id="output"></pre> | |
<script src='dragndrop.js'></script> | |
<script> | |
var console2 = console; | |
var console = { | |
out: document.getElementById('output'), | |
log: function () { | |
console2.log(...arguments); | |
this.out.innerHTML += [...arguments].join(", ") + "\n"; | |
} | |
}; | |
var fileOk = function (data, file, index) { | |
console.log('fileOk()'); | |
console.log('data', data); | |
console.log('file name', file.name); | |
console.log('index', index); | |
}; | |
var fileErr = function (err, file, index) { | |
console.log('fileErr()'); | |
console.log('err', err); | |
console.log('file name', file.name); | |
console.log('index', index); | |
}; | |
var onStart = function (files) { | |
console.log('onStart()'); | |
console.log('files', files); | |
}; | |
var preprocess = function (contents, file, index) { | |
console.log('preprocess()'); | |
console.log('contents.length', contents.length); | |
console.log('file name', file.name); | |
console.log('index', index); | |
if ( index == 1 ) { | |
throw "Super critical error!"; | |
} | |
return file.name + ' (' + contents.length + ')'; | |
} | |
var onFinished = function () { | |
console.log('onFinished()'); | |
console.log('Done!'); | |
}; | |
var css = { | |
"border": 'thick dashed', | |
"border-radius": '.25em', | |
"border-color": 'orangered' | |
}; | |
dragndrop('drop-zone', fileOk, fileErr, { | |
preprocessor: preprocess, | |
cb_start: onStart, | |
cb_finished: onFinished, | |
css}); | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment