( function () {
'use strict';
+ var config = require( './config.json' ),
+ defaults = {
+ prefix: config.prefix,
+ domain: config.domain,
+ path: config.path,
+ expires: config.expires,
+ secure: false
+ };
+
/**
- * Provides an API for getting and setting cookies that is
- * syntactically and functionally similar to the server-side cookie
- * API (`WebRequest#getCookie` and `WebResponse#setcookie`).
+ * Manage cookies in a way that is syntactically and functionally similar
+ * to the `WebRequest#getCookie` and `WebResponse#setcookie` methods in PHP.
*
* @author Sam Smith <samsmith@wikimedia.org>
* @author Matthew Flaschen <mflaschen@wikimedia.org>
- * @author Timo Tijhof <krinklemail@gmail.com>
*
* @class mw.cookie
* @singleton
/**
* Set or delete a cookie.
*
- * While this is natural in JavaScript, contrary to `WebResponse#setcookie` in PHP, the
- * default values for the `options` properties only apply if that property isn't set
- * already in your options object (e.g. passing `{ secure: null }` or `{ secure: undefined }`
- * overrides the default value for `options.secure`).
+ * **Note:** If explicitly passing `null` or `undefined` for an options key,
+ * that will override the default. This is natural in JavaScript, but noted
+ * here because it is contrary to MediaWiki's `WebResponse#setcookie()` method
+ * in PHP.
*
* @param {string} key
* @param {string|null} value Value of cookie. If `value` is `null` then this method will
* instead remove a cookie by name of `key`.
* @param {Object|Date|number} [options] Options object, or expiry date
- * @param {Date|number|null} [options.expires] The expiry date of the cookie, or lifetime in seconds.
- *
- * If `options.expires` is null, then a session cookie is set.
- *
- * By default cookie expiration is based on `wgCookieExpiration`. Similar to `WebResponse`
- * in PHP, we set a session cookie if `wgCookieExpiration` is 0. And for non-zero values
- * it is interpreted as lifetime in seconds.
- *
+ * @param {Date|number|null} [options.expires=wgCookieExpiration] The expiry date of the cookie,
+ * or lifetime in seconds. If `options.expires` is null or 0, then a session cookie is set.
* @param {string} [options.prefix=wgCookiePrefix] The prefix of the key
* @param {string} [options.domain=wgCookieDomain] The domain attribute of the cookie
* @param {string} [options.path=wgCookiePath] The path attribute of the cookie
* (Does **not** use the wgCookieSecure configuration variable)
*/
set: function ( key, value, options ) {
- var config, defaultOptions, date;
-
- // wgCookieSecure is not used for now, since 'detect' could not work with
- // ResourceLoaderStartUpModule, as module cache is not fragmented by protocol.
- config = mw.config.get( [
- 'wgCookiePrefix',
- 'wgCookieDomain',
- 'wgCookiePath',
- 'wgCookieExpiration'
- ] );
+ var date;
- defaultOptions = {
- prefix: config.wgCookiePrefix,
- domain: config.wgCookieDomain,
- path: config.wgCookiePath,
- secure: false
- };
-
- // Options argument can also be a shortcut for the expiry
- // Expiry can be a Date, number or null
- if ( !options || options instanceof Date || typeof options === 'number' ) {
- // Also takes care of options = undefined, in which case we also don't need $.extend()
- defaultOptions.expires = options;
- options = defaultOptions;
- } else {
- options = $.extend( defaultOptions, options );
+ // The 'options' parameter may be a shortcut for the expiry.
+ if ( arguments.length > 2 && ( !options || options instanceof Date || typeof options === 'number' ) ) {
+ options = { expires: options };
}
+ // Apply defaults
+ options = $.extend( {}, defaults, options );
- // Default to using wgCookieExpiration (lifetime in seconds).
- // If wgCookieExpiration is 0, that is considered a special value indicating
- // all cookies should be session cookies by default.
- if ( options.expires === undefined && config.wgCookieExpiration !== 0 ) {
- date = new Date();
- date.setTime( Number( date ) + ( config.wgCookieExpiration * 1000 ) );
- options.expires = date;
+ // Handle prefix
+ key = options.prefix + key;
+ // Don't pass invalid option to $.cookie
+ delete options.prefix;
+
+ if ( !options.expires ) {
+ // Session cookie (null or zero)
+ // Normalize to absent (undefined) for $.cookie.
+ delete options.expires;
} else if ( typeof options.expires === 'number' ) {
// Lifetime in seconds
date = new Date();
date.setTime( Number( date ) + ( options.expires * 1000 ) );
options.expires = date;
- } else if ( options.expires === null ) {
- // $.cookie makes a session cookie when options.expires is omitted
- delete options.expires;
}
- // Process prefix
- key = options.prefix + key;
- delete options.prefix;
-
- // Process value
if ( value !== null ) {
value = String( value );
}
- // Other options are handled by $.cookie
$.cookie( key, value, options );
},
var result;
if ( prefix === undefined || prefix === null ) {
- prefix = mw.config.get( 'wgCookiePrefix' );
+ prefix = defaults.prefix;
}
// Was defaultValue omitted?
}
};
+ if ( window.QUnit ) {
+ module.exports = {
+ setDefaults: function ( value ) {
+ var prev = defaults;
+ defaults = value;
+ return prev;
+ }
+ };
+ }
}() );
var NOW = 9012, // miliseconds
DEFAULT_DURATION = 5678, // seconds
+ jqcookie,
+ defaults = {
+ prefix: 'mywiki',
+ domain: 'example.org',
+ path: '/path',
+ expires: DEFAULT_DURATION,
+ secure: false
+ },
+ setDefaults = require( 'mediawiki.cookie' ).setDefaults,
expiryDate = new Date();
expiryDate.setTime( NOW + ( DEFAULT_DURATION * 1000 ) );
- QUnit.module( 'mediawiki.cookie', QUnit.newMwEnvironment( {
- setup: function () {
- this.stub( $, 'cookie' ).returns( null );
-
- this.sandbox.useFakeTimers( NOW );
+ QUnit.module( 'mediawiki.cookie', {
+ beforeEach: function () {
+ jqcookie = sinon.stub( $, 'cookie' ).returns( null );
+ this.clock = sinon.useFakeTimers( NOW );
+ this.savedDefaults = setDefaults( defaults );
},
- config: {
- wgCookiePrefix: 'mywiki',
- wgCookieDomain: 'example.org',
- wgCookiePath: '/path',
- wgCookieExpiration: DEFAULT_DURATION
+ afterEach: function () {
+ jqcookie.restore();
+ this.clock.restore();
+ setDefaults( this.savedDefaults );
}
- } ) );
+ } );
QUnit.test( 'set( key, value )', function ( assert ) {
var call;
// Simple case
mw.cookie.set( 'foo', 'bar' );
- call = $.cookie.lastCall.args;
+ call = jqcookie.lastCall.args;
assert.strictEqual( call[ 0 ], 'mywikifoo' );
assert.strictEqual( call[ 1 ], 'bar' );
assert.deepEqual( call[ 2 ], {
} );
mw.cookie.set( 'foo', null );
- call = $.cookie.lastCall.args;
+ call = jqcookie.lastCall.args;
assert.strictEqual( call[ 1 ], null, 'null removes cookie' );
mw.cookie.set( 'foo', undefined );
- call = $.cookie.lastCall.args;
+ call = jqcookie.lastCall.args;
assert.strictEqual( call[ 1 ], 'undefined', 'undefined is value' );
mw.cookie.set( 'foo', false );
- call = $.cookie.lastCall.args;
+ call = jqcookie.lastCall.args;
assert.strictEqual( call[ 1 ], 'false', 'false is a value' );
mw.cookie.set( 'foo', 0 );
- call = $.cookie.lastCall.args;
+ call = jqcookie.lastCall.args;
assert.strictEqual( call[ 1 ], '0', '0 is value' );
} );
date.setTime( 1234 );
mw.cookie.set( 'foo', 'bar' );
- options = $.cookie.lastCall.args[ 2 ];
+ options = jqcookie.lastCall.args[ 2 ];
assert.deepEqual( options.expires, expiryDate, 'default expiration' );
mw.cookie.set( 'foo', 'bar', date );
- options = $.cookie.lastCall.args[ 2 ];
+ options = jqcookie.lastCall.args[ 2 ];
assert.strictEqual( options.expires, date, 'custom expiration as Date' );
date = new Date();
date.setDate( date.getDate() + 1 );
mw.cookie.set( 'foo', 'bar', 86400 );
- options = $.cookie.lastCall.args[ 2 ];
+ options = jqcookie.lastCall.args[ 2 ];
assert.deepEqual( options.expires, date, 'custom expiration as lifetime in seconds' );
mw.cookie.set( 'foo', 'bar', null );
- options = $.cookie.lastCall.args[ 2 ];
+ options = jqcookie.lastCall.args[ 2 ];
assert.strictEqual( options.expires, undefined, 'null forces session cookie' );
- // Per DefaultSettings.php, when wgCookieExpiration is 0, the default should
- // be session cookies
- mw.config.set( 'wgCookieExpiration', 0 );
+ // Per DefaultSettings.php, if wgCookieExpiration is 0,
+ // then the default should be session cookies
+ setDefaults( $.extend( {}, defaults, { expires: 0 } ) );
mw.cookie.set( 'foo', 'bar' );
- options = $.cookie.lastCall.args[ 2 ];
+ options = jqcookie.lastCall.args[ 2 ];
assert.strictEqual( options.expires, undefined, 'wgCookieExpiration=0 results in session cookies by default' );
mw.cookie.set( 'foo', 'bar', date );
- options = $.cookie.lastCall.args[ 2 ];
+ options = jqcookie.lastCall.args[ 2 ];
assert.strictEqual( options.expires, date, 'custom expiration (with wgCookieExpiration=0)' );
} );
secure: true
} );
- call = $.cookie.lastCall.args;
+ call = jqcookie.lastCall.args;
assert.strictEqual( call[ 0 ], 'myPrefixfoo' );
assert.deepEqual( call[ 2 ], {
expires: expiryDate,
secure: true
} );
- call = $.cookie.lastCall.args;
+ call = jqcookie.lastCall.args;
assert.strictEqual( call[ 0 ], 'myPrefixfoo' );
assert.deepEqual( call[ 2 ], {
expires: date,
mw.cookie.get( 'foo' );
- key = $.cookie.lastCall.args[ 0 ];
+ key = jqcookie.lastCall.args[ 0 ];
assert.strictEqual( key, 'mywikifoo', 'Default prefix' );
mw.cookie.get( 'foo', undefined );
- key = $.cookie.lastCall.args[ 0 ];
+ key = jqcookie.lastCall.args[ 0 ];
assert.strictEqual( key, 'mywikifoo', 'Use default prefix for undefined' );
mw.cookie.get( 'foo', null );
- key = $.cookie.lastCall.args[ 0 ];
+ key = jqcookie.lastCall.args[ 0 ];
assert.strictEqual( key, 'mywikifoo', 'Use default prefix for null' );
mw.cookie.get( 'foo', '' );
- key = $.cookie.lastCall.args[ 0 ];
+ key = jqcookie.lastCall.args[ 0 ];
assert.strictEqual( key, 'foo', 'Don\'t use default prefix for empty string' );
value = mw.cookie.get( 'foo' );
QUnit.test( 'get( key ) - with value', function ( assert ) {
var value;
- $.cookie.returns( 'bar' );
+ jqcookie.returns( 'bar' );
value = mw.cookie.get( 'foo' );
assert.strictEqual( value, 'bar', 'Return value of cookie' );
mw.cookie.get( 'foo', 'bar' );
- key = $.cookie.lastCall.args[ 0 ];
+ key = jqcookie.lastCall.args[ 0 ];
assert.strictEqual( key, 'barfoo' );
} );