`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
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
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/
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>
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>
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