Question

Getting some odd behavior from google custom search that I can't seem to suss out. Maybe someone has a clue.

I'm putting together a Magento site, which has its own internal search engine - but is limited to product only. I want to implement google custom search results on the search results page as well. I figure I should be able to simply execute a search based on the query vars in the url (to return all the non-product content), as such:

        <section style="min-height:600px">
            <div style="background-color:#DFDFDF; min-height:800px; width:100%;">
                <div id="cse">Loading</div>
            </div>
        <script src="http://www.google.com/jsapi" type="text/javascript"></script>
        <script type="text/javascript"> 
        //<![CDATA[

            $(document).ready( function(){ 
                console.log('search initiated');
                var t = window.setTimeout( function(){ customSearch(); }, 5000 );
            });

            function customSearch(){
                var q = urlParams()['q'];
                if (q != undefined && q != ""){
                    console.log('q : %s', q); //outputs successfully

                    google.load('search', '1');
                    google.setOnLoadCallback(function () {
                        var customSearchControl = new google.search.CustomSearchControl(MY CUSTOM ID KEY);
                        var cseDrawOptions = new google.search.DrawOptions();
                        cseDrawOptions.setAutoComplete(true); //unknown if this is required... 
                        customSearchControl.draw('cse',cseDrawOptions);                    
                        customSearchControl.execute(q);

                    }, true);

                } 
            }

           function urlParams(){
                    var vars = []; 
                    var hash;
                    var index = window.location.href.indexOf('?');
                    if( index != -1 ){
                        var hashes = window.location.href.slice(index + 1).split('&');
                        for(var i = 0; i < hashes.length; i++){
                            hash = hashes[i].split('=');
                            vars.push(hash[0]);
                            vars[hash[0]] = hash[1].replace(/\+/g, " ");
                        }
                    }
                    return vars;
                }

        //]>
        </script>
        </section>

I'll note that I've pulled all other content out of the logic (but its implementation in magento is identical).

So the behavior goes like this: page loads fine (I'm delaying the google search with a timeout for testing purposes ). Assuming there is a query var in the url the console traces out as expected. Then the page just gets wiped out, with no content back from google. "Wiped out"... meaning all elements on teh page disappear, or are getting overwritten by a new page that google loads. As if the search control isn't creating an iframe - its just replacing the page with a <body>-less html page.

I've ready a number of articles on the subject, and gone over the API - this code looks like it should work. But clearly isn't.

What am I missing?

Cheers -

UPDATE

Continued messing around with this has revealed that for whatever reason :

google.load('search', '1');
google.google.setOnLoadCallback( console.log('loaded') )

Was the cause of the replaced page issue. The responded page, however contained links to the search module that google is hosting. And if I manually linked those files (forgoing a google.load) then I could run a search as expected:

<script src="http://www.google.com/jsapi" type="text/javascript"></script>
<script src="http://www.google.com/uds/?file=search&v=1" type="text/javascript"></script>
<script type="text/javascript"> 
//<![CDATA[
  ... search logic

Then I found an alternate syntax on the google developers page that seemed to work as expected:

$(document).ready( function(){ 
        google.load("search", "1", {"callback" : customSearch});
    });

    function customSearch(){
        var q = urlParams()['q'];
        if (q != undefined && q != ""){
            var cseControl = new google.search.CustomSearchControl('MY CUSTOM KEY');

            var cseDrawOptions = new google.search.DrawOptions();
            cseDrawOptions.enableSearchResultsOnly()
            cseControl.draw('cse', cseDrawOptions);
            cseControl.execute(q);
        } 
    }

Which works as expected. Only real problem at this point is the host of

Unsafe JavaScript attempt to access frame with URL http://mydomain from frame with URL http://www.google/cse?...

That now gets thrown.

I don't know how the two different versions of load syntax changes anything... but it seemed to of. Whatever the case, I'm unclear as to how to resolve these cross domain errors.

Thoughts would be great.

Was it helpful?

Solution

Nothin huh?

Well - I've basically worked out a good solution, using an alternate method that I think will be more flexible in the long run. Using googles RESTful API and simple jquery .ajax call, I can obtain good, controllable results with no cross-domain errors:

<div id="cse">Loading</div>
<script>
    //https://developers.google.com/custom-search/v1/getting_started
    //https://developers.google.com/custom-search/v1/using_rest#query-params
    //https://developers.google.com/custom-search/v1/cse/list

    var _url    = "https://www.googleapis.com/customsearch/v1";
    var _key    = 'AIzaSy... your api key here'; 
    var _cx     = '001809... your engine id';
    var _q      = urlParams()['q'];                         //query param

    jQuery(document).ready(function() {

        $j.ajax({
            url     : _url,
            type    : 'GET',
            dataType : 'jsonp',
            data :{
                key : _key,
                cx  : _cx,
                q   :_q 
            },
            success     : function(data, textStatus, jqXHR){ responseHandler(data); },
            error       : function(jqXHR, textStatus, errorThrown){ console.log('error: %s'), errorThrown},
            beforeSend  : function(){ console.log('sending request')},
            crossDomain : true
        });

    });

    function responseHandler( response, status) {
        console.log(response);

        var cse = $j('#cse');  // render vars as needed...
        for (var i = 0; i < response.items.length; i++) {
            var item = response.items[i];
            cse.append( "<br>" + item.htmlTitle);
        }
    }

    function urlParams(){
        var vars = []; 
        var hash;
        var index = window.location.href.indexOf('?');
        if( index != -1 ){
            var hashes = window.location.href.slice(index + 1).split('&');
            for(var i = 0; i < hashes.length; i++){
                hash = hashes[i].split('=');
                vars.push(hash[0]);
                vars[hash[0]] = hash[1];
            }
        }
        return vars;
    }

</script>

And you can too;D

Cheers

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top