...

View Full Version : Interesting Problem - Maybe Needs a Javascript Guru Help?



frank5050
01-07-2012, 01:22 AM
Hello guys I am very much a novice with javascript, but I have a problem with which I think one of the JS gurus in here might be able to help with.

I have about 10,000 keywords on a single web page. There is a checkbox next to every keyword. Some of these keywords are 2 to 3 word phrases.

I can type a word in a browser like Firefox and highlight all the instances that a particular keyword is found. Unfortunately there is no firefox extension that would automatically check a box next to the highlighted/found keyword.

Instead of manually checking the checkbox next to every keyword highlighted in the browser here is what I would ideally like to accomplish (with the help of javascript).

- Have a text field on top of the page and be able to type in a word and hit submit
- if a word is found among the keywords/phrases on the page, then the checkbox next to that keyword/phrase is automatically checked.

All i need is the checkboxes checked for every instance the searched keyword is found. I don't care if the above procedure is used. If someone can suggest a better route i'm open for it.


I don't see why it wouldn't be possible with javascript code.
Any help would be greatly appreciated.

Old Pedant
01-07-2012, 01:40 AM
Not hard at all.



<html>
<head>
<script type="text/javascript">
function checkForWord( wordField )
{
var form = wordField.form;
var word = wordField.value.replace(/^\s+/,"").replace(/\s+$/,"").toLowerCase();

var inputs = form.getElementsByTagName("input");
for ( var e = 0; e < inputs.length; ++e )
{
var field = inputs[e];
if ( field.type == "checkbox" )
{
if ( field.value.toLowerCase().indexOf(word) >= 0 )
{
field.checked = true;
} else {
// OPTIONAL, if you do NOTwant to clear previously checked boxes, omit next line:
field.checked = false;
}
}
}
}
</script>
</head>
<body>
<form onsubmit="return false;">
Type a word: <input name="word" onchange="checkForWord(this);" />
<hr>
<label>
<input type="checkbox" name="keywords" value="An apple a day keeps the doctor at bay">
An apple a day keeps the doctor at bay
</label></br/>
<label>
<input type="checkbox" name="keywords" value="All work and no play makes Jack">
All work and no play makes Jack
</label></br/>
<label>
<input type="checkbox" name="keywords" value="When in the course of inhuman events...">
When in the course of inhuman events...
</label></br/>
</form>
</body>
</html>

If you wanted to avoid having the words both as part of the label and in the <input>'s value, that's not hard either.

frank5050
01-07-2012, 07:32 AM
Hi pedant. Thanks for the response. Let me get back with you after I implement your code on the page.

frank5050
01-08-2012, 02:51 AM
Works very well. Just as intended. Thanks a bunch for that.

The only enhancement I would like to request is in the search feature.

For example currently when I type the phrase 'blue widgets' in search, it will only identify/find the checkbox if the phrase 'blue widgets' exits in sequence. If I have a pre-existing keyword phrase 'blue cool widgets' and I search for 'blue widgets' it is unable to locate that even though blue and widgets both exist in my keyword phrase.

Could it be possible that if I search for a phrase with 2 or even 3 words in it, then it can find any keyword phrase on my page in which both/all words of phrase being searched exist?

I would very much appreciate if this solution can be found.

Thank you.

Old Pedant
01-08-2012, 10:27 PM
More simple stuff. But note that this solution will find the words in either order. (Indeed, try "blue widget" to see what I mean.)

Maybe it's time to try writing a little code yourself to only find the words in the given order?


<html>
<head>
<script type="text/javascript">
function checkForWord( wordField )
{
var form = wordField.form;
var words = wordField.value.replace(/^\s+/,"").replace(/\s+$/,"").toLowerCase().split(" ");

var inputs = form.getElementsByTagName("input");
for ( var e = 0; e < inputs.length; ++e )
{
var field = inputs[e];
if ( field.type == "checkbox" )
{
var fcnt = 0;
var cbtext = field.value.toLowerCase();
for ( var w = 0; w < words.length; ++w )
{
if ( cbtext.indexOf(words[w]) >= 0 )
{
++fcnt;
}
}
if ( fcnt == words.length )
{
field.checked = true;
} else {
// OPTIONAL, if you do NOTwant to clear previously checked boxes, omit next line:
field.checked = false;
}
}
}
}
</script>
</head>
<body>
<form onsubmit="return false;">
Type a word: <input name="word" onchange="checkForWord(this);" />
<hr>
<label>
<input type="checkbox" name="keywords" value="An apple a day keeps the doctor at bay">
An apple a day keeps the doctor at bay
</label></br/>
<label>
<input type="checkbox" name="keywords" value="All work and no play makes Jack">
All work and no play makes Jack
</label></br/>
<label>
<input type="checkbox" name="keywords" value="When in the course of inhuman events...">
When in the course of inhuman events...
</label></br/>
<label>
<input type="checkbox" name="keywords" value="blue cool widgets">
blue cool widgets
</label></br/>
<label>
<input type="checkbox" name="keywords" value="widgets can be blue">
widgets can be blue
</label></br/>
</form>
</body>
</html>

