Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
YUI.add('cache-base', function (Y, NAME) {
2
 
3
/**
4
 * The Cache utility provides a common configurable interface for components to
5
 * cache and retrieve data from a local JavaScript struct.
6
 *
7
 * @module cache
8
 * @main
9
 */
10
 
11
/**
12
 * Provides the base class for the YUI Cache utility.
13
 *
14
 * @submodule cache-base
15
 */
16
var LANG = Y.Lang,
17
    isDate = Y.Lang.isDate,
18
 
19
/**
20
 * Base class for the YUI Cache utility.
21
 * @class Cache
22
 * @extends Base
23
 * @constructor
24
 */
25
Cache = function() {
26
    Cache.superclass.constructor.apply(this, arguments);
27
};
28
 
29
    /////////////////////////////////////////////////////////////////////////////
30
    //
31
    // Cache static properties
32
    //
33
    /////////////////////////////////////////////////////////////////////////////
34
Y.mix(Cache, {
35
    /**
36
     * Class name.
37
     *
38
     * @property NAME
39
     * @type String
40
     * @static
41
     * @final
42
     * @value "cache"
43
     */
44
    NAME: "cache",
45
 
46
 
47
    ATTRS: {
48
        /////////////////////////////////////////////////////////////////////////////
49
        //
50
        // Cache Attributes
51
        //
52
        /////////////////////////////////////////////////////////////////////////////
53
 
54
        /**
55
        * @attribute max
56
        * @description Maximum number of entries the Cache can hold.
57
        * Set to 0 to turn off caching.
58
        * @type Number
59
        * @default 0
60
        */
61
        max: {
62
            value: 0,
63
            setter: "_setMax"
64
        },
65
 
66
        /**
67
        * @attribute size
68
        * @description Number of entries currently cached.
69
        * @type Number
70
        */
71
        size: {
72
            readOnly: true,
73
            getter: "_getSize"
74
        },
75
 
76
        /**
77
        * @attribute uniqueKeys
78
        * @description Validate uniqueness of stored keys. Default is false and
79
        * is more performant.
80
        * @type Boolean
81
        */
82
        uniqueKeys: {
83
            value: false
84
        },
85
 
86
        /**
87
        * @attribute expires
88
        * @description Absolute Date when data expires or
89
        * relative number of milliseconds. Zero disables expiration.
90
        * @type Date | Number
91
        * @default 0
92
        */
93
        expires: {
94
            value: 0,
95
            validator: function(v) {
96
                return Y.Lang.isDate(v) || (Y.Lang.isNumber(v) && v >= 0);
97
            }
98
        },
99
 
100
        /**
101
         * @attribute entries
102
         * @description Cached entries.
103
         * @type Array
104
         */
105
        entries: {
106
            readOnly: true,
107
            getter: "_getEntries"
108
        }
109
    }
110
});
111
 
112
Y.extend(Cache, Y.Base, {
113
    /////////////////////////////////////////////////////////////////////////////
114
    //
115
    // Cache private properties
116
    //
117
    /////////////////////////////////////////////////////////////////////////////
118
 
119
    /**
120
     * Array of request/response objects indexed chronologically.
121
     *
122
     * @property _entries
123
     * @type Object[]
124
     * @private
125
     */
126
    _entries: null,
127
 
128
    /////////////////////////////////////////////////////////////////////////////
129
    //
130
    // Cache private methods
131
    //
132
    /////////////////////////////////////////////////////////////////////////////
133
 
134
    /**
135
    * @method initializer
136
    * @description Internal init() handler.
137
    * @param config {Object} Config object.
138
    * @private
139
    */
140
    initializer: function(config) {
141
 
142
        /**
143
        * @event add
144
        * @description Fired when an entry is added.
145
        * @param e {EventFacade} Event Facade with the following properties:
146
         * <dl>
147
         * <dt>entry (Object)</dt> <dd>The cached entry.</dd>
148
         * </dl>
149
        * @preventable _defAddFn
150
        */
151
        this.publish("add", {defaultFn: this._defAddFn});
152
 
153
        /**
154
        * @event flush
155
        * @description Fired when the cache is flushed.
156
        * @param e {EventFacade} Event Facade object.
157
        * @preventable _defFlushFn
158
        */
159
        this.publish("flush", {defaultFn: this._defFlushFn});
160
 
161
        /**
162
        * @event request
163
        * @description Fired when an entry is requested from the cache.
164
        * @param e {EventFacade} Event Facade with the following properties:
165
        * <dl>
166
        * <dt>request (Object)</dt> <dd>The request object.</dd>
167
        * </dl>
168
        */
169
 
170
        /**
171
        * @event retrieve
172
        * @description Fired when an entry is retrieved from the cache.
173
        * @param e {EventFacade} Event Facade with the following properties:
174
        * <dl>
175
        * <dt>entry (Object)</dt> <dd>The retrieved entry.</dd>
176
        * </dl>
177
        */
178
 
179
        // Initialize internal values
180
        this._entries = [];
181
    },
182
 
183
    /**
184
    * @method destructor
185
    * @description Internal destroy() handler.
186
    * @private
187
    */
188
    destructor: function() {
189
        this._entries = [];
190
    },
191
 
192
    /////////////////////////////////////////////////////////////////////////////
193
    //
194
    // Cache protected methods
195
    //
196
    /////////////////////////////////////////////////////////////////////////////
197
 
198
    /**
199
     * Sets max.
200
     *
201
     * @method _setMax
202
     * @protected
203
     */
204
    _setMax: function(value) {
205
        // If the cache is full, make room by removing stalest element (index=0)
206
        var entries = this._entries;
207
        if(value > 0) {
208
            if(entries) {
209
                while(entries.length > value) {
210
                    entries.shift();
211
                }
212
            }
213
        }
214
        else {
215
            value = 0;
216
            this._entries = [];
217
        }
218
        return value;
219
    },
220
 
221
    /**
222
     * Gets size.
223
     *
224
     * @method _getSize
225
     * @protected
226
     */
227
    _getSize: function() {
228
        return this._entries.length;
229
    },
230
 
231
    /**
232
     * Gets all entries.
233
     *
234
     * @method _getEntries
235
     * @protected
236
     */
237
    _getEntries: function() {
238
        return this._entries;
239
    },
240
 
241
 
242
    /**
243
     * Adds entry to cache.
244
     *
245
     * @method _defAddFn
246
     * @param e {EventFacade} Event Facade with the following properties:
247
     * <dl>
248
     * <dt>entry (Object)</dt> <dd>The cached entry.</dd>
249
     * </dl>
250
     * @protected
251
     */
252
    _defAddFn: function(e) {
253
        var entries = this._entries,
254
            entry   = e.entry,
255
            max     = this.get("max"),
256
            pos;
257
 
258
        // If uniqueKeys is true and item exists with this key, then remove it.
259
        if (this.get("uniqueKeys")) {
260
            pos = this._position(e.entry.request);
261
            if (LANG.isValue(pos)) {
262
                entries.splice(pos, 1);
263
            }
264
        }
265
 
266
        // If the cache at or over capacity, make room by removing stalest
267
        // element(s) starting at index-0.
268
        while (max && entries.length >= max) {
269
            entries.shift();
270
        }
271
 
272
        // Add entry to cache in the newest position, at the end of the array
273
        entries[entries.length] = entry;
274
    },
275
 
276
    /**
277
     * Flushes cache.
278
     *
279
     * @method _defFlushFn
280
     * @param e {EventFacade} Event Facade object.
281
     * @protected
282
     */
283
    _defFlushFn: function(e) {
284
        var entries = this._entries,
285
            details = e.details[0],
286
            pos;
287
 
288
        //passed an item, flush only that
289
        if(details && LANG.isValue(details.request)) {
290
            pos = this._position(details.request);
291
 
292
            if(LANG.isValue(pos)) {
293
                entries.splice(pos,1);
294
 
295
            }
296
        }
297
        //no item, flush everything
298
        else {
299
            this._entries = [];
300
        }
301
    },
302
 
303
    /**
304
     * Default overridable method compares current request with given cache entry.
305
     * Returns true if current request matches the cached request, otherwise
306
     * false. Implementers should override this method to customize the
307
     * cache-matching algorithm.
308
     *
309
     * @method _isMatch
310
     * @param request {Object} Request object.
311
     * @param entry {Object} Cached entry.
312
     * @return {Boolean} True if current request matches given cached request, false otherwise.
313
     * @protected
314
     */
315
    _isMatch: function(request, entry) {
316
        if(!entry.expires || new Date() < entry.expires) {
317
            return (request === entry.request);
318
        }
319
        return false;
320
    },
321
 
322
    /**
323
     * Returns position of a request in the entries array, otherwise null.
324
     *
325
     * @method _position
326
     * @param request {Object} Request object.
327
     * @return {Number} Array position if found, null otherwise.
328
     * @protected
329
     */
330
    _position: function(request) {
331
        // If cache is enabled...
332
        var entries = this._entries,
333
            length = entries.length,
334
            i = length-1;
335
 
336
        if((this.get("max") === null) || this.get("max") > 0) {
337
            // Loop through each cached entry starting from the newest
338
            for(; i >= 0; i--) {
339
                // Execute matching function
340
                if(this._isMatch(request, entries[i])) {
341
                    return i;
342
                }
343
            }
344
        }
345
 
346
        return null;
347
    },
348
 
349
    /////////////////////////////////////////////////////////////////////////////
350
    //
351
    // Cache public methods
352
    //
353
    /////////////////////////////////////////////////////////////////////////////
354
 
355
    /**
356
     * Adds a new entry to the cache of the format
357
     * {request:request, response:response, cached:cached, expires:expires}.
358
     * If cache is full, evicts the stalest entry before adding the new one.
359
     *
360
     * @method add
361
     * @param request {Object} Request value.
362
     * @param response {Object} Response value.
363
     */
364
    add: function(request, response) {
365
        var expires = this.get("expires");
366
        if(this.get("initialized") && ((this.get("max") === null) || this.get("max") > 0) &&
367
                (LANG.isValue(request) || LANG.isNull(request) || LANG.isUndefined(request))) {
368
            this.fire("add", {entry: {
369
                request:request,
370
                response:response,
371
                cached: new Date(),
372
                expires: isDate(expires) ? expires :
373
            (expires ? new Date(new Date().getTime() + this.get("expires")) : null)
374
            }});
375
        }
376
        else {
377
        }
378
    },
379
 
380
    /**
381
     * Flushes cache.
382
     *
383
     * @method flush
384
     */
385
    flush: function(request) {
386
        this.fire("flush", { request: (LANG.isValue(request) ? request : null) });
387
    },
388
 
389
    /**
390
     * Retrieves cached object for given request, if available, and refreshes
391
     * entry in the cache. Returns null if there is no cache match.
392
     *
393
     * @method retrieve
394
     * @param request {Object} Request object.
395
     * @return {Object} Cached object with the properties request and response, or null.
396
     */
397
    retrieve: function(request) {
398
        // If cache is enabled...
399
        var entries = this._entries,
400
            length = entries.length,
401
            entry = null,
402
            pos;
403
 
404
        if((length > 0) && ((this.get("max") === null) || (this.get("max") > 0))) {
405
            this.fire("request", {request: request});
406
 
407
            pos = this._position(request);
408
 
409
            if(LANG.isValue(pos)) {
410
                entry = entries[pos];
411
 
412
                this.fire("retrieve", {entry: entry});
413
 
414
                // Refresh the position of the cache hit
415
                if(pos < length-1) {
416
                    // Remove element from its original location
417
                    entries.splice(pos,1);
418
                    // Add as newest
419
                    entries[entries.length] = entry;
420
                }
421
 
422
                return entry;
423
            }
424
        }
425
        return null;
426
    }
427
});
428
 
429
Y.Cache = Cache;
430
 
431
 
432
}, '3.18.1', {"requires": ["base"]});