programming for js arcgis map - javascript

`I'm able to create my own basemap that already build with extent map, maptoggle & basemap gallery and some other widgets(refer image 1).
However, I'm still as a problem to integrate the widget for the timeslidder with the basemap (the given source code) no matter how i tries.
i also attach the link for the source of the timeslidder widget (for your reference) that i want to intergrate with the code i paste here.
[
<html>
<meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
<title>Well completion dates for the Hugoton Gas Field Over Time</title>
<link rel="stylesheet" href="https://js.arcgis.com/3.30/dijit/themes/claro/claro.css">
<link rel="stylesheet" href="https://js.arcgis.com/3.30/esri/css/esri.css">
<style>
html, body,
#mapDiv {
padding:0;
margin:0;
height:100%;
}
#mapDiv {
position: relative;
}
#bottomPanel {
left: 50%;
margin: 0 auto;
margin-left: -500px;
position: absolute;
bottom: 2.5em;
}
#timeInfo{
border-radius: 4px;
border: solid 2px #ccc;
background-color: #fff;
display: block;
padding: 5px;
position: relative;
text-align: center;
width: 1000px;
z-index: 99;
}
#bottomPanel2 {
left: 50%;
margin: 0 auto;
margin-left: -500px;
position: absolute;
bottom: 8.5em;
}
#timeInfo2{
border-radius: 4px;
border: solid 2px #ccc;
background-color: #fff;
display: block;
padding: 5px;
position: relative;
text-align: center;
width: 1000px;
z-index: 99;
}
</style>
<script src="https://js.arcgis.com/3.30/"></script>
<script>
var map;
require([
"esri/map",
"esri/layers/ArcGISDynamicMapServiceLayer",
"esri/geometry/Extent",
"esri/SpatialReference",
"esri/TimeExtent",
"esri/dijit/TimeSlider",
"dojo/_base/array",
"dojo/dom",
"dojo/domReady!",
"dojo/on",
"esri/tasks/query", "esri/tasks/QueryTask"
], function(
Map,
ArcGISDynamicMapServiceLayer,
Extent,
SpatialReference,
TimeExtent,
TimeSlider,
arrayUtils,
dom,on, Query, QueryTask
)
{
var myextent = new Extent(92.14339937585252, -4.921857675800532, 125.89339937584356,11.56021935381215, new SpatialReference({ wkid:4326 }));
map = new Map("mapDiv",
{
basemap: "topo",
extent: myextent, // funct:variable
//center; [103.8999, 1.7381] // longitude, latitude Mas
zoom: 6
});
var opLayer = new ArcGISDynamicMapServiceLayer("http://175.136.253.77/arcgis/rest/services/CAQM/CAQM_Current_Reading/MapServer");
opLayer.setVisibleLayers([0]);
//apply a definition expression so only some features are shown
var layerDefinitions = [];
layerDefinitions[0] = "FIELD_KID=1000148164";
opLayer.setLayerDefinitions(layerDefinitions);
//add the gas fields layer to the map
map.addLayers([opLayer]);
map.on("layers-add-result", initSlider);
map.on("layers-add-result", initSlider2);
function initSlider()
{
var timeSlider = new TimeSlider({
style: "width: 100%;"
}, dom.byId("timeSliderDiv"));
map.setTimeSlider(timeSlider);
var timeExtent = new TimeExtent();
timeExtent.startTime = new Date("01/01/1927 UTC");
timeExtent.endTime = new Date("12/01/1927 UTC");
timeSlider.setThumbCount(1);// Assuming slider has only one thumb:
timeSlider.createTimeStopsByTimeInterval(timeExtent, 1, "esriTimeUnitsMonths");
timeSlider.setThumbIndexes([0,1]);
timeSlider.setThumbMovingRate(1000);//for 2 sec
timeSlider.startup();
//add labels for every other time stop
var labels = arrayUtils.map(timeSlider.timeStops, function(timeStop,i)
{
if ( i % 1 === 0 ) {
return timeStop.getUTCMonth()+1; //to get the sliding timeline bcz getUTCMonth start from zero array
} else {
return "";
}
});
timeSlider.setLabels(labels);
timeSlider.on("time-extent-change", function(evt) {
console.log(startTime.getUTCMonth());
var startValString = evt.startTime.getUTCMonth();
var endValString = evt.endTime.getUTCMonth();
dom.byId("daterange").innerHTML = "<i>" + startValString + " and " + endValString + "<\/i>";
console.log(startValString);
});
}
function initSlider2()
{ var timeSlider = new TimeSlider({
style: "width: 100%;"
}, dom.byId("timeSliderDiv2"));
map.setTimeSlider(timeSlider);
var timeExtent = new TimeExtent();
timeExtent.startTime = new Date("1/1/1927 UTC");
timeExtent.endTime = new Date("1/31/1927 UTC");
timeSlider.setThumbCount(1);// Assuming slider has only one thumb:
timeSlider.createTimeStopsByTimeInterval(timeExtent, 1, "esriTimeUnitsDays");
timeSlider.setThumbIndexes([0,1]);
timeSlider.setThumbMovingRate(2000);//for 2 sec
timeSlider.startup();
//add labels for every other time stop
var labels2 = arrayUtils.map(timeSlider.timeStops, function(timeStop, i)
{ let ii = i+1;
//console.log(timeStop);console.log(ii);
if ( i % 1 === 0 ) {
//return timeStop.getUTCDay();
return ii;
} else {
return "";
}
});
timeSlider.setLabels(labels2);
timeSlider.on("time-extent-change", function(evt) {
var startValString = evt.startTime.getUTCDay();
var endValString = evt.endTime.getUTCDay();
dom.byId("daterange2").innerHTML //= "<i>" + startValString + " and " + endValString + "<\/i>";
});
}
var queryTask = new QueryTask
("http://175.136.253.77/arcgis/rest/services/CAQM/CAQM_CO/MapServer/0");
var query = new Query();
query.where = '1=1';
query.where = dom.byId("state").value;
query.returnGeometry = false;
query.outFields = //["*"];
[ //from the choosen data
"ID", "STATION_ID", "STATION_LOCATION", "PLACE",
"LONGITUDE", "LATITUDE"
];
//on(dom.byId("execute"), "click", execute);
document.getElementById("execute_bttn").onclick = function() {execute_result()};
function execute_result ()
{
<!-- query.text = dom.byId("state").value; -->
query.text = document.getElementById("state").value;
queryTask.execute(query, showResults);
function showResults (results)
{
var resultItems = [];
var resultCount = results.features.length;
for (var i = 0; i < resultCount; i++)
{
var featureAttributes = results.features[i].attributes;
for (var attr in featureAttributes)
{
resultItems.push("<b>" + attr + ":</b> " + featureAttributes[attr] + "<br>");
}
resultItems.push("<br>");
}
//dom.byId("info").innerHTML = resultItems.join("");
document.getElementById("info").innerHTML = resultItems.join("");
}
}
});
</script>
<!-- <div> <input type = "button" id = "MonthButton" value= "MONTH"></div> -->
<div id="mapDiv">
<div id = "slist">STATION LIST :
<input type="text" id="state" placeholder="State">
<input id="execute_bttn" type="button" value="FIND">
<br />
<br />
<div id="info" style="padding:5px; margin:5px; background-color:#eee;">
<br />
<br /></div>
</div>
<div id="bottomPanel">
<div id="timeInfo">
<div>Month in 1927 <span id="daterange">From Jan - Dec</span> (Completion date)</div>
<div id="timeSliderDiv"></div>
</div>
</div>
<div id="bottomPanel2">
<div id="timeInfo2">
<div>Dates For <span id="daterange2">January 1927</span> (Completion date)</div>
<div id="timeSliderDiv2"></div>
</div>
</div>
</div>

I got it already.
Here is the code when I integrate the gis js timeslidder with my api data.
Hopefully this would help other fresh grads like me, who work as gis programmer.
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
<title>Well completion dates for the Hugoton Gas Field Over Time</title>
<link rel="stylesheet" href="https://js.arcgis.com/3.30/dijit/themes/claro/claro.css">
<link rel="stylesheet" href="https://js.arcgis.com/3.30/esri/css/esri.css">
<style>
html, body,
#mapDiv {
padding:0;
margin:0;
height:100%;
}
#mapDiv {
position: relative;
}
#bottomPanel {
left: 50%;
margin: 0 auto;
margin-left: -500px;
position: absolute;
bottom: 2.5em;
}
#timeInfo{
border-radius: 4px;
border: solid 2px #ccc;
background-color: #fff;
display: block;
padding: 5px;
position: relative;
text-align: center;
width: 1000px;
z-index: 99;
}
#bottomPanel2 {
left: 50%;
margin: 0 auto;
margin-left: -500px;
position: absolute;
bottom: 8.5em;
}
#timeInfo2{
border-radius: 4px;
border: solid 2px #ccc;
background-color: #fff;
display: block;
padding: 5px;
position: relative;
text-align: center;
width: 1000px;
z-index: 99;
}
</style>
<script src="https://js.arcgis.com/3.30/"></script>
<script>
var map;
require([
"esri/map",
"esri/layers/ArcGISDynamicMapServiceLayer",
"esri/geometry/Extent",
"esri/SpatialReference",
"esri/TimeExtent",
"esri/dijit/TimeSlider",
"dojo/_base/array",
"esri/tasks/query", "esri/tasks/QueryTask"
], function(
Map,
ArcGISDynamicMapServiceLayer,
Extent,
SpatialReference,
TimeExtent,
TimeSlider,
arrayUtils, Query, QueryTask
)
{
var myextent = new Extent(92.14339937585252, -4.921857675800532, 125.89339937584356,11.56021935381215, new SpatialReference({ wkid:4326 }));
map = new Map("mapDiv",
{
basemap: "topo",
extent: myextent, // funct:variable
//center; [103.8999, 1.7381] // longitude, latitude Mas
zoom: 6
});
var opLayer = new ArcGISDynamicMapServiceLayer("http://175.136.253.77/arcgis/rest/services/CAQM/CAQM_Current_Reading/MapServer");
opLayer.setVisibleLayers([0]);
//apply a definition expression so only some features are shown
var layerDefinitions = [];
layerDefinitions[0] = "FIELD_KID=1000148164";
opLayer.setLayerDefinitions(layerDefinitions);
//add the gas fields layer to the map
map.addLayers([opLayer]);
map.on("layers-add-result", initSlider);
map.on("layers-add-result", initSlider2);
function initSlider()
{
var timeSlider = new TimeSlider({
style: "width: 100%;"
}, document.getElementById("timeSliderDiv"));
map.setTimeSlider(timeSlider);
var timeExtent = new TimeExtent();
timeExtent.startTime = new Date("01/01/1927 UTC");
timeExtent.endTime = new Date("12/01/1927 UTC");
timeSlider.setThumbCount(1);// Assuming slider has only one thumb:
timeSlider.createTimeStopsByTimeInterval(timeExtent, 1, "esriTimeUnitsMonths");
timeSlider.setThumbIndexes([0,1]);
timeSlider.setThumbMovingRate(1000);//for 2 sec
timeSlider.startup();
//add labels for every other time stop
var labels = arrayUtils.map(timeSlider.timeStops, function(timeStop,i)
{
if ( i % 1 === 0 ) {
return timeStop.getUTCMonth()+1; //to get the sliding timeline bcz getUTCMonth start from zero array
} else {
return "";
}
});
timeSlider.setLabels(labels);
timeSlider.on("time-extent-change", function(evt) {
console.log(startTime.getUTCMonth());
var startValString = evt.startTime.getUTCMonth();
var endValString = evt.endTime.getUTCMonth();
dom.byId("daterange").innerHTML = "<i>" + startValString + " and " + endValString + "<\/i>";
console.log(startValString);
});
}
function initSlider2()
{ var timeSlider = new TimeSlider({
style: "width: 100%;"
}, document.getElementById("timeSliderDiv2"));
map.setTimeSlider(timeSlider);
var timeExtent = new TimeExtent();
timeExtent.startTime = new Date("1/1/1927 UTC");
timeExtent.endTime = new Date("1/31/1927 UTC");
timeSlider.setThumbCount(1);// Assuming slider has only one thumb:
timeSlider.createTimeStopsByTimeInterval(timeExtent, 1, "esriTimeUnitsDays");
timeSlider.setThumbIndexes([0,1]);
timeSlider.setThumbMovingRate(2000);//for 2 sec
timeSlider.startup();
//add labels for every other time stop
var labels2 = arrayUtils.map(timeSlider.timeStops, function(timeStop, i)
{ let ii = i+1;
//console.log(timeStop);console.log(ii);
if ( i % 1 === 0 ) {
//return timeStop.getUTCDay();
return ii;
} else {
return "";
}
});
timeSlider.setLabels(labels2);
timeSlider.on("time-extent-change", function(evt) {
var startValString = evt.startTime.getUTCDay();
var endValString = evt.endTime.getUTCDay();
dom.byId("daterange2").innerHTML //= "<i>" + startValString + " and " + endValString + "<\/i>";
});
}
var queryTask = new QueryTask
("http://175.136.253.77/arcgis/rest/services/CAQM/CAQM_CO/MapServer/0");
var query = new Query();
//query.where = '1=1'; //get all data
query.where = document.getElementById("STATE_NAME")//get from the api data
query.returnGeometry = false;
query.outFields = //["*"]; //to get all data column
[ //choosen the data itself tht want to be display
"ID", "STATION_ID", "STATION_LOCATION", "PLACE",
"LONGITUDE", "LATITUDE"
];
//conflict during implementation so need to change n dont used dojo on
//on(dom.byId("execute"), "click", execute);
document.getElementById("execute_bttn").onclick = function() {execute_result()};
function execute_result ()
{
<!-- query.text = dom.byId("state").value; -->
query.text = document.getElementById("state").value; //get value
queryTask.execute(query, showResults);
function showResults (results)
{
var resultItems = [];
var resultCount = results.features.length;
for (var i = 0; i < resultCount; i++)
{
var featureAttributes = results.features[i].attributes;
for (var attr in featureAttributes)
{
resultItems.push("<b>" + attr + ":</b> " + featureAttributes[attr] + "<br>");
}
resultItems.push("<br>");
}
//dom.byId("info").innerHTML = resultItems.join("");
document.getElementById("info").innerHTML = resultItems.join("");
}
}
});
</script>
</head>
<body class="claro">
<div id="mapDiv">
<div id = "slist"><br />STATION LIST :
<input type="text" id="state" placeholder="State">
<input id="execute_bttn" type="button" value="FIND">
<br />
<br />
<div id="info" style="padding:5px; margin:5px; background-color:#eee;">
<br />
<br /></div>
</div>
<div id="bottomPanel">
<div id="timeInfo">
<div>Month in 1927 <span id="daterange">From Jan - Dec</span> (Completion date)</div>
<div id="timeSliderDiv"></div>
</div>
</div>
<div id="bottomPanel2">
<div id="timeInfo2">
<div>Dates For <span id="daterange2">January 1927</span> (Completion date)</div>
<div id="timeSliderDiv2"></div>
</div>
</div>
</div>
</body>
</html>
`

