2 Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
8 YUI.add('cache-base', function(Y) {
11 * The Cache utility provides a common configurable interface for components to
12 * cache and retrieve data from a local JavaScript struct.
17 isDate = Y.Lang.isDate,
20 * Base class for the YUI Cache utility.
26 Cache.superclass.constructor.apply(this, arguments);
29 /////////////////////////////////////////////////////////////////////////////
31 // Cache static properties
33 /////////////////////////////////////////////////////////////////////////////
48 /////////////////////////////////////////////////////////////////////////////
52 /////////////////////////////////////////////////////////////////////////////
56 * @description Maximum number of entries the Cache can hold.
57 * Set to 0 to turn off caching.
68 * @description Number of entries currently cached.
77 * @attribute uniqueKeys
78 * @description Validate uniqueness of stored keys. Default is false and
88 * @description Absolute Date when data expires or
89 * relative number of milliseconds. Zero disables expiration.
95 validator: function(v) {
96 return Y.Lang.isDate(v) || (Y.Lang.isNumber(v) && v >= 0);
102 * @description Cached entries.
107 getter: "_getEntries"
112 Y.extend(Cache, Y.Base, {
113 /////////////////////////////////////////////////////////////////////////////
115 // Cache private properties
117 /////////////////////////////////////////////////////////////////////////////
120 * Array of request/response objects indexed chronologically.
128 /////////////////////////////////////////////////////////////////////////////
130 // Cache private methods
132 /////////////////////////////////////////////////////////////////////////////
135 * @method initializer
136 * @description Internal init() handler.
137 * @param config {Object} Config object.
140 initializer: function(config) {
144 * @description Fired when an entry is added.
145 * @param e {Event.Facade} Event Facade with the following properties:
147 * <dt>entry (Object)</dt> <dd>The cached entry.</dd>
149 * @preventable _defAddFn
151 this.publish("add", {defaultFn: this._defAddFn});
155 * @description Fired when the cache is flushed.
156 * @param e {Event.Facade} Event Facade object.
157 * @preventable _defFlushFn
159 this.publish("flush", {defaultFn: this._defFlushFn});
163 * @description Fired when an entry is requested from the cache.
164 * @param e {Event.Facade} Event Facade with the following properties:
166 * <dt>request (Object)</dt> <dd>The request object.</dd>
172 * @description Fired when an entry is retrieved from the cache.
173 * @param e {Event.Facade} Event Facade with the following properties:
175 * <dt>entry (Object)</dt> <dd>The retrieved entry.</dd>
179 // Initialize internal values
185 * @description Internal destroy() handler.
188 destructor: function() {
192 /////////////////////////////////////////////////////////////////////////////
194 // Cache protected methods
196 /////////////////////////////////////////////////////////////////////////////
204 _setMax: function(value) {
205 // If the cache is full, make room by removing stalest element (index=0)
206 var entries = this._entries;
209 while(entries.length > value) {
227 _getSize: function() {
228 return this._entries.length;
234 * @method _getEntries
237 _getEntries: function() {
238 return this._entries;
243 * Adds entry to cache.
246 * @param e {Event.Facade} Event Facade with the following properties:
248 * <dt>entry (Object)</dt> <dd>The cached entry.</dd>
252 _defAddFn: function(e) {
253 var entries = this._entries,
254 max = this.get("max"),
257 if(this.get("uniqueKeys") && (this.retrieve(e.entry.request))) {
262 // If the cache at or over capacity, make room by removing stalest element (index=0)
263 while(max && entries.length>=max) {
267 // Add entry to cache in the newest position, at the end of the array
268 entries[entries.length] = entry;
274 * @method _defFlushFn
275 * @param e {Event.Facade} Event Facade object.
278 _defFlushFn: function(e) {
283 * Default overridable method compares current request with given cache entry.
284 * Returns true if current request matches the cached request, otherwise
285 * false. Implementers should override this method to customize the
286 * cache-matching algorithm.
289 * @param request {Object} Request object.
290 * @param entry {Object} Cached entry.
291 * @return {Boolean} True if current request matches given cached request, false otherwise.
294 _isMatch: function(request, entry) {
295 if(!entry.expires || new Date() < entry.expires) {
296 return (request === entry.request);
301 /////////////////////////////////////////////////////////////////////////////
303 // Cache public methods
305 /////////////////////////////////////////////////////////////////////////////
308 * Adds a new entry to the cache of the format
309 * {request:request, response:response, cached:cached, expires:expires}.
310 * If cache is full, evicts the stalest entry before adding the new one.
313 * @param request {Object} Request value.
314 * @param response {Object} Response value.
316 add: function(request, response) {
317 var expires = this.get("expires");
318 if(this.get("initialized") && ((this.get("max") === null) || this.get("max") > 0) &&
319 (LANG.isValue(request) || LANG.isNull(request) || LANG.isUndefined(request))) {
320 this.fire("add", {entry: {
324 expires: isDate(expires) ? expires :
325 (expires ? new Date(new Date().getTime() + this.get("expires")) : null)
342 * Retrieves cached object for given request, if available, and refreshes
343 * entry in the cache. Returns null if there is no cache match.
346 * @param request {Object} Request object.
347 * @return {Object} Cached object with the properties request and response, or null.
349 retrieve: function(request) {
350 // If cache is enabled...
351 var entries = this._entries,
352 length = entries.length,
356 if((length > 0) && ((this.get("max") === null) || (this.get("max") > 0))) {
357 this.fire("request", {request: request});
359 // Loop through each cached entry starting from the newest
363 // Execute matching function
364 if(this._isMatch(request, entry)) {
365 this.fire("retrieve", {entry: entry});
367 // Refresh the position of the cache hit
369 // Remove element from its original location
372 entries[entries.length] = entry;
387 }, '3.3.0' ,{requires:['base']});