Trouble using Titanium's webview to fire an API event - webview

I'm trying to fire an event from an external HTML page opened inside of Titanium's webview.
app.js file...
var group, now, tab, view, window;
now = new Date();
view = Titanium.UI.createWebView({url: 'http://MYWEBSITE.com/index.htm?time=' + now.getTime()});
window = Titanium.UI.createWindow({tabBarHidden: true, navBarHidden: true});
window.add(view);
Titanium.App.addEventListener('browse', function(e) {
Ti.API.info("I received " + e.something + " from the webview.");
});
group = Titanium.UI.createTabGroup();
tab = Titanium.UI.createTab({title: 'window', window: window});
group.addTab(tab);
group.open(tab);
js excerpt from web page...
$("#testButton").mousedown(function() {
alert ("I got clicked.");
Ti.App.fireEvent('browse', {something:'stuff'});
});
(I include the time in the URL to ensure the page is always fresh.)
Adding the event listener as shown above, or using view.addEventListener, compiles but ultimately doesn't work.
Using Titanium.UI.WebView.addEventListener produces an error message that the object doesn't exist.
Do I need to open the URL/webview in a different manner?
Also, since Titanium.App.fireEvent is not a recognized function, except to Titanium, how does one prevent a JavaScript error?
Thanks.

// from web page
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<div id='testButton'>TEST BUTTON</div>
</body>
<script>
var _button = document.getElementById ("testButton");
_button.onmousedown = function () {
alert (this.id);
Ti.App.fireEvent('fromwebview', {name:this.id});
return false;
};
</script>
</html>
from apps.js
Ti.App.addEventListener('fromwebview', function(data)
{
Titanium.API.info("--> " + data.name);
});

Just to warn you all - I don't think this works with remote pages anymore for security reasons. Spent ages trying fruitlessly!

You can make this work on your remote html page by including the Titanium Injection code. For sdk 1.8.3 it's the following. Now your remote html page can talk to the device.
var Ti = {_event_listeners:[],createEventListener:function(listener ){ var newListener={ listener:listener ,systemId:-1 ,index:this._event_listeners.length };this._event_listeners.push(newListener);return newListener;},getEventListenerByKey:function(key,arg){for(var i=0;i<this._event_listeners.length;i++){if(this._event_listeners[i][key]==arg){return this._event_listeners[i];}} return null;},API:TiAPI,App:{addEventListener:function(eventName,listener) {var newListener=Ti.createEventListener(listener);newListener.systemId=TiApp.addEventListener(eventName,newListener.index);return newListener.systemId;},removeEventListener:function(eventName,listener) {if(typeof listener=='number'){TiApp.removeEventListener(eventName,listener);var l=Ti.getEventListenerByKey('systemId',listener);if(l!==null){Ti._event_listeners.splice(l.index,1);}}else{l=Ti.getEventListenerByKey('listener',listener);if(l!==null){TiApp.removeEventListener(eventName,l.systemId);Ti._event_listeners.splice(l.index,1);}}},fireEvent:function(eventName,data) {TiApp.fireEvent(eventName,JSON.stringify(data));}},executeListener:function(id,data) {var listener=this.getEventListenerByKey('index',id);if(listener!==null){listener.listener.call(listener.listener,data);}}};var Titanium=Ti;

Related

Alert when code is running background in google sheet