Philip M
01-09-2012, 10:20 AM
My understanding is that he wants to find the words or part-words which exist in any order, and even when separated by another (unspecified) word. wid blu blu wid

A small improvement (if just a space is entered all the boxes are checked)


function checkForWord( wordField ){
if (/^\s/.test(wordField.value)) {
alert ("Invalid entry starts with a space - please retype");
document.forms[0].word.value = "";
return false;
}

also perhaps advise if the word was not found:-


var found = false;
....
if ( fcnt == words.length ) {
field.checked = true;
found = true;
....

if (!found) {
alert ("The word " + wordField.value + " was not found");
}
document.forms[0].word.value = ""; // whether the word was found or not clear the input field ready for next search

}
</script>

Old Pedant
01-09-2012, 10:15 PM
Well, I did handle the "entry starts with space" problem:


var words = wordField.value.replace(/^\s+/,"").replace(/\s+$/,"").toLowerCase().split(" ");

The two replace calls there "trim" the input text.

But I didn't consider the case of nothing but a space entered.

This whole problem seems contrived and artificial. I can't think of a practical use for it. And I still don't know if a subsequent entry *should* clear the existing already-checked boxes.

Philip M
01-10-2012, 10:26 AM
A further improvement (strip leading and trailing spaces at the outset):-


function checkForWord( wordField ){
wordField.value = wordField.value.replace(/^\s+/,"").replace(/\s+$/,"");
if (wordField.value.length <1) {
alert ("Please type in a word");
return false;
}
var found = false;
var form = wordField.form;
var words = wordField.value.toLowerCase().split(" ");
......



I have to say that I do not agree that the problem is contrived. Surely it offers the user the possibility to select all the titles of books containing "widget" and/or "apple", and presumably place an order for them. Or perhaps show further information about them. But as so often the OP offers not much guidance and leaves us to guess what he really wants.

frank5050
01-10-2012, 06:21 PM
Well, Pedant and Philip, you both are master coders and I appreciate that very much. It's my privilege to have both of you working on this problem for me (I understand this is not much of a problem for you guys). Thanks again.

As it seems via initial testing that Old Pedant's second solution improves the search as desired. I will put his code to real test (which includes 15000 check boxes on one page), and then post the overall result. I have a feeling it will work out fine.

The issue of entering just the space in the form field isn't an issue really since I don't intend to do so.

Just for sake of clarity, In a nut-shell this is what I'm striving to do.

---------------------------------------------
I would like to be able to search for a single word or a phrase and as long as "all the words" of the phrase being searched are present next to a checkbox, then the box gets checked.
---------------------------------------------

I will post my findings after further testing.

Thanks a bunch for your dedication towards helping others.

Frank

Philip M
01-10-2012, 06:25 PM
15000 checkboxes on one page? :eek:
It will take the user a long time to scroll through that lot!

frank5050
01-10-2012, 06:32 PM
While I put this whole thing to some real testing (result of which I will post here), here's a tiny add-on I would like to request to the second script devised by Old Pedant (post #5).

If we could have a counter next to the input form field which displays the total count of all the keywords found for a particular search, I think that would make this script even more useful for us.

Thank you in advance.

frank5050
01-10-2012, 06:35 PM
15000 checkboxes on one page? :eek:
It will take the user a long time to scroll through that lot!

You are right, 15000 is a lot, hence the enormity of the problem for us. The good news is, I have already tried Old Pedant's first script for 15000 checkboxes and though it takes long for the page to load (and all the sluggishness that comes with a large webpage), believe or not, the script works fantastically.

So imagine the relief it is for us for this script to be able to handle tens of thousands of entries. We'd be truly sweating without it.

frank5050
01-10-2012, 06:40 PM
Any one of you master coders is more than welcome to make the enhancement of a counter (of matches found) next to the input field.

Thanks.

Philip M
01-10-2012, 06:51 PM
Any one of you master coders is more than welcome to make the enhancement of a counter (of matches found) next to the input field.

Thanks.

You ought to be able to make this simple enhancement yourself!


var counter= 0;
function checkForWord( wordField ){


if ( fcnt == words.length ) {
field.checked = true;
found = true;
counter ++;
document.getElementById("Counter").value = counter;
}


Type a word: <input name="word" onchange="checkForWord(this);" /> <input type = "text" id = "Counter">

The counter shows the cumulative total of matches from all the searches (say widget and apple). If you want another counter showing the number of matches on the last search it would be easy to add that. Yes? Hint - declare the second counter within the function

frank5050
01-10-2012, 07:10 PM
I am not clear on how to implement your code.

Do I put:

if ( fcnt == words.length ) {
field.checked = true;
found = true;
counter ++;
document.getElementById("Counter").value = counter;
}

inside the code created by Pedant?

Upon doing so, it doesn't seem to work. Also, I am just looking for a text counter, but seems like your code creates another input field?

As for the counter, what I'm looking for is, "when a word or phrase is typed into the text field (in Pedant's code), if there are matches found then the number of found matches for that particular search is displayed next to the input field"

Yes, I'm a noob with Javascript, but I'll try to learn more as time goes on.
Thanks

Philip M
01-10-2012, 07:57 PM
I indicated the code to be added in blue. The surrounding code indicates where to put the blue lines.

<input type = "text"> creates a textbox which can be used either for input or to display a result. I have made it readonly, i.e. you cannot enter a value in it from the keyboard, that is write to it.

Here is the final version of Old Pedant's code as modified/improved/enhanced by myself:-


<html>
<head>
<script type="text/javascript">

var counter = 0;

function checkForWord( wordField ) {

// uncomment the next line if you want the counter to return the matches of only the most recent search
// var counter = 0;

wordField.value = wordField.value.replace(/^\s+/,"").replace(/\s+$/,""); // strip leading and trailing spaces
if (wordField.value.length <1) {
alert ("Please type in a word");
return false;
}

var found = false;
var form = wordField.form;
var words = wordField.value.toLowerCase().split(" ");

var inputs = form.getElementsByTagName("input");
for ( var e = 0; e < inputs.length; ++e ) {
var field = inputs[e];
if ( field.type == "checkbox" ) {
var fcnt = 0;
var cbtext = field.value.toLowerCase();
for ( var w = 0; w < words.length; ++w ) {
if ( cbtext.indexOf(words[w]) >= 0 ) {
++fcnt;
}
}

if ( fcnt == words.length ) {
field.checked = true;
found = true;
counter ++;
document.getElementById("Counter").value = counter;
}
else {
// OPTIONAL - if you do NOT want to clear previously checked boxes, the next line should remain commented out:
//field.checked = false;
// if you DO want to clear previously checked boxes uncomment the above line
}
}

}

if (!found) {
alert ("The word(s) " + wordField.value + " was/were not found in the same phrase");
}

document.forms[0].word.value = ""; // clear the input field

}
</script>
</head>

<body>

<form onsubmit="return false;">
Type a word: <input name="word" onblur="checkForWord(this);" /> Matches found <input type = "text" id = "Counter" readonly>
<hr>
<label>
<input type="checkbox" name="keywords" value="An apple a day keeps the doctor at bay">
An apple a day keeps the doctor at bay
</label></br/>
<label>
<input type="checkbox" name="keywords" value="All work and no play makes Jack a dull boy">
All work and no play makes Jack a dull boy
</label></br/>
<label>
<input type="checkbox" name="keywords" value="When in the course of inhuman events...">
When in the course of inhuman events...
</label></br/>
<label>
<input type="checkbox" name="keywords" value="blue cool widgets">
blue cool widgets
</label></br/>
<label>
<input type="checkbox" name="keywords" value="widgets can be blue">
widgets can be blue
</label></br/>
</form>
</body>
</html>

As I say, you could very easily have two counters, one for the most recent search (say apple), and another for all the successful search matches (say apple and widget). Of course apple widget returns not found.

frank5050
01-11-2012, 01:12 AM
Hi Philip, the above code seems to have a bug or so. When I search for a string it gives the correct number of matches found, but doesn't seem to reset for the next search. The boxes stay checked from the previous search as well as the counter.

As for my needs, the aggregate of searches isn't necessary, all I'm interested in is the total matches in a given search and then for the check boxes to be unchecked from the previous search when a new search is conducted.

Old Pedant
01-11-2012, 01:43 AM
READ what the code says:


else {
// OPTIONAL - if you do NOT want to clear previously checked boxes, the next line should remain commented out:
// field.checked = false;
// if you DO want to clear previously checked boxes uncomment the above line
}

So just change

// field.checked = false;
to


field.checked = false;

frank5050
01-11-2012, 06:55 AM
In the code, on top there is another optional commenting out prior to this and I did just that one. Never even looked at the bottom.

After commenting out at both places, the script works as desired. After extensive testing and deployment on my project if there is any further refinements that come to mind and if I need your help for that I'll certainly post here.

There's all kinds of champions in this world, and then it's people like you and Phillip. In my books, you guys are the very special kind. What you guys do is some of the best service that can be rendered to mankind.

Best regards,
Frank

frank5050
01-11-2012, 07:44 AM
Now that I have started to do real time testing on my 15000 list of keywords, I think another small yet useful feature to add would be to give a background color to the matches found.

When going through a list of over 10,000 keywords on a single webpage (where found matches float by fast) sometimes there's only a few matches and a background color would make it easy to visually locate those few matches.

frank5050
01-11-2012, 08:00 AM
Here's another little thing that is important to amend as I am doing real time testing.

So I launch a search and there are matches found, and as soon as I click below the horizontal line <hr> on the web page, the searched keyword disappears from the form input field.

Practically, I think the searched keyword should be retained and should disappear only when the cursor is back in the input field for the next search, that is, when the user is ready for the next search.

Similar to the counter, leaving the searched entry in the input field before the next search is important because that way while the user scrolls down the web page and is working on the check boxes, he/she will never lose track of the keyword that they used to generate those checked boxes in the first place. The searched keyword(s) will always be in the input field for their reference, and once they click inside the input field again in order to search, then the previous entry should disappear.

This is particularly important when there is a large number of keywords on the web page and with lots of scrolling down on the page one can forget the original keyword they searched for.

Philip M
01-11-2012, 08:38 AM
Here's another little thing that is important to amend as I am doing real time testing.

So I launch a search and there are matches found, and as soon as I click below the horizontal line <hr> on the web page, the searched keyword disappears from the form input field.

Practically, I think the searched keyword should be retained and should disappear only when the cursor is back in the input field for the next search, that is, when the user is ready for the next search.

Similar to the counter, leaving the searched entry in the input field before the next search is important because that way while the user scrolls down the web page and is working on the check boxes, he/she will never lose track of the keyword that they used to generate those checked boxes in the first place. The searched keyword(s) will always be in the input field for their reference, and once they click inside the input field again in order to search, then the previous entry should disappear.

This is particularly important when there is a large number of keywords on the web page and with lots of scrolling down on the page one can forget the original keyword they searched for.

Frank - I do really think that you ought to read the code and make some slight effort to understand it.
My code does not contain a bug. :( Like Microsoft, my code has features. :D In your case, the fault, dear Brutus, lies not in the stars but .......

Have you not noticed the line

document.forms[0].word.value = ""; // clear the input field

That is deliberate, and clears the input field ready for the next entry.
If you don't want that, simply delete the line.

If you prefer to clear the input box when it receives focus, then all you have to do is add the blue as shown below:-

Type a word: <input name="word" onfocus = "this.value = '' "; onblur="checkForWord(this);" /> Matches found <input type = "text" id = "Counter" readonly>

To be candid, you have had extraordinary help from Old Pedant and myself, yet you seem to be quite incapable of understanding the code or making any small adjustments. You can easily change the background color of matches found using CSS. I think you should try to learn Javascript and CSS. After all, this forum is not a free coding service.

However, I'll show you how you can adapt the script to change the color of found items to red (if you don't like red, then choose green or blue or any other color):-

You need to place each item text within a <span>, and assign the span a unique id (here I have chosen a1, a2 etc.).
And add that id preceded by a tilde sign (~) to the value of each corresponding checkbox. Like this:-


<label>
<input type="checkbox" name="keywords" value="An apple a day keeps the doctor at bay~a1">
<span id = "a1"> An apple a day keeps the doctor at bay </span>
</label></br/>
<label>
<input type="checkbox" name="keywords" value="All work and no play makes Jack a dull boy~a2">
<span id = "a2"> All work and no play makes Jack a dull boy </span>
</label></br/>

and so on for all your 15000 items! I expect you realise that if you want to change the color of a specific element you need to assign an id to that element so it can be, er, identified. Presumably the id of your last item will be a15000.

The additional Javascript is trivial (in blue):


if ( fcnt == words.length ) {
field.checked = true;
found = true;
counter ++;
document.getElementById("Counter").value = counter;
var cbsplt = cbtext.split("~");
var x = cbsplt[1]; // x is the id of the span
document.getElementById(x).style.color = "red";
}

If you want to revert to black after each search, add these blue lines:


function checkForWord( wordField ) {

var spanArray = document.getElementsByTagName('span');
var slen = spanArray.length; // the number of <span> elements
for (var i=1; i<=slen; i++) {
document.getElementById("a" + i).style.color = "black"; // reset to black after each search if required
}


You may also wish to alter this line to

if (wordField.value.length <2) { // otherwise entering just "a" will find all the items.


I do hope that this thread can now be put to bed.

frank5050
01-11-2012, 07:22 PM
Thanks guys for all your help. I'll make adjustments as necessary. All your assistance is greatly appreciated.



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum