| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656 | define("dojox/data/GoogleSearchStore", ["dojo/_base/kernel", "dojo/_base/lang", "dojo/_base/declare", "dojo/_base/window", "dojo/_base/query", 		"dojo/dom-construct","dojo/io/script"],   function(dojo, lang, declare, winUtil, domQuery, domConstruct, scriptIO) {dojo.experimental("dojox.data.GoogleSearchStore");var SearchStore = declare("dojox.data.GoogleSearchStore",null,{	//	summary:	//		A data store for retrieving search results from Google.	//		This data store acts as a base class for Google searches,	//		and has a number of child data stores that implement different	//		searches. This store defaults to searching the web, and is functionally	//		identical to the dojox.data.GoogleWebSearchStore object.	//		The following attributes are supported on each item:	//		<ul>	//			<li>url - The URL for the item</li>	//			<li>unescapedUrl - The URL for the item, with URL escaping. This is often more readable</li>	//			<li>visibleUrl - The URL with no protocol specified.	//			<li>cacheUrl - The URL to the copy of the document cached by Google	//			<li>title - The page title in HTML format.</li>	//			<li>titleNoFormatting - The page title in plain text</li>	//			<li>content - A snippet of information about the page</li>	//		</ul>	//		The query accepts one parameter: text - The string to search for	constructor: function(/*Object*/args){		//	summary:		//		Initializer for the GoogleSearchStore store.		//	description:		//		The GoogleSearchStore is a Datastore interface to		//		the Google search service. The constructor accepts the following arguments:		//		<ul>		//			<li>label - the label attribute to use. Defaults to titleNoFormatting</li>		//			<li>key - The API key to use. This is optional</li>		//			<li>lang - The language locale to use. Defaults to the browser locale</li>		//		</ul>		if(args){			if(args.label){				this.label = args.label;			}			if(args.key){				this._key = args.key;			}			if(args.lang){				this._lang = args.lang;			}			if("urlPreventCache" in args){				this.urlPreventCache = args.urlPreventCache?true:false;			}		}		this._id = dojox.data.GoogleSearchStore.prototype._id++;	},	// _id: Integer	// A unique identifier for this store.	_id: 0,	// _requestCount: Integer	// A counter for the number of requests made. This is used to define	// the callback function that GoogleSearchStore will use.	_requestCount: 0,	// _googleUrl: String	// The URL to Googles search web service.	_googleUrl: "http://ajax.googleapis.com/ajax/services/search/",	// _storeRef: String	// The internal reference added to each item pointing at the store which owns it.	_storeRef: "_S",	// _attributes: Array	// The list of attributes that this store supports	_attributes: [	"unescapedUrl", "url", "visibleUrl", "cacheUrl", "title",			"titleNoFormatting", "content", "estimatedResultCount"],	// _aggregtedAttributes: Hash	// Maps per-query aggregated attributes that this store supports to the result keys that they come from.	_aggregatedAttributes: {		estimatedResultCount: "cursor.estimatedResultCount"	},	// label: String	// The default attribute which acts as a label for each item.	label: "titleNoFormatting",	// type: String	// The type of search. Valid values are "web", "local", "video", "blogs", "news", "books", "images".	// This should not be set directly. Instead use one of the child classes.	_type: "web",	// urlPreventCache: boolean	// Sets whether or not to pass preventCache to dojo.io.script.	urlPreventCache: true,	// _queryAttrs: Hash	// Maps query hash keys to Google query parameters.	_queryAttrs: {		text: 'q'	},	_assertIsItem: function(/* item */ item){		//	summary:		//		This function tests whether the item passed in is indeed an item in the store.		//	item:		//		The item to test for being contained by the store.		if(!this.isItem(item)){			throw new Error("dojox.data.GoogleSearchStore: a function was passed an item argument that was not an item");		}	},	_assertIsAttribute: function(/* attribute-name-string */ attribute){		//	summary:		//		This function tests whether the item passed in is indeed a valid 'attribute' like type for the store.		//	attribute:		//		The attribute to test for being contained by the store.		if(typeof attribute !== "string"){			throw new Error("dojox.data.GoogleSearchStore: a function was passed an attribute argument that was not an attribute name string");		}	},	getFeatures: function(){		//	summary:		//		See dojo.data.api.Read.getFeatures()		return {			'dojo.data.api.Read': true		};	},	getValue: function(item, attribute, defaultValue){		//	summary:		//		See dojo.data.api.Read.getValue()		var values = this.getValues(item, attribute);		if(values && values.length > 0){			return values[0];		}		return defaultValue;	},	getAttributes: function(item){		//	summary:		//		See dojo.data.api.Read.getAttributes()		return this._attributes;	},	hasAttribute: function(item, attribute){		//	summary:		//		See dojo.data.api.Read.hasAttributes()		if(this.getValue(item,attribute)){			return true;		}		return false;	},	isItemLoaded: function(item){		 //	summary:		 //		See dojo.data.api.Read.isItemLoaded()		 return this.isItem(item);	},	loadItem: function(keywordArgs){		//	summary:		//		See dojo.data.api.Read.loadItem()	},	getLabel: function(item){		//	summary:		//		See dojo.data.api.Read.getLabel()		return this.getValue(item,this.label);	},	getLabelAttributes: function(item){		//	summary:		//		See dojo.data.api.Read.getLabelAttributes()		return [this.label];	},	containsValue: function(item, attribute, value){		//	summary:		//		See dojo.data.api.Read.containsValue()		var values = this.getValues(item,attribute);		for(var i = 0; i < values.length; i++){			if(values[i] === value){				return true;			}		}		return false;	},	getValues: function(item, attribute){		//	summary:		//		See dojo.data.api.Read.getValue()		this._assertIsItem(item);		this._assertIsAttribute(attribute);		var val = item[attribute];		if(lang.isArray(val)) {			return val;		}else if(val !== undefined){			return [val];		}else{			return [];		}	},	isItem: function(item){		//	summary:		//		See dojo.data.api.Read.isItem()		if(item && item[this._storeRef] === this){			return true;		}		return false;	},	close: function(request){		//	summary:		//		See dojo.data.api.Read.close()	},	_format: function(item, name){		return item;//base implementation does not format any items	},	fetch: function(request){		//	summary:		//		Fetch Google search items that match to a query		//	request:		//		A request object		//	fetchHandler:		//		A function to call for fetched items		//	errorHandler:		//		A function to call on error		request = request || {};		var scope = request.scope || winUtil.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 = scriptIO.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.				domQuery("#" + scriptIds.splice(0,1)).forEach(domConstruct.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					winUtil.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.		winUtil.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);					}					winUtil.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);	},		_getSort: function() {		return function(a,b){			if(a.start < b.start){return -1;}			if(b.start < a.start){return 1;}			return 0;		};	},	_processItem: function(item, data) {		item[this._storeRef] = this;		// Copy aggregated attributes from query results to the item.		for(var attribute in this._aggregatedAttributes) {			item[attribute] = lang.getObject(this._aggregatedAttributes[attribute], false, data);		}	},	_getItems: function(data){		return data['results'] || data;	},	_createContent: function(query, callback, request){		var content = {			v: "1.0",			rsz: "large",			callback: callback,			key: this._key,			hl: this._lang		};		for(var attr in this._queryAttrs) {			content[this._queryAttrs[attr]] = query[attr];		}		return content;	}});var WebSearchStore = declare("dojox.data.GoogleWebSearchStore", SearchStore,{	//	Summary:	//		A data store for retrieving search results from Google.	//		The following attributes are supported on each item:	//		<ul>	//			<li>title - The page title in HTML format.</li>	//			<li>titleNoFormatting - The page title in plain text</li>	//			<li>content - A snippet of information about the page</li>	//			<li>url - The URL for the item</li>	//			<li>unescapedUrl - The URL for the item, with URL escaping. This is often more readable</li>	//			<li>visibleUrl - The URL with no protocol specified.</li>	//			<li>cacheUrl - The URL to the copy of the document cached by Google</li>	//			<li>estimatedResultCount - (aggregated per-query) estimated number of results</li>	//		</ul>	//		The query accepts one parameter: text - The string to search for});var BlogSearchStore = declare("dojox.data.GoogleBlogSearchStore", SearchStore,{	//	Summary:	//		A data store for retrieving search results from Google.	//		The following attributes are supported on each item:	//		<ul>	//			<li>title - The blog post title in HTML format.</li>	//			<li>titleNoFormatting - The  blog post title in plain text</li>	//			<li>content - A snippet of information about the blog post</li>	//			<li>blogUrl - The URL for the blog</li>	//			<li>postUrl - The URL for the a single blog post</li>	//			<li>visibleUrl - The URL with no protocol specified.	//			<li>cacheUrl - The URL to the copy of the document cached by Google	//			<li>author - The author of the blog post</li>	//			<li>publishedDate - The published date, in RFC-822 format</li>	//		</ul>	//		The query accepts one parameter: text - The string to search for	_type: "blogs",	_attributes: ["blogUrl", "postUrl", "title", "titleNoFormatting", "content",			"author", "publishedDate"],	_aggregatedAttributes: { }});var LocalSearchStore = declare("dojox.data.GoogleLocalSearchStore", SearchStore,{	//	summary:	//		A data store for retrieving search results from Google.	//		The following attributes are supported on each item:	//		<ul>	//			<li>title - The blog post title in HTML format.</li>	//			<li>titleNoFormatting - The  blog post title in plain text</li>	//			<li>content - A snippet of information about the blog post</li>	//			<li>url - The URL for the item</li>	//			<li>lat - The latitude.</li>	//			<li>lng - The longtitude.</li>	//			<li>streetAddress - The street address</li>	//			<li>city - The city</li>	//			<li>region - The region</li>	//			<li>country - The country</li>	//			<li>phoneNumbers - Phone numbers associated with this address. Can be one or more.</li>	//			<li>ddUrl - A URL that can be used to provide driving directions from the center of the search results to this search results</li>	//			<li>ddUrlToHere - A URL that can be used to provide driving directions from this search result to a user specified location</li>	//			<li>staticMapUrl - The published date, in RFC-822 format</li>	//			<li>viewport - Recommended viewport for the query results (same for all results in a query)	//				<ul>	//					<li>center - contains lat, lng properties</li>	//					<li>span - lat, lng properties for the viewport span</li>	//					<li>ne, sw - lat, lng properties for the viewport corners<li>	//				</ul>	//			</li>	//		</ul>	//		The query accepts the following parameters:	//		<ul>	//			<li>text - The string to search for</li>	//			<li>centerLatLong - Comma-separated lat & long for the center of the search (e.g. "48.8565,2.3509")</li>	//			<li>searchSpan - Comma-separated lat & long degrees indicating the size of the desired search area (e.g. "0.065165,0.194149")</li>	//		</ul>	_type: "local",	_attributes: ["title", "titleNoFormatting", "url", "lat", "lng", "streetAddress",			"city", "region", "country", "phoneNumbers", "ddUrl", "ddUrlToHere",			"ddUrlFromHere", "staticMapUrl", "viewport"],	_aggregatedAttributes: {		viewport: "viewport"	},	_queryAttrs: {		text: 'q',		centerLatLong: 'sll',		searchSpan: 'sspn'	}});var VideoSearchStore = declare("dojox.data.GoogleVideoSearchStore", SearchStore,{	//	summary:	//		A data store for retrieving search results from Google.	//		The following attributes are supported on each item:	//		<ul>	//			<li>title - The blog post title in HTML format.</li>	//			<li>titleNoFormatting - The  blog post title in plain text</li>	//			<li>content - A snippet of information about the blog post</li>	//			<li>url - The URL for the item</li>	//			<li>published - The published date, in RFC-822 format.</li>	//			<li>publisher - The name of the publisher.</li>	//			<li>duration - The approximate duration, in seconds, of the video.</li>	//			<li>tbWidth - The width in pixels of the video.</li>	//			<li>tbHeight - The height in pixels of the video</li>	//			<li>tbUrl - The URL to a thumbnail representation of the video.</li>	//			<li>playUrl - If present, supplies the url of the flash version of the video that can be played inline on your page. To play this video simply create and <embed> element on your page using this value as the src attribute and using application/x-shockwave-flash as the type attribute. If you want the video to play right away, make sure to append &autoPlay=true to the url..</li>	//		</ul>	//		The query accepts one parameter: text - The string to search for	_type: "video",	_attributes: ["title", "titleNoFormatting", "content", "url", "published", "publisher",			"duration", "tbWidth", "tbHeight", "tbUrl", "playUrl"],	_aggregatedAttributes: { }});var NewsSearchStore = declare("dojox.data.GoogleNewsSearchStore", SearchStore,{	//	summary:	//		A data store for retrieving search results from Google.	//		The following attributes are supported on each item:	//		<ul>	//			<li>title - The news story title in HTML format.</li>	//			<li>titleNoFormatting - The news story title in plain text</li>	//			<li>content - A snippet of information about the news story</li>	//			<li>url - The URL for the item</li>	//			<li>unescapedUrl - The URL for the item, with URL escaping. This is often more readable</li>	//			<li>publisher - The name of the publisher</li>	//			<li>clusterUrl - A URL pointing to a page listing related storied.</li>	//			<li>location - The location of the news story.</li>	//			<li>publishedDate - The date of publication, in RFC-822 format.</li>	//			<li>relatedStories - An optional array of objects specifying related stories.	//				Each object has the following subset of properties:	//				"title", "titleNoFormatting", "url", "unescapedUrl", "publisher", "location", "publishedDate".	//			</li>	//		</ul>	//		The query accepts one parameter: text - The string to search for	_type: "news",	_attributes: ["title", "titleNoFormatting", "content", "url", "unescapedUrl", "publisher",			"clusterUrl", "location", "publishedDate", "relatedStories" ],	_aggregatedAttributes: { }});var BookSearchStore = declare("dojox.data.GoogleBookSearchStore", SearchStore,{	// 	summary:	//		A data store for retrieving search results from Google.	//		The following attributes are supported on each item:	//		<ul>	//			<li>title - The book title in HTML format.</li>	//			<li>titleNoFormatting - The book title in plain text</li>	//			<li>authors - An array of authors</li>	//			<li>url - The URL for the item</li>	//			<li>unescapedUrl - The URL for the item, with URL escaping. This is often more readable</li>	//			<li>bookId - An identifier for the book, usually an ISBN.</li>	//			<li>pageCount - The number of pages in the book.</li>	//			<li>publishedYear - The year of publication.</li>	//		</ul>	//		The query accepts one parameter: text - The string to search for	_type: "books",	_attributes: ["title", "titleNoFormatting", "authors", "url", "unescapedUrl", "bookId",			"pageCount", "publishedYear"],	_aggregatedAttributes: { }});var ImageSearchStore = declare("dojox.data.GoogleImageSearchStore", SearchStore,{	//	summary:	//		A data store for retrieving search results from Google.	//		The following attributes are supported on each item:	//		<ul>	//			<li>title - The image title in HTML format.</li>	//			<li>titleNoFormatting - The image title in plain text</li>	//			<li>url - The URL for the image</li>	//			<li>unescapedUrl - The URL for the image, with URL escaping. This is often more readable</li>	//			<li>tbUrl - The URL for the image thumbnail</li>	//			<li>visibleUrl - A shortened version of the URL associated with the result, stripped of a protocol and path</li>	//			<li>originalContextUrl - The URL of the page containing the image.</li>	//			<li>width - The width of the image in pixels.</li>	//			<li>height - The height of the image in pixels.</li>	//			<li>tbWidth - The width of the image thumbnail in pixels.</li>	//			<li>tbHeight - The height of the image thumbnail in pixels.</li>	//			<li>content - A snippet of information about the image, in HTML format</li>	//			<li>contentNoFormatting - A snippet of information about the image, in plain text</li>	//		</ul>	//		The query accepts one parameter: text - The string to search for	_type: "images",	_attributes: ["title", "titleNoFormatting", "visibleUrl", "url", "unescapedUrl",			"originalContextUrl", "width", "height", "tbWidth", "tbHeight",			"tbUrl", "content", "contentNoFormatting"],	_aggregatedAttributes: { }});return {	Search: SearchStore,	ImageSearch: ImageSearchStore,	BookSearch: BookSearchStore,	NewsSearch: NewsSearchStore,	VideoSearch: VideoSearchStore,	LocalSearch: LocalSearchStore,	BlogSearch: BlogSearchStore,	WebSearch: WebSearchStore	}});
 |