Hi.
1) Injecting a <script> tag means more than just trying to use excuteJavascript on the script text...
Here's the javascript you'll want to inject into the page - using executeJavascript:
var ch_client='cbanks',ch_width=320,ch_height=50,ch_type='mobile',ch_sid='LDS',script=document.createElement('script');
script.type='text/javascript';
script.src='http://scripts.chitika.net/eminimalls/amm.js';
document.getElementsByTagName('head')[0].appendChild(script);
See how it creates the variables that the ads script requires then dynamically creates the script tag required for the external javascript file?
That code can be reduced to a single line:
var ch_client='cbanks',ch_width=320,ch_height=50,ch_type='mobile',ch_sid='LDS',script=document.createElement('script');script.type='text/javascript';script.src='http://scripts.chitika.net/eminimalls/amm.js';document.getElementsByTagName('head')[0].appendChild(script);
And the B4A code:
Sub Globals
Dim ShowAds As Boolean
End Sub
Sub Activity_Create(FirstTime As Boolean)
ShowAds=True
End Sub
Sub WebView1_PageFinished (Url As String)
If ShowAds Then
WebViewExtras1.executeJavascript(WebView1, "var ch_client='cbanks',ch_width=320,ch_height=50,ch_type='mobile',ch_sid='LDS',script=document.createElement('script');script.type='text/javascript';script.src='http://scripts.chitika.net/eminimalls/amm.js';document.body.appendChild(script);")
Log("Ads code added to webpage")
End If
End Sub
The page loads then disappears leaving just the ad visible!
2) Use javascript to detect any key/value in the url and insert the ads code:
function getQueryObject(){
var query=location.search, args={};
query=query.length>0?query.substring(1):'';
var items=query.split('&'), item, name, value, i;
for(i=0; i<items.length; i++){
item=items[i].split('=');
name=decodeURIComponent(item[0]);
value=decodeURIComponent(item[1]);
args[name]=value;
}
return args;
}
// code to add the ads code based on the key/value ads=no
var query=getQueryObject();
if(!query.ads && query.ads!=='no'){
// insert the ads code
var ch_client='cbanks', ch_width=320, ch_height=50, ch_type='mobile', ch_sid='LDS', script=document.createElement('script');
script.type='text/javascript';
script.src='http://scripts.chitika.net/eminimalls/amm.js';
document.getElementsByTagName('head')[0].appendChild(script);
}
Adding that code to the javascript function which creates the 'highlight on click' listener has the same effect as option 1...
The webpage loads and if ads code is inserted the webpage disappears - the ad generally is visible.
The problem is that the ads script uses document.write to insert itself and ads in the webpage.
If document.write is used while the webpage is being rendered then it does just that - writes some tags or text into the webpage.
BUT if the webpage has already been rendered and then document.write is used the entire rendered page is replaced with whatever document.write writes.
So after the ads code has executed the webpage consists of just this - none of your original webpage remains:
<html>
<head>
<script type="text/javascript" src="http://mm.chitika.net/minimall?&cid=default&screenres=313x483&winsize=480x724&canvas=297x2376&frm=false&history=1&impsrc=amm-1.10.0&url=file%3A///android_asset/my_webpage2.htm&cb=183&loc=8%2C8&snip_title=Toggle%20highlight%20HTML%20element%20on%20click&output=simplejs&callback=ch_ad_render_search"></script>
<script type="text/javascript" src="http://mm.chitika.net/minimall?&w=320&h=50&client=cbanks&sid=LDS&cid=LDS&type=mobile&previous_format=undefinedxundefined&screenres=313x483&winsize=480x724&canvas=313x483&frm=false&history=1&impsrc=amm-1.10.0&url=file%3A///android_asset/my_webpage2.htm&cb=794&loc=8%2C8&snip_title=Toggle%20highlight%20HTML%20element%20on%20click&output=simplejs&callback=ch_ad_render_search"></script>
</head>
<body>
<div id="chitikaAdBeacon-183"></div>
<iframe id="ch_ad183" name="ch_ad183" width="0" height="0" frameborder="0" src="about:blank" marginwidth="0" marginheight="0" vspace="0" hspace="0" allowtransparency="true" scrolling="no"></iframe>
<script type="text/javascript" src="http://scripts.chitika.net/eminimalls/amm.js"></script>
<div id="chitikaAdBeacon-794"></div>
<div></div>
<iframe id="ch_ad794" name="ch_ad794" width="0" height="0" frameborder="0" src="about:blank" marginwidth="0" marginheight="0" vspace="0" hspace="0" allowtransparency="true" scrolling="no" style="display: none; "></iframe>
</body>
</html>
Getting nearer a solution i have updated the B4A code:
'Activity module
Sub Process_Globals
'These global variables will be declared once when the application starts.
'These variables can be accessed from all modules.
End Sub
Sub Globals
'These global variables will be redeclared each time the activity is created.
'These variables can only be accessed from this module.
Dim AdParam As String
Dim ModifiedWebPage, WebPageFilename As String
Dim UserPaid As Boolean
Dim WebView1 As WebView
Dim WebViewExtras1 As WebViewExtras
End Sub
Sub Activity_Create(FirstTime As Boolean)
ModifiedWebPage=""
UserPaid=True ' use this boolean to set whether or not ads should be displayed
WebPageFilename="my_webpage2.htm"
If UserPaid Then
AdParam="?ads=no"
Else
AdParam=""
End If
WebView1.Initialize("WebView1")
WebViewExtras1.addJavascriptInterface(WebView1, "B4A")
WebViewExtras1.addWebChromeClient(WebView1)
Activity.AddView(WebView1, 0, 0, 100%x, 100%y)
End Sub
Sub Activity_Resume
If File.Exists(File.DirInternalCache, WebPageFilename) Then
' GetText assumes the file is encoded using UTF8
' the cached webpage will contain no ad code and requires no 'ads' key/value
WebView1.LoadHtml(File.GetText(File.DirInternalCache, WebPageFilename))
File.Delete(File.DirInternalCache, WebPageFilename)
Log("Modified webpage loaded")
Else
WebView1.LoadUrl("file:///android_asset/"&WebPageFilename&AdParam)
Log("Original webpage loaded")
End If
End Sub
Sub Activity_Pause (UserClosed As Boolean)
If ModifiedWebPage="" Then
Log("The webpage contains no highlighted elements so there is no need to save it")
Else
Log("The webpage has been modified - cache it to the filesystem")
File.WriteString(File.DirInternalCache, WebPageFilename, ModifiedWebPage)
End If
End Sub
Sub SaveHtml(Html As String)
' this Sub is called only by the WebView1 click event listener
' Html will be either the entire modified webpage html or (if the webpage is NOT modified) an empty String
' Log(Html)
ModifiedWebPage=Html
End Sub
And the webpage code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Toggle highlight HTML element on click</title>
<style type="text/css">
.highlight{
background-color: black;
color: white;
}
</style>
<script type="text/javascript">
function createListener(){
// code to add the highlight on click event listener
document.addEventListener('click', function(event){
var element=event.target;
var tagName=element.tagName.toLowerCase();
// detect HTML tags that should NOT be highlighted
if(tagName!=='html' && tagName!=='body' && tagName!=='a'){
if(element.className===''){
element.className='highlight';
} else {
element.className='';
}
}
var modifiedElements=document.getElementsByClassName('highlight'), text;
if(modifiedElements.length>0){
// some elements have been highlighted so send the entire modofied page to a B4A Sub SaveHtml
text=document.documentElement.outerHTML;
} else {
// the page currently contains no highlighted elements send an empty string to the B4A Sub SaveHtml to indicate there is no need to save the page
text='';
}
B4A.CallSub('SaveHtml', true, text);
}, false);
}
</script>
</head>
<body onload="createListener()">
<p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed venenatis, leo et ornare tempor, est tellus suscipit mauris, et tincidunt lectus justo eu mauris. Vivamus sit amet est id lorem sodales semper. Integer odio nisi, aliquet in tincidunt vitae, auctor vel nisi. Phasellus lacinia velit eu ligula elementum commodo viverra sapien sodales. Duis tincidunt est arcu, ut facilisis arcu. Nullam pulvinar interdum aliquet. Suspendisse eleifend convallis lacinia. </p>
<p> Aenean sed mi justo, commodo imperdiet urna. Praesent adipiscing, nisl sit amet viverra tempor, arcu nisl imperdiet libero, ut vestibulum lorem nisl at erat. Aliquam tincidunt suscipit diam, sit amet blandit ligula ultricies eget. Suspendisse suscipit enim eget ante ultricies vel laoreet est commodo. Duis placerat sem id libero aliquam auctor. Vestibulum sed quam ipsum, ac volutpat ante. Cras fringilla elit in nunc lobortis bibendum varius dolor ultricies. Nullam est mi, bibendum vitae tempus vitae, aliquet non neque. Sed urna sapien, lobortis non molestie ac, gravida nec ligula. </p>
<script type="text/javascript">
function getQueryObject(){
var query=location.search, args={};
query=query.length>0?query.substring(1):'';
var items=query.split('&'), item, name, value, i;
for(i=0; i<items.length; i++){
item=items[i].split('=');
name=decodeURIComponent(item[0]);
value=decodeURIComponent(item[1]);
args[name]=value;
}
return args;
}
// code to add the ads code based on the key/value ads=no
var query=getQueryObject();
if(!query.ads || query.ads!=='no'){
// insert the ads code
query=null; // no longer need to keep a reference to this object
var ch_client='cbanks', ch_width=320, ch_height=50, ch_type='mobile', ch_sid='LDS';
document.write('<script type="text/javascript" src="http://scripts.chitika.net/eminimalls/amm.js"></sc'+'ript>');
console.log('ads code inserted');
} else {
console.log('ads code NOT inserted');
}
</script>
</body>
</html>
Now everything works as intended BUT on an orientation change, if a cached webpage is reloaded there is no way to send to add the
AdParam parameter so ads will always be displayed on orientation change.
There is no way to add the AdParam String to this line in B4A:
WebView1.LoadHtml(File.GetText(File.DirInternalCache, WebPageFilename))
In B4A we can use
file:///android_asset/filename in the WebView LoadUrl method but we cannot (i think but could be wrong) create a path using something like:
WebView1.LoadUrl(File.DirInternalCache&WebPageFilename&AdParam)
Another problem i thought of - what if a user of your free app upgrades and pays - any saved modified webpages WILL contained the ads code!
So i think we have the basics of working code to insert or not insert ads code and also highlight page elements and save modified pages - what you have to do now is think how best to (re)structure your application so these bits of code can be added without the problems i mentioned above.
Are you adding (a lot of) webpages to your application - lots of webpages in the android asset folder?
Saving a copy of each modified webpage is gonna start using a lot of memory.
You could save the modified webpages to external storage instead of the app's Internal or InternalCache folder.
This would then allow you to load modified webpages using the LoadUrl method and add the AdParam String - i think you can use something like file:///sd-ext/foldername/webpage.htm?ads=no but you'd have to check that that is valid.
But surely at some point you'll want to add so many webpages to your application assets that the APK size will get ridiculous?
Have you thought about using a database to store ALL pages?
A simple table with two columns: 'filename' and 'content' could be used.
When you create you app you could manually add some webpages to the database.
Add as many as you require but not that many that your APK is bloated.
When a webpage is modified just query the database and UPDATE the content for that webpage.
If a user requires a webpage that is not currently in the database you could use HttPClient (or HttpUtils if you want a ready made code module) to download the webpage from the internet.
Once downloaded you can INSERT it into the database and display it in the WebView.
Just looking at your other post where you say this app is basically a bookreader.
Could you create a database for each book - a single database containing all webpages for that book.
You could create you app with no database included and then offer the user a choice of books to download from the internet.
You'd need some webhosting but if you have that then your app is much more flexible.
Maybe the app could download more than one book - each book being either a database to itself or a database table to itself.
If you forget about the ads code and concentrate more on the webpages and storage of the webpages then once you have that working look at adding the ads code back to your new code.
Just some ideas - hope i haven't confused things too much.
Martin.