Working with Google App script and Javascript, I managed to retrieve xls Gmail attachments, convert it to google sheets, send an warning email to some recipients, insert an event with the Google Drive folder link when a new attachment is added to it, and at the end I managed with a standalone script to import some of the data coming from such xls file converted to a main Google Sheet where one operator is working h24 ( updating some data to be forwarded later on and during the service itself).
The standalone script run every 30 minutes to check incoming mail ( the schedule for the next day or days), and when it find it, it execute the code.
The lock service is not available on standalone scripts up to now, so I cannot lock the document, so I wish to display a message to the user that the script is about to run and not edit anything, since other scripts bounded to the Spreadsheet are using the Lock service, and so the result could be quite disappointing. I searched info regarding this "alert", but I cannot find a clue about it.
Could you address me somewhere?
I could add a menu function instead of a standalone script, and the operator could select "Import data" and that's it, but I wish to automate the operation in background.
You could use the HTML Service. I don't know much about it myself but I think the following may do what you need:
At the top of you .gs file:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var htmlApp = HtmlService.createTemplateFromFile("html");
var status = "Loading....."
htmlApp.data = status;
ss.show(htmlApp.evaluate()
.setWidth(300)
.setHeight(200));
At the end (just before the last brace):
var status = "Finished!"
htmlApp.data = status;
ss.show(htmlApp.evaluate()
.setWidth(300)
.setHeight(200));
In a new HTML script file named 'html':
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<h2>Updating..</h2>
<p id="status">(innerHTML).</p>
<div id="imageico"></div>
<script>
var imageContainer = document.getElementById("imageico");
if (<?= data ?> != "Finished!"){
document.getElementById("status").innerHTML = "Running script, please wait..";
} else {
document.getElementById("status").innerHTML = "Finished! You can now close the window.";
closeBtn();
}
function closeBtn(){
var button = document.createElement("INPUT");
button.setAttribute("type", "button");
button.setAttribute("value", "Close");
button.setAttribute("onclick", "closeWindow();");
imageContainer.appendChild(button);
}
function closeWindow(){
google.script.host.close();
}
</script>
</body>
</html>
EDITED Based on comments
In your .gs file:
function test() {
htmlApp("","");
/*
*
* Put your code in here....
*
*/
Utilities.sleep(3000); // change this value to show the "Running script, please wait.." HTML window for longer time.
htmlApp("Finished!","");
Utilities.sleep(3000); // change this value to show the "Finished! This window will close automatically. HTML window for longer time.
htmlApp("","close"); // Automatically closes the HTML window.
}
function htmlApp (status,close) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var htmlApp = HtmlService.createTemplateFromFile("html");
htmlApp.data = status;
htmlApp.close = close;
ss.show(htmlApp.evaluate()
.setWidth(300)
.setHeight(200));
}
In the HTML script file named 'html':
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<h2>Updating..</h2>
<p id="status">(innerHTML).</p>
<div id="imageico"></div>
<script>
var imageContainer = document.getElementById("imageico");
if (<?= data ?> != "Finished!"){
document.getElementById("status").innerHTML = "Running script, please wait..";
} else {
document.getElementById("status").innerHTML = "Finished! This window will close automatically.";
}
if (<?= close ?> == "close"){
google.script.host.close();
}
</script>
</body>
</html>
Have a look at this Sample Spreadsheet.
I don't see any methods or sample scripts regarding your concern. But this documentation about alert might help. It will open a dialog box in the user's editor with the given message and an "OK" button. However, this method suspends the server-side script while the dialog is open and the script will resume after the user dismisses the dialog.
You may also execute alert dialogs before running your script.
function onOpen() {
SpreadsheetApp.getUi() // Or DocumentApp or FormApp.
.createMenu('Custom Menu')
.addItem('Show alert', 'showAlert')
.addToUi();
}
function showAlert() {
var ui = SpreadsheetApp.getUi(); // Same variations.
var result = ui.alert(
'Please confirm',
'Are you sure you want to continue?',
ui.ButtonSet.YES_NO);
// Process the user's response.
if (result == ui.Button.YES) {
// User clicked "Yes".
ui.alert('Confirmation received.');
} else {
// User clicked "No" or X in the title bar.
ui.alert('Permission denied.');
}
}

get content of webview in nativescript

