I want to upload folder to server by d'n'd via AJAX. But already, I have troubles with upload files.
I use e.dataTransfer.items and webkitGetAsEntry() to check - is it file or folder?
If it's file, in function traverseFileTree I get file, but I can't append it to formData.
If I use e.dataTransfer.files, I don't know what is it. File or Folder because webkitGetAsEntry() get error.
What I do wrong?
How transfer files to global array $_FILES.
Source (upload.php):
echo "<pre>";
print_r ($_FILES);
echo "</pre>";
Source (index.html):
<!DOCTYPE html>
<html>
<head>
<title>Drag and Drop</title>
<style>
body {
background: rgba(211,211,100, .5);
font: 20px Arial;
}
.dropzone {
width: 300px;
height: 300px;
border: 2px dashed #aaa;
color: #aaa;
line-height: 280px;
text-align: center;
position: absolute;
left: 50%;
margin-left: -150px;
top: 50%;
margin-top: -150px;
}
.dropzone.dragover {
color: green;
border: 2px dashed #000;
}
</style>
</head>
<body>
<p>Loaded files:</p>
<div id="uploads">
<ul>
</ul>
</div>
<div class="dropzone" id="dropzone">Drop files</div>
<script>
(function() {
var formData = new FormData();
var dropzone = document.getElementById("dropzone");
dropzone.ondrop = function(e) {
this.className = 'dropzone';
this.innerHTML = 'Drop files';
e.preventDefault();
upload(e.dataTransfer.items);
};
function traverseFileTree(item, path) {
path = path || "";
if (item.isFile) {
item.file(function(file) {
console.log(file); // show info
formData.append('file[]', file); // file exist, but don't append
});
} /*else if (item.isDirectory) {
var dirReader = item.createReader();
dirReader.readEntries(function(entries) {
for (var i=0; i<entries.length; i++) {
traverseFileTree(entries[i], path + item.name + "/");
}
});
}*/
}
var upload = function(items) {
var xhr = new XMLHttpRequest();
for(var i = 0; i < items.length; i++) {
var item = items[i].webkitGetAsEntry();
if (item) {
traverseFileTree(item,'');
}
}
xhr.onload = function() {
console.log(this.responseText);
};
xhr.open('post', 'upload.php');
xhr.send(formData);
};
dropzone.ondragover = function() {
this.className = 'dropzone dragover';
this.innerHTML = 'Mouse up';
return false;
};
dropzone.ondragleave = function() {
this.className = 'dropzone';
this.innerHTML = 'Drop files';
return false;
};
})();
</script>
Both file() and readEntries() return results asynchronously. Since it is impossible to know for certain how many files or directories, which themselves could contain additional directories containing still more files or folders, will be selected and dropped by user, the a single or recursive calls to traverseFileTree require some mechanism to determine when all asynchronous operations have completed. This can be achieved using one or more of several approaches.
The present approach increments a variable n, pushes each individual file to an array uploads. If n is 0, process the first file; increment n so that its value 1 greater than the array containing files .length until the array .length is equal to n - 1
uploads.length === n - 1 || n === 0
then copy uploads array using .slice(), set uploads.length and n to 0, pass array of files to function processFiles where files are appended to FormData() object, call to XMLHttpRequest() is made.
<!DOCTYPE html>
<html>
<head>
<title>Drag and Drop</title>
<style>
body {
background: rgba(211, 211, 100, .5);
font: 20px Arial;
}
.dropzone {
width: 300px;
height: 300px;
border: 2px dashed #aaa;
color: #aaa;
line-height: 280px;
text-align: center;
position: absolute;
left: 50%;
margin-left: -150px;
top: 50%;
margin-top: -150px;
}
.dropzone.dragover {
color: green;
border: 2px dashed #000;
}
</style>
</head>
<body>
<p>Loaded files:</p>
<div id="uploads">
<ul>
</ul>
</div>
<div class="dropzone" id="dropzone">Drop files</div>
<script>
(function() {
var n = 0, uploads = [];
var dropzone = document.getElementById("dropzone");
dropzone.ondrop = function(e) {
this.className = 'dropzone';
this.innerHTML = 'Drop files';
e.preventDefault();
upload(e.dataTransfer.items);
};
function processFiles(files) {
console.log("files:", files);
alert("processing " + files.length + " files");
var formData = new FormData();
// append files to `formData`
for (file of files) {
formData.append("file[]", file, file.name)
}
// check `formData` entries
var curr = 0;
for (data of formData.entries()) {
console.log("formData entry " + curr, data);
++curr;
}
delete curr;
// do ajax stuff here
var xhr = new XMLHttpRequest();
xhr.onload = function() {
console.log(this.responseText);
};
xhr.open("POST", "upload.php");
xhr.send(formData);
}
function traverseFileTree(item, path) {
var handleFiles = function handleFiles(item, path) {
path = path || "";
if (item.isFile) {
item.file(function(file) {
uploads.push(file);
console.log(file, n, uploads.length); // show info
if (uploads.length === n - 1 || n === 0) {
alert("traverseFiles complete, uploads length: "
+ uploads.length);
var files = uploads.slice(0);
n = uploads.length = 0;
processFiles(files)
}
});
} else if (item.isDirectory) {
var dirReader = item.createReader();
dirReader.readEntries(function(entries) {
// increment `n` here
n += entries.length;
for (var i = 0; i < entries.length; i++) {
handleFiles(entries[i], path + item.name + "/");
}
});
}
}
handleFiles(item, path);
}
var upload = function(items) {
if (n !== 0 && uploads.length !== 0) {
n = uploads.length = 0;
}
for (var i = 0; i < items.length; i++) {
var item = items[i].webkitGetAsEntry();
if (item) {
traverseFileTree(item, "");
}
}
};
dropzone.ondragover = function() {
this.className = 'dropzone dragover';
this.innerHTML = 'Mouse up';
return false;
};
dropzone.ondragleave = function() {
this.className = 'dropzone';
this.innerHTML = 'Drop files';
return false;
};
})();
</script>
</body>
</html>
plnkr http://plnkr.co/edit/OdFrwYH2gmbtvHfq3ZjH?p=preview
See also How can I filter out directories from upload handler in Firefox? , How to read files from folder
Related
i used by javascrip upload multiple file but that files insert different columns.
Why is it that when uploading multiple files with drag drop, they are written in multiple rows instead of one line in the database?
Pictured is a view of the data after inserting it into the database
My php Code is : uploads.php
if(isset($_FILES)){
$upload_dir = "upload/";
$fileName = strtolower(pathinfo($_FILES["files"]["name"], PATHINFO_EXTENSION));
$new_file_name = rand() . '.' . $fileName;
$uploaded_file = $upload_dir.$new_file_name;
if(move_uploaded_file($_FILES['files']['tmp_name'],$uploaded_file)){
}
$content = $_POST['textpost'];
$data = array(
':file' => $new_file_name,
':uploaded_on' => date("Y-m-d H:i:s"),
':content' => $content,
);
$query = "
INSERT INTO images
(name, uploaded_on ,content)
VALUES (:name,:uploaded_on,:content)
";
$statement = $connect->prepare($query);
$statement->execute($data);
}
The Below is the code I originally used. I used these codes as examples from other people’s codes. Then I made some changes myself and added a little functionality. For example, I added a few codes, such as deleting images, separating images and videos, and brought them to the function I needed. But the problem with me now is that When uploading multiple images at the same time as text, All data sent are insert into separate rows, Finally when I select the data from the database the content and images are not select out correctly.My goal is to insert images and text into a single line.
My javascript Code is :index.html
var dropRegion = document.getElementById("drop-region"),
// where images are previewed
imagePreviewRegion = document.getElementById("image-preview");
var file_drag_area = document.getElementById("file_drag_area");
var images_button = document.getElementById("images_btn");
var submit = document.getElementById("submit");
// open file selector when clicked on the drop region
var fakeInput = document.createElement("input");
fakeInput.type = "file";
fakeInput.accept = "video/*,image/*";
fakeInput.multiple = true;
images_button.addEventListener('click', function() {
fakeInput.click();
});
fakeInput.addEventListener("change", function() {
var files = fakeInput.files;
handleFiles(files);
});
function preventDefault(e) {
e.preventDefault();
e.stopPropagation();
}
file_drag_area.addEventListener('dragenter', preventDefault, false)
file_drag_area.addEventListener('dragleave', preventDefault, false)
file_drag_area.addEventListener('dragover', preventDefault, false)
file_drag_area.addEventListener('drop', preventDefault, false)
dropRegion.addEventListener('dragenter', preventDefault, false)
dropRegion.addEventListener('dragleave', preventDefault, false)
dropRegion.addEventListener('dragover', preventDefault, false)
dropRegion.addEventListener('drop', preventDefault, false)
function handleDrop(e) {
var dt = e.dataTransfer,
files = dt.files;
handleFiles(files)
}
dropRegion.addEventListener('drop', handleDrop, false);
file_drag_area.addEventListener('drop', handleDrop, false);
// when drag file the border change to other dotted
file_drag_area.addEventListener("dragenter", function(event) {
if ( event.target.className == "file_drag_area" ) {
event.target.style.border = "3px dotted #79d4ff";
}
});
// when drag file the border display none
file_drag_area.addEventListener("dragleave", function(event) {
if ( event.target.className == "trigger_popup_fricc_wrapper" ) {
event.target.style.border = "";
}
});
file_drag_area.addEventListener("drop", function(event) {
if ( event.target.className == "trigger_popup_fricc_wrapper" ) {
event.target.style.border = "";
}
});
function handleFiles(files) {
for (var i = 0, len = files.length; i < len; i++) {
if (validateImage(files[i]))
previewAnduploadImage(files[i]);
}
}
function validateImage(image) {
// check the type
var validTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/jpg','video/mp4', 'video/mkv', 'video/webm'];
var vedioType = validTypes.includes('video/mp4', 'video/mkv', 'video/webm');
if (validTypes.indexOf( image.type ) === -1 && vedioType.indexOf( video.type ) === -1) {
alert("Invalid File Type");
return false;
}
// check the size
var maxSizeInBytes = 10e6; // 10MB
if (image.size > maxSizeInBytes) {
alert("File too large");
return false;
}
return true;
}
function previewAnduploadImage(image) {
var fileType = image.type;
var match = ['image/jpeg', 'image/png', 'image/gif', 'image/jpg','video/mp4', 'video/mkv', 'video/webm'];
if ((fileType == match[0]) || (fileType == match[1]) || (fileType == match[2]) || (fileType == match[3])) {
var imgView = document.createElement("div");
imgView.className = "image-view";
imagePreviewRegion.appendChild(imgView);
var icon = document.createElement("div")
icon.className = "image-icon";
//icon.setAttribute("onclick", "remove_image()");
imgView.appendChild(icon);
var remove = document.createElement("img")
remove.className = "img_class";
remove.setAttribute("height", "20px");
remove.setAttribute("width", "20px");
remove.setAttribute("src", "../../assets/images/cancel.png");
icon.appendChild(remove);
// previewing image
var img = document.createElement("img");
img.className = "remove_input";
img.setAttribute("height", "200px");
img.setAttribute("width", "300px");
imgView.appendChild(img);
var reader = new FileReader();
reader.onload = function(e) {
img.src = e.target.result;
}
reader.readAsDataURL(image);
}else if ((fileType == match[4]) || (fileType == match[5]) || (fileType == match[6])) {
// show video
var video = document.createElement("video")
video.classList.add("obj");
video.file = image;
video.className = "preview_vedio";
video.controls = true;
video.autoplay = true;
video.setAttribute("width", "500");
video.setAttribute("height", "300");
//icon.setAttribute("onclick", "remove_image()");
imagePreviewRegion.appendChild(video);
var reader = new FileReader();
reader.onload = function(e) {
video.src = e.target.result;
}
reader.readAsDataURL(image);
}
var formData = new FormData();
formData.append('image', image);
formData.append('action', 'files');
//formData.append('vedio', vediofiles);
$("#drop-region").css("display", "block");
$("#drop-region").slideDown("slow")
addEventListener('submit', (event) => {
var uploadLocation = 'uploads.php';
var ajax = new XMLHttpRequest();
ajax.open("POST", uploadLocation, true);
ajax.onreadystatechange = function(e) {
if (ajax.readyState === 4) {
if (ajax.status === 200) {
//var myObj = JSON.parse(this.responseText);
} else {
// error!
}
}
}
ajax.upload.onprogress = function(e) {
// change progress
// (reduce the width of overlay)
var perc = (e.loaded / e.total * 100) || 100,
width = 100 - perc;
overlay.style.width = width;
}
ajax.send(formData);
});
}
textarea
{
width: 100%;
margin: 0px;
padding: .2em;
border: none;
outline-width: 0;
text-align: start;
unicode-bidi: plaintext;
font-weight: 400;
cursor: text;
background-color: #ffffff;
overflow:hidden;
resize: none;
font-size: 18px;
}
input#submit {
width: 100%;
color: white;
background: #79d4ff;
font-size: 18px;
border: none;
border-radius: 8px;
outline-width: 0;
line-height: 2;
}
input#submit:hover
{
background: #3da0f5;
}
input#submit:focus{width: 98%;}
#drop-region {
background-color: #fff;
border-radius:20px;
box-shadow:0 0 35px rgba(0,0,0,0.05);
padding:60px 40px;
text-align: center;
cursor:pointer;
transition:.3s;
display:none;
}
#drop-region:hover {
box-shadow:0 0 45px rgba(0,0,0,0.1);
}
#image-preview {
margin-top:20px;
}
#image-preview .image-view {
display: inline-block;
position:relative;
margin-right: 13px;
margin-bottom: 13px;
}
#image-preview .image-view img {
max-width: 300px;
max-height: 300px;
transform: scale(.9);
transition: .4s;
}
#image-preview .overlay {
position: absolute;
width: 100%;
height: 100%;
top: 0;
right: 0;
z-index: 2;
background: rgba(255,255,255,0.5);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<form id="fupForm"enctype="multipart/form-data" accept-charset="utf-8">
<textarea style="direction:ltr;" name="post_content" class="file_drag_area" id="file_drag_area" maxlength="1000" placeholder="Greate Post..." ></textarea>
<div id="drop-region">
<div id="image-preview">
</div>
</div>
<button type="button" class="emoji_button" id="images_btn"><img src="../../assets/images/image.png" width="25px" height="25px" ></button>
<input type="submit" name="submit" id="submit" class="btn btn-primary" value="Send Post" />
</form>
For your case, when you drag and drop the files (file upload), you will trigger the following function:
function handleFiles(files) {
for (var i = 0, len = files.length; i < len; i++) {
if (validateImage(files[i]))
previewAnduploadImage(files[i]);
}
}
It is obvious that this "handleFiles" function will process the files one by one. Hence the php is called ONCE for every file uploaded --- and that explains why the files are saved into separate records.
The above should explain what you encounter. So if you want to save the data into a single record, you need to amend the above codes
Any best example is there for drag and upload the image in angularjs or angular any version? I didn't find anything in angular.
jsfiddle
I have this example, But my requirement is, I have one + button in a box. If I drag and drop any image on that + button it should upload and one more box should open next to that box. Please see the image.
Like this I need to upload more images. If any fiddle or examples are there, please anyone send me.
// Generated by CoffeeScript 1.6.3
// Couldn't get JSFiddle to work with CoffeeScript as advertised - Link to CoffeeScript Gist: https://gist.github.com/lsiv568/5623361
(function() {
'use strict';
angular.module('reusableThings', []).directive('fileDropzone', function() {
return {
restrict: 'A',
scope: {
file: '=',
fileName: '='
},
link: function(scope, element, attrs) {
var checkSize, isTypeValid, processDragOverOrEnter, validMimeTypes;
processDragOverOrEnter = function(event) {
if (event != null) {
event.preventDefault();
}
event.dataTransfer.effectAllowed = 'copy';
return false;
};
validMimeTypes = attrs.fileDropzone;
checkSize = function(size) {
var _ref;
if (((_ref = attrs.maxFileSize) === (void 0) || _ref === '') || (size / 1024) / 1024 < attrs.maxFileSize) {
return true;
} else {
alert("File must be smaller than " + attrs.maxFileSize + " MB");
return false;
}
};
isTypeValid = function(type) {
if ((validMimeTypes === (void 0) || validMimeTypes === '') || validMimeTypes.indexOf(type) > -1) {
return true;
} else {
alert("Invalid file type. File must be one of following types " + validMimeTypes);
return false;
}
};
element.bind('dragover', processDragOverOrEnter);
element.bind('dragenter', processDragOverOrEnter);
return element.bind('drop', function(event) {
var file, name, reader, size, type;
if (event != null) {
event.preventDefault();
}
reader = new FileReader();
reader.onload = function(evt) {
if (checkSize(size) && isTypeValid(type)) {
return scope.$apply(function() {
scope.file = evt.target.result;
if (angular.isString(scope.fileName)) {
return scope.fileName = name;
}
});
}
};
file = event.dataTransfer.files[0];
name = file.name;
type = file.type;
size = file.size;
reader.readAsDataURL(file);
return false;
});
}
};
});
}).call(this);
(function() {
'use strict';
angular.module('reusableThings').controller('TestCtrl', function($scope) {
$scope.image = null
$scope.imageFileName = ''
});
}).call(this);
.dropzone {
width: 250px;
height: 45px;
border: 1px solid #ccc;
text-align: center;
padding: 30px;
margin: 20px;
font-family: Arial;
position: absolute;
top: 0;
left: 0;
}
.image-container {
width: 312px;
height: 312px;
margin: 20px;
position: absolute;
top: 0;
left: 0;
z-index: 2;
}
.image-container img {
max-width: 100%;
}
.file-name {
font-family: Arial;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="reusableThings" ng-controller="TestCtrl">
<div class="dropzone" file-dropzone="[image/png, image/jpeg, image/gif]" file="image" file-name="imageFileName" data-max-file-size="3">
<span>Drop Image Here</span>
</div>
<div class="image-container" ng-show="image">
<img ng-src={{image}} />
<span class="file-name">{{imageFileName}}</span>
</div>
</div>
Let's agree about some steps:
To support multiple images in the scope, obviously, you should keep an array of images.
We want to re-use the dropzone so after a user will drop an image to it, the image will be next to it and the user could drop another image. So, we don't want to handle the scope, we will parse the file (src and name) and call a callback onDrop with these parameters, and the control itself will handle it.
Please, read my comment in the code
// Generated by CoffeeScript 1.6.3
// Couldn't get JSFiddle to work with CoffeeScript as advertised - Link to CoffeeScript Gist: https://gist.github.com/lsiv568/5623361
(function() {
'use strict';
angular.module('reusableThings', []).directive('fileDropzone', function() {
return {
restrict: 'A',
scope: {
// get only a drop callback which will be called with the image object
image: '='
},
link: function(scope, element, attrs) {
var checkSize, isTypeValid, processDragOverOrEnter, validMimeTypes;
processDragOverOrEnter = function(event) {
if (event != null) {
event.preventDefault();
}
event.dataTransfer.effectAllowed = 'copy';
return false;
};
validMimeTypes = attrs.fileDropzone;
checkSize = function(size) {
var _ref;
if (((_ref = attrs.maxFileSize) === (void 0) || _ref === '') || (size / 1024) / 1024 < attrs.maxFileSize) {
return true;
} else {
alert("File must be smaller than " + attrs.maxFileSize + " MB");
return false;
}
};
isTypeValid = function(type) {
if ((validMimeTypes === (void 0) || validMimeTypes === '') || validMimeTypes.indexOf(type) > -1) {
return true;
} else {
alert("Invalid file type. File must be one of following types " + validMimeTypes);
return false;
}
};
element.bind('dragover', processDragOverOrEnter);
element.bind('dragenter', processDragOverOrEnter);
return element.bind('drop', function(event) {
var file, name, reader, size, type;
if (event != null) {
event.preventDefault();
}
reader = new FileReader();
reader.onload = function(evt) {
if (checkSize(size) && isTypeValid(type)) {
return scope.$apply(function() {
// call the callback with the data
scope.image.image = evt.target.result,
scope.image.imageFileName = name;
});
}
};
file = event.dataTransfer.files[0];
name = file.name;
type = file.type;
size = file.size;
reader.readAsDataURL(file);
return false;
});
}
};
});
}).call(this);
(function() {
'use strict';
angular.module('reusableThings').controller('TestCtrl', function($scope) {
// keep in array instead of variables on the scope
$scope.images = [];
$scope.drop = (image) => {
// console.log(image);
$scope.images.unshift(image);
}
});
}).call(this);
.container {
position: relative;
width: 312px;
height: 312px;
margin: 20px;
}
.dropzone {
border: 1px solid #ccc;
text-align: center;
padding: 30px;
font-family: Arial;
position: absolute;
top: 0;
left: 0;
width: 250px;
height: 45px;
}
.image-container {
width: 100%;
height: 100%;
margin: 20px;
position: absolute;
top: 0;
left: 0;
z-index: 2;
}
.image-container img {
max-width: 100%;
}
.file-name {
font-family: Arial;
}
.button {
width: 50px;
height: 50px;
border-radius: 50%;
text-align: center;
border: 1px solid;
font-size: 25px;
color: #aaa;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="reusableThings" ng-controller="TestCtrl">
<div class="container" ng-repeat="image in images">
<div ng-if="!image.image" class="dropzone" file-dropzone="[image/png, image/jpeg, image/gif]" image="image" data-max-file-size="3">
<span>Drop Image Here</span>
</div>
<div class="image-container" ng-if="image.image">
<img ng-src={{image.image}} />
<span class="file-name">{{image.imageFileName}}</span>
</div>
</div>
<button class="button" ng-click="images.push({})">+</button>
</div>
It could be a little complex change in the line of thought. If anything is not clear, let me know.
I've got a stand-alone script deployed as a Web App. My code is working exactly as it should as a Web App. However, my goal is to use that code in a Spreadsheet Project.
I copied and pasted the code into a Spreadsheet Script and made a few alterations to make it work in a pop-up Modal dialog window, but it does not work as it does as a deployed web app. The code seems to not return any data to Code.gs. After running alerts at various points along the code path I have discovered the point of failure but am not sure how to address it.
Code from the working WebApp (2 files: Code.gs & form.html):
## Code.gs file ##
function doGet() {
return HtmlService.createHtmlOutputFromFile('form')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function uploadFileToDrive(base64Data, fileName, totalFiles, finalCount) {
try{
var splitBase = base64Data.split(','),
type = splitBase[0].split(';')[0].replace('data:','');
var byteCharacters = Utilities.base64Decode(splitBase[1]);
var ss = Utilities.newBlob(byteCharacters, type);
ss.setName(fileName);
var dropbox = "stuff"; // Folder Name
var folder, folders = DriveApp.getFoldersByName(dropbox); // Get folders by name
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = DriveApp.createFolder(dropbox);
}
var file = folder.createFile(ss);
// BEGIN LOGGING FILE NAMES AND IDs
var dropboxId = "SOME_FOLDER_ID_HERE" // Folder ID
var theFolder = DriveApp.getFolderById(dropboxId); // Get folder by ID
var list = [];
var theBlobs = [];
if (totalFiles == finalCount) {
var files = theFolder.getFiles();
while (files.hasNext()) {
var theFile = files.next();
list.push(theFile.getId());
}
for (var i = 0; i < list.length; i++) {
Logger.log(DriveApp.getFileById(list[i]).getName() + " : " + list[i]);
theBlobs.push(DriveApp.getFileById(list[i]).getBlob());
}
Logger.log(theBlobs);
// END LOGGING FILE NAMES AND IDs
// BEGIN ZIPPING UP FILES
var newZip = theFolder.createFile(Utilities.zip(theBlobs, 'zippedFiles.zip'));
var zipId = newZip.getId();
Logger.log("Zip Id: " + zipId);
// END ZIPPING UP FILES
// BEGIN TRASHING UPLOADED FILES
for (var i = 0; i < list.length; i++) {
DriveApp.getFileById(list[i]).setTrashed(true);
}
// END TRASHING UPLOADED FILES
}
return file.getName();
}catch(e){
return 'Error: ' + e.toString();
}
}
## form.html ##
<body>
<div id="formcontainer">
<form id="myForm">
<label for="myFile">Upload File(s):</label><br />
<input type="file" name="filename" id="myFile" multiple />
<input type="button" class="blue" value="Submit" onclick="iteratorFileUpload()" /><br /><br />
</form>
</div>
<div id="output"></div>
<div id="progressbar">
<div class="progress-label"></div>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
<link rel="stylesheet" href="https://googledrive.com/host/0By0COpjNTZPnZTBvVGZOSFRhREE/add-ons.css">
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script>
var numUploads = {};
numUploads.done = 0 ;
numUploads.total = 0 ;
// Upload the files into a folder in drive...set to send them all to one folder (specificed in the .gs file)
function iteratorFileUpload() {
var allFiles = document.getElementById('myFile').files;
if (allFiles.length == 0) {
alert('No file selected!');
} else { // Show Progress Bar
var myCount = 0; // Begin count to compare loops through
numUploads.total = allFiles.length;
$('#progressbar').progressbar({
value : false
});
$(".progress-label").html('Preparing files..');
// Send a file at a time
for (var i = 0; i < allFiles.length; i++) {
myCount++; // Increment count each time before sending the file to drive
sendFileToDrive(allFiles[i], allFiles.length, myCount);
}
}
}
function sendFileToDrive(file, totalFiles, newCount) {
var reader = new FileReader();
reader.onload = function (e) {
var content = reader.result;
google.script.run.withSuccessHandler(updateProgressbar).uploadFileToDrive(content, file.name, totalFiles, newCount);
}
reader.readAsDataURL(file);
}
function updateProgressbar( idUpdate ){
numUploads.done++;
var porc = Math.ceil((numUploads.done / numUploads.total)*100);
$("#progressbar").progressbar({value: porc });
$(".progress-label").text(numUploads.done +'/'+ numUploads.total);
if( numUploads.done == numUploads.total ){
numUploads.done = 0;
};
}
function fileUploaded(status) {
document.getElementById('myForm').style.display = 'none';
document.getElementById('output').innerHTML = status;
}
</script>
<style>
body {
max-width: 400px;
padding: 20px;
margin: auto;
}
input {
display: inline-block;
width: 100%;
padding: 5px 0px 5px 5px;
margin-bottom: 10px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
select {
margin: 5px 0px 15px 0px;
}
input[type="submit"] {
width: auto !important;
display: block !important;
}
input[type="file"] {
padding: 5px 0px 15px 0px !important;
}
#progressbar{
width: 100%;
text-align: center;
overflow: hidden;
position: relative;
vertical-align: middle;
}
.progress-label {
float: left;
margin-top: 5px;
font-weight: bold;
text-shadow: 1px 1px 0 #fff;
width: 100%;
height: 100%;
position: absolute;
vertical-align: middle;
}
</style>
</body>
When deploying as a Spreadsheet container bound app the code is as follows (2 files: Code.gs & form.html):
## Code.gs ##
function uploadFiles() {
function doGet() {
return SpreadsheetApp.getUi().showModalDialog(HtmlService.createHtmlOutputFromFile('form').setSandboxMode(HtmlService.SandboxMode.IFRAME), "Upload Files");
}
doGet();
function uploadFileToDrive(base64Data, fileName, totalFiles, finalCount) {
try{
var splitBase = base64Data.split(','),
type = splitBase[0].split(';')[0].replace('data:','');
var byteCharacters = Utilities.base64Decode(splitBase[1]);
var ss = Utilities.newBlob(byteCharacters, type);
ss.setName(fileName);
var dropbox = "stuff"; // Folder Name
var folder, folders = DriveApp.getFoldersByName(dropbox); // Get folders by name
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = DriveApp.createFolder(dropbox);
}
var file = folder.createFile(ss);
// BEGIN LOGGING FILE NAMES AND IDs
var dropboxId = "SOME_FOLDER_ID_HERE" // Folder ID
var theFolder = DriveApp.getFolderById(dropboxId); // Get folder by ID
var list = [];
var theBlobs = [];
if (totalFiles == finalCount) {
var files = theFolder.getFiles();
while (files.hasNext()) {
var theFile = files.next();
list.push(theFile.getId());
}
for (var i = 0; i < list.length; i++) {
Logger.log(DriveApp.getFileById(list[i]).getName() + " : " + list[i]);
theBlobs.push(DriveApp.getFileById(list[i]).getBlob());
}
Logger.log(theBlobs);
// END LOGGING FILE NAMES AND IDs
// BEGIN ZIPPING UP FILES
var newZip = theFolder.createFile(Utilities.zip(theBlobs, 'zippedFiles.zip'));
var zipId = newZip.getId();
Logger.log("Zip Id: " + zipId);
// END ZIPPING UP FILES
// BEGIN TRASHING UPLOADED FILES
for (var i = 0; i < list.length; i++) {
DriveApp.getFileById(list[i]).setTrashed(true);
}
// END TRASHING UPLOADED FILES
}
return file.getName();
}catch(e){
return 'Error: ' + e.toString();
}
}
}
## form.html ##
<body>
<div id="formcontainer">
<form id="myForm">
<label for="myFile">Upload File(s):</label><br />
<input type="file" name="filename" id="myFile" multiple />
<input type="button" class="blue" value="Submit" onclick="iteratorFileUpload()" /><br /><br />
</form>
</div>
<div id="output"></div>
<div id="progressbar">
<div class="progress-label"></div>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
<link rel="stylesheet" href="https://googledrive.com/host/0By0COpjNTZPnZTBvVGZOSFRhREE/add-ons.css">
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script>
var numUploads = {};
numUploads.done = 0 ;
numUploads.total = 0 ;
// Upload the files into a folder in drive...set to send them all to one folder (specificed in the .gs file)
function iteratorFileUpload() {
var allFiles = document.getElementById('myFile').files;
if (allFiles.length == 0) {
alert('No file selected!');
} else { // Show Progress Bar
var myCount = 0; // Begin count to compare loops through
numUploads.total = allFiles.length;
$('#progressbar').progressbar({
value : false
});
$(".progress-label").html('Preparing files..');
// Send a file at a time
for (var i = 0; i < allFiles.length; i++) {
myCount++; // Increment count each time before sending the file to drive
sendFileToDrive(allFiles[i], allFiles.length, myCount);
}
}
}
function sendFileToDrive(file, totalFiles, newCount) {
var reader = new FileReader();
reader.onload = function (e) {
var content = reader.result;
google.script.run.withSuccessHandler(updateProgressbar).uploadFileToDrive(content, file.name, totalFiles, newCount);
}
reader.readAsDataURL(file);
}
function updateProgressbar( idUpdate ){
numUploads.done++;
var porc = Math.ceil((numUploads.done / numUploads.total)*100);
$("#progressbar").progressbar({value: porc });
$(".progress-label").text(numUploads.done +'/'+ numUploads.total);
if( numUploads.done == numUploads.total ){
numUploads.done = 0;
};
}
/*
function updateProgressbar( idUpdate ){
numUploads.done++;
var porc = Math.ceil((numUploads.done / numUploads.total)*100);
$("#progressbar").progressbar({value: porc });
$(".progress-label").text(numUploads.done +'/'+ numUploads.total);
if( numUploads.done == numUploads.total ){
numUploads.done = 0;
};
}
*/
function fileUploaded(status) {
document.getElementById('myForm').style.display = 'none';
document.getElementById('output').innerHTML = status;
}
</script>
<style>
body {
max-width: 400px;
padding: 20px;
margin: auto;
}
input {
display: inline-block;
width: 100%;
padding: 5px 0px 5px 5px;
margin-bottom: 10px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
select {
margin: 5px 0px 15px 0px;
}
input[type="submit"] {
width: auto !important;
display: block !important;
}
input[type="file"] {
padding: 5px 0px 15px 0px !important;
}
#progressbar{
width: 100%;
text-align: center;
overflow: hidden;
position: relative;
vertical-align: middle;
}
.progress-label {
float: left;
margin-top: 5px;
font-weight: bold;
text-shadow: 1px 1px 0 #fff;
width: 100%;
height: 100%;
position: absolute;
vertical-align: middle;
}
</style>
</body>
The non-working code stops at this point:
google.script.run.withSuccessHandler(updateProgressbar).uploadFileToDrive(content, file.name, totalFiles, newCount);.
Up to that point everything moves along nicely and info is passed from function to function.
In the Spreadsheet script the files never get uploaded to Drive and the counter for the files that displays on the html page never increments...it just stalls.
The closest articles I've come across that may aid in resolving this are: how to use google.script.run as if it was a function that was originally proposed as a solution to this question Google Apps Script HTML Service: Passing variables and Returning a value using Date picker in HTMLService / Google Apps Script.
Thank you for your help in advance!!
The solution was rather simple since the underlying code already functioned as a stand-alone Web App.
The only changes needed made were to the Code.gs file.
Pulled out the beginning of the code and kept it in it's own top-level function:
function uploadFiles() {
function doGet() {
return SpreadsheetApp.getUi().showModalDialog(HtmlService.createHtmlOutputFromFile('form').setSandboxMode(HtmlService.SandboxMode.IFRAME), "Upload Files");
}
doGet();
}
Then put the remainder in it's own top-level function as well:
function uploadFileToDrive(base64Data, fileName, totalFiles, finalCount) {
try{
var splitBase = base64Data.split(','),
type = splitBase[0].split(';')[0].replace('data:','');
var byteCharacters = Utilities.base64Decode(splitBase[1]);
var ss = Utilities.newBlob(byteCharacters, type);
ss.setName(fileName);
var dropbox = "stuff"; // Folder Name
var folder, folders = DriveApp.getFoldersByName(dropbox); // Get folders by name
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = DriveApp.createFolder(dropbox);
}
var file = folder.createFile(ss);
// BEGIN LOGGING FILE NAMES AND IDs
var dropboxId = "SOME_FOLDER_ID_HERE" // Folder ID
var theFolder = DriveApp.getFolderById(dropboxId); // Get folder by ID
var list = [];
var theBlobs = [];
if (totalFiles == finalCount) {
var files = theFolder.getFiles();
while (files.hasNext()) {
var theFile = files.next();
list.push(theFile.getId());
}
for (var i = 0; i < list.length; i++) {
Logger.log(DriveApp.getFileById(list[i]).getName() + " : " + list[i]);
theBlobs.push(DriveApp.getFileById(list[i]).getBlob());
}
Logger.log(theBlobs);
// END LOGGING FILE NAMES AND IDs
// BEGIN ZIPPING UP FILES
var newZip = theFolder.createFile(Utilities.zip(theBlobs, 'zippedFiles.zip'));
var zipId = newZip.getId();
Logger.log("Zip Id: " + zipId);
// END ZIPPING UP FILES
// BEGIN TRASHING UPLOADED FILES
for (var i = 0; i < list.length; i++) {
DriveApp.getFileById(list[i]).setTrashed(true);
}
// END TRASHING UPLOADED FILES
}
return file.getName();
}catch(e){
return 'Error: ' + e.toString();
}
}
It now works perfectly as a script attached to a Spreadsheet!
Alright, so I have been killing myself over this for a while now. I simply want to take an XML response containing names from my arduino and then dynamically create buttons. Each button needs to say the name and have the name as its id for the GetDrink function to use to send back to the arduino. If anyone can give me some help, maybe some code to work off of it would be appreciated.
I am able to have a button call the CreateButton function to create more buttons which all work. But I need to dynamically create the buttons off of the XML response. Also, this has to be done strictly using JavaScript and HTML.
<!DOCTYPE html>
<html>
<head>
<title>The AutoBar</title>
<script>
// Drinks
strDRINK1 = "";
function GetArduinoIO()
{
nocache = "&nocache=" + Math.random() * 1000000;
var request = new XMLHttpRequest();
request.onreadystatechange = function()
{
if (this.readyState == 4) {
if (this.status == 200) {
if (this.responseXML != null) {
var count;
var num_an = this.responseXML.getElementsByTagName('alcohol').length;
for (count = 0; count < num_an; count++) {
document.getElementsByClassName("AlcStatus")[count].innerHTML =
this.responseXML.getElementsByTagName('alcohol')[count].childNodes[0].nodeValue;
}
}
}
}
}
request.open("GET", "ajax_inputs" + strDRINK1 + nocache, true);
request.send(null);
setTimeout('GetArduinoIO()', 1000);**strong text**
strDRINK1 = "";
}
function GetDrink(clicked_id)
{
strDRINK1 = "&" + clicked_id;
document.getElementById("AlcStatus").innerHTML = "Your " + clicked_id + " is being made";
}
function CreateButton(Drink_Name)
{
myButton = document.createElement("input");
myButton.type = "button";
myButton.value = Drink_Name;
placeHolder = document.getElementById("button");
placeHolder.appendChild(myButton);
myButton.id = Drink_Name;
myButton.onclick = function()
{
strDRINK1 = "&" + myButton.id;
document.getElementById("AlcStatus").innerHTML = "Your " + myButton.id + " is being made";
}
}
</script>
<style>
.IO_box {
float: left;
margin: 0 20px 20px 0;
border: 1px solid blue;
padding: 0 5px 0 5px;
width: 320px;
}
h1 {
font-size: 320%;
color: blue;
margin: 0 0 10px 0;
}
h2 {
font-size: 200%;
color: #5734E6;
margin: 5px 0 5px 0;
}
p, form, button {
font-size: 180%;
color: #252525;
}
.small_text {
font-size: 70%;
color: #737373;
}
</style>
</head>
<body onload="GetArduinoIO()" BGCOLOR="#F5F6CE">
<p> <center><img src="pic.jpg" /></center><p>
<div class="IO_box">
<div id="button"></div>
</div>
<div class="IO_box">
<h2><span class="AlcStatus">...</span></h2>
</div>
<div>
<button onclick="location.href='Edit_Bar.htm'">Edit Bar Menu</button>
<div>
</body>
</html>
Something like this?
var xml = "<items><alcohol>Bourbon</alcohol><alcohol>Gin</alcohol><alcohol>Whiskey</alcohol></items>";
var parser = new DOMParser();
var dom = parser.parseFromString(xml, "text/xml");
var alcohol = dom.querySelectorAll('alcohol');
function getDrink(event) {
alert(event.target.value);
}
function makeButton(value) {
var b = document.createElement('button');
b.innerHTML = value;
b.value = value;
b.id = value;
b.addEventListener('click', getDrink);
return b;
}
var list = document.getElementById('buttons');
for(var i = 0; i < alcohol.length; i++ ) {
var b = makeButton(alcohol[i].firstChild.nodeValue);
var li = document.createElement('li');
li.appendChild(b);
list.appendChild(li);
}
<ul id="buttons"></ul>
I hope that someone will know how to help me with this problem, I am new to javaScript and XML. Basically I have the xml file with list of products, I have managed to dynamically load the data into an ul li list in my html page, the li elements has title and image, and now I need to be able to click on this li element and load remaining data for a specific product into a new page (or div). I am getting the "Uncaught ReferenceError: i is not defined" My question is how could I load the correct remaining data after clicking on a specific product from the list of products. (I hope that my explanation is clear enough) here is my code, the first function produces the ul li list in the html page, the displayPRInfo() function should load the data into showPrInfo div for any product which was clicked.
please help me, any help appreciated , thanks for reading.
function loadProducts() {
var liOpen=("<li onclick='displayPRInfo(" + i + ")'><p>");
var divOpen=("</p><div class='prod-sq-img'>");
var closingTags=("</div></li>");
var txt;
var image;
var title;
var x=xmlDoc.getElementsByTagName("product");
for (i=0;i<x.length;i++)
{
title=(x[i].getElementsByTagName("title")[0].childNodes[0].nodeValue);
image=(x[i].getElementsByTagName("imgfile")[0].childNodes[0].nodeValue);
txt= liOpen + title + divOpen + image + closingTags ;
document.getElementById("ulList").innerHTML+=txt;
}
}
function displayPRInfo(i)
{
title=(x[i].getElementsByTagName("title")[0].childNodes[0].nodeValue);
euPriceRet=(x[i].getElementsByTagName("euror")[0].childNodes[0].nodeValue);
euPriceTrade=(x[i].getElementsByTagName("eurot")[0].childNodes[0].nodeValue);
euPriceSet=(x[i].getElementsByTagName("eset")[0].childNodes[0].nodeValue);
minimumQuantity=(x[i].getElementsByTagName("mqty")[0].childNodes[0].nodeValue);
description=(x[i].getElementsByTagName("desc")[0].childNodes[0].nodeValue);
prBigImg=(x[i].getElementsByTagName("pimgfile")[0].childNodes[0].nodeValue);
prInfo=title+"<br>"+euPriceRet+"<br>"+euPriceTrade+"<br> "+euPriceSet+"<br> "+minimumQuantity+"<br>"+description+"<br>"+ prBigImg ;
document.getElementById("showPrInfo").innerHTML=prInfo;
}
You can use jQuery to manipulate xml and set onclick events.
function loadProducts() {
var products = $(xmlDoc).find('product');
for (var i = 0; i < products.length; i++) {
$('#ulList').append('<li id="product_' + i + '"><p>' + $(products[i]).find('title').text() + '</p><div class="prod-sq-img">' + $(products[i]).find('imgfile').text() + '</div></li>');
$('#product_' + i).click(displayPRInfo.bind($('#product_' + i), products[i]));
}
}
function displayPRInfo(xmlProduct) {
var title= $(xmlProduct).find('title).text();
var euPriceRet = $(xmlProduct).find('euror').text();
var euPriceTrade = $(xmlProduct).find('eurot').text();
var euPriceSet = $(xmlProduct).find('eset').text();
var minimumQuantity = $(xmlProduct).find('mqty').text();
var description = $(xmlProduct).find('desc').text();
var prBigImg = $(xmlProduct).find('pimgfile').text();
var prInfo = title+"<br>"+euPriceRet+"<br>"+euPriceTrade+"<br> "+euPriceSet+"<br> "+minimumQuantity+"<br>"+description+"<br>"+ prBigImg ;
$('#showPrInfo').html(prInfo);
}
I haven't tried the whole script but for sure you have to move this:
liOpen=("<li onclick='displayPRInfo(" + i + ")'><p>")
into the for loop
for (i=0; i<x.length; i++) {
title=(x[i].getElementsByTagName("title")[0].childNodes[0].nodeValue);
image=(x[i].getElementsByTagName("imgfile")[0].childNodes[0].nodeValue);
liOpen=("<li onclick='displayPRInfo(" + i + ")'><p>");
txt= liOpen + title + divOpen + image + closingTags ;
document.getElementById("ulList").innerHTML+=txt;
}
where acctually i is defined
I found this and it helped me a bit, the thing is that I want to load images by request, not loading them all at once but by clicking a button and set the img src with the xml data, I have this...
<!doctype html>
<html lang="es">
<head>
<style>
#iosslider_nav {
height: 13px;
right: 10px;
/* align right side */
/*left: 10px;*/
/* align left side */
bottom: 10px;
/*position: absolute;*/
/* set if needed */
/*margin-top: 10px;*/
/* remove if position is absolute */
}
#iosslider_nav .btn {
width: 13px;
height: 13px;
background: #eaeaea;
margin: 0 5px 0 0;
-webkit-border-radius: 100%;
-moz-border-radius: 100%;
border-radius: 100%;
cursor: pointer;
float: left;
/* ie 7/8 fix */
background: url('../images/bull_off.png') no-repeat\9;
}
</style>
</head>
<body>
<div id="ninja_slider"></div>
<div id="iosslider_nav"></div>
<script type="text/javascript" src="jquery-1.9.1.min.js"></script>
<script type="text/javascript">
var xmlDoc = loadXMLDoc("xml/xml_data.xml");
// generic load xml data function
function loadXMLDoc(filename) {
if (window.XMLHttpRequest) {
xhttp = new XMLHttpRequest();
} else { // code for IE5 and IE6
xhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xhttp.open("GET", filename, false);
xhttp.send();
return xhttp.responseXML;
}
set_slider();
//set_navigation('xml/xml_data.xml', 'iosslider_nav');
function set_slider() {
var item_div = $(xmlDoc).find('desk');
var item_btn = $(xmlDoc).find('desk');
var item_img = $(xmlDoc).find('desk');
// Object.bind() handler for ie 7/8
if (!Function.prototype.bind) {
Function.prototype.bind = function (oThis) {
if (typeof this !== 'function') {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function () {},
fBound = function () {
return fToBind.apply(this instanceof fNOP && oThis ? this : oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
// create main div's
for (var i = 0; i < item_div.length; i++) {
$('#ninja_slider').append('<div id="item_div' + i + '"><img id="item_img' + i + '" src="" class="ninja_item"></div>');
$('#item_div' + i).on('click', load_current.bind($('#item_div' + i), item_div[i]));
}
// load first element
$('#ninja_slider #item_div0 .item_anchor img').attr('src', $(item_img[0]).find('image').text());
// create nav div's
for (var i = 0; i < item_btn.length; i++) {
$('#iosslider_nav').append('<div id="item_btn' + i + '" class="btn"></div>');
$('#item_btn' + i).on('click', load_current.bind($('#item_btn' + i), item_btn[i]));
}
}
function load_current(xmlData) {
var image = $(xmlData).find('image').text();
var src = image;
//console.log(image);
var item_img = $(xmlDoc).find('desk');
for (var i = 0; i < item_img.length; i++) {
$('#ninja_slider').append('<div id="item_div' + i + '"><img id="item_img' + i + '" src="' + $(item_img[i]).find('image').text() + '" class="ninja_item"></div>');
}
}
function set_navigation(url, id) {
$.ajax({
url: url,
async: false,
type: "GET",
data: "xml",
success: function (xml) {
$(xml).find("desk").each(function () {
var item_nav = document.getElementById(id),
click_item = document.createElement("div");
item_nav.appendChild(click_item);
click_item.className = click_item.className + "btn";
});
}
});
}
</script>
</body>
</html>
hope it makes sense...