Page Menu
Home
Code
Search
Configure Global Search
Log In
Files
F884886
FlickrRestStore.js
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
14 KB
Subscribers
None
FlickrRestStore.js
View Options
if
(
!
dojo
.
_hasResource
[
"dojox.data.FlickrRestStore"
]){
//_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo
.
_hasResource
[
"dojox.data.FlickrRestStore"
]
=
true
;
dojo
.
provide
(
"dojox.data.FlickrRestStore"
);
dojo
.
require
(
"dojox.data.FlickrStore"
);
dojo
.
declare
(
"dojox.data.FlickrRestStore"
,
dojox
.
data
.
FlickrStore
,
{
constructor
:
function
(
/*Object*/
args
){
// summary:
// Initializer for the FlickrRestStore store.
// description:
// The FlickrRestStore is a Datastore interface to one of the basic services
// of the Flickr service, the public photo feed. This does not provide
// access to all the services of Flickr.
// This store cannot do * and ? filtering as the flickr service
// provides no interface for wildcards.
if
(
args
&&
args
.
label
){
if
(
args
.
label
)
{
this
.
label
=
args
.
label
;
}
if
(
args
.
apikey
)
{
this
.
_apikey
=
args
.
apikey
;
}
}
this
.
_cache
=
[];
this
.
_prevRequests
=
{};
this
.
_handlers
=
{};
this
.
_prevRequestRanges
=
[];
this
.
_maxPhotosPerUser
=
{};
this
.
_id
=
dojox
.
data
.
FlickrRestStore
.
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 Flickr will use.
_requestCount
:
0
,
// _flickrRestUrl: String
// The URL to the Flickr REST services.
_flickrRestUrl
:
"http://www.flickr.com/services/rest/"
,
// _apikey: String
// The users API key to be used when accessing Flickr REST services.
_apikey
:
null
,
// _storeRef: String
// A key used to mark an data store item as belonging to this store.
_storeRef
:
"_S"
,
// _cache: Array
// An Array of all previously downloaded picture info.
_cache
:
null
,
// _prevRequests: Object
// A HashMap used to record the signature of a request to prevent duplicate
// request being made.
_prevRequests
:
null
,
// _handlers: Object
// A HashMap used to record the handlers registered for a single remote request. Multiple
// requests may be made for the same information before the first request has finished.
// Each element of this Object is an array of handlers to call back when the request finishes.
// This prevents multiple requests being made for the same information.
_handlers
:
null
,
// _sortAttributes: Object
// A quick lookup of valid attribute names in a sort query.
_sortAttributes
:
{
"date-posted"
:
true
,
"date-taken"
:
true
,
"interestingness"
:
true
},
_fetchItems
:
function
(
request
,
fetchHandler
,
errorHandler
){
// summary: Fetch flickr 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
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
);
});
},
getAttributes
:
function
(
item
){
// summary:
// See dojo.data.api.Read.getAttributes()
return
[
"title"
,
"author"
,
"imageUrl"
,
"imageUrlSmall"
,
"imageUrlMedium"
,
"imageUrlThumb"
,
"link"
,
"dateTaken"
,
"datePublished"
];
},
getValues
:
function
(
item
,
attribute
){
// summary:
// See dojo.data.api.Read.getValue()
this
.
_assertIsItem
(
item
);
this
.
_assertIsAttribute
(
attribute
);
if
(
attribute
===
"title"
){
return
[
this
.
_unescapeHtml
(
item
.
title
)];
// String
}
else
if
(
attribute
===
"author"
){
return
[
item
.
ownername
];
// String
}
else
if
(
attribute
===
"imageUrlSmall"
){
return
[
item
.
media
.
s
];
// String
}
else
if
(
attribute
===
"imageUrl"
){
return
[
item
.
media
.
l
];
// String
}
else
if
(
attribute
===
"imageUrlMedium"
){
return
[
item
.
media
.
m
];
// String
}
else
if
(
attribute
===
"imageUrlThumb"
){
return
[
item
.
media
.
t
];
// String
}
else
if
(
attribute
===
"link"
){
return
[
"http://www.flickr.com/photos/"
+
item
.
owner
+
"/"
+
item
.
id
];
// String
}
else
if
(
attribute
===
"dateTaken"
){
return
item
.
datetaken
;
}
else
if
(
attribute
===
"datePublished"
){
return
item
.
datepublished
;
}
return
undefined
;
},
_processFlickrData
:
function
(
/* Object */
data
,
/* Object */
request
,
/* String */
cacheKey
){
// summary: Processes the raw data from Flickr and updates the internal cache.
// data:
// Data returned from Flickr
// request:
// The original dojo.data.Request object passed in by the user.
//If the data contains an 'item' object, it has not come from the REST services,
//so process it using the FlickrStore.
if
(
data
.
items
){
return
dojox
.
data
.
FlickrStore
.
prototype
.
_processFlickrData
.
apply
(
this
,
arguments
);
}
var
template
=
[
"http://farm"
,
null
,
".static.flickr.com/"
,
null
,
"/"
,
null
,
"_"
,
null
];
var
items
=
[];
if
(
data
.
stat
==
"ok"
&&
data
.
photos
&&
data
.
photos
.
photo
){
items
=
data
.
photos
.
photo
;
//Add on the store ref so that isItem can work.
for
(
var
i
=
0
;
i
<
items
.
length
;
i
++
){
var
item
=
items
[
i
];
item
[
this
.
_storeRef
]
=
this
;
template
[
1
]
=
item
.
farm
;
template
[
3
]
=
item
.
server
;
template
[
5
]
=
item
.
id
;
template
[
7
]
=
item
.
secret
;
var
base
=
template
.
join
(
""
);
item
.
media
=
{
s
:
base
+
"_s.jpg"
,
m
:
base
+
"_m.jpg"
,
l
:
base
+
".jpg"
,
t
:
base
+
"_t.jpg"
};
}
}
var
start
=
request
.
start
?
request
.
start
:
0
;
var
arr
=
this
.
_cache
[
cacheKey
];
if
(
!
arr
)
{
this
.
_cache
[
cacheKey
]
=
arr
=
[];
}
for
(
var
count
=
0
;
count
<
items
.
length
;
count
++
){
arr
[
count
+
start
]
=
items
[
count
];
}
return
arr
;
// Array
},
_checkPrevRanges
:
function
(
primaryKey
,
start
,
count
)
{
var
end
=
start
+
count
;
var
arr
=
this
.
_prevRequestRanges
[
primaryKey
];
if
(
!
arr
)
{
return
false
;
}
for
(
var
i
=
0
;
i
<
arr
.
length
;
i
++
)
{
if
(
start
>=
arr
[
i
].
start
&&
end
<=
arr
[
i
].
end
)
{
return
true
;
}
}
return
false
;
}
});
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Apr 6, 11:24 (3 w, 5 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
25747
Default Alt Text
FlickrRestStore.js (14 KB)
Attached To
rZEDHG ZedLegacy
Event Timeline
Log In to Comment