Is there a way I can read the content of webview after the page is loaded ?
The reason is redirect (like window.location.replace or window.location.href ) is not working in IOS in my case, works fine in Android.
https://docs.nativescript.org/cookbook/ui/web-view
I can access url, error. but how to access content ?
Narayan
I was only looking for IOS. I found the answer and sharing it here. For Android I would like to point some leads.
if (webView.ios) {
var webHeader = webView.ios.stringByEvaluatingJavaScriptFromString("document.head.innerHTML").trim();
console.log(webHeader);
var webBody = webView.ios.stringByEvaluatingJavaScriptFromString("document.body.innerHTML").trim();
console.log(webBody);
} else if (webView.android) {
webTitle = webView.android.getTitle(); //getting the title title
console.log(webTitle)
}
Some stack overflow lead for Android
You could look at this post. installs a library that allows communication with the webview through observables. Right now I'm using it myself and it's great for both iOS and Android
1- install:
tns plugin add nativescript-webview-interface
2- in web project copy plugin file
cp node_modules/nativescript-webview-interface/www/nativescript-webview-interface.js app/www/lib/
3- code:
xml:
<Page xmlns="http://schemas.nativescript.org/tns.xsd"
loaded="pageLoaded">
<web-view id="webView"></web-view>
</Page>
var webViewInterfaceModule = require('nativescript-webview-
interface');
var oWebViewInterface;
function pageLoaded(args){
page = args.object;
setupWebViewInterface(page)
}
function setupWebViewInterface(page){
var webView = page.getViewById('webView');
oWebViewInterface = new
webViewInterfaceModule.WebViewInterface(webView, '~/www/index.html');
}
function handleEventFromWebView(){
oWebViewInterface.on('anyEvent', function(eventData){
// perform action on event
});
}
function emitEventToWebView(){
oWebViewInterface.emit('anyEvent', eventData);
}
function callJSFunction(){
oWebViewInterface.callJSFunction('functionName', args, function(result){
});
}
web-view:
<html>
<head></head>
<body>
<script src="path/to/nativescript-webview-interface.js"></script>
<script src="path/to/your-custom-script.js"></script>
</body>
web-view js:
var oWebViewInterface = window.nsWebViewInterface;
// register listener for any event from native app
oWebViewInterface.on('anyEvent', function(eventData){
});
// emit event to native app
oWebViewInterface.emit('anyEvent', eventData);
// function which can be called by native app
window.functionCalledByNative = function(arg1, arg2){
// do any processing
return dataOrPromise;
}
More Info:
https://www.npmjs.com/package/nativescript-webview-interface
http://shripalsoni.com/blog/nativescript-webview-native-bi-directional-communication/
This will work for IOS
if (webview.ios){
url = args.url;
}

Adding filetransfer in PhoneGap breaks build

I'm trying to upload a video to a server in PhoneGap. The code is running in terms of opening the camera dialog and recording the video, but then the JS in the index.html file requires use of the FileTransfer plugin.
Adding this plugin from the phonegap command line results in the following error...
/platforms/ios/ManUtd/Plugins/org.apache.cordova.file-transfer/CDVFileTransfer.m:23:9: 'CDVLocalFilesystem.h' file not found
The html file is the documented code from the PhoneGap website
<!DOCTYPE html>
<html>
<head>
<title>Capture Video</title>
<script type="text/javascript" charset="utf-8" src="cordova.js"></script>
<script type="text/javascript" charset="utf-8">
// Called when capture operation is finished
//
function captureSuccess(mediaFiles) {
var i, len;
for (i = 0, len = mediaFiles.length; i < len; i += 1) {
uploadFile(mediaFiles[i]);
}
}
// Called if something bad happens.
//
function captureError(error) {
var msg = 'An error occurred during capture: ' + error.code;
navigator.notification.alert(msg, null, 'Uh oh!');
}
// A button will call this function
//
function captureVideo() {
// Launch device video recording application,
// allowing user to capture up to 2 video clips
navigator.device.capture.captureVideo(captureSuccess, captureError, {limit: 2});
}
// Upload files to server
function uploadFile(mediaFile) {
var ft = new FileTransfer(),
path = mediaFile.fullPath,
name = mediaFile.name;
ft.upload(path,
"http://my.domain.com/upload.php",
function(result) {
console.log('Upload success: ' + result.responseCode);
console.log(result.bytesSent + ' bytes sent');
},
function(error) {
console.log('Error uploading file ' + path + ': ' + error.code);
},
{ fileName: name });
}
</script>
</head>
<body>
<button onclick="captureVideo();">Capture Video</button> <br>
</body>
</html>
I have run both these commands and both result in the code breaking
$ phonegap local plugin add https://git-wip-us.apache.org/repos/asf/cordova-plugin-file.git
$ phonegap local plugin add https://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer.git
I am targeting iOS only at the moment
This appears to be related to the whole PhoneGap/Cordova thing.
Creating a new project using Cordova instead of PhoneGap, has sorted the problem. It appears as if the FileTransfer API is broken if you start an app using PhoneGap.

What would unhook my View and Controller from each other in Chrome and IE but not in Firefox?

I have previously successfully tested this MVC functionality in my app in Chrome but have recenlty also tested in IE (10) and Firefox.
When I mash the submit button on a page which sends model values to its controller for running a query and generating a report, it now works only in Firefox (each of the three browser indeed have their own peculiar characteristics -- where they shine or "dull" in relation to their cohorts (gleaming in purple and gold) -- but Chrome and Firefox seem to have lost the connection between the submit button's click handler and the corresponding Controller's method.
The app seems to simply hang after mashing the submit button in Chrome and IE; the breakpoints I have -- the first of which is at the very beginning of the corresponding [HttpPost] ActionResult in the Controller class -- are not reached. In fact, the app seems to freeze after mashing the button -- right-clicking the submit button after that does not give me an "inspect that element" in the context menu.
[HttpPost]
public ActionResult ReceiptCriteria(SalesReceiptCriteriaModel model)
{
if (ModelState.IsValid) // <-- there is a breakpoint here; only Firefox reaches it
{
. . .
In Firefox, it runs, and the breakpoints are hit.
What could possibly cause Chrome and IE to fail in this way, wheras Firefox soldiers on?
UPDATE
In response to Moby's request, here is the jQuery for the View in question:
The HTML in the View is pretty generic; the jQuery is:
$("#submit_button").click(function() {
// http://stackoverflow.com/questions/18192288/how-can-i-compare-date-time-values-using-the-jqueryui-datepicker-and-html5-time
var begD = $.datepicker.parseDate('mm/dd/yy', $('#BeginDate').val());
var endD = $.datepicker.parseDate('mm/dd/yy', $('#EndDate').val());
if (begD > endD) {
alert('Begin date must be before End date');
$('#BeginDate').focus();
return false;
}
else if (begD.toString() == endD.toString()) {
var dteString = begD.getFullYear() + "/" + (begD.getMonth() + 1) + "/" + begD.getDate();
var begT = new Date(dteString + " " + $('#BeginTime').val());
var endT = new Date(dteString + " " + $('#EndTime').val());
if (begT > endT) {
alert('Begin date must be before End date');
$('#BeginTime').focus();
return false;
}
}
$("#NumberOfResults").css("visibility", "visible");
$("#NumberOfResults").html("Please wait...");
EnableButton("submit_button", false);
// If all are selected, don't enumerate them; just set it at "All" (change of case, from 'all' to 'All', shows that the logic did execute)
var deptsList = $('#depts').checkedBoxes();
if (deptsList.length < deptsArray.length) {
$('#deptHeader span').html(deptsList.join(", "));
}
else if (deptsList.length == deptsArray.length) {
$('#deptHeader span').html("All");
}
// " "
var sitesList = $('#sites').checkedBoxes();
$('#sitesHeader span').html(sitesList.join(", "));
if (sitesList.length < sitesArray.length) {
$('#sitesHeader span').html(sitesList.join(", "));
}
else if (sitesList.length == sitesArray.length) {
$('#sitesHeader span').html("All");
}
$('#hiddenDepts').val(deptsList);
$('#hiddenSites').val(sitesList);
var UPCs = $('#UPC').val();
if (UPCs == "All") {
$('#UPC').val("1"); // take everything (1 and greater)
}
var resultsText = jQuery.trim($("#spanNumberOfResults").text());
if (resultsText != "") {
$("#NumberOfResults").css("visibility", "visible");
if (resultsText == "0") {
$("#NumberOfResults").css("color", "red");
} else {
var href = '/#ConfigurationManager.AppSettings["ThisApp"]/TLDCriteria/LoadReport';
var report_parms = {
GUID: "#Model.GUID",
SerialNumber: "#Model.SerialNumber",
ReportName: "#Model.ReportName"
};
window.open(href, "report_window", "resizable=1, width=850, left=" + (screen.width / 2 - 425));
}
}
}); // end of submit button click
function EnableButton(id, enable) {
if (enable) {
$("#" + id).removeAttr("disabled")
.removeClass("bottomButtonDisabled")
.removeClass("bottomButtonEnabled")
.addClass("bottomButtonEnabled");
} else {
$("#" + id).attr("disabled", "true")
.removeClass("bottomButtonDisabled")
.removeClass("bottomButtonEnabled")
.addClass("bottomButtonDisabled");
}
}
UPDATE 2
Something else which may or may not shed some light on this problem is my .js and .css references:
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.9.2/jquery-ui.min.js" type="text/javascript" defer > </script>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript" defer> </script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript" defer> </script>
<script src="#Url.Content("~/Scripts/jquery-migrate-1.2.0.min.js")" type="text/javascript"> </script>
<script src="#Url.Content("~/Scripts/anytime.compressed.js")" type="text/javascript"> </script>
<script src="#Url.Content("~/Scripts/dynamicCheckboxes.js")" type="text/javascript" > </script>
. . .
<link href="http://code.jquery.com/ui/1.9.2/themes/smoothness/jquery-ui.css" rel="stylesheet" type="text/css" />
<link href="#Url.Content("~/Content/dynamicCheckboxes.css")" rel="stylesheet" type="text/css" />
<link href="#Url.Content("~/Content/anytime.compressed.css")" rel="stylesheet" type="text/css" />
<!--[if lt IE 9]>
<script src="/Scripts/html5shiv.js"> </script>
<![endif]-->
UPDATE 3
The Network tab in the Chrome Developer Tools looks like the middle of Wyoming (a whole lot of nothing), with a msg about the bottom informing me "No requests captured. Reload the page to see detailed information on the network activity."
When I dutifully mashed F5, it showed all the .js and .css files accessed, and finally (at the top), the page I'm gawking at. Mashing the "View Report" causes no more activity in the tab, though. I do see the console.log() msg I placed at the end of the submit button click handler, though, to wit: "made it to the end of submit button click"
There is one err msg in the console, too, but this:
Failed to load resource: the server responded with a status of 400 (Bad Request) http://localhost/%3C%=%20System.Configuration.ConfigurationManager.AppSettings[%22ThisApp%22]%20%%3E/Content/Images/SSCSsprite.png
Would simply fail to load the resource, not wreak other mayhem, right?
UPDATE 4
Based on Simon Halsey's hint, I found that, on stepping though the jQuery in Chrome, it fails this test:
if (resultsText != "") {
...obviously it's not in Firefox, and I assume that it also fails in IE (I'll czech to be sure in both cases, and update this).
Later: It's "" in Firefox, too...and the first time through, it also failed-wouldn't continue on. Second time through, it got through, though...???
There is two options:
There is no request due to javascript error
Your request signature doesnt math controller method
A.
Browsers have different behaivior with some javascript functions. Thats one of the reasons why jQuery is so popular.
The most efficient way to find it is to debug javascript line by line in each browser.
Likely it is the reason.
B.
Also your javascript is quite exotic for me. I guess you are catching sumbit button click and modifying inputs values on a fly.
I would recommend to use $.post or $.ajax and preventDefault instead.
It would make your javascript more clear and simple.
C.
To analyze what requests are sent from your browser I would recommend to use fiddler.
http://fiddler2.com/

Phonegap and jquery mobile : a href -> Origin null is not allowed by Access-Control-Allow-Origin

Im trying to use jquery mobile with phonegap, in a multi-page document.
Tring to use basic href links within the document, gives the Origin null is not allowed by Access-Control-Allow-Origin error which is quite annoying.
This is because the index page is refered to via file:// rather than http:// which webkit interprets as origin null. Has anyone got jquery mobile and phonegap to work in a multi page environment? if so how can you do it? If you add rel=external to the href tags the links work, but of course all the transitions are lost.
Cant find any info on this specific problem on stack overflow or teh internetz.
<!DOCTYPE HTML>
<html>
<head>
<title>PhoneGap</title>
<script type="text/javascript" charset="utf-8" src="phonegap-1.2.0.js"></script>
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0/jquery.mobile-1.0.min.css" />
<script src="http://code.jquery.com/jquery-1.6.4.min.js"></script>
<script>
$(document).bind( "mobileinit", function(){
//alert("mobileinit fired");
$.support.cors = true;
$.mobile.allowCrossDomainPages = true;
});
</script>
<script src="http://code.jquery.com/mobile/1.0/jquery.mobile-1.0.min.js"></script>
<script type="text/javascript">
function onDeviceReady() {
navigator.network.isReachable("google.com", reachableCallback, {});
}
// Check network status
function reachableCallback(reachability) {
// There is no consistency on the format of reachability
var networkState = reachability.code || reachability;
var states = {};
states[NetworkStatus.NOT_REACHABLE] = 'No network connection';
states[NetworkStatus.REACHABLE_VIA_CARRIER_DATA_NETWORK] = 'Carrier data connection';
states[NetworkStatus.REACHABLE_VIA_WIFI_NETWORK] = 'WiFi connection';
if (networkState != 0) online = true;
}
var online = navigator.onLine || false;
$(document).ready(function() {
$(document).bind('deviceready', function(){
onDeviceReady()
})
// Your main code
})
//Now if you about to make an AJAX call to load up some dynamic data, you can easily check to see if you're online
if(online) {
} else {
}
</script>
</head>
<body>
<h1>Welcome to PhoneGap</h1>
Edit html
</body>
</html>
Here's the official documentation on how to do just what you are looking for...
Hope this helps!
Leon's comment is the correct answer - you need to add rel="external" to static links.
To Test
Download mongoose http server
copy mongoose_xxxxxxx.exe file to your assets/www
Now you can design your html pages for jquery mobile without Access-Control-Allow-Origin
I think you can find the solution here: http://view.jquerymobile.com/master/demos/faq/how-configure-phonegap-cordova.php
$.mobile.allowCrossDomainPages = true;
$.support.cors = true;
$.mobile.phonegapNavigationEnabled = true
Although I have not gotten it to work, I think that here are the solution.
if you are targeting app above JELLY_BEAN(API Level 16), here is what you can add to MainActivity class.
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
super.appView.getSettings().setAllowUniversalAccessFromFileURLs(true);
}
Which will allow null origin XHR requests.

Resources