3
Copyright 2011 Yahoo! Inc. All rights reserved.
4
Licensed under the BSD License.
5
http://yuilibrary.com/license/
7
YUI.add('cache-base', function(Y) {
10
* The Cache utility provides a common configurable interface for components to
11
* cache and retrieve data from a local JavaScript struct.
18
* Provides the base class for the YUI Cache utility.
20
* @submodule cache-base
23
isDate = Y.Lang.isDate,
26
* Base class for the YUI Cache utility.
32
Cache.superclass.constructor.apply(this, arguments);
35
/////////////////////////////////////////////////////////////////////////////
37
// Cache static properties
39
/////////////////////////////////////////////////////////////////////////////
54
/////////////////////////////////////////////////////////////////////////////
58
/////////////////////////////////////////////////////////////////////////////
62
* @description Maximum number of entries the Cache can hold.
63
* Set to 0 to turn off caching.
74
* @description Number of entries currently cached.
83
* @attribute uniqueKeys
84
* @description Validate uniqueness of stored keys. Default is false and
94
* @description Absolute Date when data expires or
95
* relative number of milliseconds. Zero disables expiration.
101
validator: function(v) {
102
return Y.Lang.isDate(v) || (Y.Lang.isNumber(v) && v >= 0);
108
* @description Cached entries.
113
getter: "_getEntries"
118
Y.extend(Cache, Y.Base, {
119
/////////////////////////////////////////////////////////////////////////////
121
// Cache private properties
123
/////////////////////////////////////////////////////////////////////////////
126
* Array of request/response objects indexed chronologically.
134
/////////////////////////////////////////////////////////////////////////////
136
// Cache private methods
138
/////////////////////////////////////////////////////////////////////////////
141
* @method initializer
142
* @description Internal init() handler.
143
* @param config {Object} Config object.
146
initializer: function(config) {
150
* @description Fired when an entry is added.
151
* @param e {Event.Facade} Event Facade with the following properties:
153
* <dt>entry (Object)</dt> <dd>The cached entry.</dd>
155
* @preventable _defAddFn
157
this.publish("add", {defaultFn: this._defAddFn});
161
* @description Fired when the cache is flushed.
162
* @param e {Event.Facade} Event Facade object.
163
* @preventable _defFlushFn
165
this.publish("flush", {defaultFn: this._defFlushFn});
169
* @description Fired when an entry is requested from the cache.
170
* @param e {Event.Facade} Event Facade with the following properties:
172
* <dt>request (Object)</dt> <dd>The request object.</dd>
178
* @description Fired when an entry is retrieved from the cache.
179
* @param e {Event.Facade} Event Facade with the following properties:
181
* <dt>entry (Object)</dt> <dd>The retrieved entry.</dd>
185
// Initialize internal values
191
* @description Internal destroy() handler.
194
destructor: function() {
198
/////////////////////////////////////////////////////////////////////////////
200
// Cache protected methods
202
/////////////////////////////////////////////////////////////////////////////
210
_setMax: function(value) {
211
// If the cache is full, make room by removing stalest element (index=0)
212
var entries = this._entries;
215
while(entries.length > value) {
233
_getSize: function() {
234
return this._entries.length;
240
* @method _getEntries
243
_getEntries: function() {
244
return this._entries;
249
* Adds entry to cache.
252
* @param e {Event.Facade} Event Facade with the following properties:
254
* <dt>entry (Object)</dt> <dd>The cached entry.</dd>
258
_defAddFn: function(e) {
259
var entries = this._entries,
260
max = this.get("max"),
263
if(this.get("uniqueKeys") && (this.retrieve(e.entry.request))) {
268
// If the cache at or over capacity, make room by removing stalest element (index=0)
269
while(max && entries.length>=max) {
273
// Add entry to cache in the newest position, at the end of the array
274
entries[entries.length] = entry;
280
* @method _defFlushFn
281
* @param e {Event.Facade} Event Facade object.
284
_defFlushFn: function(e) {
285
var entries = this._entries,
286
details = e.details[0],
289
//passed an item, flush only that
290
if(details && LANG.isValue(details.request)) {
291
pos = this._position(details.request);
293
if(LANG.isValue(pos)) {
294
entries.splice(pos,1);
298
//no item, flush everything
305
* Default overridable method compares current request with given cache entry.
306
* Returns true if current request matches the cached request, otherwise
307
* false. Implementers should override this method to customize the
308
* cache-matching algorithm.
311
* @param request {Object} Request object.
312
* @param entry {Object} Cached entry.
313
* @return {Boolean} True if current request matches given cached request, false otherwise.
316
_isMatch: function(request, entry) {
317
if(!entry.expires || new Date() < entry.expires) {
318
return (request === entry.request);
324
* Returns position of a request in the entries array, otherwise null.
327
* @param request {Object} Request object.
328
* @return {Number} Array position if found, null otherwise.
331
_position: function(request) {
332
// If cache is enabled...
333
var entries = this._entries,
334
length = entries.length,
337
if((this.get("max") === null) || this.get("max") > 0) {
338
// Loop through each cached entry starting from the newest
340
// Execute matching function
341
if(this._isMatch(request, entries[i])) {
350
/////////////////////////////////////////////////////////////////////////////
352
// Cache public methods
354
/////////////////////////////////////////////////////////////////////////////
357
* Adds a new entry to the cache of the format
358
* {request:request, response:response, cached:cached, expires:expires}.
359
* If cache is full, evicts the stalest entry before adding the new one.
362
* @param request {Object} Request value.
363
* @param response {Object} Response value.
365
add: function(request, response) {
366
var expires = this.get("expires");
367
if(this.get("initialized") && ((this.get("max") === null) || this.get("max") > 0) &&
368
(LANG.isValue(request) || LANG.isNull(request) || LANG.isUndefined(request))) {
369
this.fire("add", {entry: {
373
expires: isDate(expires) ? expires :
374
(expires ? new Date(new Date().getTime() + this.get("expires")) : null)
386
flush: function(request) {
387
this.fire("flush", { request: (LANG.isValue(request) ? request : null) });
391
* Retrieves cached object for given request, if available, and refreshes
392
* entry in the cache. Returns null if there is no cache match.
395
* @param request {Object} Request object.
396
* @return {Object} Cached object with the properties request and response, or null.
398
retrieve: function(request) {
399
// If cache is enabled...
400
var entries = this._entries,
401
length = entries.length,
405
if((length > 0) && ((this.get("max") === null) || (this.get("max") > 0))) {
406
this.fire("request", {request: request});
408
pos = this._position(request);
410
if(LANG.isValue(pos)) {
411
entry = entries[pos];
413
this.fire("retrieve", {entry: entry});
415
// Refresh the position of the cache hit
417
// Remove element from its original location
418
entries.splice(pos,1);
420
entries[entries.length] = entry;
433
}, '3.4.1' ,{requires:['base']});