Issue injecting external script with executeScript method in Cordova - javascript

I'm writing a dummy app to test how works the executeScript() method inside Cordova's InAppBrowser plugin. In particular, I'm trying to inject a javascript code inside one webview.
Here there is my index.html file:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="format-detection" content="telephone=no" />
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
<link rel="stylesheet" type="text/css" href="css/style.css" />
<script type="text/javascript" src="phonegap.js"></script>
<script type="text/javascript" src="js/index.js"></script>
<title>InAppBrowser Injection Test</title>
</head>
<body>
<div class="app">
<h1>Testing Injection</h1>
<div id="deviceready" class="blink">
<p class="event listening">Starting Mother WebView</p>
<div class="event received">
<p>Device is Ready</p>
</div>
</div>
</div>
<script type="text/javascript">
app.initialize();
</script>
</body>
</html>
And the index.js file
var app = {
initialize: function() {
this.bindEvents();
},
bindEvents: function() {
document.addEventListener('deviceready', this.onDeviceReady, false);
},
onDeviceReady: function() {
app.receivedEvent('deviceready');
var ref = window.open('http://www.example.net', '_blank', 'location=yes ,toolbar=yes, EnableViewPortScale=yes');
ref.addEventListener('loadstart', function(event) { alert('start: ' + event.url); });
ref.addEventListener('loadstop', function() {
//ref.executeScript({ code: "alert('Injected Code')" });
ref.executeScript({ file: "externaljavascriptfile.js" });
showalert();
});
ref.addEventListener('loaderror', function(event) { alert('error: ' + event.message); });
ref.addEventListener('exit', function(event) { alert(event.type); });
},
receivedEvent: function(id) {
var parentElement = document.getElementById(id);
var listeningElement = parentElement.querySelector('.listening');
var receivedElement = parentElement.querySelector('.received');
listeningElement.setAttribute('style', 'display:none;');
receivedElement.setAttribute('style', 'display:block;');
console.log('Received Event: ' + id);
}
};
and last the externaljavascriptfile.js
alert('External Injected Code');
If I try to inject javascript code directly (i.e. uncommenting the line "ref.executeScript({ code: "alert('Injected Code')" });" ) all works fine and the alert is triggered after the page load, but if I try to inject an external javascript (i.e. using the line "ref.executeScript({ file: "externaljavascriptfile.js" });", nothing happens.
Am I missing something?

Actually, I think you already know the answer.
executeScript() method run in the child WebView.
ref.executeScript({ file: "externaljavascriptfile.js" });
In your code, executeScript() method is referenced http://www.example.net/externaljavascriptfile.js, not in your script file in /www/js cordova directory. Because executeScript() method injects JavaScript in childview as you know.
You can test the code with below. I've put the file in my website.
//...
onDeviceReady: function() {
var ref = window.open('http://www.haruair.com/', '_blank', 'location=yes, toolbar=yes, EnableViewPortScale=yes');
ref.addEventListener('loadstop', function() {
ref.executeScript({ file: "externaljavascriptfile.js" });
});
},
//...
FYI, if you need to get the data from childview, you can use callback.
//...
var ref = window.open('http://www.haruair.com/', '_blank', 'location=yes, toolbar=yes, EnableViewPortScale=yes');
ref.addEventListener( "loadstop", function() {
ref.executeScript(
{ file:'http://haruair.com/externaljavascriptfile.js' },
function() {
ref.executeScript(
{ code:'getSomething()' },
function(values){
var data = values[0];
alert(data.name);
});
}
);
});
//...
In externaljavascriptfile.js:
var getSomething = function(){
// do something and get the result from childview webpage
return { name : 'foo', age : 12 };
};

Use Ajax to get JS file data then inject it using execute script
$.ajax({
type: "GET",
url: cordova.file.applicationDirectory + "www/js/externalScript.js",
dataType: "text",
success: function (jsCode) {
ref.executeScript({code: jsCode}, function () {
console.log("Code Inserted Succesfully");
});
},
error: function () {
console.log("Ajax Error");
}
});
//ref is reference of inappbrowser
//i.e. var ref = window.open();
//url is url of your local javascript file
With this method you can add a script file which is located in the local APP's sandbox, and not around in the Internet.
Note, you need to cordova-plugin-file:
cordova plugin add cordova-plugin-file

Did you install the inappbrowser plugin?
I have this working in android as follows:
EDIT: Updated for cordova 7
Create the phonegap project
> cordova create JsExec
> cd JsExec
> cordova platform add android
> cordova plugin add cordova-plugin-inappbrowser
Update index.js -here is my onDeviceReady function:
onDeviceReady: function() {
this.receivedEvent('deviceready');
var w = window.open('http://www.example.net','_blank','location=yes');
w.addEventListener('loadstop', function(event) {
w.executeScript({file: "https://s3.amazonaws.com/avvi00/externaljavascriptfile.js"});
});
},
Deploy to my HTC
> cordova run --device
external script file is here
the full working copy of this project is here
regards,
Av

externaljavscriptfile.js is not linked in your html file.
You need to include it with the
<script type="text/javascript" src="path/externaljavascriptfile.js"></script>
tag or to load it dynamically with:
var script = document.createElement('script');
script.async = "async";
script.src = "path/externaljavascriptfile.js";
document.getElementsByTagName("head")[0].appendChild( script );
NOTE: you may need to put your code in a function to execute it.
Hope it works.

Related

Accessing Functions From Other JS Files - DOJO

Im trying to call a function from another js file that is located in the same application directory as my main js script and html file. I receive an error claiming that the referenced function does not exist. I have referenced both of the scripts in the main html file in the proper order but cant for the life of me figure out why it cannot detect the function. I can only assume it has something to do with how dojo parses through the files and have experimented with both its dojo/domReady! and dojo/ready modules in hopes to force scripts to load. I feel like this should be much simpler than Im making it out to be. Any help would be greatly appreciated.
html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Asset View</title>
<meta charset="utf-8">
<link rel="stylesheet" href="http://js.arcgis.com/3.14/dijit/themes/claro/claro.css">
<link rel="stylesheet" href="http://js.arcgis.com/3.14/esri/css/esri.css">
<link rel="stylesheet" href= "styles/styles.css">
<script src="http://js.arcgis.com/3.14/"></script>
<script src="scripts/requests-js.js"></script>
<script src="scripts/layout-js.js"></script>
<script src="scripts/xmain-js.js"></script>
</head>
<body class = "claro">
</body>
</html>
requests-js.js
require(["dojo/dom","dojo/on","dojo/request","dojo/json","dojo/parser","dojo/ready"
], function(dom,on,request,JSON,parser,ready) {
ready(function() {
console.log("request start");
function sendRequest (url,assetCode,fromDate,toDate) {
console.log("Request innit");
request(url,{
method: "POST",
handleAs: "json",
headers: {"Content-Type": "application/json"},
data: JSON.stringify(
[
{
"AssetCodes": assetCode,
"FromGasDay": fromDate,
"ToGasDate": toDate
}
]
)
}).then(function(resp){
console.log(JSON.stringify(resp));
var naStorageJSON = resp;
});
}
console.log("request end");
});
});
main-js.js
require([
"dojo/dom","dojo/on","dojo/parser","dojo/json","dojo/request","dojo/ready"
], function(dom,on,parser,JSON,request,ready) {
ready(function() {
console.log("Main Start");
var url = "http://*********";
var assetCode = ["**"];
var toDate = "****";
var fromDate ="*****";
on(dom.byId("senecaLakeBtn"),"click", sendRequest(url,assetCode,toDate,fromDate));
console.log("Main End");
});
});
The issue is scope here. By declaring an empty array at the top of the js script (outside of its successive functions) the function can be accessible to other scripts in the application.
var app = [];
require(["dojo/dom","dojo/on","dojo/request","dojo/json","dojo/parser","dojo/ready"
], function(dom,on,request,JSON,parser,ready) {
ready(function(){
app.sendRequest = function sendRequest (url,assetCode,fromDate,toDate) {
...
...
}
}
it can them be called upon from other scripts by referencing
app.sendRequest(arg1,arg2,arg3);

unable to call function in dojo module from another dojo module

I'm getting an Object doesn't support property or method error when I try to call a function in a dojo module. I have a main page and two modules. I call the first module from the main page and it works, I call the second module from the first and it works, but I get the error when I try to call the first module from the second. Here is my code:
main page:
<!DOCTYPE html>
<html >
<head>
<meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>
<link rel="stylesheet" href="http://js.arcgis.com/3.10/js/dojo/dijit/themes/claro/claro.css">
<link rel="stylesheet" href="http://js.arcgis.com/3.10/js/esri/css/esri.css">
<script>
var dojoConfig = {
parseOnLoad:true,
async: true,
isDebug:true,
packages: [
{name: "Scripts", location: location.pathname.replace(/\/[^/]+$/, "") + "/Scripts"},
]
};
</script>
<script> src="http://js.arcgis.com/3.10/"></script>
<script>
require(["Scripts/Mod1", "Scripts/Mod2"],
function (Mod1, Mod2) {
Mod1.M1Method("call from main page");//works great
});
</script>
</head>
<body class="claro">
<div>look here you</div>
</body>
</html>
Module 1:
define(["Scripts/Mod2"],
function (Mod2) {
return {
M1Method: function (msg) {
alert(msg);
Mod2.M2Method("call from Mod1");//works great
},
M1Method2: function (msg) {
alert(msg);
}
}
});
Module 2:
define(["Scripts/Mod1"],
function (Mod1) {
return {
M2Method: function (msg) {
alert(msg);
Mod1.M1Method2("call from Mod2"); //JavaScript runtime error: Object doesn't support property or method 'M1Method2'
}
}
});
How can I make that call from Mod 2 to Mod1?
Thanks
You are trying to do a cyclic dependency. In module 2, use a require statement. Try something like this:
define(["require"],
function (require) {
return {
M2Method: function (msg) {
alert(msg);
try {
require(["Scripts/Mod1"], function(Mod1) {
Mod1.M1Method2("call from Mod2");
});
} catch (dohObj) {
alert('Doh!, this failed. Stupid answer: ' + dohObj.message);
}
}
}
}
);
Your html code has a typo in that you enclosed the 'script' tag too soon when including dojo.js. Should be something like
<script type="text/javascript" src="http://js.arcgis.com/3.10/"></script>
You need to fix that file first to properly include dojo and 'require()'.

could not open db , $ is not defined, Failed to load jquery

The error is that the db could not be opened and $ not defined, failed to load resources(j query).The code aims at receiving the input field values(date,cal) and storing them into the database using indexedDB
<!DOCTYPE html>
<html manifest="manifest.webapp" lang="en">
<head>
<meta charset="utf-8">
<title>Diab</title>
<link rel="stylesheet" href="diab.css">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0/jquery.min.js"></script>
<script type="text/javascript" src="diab1.js"></script>
</head>
<body>
<input type="date" id="date">Date</input>
<input type="number" id="cal">Cal</input>
<button id="add" >Add</button>
</body>
</html>
(function()
{ var db;
var openDb=function()
{
var request=indexedDB.open("diabetore");
request.onsuccess = function()
{
console.log("DB created succcessfully");
db = request.result;
console.log("openDB done!!");
};
request.onerror=function(){
alert("could not open db");
};
request.onupgradeneeded = function()
{
console.log("openDB.onupgradeneeded function");
var store = db.createObjectStore("diab", {keyPath: "date"});
var dateIndex = store.createIndex("date", "date",{unique: true});
// Populate with initial data.
store.put({date: "june 1 2013",cal:70});
store.put({date: "june 2 2013",cal:71});
store.put({date: "june 3 2013",cal:72});
store.put({date: "june 8 2013",cal:73});
};
};
function getObjectStore(store_name,mode)
{
var tx=db.transaction(store_name,mode);
return tx.objectStore(store_name);
}
function addItems(date,cal)
{
console.log("addition to db started");
var obj={date:date,cal:cal};
var store=getObjectStore("diab",'readwrite');
var req;
try
{
req=store.add(obj);
}catch(e)
{
if(e.name=='DataCloneError')
alert("This engine doesn't know how to clone");
throw(e);
}
req.onsuccess=function(evt)
{
console.log("****Insertion in DB successful!!****");
};
req.onerror=function(evt)
{
console.log("Could not insert into DB");
};
}
function addEventListners()
{
console.log("addEventListeners called...");
$('#add').click(function(evt){
console.log("add...");
var date=$('#date').val();
var cal=$('#cal').val();
if(!date || !cal)
{
alert("required field missing..");
return;
}
addItems(date,cal);
});
}
openDb();
addEventListners();
})();
Regarding the problem of not being able to see the db created, when you open the database you should pass another parameter with the version of the database, like:
var request=indexedDB.open("diabetore",1);
To see the DB structure on the Resources tab of Chrome Developer Tools, sometimes you must refresh the page.
You will also have a problem with your addEventListners() function since your anonymous function is run before the browser reads the HTML content so the browser doesn't not know about the '#add' element, so the click event handler for that element is not created.
You should put your code inside "$(function() {" or "$(document).ready(function() {":
$(function() {
(function() {
var db;
var openDb=function() {
You should test the script URL in your browser. Then you'd realize that the script doesn't exist.
You need to change 2.0 to 2.0.0 for example.
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>

How to download external file using phonegap?

I am trying to download an apk file on a button click using phonegap. Why does this code not work? Nothing happens when I click Download. Could someone point me in the right direction? Thanks.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" href="css/index.css" />
<script charset="utf-8" src = "jquery-1.10.1.min.js"></script>
<script charset="utf-8" src = "cordova-2.7.0.js"></script>
<script>
function foo()
{
var fileTransfer = new FileTransfer();
fileTransfer.download(
"http://samplewebsite.com/example.apk",
"file:///sdcard/example.apk",
function(entry) {
console.log("download complete: " + entry.fullPath);
},
function(error) {
console.log("download error source " + error.source);
console.log("download error target " + error.target);
console.log("upload error code" + error.code);
}
);
}
</script>
</head>
<body>
<button onclick="foo()">Download</button>
</body>
</html>
var fileTransfer = new FileTransfer();
var uri = encodeURI(url);
var filePath= "/sdcard/directory/file.extension";
fileTransfer.download(uri,filePath,
function(entry) {
//success
},
function(error) {
//failed
}
);
This worked for me
Your code works fine.
This seems stupid but have you tried to use alert() instead of console.log() in the callbacks?
If you are sure the callback code is not invoked try to run just the app created by the phonegap' create script and check that the device is ready before doing other tests.
just my 2c

Javascript not working without an internet connection in IE9

I have published a website on a laptop with IIS 7.5 running IE9. When I have the internet plugged in the website works fine. The weird thing is that it will work fine in firefox weither the machine has internet or not.
Some other information that may be helpful.
Running Windows 7 64Bit. Latest version of firefox. IE9.
Not sure what else you may need. I have tried checking IE permissions but there may be something I have missed so any help will be appreciated.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>#ViewBag.Title</title>
<link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
<meta name="viewport" content="width=device-width" />
#*----------------- JQUERY UI for Accordion Starts here-------------------- *#
<link href="../../Content/themes/Blue/jquery-ui-1.9.1.custom.min.css" rel="stylesheet"
type="text/css" />
<script src="../../Scripts/jquery-1.8.2.js" type="text/javascript"></script>
<script src="../../Scripts/jquery-ui-1.9.1.custom.js" type="text/javascript"></script>
#* -----------JQUERY UI for Accordion Ends here--------------------- *# #*----------------- JQUERY UI for Delete Dialog Starts here-------------------- *#
<script src="../../Scripts/external/jquery.bgiframe-2.1.2.js" type="text/javascript"></script>
#* <script src="http://code.jquery.com/ui/1.9.1/jquery-ui.js"></script>*#
<script src="../../Scripts/external/jquery-ui.js">></script>
#*----------------- JQUERY UI for Delete Dialog Ends here-------------------- *#
#Styles.Render("~/Content/css")
#Scripts.Render("~/bundles/modernizr")
#*
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
*# #* ----------- Scripts added for Devexpress but commented because JQUERY UI not working --------------------- *#
#*
<script type="text/javascript" src="#Url.Content("~/Scripts/jquery-1.4.4.js")"></script>
<script type="text/javascript" src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")"></script>
*# #* ----------- Scripts added for Devexpress ends here--------------------- *#
#Html.DevExpress().GetScripts(
new Script { ExtensionSuite = ExtensionSuite.GridView },
new Script { ExtensionSuite = ExtensionSuite.PivotGrid },
new Script { ExtensionSuite = ExtensionSuite.HtmlEditor },
new Script { ExtensionSuite = ExtensionSuite.Editors },
new Script { ExtensionSuite = ExtensionSuite.NavigationAndLayout },
new Script { ExtensionSuite = ExtensionSuite.Chart },
new Script { ExtensionSuite = ExtensionSuite.Report }
//new Script { ExtensionSuite = ExtensionSuite.Scheduler }
)
#Html.DevExpress().GetStyleSheets(
new StyleSheet { ExtensionSuite = ExtensionSuite.GridView },
new StyleSheet { ExtensionSuite = ExtensionSuite.PivotGrid },
new StyleSheet { ExtensionSuite = ExtensionSuite.HtmlEditor },
new StyleSheet { ExtensionSuite = ExtensionSuite.Editors },
new StyleSheet { ExtensionSuite = ExtensionSuite.NavigationAndLayout },
new StyleSheet { ExtensionSuite = ExtensionSuite.Chart },
new StyleSheet { ExtensionSuite = ExtensionSuite.Report }
//new StyleSheet { ExtensionSuite = ExtensionSuite.Scheduler }
)
#* ---------------------------------JQUERY Scripts for Delete confirmation Starts here --------------------------------*#
<script type="text/javascript">
// increase the default animation speed to exaggerate the effect
$.fx.speeds._default = 500;
$(function () {
$("#dialog").dialog({
autoOpen: false,
show: "blind",
hide: "explode",
width: 250,
resizable: false,
modal: true,
buttons:
{
"Delete": function () {
$.post(deleteLinkObj[0].href, function (data) { //Post to action
//Check data the return from the middle layer, if it is just true, deletion is successful
if (data == '#Boolean.TrueString') {
deleteLinkObj.closest("tr").hide('fast'); //Hide Row
$("#dialog").dialog("close"); //See it used #dialog instead of (this) because the scope (context) has changed in the "Delete" callback
$(this).empty();
$("#StatusMsg").html("Deleted");
location.reload(); //refreshes the page
}
else {
//Show the errror on the dialog content. Data is used to show the error
//expecting the Error handlers in middle layer will return the meaning ful error message
$("#dialog").html(data);
//Hide confirmation button inorder to show the user to only the content of error in the same
//dialog box and allow to cancel this dialog
$(":button:contains('Delete')").css("display", "none");
$("#StatusMsg").html("Not Deleted");
}
//location.reload();
});
},
"Cancel": function () {
//This reset of the Delete button is need since if it wsas invoked and jumped into show error routine,
// then that routine would have removed the Delete button.
$(":button:contains('Delete')").css("display", "inline");
$(this).dialog("close");
$("#StatusMsg").html("");
}
}
});
var deleteLinkObj;
var deletMsg;
$('a.inputFakeDelete').click(function () {
//Here the message is built using the delete button properties id and name.
//So every page calling this jquery need to have the link button embedded with these properties
//eg: id = Grade, name = the name of the grade from the model
deletMsg = "Are you sure you want to delete this " + this.id;
if (this.name == "") {
}
else {
deletMsg = deletMsg + " '" + this.name + "'" //"Are you sure you want to delete the " + (this).id + " '" + (this).name + "'?";
}
deletMsg = deletMsg + "?"
$("#dialog").html(deletMsg)
deleteLinkObj = $(this); //to use in the dialog javascript
$("#dialog").dialog("open");
return false;
});
});
</script>
#*----------------------------------JQUERY Scripts delete confirmation Ends here --------------------------------*#
#*----------------------------------JQUERY Scripts for record cuirrent filer --------------------------------*#
<script type="text/javascript">
var currentValue = 0;
function handleClick(currentfilter) {
//alert('Old value: ' + currentValue);
//alert('New value: ' + currentfilter.value);
currentValue = currentfilter.value;
//Redirect the page so that will reload with new parameters
window.location = 'http://' + window.location.host + currentValue; //Add 'http://' since host will not include this
}
</script>
#*----------------------------------JQUERY Scripts for record cuirrent filer ends here --------------------------------*#
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
The error page just says that it cannot find a specific webpage. Customer/Delete
I am not sure if this is was the fix for my problem (and it is a little hard to test as the machine is not my own) but later on we reconfigured .net by using aspnet_regiis.exe and the problem looks like it has disapeared.

Categories

Resources