I am loading a HTML file file from server inside UIWebView. In HTML file, we have external links to open and a Javascript function is written to handle that events.I want to open that hyperlinks inside a seperate new webview within the app.
Is there any way that server side javascript method notify to objective-C or any callback function which will call in objective-C and then i can do someting in my code? i have seen the example of WEBViewJavaScriptBridge to communicate between javascript and objective C. but they are using the local HTML file to load and communicate.Bt my HTML file is on server side.It would be great if anyone can help on this.
I am puuting a sample HTML file here. We have two hypelinks "Open" and "Close" on taping on open button a function is called that show alert. so instead of alert i want to pass the retuen callback to objective-C code.
Here it is:-
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width = device-width, initial-scale = 1.0, maximum-scale = 1.0, minimum-scale = 1.0, user-scalable=no"/>
<meta name="HandheldFriendly" content="True"/>
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<title>Test HTML</title>
<script type="text/javascript">
function open(url, offset){
alert("Open Webview with url:"+ url + " & Offset: " + offset);
}
function close(url, offset){
alert("close webview");
}
</script>
</head>
<body>
Open<br>
Close
</body>
</html>
I used webviewjavascriptbridge to communicate javascript and objective C code.
In this example code, note the global variable of bridge.
<!doctype html>
<html><head>
<style type='text/css'>
html { font-family:Helvetica; color:#222; }
h1 { color:steelblue; font-size:24px; margin-top:24px; }
button { margin:0 3px 10px; font-size:12px; }
.logLine { border-bottom:1px solid #ccc; padding:4px 2px; font-family:courier; font-size:11px; }
</style>
</head><body>
<h1>WebViewJavascriptBridge Demo</h1>
<script>
window.onerror = function(err) {
alert('window.onerror: ' + err)
}
var bridge;
document.addEventListener('WebViewJavascriptBridgeReady', onBridgeReady, false)
function onBridgeReady(event){
alert("Onbridge ready call");
bridge = event.bridge
var uniqueId = 1
function log(message, data) {
var log = document.getElementById('log')
var el = document.createElement('div')
el.className = 'logLine'
el.innerHTML = uniqueId++ + '. ' + message + (data ? ': ' + JSON.stringify(data) : '')
if (log.children.length) { log.insertBefore(el, log.children[0]) }
else { log.appendChild(el) }
}
bridge.init(function(message) {
log('JS got a message', message)
})
bridge.registerHandler('open', function(data, response) {
log('JS handler testJavascriptHandler was called', data)
response.respondWith({ 'Javascript Says':'open open open!' })
})
bridge.registerHandler('testJavascriptHandler', function(data, response) {
log('JS handler testJavascriptHandler was called', data)
response.respondWith({ 'Javascript Says':'Right back atcha!' })
})
var button = document.getElementById('buttons').appendChild(document.createElement('button'))
button.innerHTML = 'Send message to ObjC'
button.ontouchstart = function(e) {
e.preventDefault()
bridge.send('Hello from JS button')
}
document.body.appendChild(document.createElement('br'))
var callbackButton = document.getElementById('buttons').appendChild(document.createElement('button'))
callbackButton.innerHTML = 'Fire testObjcCallback'
callbackButton.ontouchstart = function(e) {
e.preventDefault()
log("Calling handler testObjcCallback")
bridge.callHandler('testObjcCallback', {'foo': 'bar'}, function(response) {
log('Got response from testObjcCallback', response)
})
}
}
function open(url, offset,e)
{
alert(bridge);
//alert("Open Webview with url:Yes Got it");
// alert(document.getElementById(offset).href);
// var bridge = event.bridge;
// alert(bridge);
window.location = url+'?offset='+offset//'myapp:myaction:url:offset'
//requestFromObjc("buttonColor&someParam=1");
}
function close()
{
alert("Open Webview with url:"+ url + " & Offset: " + offset);
}
function requestFromObjc(functionName, objcResult, callback)
{
if (!objcResult)
{
window.location = 'myapp:myaction:param1:param2'
// window.location = "myapp://objcRequest?function=" + functionName + "&callback=" + arguments.callee.name + "&callbackFunc=" + arguments.callee.caller.name;
}
else
{
window[callback](objcResult);
}
}
</script>
<div id='buttons'></div> <div id='log'></div>
<body>
<a id="55" href="javascript:open('http://www.tcm.com', '55',this)">Open</a><br>
Close
</body>
</body></html>
Reference: https://github.com/marcuswestin/WebViewJavascriptBridge
You can communicate with your HTML from objective c with the following webView delagate methods...
- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
Please go through the usage of these methods...
I hope this may help you
Related
I have this html code (below), which works perfectly as a hosted file (meaning the code is working) -
<!DOCTYPE html>
<html>
<head>
<title>Read Text File</title>
<!--<script src="https://thunkable.github.io/webviewer-extension/thunkableWebviewerExtension.js" type="text/javascript"></script>-->
<script>
var ThunkableWebviewerExtension = (function () {
const postMessageToWebview = (message) => {
if (window.ReactNativeWebView) {
window.ReactNativeWebView.postMessage(message);
} else {
window.parent.postMessage(message, '*');
}
};
const getReceiveMessageCallback = (fxn, hasReturnValue) => (event) => {
if (typeof fxn === 'function') {
if (event.data) {
let dataObject;
try {
dataObject = JSON.parse(event.data);
} catch (e) {
// message is not valid json
}
if (dataObject && dataObject.type === 'ThunkablePostMessage' && hasReturnValue) {
fxn(dataObject.message, (returnValue) => {
const returnMessageObject = { type: 'ThunkablePostMessageReturnValue', uuid: dataObject.uuid, returnValue };
postMessageToWebview(JSON.stringify(returnMessageObject));
});
} else if (!hasReturnValue && (!dataObject || dataObject.type !== 'ThunkablePostMessage')) {
fxn(event.data);
}
}
}
};
return {
postMessage: postMessageToWebview,
receiveMessage: function(fxn) {
const callbackFunction = getReceiveMessageCallback(fxn, false);
document.addEventListener('message', callbackFunction, false);
window.addEventListener('message', callbackFunction, false);
},
receiveMessageWithReturnValue: function(fxn) {
const callbackFunction = getReceiveMessageCallback(fxn, true);
document.addEventListener('message', callbackFunction, false);
window.addEventListener('message', callbackFunction, false);
},
};
})();
</script>
</head>
<body>
<input type="file" name="inputfile" id="inputfile">
<br>
<pre id="output"></pre>
<script type="text/javascript">
document.getElementById('inputfile')
.addEventListener('change', function() {
var fr=new FileReader();
fr.onload=function(){
//document.getElementById('output').textContent=fr.result;
var msg = fr.result;
ThunkableWebviewerExtension.postMessage(msg);
}
fr.readAsText(this.files[0]);
})
</script>
</body>
</html>
What I want to do is, turn this whole code into a long URL, and I found that by using 'data:text/html,<meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"/>' at the start, then adding the code.
So the HTML url would become something like - 'data:text/html,<meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"/><!DOCTYPE html><html><head> ...'
I can see the file upload button, and even can select and upload a file. But, the script parts are not working - I am unable to catch the error here 😪
Kindly guide/advice me here... Thanks!
After experimenting a little bit, I think the problem might be that you haven't url-encoded it. Try using this instead of just pasting in the whole thing directly
(or copy it from here)
data:text/html,%3C!DOCTYPE%20html%3E%0A%3Chtml%3E%0A%3Chead%3E%0A%20%20%20%20%3Ctitle%3ERead%20Text%20File%3C/title%3E%0A%20%20%20%20%3C!--%3Cscript%20src=%22https://thunkable.github.io/webviewer-extension/thunkableWebviewerExtension.js%22%20type=%22text/javascript%22%3E%3C/script%3E--%3E%0A%20%20%20%20%3Cscript%3E%0A%20%20%20%20var%20ThunkableWebviewerExtension%20=%20(function%20()%20%7B%0A%20%20%20%20%20%20const%20postMessageToWebview%20=%20(message)%20=%3E%20%7B%0A%20%20%20%20%20%20%20%20if%20(window.ReactNativeWebView)%20%7B%0A%20%20%20%20%20%20%20%20%20%20window.ReactNativeWebView.postMessage(message);%0A%20%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20window.parent.postMessage(message,%20'*');%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%7D;%0A%20%20%20%20%0A%20%20%20%20%20%20const%20getReceiveMessageCallback%20=%20(fxn,%20hasReturnValue)%20=%3E%20(event)%20=%3E%20%7B%0A%20%20%20%20%20%20%20%20if%20(typeof%20fxn%20===%20'function')%20%7B%0A%20%20%20%20%20%20%20%20%20%20if%20(event.data)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20let%20dataObject;%0A%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20dataObject%20=%20JSON.parse(event.data);%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20//%20message%20is%20not%20valid%20json%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(dataObject%20&&%20dataObject.type%20===%20'ThunkablePostMessage'%20&&%20hasReturnValue)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20fxn(dataObject.message,%20(returnValue)%20=%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20const%20returnMessageObject%20=%20%7B%20type:%20'ThunkablePostMessageReturnValue',%20uuid:%20dataObject.uuid,%20returnValue%20%7D;%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20postMessageToWebview(JSON.stringify(returnMessageObject));%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D);%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20if%20(!hasReturnValue%20&&%20(!dataObject%20%7C%7C%20dataObject.type%20!==%20'ThunkablePostMessage'))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20fxn(event.data);%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%7D;%0A%20%20%20%20%0A%20%20%20%20%20%20return%20%7B%0A%20%20%20%20%20%20%20%20postMessage:%20postMessageToWebview,%0A%20%20%20%20%20%20%20%20receiveMessage:%20function(fxn)%20%7B%0A%20%20%20%20%20%20%20%20%20%20const%20callbackFunction%20=%20getReceiveMessageCallback(fxn,%20false);%0A%20%20%20%20%20%20%20%20%20%20document.addEventListener('message',%20callbackFunction,%20false);%0A%20%20%20%20%20%20%20%20%20%20window.addEventListener('message',%20callbackFunction,%20false);%0A%20%20%20%20%20%20%20%20%7D,%0A%20%20%20%20%20%20%20%20receiveMessageWithReturnValue:%20function(fxn)%20%7B%0A%20%20%20%20%20%20%20%20%20%20const%20callbackFunction%20=%20getReceiveMessageCallback(fxn,%20true);%0A%20%20%20%20%20%20%20%20%20%20document.addEventListener('message',%20callbackFunction,%20false);%0A%20%20%20%20%20%20%20%20%20%20window.addEventListener('message',%20callbackFunction,%20false);%0A%20%20%20%20%20%20%20%20%7D,%0A%20%20%20%20%20%20%7D;%0A%20%20%20%20%7D)();%0A%20%20%20%20%3C/script%3E%0A%3C/head%3E%0A%0A%3Cbody%3E%0A%20%20%20%20%3Cinput%20type=%22file%22%20name=%22inputfile%22%20id=%22inputfile%22%3E%0A%20%20%20%20%3Cbr%3E%0A%0A%20%20%20%20%3Cpre%20id=%22output%22%3E%3C/pre%3E%0A%20%20%20%20%0A%20%20%20%20%3Cscript%20type=%22text/javascript%22%3E%0A%20%20%20%20%20%20%20%20document.getElementById('inputfile')%0A%20%20%20%20%20%20%20%20%20%20%20%20.addEventListener('change',%20function()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20var%20fr=new%20FileReader();%0A%20%20%20%20%20%20%20%20%20%20%20%20fr.onload=function()%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20//document.getElementById('output').textContent=fr.result;%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20msg%20=%20fr.result;%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ThunkableWebviewerExtension.postMessage(msg);%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20fr.readAsText(this.files%5B0%5D);%0A%20%20%20%20%20%20%20%20%7D)%0A%20%20%20%20%3C/script%3E%0A%3C/body%3E%0A%3C/html%3E%0A
But I could be wrong -- I'm not very experienced with javascript
Json fetching has worked before in site for example here where i used the same processes - https://n-ce.github.io/Sea-arch
Here's the script
//FETCH
function content(a){
fetch(a+'.json').then(function (response) {
return response.json();
}).then(function (data) {
appendData(data);
}).catch(function (err) {
console.log('error: ' + err);
});
}
//Loading the objects
var root = document.getElementById('root');
function appendData(data) {
for (var i = 0; i < data.length; i++) {
var p = document.createElement("p");
p.innerHTML = data[i].Name;
root.appendChild(p);
}
}
// Remove Function
function remove(){
while (root.hasChildNodes()) {
root.removeChild(root.firstChild);
}
}
// Click decision making
var count = couns = 0;
function Sites() {
if(count%2==0){
content('Sites');
count++;
}
else{
count--;
remove();
}
}
function Animals() {
if (couns % 2 == 0) {
content('Animals');
couns++;
}
else {
couns--;
remove();
}
}
And this is the HTML
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JSON SD</title>
<link rel="stylesheet" href="style.css"/>
</head>
<body onload="content('Onload')">
<span>
<button onclick="Animals()">Load Animals</button>
<button onclick="Sites()">Load Sites</button>
</span>
<div id="root"></div>
<script src="script.js"></script>
</body>
</html>
There is no way for me to debug this given that the console doesnot throw any errors since its working fine in localhost.
Im fairly new to the Fetch API But
Im thinking maybe it is because the json files are being transferred are taking too long?
Can someone please highlight whats the issue?
Here's how it worked for github pages, thanks to #programmarRaj for highlighting
Script
//FETCH
function content(a){
fetch("./"+a+".json").then(function (response) {
return response.json();
}).then(function (data) {
appendData(data);
}).catch(function (err) {
console.log('error: ' + err);
});
}
Working with trying to learn json and ajax and how they interoperate with html and javascript
I have a php with json data inside
I am trying to get the json data formatted into the html page but I keep getting error that "callback is not a function"
I am running the php and html files on my MAMP server to simulate a api feed
I will share my html and js files
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="style.css" rel="stylesheet" type="text/css">
<script src="run2.js"></script>
<title>Ajax Demo</title>
</head>
<body>
<h1 class="title">Todays Weather Forecast</h1>
<p class="sub">Click the button the check the local weather.</p>
<button class="demo-centered" type="button" onclick="loadPhp()">Check Weather</button><br><br>
<p id="demo"></p>
</body>
</html>
var loadPhp = function(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'json';
xhr.onload = function () {
var status = xhr.status;
if (status == 200) {
callback(null, xhr.response);
} else {
callback(status);
}
};
xhr.send();
};
loadPhp('demo.php', function (err, data) {
if (err != null) {
alert('Something went wrong: ' + err);
} else {
for (var i = 0; i < data.length; i++) {
for (x in data[i]) {
console.log(data[i][x]);
}
}
}
});
PHP just in case
{"coord":{"lon":-116.8,"lat":33.03},"weather":[{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03d"}],"base":"stations","main":{"temp":293.73,"feels_like":289.89,"temp_min":289.26,"temp_max":295.93,"pressure":1016,"humidity":52},"visibility":16093,"wind":{"speed":5.7,"deg":260},"clouds":{"all":40},"dt":1589408840,"sys":{"type":1,"id":5686,"country":"US","sunrise":1589374130,"sunset":1589423903},"timezone":-25200,"id":5391832,"name":"San Diego County","cod":200}
You have to create a javascript function called callback to do what the you want the callback to do.
I am trying to display a particular webpage
https://www.emcsg.com/marketdata/priceinformation
but no matter what, my code only opens the home page of this website and not the link mentioned above. i tried the same code with many other websites, and it works fine. My code is as follows:
<html>
<head>
<title>NASA Meteorology </title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js" type="text/javascript"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script type="text/javascript" src="https://github.com/douglascrockford/JSON-js/raw/master/json2.js"></script>
<script>
$(function(){
function requestCrossDomain(site, callback) {
if (!site) {
alert('No site was passed.');
return false;
}
var yql = 'http://query.yahooapis.com/v1/public/yql?q=' + encodeURIComponent('select * from html where url="' + site + '"') + '&format=xml&callback=?';
$.getJSON(yql, cbFunc);
function cbFunc(data) {
if (data.results[0]) {
data = data.results[0].replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '');
window[callback](data);
} else throw new Error('Nothing returned from getJSON.');
}
}
$('#test').click(function(){
var url = 'https://www.emcsg.com/marketdata/priceinformation';
requestCrossDomain(url, 'someFunction');
});
});
function someFunction(results){
console.log(results);
$('#loadedContent').css("display","").html(results);
}
</script>
</head>
<body>
<button id="test">Submit</button>
<br><br>
<div id="result"></div>
<div id="loadedContent"></div>
</body>
</html>
where am i going wrong? Any suggestions or hel would be appreciated.. thanks
Change
&format=xml&callback=?
to
&format=json
And your $.getJSON will indeed get JSON
The result will be an object something like
{
"query": {
"count": 1,
"created": "2016-02-10T12:26:11Z",
"lang": "en-AU",
"results": {
"body": {
// removed for brevity
}
}
}
}
Try putting passing the params to ajax instead of attaching them to the url
var yql = 'http://query.yahooapis.com/v1/public/yql';
$.getJSON(yql,{q:'select * from html where url="' + site + '"',format:'json'},cbFunc);
function cbFunc(data) {
if (data.results[0]) {
data = data.results[0].replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '');
window[callback](data);
} else throw new Error('Nothing returned from getJSON.');
}
I have only ever loaded in a JS library in the head of an html doc like so
<head>
<script src="somelink.js" />
</head>
My question is, can I load this script from within a function and if so what would that look like?
function() {
src="somelink.js"
return somemethod.bla;
}
Would that work? Presumably not.
I have my reasons for wanting to do this but will leave them out of the question for now.
Is it possible to load in a library from within a function and if so what would that look like?
Try this :
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>load demo</title>
<style>
body {
font-size: 12px;
font-family: Arial;
}
</style>
<script src="https://code.jquery.com/jquery-1.10.2.js"></script>
</head>
<body>
<b>Successful Response (should be blank):</b>
<div id="success"></div>
<b>Error Response:</b>
<div id="error"></div>
<script>
$( "#success" ).load( "somelink.js", function( response, status, xhr ) {
if ( status == "error" ) {
var msg = "Sorry but there was an error: ";
$( "#error" ).html( msg + xhr.status + " " + xhr.statusText );
}
});
</script>
</body>
</html>
Here's how it's done in script.js. https://github.com/ded/script.js/
var el = doc.createElement("script"),
loaded = false;
el.onload = el.onreadystatechange = function () {
if ((el.readyState && el.readyState !== "complete" && el.readyState !== "loaded") || loaded) {
return false;
}
el.onload = el.onreadystatechange = null;
loaded = true;
// done!
};
el.async = true;
el.src = "script-to-load.js";
document.getElementsByTagName('head')[0].insertBefore(el, head.firstChild);
If you use the script.js library then you can load a script like this.
$script('script-to-load.js');