Instantly share code, notes, and snippets.
Last active
March 29, 2021 15:23
-
Star
0
(0)
You must be signed in to star a gist -
Fork
1
(1)
You must be signed in to fork a gist
-
Save nicolasdao/e5ba7a6cb919f08a100d4081f9ec09f1 to your computer and use it in GitHub Desktop.
html code that demos various forms to interact with your Google Docs. Build with jQuery, jQuery UI, jQuery Validation, spin.js and Google Apps Script CSS style guide
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<!-- Used by Google Apps Script to use with iFrame (ref. https://developers.google.com/apps-script/migration/iframe) --> | |
<base target="_top"> | |
<!-- Google Apps Script CCS STyle Guide (ref. https://developers.google.com/apps-script/add-ons/css) --> | |
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css"> | |
<!-- jQuery UI ThemeRoller (ref. http://jqueryui.com/themeroller/) - e.g. needed for calendar --> | |
<link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.9.1/themes/smoothness/jquery-ui.css"> | |
<!-- Good ol' jQuery --> | |
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> | |
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.9.1/jquery-ui.min.js"></script> | |
<script src="https://cdn.jsdelivr.net/jquery.validation/1.16.0/jquery.validate.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/spin.js/2.3.2/spin.min.js"></script> | |
<script> | |
//-------------------------------------------------------------------------------- 1. START - EVENT HANDLERS | |
// Prevent forms from submitting. | |
function preventFormSubmit() { | |
var forms = document.querySelectorAll('form'); | |
for (var i = 0; i < forms.length; i++) { | |
forms[i].addEventListener('submit', function(event) { | |
event.preventDefault(); | |
}); | |
} | |
} | |
window.addEventListener('load', preventFormSubmit); | |
function validateInt(evt) { | |
var theEvent = evt || window.event; | |
var key = theEvent.keyCode || theEvent.which; | |
key = String.fromCharCode(key); | |
var regex = /[0-9]/; | |
if (!regex.test(key)) { | |
theEvent.returnValue = false; | |
if (theEvent.preventDefault) theEvent.preventDefault(); | |
} | |
} | |
function submitHandler(form) { | |
var v = form["randomvalue"].value; | |
showSpinner('submit-spinning-wheel'); | |
// Replace this code with a call to 'google.script.run.yourGScode()' | |
showDialog( | |
"Dummy Behavior", | |
"Replace this dialog with a call to 'google.script.run.yourGScode()'", | |
function() { | |
hideSpinner(); | |
}); | |
} | |
function handleFindUserSubmit(form) { | |
var age = getFormValue("#age", form); | |
var name = getFormValue("#name", form); | |
var email = getFormValue("#email", form); | |
showSpinner('find-spinning-wheel'); | |
// Replace this code with a call to 'google.script.run.yourGScode()' | |
showDialog( | |
"Dummy Behavior", | |
"Replace this dialog with a call to 'google.script.run.yourGScode()'", | |
function() { | |
hideSpinner(); | |
}); | |
} | |
function handleSearchTripSubmit(form) { | |
var startdate = getFormValue("#startdate", form); // string | |
var enddate = getFormValue("#enddate", form); // string | |
var departDate = new Date(startdate); | |
var returnDate = new Date(enddate); | |
var priceRange = $( "#slider-range" ).slider( "values" ); // e.g. [75, 345] | |
var extraSources = getFormValues('input[name=travel-source]:checked', form); | |
var tripType = getFormValues('input[name=triptype]:checked', form); | |
showSpinner('search-spinning-wheel'); | |
// WARNING - Javascript dates serialization issue | |
// As of March 2017, there is a weird bug when passing js date objects to | |
// 'google.script.run.yourGScode(yourInputWithJsDate)'. To cope with this | |
// issue, one possible solution is to serialize the js date object into a | |
// string using JSON.stringify(yourDateObj). On the server-side (i.e.) .gs | |
// code, you will then use JSON.parse to deserialize that string object. | |
// Replace this code with a call to 'google.script.run.yourGScode()' | |
showDialog( | |
"Dummy Behavior", | |
"Replace this dialog with a call to 'google.script.run.yourGScode()'", | |
function() { | |
hideSpinner(); | |
}); | |
} | |
function onCurrencyChange(obj) { | |
var currency = obj.value; | |
var currencySymbol = getCurrencySymbol(currency); | |
$("#slider-range").slider("option","slide",""); // unbind the previous callback method on the slide event | |
$("#slider-range").on( "slide", function( event, ui ) { // bind a new callback on the slide event | |
updateRangeValue(ui.values[0], ui.values[1], currencySymbol); | |
} ); | |
updateRangeValue($("#slider-range").slider("values", 0), $("#slider-range").slider("values", 1), currencySymbol); | |
} | |
function updateDatepickers(obj){ | |
var selection = obj.value; | |
if (selection == "return"){ | |
$("#enddate").val(null); | |
$("#enddate-row").show(); | |
} | |
else { // one way has been selected | |
$("#enddate-row").hide(); | |
$("#enddate").val("01/01/2999"); // hack to 'disable' validation so we can submit without worrying about that field | |
} | |
} | |
//-------------------------------------------------------------------------------- 1. END - EVENT HANDLERS | |
// | |
//-------------------------------------------------------------------------------- 2. START - UTILITIES | |
function getFormValue(selector, form) { | |
return $($(form).find(selector)).val(); | |
} | |
function getFormValues(selector, form) { | |
var results = $(form).find(selector); | |
var a = []; | |
for (var i = 0; i < results.length; i++) a.push(results[i].value); | |
return a; | |
} | |
function updateRangeValue(minValue, maxValue, currency){ | |
$("#amount").val(currency + minValue + " - " + currency + maxValue); | |
} | |
function getCurrencySymbol(currency){ | |
switch(currency.toUpperCase()){ | |
case "USD": | |
return "$"; | |
case "CAD": | |
return "$"; | |
case "NZD": | |
return "$"; | |
case "AUD": | |
return "$"; | |
case "JPY": | |
return "¥"; | |
case "EUR": | |
return "€"; | |
default: | |
return "$"; | |
} | |
} | |
//-------------------------------------------------------------------------------- 2. END - UTILITIES | |
// | |
//-------------------------------------------------------------------------------- 3. START - UI CONFIG | |
// Check out http://spin.js.org/ to visually adjust those params | |
var opts = { | |
lines: 9, // The number of lines to draw | |
length: 2, // The length of each line | |
width: 3, // The line thickness | |
radius: 6, // The radius of the inner circle | |
scale: 1, // Scales overall size of the spinner | |
corners: 1, // Corner roundness (0..1) | |
color: '#000', // #rgb or #rrggbb or array of colors | |
opacity: 0.35, // Opacity of the lines | |
rotate: 0, // The rotation offset | |
direction: 1, // 1: clockwise -1: counterclockwise | |
speed: 1, // Rounds per second | |
trail: 60, // Afterglow percentage | |
fps: 20, // Frames per second when using setTimeout() as a fallback for CSS | |
zIndex: 2e9, // The z-index (defaults to 2000000000) | |
className: 'spinner', // The CSS class to assign to the spinner | |
top: '50%', // Top position relative to parent | |
left: '50%', // Left position relative to parent | |
shadow: false, // Whether to render a shadow | |
hwaccel: false, // Whether to use hardware acceleration | |
position: 'relative', // Element positioning | |
}; | |
var spinner = {}; | |
function showSpinner(selector) { | |
var spinningTarget = document.getElementById(selector); | |
spinner = new Spinner(opts).spin(spinningTarget); | |
} | |
function hideSpinner() { | |
spinner.stop(); | |
} | |
function showDialog(header, msg, onCloseCb) { | |
$("#dialog") | |
.dialog("option", "title", header) | |
.html(msg) | |
.on("dialogclose", function(event, ui) { | |
onCloseCb(); | |
}) | |
.dialog("open"); | |
} | |
//-------------------------------------------------------------------------------- 3. END - UI | |
</script> | |
</head> | |
<body> | |
<style> | |
.main { | |
padding-top: 10px; | |
padding-left: 20px | |
} | |
.row { | |
margin-bottom: 15px; | |
vertical-align: top; | |
} | |
.col-100-perc { | |
width: 230px; | |
} | |
.col-33-perc { | |
width: 70px; | |
} | |
.col-66-perc { | |
width: 144px; | |
} | |
.col-50-perc { | |
width: 105px; | |
} | |
.spinning-wheel-container { | |
max-height: 0px; | |
} | |
.spinning-wheel { | |
margin-top: 10px; | |
margin-left: 20px; | |
} | |
.slider { | |
margin-left: 0px !important | |
} | |
.group-checkbox { | |
margin-left: 10px; | |
margin-top: 5px | |
} | |
</style> | |
<div class="main"> | |
<div id="dialog" title="Dialog Title"></div> | |
<form id="simplest-form" onsubmit="submitHandler(this)"> | |
<h3>Example A - Simplest Form + No Validation</h3> | |
<div class="row form-group"> | |
<label for="randomvalue">Enter any value</label> | |
<input id="randomvalue" type="text" name="randomvalue" class="col-100-perc" /> | |
</div> | |
<div class="row inline form-group"> | |
<input class="action" type="submit" value="Submit" /> | |
<input type="button" value="Close" onclick="google.script.host.close()" /> | |
</div> | |
<div class="row inline form-group spinning-wheel-container"> | |
<div id="submit-spinning-wheel" class="spinning-wheel"></div> | |
</div> | |
</form> | |
<form id="user-form"> | |
<h3>Example B - Find User + Validation</h3> | |
<div id="name-age"> | |
<div class="row inline form-group"> | |
<label for="name">Name</label> | |
<input id="name" type="text" name="name" class="col-66-perc" /> | |
</div> | |
<div class="row inline form-group"> | |
<label for="age">Age</label> | |
<input id="age" type="text" name="age" class="col-33-perc" onkeypress='validateInt(event)' /> | |
</div> | |
</div> | |
<div id="name-error"></div> | |
<div id="age-error"></div> | |
<div class="row form-group"> | |
<label for="email">Email (optional)</label> | |
<input id="email" type="text" name="email" class="col-100-perc" /> | |
</div> | |
<div class="row inline form-group"> | |
<input id="find-button" type="submit" value="Find" /> | |
</div> | |
<div class="row inline form-group spinning-wheel-container"> | |
<div id="find-spinning-wheel" class="spinning-wheel"></div> | |
</div> | |
</form> | |
<form id="filter-form"> | |
<h3>Example C - Find Random Trip + Validation</h3> | |
<div class="row form-group"> | |
<input type="radio" name="triptype" id="oneway" value="oneway" onClick="updateDatepickers(this)" > One way | |
<input type="radio" name="triptype" id="return" value="return" onClick="updateDatepickers(this)" checked="checked" style="margin: 0px 5px 0px 20px"> Return | |
</div> | |
<div class="row inline form-group"> | |
<label for="startdate">Depart</label> | |
<input type="text" name="startdate" id="startdate" class="col-50-perc" /> | |
</div> | |
<div id="enddate-row" class="row inline form-group"> | |
<label for="enddate">Return</label> | |
<input type="text" name="enddate" id="enddate" class="col-50-perc" /> | |
</div> | |
<div class="row inline form-group slider"> | |
<span for="amount">Price Range:</span> | |
<input type="text" id="amount" readonly style="border:0; color:#f6931f; font-weight:bold;"> | |
<div style="margin-top: 5px"> | |
<div id="slider-range"></div> | |
</div> | |
</div> | |
<div class="row form-group" style="margin-top: 12px"> | |
<label for="currency">Currency</label> | |
<select id="currency" name="currency" class="col-33-perc" onchange="onCurrencyChange(this)"> | |
<option value="usd" selected>USD</option> | |
<option value="cad">CAD</option> | |
<option value="aud">AUD</option> | |
<option value="nzd">NZD</option> | |
<option value="eur">EUR</option> | |
<option value="jpy">JPY</option> | |
</select> | |
</div> | |
<div class="row form-group" style="margin-top: 12px"> | |
<label for="travel-source">Included Extra Sources</label> | |
<div class="group-checkbox"> | |
<input type="checkbox" name="travel-source" id="google" value="google"> Google Trips <br/> | |
<input type="checkbox" name="travel-source" id="kayak" value="kayak"> Kayak <br/> | |
<input type="checkbox" name="travel-source" id="skyscanner" value="skyscanner"> Skyscanner | |
</div> | |
</div> | |
<div class="row inline form-group"> | |
<input class="share" type="submit" value="Search" /> | |
</div> | |
<div class="row inline form-group spinning-wheel-container"> | |
<div id="search-spinning-wheel" class="spinning-wheel"></div> | |
</div> | |
</form> | |
</div> | |
<script> | |
$().ready(function() { | |
//-------------------------------------------------------------------------------- 1. START - VALIDATION CONFIG | |
$("#user-form").validate({ | |
rules: { | |
name: "required", | |
age: "required", | |
email: { | |
email: true | |
} | |
}, | |
messages: { | |
age: "The Age field is required", | |
name: "The Name field is required" | |
}, | |
submitHandler: handleFindUserSubmit, | |
invalidHandler: function(event, validator) { | |
// code being called if the form is being submitted, but the validation fails. | |
}, | |
errorPlacement: function(error, element) { | |
switch (element.attr("name")) { | |
case "age": | |
error.insertAfter($("div#name-error")); | |
break; | |
case "name": | |
error.insertAfter($("div#age-error")); | |
break; | |
default: | |
error.insertAfter(element); | |
} | |
} | |
}); | |
$("#filter-form").validate({ | |
rules: { | |
startdate: "required", | |
enddate: "required" | |
}, | |
messages: { | |
startdate: "Depart date required", | |
enddate: "Return date required" | |
}, | |
submitHandler: handleSearchTripSubmit, | |
invalidHandler: function(event, validator) { | |
// code being called if the form is being submitted, but the validation fails. | |
} | |
}); | |
//-------------------------------------------------------------------------------- 1. END - VALIDATION CONFIG | |
// | |
//-------------------------------------------------------------------------------- 2. START - JQUERY UI CONFIG | |
// Doc for the datepicker API here http://api.jqueryui.com/datepicker/ | |
var today = new Date(); | |
$("#startdate").datepicker({ | |
minDate: today | |
}) | |
.on('change', function(ev) { | |
$(this).valid(); // triggers the validation test | |
$("#enddate").datepicker("option", "minDate", new Date(this.value)); // make sure the end date never happens before the start date | |
}); | |
$("#enddate").datepicker({ | |
minDate: today | |
}) | |
.on('change', function(ev) { | |
$(this).valid(); // triggers the validation test | |
}); | |
$("#slider-range").slider({ | |
range: true, | |
min: 0, | |
max: 2000, | |
values: [450, 1200], | |
slide: function(event, ui) { | |
updateRangeValue(ui.values[0], ui.values[1], "$"); | |
} | |
}); | |
updateRangeValue($("#slider-range").slider("values", 0), $("#slider-range").slider("values", 1), "$"); | |
// You probably don't need this dialog code. It's just usefull to guide you through this demo | |
$("#dialog").dialog({ | |
autoOpen: false, | |
width: 250 | |
}); | |
//-------------------------------------------------------------------------------- 2. END - JQUERY UI CONFIG | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment