Search WebView for Text

gobblegob

Member
Licensed User
Longtime User
Hi,

I have searched all the documents and tutorials but failed to find out the best way to search documents for a string.
eg if i have 2 html files and i want to search for a string, and if found return which html file it found it in. How would be the best way to do this?


Cheers Waz
 

gobblegob

Member
Licensed User
Longtime User
Thanks heaps Erel. I will give that method a go when I finish work. I am sorry for such noob questions I am still learning the basics. :)

PS I am having a lot of fun with basic4android.


cheers Waz
 
Upvote 0

nfordbscndrd

Well-Known Member
Licensed User
Longtime User
You can read the files with File.ReadString and then search for a string with String.IndexOf.
B4X:
Dim h1 as String
h1 = File.ReadString(...)
if h1.IndexOf("some text") > -1 then ...

I have a pretty long Help file which is displayed in a WebView. After I have searched for a string and found it, is there any simple way to cause WebView to display the section of the document with the text in it (before I resort to a non-simple way)?
 
Upvote 0

nfordbscndrd

Well-Known Member
Licensed User
Longtime User
When I search a local HTML file for text and when found, link back to the closest preceding anchor, I have three problems. One is that the target text is not highlighted, making it hard to find, and I can't figure any reasonable way of highlighting it in WebView.

Another problem is that the target text may not be close enough to the previous anchor to appear on the screen when I link to that anchor. This takes me back to my previous "dumb" idea of having to sprinkle anchors throughout the file every couple of paragraphs (and my actual help file is 100k, so that's a lot of sprinkling).

The most serious problem is that if the user searches again for the next occurrence of the same text and it falls under the same anchor as the prior search, the browser gives me an error saying that the page is "not available", even though it shows the correct URL and anchor name, as can be seen in the Logs. To simplify: I can just load the same URL with the same anchor name twice and get the error on the 2nd attempt. [Edit: This was done on a Toshiba Thrive running 3.1. I just tried it on an Archos 70 running 1.6 and it worked, but the first two problems stand. I would be interested in knowing if anyone else gets this 3rd problem.] [I think I worked around this problem by loading the file without the anchor before loading it with the anchor.]

NOTE: The attached Zip file is missing the test.htm file. The corrected Zip file is attached 3 posts down.
 

Attachments

  • WebViewSearchTest.zip
    5.9 KB · Views: 722
Last edited:
Upvote 0

warwound

Expert
Licensed User
Longtime User
Here's an idea...

You have already found an occurence of the searched for text in the local HTML file.

Can you insert an HTML <span> element around the text to display?

Original text: "This is my local HTML file"

Search for: "local"

Modified text: "This is my <span style="color:red">local</span> HTML file"

Now the span element should(!) have a javascript method scrollIntoView(), see the documentation here: https://developer.mozilla.org/en/DOM/element.scrollIntoView

So if you give the span element an id then you can call it's scrollIntoView() method.
Your modified HTML should now resemble this:

"This is my <span style="color:red" id="searchResult">local</span> HTML file"

That's easy to load into your WebView with the loadHtml() method - you just want to execute some javascript to bring the span element into view.

If you're prepared to add a javascript function to your local HTML file then add this function within the <head> section:

B4X:
<script type="text/javascript">
function initialise(){
 var span=document.getElementById('searchResult');
 if(typeof span!=='undefined'){
  span.scrollIntoView();
 }
}
</script>

Now modify your HTML file's <body> element:

B4X:
<body onload="initialise()">

If you don't want to add that javascript function and modify the <body> element you could try my JSInterface library and use it's execJS() method to execute the javascript in the WebView.

Once that's working you could look at improving it to handle multiple occurences of the searched for text.
You could wrap all occurences of the searched for text in a span element with a unique id:

Original text: "I searched for the search term 'search'"

Searched for: "search"

Modified text: "I <span style="color:red" id="searchResult1">search</span>ed for the <span style="color:red" id="searchResult2">search</span> term '<span style="color:red" id="searchResult3">search</span>'"

And a new javascript function:

B4X:
<script type="text/javascript">
function showSearchResult(index){
 var span=document.getElementById('searchResult'+index);
 if(typeof span!=='undefined'){
  span.scrollIntoView();
 }
}
</script>

Martin.

PS There is no 'test.htm' file in the project attached to your last post.
 
Upvote 0

warwound

Expert
Licensed User
Longtime User
javascript highlight words - Google Search

See that you could also perform the search entirely within the page using javascript.
The first link in that search looks promising and as a bonus the javascript function it uses will not modify HTML elements.
Something my previous post didn't consider - for example if a user searches for "body" then you will break your web page if you modify it.

From:
B4X:
<body>

To:
B4X:
<<span style="color:red" id="searchResult1">body</span>>

Look at the source code for this page: JavaScript Text Highlighting

Martin.
 
Upvote 0

nfordbscndrd

Well-Known Member
Licensed User
Longtime User
Thanks for your ideas.

When I said that I couldn't think of any "reasonable" way to highlight the text, the problem I had in mind was not adding code to highlight text once it is found, which is pretty straightforward, but the fact that the HTML file must be read in from DirAssets and then each time a search is done, it must be copied to a 2nd variable which must be searched and modified, and then saved to, say, DirInternal, PLUS any files it links to must be copied from DirAssets to DirInternal. For example, my 100k help file has about a dozen screen shots (in .png format) of about 50k each for about 600k total to be copied in addition to rewriting the 100k html file.

And this is a relatively simple file which is mostly text, and the HTML file and all the png files are in the app's Files folder. If someone wanted to display a page from the Web and search it, this might not even be possible.

Before I quit for the evening last night, I had already added code to check to see if each of these files is in DirInternal and if not, copy them over. I haven't run it to see how long this takes, which is what I'll be doing after this post.

Re: the missing test.htm file -- I forgot to add it in the Files tab. I've now done that and made a new Zip file, but when I tried to edit that post and "Go Advanced", I got an "Error on page" message, so I'm attaching it here.
 

Attachments

  • WebViewSearchTest.zip
    6.4 KB · Views: 504
Last edited:
Upvote 0

nfordbscndrd

Well-Known Member
Licensed User
Longtime User
Attached is the test app with the highlighting text feature. I also used it in my big app and it is much faster than I expected. Of course the files only have to be copied the first time a search is done, which helps, but I thought that writing the file for each search would slow things down, but it doesn't -- even my 100k file.

Instead of reading the HTML file in for each search, I could just store it in a global variable and copy it into a temporary variable to change up, but it's so fast as-is, I didn't bother.

The attached file is a simple example. For a more complex example, see the next post.
 

Attachments

  • WebViewSearchTest.zip
    6.8 KB · Views: 561
Last edited:
Upvote 0

nfordbscndrd

Well-Known Member
Licensed User
Longtime User
The example app attached to the previous message has been updated. Added is code to ignore matches found in a page's HTML code.

In order to make it more realistic, the actual HTML help file from CardShark Spades is being used. This file includes several screenshots which illustrate the bug in WebView discussed on this page in the Wiki and in the thread at the link above. Because of the screenshots, the zip file is now too large to attach, so download it from this link.
 
Upvote 0

awama

Active Member
Licensed User
Longtime User
The example app attached to the previous message has been updated. Added is code to ignore matches found in a page's HTML code.

In order to make it more realistic, the actual HTML help file from CardShark Spades is being used. This file includes several screenshots which illustrate the bug in WebView discussed on this page in the Wiki and in the thread at the link above. Because of the screenshots, the zip file is now too large to attach, so download it from this link.

Hi,

I tested your example but it works not yet perfectly. On bei galaxy s2 shows the first founded word in the topline, another founded words are only visible if I scroll up.

Walter
 
Upvote 0

nfordbscndrd

Well-Known Member
Licensed User
Longtime User
I tested your example but it works not yet perfectly. On bei galaxy s2 shows the first founded word in the topline, another founded words are only visible if I scroll up.

The code requires two versions of the HTML file, one with large pictures for tablets and one with small pictures for phones. When I was copying the files over from CardShark Spades, I missed getting the small HTML file. I've added it, tested it, and reuploaded it to the link in the previous post.

Even with this, the routine still will not work perfectly (as mentioned in the previous post) when there are pictures in the file due to a bug in WebView, as discussed in the links previously given.

The way the routine works is to embed an HTML anchor in a copy of the file where the target text is found, then load the copy of the file into WebView specifying that anchor. By all the laws of HTML, that is supposed to make the anchored text appear on screen, but as you can see, it doesn't always work and I haven't been able to figure out a foolproof work-around.
 
Upvote 0

nfordbscndrd

Well-Known Member
Licensed User
Longtime User
Look at my first post in this thread and my suggestion to use the javascript scrollIntoView() method:

https://developer.mozilla.org/en/DOM/element.scrollIntoView

I'm 99% sure it'll work flawlessly in the WebKit based WebView that we have in B4A.

It'll scroll any element into view - whether you use an anchor or span is up to you.

I was put off by the statement on the page linked above that "The element may not be scrolled completely to the top or bottom depending on the layout of other elements" which is the problem I'm already having. It looked like a lot of work to go through just to find out I was back at square 1, but if you are really 99% sure it will work, I'll give it another look.
 
Upvote 0

warwound

Expert
Licensed User
Longtime User
I suspect you'd only run into problems if your webpage contains elements that have CSS position styles such as absolute.

Such an element is removed from the normal rendering of the page (that is it's no longer part of the linear type layout of an HTML page) and rendered on it's own based on the CSS applied.

That might interfere with the browser's ability to successfully scroll a search result into view.

But looking at your page i see no CSS styles being used so don't think you'll have problems with scrollIntoView().

Martin.
 
Upvote 0

nfordbscndrd

Well-Known Member
Licensed User
Longtime User
To make a LONG story short, I spent a couple of hours trying a bunch of different things (with javascript scrollIntoView() method), but none of it worked, so I simplified the test code to just load the HTML file into WebView and it doesn't work on either of my tablets nor an emulator (though it works in IE8 in Windows).

The HTML page (almost) never moves. The odd thing is that a couple of times, it moved down just past where the target was so that I had to scroll up to see it, but that rarely happens. In fact, I compiled it to one tablet and it did that, then I compiled it to a 2nd tablet and it didn't, then compiled it to the 1st tablet again and it didn't. Then I tried it on an emulator and it didn't.

Here is a simplified version of the test code which just displays the file with the javascript in it: http://www.aeyec.com/SimpleSearch.zip
 
Last edited:
Upvote 0

warwound

Expert
Licensed User
Longtime User
Hi.

I really don't know why this isn't working.
I tried a few things with the code you last posted but as you say the B4A WebView just doesn't seem to actually scroll anything into view.

On my desktop computer the page scrolls fine when viewed with Firefox, IE9 and Safari.
The fact that the scrolling works with Safari led me to think it'd work in B4A as Safari like the B4A WebView is WebKit based - but in B4A it doesn't scroll.

Your webpage HTML doesn't validate - i wondered if this was stopping the scroll working so created a valid XHTML page with my own text.
My webpage validates and uses the same javascript as your page but again the span doesn't scroll into view.

Look at post #3 on this page: Issue 3883 - google-web-toolkit - scrollIntoView() misbehaves in standards mode (Webkit) - Google Web Toolkit (GWT) - Google Project Hosting.

1. The BODY's clientHeight in standards mode is (in the case of this example with absolutely
positioned content) less than the browser window's viewport height. In fact adding "HTML, BODY {
height: 100%; }" will allow the sample code to work correctly in standards mode.
2. The fact that in Webkit document scrolling is done via the BODY element (i.e.
bodyElement.scrollTop). In Firefox document scrolling is applied via the HTML element.

