Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
YUI.add('cookie', function (Y, NAME) {
2
 
3
/**
4
 * Utilities for cookie management
5
 * @module cookie
6
 */
7
 
8
    //shortcuts
9
    var L       = Y.Lang,
10
        O       = Y.Object,
11
        NULL    = null,
12
 
13
        //shortcuts to functions
14
        isString    = L.isString,
15
        isObject    = L.isObject,
16
        isUndefined = L.isUndefined,
17
        isFunction  = L.isFunction,
18
        encode      = encodeURIComponent,
19
        decode      = decodeURIComponent,
20
 
21
        //shortcut to document
22
        doc         = Y.config.doc;
23
 
24
    /*
25
     * Throws an error message.
26
     */
27
    function error(message){
28
        throw new TypeError(message);
29
    }
30
 
31
    /*
32
     * Checks the validity of a cookie name.
33
     */
34
    function validateCookieName(name){
35
        if (!isString(name) || name === ""){
36
            error("Cookie name must be a non-empty string.");
37
        }
38
    }
39
 
40
    /*
41
     * Checks the validity of a subcookie name.
42
     */
43
    function validateSubcookieName(subName){
44
        if (!isString(subName) || subName === ""){
45
            error("Subcookie name must be a non-empty string.");
46
        }
47
    }
48
 
49
    /**
50
     * Cookie utility.
51
     * @class Cookie
52
     * @static
53
     */
54
    Y.Cookie = {
55
 
56
        //-------------------------------------------------------------------------
57
        // Private Methods
58
        //-------------------------------------------------------------------------
59
 
60
        /**
61
         * Creates a cookie string that can be assigned into document.cookie.
62
         * @param {String} name The name of the cookie.
63
         * @param {String} value The value of the cookie.
64
         * @param {Boolean} encodeValue True to encode the value, false to leave as-is.
65
         * @param {Object} options (Optional) Options for the cookie.
66
         * @return {String} The formatted cookie string.
67
         * @method _createCookieString
68
         * @private
69
         * @static
70
         */
71
        _createCookieString : function (name /*:String*/, value /*:Variant*/, encodeValue /*:Boolean*/, options /*:Object*/) /*:String*/ {
72
 
73
            options = options || {};
74
 
75
            var text /*:String*/ = encode(name) + "=" + (encodeValue ? encode(value) : value),
76
                expires = options.expires,
77
                path    = options.path,
78
                domain  = options.domain;
79
 
80
 
81
            if (isObject(options)){
82
                //expiration date
83
                if (expires instanceof Date){
84
                    text += "; expires=" + expires.toUTCString();
85
                }
86
 
87
                //path
88
                if (isString(path) && path !== ""){
89
                    text += "; path=" + path;
90
                }
91
 
92
                //domain
93
                if (isString(domain) && domain !== ""){
94
                    text += "; domain=" + domain;
95
                }
96
 
97
                //secure
98
                if (options.secure === true){
99
                    text += "; secure";
100
                }
101
            }
102
 
103
            return text;
104
        },
105
 
106
        /**
107
         * Formats a cookie value for an object containing multiple values.
108
         * @param {Object} hash An object of key-value pairs to create a string for.
109
         * @return {String} A string suitable for use as a cookie value.
110
         * @method _createCookieHashString
111
         * @private
112
         * @static
113
         */
114
        _createCookieHashString : function (hash /*:Object*/) /*:String*/ {
115
            if (!isObject(hash)){
116
                error("Cookie._createCookieHashString(): Argument must be an object.");
117
            }
118
 
119
            var text /*:Array*/ = [];
120
 
121
            O.each(hash, function(value, key){
122
                if (!isFunction(value) && !isUndefined(value)){
123
                    text.push(encode(key) + "=" + encode(String(value)));
124
                }
125
            });
126
 
127
            return text.join("&");
128
        },
129
 
130
        /**
131
         * Parses a cookie hash string into an object.
132
         * @param {String} text The cookie hash string to parse (format: n1=v1&n2=v2).
133
         * @return {Object} An object containing entries for each cookie value.
134
         * @method _parseCookieHash
135
         * @private
136
         * @static
137
         */
138
        _parseCookieHash : function (text) {
139
 
140
            var hashParts   = text.split("&"),
141
                hashPart    = NULL,
142
                hash        = {};
143
 
144
            if (text.length){
145
                for (var i=0, len=hashParts.length; i < len; i++){
146
                    hashPart = hashParts[i].split("=");
147
                    hash[decode(hashPart[0])] = decode(hashPart[1]);
148
                }
149
            }
150
 
151
            return hash;
152
        },
153
 
154
        /**
155
         * Parses a cookie string into an object representing all accessible cookies.
156
         * @param {String} text The cookie string to parse.
157
         * @param {Boolean} shouldDecode (Optional) Indicates if the cookie values should be decoded or not. Default is true.
158
         * @param {Object} options (Optional) Contains settings for loading the cookie.
159
         * @return {Object} An object containing entries for each accessible cookie.
160
         * @method _parseCookieString
161
         * @private
162
         * @static
163
         */
164
        _parseCookieString : function (text /*:String*/, shouldDecode /*:Boolean*/, options /*:Object*/) /*:Object*/ {
165
 
166
            var cookies /*:Object*/ = {};
167
 
168
            if (isString(text) && text.length > 0) {
169
 
170
                var decodeValue = (shouldDecode === false ? function(s){return s;} : decode),
171
                    cookieParts = text.split(/;\s/g),
172
                    cookieName  = NULL,
173
                    cookieValue = NULL,
174
                    cookieNameValue = NULL;
175
 
176
                for (var i=0, len=cookieParts.length; i < len; i++){
177
                    //check for normally-formatted cookie (name-value)
178
                    cookieNameValue = cookieParts[i].match(/([^=]+)=/i);
179
                    if (cookieNameValue instanceof Array){
180
                        try {
181
                            cookieName = decode(cookieNameValue[1]);
182
                            cookieValue = decodeValue(cookieParts[i].substring(cookieNameValue[1].length+1));
183
                        } catch (ex){
184
                            //intentionally ignore the cookie - the encoding is wrong
185
                        }
186
                    } else {
187
                        //means the cookie does not have an "=", so treat it as a boolean flag
188
                        cookieName = decode(cookieParts[i]);
189
                        cookieValue = "";
190
                    }
191
                    // don't overwrite an already loaded cookie if set by option
192
                    if (!isUndefined(options) && options.reverseCookieLoading) {
193
                        if (isUndefined(cookies[cookieName])) {
194
                            cookies[cookieName] = cookieValue;
195
                        }
196
                    } else {
197
                        cookies[cookieName] = cookieValue;
198
                    }
199
                }
200
 
201
            }
202
 
203
            return cookies;
204
        },
205
 
206
        /**
207
         * Sets the document object that the cookie utility uses for setting
208
         * cookies. This method is necessary to ensure that the cookie utility
209
         * unit tests can pass even when run on a domain instead of locally.
210
         * This method should not be used otherwise; you should use
211
         * <code>Y.config.doc</code> to change the document that the cookie
212
         * utility uses for everyday purposes.
213
         * @param {Object} newDoc The object to use as the document.
214
         * @method _setDoc
215
         * @private
216
         */
217
        _setDoc: function(newDoc){
218
            doc = newDoc;
219
        },
220
 
221
        //-------------------------------------------------------------------------
222
        // Public Methods
223
        //-------------------------------------------------------------------------
224
 
225
        /**
226
         * Determines if the cookie with the given name exists. This is useful for
227
         * Boolean cookies (those that do not follow the name=value convention).
228
         * @param {String} name The name of the cookie to check.
229
         * @return {Boolean} True if the cookie exists, false if not.
230
         * @method exists
231
         * @static
232
         */
233
        exists: function(name) {
234
 
235
            validateCookieName(name);   //throws error
236
 
237
            var cookies = this._parseCookieString(doc.cookie, true);
238
 
239
            return cookies.hasOwnProperty(name);
240
        },
241
 
242
        /**
243
         * Returns the cookie value for the given name.
244
         * @param {String} name The name of the cookie to retrieve.
245
         * @param {Function|Object} options (Optional) An object containing one or more
246
         *      cookie options: raw (true/false), reverseCookieLoading (true/false)
247
         *      and converter (a function).
248
         *      The converter function is run on the value before returning it. The
249
         *      function is not used if the cookie doesn't exist. The function can be
250
         *      passed instead of the options object for backwards compatibility. When
251
         *      raw is set to true, the cookie value is not URI decoded.
252
         * @return {Any} If no converter is specified, returns a string or null if
253
         *      the cookie doesn't exist. If the converter is specified, returns the value
254
         *      returned from the converter or null if the cookie doesn't exist.
255
         * @method get
256
         * @static
257
         */
258
        get : function (name, options) {
259
 
260
            validateCookieName(name);   //throws error
261
 
262
            var cookies,
263
                cookie,
264
                converter;
265
 
266
            //if options is a function, then it's the converter
267
            if (isFunction(options)) {
268
                converter = options;
269
                options = {};
270
            } else if (isObject(options)) {
271
                converter = options.converter;
272
            } else {
273
                options = {};
274
            }
275
 
276
            cookies = this._parseCookieString(doc.cookie, !options.raw, options);
277
            cookie = cookies[name];
278
 
279
            //should return null, not undefined if the cookie doesn't exist
280
            if (isUndefined(cookie)) {
281
                return NULL;
282
            }
283
 
284
            if (!isFunction(converter)){
285
                return cookie;
286
            } else {
287
                return converter(cookie);
288
            }
289
        },
290
 
291
        /**
292
         * Returns the value of a subcookie.
293
         * @param {String} name The name of the cookie to retrieve.
294
         * @param {String} subName The name of the subcookie to retrieve.
295
         * @param {Function} converter (Optional) A function to run on the value before returning
296
         *      it. The function is not used if the cookie doesn't exist.
297
         * @param {Object} options (Optional) Containing one or more settings for cookie parsing.
298
         * @return {Any} If the cookie doesn't exist, null is returned. If the subcookie
299
         *      doesn't exist, null if also returned. If no converter is specified and the
300
         *      subcookie exists, a string is returned. If a converter is specified and the
301
         *      subcookie exists, the value returned from the converter is returned.
302
         * @method getSub
303
         * @static
304
         */
305
        getSub : function (name /*:String*/, subName /*:String*/, converter /*:Function*/, options /*:Object*/) /*:Variant*/ {
306
 
307
            var hash /*:Variant*/ = this.getSubs(name, options);
308
 
309
            if (hash !== NULL) {
310
 
311
                validateSubcookieName(subName);   //throws error
312
 
313
                if (isUndefined(hash[subName])){
314
                    return NULL;
315
                }
316
 
317
                if (!isFunction(converter)){
318
                    return hash[subName];
319
                } else {
320
                    return converter(hash[subName]);
321
                }
322
            } else {
323
                return NULL;
324
            }
325
 
326
        },
327
 
328
        /**
329
         * Returns an object containing name-value pairs stored in the cookie with the given name.
330
         * @param {String} name The name of the cookie to retrieve.
331
         * @param {Object} options (Optional) Containing one or more settings for cookie parsing.
332
         * @return {Object} An object of name-value pairs if the cookie with the given name
333
         *      exists, null if it does not.
334
         * @method getSubs
335
         * @static
336
         */
337
        getSubs : function (name /*:String*/, options /*:Object*/) {
338
 
339
            validateCookieName(name);   //throws error
340
 
341
            var cookies = this._parseCookieString(doc.cookie, false, options);
342
            if (isString(cookies[name])){
343
                return this._parseCookieHash(cookies[name]);
344
            }
345
            return NULL;
346
        },
347
 
348
        /**
349
         * Removes a cookie from the machine by setting its expiration date to
350
         * sometime in the past.
351
         * @param {String} name The name of the cookie to remove.
352
         * @param {Object} options (Optional) An object containing one or more
353
         *      cookie options: path (a string), domain (a string),
354
         *      and secure (true/false). The expires option will be overwritten
355
         *      by the method.
356
         * @return {String} The created cookie string.
357
         * @method remove
358
         * @static
359
         */
360
        remove : function (name, options) {
361
 
362
            validateCookieName(name);   //throws error
363
 
364
            //set options
365
            options = Y.merge(options || {}, {
366
                expires: new Date(0)
367
            });
368
 
369
            //set cookie
370
            return this.set(name, "", options);
371
        },
372
 
373
        /**
374
         * Removes a sub cookie with a given name.
375
         * @param {String} name The name of the cookie in which the subcookie exists.
376
         * @param {String} subName The name of the subcookie to remove.
377
         * @param {Object} options (Optional) An object containing one or more
378
         *      cookie options: path (a string), domain (a string), expires (a Date object),
379
         *      removeIfEmpty (true/false), and secure (true/false). This must be the same
380
         *      settings as the original subcookie.
381
         * @return {String} The created cookie string.
382
         * @method removeSub
383
         * @static
384
         */
385
        removeSub : function(name, subName, options) {
386
 
387
            validateCookieName(name);   //throws error
388
 
389
            validateSubcookieName(subName);   //throws error
390
 
391
            options = options || {};
392
 
393
            //get all subcookies for this cookie
394
            var subs = this.getSubs(name);
395
 
396
            //delete the indicated subcookie
397
            if (isObject(subs) && subs.hasOwnProperty(subName)){
398
                delete subs[subName];
399
 
400
                if (!options.removeIfEmpty) {
401
                    //reset the cookie
402
 
403
                    return this.setSubs(name, subs, options);
404
                } else {
405
                    //reset the cookie if there are subcookies left, else remove
406
                    for (var key in subs){
407
                        if (subs.hasOwnProperty(key) && !isFunction(subs[key]) && !isUndefined(subs[key])){
408
                            return this.setSubs(name, subs, options);
409
                        }
410
                    }
411
 
412
                    return this.remove(name, options);
413
                }
414
            } else {
415
                return "";
416
            }
417
 
418
        },
419
 
420
        /**
421
         * Sets a cookie with a given name and value.
422
         * @param {String} name The name of the cookie to set.
423
         * @param {Any} value The value to set for the cookie.
424
         * @param {Object} options (Optional) An object containing one or more
425
         *      cookie options: path (a string), domain (a string), expires (a Date object),
426
         *      secure (true/false), and raw (true/false). Setting raw to true indicates
427
         *      that the cookie should not be URI encoded before being set.
428
         * @return {String} The created cookie string.
429
         * @method set
430
         * @static
431
         */
432
        set : function (name, value, options) {
433
 
434
            validateCookieName(name);   //throws error
435
 
436
            if (isUndefined(value)){
437
                error("Cookie.set(): Value cannot be undefined.");
438
            }
439
 
440
            options = options || {};
441
 
442
            var text = this._createCookieString(name, value, !options.raw, options);
443
            doc.cookie = text;
444
            return text;
445
        },
446
 
447
        /**
448
         * Sets a sub cookie with a given name to a particular value.
449
         * @param {String} name The name of the cookie to set.
450
         * @param {String} subName The name of the subcookie to set.
451
         * @param {Any} value The value to set.
452
         * @param {Object} options (Optional) An object containing one or more
453
         *      cookie options: path (a string), domain (a string), expires (a Date object),
454
         *      and secure (true/false).
455
         * @return {String} The created cookie string.
456
         * @method setSub
457
         * @static
458
         */
459
        setSub : function (name, subName, value, options) {
460
 
461
            validateCookieName(name);   //throws error
462
 
463
            validateSubcookieName(subName);   //throws error
464
 
465
            if (isUndefined(value)){
466
                error("Cookie.setSub(): Subcookie value cannot be undefined.");
467
            }
468
 
469
            var hash = this.getSubs(name);
470
 
471
            if (!isObject(hash)){
472
                hash = {};
473
            }
474
 
475
            hash[subName] = value;
476
 
477
            return this.setSubs(name, hash, options);
478
 
479
        },
480
 
481
        /**
482
         * Sets a cookie with a given name to contain a hash of name-value pairs.
483
         * @param {String} name The name of the cookie to set.
484
         * @param {Object} value An object containing name-value pairs.
485
         * @param {Object} options (Optional) An object containing one or more
486
         *      cookie options: path (a string), domain (a string), expires (a Date object),
487
         *      and secure (true/false).
488
         * @return {String} The created cookie string.
489
         * @method setSubs
490
         * @static
491
         */
492
        setSubs : function (name, value, options) {
493
 
494
            validateCookieName(name);   //throws error
495
 
496
            if (!isObject(value)){
497
                error("Cookie.setSubs(): Cookie value must be an object.");
498
            }
499
 
500
            var text /*:String*/ = this._createCookieString(name, this._createCookieHashString(value), false, options);
501
            doc.cookie = text;
502
            return text;
503
        }
504
 
505
    };
506
 
507
 
508
}, '3.18.1', {"requires": ["yui-base"]});