dojox.data.FlickrRestStore._fetchItems
dojo.require("dojox.data.FlickrRestStore");
defined in dojox/data/FlickrRestStore.js
Fetch flickr items that match to a query
Usage
function (request, fetchHandler, errorHandler) (view source)
var query = {}; if(!request.query){ request.query = query = {}; } else { dojo.mixin(query, request.query); } var primaryKey = []; var secondaryKey = []; //Generate a unique function to be called back var callbackFn = "FlickrRestStoreCallback_" + this._id + "_" + (++this._requestCount); //Build up the content to send the request for. var content = { format: "json", method: "flickr.photos.search", api_key: this._apikey, extras: "owner_name,date_upload,date_taken", jsoncallback: callbackFn }; var isRest = false; if(query.userid){ isRest = true; content.user_id = request.query.userid; primaryKey.push("userid"+request.query.userid); } if(query.apikey){ isRest = true; content.api_key = request.query.apikey; secondaryKey.push("api"+request.query.apikey); } else{ throw Error("dojox.data.FlickrRestStore: An API key must be specified."); } request._curCount = request.count; if(query.page){ content.page = request.query.page; secondaryKey.push("page" + content.page); }else if(typeof(request.start) != "undefined" && request.start != null) { if(!request.count){ request.count = 20; } var diff = request.start % request.count; var start = request.start, count = request.count; //If the count does not divide cleanly into the start number, //more work has to be done to figure out the best page to request if(diff != 0) { if(start < count / 2) { //If the first record requested is less than half the amount requested, //then request from 0 to the count record count = start + count; start = 0; } else { var divLimit = 20, div = 2; for(var i = divLimit; i > 0; i--) { if(start % i == 0 && (start/i) >= count){ div = i; break; } } count = start/div; } request._realStart = request.start; request._realCount = request.count; request._curStart = start; request._curCount = count; } else { request._realStart = request._realCount = null; request._curStart = request.start; request._curCount = request.count; } content.page = (start / count) + 1; secondaryKey.push("page" + content.page); } if(request._curCount){ content.per_page = request._curCount; secondaryKey.push("count" + request._curCount); } if(query.lang){ content.lang = request.query.lang; primaryKey.push("lang" + request.lang); } var url = this._flickrRestUrl; if(query.setid){ content.method = "flickr.photosets.getPhotos"; content.photoset_id = request.query.set; primaryKey.push("set" + request.query.set); } if(query.tags){ if(query.tags instanceof Array){ content.tags = query.tags.join(","); } else { content.tags=query.tags; } primaryKey.push("tags" + content.tags); if(query["tag_mode"] && (query.tag_mode.toLowerCase() == "any" || query.tag_mode.toLowerCase() == "all")){ content.tag_mode = query.tag_mode; } } if(query.text){ content.text=query.text; primaryKey.push("text:"+query.text); } //The store only supports a single sort attribute, even though the //Read API technically allows multiple sort attributes if(query.sort && query.sort.length > 0){ //The default sort attribute is 'date-posted' if(!query.sort[0].attribute){ query.sort[0].attribute = "date-posted"; } //If the sort attribute is valid, check if it is ascending or //descending. if(this._sortAttributes[query.sort[0].attribute]) { if(query.sort[0].descending){ content.sort = query.sort[0].attribute + "-desc"; } else { content.sort = query.sort[0].attribute + "-asc"; } } } else { //The default sort in the Dojo Data API is ascending. content.sort = "date-posted-asc"; } primaryKey.push("sort:"+content.sort); //Generate a unique key for this request, so the store can //detect duplicate requests. primaryKey = primaryKey.join("."); secondaryKey = secondaryKey.length > 0 ? "." + secondaryKey.join(".") : ""; var requestKey = primaryKey + secondaryKey; //Make a copy of the request, in case the source object is modified //before the request completes request = { query: query, count: request._curCount, start: request._curStart, _realCount: request._realCount, _realStart: request._realStart, onBegin: request.onBegin, onComplete: request.onComplete, onItem: request.onItem }; var thisHandler = { request: request, fetchHandler: fetchHandler, errorHandler: errorHandler }; //If the request has already been made, but not yet completed, //then add the callback handler to the list of handlers //for this request, and finish. if(this._handlers[requestKey]){ this._handlers[requestKey].push(thisHandler); return; } this._handlers[requestKey] = [thisHandler]; //Linking this up to Flickr is a PAIN! var self = this; var handle = null; var getArgs = { url: this._flickrRestUrl, preventCache: true, content: content }; var doHandle = function(processedData, data, handler){ var onBegin = handler.request.onBegin; handler.request.onBegin = null; var maxPhotos; var req = handler.request; if(typeof(req._realStart) != undefined && req._realStart != null) { req.start = req._realStart; req.count = req._realCount; req._realStart = req._realCount = null; } //If the request contains an onBegin method, the total number //of photos must be calculated. if(onBegin){ if(data && typeof(data.photos.perpage) != "undefined" && typeof(data.photos.pages) != "undefined"){ if(data.photos.perpage * data.photos.pages <= handler.request.start + handler.request.count){ //If the final page of results has been received, it is possible to //know exactly how many photos there are maxPhotos = handler.request.start + data.photos.photo.length; }else{ //If the final page of results has not yet been received, //it is not possible to tell exactly how many photos exist, so //return the number of pages multiplied by the number of photos per page. maxPhotos = data.photos.perpage * data.photos.pages; } self._maxPhotosPerUser[primaryKey] = maxPhotos; onBegin(maxPhotos, handler.request); } else if(self._maxPhotosPerUser[primaryKey]) { onBegin(self._maxPhotosPerUser[primaryKey], handler.request); } } //Call whatever functions the caller has defined on the request object, except for onBegin handler.fetchHandler(processedData, handler.request); if(onBegin){ //Replace the onBegin function, if it existed. handler.request.onBegin = onBegin; } }; //Define a callback for the script that iterates through a list of //handlers for this piece of data. Multiple requests can come into //the store for the same data. var myHandler = function(data){ //The handler should not be called more than once, so disconnect it. //if(handle !== null){ dojo.disconnect(handle); } if(data.stat != "ok"){ errorHandler(null, request); }else{ //Process the items... var handlers = self._handlers[requestKey]; if(!handlers){ console.log("FlickrRestStore: no handlers for data", data); return; } self._handlers[requestKey] = null; self._prevRequests[requestKey] = data; //Process the data once. var processedData = self._processFlickrData(data, request, primaryKey); if(!self._prevRequestRanges[primaryKey]) { self._prevRequestRanges[primaryKey] = []; } self._prevRequestRanges[primaryKey].push({ start: request.start, end: request.start + data.photos.photo.length }); //Iterate through the array of handlers, calling each one. for(var i = 0; i < handlers.length; i++ ){ doHandle(processedData, data, handlers[i]); } } }; var data = this._prevRequests[requestKey]; //If the data was previously retrieved, there is no need to fetch it again. if(data){ this._handlers[requestKey] = null; doHandle(this._cache[primaryKey], data, thisHandler); return; } else if(this._checkPrevRanges(primaryKey, request.start, request.count)) { //If this range of data has already been retrieved, reuse it. this._handlers[requestKey] = null; doHandle(this._cache[primaryKey], null, thisHandler); return; } dojo.global[callbackFn] = function(data){ myHandler(data); //Clean up the function, it should never be called again dojo.global[callbackFn] = null; }; var deferred = dojo.io.script.get(getArgs); //We only set up the errback, because the callback isn't ever really used because we have //to link to the jsonFlickrFeed function.... deferred.addErrback(function(error){ dojo.disconnect(handle); errorHandler(error, request); });
parameter | type | description |
---|---|---|
request | request object | |
fetchHandler | function to call for fetched items | |
errorHandler | function to call on error |