So i added some CSS style to your page and mine:

B4X:
<style type="text/css">
html, body {
   height:100%;
}
</style>

Scroll still doesn't work.

I added a meta tag (in the 'head' element) and tried that with no success too:

B4X:
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />

I tried with the WebView's ZoomEnabled set to True and False and that didn't work either.

I thought it might be a timing issue - the javascript is trying to scroll the span before the span is initialized.
So i made your btnSearchAgain Button visible and created a new Sub:

B4X:
Sub btnSearchAgain_Click
   Dim javascript As String
   javascript="initialise()"
   webInterface.execJS(viewHelp, javascript)
End Sub

Note i've added my JSInterface library to the code.
I recompiled the app, the webpage loads and fails to scroll.
I waited half a minute and clicked the button - still no scroll so it's not a timing issue.

Here's the code i'm working with:

B4X:
Sub Globals
   Dim viewHelp As WebView
   Dim webInterface As JSInterface
End Sub

Sub Activity_Create(FirstTime As Boolean)
   Activity.LoadLayout("SearchHelp")
   webInterface.addConsoleInterface(viewHelp)
   viewHelp.LoadUrl("file:///android_asset/martin.htm")
End Sub


Sub btnSearchAgain_Click
   Dim javascript As String
   javascript="initialise()"
   webInterface.execJS(viewHelp, javascript)
End Sub

And the webpage javascript:

B4X:
<script type="text/javascript">
function initialise(){
   console.log('initialise start');
   var span=document.getElementById('searchResult');
   if(typeof span!=='undefined'){
      console.log('span found');
      span.scrollIntoView();
      console.log(span.scrollIntoView);
   }
   console.log('initialise end');
}
</script>

And the log output:

B4X:
** Activity (main) Create, isFirst = true **


** Activity (main) Resume **


initialise start in file:///android_asset/martin.htm (Line: 14)


span found in file:///android_asset/martin.htm (Line: 17)


function scrollIntoView() {


    [native code]
} in file:///android_asset/martin.htm (Line: 19)
initialise end in file:///android_asset/martin.htm (Line: 21)

The javascript throws no errors, the initialise() function successfully runs and the span element is successfully found and it's scrollIntoView() method successfully executed.

Note how the javascript console.log(span.scrollIntoView); produces the log output:

B4X:
function scrollIntoView() {


    [native code]
} in file:///android_asset/martin.htm (Line: 19)

That indicates (as we already assumed!) that the the WebKit based WebView DOES support the scrollIntoView() method - as do all modern browsers - so the problem isn't there.

I'm not really sure what to suggest now - you've spent time trying to get scrollIntoView to work and there's no logical reason why it doesn't!

Martin.
 

Attachments

  • SimpleSearchUpdated.zip
    68.5 KB · Views: 667
Upvote 0

nfordbscndrd

Well-Known Member
Licensed User
Longtime User
Well, thanks for looking into it. I think we've established that there is a bug in WebView. Is there anyone in AndroidLand that we could report this to?

I don't think I mentioned this before, but my original search routine works flawlessly on my 10" tablet.
 
Last edited:
Upvote 0
Top