PDA

View Full Version : Script which allows users to select from multiple Google CSE 's



RichardH
11-17-2014, 01:11 AM
I am having trouble with this script. No matter what I try it does not run.

Can anyone see what I am doing wrong or do you see any errors in the script?


<script>
(function() {
var cx = 'user_id:field_id1';
var gcse = document.createElement('script');
gcse.type = 'text/javascript';
gcse.async = true;
gcse.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') +
'//www.google.com/cse/cse.js?cx=' + cx;
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(gcse, s);

// This basically takes the value of the radio button (requires jQuery)
$("input:radio[name='GCSField']").change(function() {
cx = $(this).val();
});

})();
</script>
<label for="user1">
<input name=GCSField id="user1" type="radio" value="user_id:field_id1" checked >User Field 1 </label>
<label for="user2">
<input name=GCSField id="user2" type="radio" value="user_id:field_id2">User Field 2 </label>

<gcse:search></gcse:search>



Here is the html.


<html>
<head><meta charset="UTF-8">
<!--[if lt IE 9]><script src=http://html5shiv.googlecode.com/svn/trunk/html5.js></script><![endif]-->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<title>TEST</title> <meta name="robots" content="noindex, nofollow"> <meta name="viewport" content=" width=device-width, initial-scale=1"><meta name="HandheldFriendly" content="true"><meta name="MobileOptimized" content="320">
<style>body{width:100%;max-width:25em;margin-left:auto;margin-right:auto;font-family:Verdana,'Palatino Linotype',Palatino,'Book Antiqua',Arial,Helvetica,sans-serif;text-align:justify;font-size:105%;background-color:#000;background:#000;}p{margin-bottom:1%;}strong{font-size:115%;font-weight:bold;}a{line-height:200%;text-decoration:underline;color:#0007C6;}article{margin: 0 0 1% 0; color:#000;background:#FEE800;background-color:#FEE800; text-align: center;}</style>
</head><body>
<article>
<div><script>
(function() {
var cx = 'user_id:field_id1';
var gcse = document.createElement('script');
gcse.type = 'text/javascript';
gcse.async = true;
gcse.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') +
'//www.google.com/cse/cse.js?cx=' + cx;
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(gcse, s);

// This basically takes the value of the radio button (requires jQuery)
$("input:radio[name='GCSField']").change(function() {
cx = $(this).val();
});

})();
</script>
<label for="user1">
<input name=GCSField id="user1" type="radio" value="011565775292567206849:xkh-s7ljiug" checked >User Field 1 </label>
<label for="user2">
<input name=GCSField id="user2" type="radio" value="partner-pub-4173665486685435:n2tml3-z5vf">User Field 2 </label>
<gcse:search></gcse:search></div>
<div><gcse:searchresults></gcse:searchresults></div>
</article>
</body></html>

jscheuer1
11-17-2014, 03:16 AM
Cart before the horse and possibly then some. The javascript code on the page means (seems to want to at least) to reference the value of elements that the user might select (check) when they change and then access a CSE on that basis. However, the code runs before the browser parses said elements and doesn't successfully assign any events to them. And treats one of said element's id as its value (maybe - not positive on that yet). I think I 'get' what you're trying to do, so will attempt a rewrite. At the same time I would also note that the protocol (HTTP, or localhost, or HTTPS) could be another issue once the main issues I first mentioned are resolved.

But if in the meantime this (merely what I've said here) helps you resolve this - you will have learned more.

jscheuer1
11-17-2014, 03:28 AM
Try this:


<html>
<head><meta charset="UTF-8">
<!--[if lt IE 9]><script src=http://html5shiv.googlecode.com/svn/trunk/html5.js></script><![endif]-->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<title>TEST</title> <meta name="robots" content="noindex, nofollow"> <meta name="viewport" content=" width=device-width, initial-scale=1"><meta name="HandheldFriendly" content="true"><meta name="MobileOptimized" content="320">
<style>body{width:100%;max-width:25em;margin-left:auto;margin-right:auto;font-family:Verdana,'Palatino Linotype',Palatino,'Book Antiqua',Arial,Helvetica,sans-serif;text-align:justify;font-size:105%;background-color:#000;background:#000;}p{margin-bottom:1%;}strong{font-size:115%;font-weight:bold;}a{line-height:200%;text-decoration:underline;color:#0007C6;}article{margin: 0 0 1% 0; color:#000;background:#FEE800;background-color:#FEE800; text-align: center;}</style>
</head><body>
<article>
<div><script>
jQuery(function($){
var cx;
// This basically takes the value of the radio button (requires jQuery)
$("input:radio[name='GCSField']").change(function() {
cx = $(this).val();
getcse();
});
function getcse() {
var gcse = document.createElement('script');
gcse.type = 'text/javascript';
gcse.async = true;
gcse.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') +
'//www.google.com/cse/cse.js?cx=' + cx;
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(gcse, s);
}
});
</script>
<label for="user1">
<input name=GCSField id="user1" type="radio" value="011565775292567206849:xkh-s7ljiug" >User Field 1 </label>
<label for="user2">
<input name=GCSField id="user2" type="radio" value="partner-pub-4173665486685435:n2tml3-z5vf">User Field 2 </label>
<gcse:search></gcse:search></div>
<div><gcse:searchresults></gcse:searchresults></div>
</article>
</body></html>

If you want more help, please post a link to the page on your site the shows the problematic code.

RichardH
11-17-2014, 04:01 AM
Thank-you John.

Using your code changes the script now works when the page is first loaded, but does not switch CSE's after one is selected unless the page is reloaded.

Have you any idea how we could fix that.

I put your code up on a test page www.rickym.com/index43.htm
and added 2 more CSE's

Home Pages Only uses a search engine that searches only the homepage of the domain name
Full Web uses a search engine that searches all levels
Twitter searches only Twitter
YouTube searches only Youtube


Thanks again

Richard

jscheuer1
11-17-2014, 04:40 AM
Yes, but it depends upon how firmly set one search engine is once one is chosen as to how best to change to another one after that. In the most extreme case we could reload the page with either a url parameter or cookie to tell it which new engine to load/display. In a less extreme case we could perhaps simply empty out the current search engine's markup and/or remove its script from the page before trying to institute the next one. I'll play around a little and get back to you.

jscheuer1
11-17-2014, 06:35 AM
Alright, this seems like about the best I can get. I would like to be able to trigger a search on reload of a new custom engine, but without the Google cse api (even with it) that might be impossible. I added a jQuery cookie unit, updated the javascript to use it to reload the page with the new search each time, preserving the search term(s) if any, and made the HTML a little more standard:


<!DOCTYPE html>
<html>
<head><meta charset="UTF-8">
<title>TEST</title> <meta name="robots" content="noindex, nofollow"> <meta name="viewport" content=" width=device-width, initial-scale=1"><meta name="HandheldFriendly" content="true"><meta name="MobileOptimized" content="320">
<style>body{width:100%;max-width:25em;margin-left:auto;margin-right:auto;font-family:Verdana,'Palatino Linotype',Palatino,'Book Antiqua',Arial,Helvetica,sans-serif;text-align:justify;font-size:105%;background-color:#000;background:#000;}p{margin-bottom:1%;}strong{font-size:115%;font-weight:bold;}a{line-height:200%;text-decoration:underline;color:#0007C6;}article{margin: 0 0 1% 0; color:#000;background:#FEE800;background-color:#FEE800; text-align: center;}</style>
<!--[if lt IE 9]><script src=http://html5shiv.googlecode.com/svn/trunk/html5.js></script><![endif]-->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://www.parkerlabs.com/Scripts/jquery.cookie.js"></script>
</head><body>
<article>
<div><script>
jQuery(function($){
var cx = $.cookie('whichengine'), cv = $.cookie('whichenginesearchval');
// This basically takes the value of the radio button (requires jQuery)
$("input:radio[name='GCSField']").change(function(){
$.cookie('whichengine', this.id);
if(document.getElementsByName('search').length){
$.cookie('whichenginesearchval', document.getElementsByName('search')[0].value);
} else {
$.cookie('whichenginesearchval', '', {expires: -1});
}
window.location.replace(window.location.href.replace(window.location.hash, '').replace(window.location.search, ''));
});
function pollforsearchinput(val){
if(document.getElementsByName('search').length){
document.getElementsByName('search')[0].style.backgroundImage = 'none';
document.getElementsByName('search')[0].value = val;
document.getElementsByName('search')[0].focus();
} else {
setTimeout(function(){pollforsearchinput(val);}, 300);
}
}
if(cx){
$.cookie('whichengine', '', {expires: -1});
$.cookie('whichenginesearchval', '', {expires: -1});
document.getElementById(cx).checked = true;
cx = document.getElementById(cx).value;
var gcse = document.createElement('script');
gcse.type = 'text/javascript';
gcse.async = true;
gcse.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') +
'//www.google.com/cse/cse.js?cx=' + cx;
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(gcse, s);
if(cv){
pollforsearchinput(cv);
}
}
});
</script>
<label for="user1">
<input name=GCSField id="user1" type="radio" value="011565775292567206849:xkh-s7ljiug" >HomePages Only </label>
<label for="user2">
<input name=GCSField id="user2" type="radio" value="partner-pub-4173665486685435:n2tml3-z5vf">Full Web </label>
<label for="user3">
<input name=GCSField id="user3" type="radio" value="011565775292567206849:yg9akpqgtpc">YouTube </label>
<label for="user4">
<input name=GCSField id="user4" type="radio" value="011565775292567206849:jbecahferig">Twitter </label>
<gcse:search></gcse:search></div>
<div><gcse:searchresults></gcse:searchresults></div>
</article>
</body></html>

You should get and host your own copy of the cookie unit. It's available here:

https://github.com/carhartl/jquery-cookie/blob/master/src/jquery.cookie.js

RichardH
11-17-2014, 02:48 PM
Good Morning John,

Looking good! I put the new code in and jquery.cookie on my server. at http://rickym.com/index33.htm

Richard

jscheuer1
11-17-2014, 07:05 PM
Great! I found the Google cse api and was able to devise a method to execute the search if there are already search term(s) and the search method is changed. And, since you are now hosting your own jQuery cookie unit, I've updated the code to use it. I also widened the search (the body actually) slightly to prevent wrapping in the radio box area:


<!DOCTYPE html>
<html>
<head><meta charset="UTF-8">
<title>TEST</title> <meta name="robots" content="noindex, nofollow"> <meta name="viewport" content=" width=device-width, initial-scale=1"><meta name="HandheldFriendly" content="true"><meta name="MobileOptimized" content="320">
<style>body{width:100%;max-width:30em;margin-left:auto;margin-right:auto;font-family:Verdana,'Palatino Linotype',Palatino,'Book Antiqua',Arial,Helvetica,sans-serif;text-align:justify;font-size:105%;background-color:#000;background:#000;}p{margin-bottom:1%;}strong{font-size:115%;font-weight:bold;}a{line-height:200%;text-decoration:underline;color:#0007C6;}article{margin: 0 0 1% 0; color:#000;background:#FEE800;background-color:#FEE800; text-align: center;}</style>
<!--[if lt IE 9]><script src=http://html5shiv.googlecode.com/svn/trunk/html5.js></script><![endif]-->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://www.rickym.com/Scripts/jquery.cookie.js"></script>
</head><body>
<article>
<div><script>
window.__gcse = {callback: function(){jQuery('body').data('searchready', true);}};
jQuery(function($){
var cx = $.cookie('whichengine'), cv = $.cookie('whichenginesearchval');
// This basically takes the value of the radio button (requires jQuery)
$("input:radio[name='GCSField']").change(function(){
$.cookie('whichengine', this.id);
if(document.getElementsByName('search').length){
$.cookie('whichenginesearchval', document.getElementsByName('search')[0].value);
} else {
$.cookie('whichenginesearchval', '', {expires: -1});
}
window.location.replace(window.location.href.replace(window.location.hash, '').replace(window.location.search, ''));
});
function pollforsearchinput(val){
if(document.getElementsByName('search').length && $('body').data('searchready')){
document.getElementsByName('search')[0].style.backgroundImage = 'none';
document.getElementsByName('search')[0].value = val;
document.getElementsByName('search')[0].focus();
setTimeout(function(){
var bob = google.search.cse.element.getAllElements();
bob.standard0.execute();
}, 0);
} else {
setTimeout(function(){pollforsearchinput(val);}, 300);
}
}
if(cx){
$.cookie('whichengine', '', {expires: -1});
$.cookie('whichenginesearchval', '', {expires: -1});
document.getElementById(cx).checked = true;
cx = document.getElementById(cx).value;
var gcse = document.createElement('script');
gcse.type = 'text/javascript';
gcse.async = true;
gcse.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') +
'//www.google.com/cse/cse.js?cx=' + cx;
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(gcse, s);
if(cv){
pollforsearchinput(cv);
}
}
});
</script>
<label for="user1">
<input name=GCSField id="user1" type="radio" value="011565775292567206849:xkh-s7ljiug" >HomePages Only </label>
<label for="user2">
<input name=GCSField id="user2" type="radio" value="partner-pub-4173665486685435:n2tml3-z5vf">Full Web </label>
<label for="user3">
<input name=GCSField id="user3" type="radio" value="011565775292567206849:yg9akpqgtpc">YouTube </label>
<label for="user4">
<input name=GCSField id="user4" type="radio" value="011565775292567206849:jbecahferig">Twitter </label>
<gcse:search></gcse:search></div>

</article>
</body></html>

Oh, and since you are not using <gcse:searchbox></gcse:searchbox>, you should not use <gcse:searchresults></gcse:searchresults> because <gcse:search></gcse:search> makes both (box and results) and having the results one there with it cause a non-fatal error. So it really isn't that important, but might cause a more serious error in some browsers. I've made this change in the above code already.

RichardH
11-17-2014, 08:22 PM
Hi John,

You are quite a helpful character. Good to meet you. I am Canadian living in Toronto.

I will give your latest a try tonight and see how it works. The CSE codes for my CSE all have the <gcse:searchresults></gcse:searchresults> etc. Let's see what happens. I will keep you informed.

Richard

RichardH
11-18-2014, 12:44 AM
Hey John

The latest version seems to work well. Give it a try at http://rickym.com/s/AK/index22.htm

Thanks

Richard

jscheuer1
11-18-2014, 01:56 AM
Good. It just occurred to me that there might be problems using the body tag as I did here:


window.__gcse = {callback: function(){jQuery('body').data('searchready', true);}};

and here:


function pollforsearchinput(val){
if(document.getElementsByName('search').length && $('body').data('searchready')){

Because we cannot always be guaranteed that the body will have been parsed when the gcse fires it's callback. If so we could switch to (unquoted) document here:


window.__gcse = {callback: function(){jQuery(document).data('searchready', true);}};

and here:


function pollforsearchinput(val){
if(document.getElementsByName('search').length && $(document).data('searchready')){

Or skip that part (get rid of this line completely):


window.__gcse = {callback: function(){jQuery('body').data('searchready', true);}};

and change the other to:


function pollforsearchinput(val){
if(document.getElementsByName('search').length){

Right now, any of the three (including the current one with 'body') seem to work, so I wouldn't worry about it unless a problem occurs.

RichardH
11-18-2014, 02:38 AM
John,

The issues above. How much risk of error?

Which patch would you say is best?

Richard

jscheuer1
11-18-2014, 05:11 AM
Not much risk. It would be hard to know without trying in tons of browsers. I think the best approach would be getting rid of the callback line and eliminating the test that was based upon it, while at the same time increasing the timeout for the execution command to 750 milliseconds (like in this example):


<!DOCTYPE html>
<html>
<head><meta charset="UTF-8">
<title>TEST</title> <meta name="robots" content="noindex, nofollow"> <meta name="viewport" content=" width=device-width, initial-scale=1"><meta name="HandheldFriendly" content="true"><meta name="MobileOptimized" content="320">
<style>body{width:100%;max-width:30em;margin-left:auto;margin-right:auto;font-family:Verdana,'Palatino Linotype',Palatino,'Book Antiqua',Arial,Helvetica,sans-serif;text-align:justify;font-size:105%;background-color:#000;background:#000;}p{margin-bottom:1%;}strong{font-size:115%;font-weight:bold;}a{line-height:200%;text-decoration:underline;color:#0007C6;}article{margin: 0 0 1% 0; color:#000;background:#FEE800;background-color:#FEE800; text-align: center;}</style>
<!--[if lt IE 9]><script src=http://html5shiv.googlecode.com/svn/trunk/html5.js></script><![endif]-->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://www.rickym.com/Scripts/jquery.cookie.js"></script>
</head><body>
<article>
<div><script>
jQuery(function($){
var cx = $.cookie('whichengine'), cv = $.cookie('whichenginesearchval');
// This basically takes the value of the radio button (requires jQuery)
$("input:radio[name='GCSField']").change(function(){
$.cookie('whichengine', this.id);
if(document.getElementsByName('search').length){
$.cookie('whichenginesearchval', document.getElementsByName('search')[0].value);
} else {
$.cookie('whichenginesearchval', '', {expires: -1});
}
window.location.replace(window.location.href.replace(window.location.hash, '').replace(window.location.search, ''));
});
function pollforsearchinput(val){
if(document.getElementsByName('search').length){
document.getElementsByName('search')[0].style.backgroundImage = 'none';
document.getElementsByName('search')[0].value = val;
document.getElementsByName('search')[0].focus();
setTimeout(function(){
var bob = google.search.cse.element.getAllElements();
bob.standard0.execute();
}, 750);
} else {
setTimeout(function(){pollforsearchinput(val);}, 300);
}
}
if(cx){
$.cookie('whichengine', '', {expires: -1});
$.cookie('whichenginesearchval', '', {expires: -1});
document.getElementById(cx).checked = true;
cx = document.getElementById(cx).value;
var gcse = document.createElement('script');
gcse.type = 'text/javascript';
gcse.async = true;
gcse.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') +
'//www.google.com/cse/cse.js?cx=' + cx;
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(gcse, s);
if(cv){
pollforsearchinput(cv);
}
}
});
</script>
<label for="user1">
<input name=GCSField id="user1" type="radio" value="011565775292567206849:xkh-s7ljiug" >HomePages Only </label>
<label for="user2">
<input name=GCSField id="user2" type="radio" value="partner-pub-4173665486685435:n2tml3-z5vf">Full Web </label>
<label for="user3">
<input name=GCSField id="user3" type="radio" value="011565775292567206849:yg9akpqgtpc">YouTube </label>
<label for="user4">
<input name=GCSField id="user4" type="radio" value="011565775292567206849:jbecahferig">Twitter </label>
<gcse:search></gcse:search></div>

</article>
</body></html>

That's my best guess, and my guesses in these areas are generally better than a lot of folks' certainties. However, as with any new api, there could always be unexpected results under some conditions that might be able to be avoided with a different approach. So if anything comes up, let me know.

RichardH
11-18-2014, 04:52 PM
John,

I tested the above code in windows and linux.

In windows xp it works nicely with (chrome, opera, explorer)
FIREFOX ( up to date) does not work to switch CSE's

In ubuntu 14 it works well with chrome.
FIREFOX 33.0 it exhibits the same behaviour as Firefox in windows.

Any idea as to why?

Otherwise in working browsers it's good and is fast.

Again, thanks for your considerable help.

Richard

jscheuer1
11-19-2014, 12:45 AM
Just tried using Firefox 33.1 under Win 7 and got the same problem. Firefox apparently objects to this line (just will not run it):


window.location.replace(window.location.href.replace(window.location.hash, '').replace(window.location.search, ''));


I like the line because it restores the url in the address bar to it's bare state while reloading the page and not adding to the history stack, so that the new url will display only the hash and search added by the CSE script for the current engine. But, as I said, Firefox just will not run it. I think it misunderstands it as a security violation, but doesn't report it like that in its console, so I'm not positive. The Firefox developer's scratch pad implies it's a security violation, but isn't definitive. Fine, there's a work around, just after it add the highlighted, as shown:


window.location.replace(window.location.href.replace(window.location.hash, '').replace(window.location.search, ''));
window.location.reload();


That way browsers (all others I guess) that will allow the page to be reloaded with the bare url will do that. The Fox will still reload without adding to the history stack, and other than a messier looking address bar, everything else will work the same as in the rest of the browsers.

RichardH
11-19-2014, 01:11 AM
That fixed the ubuntu Firefox issue.

I'll check the windows side and add my finding here when done.

John, you certainly know your stuff!

Richard

RichardH
11-21-2014, 07:08 PM
Hi John,

I tested the code with 4 different search engines, in various browser and OS situations and the code seems to work well and quickly.

I have put a working example it up at www.rickym.com

If anyone finds a situation where it has issues. Please make a comment here.

Thanks again.

Richard

RichardH
11-23-2014, 04:38 AM
Hi John,

Can you advise me how to modify your code so that upon the page first loading the Homepages Only CSE is active?

Richard

RichardH
01-06-2015, 02:04 AM
Hi John,

I tested the code with 4 different search engines, in various browser and OS situations and the code seems to work well and quickly.

I have put a working example it up at www.rickym.com

If anyone finds a situation where it has issues. Please make a comment here.

Thanks again.

Richard

I had to take this down because someone from Russia was attacking it.

RichardH
08-12-2015, 02:20 PM
Dear John,

I write to thank you for all your help. It is not often I find people like you who freely give their expertise expecting little in return.

You can see how well everything works at rickym.com (http://rickym.com)

Including how nicely the Google CSE's deliver very good search results and how nicely search term roll-over works with your script.

Again, John many thanks for your help.

I hope you are well.

Richard Hirtle