source: [view]
request = request || {};
var scope = request.scope || dojo.global;
if(!request.query){
if(request.onError){
request.onError.call(scope, new Error(this.declaredClass +
": A query must be specified."));
return;
}
}
//Make a copy of the request object, in case it is
//modified outside the store in the middle of a request
var query = {};
for(var attr in this._queryAttrs) {
query[attr] = request.query[attr];
}
request = {
query: query,
onComplete: request.onComplete,
onError: request.onError,
onItem: request.onItem,
onBegin: request.onBegin,
start: request.start,
count: request.count
};
//Google's web api will only return a max of 8 results per page.
var pageSize = 8;
//Generate a unique function to be called back
var callbackFn = "GoogleSearchStoreCallback_" + this._id + "_" + (++this._requestCount);
//Build up the content to send the request for.
//rsz is the result size, "large" gives 8 results each time
var content = this._createContent(query, callbackFn, request);
var firstRequest;
if(typeof(request.start) === "undefined" || request.start === null){
request.start = 0;
}
if(!request.count){
request.count = pageSize;
}
firstRequest = {start: request.start - request.start % pageSize};
var _this = this;
var searchUrl = this._googleUrl + this._type;
var getArgs = {
url: searchUrl,
preventCache: this.urlPreventCache,
content: content
};
var items = [];
var successfulReq = 0;
var finished = false;
var lastOnItem = request.start -1;
var numRequests = 0;
var scriptIds = [];
// Performs the remote request.
function doRequest(req){
//Record how many requests have been made.
numRequests ++;
getArgs.content.context = getArgs.content.start = req.start;
var deferred = dojo.io.script.get(getArgs);
scriptIds.push(deferred.ioArgs.id);
//We only set up the errback, because the callback isn't ever really used because we have
//to link to the jsonp callback function....
deferred.addErrback(function(error){
if(request.onError){
request.onError.call(scope, error, request);
}
});
}
// Function to handle returned data.
var myHandler = function(start, data){
if (scriptIds.length > 0) {
// Delete the script node that was created.
dojo.query("#" + scriptIds.splice(0,1)).forEach(dojo.destroy);
}
if(finished){return;}
var results = _this._getItems(data);
var cursor = data ? data['cursor']: null;
if(results){
//Process the results, adding the store reference to them
for(var i = 0; i < results.length && i + start < request.count + request.start; i++) {
_this._processItem(results[i], data);
items[i + start] = results[i];
}
successfulReq ++;
if(successfulReq == 1){
// After the first request, we know how many results exist.
// So perform any follow up requests to retrieve more data.
var pages = cursor ? cursor.pages : null;
var firstStart = pages ? Number(pages[pages.length - 1].start) : 0;
//Call the onBegin method if it exists
if (request.onBegin){
var est = cursor ? cursor.estimatedResultCount : results.length;
var total = est ? Math.min(est, firstStart + results.length) : firstStart + results.length;
request.onBegin.call(scope, total, request);
}
// Request the next pages.
var nextPage = (request.start - request.start % pageSize) + pageSize;
var page = 1;
while(pages){
if(!pages[page] || Number(pages[page].start) >= request.start + request.count){
break;
}
if(Number(pages[page].start) >= nextPage) {
doRequest({start: pages[page].start});
}
page++;
}
}
// Call the onItem function on all retrieved items.
if(request.onItem && items[lastOnItem + 1]){
do{
lastOnItem++;
request.onItem.call(scope, items[lastOnItem], request);
}while(items[lastOnItem + 1] && lastOnItem < request.start + request.count);
}
//If this is the last request, call final fetch handler.
if(successfulReq == numRequests){
//Process the items...
finished = true;
//Clean up the function, it should never be called again
dojo.global[callbackFn] = null;
if(request.onItem){
request.onComplete.call(scope, null, request);
}else{
items = items.slice(request.start, request.start + request.count);
request.onComplete.call(scope, items, request);
}
}
}
};
var callbacks = [];
var lastCallback = firstRequest.start - 1;
// Attach a callback function to the global namespace, where Google can call it.
dojo.global[callbackFn] = function(start, data, responseCode, errorMsg){
try {
if(responseCode != 200){
if(request.onError){
request.onError.call(scope, new Error("Response from Google was: " + responseCode), request);
}
dojo.global[callbackFn] = function(){};//an error occurred, do not return anything else.
return;
}
if(start == lastCallback + 1){
myHandler(Number(start), data);
lastCallback += pageSize;
//make sure that the callbacks happen in the correct sequence
if(callbacks.length > 0){
callbacks.sort(_this._getSort());
//In case the requsts do not come back in order, sort the returned results.
while(callbacks.length > 0 && callbacks[0].start == lastCallback + 1){
myHandler(Number(callbacks[0].start), callbacks[0].data);
callbacks.splice(0,1);
lastCallback += pageSize;
}
}
}else{
callbacks.push({start:start, data: data});
}
} catch (e) {
request.onError.call(scope, e, request);
}
};
// Perform the first request. When this has finished
// we will have a list of pages, which can then be
// gone through
doRequest(firstRequest);