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
- }
- });
|