I've made a Google Apps Script deployed as a standalone web app using HTMLService that provides a simple front end to enter budget data into a Google Spreadsheet. I'm using JQuery Mobile for some of the javascript as well as to style it a mobile-friendly manner, as my main use case for this app is to enter purchases from my mobile.
My problem is that on a mobile browser, the app doesn't scale properly. It's the width of the browser, but it's as if it was "zoomed out". All the controls become essentially unusable on mobile.
If the script is embedded in a Google Site, it scales properly, but I'd rather be able to view the web app directly, rather than embed it in Google Sites.
EDIT: My rep is high enough to post photos now, so here they are (below code).
EDIT: The beginning of my HTML is below. I originally had the javascript and the full HTML in here, and I can add snippets if needed, but I reviewed it again and don't think it's relelvant to the problem it was cluttering up the question, so I removed it.
HTML:
<!DOCTYPE html>
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquerymobile/1.4.5/jquery.mobile.min.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jquerymobile/1.4.5/jquery.mobile.min.css">
<?!= include('javascript'); ?>
<div data-role="page" data-theme="a" id="main">
<div data-role="content">
<form id="myForm">
...
Code.gs:
function doGet() {
return HtmlService.createTemplateFromFile('index').evaluate()
.setSandboxMode(HtmlService.SandboxMode.IFRAME).setTitle('Budget Entry');
}
Snippet with full code:
//<script>
function formSuccess() {
var dateSelect = document.getElementById("date");
var dateSelected = dateSelect.options[dateSelect.selectedIndex].text;
var catSelect = document.getElementById("category");
var catSelected = catSelect.options[catSelect.selectedIndex].text;
var amountEntered = document.getElementById("amount").value;
var noteEntered = document.getElementById("note").value;
var successMsg = 'Date: ' + dateSelected +
'<br>Category: ' + catSelected +
'<br>Amount: $' + amountEntered +
'<br>Note: ' + noteEntered;
$('#dialogMain').html(successMsg);
$.mobile.silentScroll(0);
$.mobile.changePage( "#dialog", { role: "dialog" } );
requestCategoryInfo(document.getElementById("status"));
document.getElementById("amount").value = '';
document.getElementById("note").value = '';
}
function submitForm() {
if (document.getElementById('amount').value.length == 0) {
alert('Please enter an amount.');
return;
}
$.mobile.loading( 'show' );
$('#status').html('');
google.script.run
.withSuccessHandler(formSuccess)
.processForm(document.getElementById('myForm'));
}
function loadUI() {
$.mobile.loading( 'show' );
loadDateSelect();
google.script.run.withSuccessHandler(loadCategoryNamesAndValues).withFailureHandler(sendLog)
.getCategoryNamesAndValues();
$.mobile.loading( 'hide' );
}
function loadDateSelect(){
var d = new Date();
var month = d.getMonth()+1;
var today = d.getDate();
var daysInAMonth = [0,31,28,31,30,31,30,31,31,30,31,30,31];
for (var n=1; n <= daysInAMonth[month]; n++) {
var option = $("<option>").attr('value',n).text(month+"/"+n);
$('#date').append(option);
}
$('#date').val(today);
$('#date').selectmenu('refresh', true);
}
function loadCategoryNamesAndValues(catNamesAndValues){
var namesAndValues = catNamesAndValues;
var optionHTML = '';
var currentGroup = '';
var catName = '';
var catID = '';
for (var i=0; i<namesAndValues.length; i++) {
catName = namesAndValues[i][0];
catID = namesAndValues[i][1];
if (catID.toString() == "Group"){ // Handle Group Name
if (currentGroup.length > 0) { // close previous optgroup tag
optionHTML += "</optGroup>";
}
// Open optGroup
currentGroup = catName;
optionHTML += "<optGroup label='" + currentGroup + "'>";
} else if (isNaN(parseInt(catID)) || parseInt(catID) == 0){ //Do Nothing
} else { // Create Option HTML as: <option value=namesAndValues[i][1]>namesAndValues[i][0]</option>
optionHTML += "<option value='" + catID + "'>" + catName + "</option>";
}
}
// Close current OptGroup
optionHTML += "</optGroup>"
document.getElementById('category').innerHTML = optionHTML;
$('#category').selectmenu('refresh', true);
}
function categoryChanged() {
setStatus('');
requestCategoryInfo(document.getElementById('status'));
}
function requestCategoryInfo(container) {
$.mobile.loading( 'show' );
google.script.run
.withSuccessHandler(displayCategoryInfo)
.withFailureHandler(sendLog)
.withUserObject(container)
.getCategoryInfo(document.getElementById('category').value);
}
function displayCategoryInfo(categoryInfo, container){
var spentStr = 'Spent $' + categoryInfo.actual.toFixed(2) + ' of $' + categoryInfo.budgeted.toFixed(2);
var remainingStr = 'Remaining: $' + categoryInfo.remaining.toFixed(2);
var statusDiv = container;
if (statusDiv.innerHTML.length > 0){ statusDiv.innerHTML += '<br>'};
statusDiv.innerHTML += spentStr + '<br>' + remainingStr;
if (String(categoryInfo.fundAmount).length > 0) {
var fundAmountStr = '';
if (categoryInfo.remaining < 0) {
fundAmountStr = (categoryInfo.fundAmount + categoryInfo.remaining).toFixed(2);
} else {
fundAmountStr = categoryInfo.fundAmount.toFixed(2);
}
statusDiv.innerHTML += '<br>Fund: $' + fundAmountStr;
}
$.mobile.loading( 'hide' );
}
function setStatus(html){
document.getElementById('status').innerHTML = html;
}
function appendStatus(html){
setStatus(document.getElementById('status').innerHTML + '<br>' + html);
}
function sendLog(){
google.script.run.sendLog();
}
//</script>
<!DOCTYPE html>
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquerymobile/1.4.5/jquery.mobile.min.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jquerymobile/1.4.5/jquery.mobile.min.css">
<?!= include('javascript'); ?>
<div data-role="page" data-theme="a" id="main">
<div data-role="content">
<form id="myForm">
<div>Date</div>
<div><select name="date" id="date"></select></div>
<div>Category</div>
<div><select name=category id="category" onchange="categoryChanged()" required></select></div>
<div>Amount</div>
<div><input type="text" name="amount" id="amount" required></div>
<div>Note</div>
<div><input type="text" name="note" id="note"></div>
<div><input type="button" id="submit" value="Submit" onclick="submitForm()"/></div>
</form>
<!--<a href="#dialog" data-role="button" data-rel="dialog" data-transition="pop">Dialog</a>-->
</div><!-- /content -->
<div data-role="footer">
<div id="status"></div>
</div><!-- /footer -->
</div><!-- /page -->
<div data-role="page" id="dialog" data-close-btn="none">
<div data-role="header">
<h1 id="dialogHeading">Success!</h1>
</div>
<div data-role="main" class="ui-content" id="dialogMain">
<p>Text goes here.</p>
</div>
<div class="ui-grid-b">
<div class="ui-block-a"></div>
<div class="ui-block-b"><a href="#main" data-role="button" data-icon="check">OK</a></div>
<div class="ui-block-c"></div>
</div><!-- /grid-a -->
<!--><div data-role="footer"></div>-->
</div>
<script type="text/javascript">
$(loadUI);
</script>
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…