Related

How To Upload Multiple Files To Google Drive With Apps Script [duplicate]

I'm trying to upload multiple files at once with my app. It recognizes when there are 2 or more files being selected. However, it will only upload the 1st file that is selected to my drive. Also (although quite minor), I was wondering how I can change my textarea font to be Times New Roman to stay consistent with the rest of the font.
Code.gs
function doGet() {
return HtmlService.createHtmlOutputFromFile('form')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function uploadFiles(form) {
try {
var foldertitle = form.zone + ' | Building: ' + form.building + ' | ' + form.propertyAddress + ' | ' + form.attachType;
var folder, folders = DriveApp.getFolderById("0B7UEz7SKB72HfmNmNnlSM2NDTVVUSlloa1hZeVI0VEJuZUhSTmc4UXYwZjV1eWM5YXJPaGs");
var createfolder = folders.createFolder(foldertitle);
folder = createfolder;
var blob = form.filename;
var file = folder.createFile(blob);
file.setDescription(" " + form.fileText);
return "File(s) uploaded successfully! Here is the link to your file(s): " + folder.getUrl();
} catch (error) {
Logger.log('err: ' + error.toString());
return error.toString();
}
}
function uploadArquivoParaDrive(base64Data, nomeArq, idPasta) {
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(nomeArq);
var file = DriveApp.getFolderById("0B7UEz7SKB72HfmNmNnlSM2NDTVVUSlloa1hZeVI0VEJuZUhSTmc4UXYwZjV1eWM5YXJPaGs").createFile(ss);
return file.getName();
}catch(e){
return 'Erro: ' + e.toString();
}
}
form.html
<body>
<div id="formcontainer">
<label for="myForm">Facilities Project Database Attachment Uploader:</label>
<br><br>
<form id="myForm">
<label for="myForm">Project Details:</label>
<div>
<input type="text" name="zone" placeholder="Zone:">
</div>
<div>
<input type="text" name="building" placeholder="Building(s):">
</div>
<div>
<input type="text" name="propertyAddress" placeholder="Property Address:">
</div>
<div>
<label for="fileText">Project Description:</label>
<TEXTAREA name="projectDescription"
placeholder="Describe your attachment(s) here:"
style ="width:400px; height:200px;"
></TEXTAREA>
</div>
<br>
<label for="attachType">Choose Attachment Type:</label>
<br>
<select name="attachType">
<option value="Pictures Only">Picture(s)</option>
<option value="Proposals Only">Proposal(s)</option>
<option value="Pictures & Proposals">All</option>
</select>
<br>
<label for="myFile">Upload Attachment(s):</label>
<br>
<input type="file" name="filename" id="myFile" multiple>
<input type="submit" value="Submit" onclick="iteratorFileUpload()">
</form>
</div>
<div id="output"></div>
<script>
function iteratorFileUpload() {
var allFiles = document.getElementById('myFile').files;
if (allFiles.length == 0) {
alert('No file selected!');
} else {
// Send each file one at a time
var i=0;
for (i=0; i < allFiles.total; i+=1) {
console.log('This iteration: ' + i);
sendFileToDrive(allFiles[i]);
};
};
};
function sendFileToDrive(file) {
var reader = new FileReader();
reader.onload = function (e) {
var content = reader.result;
console.log('Sending ' + file.name);
google.script.run
.withSuccessHandler(fileUploaded)
.uploadArquivoParaDrive(content, file.name, currFolder);
}
reader.readAsDataURL(file);
};
</script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script>
// Upload de arquivo dentro das pastas Arquivos Auxiliares
function iterarArquivosUpload() {
var arquivos = document.getElementById('inputUpload').files;
if (arquivos.length == 0) {
alert('No file selected!');
} else {
//Show Progress Bar
numUploads.total = arquivos.length;
$('.progressUpload').progressbar({
value : false
});
$('.labelProgressUpload').html('Preparando arquivos para upload');
// Send each file at a time
for (var arqs = 0; arqs < numUploads.total; arqs++) {
console.log(arqs);
enviarArquivoParaDrive(arquivos[arqs]);
}
}
}
function enviarArquivoParaDrive(arquivo) {
var reader = new FileReader();
reader.onload = function (e) {
var content = reader.result;
console.log('Sending ' + arquivo.name);
google.script.run.withSuccessHandler(updateProgressbar).uploadArquivoParaDrive(content, arquivo.name, currFolder);
}
reader.readAsDataURL(arquivo);
}
function updateProgressbar( idUpdate ){
console.log('Received: ' + idUpdate);
numUploads.done++;
var porc = Math.ceil((numUploads.done / numUploads.total)*100);
$('.progressUpload').progressbar({value: porc });
$('.labelProgressUpload').html(numUploads.done +'/'+ numUploads.total);
if( numUploads.done == numUploads.total ){
uploadsFinished();
numUploads.done = 0;
};
}
</script>
<script>
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;
}
</style>
</body>
I know this question is old, but after finding it and related ones, I was never able to get the multiple file upload working. So after a lot of banging my head against walls, I wanted to post a full example (.html and .gs) in case anyone in the future is looking for one to get started. This is working when I deploy it right now and will hopefully work for other people out there. Note that I just hardcoded the folder in the drive to use in the code.gs file, but that can be easily changed.
form.html:
<body>
<div id="formcontainer">
<label for="myForm">Facilities Project Database Attachment Uploader:</label>
<br><br>
<form id="myForm">
<label for="myForm">Project Details:</label>
<div>
<input type="text" name="zone" placeholder="Zone:">
</div>
<div>
<input type="text" name="building" placeholder="Building(s):">
</div>
<div>
<input type="text" name="propertyAddress" placeholder="Property Address:">
</div>
<div>
<label for="fileText">Project Description:</label>
<TEXTAREA name="projectDescription"
placeholder="Describe your attachment(s) here:"
style ="width:400px; height:200px;"
></TEXTAREA>
</div>
<br>
<label for="attachType">Choose Attachment Type:</label>
<br>
<select name="attachType">
<option value="Pictures Only">Picture(s)</option>
<option value="Proposals Only">Proposal(s)</option>
<option value="Pictures & Proposals">All</option>
</select>
<br>
<label for="myFile">Upload Attachment(s):</label>
<br>
<input type="file" name="filename" id="myFile" multiple>
<input type="button" value="Submit" onclick="iteratorFileUpload()">
</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">
<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
// This is 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
numUploads.total = allFiles.length;
$('#progressbar').progressbar({
value : false
});//.append("<div class='caption'>37%</div>");
$(".progress-label").html('Preparing files for upload');
// Send each file at a time
for (var i = 0; i < allFiles.length; i++) {
console.log(i);
sendFileToDrive(allFiles[i]);
}
}
}
function sendFileToDrive(file) {
var reader = new FileReader();
reader.onload = function (e) {
var content = reader.result;
console.log('Sending ' + file.name);
var currFolder = 'Something';
google.script.run.withSuccessHandler(updateProgressbar).uploadFileToDrive(content, file.name, currFolder);
}
reader.readAsDataURL(file);
}
function updateProgressbar( idUpdate ){
console.log('Received: ' + 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 ){
//uploadsFinished();
numUploads.done = 0;
};
}
</script>
<script>
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>
code.gs:
function doGet() {
return HtmlService.createHtmlOutputFromFile('form')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function uploadFileToDrive(base64Data, fileName) {
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 = "Something"; // Folder Name
var folder, folders = DriveApp.getFoldersByName(dropbox);
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = DriveApp.createFolder(dropbox);
}
var file = folder.createFile(ss);
return file.getName();
}catch(e){
return 'Error: ' + e.toString();
}
}
Updated For May 2017
I updated and improved barragan's answer.
Advantages:
Allows users to create a subfolder name to contain all the files uploaded during this session
Ensures that these subfolders all exist within one specified folder within your Google Drive
The page/form is mobile-responsive
You can start with this example just to create the script and get to know the basics.
Then you can completely replace form.html with this:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>
Send Files
</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script>
$(document).ready(function () {
function afterSubfolderCreated(subfolderId) {
console.log(subfolderId);
console.log(allFiles);
numUploads.total = allFiles.length;
$('#progressbar').progressbar({
value: false
});
$(".progress-label").html('Preparing files for upload');
for (var i = 0; i < allFiles.length; i++) {
console.log(i);
sendFileToDrive(allFiles[i], subfolderId);
}
}
function sendFileToDrive(file, subfolderId) {
var reader = new FileReader();
reader.onload = function (e) {
var content = reader.result;
console.log('Sending ' + file.name);
google.script.run.withSuccessHandler(updateProgressbar).uploadFileToDrive(content, file.name, subfolderId);
}
reader.readAsDataURL(file);
}
function updateProgressbar(idUpdate) {
console.log('Received: ' + 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;
$(".progress-label").text($(".progress-label").text() + ': FINISHED!');
$("#progressbar").after('(Optional) Refresh this page if you remembered other screenshots you want to add.');//<a href="javascript:window.top.location.href=window.top.location.href"> does not work
}
}
function fileUploaded(status) {
document.getElementById('myForm').style.display = 'none';
document.getElementById('output').innerHTML = status;
}
var numUploads = {};
numUploads.done = 0;
numUploads.total = 0;
var allFiles;
var frm = $('#myForm');
frm.submit(function () {
allFiles = document.getElementById('myFile').files;
if (!frm.checkValidity || frm.checkValidity()) {
if (allFiles.length == 0) {
alert('Error: Please choose at least 1 file to upload.');
return false;
} else {
frm.hide();
var subfolderName = document.getElementById('myName').value;
$.ajax({
url: '',//URL of webhook endpoint for sending a Slack notification
data: {
title: subfolderName + ' is uploading screenshots',
message: ''
}
});
google.script.run.withSuccessHandler(afterSubfolderCreated).createSubfolder(subfolderName);
return false;
}
} else {
alert('Invalid form');
return false;
}
});
});//end docReady
</script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
<style>
body {
padding: 20px;
margin: auto;
font-size: 20px;
}
label{
font-weight: bold;
}
input{
font-size: 20px;
padding: 5px;
display: inline-block;
margin-bottom: 10px;
-webkit-box-sizing: border-box;
‌-moz-box-sizing: border-box;
box-sizing: border-box;
}
.hint{
font-size: 90%;
color: #666;
}
select {
margin: 5px 0px 15px 0px;
}
input[type="file"] {
padding: 5px 0px 15px 0px;
}
#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;
}
li{
padding: 10px;
}
#media only screen and (max-width : 520px) {
#logo {
max-width: 100%;
}
}
</style>
</head>
<body>
<p>
<img src="" id="logo">
</p>
<p>This webpage allows you to send me screenshots of your dating profiles.</p>
<ol>
<li>
In each of your dating apps, take a screenshot (how?) of every part of every page of your profile.
</li>
<li>
Do the same for each of your photos (at full resolution).
</li>
<li>
In the form below, type your first name and last initial (without any spaces or special characters), such as SallyT.
</li>
<li>
Then click the first button and select all of your screenshot images (all at once).
</li>
<li>
Finally, press the last button to send them all to me!
</li>
</ol>
<form id="myForm">
<div>
<label for="myName">Your first name and last initial:</label>
</div>
<div>
<input type="text" name="myName" id="myName" placeholder="SallyT" required pattern="[a-zA-Z]+" value="">
</div>
<div>
<span class="hint">(No spaces or special characters allowed because this will determine your folder name)</span>
</div>
<div style="margin-top: 20px;">
<label for="myFile">Screenshot image files:</label>
<input type="file" name="filename" id="myFile" multiple>
</div>
<div style="margin-top: 20px;">
<input type="submit" value="Send File(s) ➔" >
</div>
</form>
<div id="output"></div>
<div id="progressbar">
<div class="progress-label"></div>
</div>
</body>
</html>
And completely replace server.gs with this:
function doGet() {
var output = HtmlService.createHtmlOutputFromFile('form');
output.addMetaTag('viewport', 'width=device-width, initial-scale=1');// See http://stackoverflow.com/a/42681526/470749
return output.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function uploadFileToDrive(base64Data, fileName, subfolderId) {
Logger.log(subfolderId);
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 subfolder = DriveApp.getFolderById(subfolderId);
var file = subfolder.createFile(ss);
Logger.log(file);
return file.getName() + ' at ' + file.getUrl();
} catch(e){
return 'createFile Error: ' + e.toString();
}
}
function createSubfolder(subfolderName){
var dropbox = subfolderName + Utilities.formatDate(new Date(), "US/Eastern", "_yyyy-MM-dd");
Logger.log(dropbox);
var parentFolderId = "{ID such as 0B9iQ20nrMNYAaHZxRjd}";
var parentFolder = DriveApp.getFolderById(parentFolderId);
var folder;
try {
folder = parentFolder.getFoldersByName(dropbox).next();
}
catch(e) {
folder = parentFolder.createFolder(dropbox);
}
Logger.log(folder);
return folder.getId();
}
Joining the pile of older answers, but this really helped me when I implemented my own file multi upload for getting files into Google Drive using the DriveApp V3 api.
I wrote and posted my own solution here: https://github.com/CharlesPlucker/drive-multi-upload/
Improvements:
- Handles multiple files sequentially
- Handles large > 50MB files
- Validation
I wrapped my google api calls into promises since I was running into timing issues when creating a folder and immediately trying to fetch it by name reference. Each one of my promises will only resolve when its file is fully uploaded. To get that working I had to use a Promise Factory. I'll be glad to explain this code if the need arises!
You have to send a file at a time trough the script.run, here's my implementation with FileReaders/ReadAsURL, which makes the file a Base64 string, which can be easily passed around:
Notes:
Dunno if it's necessary but I'm using IFRAME sandbox
I left the progressBar in the code, you can remove it
Everything must be OUTSIDE a form
It accepts any file type
HTML:
// Upload de arquivo dentro das pastas Arquivos Auxiliares
function iterarArquivosUpload() {
var arquivos = document.getElementById('inputUpload').files;
if (arquivos.length == 0) {
alert('No file selected!');
} else {
//Show Progress Bar
numUploads.total = arquivos.length;
$('.progressUpload').progressbar({
value : false
});
$('.labelProgressUpload').html('Preparando arquivos para upload');
// Send each file at a time
for (var arqs = 0; arqs < numUploads.total; arqs++) {
console.log(arqs);
enviarArquivoParaDrive(arquivos[arqs]);
}
}
}
function enviarArquivoParaDrive(arquivo) {
var reader = new FileReader();
reader.onload = function (e) {
var content = reader.result;
console.log('Sending ' + arquivo.name);
google.script.run.withSuccessHandler(updateProgressbar).uploadArquivoParaDrive(content, arquivo.name, currFolder);
}
reader.readAsDataURL(arquivo);
}
function updateProgressbar( idUpdate ){
console.log('Received: ' + idUpdate);
numUploads.done++;
var porc = Math.ceil((numUploads.done / numUploads.total)*100);
$('.progressUpload').progressbar({value: porc });
$('.labelProgressUpload').html(numUploads.done +'/'+ numUploads.total);
if( numUploads.done == numUploads.total ){
uploadsFinished();
numUploads.done = 0;
};
}
Code.GS
function uploadArquivoParaDrive(base64Data, nomeArq, idPasta) {
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(nomeArq);
var file = DriveApp.getFolderById(idPasta).createFile(ss);
return file.getName();
}catch(e){
return 'Erro: ' + e.toString();
}
}
as #barragan's answer here is the best answer i found after hours and hours of searching for a question many people were asking, i've done a bit of development to improve the design a bit for others as a thanks. still a few bugs and chrome seems to run out of memory and give up with any file over 100MB
here's a live version
server.gs
'function doGet() {
return HtmlService.createHtmlOutputFromFile('form')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function uploadFileToDrive(base64Data, fileName) {
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 = "Something"; // Folder Name
var folder, folders = DriveApp.getFoldersByName(dropbox);
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = DriveApp.createFolder(dropbox);
}
var file = folder.createFile(ss);
return file.getName();
}catch(e){
return 'Error: ' + e.toString();
}
}
'
form.html
<head>
<base target="_blank">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Focallocal Uploader</title>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.5/css/materialize.min.css">
<div align="center">
<p><img src="http://news.focallocal.org/wp-content/uploads/2015/03/FOCALLOCAL-Website-Text-Header.png" width="80%"></p>
</div>
</head>
<body>
<div id="formcontainer" width="50%">
<label for="myForm">Focallocal Community G.Drive Uploader</label>
<br>
<br>
<form id="myForm" width="50%">
<label for="myForm">Details</label>
<div>
<input type="text" name="Name" placeholder="your name">
</div>
<div>
<input type="text" name="gathering" placeholder="which fabulous Positive Action you're sending us">
</div>
<div>
<input type="text" name="location" placeholder="the town/village/city and country month brightend by positivity">
</div>
<div>
<input type="text" name="date" placeholder="date of the beautiful action">
</div>
<div width="100%" height="200px">
<label for="fileText">would you like to leave a short quote?</label>
<TEXTAREA name="Quote"
placeholder="many people would love to share in your experience. if you have more than a sentence or two to write, why not writing an article the Community News section of our website?"
></TEXTAREA>
</div>
<br>
<br>
<label for="myFile">Upload Your Files:</label>
<br>
<input type="file" name="filename" id="myFile" multiple>
<input type="button" value="Submit" onclick="iteratorFileUpload();">
</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">
<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
// This is 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
numUploads.total = allFiles.length;
$('#progressbar').progressbar({
value : false
});//.append("<div class='caption'>37%</div>");
$(".progress-label").html('Preparing files for upload');
// Send each file at a time
for (var i = 0; i < allFiles.length; i++) {
console.log(i);
sendFileToDrive(allFiles[i]);
}
}
}
function sendFileToDrive(file) {
var reader = new FileReader();
reader.onload = function (e) {
var content = reader.result;
console.log('Sending ' + file.name);
var currFolder = 'Something';
google.script.run.withSuccessHandler(updateProgressbar).uploadFileToDrive(content, file.name, currFolder);
}
reader.readAsDataURL(file);
}
function updateProgressbar( idUpdate ){
console.log('Received: ' + 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 ){
//uploadsFinished();
numUploads.done = 0;
};
}
</script>
<script>
function fileUploaded(status) {
document.getElementById('myForm').style.display = 'none';
document.getElementById('output').innerHTML = status;
}
</script>
<style>
body {
max-width: 60%;
padding: 20px;
margin: auto;
}
input {
display: inline-block;
width: 50%;
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: 40%;
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>
i wasn't able to get the text fields to send an email with the details out, and ran out of time before working out how to hook them up to a Google Spreadsheet, so for the moment they don't record the information added
as an added bonus, it looked fabulous with is in the form.html
<div class="fixed-action-btn horizontal" style="bottom: 45px; right: 24px;">
<a class="btn-floating btn-large red">
<i class="large material-icons">menu</i>
</a>
<ul>
<li><a class="btn-floating red" href="https://focallocal-a-positive-action-movement.myshopify.com/" target="_blank" title="Pimp your Cool at the Positive Action Shop"><i class="material-icons">monetization_on</i></a></li>
<li><a class="btn-floating blue" href="https://www.youtube.com/user/Focallocal" target="_blank" title="Follow the Positive Action Youtube Channel"><i class="material-icons">video_library</i></a></li>
<li><a class="btn-floating green" href="http://focallocal.org/" target="_blank" title="Read our About Us Page"><i class="material-icons">help</i></a></li>
</ul>
</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">
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.5/js/materialize.min.js"></script>
<script src="https://gumroad.com/js/gumroad.js"></script>
i took it out again as some of the scripts being called in were causing issues. if anyone can fix them it they add a lot to the appearance and functionality of the form
*edit: i've been playing around with it and only around half of the files sent seem to arrive, so there are still some issues with both of the codes here atm

not able to see the map in a div without min-height and min-width attributes

I am new to JavaScript and CSS.
I want to show the map in one of my div. And i was not seeing any map in the div until and unless i am using min-height and min-width (map is coming in full screen) or height and width(map is in half screen) to 500px.
Below are my code snippets.
HTML Code:
<head>
<title>My Location</title>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="/HtmlApp/css/myStyle.css">
<script type="text/javascript" src="/HtmlApp/js/myLoc.js"></script>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?key=AIzaSyBaPDmn6Z_TdZDjhgbcBQ3ksLG7zw0sGaE"></script>
</head>
<body>
<div>
<div class="col-lg-6 col-md-6 col-sm-12 col-xs-12">
<div id="location" class="div1">
Your Location will go here.
</div>
</div>
<div class="col-lg-6 col-md-6 col-sm-12 col-xs-12">
<div id="distance" class="div2">
Distance from WickedlySmart HQ will go here.
</div>
</div>
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<div id="map" class="div3">
Your map will go here.
</div>
</div>
</div>
</body>
JavaScript :
window.onload = getMyLocation;
function getMyLocation() {
if(navigator.geolocation) {
navigator.geolocation.getCurrentPosition(displayLocation, displayError);
} else {
alert("Oops! no geo location supports..");
}
}
function displayLocation(position) {
var latitude = position.coords.latitude;
var longitude = position.coords.longitude;
var location = document.getElementById("location");
location.innerHTML = "You are at Latitude : " + latitude + " , Longitude : " + longitude;
var km = computeDistance(position.coords, ourCoords);
var distance = document.getElementById("distance");
distance.innerHTML = "You are " + km + " km's from your home town";
showMap(position.coords);
}
function displayError(error) {
var errorTypes = {
0: "Unknown Error",
1: "Permission Denied by User",
2: "position is not available",
3: "Request Timed out"
};
var errorMessage = errorTypes[error.code];
if(error.code == 0 || error.code ==2) {
errorMessage = errorMessage + " " + error.message;
}
var location = document.getElementById("location");
location.innerHTML = errorMessage;
}
//Ready bake code
function computeDistance(startCoords, destCoords) {
var startLatRads = degreesToRadians(startCoords.latitude);
var startLongRads = degreesToRadians(startCoords.longitude);
var destLatRads = degreesToRadians(destCoords.latitude);
var destLongRads = degreesToRadians(destCoords.longitude);
var Radius = 6371; // radius of the Earth in km
var distance = Math.acos(Math.sin(startLatRads) * Math.sin(destLatRads) + Math.cos(startLatRads) * Math.cos(destLatRads) * Math.cos(startLongRads - destLongRads)) * Radius;
return distance;
}
function degreesToRadians(degrees) {
var radians = (degrees * Math.PI)/180;
return radians;
}
//end of ready bake code
var ourCoords = {
latitude: 47.624851,
longitude: -122.52099
};
var map;
function showMap(coords) {
var googleLatAndLong = new google.maps.LatLng(coords.latitude, coords.longitude);
var mapOptions = {
zoom: 10,
center: googleLatAndLong,
mapTypeId: google.maps.MapTypeId.ROADMAP //we can also try SATELITE and HYBRID-->SATELITE Is the default view for HYBRID.
};
var mapDiv = document.getElementById("map");
map = new google.maps.Map(mapDiv, mapOptions);
}
CSS:
.div1, .div2{
border: 1px solid;
border-color: red;
background-color: #d4d4f5;
font-weight: : bold;
margin: 1px;
}
.div3 {
position: relative;
float: center;
border: 1px solid black;
border-color: red;
min-height: 500px;
min-width: 500px;
}
.container {
position: relative;
height: 100%;
width: 100%;
}
jsfiddle link:
https://jsfiddle.net/narasimha1805/2w3mrmrd/

Complete function not forcing jquery to wait for end of animation

I am trying to use a counter in my complete function to make sure the animation of margin-top is completed before moving on. Right now, I have the counter in my MakeList(), and in my Spin() function, I console.log the counter and it doesn't recognize the counter++ because it fires before the animation finishes. Nobody I ask can figure out why.
** Note: I can't use timeOut's because the time is set to random (supposed to look like a slot machine ** Also, I can't find what this test platform is saying is an error, but the code runs on my machine. really the script-2.js is all i need to show to get point across though :)
// ********************************************************
// SLOT MACHINE ICONS. Each array has 3 icons for each slot
// ********************************************************
var array1 = [
'<div data-id="0" style="width:100%; background:#fff; height:150px;"></div>',
'<div data-id="1" style="width:100%; background:#ccc; height:150px;"></div>',
'<div data-id="0" style="width:100%; background:#666; height:150px;"></div>'
]
var array2 = [
'<div data-id="0" style="width:100%; background:#fff; height:150px;"></div>',
'<div data-id="1" style="width:100%; background:#ccc; height:150px;"></div>',
'<div data-id="0" style="width:100%; background:#666; height:150px;"></div>'
]
var array3 = [
'<div data-id="0" style="width:100%; background:#fff; height:150px;"></div>',
'<div data-id="1" style="width:100%; background:#ccc; height:150px;"></div>',
'<div data-id="0" style="width:100%; background:#666; height:150px;"></div>'
]
// Generates random # between 0 and 2. Used for choosing winner and creating random slots
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// Generates winning array item between coffee, tea and espresso
function win(whatArray){
var arrayItem = getRandomInt(0,2);
var winItem = whatArray[arrayItem];
return winItem;
}
// Populates each slot with random icons to spin through
var makeList = function(whatArray, whatSlot){
var slotArray = [];
for(i=0; i < 100; i++){
var randNum = getRandomInt(0,2); // Generate random number
var findItem = whatArray[randNum]; // Use random number to find associated array item
var slot = whatSlot; // Set which slot to append array item to (first, second or third)
$('#' + slot).append('<div>'+findItem+'</div>'); // Append icon to HTML
}
var winItem = win(whatArray); // Generate winning icon for slot
console.log("winner " + winItem);
$('#' + slot).append('<div>'+winItem+'</div>'); // Append winning icon to end of list
}
// Spin the slot and win some caffeine!
function Spin(){
window.counter = 0;
// Generate lists for each slot
makeList(array1, 'slot-1');
makeList(array2, 'slot-2');
makeList(array3, 'slot-3');
MoveSlots($('#slot1-wrapper'), 2500);
MoveSlots($('#slot2-wrapper'), 5200);
MoveSlots($('#slot3-wrapper'), 500);
//var running = true;
// console.log(running);
var slot1attr = $('#slot1-wrapper div').children().last().attr('data-id');
var slot2attr = $('#slot2-wrapper div').children().last().attr('data-id');
var slot3attr = $('#slot3-wrapper div').children().last().attr('data-id');
console.log('counter = ' + counter);
if(counter > 0){
if(slot1attr == slot2attr && slot1attr == slot3attr ){
console.log("WIN");
} else {
console.log("LOSE");
}
}
function MoveSlots(el, speed){
var time = speed;
time += Math.round(Math.random()*10000);
el.stop(true,true);
var marginTop = -(100 * 150 ); //change 100 to height placeholder
var running = true;
el.animate({
'margin-top':'+='+marginTop+'px'
}, {
'duration' : time,
'easing' : 'easeInOutQuint',
complete: function(){
console.log('yolo');
//$(this).on('animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd', function(){
counter++;
console.log(counter);
//})
}
});
} // end MoveSlots
} // end Spin
body{
/*background-color:white;*/
padding:50px;
margin:50px;
background: #505f77 !important;
}
#slotWrapper {
width:410px;
height:150px;
margin:50px auto;
overflow: hidden;
position:relative;
border:1px solid #f00;
}
#slot1-wrapper, #slot2-wrapper, #slot3-wrapper {
margin-top:0;
position: relative;
}
.slot {
width:120px;
height:150px;
margin-right:25px;
text-align:center;
float:left;
position: absolute;
}
#slot-3 {
margin-right:0;
}
#slot-1 {
top:0;
left:0;
}
#slot-2 {
top:0;
left:145px;
}
#slot-3 {
top:0;
left:290px;
}
.slot div {
width:120px;
height:150px;
}
.slot div img {
width:100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<link rel="stylesheet" type="text/css" href="css/style.css" />
<!-- <link rel="stylesheet" type="text/css" href="css/default.css" />
<link rel="stylesheet" type="text/css" href="css/component.css" /> -->
<div style="text-align:center">
<input type="button" value="spin!" onClick="Spin();" style="margin-top:4px;">
</div>
<div id="slotWrapper">
<div id="slot1-wrapper">
<div id="slot-1" class="slot"></div>
</div>
<div id="slot2-wrapper">
<div id="slot-2" class="slot"></div>
</div>
<div id="slot3-wrapper">
<div id="slot-3" class="slot"></div>
</div>
</div>
</body>
</html>
The problem is complete is executed asynchronously, ie the counter condition is executed is before the animations are completed.
You can use the animation promise to solve it
// ********************************************************
// SLOT MACHINE ICONS. Each array has 3 icons for each slot
// ********************************************************
var array1 = [
'<div data-id="0" style="width:100%; background:#fff; height:150px;"></div>',
'<div data-id="1" style="width:100%; background:#ccc; height:150px;"></div>',
'<div data-id="0" style="width:100%; background:#666; height:150px;"></div>'
]
var array2 = [
'<div data-id="0" style="width:100%; background:#fff; height:150px;"></div>',
'<div data-id="1" style="width:100%; background:#ccc; height:150px;"></div>',
'<div data-id="0" style="width:100%; background:#666; height:150px;"></div>'
]
var array3 = [
'<div data-id="0" style="width:100%; background:#fff; height:150px;"></div>',
'<div data-id="1" style="width:100%; background:#ccc; height:150px;"></div>',
'<div data-id="0" style="width:100%; background:#666; height:150px;"></div>'
]
// Generates random # between 0 and 2. Used for choosing winner and creating random slots
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// Generates winning array item between coffee, tea and espresso
function win(whatArray) {
var arrayItem = getRandomInt(0, 2);
var winItem = whatArray[arrayItem];
return winItem;
}
// Populates each slot with random icons to spin through
var makeList = function(whatArray, whatSlot) {
var slotArray = [];
for (i = 0; i < 100; i++) {
var randNum = getRandomInt(0, 2); // Generate random number
var findItem = whatArray[randNum]; // Use random number to find associated array item
var slot = whatSlot; // Set which slot to append array item to (first, second or third)
$('#' + slot).append('<div>' + findItem + '</div>'); // Append icon to HTML
}
var winItem = win(whatArray); // Generate winning icon for slot
console.log("winner " + winItem);
$('#' + slot).append('<div>' + winItem + '</div>'); // Append winning icon to end of list
}
// Spin the slot and win some caffeine!
function Spin() {
var counter = 0;
// Generate lists for each slot
makeList(array1, 'slot-1');
makeList(array2, 'slot-2');
makeList(array3, 'slot-3');
var p1 = MoveSlots($('#slot1-wrapper'), 2500);
var p2 = MoveSlots($('#slot2-wrapper'), 5200);
var p3 = MoveSlots($('#slot3-wrapper'), 500);
$.when(p1, p2, p3).then(function() {
//var running = true;
// console.log(running);
var slot1attr = $('#slot1-wrapper div').children().last().attr('data-id');
var slot2attr = $('#slot2-wrapper div').children().last().attr('data-id');
var slot3attr = $('#slot3-wrapper div').children().last().attr('data-id');
console.log('counter = ' + counter);
if (counter > 0) {
if (slot1attr == slot2attr && slot1attr == slot3attr) {
console.log("WIN");
} else {
console.log("LOSE");
}
}
});
function MoveSlots(el, speed) {
var time = speed;
time += Math.round(Math.random() * 10000);
el.stop(true, true);
var marginTop = -(100 * 150); //change 100 to height placeholder
var running = true;
el.animate({
'margin-top': '+=' + marginTop + 'px'
}, {
'duration': time,
'easing': 'easeInOutQuint',
complete: function() {
console.log('yolo');
counter++;
console.log(counter);
}
});
return el.promise();
} // end MoveSlots
} // end Spin
body {
/*background-color:white;*/
padding: 50px;
margin: 50px;
background: #505f77 !important;
}
#slotWrapper {
width: 410px;
height: 150px;
margin: 50px auto;
overflow: hidden;
position: relative;
border: 1px solid #f00;
}
#slot1-wrapper,
#slot2-wrapper,
#slot3-wrapper {
margin-top: 0;
position: relative;
}
.slot {
width: 120px;
height: 150px;
margin-right: 25px;
text-align: center;
float: left;
position: absolute;
}
#slot-3 {
margin-right: 0;
}
#slot-1 {
top: 0;
left: 0;
}
#slot-2 {
top: 0;
left: 145px;
}
#slot-3 {
top: 0;
left: 290px;
}
.slot div {
width: 120px;
height: 150px;
}
.slot div img {
width: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.js"></script>
<link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/redmond/jquery-ui.css" rel="stylesheet" />
<div style="text-align:center">
<input type="button" value="spin!" onClick="Spin();" style="margin-top:4px;">
</div>
<div id="slotWrapper">
<div id="slot1-wrapper">
<div id="slot-1" class="slot"></div>
</div>
<div id="slot2-wrapper">
<div id="slot-2" class="slot"></div>
</div>
<div id="slot3-wrapper">
<div id="slot-3" class="slot"></div>
</div>
</div>

Flexbox carousel transition issue

I'm trying to build a simple carousel with flexbox for a mobile website.
I found some examples I used to build mine.
I have a last issue I cannot resolve.
When I swipe left, the transition does not work.
The current image disapears before the transition begins.
When I swipe right, it works fine.
Thanks for your help.
Here is my code :
<!DOCTYPE html>
<html lang="fr-FR">
<head>
<meta name="viewport" content="target-densitydpi=device-dpi; width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"/>
<style>
.flex, .flex-c
{
display: box;
display: flexbox;
display: flex;
}
.flex-c
{
flex-direction: column;
}
.carousel-container
{
overflow: hidden;
}
.carousel-element
{
flex: 1 0 100%;
transform: translateX(0);
order: 2;
}
.carousel-swipeleft
{
transform: translateX(100%);
}
.carousel-swiperight
{
transform: translateX(-100%);
}
.carousel-transition
{
transform: none !important;
transition: transform 0.5s cubic-bezier(0.23, 1, 0.32, 1);
}
.carousel-ocontainer
{
margin: 10px 0;
justify-content: center;
}
.carousel-o
{
background: lightgray none repeat scroll 0 0;
-ms-border-radius: 5px;
border-radius: 5px;
height: 10px;
margin: 0 5px;
outline: 0 none;
text-indent: -9999px;
width: 10px;
padding-bottom: 10px;
}
.carousel-oactive
{
background: black none repeat scroll 0 0;
}
</style>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript" src="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.js"></script>
<script type="text/javascript">
$.mobile.pushStateEnabled = false;
Oog = function () {};
Oog.Carousel = function (containerClass, loop)
{
var self = this;
self.loop = loop;
self.elementClass = "carousel-element";
self.LazyClass = "carousel-lazy";
self.oContainerClass = containerClass + "-carousel-ocontainer";
self.oClass = "carousel-o";
self.oActiveClass = "carousel-oactive";
self.swipeleftClass = "carousel-swipeleft";
self.swiperightClass = "carousel-swiperight";
self.transitionClass = "carousel-transition";
self.containerSelector = "." + containerClass;
self.elementSelector = self.containerSelector + " ." + self.elementClass;
self.LazySelector = self.containerSelector + " ." + self.LazyClass;
self.findLazySelector = "." + self.LazyClass;
self.oContainerSelector = "." + self.oContainerClass;
self.oSelector = self.oContainerSelector + " ." + self.oClass;
};
Oog.Carousel.prototype =
{
initialize: function()
{
var self = this;
// Bullet points
var elements = $(self.elementSelector);
var html = "<div class='" + self.oContainerClass + " / carousel-ocontainer / flex'>";
for (var i = 0; i < elements.length; i++)
{
html = html + "<p class='" + self.oClass + "' data-id='" + $(elements[i]).data("id") + "'> O </p> ";
}
html = html + "</div>";
$(html).insertAfter(self.containerSelector);
// Affiche les bullets points si et seulement si le carousel est affiché
// -> nécessite que l'event existe (créé dans oog-mobile-script.js)
var oContainerSelector = self.oContainerSelector;
$(self.containerSelector).bind("displayChanged", function ()
{
if ($(this).css("display") === "none")
{
$(oContainerSelector).hide();
} else
{
$(oContainerSelector).show();
}
});
// Affichage du 1er élément du carousel
$(self.LazySelector).first().attr("src", $(self.LazySelector).first().data("src"));
$(self.oContainerSelector).hide();
$(self.oSelector).first().addClass(self.oActiveClass);
// Gestion des déplacements vers la gauche ou la droite
$(self.elementSelector).on("swipeleft", function ()
{
self.swipe(this, "swipeleft");
});
$(self.elementSelector).on("swiperight", function ()
{
self.swipe(this, "swiperight");
});
},
swipe: function(element, swipe)
{
var self = this;
var elements = $(self.elementSelector);
var nextElement;
if (swipe === "swipeleft")
{
elements.removeClass(self.swiperightClass);
elements.addClass(self.swipeleftClass);
nextElement = self.next(element, self.loop);
}
else
{
elements.removeClass(self.swipeleftClass);
elements.addClass(self.swiperightClass);
nextElement = self.prev(element, self.loop);
}
if (nextElement.length > 0)
{
$(self.oSelector).removeClass(self.oActiveClass);
$(self.oSelector + '[data-id="' + nextElement.data("id") + '"]').addClass(self.oActiveClass);
nextElement.find(self.findLazySelector).attr("src", nextElement.find(self.findLazySelector).data("src"));
for (var i = 0; i < elements.length; i++)
{
nextElement.css("order", (i + 1).toString());
nextElement = self.next(nextElement, true);
}
elements.removeClass(self.transitionClass);
setTimeout(function () { elements.addClass(self.transitionClass) }, 50);
}
},
next: function(element, loop)
{
var self = this;
return self.nextorprev(element, "swipeleft", loop);
},
prev: function (element, loop)
{
var self = this;
return self.nextorprev(element, "swiperight", loop);
},
nextorprev: function (element, swipe, loop) {
var self = this;
var elements = $(self.elementSelector);
var current = $(element);
var next;
if (swipe === "swipeleft") {
next = current.next();
if (next.length === 0 && loop) {
next = elements.first();
}
} else {
next = current.prev();
if (next.length === 0 && loop) {
next = elements.last();
}
}
return next;
}
};
$(document).ready(function()
{
var accessoryCarousel = new Oog.Carousel("product-tabAccessories", false);
accessoryCarousel.initialize();
});
</script>
</head>
<body class="body">
<div class="product-tabs / flex">
<div class="product-tab / product-tabAccessories / carousel-container / flex" data-tab="Accessories">
<a href="/prod-16768-Plaque-ONDUVILLA-217m2-rouge-ombre.html" title="Plaque ONDUVILLA rouge ombré, plusieurs surfaces disponibles" class="product-accessory / carousel-element / flex" data-id="16768">
<img class="carousel-lazy" alt="Plaque ONDUVILLA 2.17m² rouge ombré" data-src="http://media.oogarden.com/Product/0290/0290-0007-Thumb.jpg"/>
<div class="flex-c" style="justify-content: space-around; margin-left: 10px;">
<label>Plaque ONDUVILLA rouge ombré, plusieurs surfaces disponibles</label>
</div>
</a>
<a href="/prod-16769-Pointes-pour-feutre-bitumeux-x1200.html" title="Pointes pour bardeaux et feutres bitumeux " class="product-accessory / carousel-element / flex" data-id="16769">
<img class="carousel-lazy" alt="Pointes pour bardeaux et feutres bitumeux " data-src="http://media.oogarden.com/Product/0290/0290-0008-Thumb.jpg"/>
<div class="flex-c" style="justify-content: space-around; margin-left: 10px;">
<label>Pointes pour bardeaux et feutres bitumeux </label>
</div>
</a>
<a href="/prod-16782-Bardoline-100-3m2-bleu-ardoise.html" title="Bardoline couleur ardoise surface 3 m²" class="product-accessory / carousel-element / flex" data-id="16782">
<img class="carousel-lazy" alt="Bardoline couleur ardoise surface 3 m²" data-src="http://media.oogarden.com/Product/0290/0290-0004-Thumb.jpg"/>
<div class="flex-c" style="justify-content: space-around; margin-left: 10px;">
<label>Bardoline couleur ardoise surface 3 m²</label>
</div>
</a>
</div>
</div>
</body>
</html>

Uploading Multiple Files to Google Drive with Google App Script

I'm trying to upload multiple files at once with my app. It recognizes when there are 2 or more files being selected. However, it will only upload the 1st file that is selected to my drive. Also (although quite minor), I was wondering how I can change my textarea font to be Times New Roman to stay consistent with the rest of the font.
Code.gs
function doGet() {
return HtmlService.createHtmlOutputFromFile('form')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function uploadFiles(form) {
try {
var foldertitle = form.zone + ' | Building: ' + form.building + ' | ' + form.propertyAddress + ' | ' + form.attachType;
var folder, folders = DriveApp.getFolderById("0B7UEz7SKB72HfmNmNnlSM2NDTVVUSlloa1hZeVI0VEJuZUhSTmc4UXYwZjV1eWM5YXJPaGs");
var createfolder = folders.createFolder(foldertitle);
folder = createfolder;
var blob = form.filename;
var file = folder.createFile(blob);
file.setDescription(" " + form.fileText);
return "File(s) uploaded successfully! Here is the link to your file(s): " + folder.getUrl();
} catch (error) {
Logger.log('err: ' + error.toString());
return error.toString();
}
}
function uploadArquivoParaDrive(base64Data, nomeArq, idPasta) {
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(nomeArq);
var file = DriveApp.getFolderById("0B7UEz7SKB72HfmNmNnlSM2NDTVVUSlloa1hZeVI0VEJuZUhSTmc4UXYwZjV1eWM5YXJPaGs").createFile(ss);
return file.getName();
}catch(e){
return 'Erro: ' + e.toString();
}
}
form.html
<body>
<div id="formcontainer">
<label for="myForm">Facilities Project Database Attachment Uploader:</label>
<br><br>
<form id="myForm">
<label for="myForm">Project Details:</label>
<div>
<input type="text" name="zone" placeholder="Zone:">
</div>
<div>
<input type="text" name="building" placeholder="Building(s):">
</div>
<div>
<input type="text" name="propertyAddress" placeholder="Property Address:">
</div>
<div>
<label for="fileText">Project Description:</label>
<TEXTAREA name="projectDescription"
placeholder="Describe your attachment(s) here:"
style ="width:400px; height:200px;"
></TEXTAREA>
</div>
<br>
<label for="attachType">Choose Attachment Type:</label>
<br>
<select name="attachType">
<option value="Pictures Only">Picture(s)</option>
<option value="Proposals Only">Proposal(s)</option>
<option value="Pictures & Proposals">All</option>
</select>
<br>
<label for="myFile">Upload Attachment(s):</label>
<br>
<input type="file" name="filename" id="myFile" multiple>
<input type="submit" value="Submit" onclick="iteratorFileUpload()">
</form>
</div>
<div id="output"></div>
<script>
function iteratorFileUpload() {
var allFiles = document.getElementById('myFile').files;
if (allFiles.length == 0) {
alert('No file selected!');
} else {
// Send each file one at a time
var i=0;
for (i=0; i < allFiles.total; i+=1) {
console.log('This iteration: ' + i);
sendFileToDrive(allFiles[i]);
};
};
};
function sendFileToDrive(file) {
var reader = new FileReader();
reader.onload = function (e) {
var content = reader.result;
console.log('Sending ' + file.name);
google.script.run
.withSuccessHandler(fileUploaded)
.uploadArquivoParaDrive(content, file.name, currFolder);
}
reader.readAsDataURL(file);
};
</script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script>
// Upload de arquivo dentro das pastas Arquivos Auxiliares
function iterarArquivosUpload() {
var arquivos = document.getElementById('inputUpload').files;
if (arquivos.length == 0) {
alert('No file selected!');
} else {
//Show Progress Bar
numUploads.total = arquivos.length;
$('.progressUpload').progressbar({
value : false
});
$('.labelProgressUpload').html('Preparando arquivos para upload');
// Send each file at a time
for (var arqs = 0; arqs < numUploads.total; arqs++) {
console.log(arqs);
enviarArquivoParaDrive(arquivos[arqs]);
}
}
}
function enviarArquivoParaDrive(arquivo) {
var reader = new FileReader();
reader.onload = function (e) {
var content = reader.result;
console.log('Sending ' + arquivo.name);
google.script.run.withSuccessHandler(updateProgressbar).uploadArquivoParaDrive(content, arquivo.name, currFolder);
}
reader.readAsDataURL(arquivo);
}
function updateProgressbar( idUpdate ){
console.log('Received: ' + idUpdate);
numUploads.done++;
var porc = Math.ceil((numUploads.done / numUploads.total)*100);
$('.progressUpload').progressbar({value: porc });
$('.labelProgressUpload').html(numUploads.done +'/'+ numUploads.total);
if( numUploads.done == numUploads.total ){
uploadsFinished();
numUploads.done = 0;
};
}
</script>
<script>
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;
}
</style>
</body>
I know this question is old, but after finding it and related ones, I was never able to get the multiple file upload working. So after a lot of banging my head against walls, I wanted to post a full example (.html and .gs) in case anyone in the future is looking for one to get started. This is working when I deploy it right now and will hopefully work for other people out there. Note that I just hardcoded the folder in the drive to use in the code.gs file, but that can be easily changed.
form.html:
<body>
<div id="formcontainer">
<label for="myForm">Facilities Project Database Attachment Uploader:</label>
<br><br>
<form id="myForm">
<label for="myForm">Project Details:</label>
<div>
<input type="text" name="zone" placeholder="Zone:">
</div>
<div>
<input type="text" name="building" placeholder="Building(s):">
</div>
<div>
<input type="text" name="propertyAddress" placeholder="Property Address:">
</div>
<div>
<label for="fileText">Project Description:</label>
<TEXTAREA name="projectDescription"
placeholder="Describe your attachment(s) here:"
style ="width:400px; height:200px;"
></TEXTAREA>
</div>
<br>
<label for="attachType">Choose Attachment Type:</label>
<br>
<select name="attachType">
<option value="Pictures Only">Picture(s)</option>
<option value="Proposals Only">Proposal(s)</option>
<option value="Pictures & Proposals">All</option>
</select>
<br>
<label for="myFile">Upload Attachment(s):</label>
<br>
<input type="file" name="filename" id="myFile" multiple>
<input type="button" value="Submit" onclick="iteratorFileUpload()">
</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">
<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
// This is 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
numUploads.total = allFiles.length;
$('#progressbar').progressbar({
value : false
});//.append("<div class='caption'>37%</div>");
$(".progress-label").html('Preparing files for upload');
// Send each file at a time
for (var i = 0; i < allFiles.length; i++) {
console.log(i);
sendFileToDrive(allFiles[i]);
}
}
}
function sendFileToDrive(file) {
var reader = new FileReader();
reader.onload = function (e) {
var content = reader.result;
console.log('Sending ' + file.name);
var currFolder = 'Something';
google.script.run.withSuccessHandler(updateProgressbar).uploadFileToDrive(content, file.name, currFolder);
}
reader.readAsDataURL(file);
}
function updateProgressbar( idUpdate ){
console.log('Received: ' + 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 ){
//uploadsFinished();
numUploads.done = 0;
};
}
</script>
<script>
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>
code.gs:
function doGet() {
return HtmlService.createHtmlOutputFromFile('form')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function uploadFileToDrive(base64Data, fileName) {
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 = "Something"; // Folder Name
var folder, folders = DriveApp.getFoldersByName(dropbox);
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = DriveApp.createFolder(dropbox);
}
var file = folder.createFile(ss);
return file.getName();
}catch(e){
return 'Error: ' + e.toString();
}
}
Updated For May 2017
I updated and improved barragan's answer.
Advantages:
Allows users to create a subfolder name to contain all the files uploaded during this session
Ensures that these subfolders all exist within one specified folder within your Google Drive
The page/form is mobile-responsive
You can start with this example just to create the script and get to know the basics.
Then you can completely replace form.html with this:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>
Send Files
</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script>
$(document).ready(function () {
function afterSubfolderCreated(subfolderId) {
console.log(subfolderId);
console.log(allFiles);
numUploads.total = allFiles.length;
$('#progressbar').progressbar({
value: false
});
$(".progress-label").html('Preparing files for upload');
for (var i = 0; i < allFiles.length; i++) {
console.log(i);
sendFileToDrive(allFiles[i], subfolderId);
}
}
function sendFileToDrive(file, subfolderId) {
var reader = new FileReader();
reader.onload = function (e) {
var content = reader.result;
console.log('Sending ' + file.name);
google.script.run.withSuccessHandler(updateProgressbar).uploadFileToDrive(content, file.name, subfolderId);
}
reader.readAsDataURL(file);
}
function updateProgressbar(idUpdate) {
console.log('Received: ' + 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;
$(".progress-label").text($(".progress-label").text() + ': FINISHED!');
$("#progressbar").after('(Optional) Refresh this page if you remembered other screenshots you want to add.');//<a href="javascript:window.top.location.href=window.top.location.href"> does not work
}
}
function fileUploaded(status) {
document.getElementById('myForm').style.display = 'none';
document.getElementById('output').innerHTML = status;
}
var numUploads = {};
numUploads.done = 0;
numUploads.total = 0;
var allFiles;
var frm = $('#myForm');
frm.submit(function () {
allFiles = document.getElementById('myFile').files;
if (!frm.checkValidity || frm.checkValidity()) {
if (allFiles.length == 0) {
alert('Error: Please choose at least 1 file to upload.');
return false;
} else {
frm.hide();
var subfolderName = document.getElementById('myName').value;
$.ajax({
url: '',//URL of webhook endpoint for sending a Slack notification
data: {
title: subfolderName + ' is uploading screenshots',
message: ''
}
});
google.script.run.withSuccessHandler(afterSubfolderCreated).createSubfolder(subfolderName);
return false;
}
} else {
alert('Invalid form');
return false;
}
});
});//end docReady
</script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
<style>
body {
padding: 20px;
margin: auto;
font-size: 20px;
}
label{
font-weight: bold;
}
input{
font-size: 20px;
padding: 5px;
display: inline-block;
margin-bottom: 10px;
-webkit-box-sizing: border-box;
‌-moz-box-sizing: border-box;
box-sizing: border-box;
}
.hint{
font-size: 90%;
color: #666;
}
select {
margin: 5px 0px 15px 0px;
}
input[type="file"] {
padding: 5px 0px 15px 0px;
}
#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;
}
li{
padding: 10px;
}
#media only screen and (max-width : 520px) {
#logo {
max-width: 100%;
}
}
</style>
</head>
<body>
<p>
<img src="" id="logo">
</p>
<p>This webpage allows you to send me screenshots of your dating profiles.</p>
<ol>
<li>
In each of your dating apps, take a screenshot (how?) of every part of every page of your profile.
</li>
<li>
Do the same for each of your photos (at full resolution).
</li>
<li>
In the form below, type your first name and last initial (without any spaces or special characters), such as SallyT.
</li>
<li>
Then click the first button and select all of your screenshot images (all at once).
</li>
<li>
Finally, press the last button to send them all to me!
</li>
</ol>
<form id="myForm">
<div>
<label for="myName">Your first name and last initial:</label>
</div>
<div>
<input type="text" name="myName" id="myName" placeholder="SallyT" required pattern="[a-zA-Z]+" value="">
</div>
<div>
<span class="hint">(No spaces or special characters allowed because this will determine your folder name)</span>
</div>
<div style="margin-top: 20px;">
<label for="myFile">Screenshot image files:</label>
<input type="file" name="filename" id="myFile" multiple>
</div>
<div style="margin-top: 20px;">
<input type="submit" value="Send File(s) ➔" >
</div>
</form>
<div id="output"></div>
<div id="progressbar">
<div class="progress-label"></div>
</div>
</body>
</html>
And completely replace server.gs with this:
function doGet() {
var output = HtmlService.createHtmlOutputFromFile('form');
output.addMetaTag('viewport', 'width=device-width, initial-scale=1');// See http://stackoverflow.com/a/42681526/470749
return output.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function uploadFileToDrive(base64Data, fileName, subfolderId) {
Logger.log(subfolderId);
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 subfolder = DriveApp.getFolderById(subfolderId);
var file = subfolder.createFile(ss);
Logger.log(file);
return file.getName() + ' at ' + file.getUrl();
} catch(e){
return 'createFile Error: ' + e.toString();
}
}
function createSubfolder(subfolderName){
var dropbox = subfolderName + Utilities.formatDate(new Date(), "US/Eastern", "_yyyy-MM-dd");
Logger.log(dropbox);
var parentFolderId = "{ID such as 0B9iQ20nrMNYAaHZxRjd}";
var parentFolder = DriveApp.getFolderById(parentFolderId);
var folder;
try {
folder = parentFolder.getFoldersByName(dropbox).next();
}
catch(e) {
folder = parentFolder.createFolder(dropbox);
}
Logger.log(folder);
return folder.getId();
}
Joining the pile of older answers, but this really helped me when I implemented my own file multi upload for getting files into Google Drive using the DriveApp V3 api.
I wrote and posted my own solution here: https://github.com/CharlesPlucker/drive-multi-upload/
Improvements:
- Handles multiple files sequentially
- Handles large > 50MB files
- Validation
I wrapped my google api calls into promises since I was running into timing issues when creating a folder and immediately trying to fetch it by name reference. Each one of my promises will only resolve when its file is fully uploaded. To get that working I had to use a Promise Factory. I'll be glad to explain this code if the need arises!
You have to send a file at a time trough the script.run, here's my implementation with FileReaders/ReadAsURL, which makes the file a Base64 string, which can be easily passed around:
Notes:
Dunno if it's necessary but I'm using IFRAME sandbox
I left the progressBar in the code, you can remove it
Everything must be OUTSIDE a form
It accepts any file type
HTML:
// Upload de arquivo dentro das pastas Arquivos Auxiliares
function iterarArquivosUpload() {
var arquivos = document.getElementById('inputUpload').files;
if (arquivos.length == 0) {
alert('No file selected!');
} else {
//Show Progress Bar
numUploads.total = arquivos.length;
$('.progressUpload').progressbar({
value : false
});
$('.labelProgressUpload').html('Preparando arquivos para upload');
// Send each file at a time
for (var arqs = 0; arqs < numUploads.total; arqs++) {
console.log(arqs);
enviarArquivoParaDrive(arquivos[arqs]);
}
}
}
function enviarArquivoParaDrive(arquivo) {
var reader = new FileReader();
reader.onload = function (e) {
var content = reader.result;
console.log('Sending ' + arquivo.name);
google.script.run.withSuccessHandler(updateProgressbar).uploadArquivoParaDrive(content, arquivo.name, currFolder);
}
reader.readAsDataURL(arquivo);
}
function updateProgressbar( idUpdate ){
console.log('Received: ' + idUpdate);
numUploads.done++;
var porc = Math.ceil((numUploads.done / numUploads.total)*100);
$('.progressUpload').progressbar({value: porc });
$('.labelProgressUpload').html(numUploads.done +'/'+ numUploads.total);
if( numUploads.done == numUploads.total ){
uploadsFinished();
numUploads.done = 0;
};
}
Code.GS
function uploadArquivoParaDrive(base64Data, nomeArq, idPasta) {
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(nomeArq);
var file = DriveApp.getFolderById(idPasta).createFile(ss);
return file.getName();
}catch(e){
return 'Erro: ' + e.toString();
}
}
as #barragan's answer here is the best answer i found after hours and hours of searching for a question many people were asking, i've done a bit of development to improve the design a bit for others as a thanks. still a few bugs and chrome seems to run out of memory and give up with any file over 100MB
here's a live version
server.gs
'function doGet() {
return HtmlService.createHtmlOutputFromFile('form')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function uploadFileToDrive(base64Data, fileName) {
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 = "Something"; // Folder Name
var folder, folders = DriveApp.getFoldersByName(dropbox);
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = DriveApp.createFolder(dropbox);
}
var file = folder.createFile(ss);
return file.getName();
}catch(e){
return 'Error: ' + e.toString();
}
}
'
form.html
<head>
<base target="_blank">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Focallocal Uploader</title>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.5/css/materialize.min.css">
<div align="center">
<p><img src="http://news.focallocal.org/wp-content/uploads/2015/03/FOCALLOCAL-Website-Text-Header.png" width="80%"></p>
</div>
</head>
<body>
<div id="formcontainer" width="50%">
<label for="myForm">Focallocal Community G.Drive Uploader</label>
<br>
<br>
<form id="myForm" width="50%">
<label for="myForm">Details</label>
<div>
<input type="text" name="Name" placeholder="your name">
</div>
<div>
<input type="text" name="gathering" placeholder="which fabulous Positive Action you're sending us">
</div>
<div>
<input type="text" name="location" placeholder="the town/village/city and country month brightend by positivity">
</div>
<div>
<input type="text" name="date" placeholder="date of the beautiful action">
</div>
<div width="100%" height="200px">
<label for="fileText">would you like to leave a short quote?</label>
<TEXTAREA name="Quote"
placeholder="many people would love to share in your experience. if you have more than a sentence or two to write, why not writing an article the Community News section of our website?"
></TEXTAREA>
</div>
<br>
<br>
<label for="myFile">Upload Your Files:</label>
<br>
<input type="file" name="filename" id="myFile" multiple>
<input type="button" value="Submit" onclick="iteratorFileUpload();">
</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">
<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
// This is 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
numUploads.total = allFiles.length;
$('#progressbar').progressbar({
value : false
});//.append("<div class='caption'>37%</div>");
$(".progress-label").html('Preparing files for upload');
// Send each file at a time
for (var i = 0; i < allFiles.length; i++) {
console.log(i);
sendFileToDrive(allFiles[i]);
}
}
}
function sendFileToDrive(file) {
var reader = new FileReader();
reader.onload = function (e) {
var content = reader.result;
console.log('Sending ' + file.name);
var currFolder = 'Something';
google.script.run.withSuccessHandler(updateProgressbar).uploadFileToDrive(content, file.name, currFolder);
}
reader.readAsDataURL(file);
}
function updateProgressbar( idUpdate ){
console.log('Received: ' + 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 ){
//uploadsFinished();
numUploads.done = 0;
};
}
</script>
<script>
function fileUploaded(status) {
document.getElementById('myForm').style.display = 'none';
document.getElementById('output').innerHTML = status;
}
</script>
<style>
body {
max-width: 60%;
padding: 20px;
margin: auto;
}
input {
display: inline-block;
width: 50%;
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: 40%;
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>
i wasn't able to get the text fields to send an email with the details out, and ran out of time before working out how to hook them up to a Google Spreadsheet, so for the moment they don't record the information added
as an added bonus, it looked fabulous with is in the form.html
<div class="fixed-action-btn horizontal" style="bottom: 45px; right: 24px;">
<a class="btn-floating btn-large red">
<i class="large material-icons">menu</i>
</a>
<ul>
<li><a class="btn-floating red" href="https://focallocal-a-positive-action-movement.myshopify.com/" target="_blank" title="Pimp your Cool at the Positive Action Shop"><i class="material-icons">monetization_on</i></a></li>
<li><a class="btn-floating blue" href="https://www.youtube.com/user/Focallocal" target="_blank" title="Follow the Positive Action Youtube Channel"><i class="material-icons">video_library</i></a></li>
<li><a class="btn-floating green" href="http://focallocal.org/" target="_blank" title="Read our About Us Page"><i class="material-icons">help</i></a></li>
</ul>
</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">
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.5/js/materialize.min.js"></script>
<script src="https://gumroad.com/js/gumroad.js"></script>
i took it out again as some of the scripts being called in were causing issues. if anyone can fix them it they add a lot to the appearance and functionality of the form
*edit: i've been playing around with it and only around half of the files sent seem to arrive, so there are still some issues with both of the codes here atm

Categories