Permalink
Browse files

Add a Cookie library to Javelin

Summary:
Based on the MooTools Cookie lib, this is a Javelin-ized
version that includes as much of a unit test as makes sense. I also
hacked off parts of the API that didn't seem necessary.

Test Plan:
Tested in fbri.de, also 5ish years in Mooland. Also, unit
test.

Reviewers: epriestley, cpojer, leebyron, tomo

Reviewed By: epriestley

CC: aran, cpojer, epriestley, jg, leebyron

Differential Revision: 1175
  • Loading branch information...
1 parent 962470c commit 3ecf417b043ff38d858d667cc5e4c3367129afca Jackson Gabbard committed Nov 4, 2011
Showing with 152 additions and 0 deletions.
  1. +2 −0 specs/runner.html
  2. +102 −0 src/lib/Cookie.js
  3. +48 −0 src/lib/__tests__/Cookie.js
View
@@ -32,6 +32,7 @@
</script>
<script type="text/javascript" src="../src/lib/behavior.js"></script>
+<script type="text/javascript" src="../src/lib/Cookie.js"></script>
<script type="text/javascript" src="../src/lib/DOM.js"></script>
<script type="text/javascript" src="../src/lib/JSON.js"></script>
<script type="text/javascript" src="../src/lib/Mask.js"></script>
@@ -50,6 +51,7 @@
<script type="text/javascript" src="../src/lib/__tests__/URI.js"></script>
<script type="text/javascript" src="../src/lib/__tests__/JSON.js"></script>
<script type="text/javascript" src="../src/lib/__tests__/DOM.js"></script>
+<script type="text/javascript" src="../src/lib/__tests__/Cookie.js"></script>
<!-- ext/view source files -->
<script type="text/javascript" src="../src/ext/view/View.js"></script>
View
@@ -0,0 +1,102 @@
+/**
+ * @provides javelin-cookie
+ * @requires javelin-install
+ * javelin-util
+ * @javelin
+ */
+
+/*
+ * API/Wrapper for document cookie access and manipulation based heavily on the
+ * MooTools Cookie.js
+ *
+ * github.com/mootools/mootools-core/blob/master/Source/Utilities/Cookie.js
+ *
+ * Thx again, Moo.
+ */
+JX.install('Cookie', {
+
+ /**
+ * Setting cookies involves setting up a cookie object which is eventually
+ * written.
+ *
+ * var prefs = new JX.Cookie('prefs');
+ * prefs.setDaysToLive(5);
+ * prefs.setValue('1,0,10,1350');
+ * prefs.setSecure();
+ * prefs.write();
+ *
+ * Retrieving a cookie from the browser requires only a read() call on the
+ * cookie object. However, because cookies have such a complex API you may
+ * not be able to get your value this way if a path or domain was set when the
+ * cookie was written. Good luck with that.
+ *
+ * var prefs_string = new JX.Cookie('prefs').read();
+ *
+ * There is no real API in HTTP for deleting a cookie aside from setting the
+ * cookie to expire immediately. This dispose method will null out the value
+ * and expire the cookie as well.
+ *
+ * new JX.Cookie('prefs').dispose();
+ */
+ construct : function(key) {
+ if (__DEV__ &&
+ (!key.length ||
+ key.match(/^(?:expires|domain|path|secure)$/i) ||
+ key.match(/[\s,;]/) ||
+ key.indexOf('$') === 0)) {
+ JX.$E('JX.Cookie(): Invalid cookie name. "' + key + '" provided.');
+ }
+ this.setKey(key);
+ this.setTarget(document);
+ },
+
+ properties : {
+ key : null,
+ value : null,
+ domain : null,
+ path : null,
+ daysToLive : 0,
+ secure : true,
+ target : null
+ },
+
+ members : {
+ write : function() {
+ this.setValue(encodeURIComponent(this.getValue()));
+
+ var cookie_bits = [];
+ cookie_bits.push(this.getValue());
+
+ if (this.getDomain()) {
+ cookie_bits.push('Domain=' + this.getDomain());
+ }
+
+ if (this.getPath()) {
+ cookie_bits.push('Path=' + this.getPath());
+ }
+
+ var exp = new Date(JX.now() + this.getDaysToLive() * 1000 * 60 * 60 * 24);
+ cookie_bits.push('Expires=' + exp.toGMTString());
+
+ if (this.getSecure()) {
+ cookie_bits.push('Secure');
+ }
+
+ cookie_str = cookie_bits.join('; ') + ';';
+ var cookie_str = this.getKey() + '=' + cookie_str;
+ this.getTarget().cookie = cookie_str;
+ },
+
+ read : function() {
+ var key = this.getKey().replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
+ var val = this.getTarget().cookie.match('(?:^|;)\\s*' + key + '=([^;]*)');
+ return (val) ? decodeURIComponent(val[1]) : null;
+ },
+
+ dispose : function() {
+ this.setValue(null);
+ this.setDaysToLive(-1);
+ this.write();
+ }
+ }
+});
@@ -0,0 +1,48 @@
+/**
+ * @requires javelin-cookie
+ */
+
+/*
+ * These all are hope-and-pray tests because cookies have such a piss poor
+ * API in HTTP and offer so little insight from JS. This is just a
+ * supplement to the battle testing the cookie library has.
+ */
+describe('Javelin Cookie', function() {
+
+ it('should create a cookie string with the correct format', function() {
+ var doc = { cookie : null };
+ var c = new JX.Cookie('omnom');
+ c.setValue('nommy');
+ c.setDaysToLive(5);
+ c.setTarget(doc);
+ c.setPath('/');
+ c.setSecure(true);
+ c.write();
+
+ // Should be something like:
+ // omnom=nommy; path=/; expires=Sat, 10 Dec 2011 05:00:34 GMT; Secure;
+
+ expect(doc.cookie).toMatch(
+ /^omnom=nommy;\sPath=\/;\sExpires=[^;]+;\sSecure;/);
+ });
+
+ it('should properly encode and decode special chars in cookie values',
+ function() {
+ var value = '!@#$%^&*()?+|/=\\{}[]<>';
+ var doc = { cookie : null };
+ var c = new JX.Cookie('data');
+ c.setTarget(doc);
+ c.setValue(value);
+ c.write();
+
+ var data = doc.cookie.substr(0, doc.cookie.indexOf(';'));
+
+ // Make sure the raw value is all escaped
+ expect(data).toEqual(
+ 'data=!%40%23%24%25%5E%26*()%3F%2B%7C%2F%3D%5C%7B%7D%5B%5D%3C%3E');
+
+ // Make sure the retrieved value is all unescaped
+ expect(c.read()).toEqual(value);
+ });
+
+});

0 comments on commit 3ecf417

Please sign in to comment.