<!-- Importing cookie library Cookie.js provided by MyersDaily. For documentation see https://www.angelfire.com/yt/jmyers/bin/pod/Cookie.shtml. --> <script type="text/javascript" src="https://www.angelfire.com/yt/jmyers/free/Cookie.js"> </script>
The Cookie.js JavaScript module is a natural extension to JavaScript's built-in cookie capabilities. The document.cookie variable is a powerful dynamic property accessible to JavaScript authors. Unfortunately, however, there are no built-in methods able to be used.
Up till now using the document.cookie property has been a source of confusion for those not inclined to earn "guru" status. It's not a lack of usable cookie functions, but rather the fact that hardly anyone seems to understand how they work, or even how to use them!
In the past the "standard" cookie functions were the initial archaic ones by Bill Dortch of hIdaho Design (hats off to him). Ease-of-use has been compromised because there is not a de facto standard, especially not one which makes use of JS 1.2's capabilities (present in the overwhelming majority of browsers today).
Browser differences are very much of a problem too. A perfectly good set of cookie functions may totally flop on another browser because of a crazy browser-related compatibility fluke. These functions have been completely tested, but if you do find any bug please report it quickly.
Some of the benefits of this modularized library "scriptlet" are:
var Cookie = { pref:'',last:null, cnfg:function(a1) { var Bool={secure:1}, text=''; if (''+a1!==a1) for (var k in a1) if (a1[k]) text += '; '+( Bool[k] ? k : k+'='+( k!='expires'||isNaN(a1[k]) ? a1[k] : this.date(a1[k]) ) ); return this.pref = text||a1||text; }, make:function(a1,a2,a3) { document.cookie = this.last=escape(a1)+'='+escape(a2)+this.cnfg(a3); return this.read(a1) == a2; }, date:function(a1) { var D = new Date(); D.setTime(D.getTime()+(a1||0)*86400000); return D.toGMTString(); }, read:function(a1) { var F=' '+document.cookie+';', S=F.indexOf(' '+(a1=escape(a1))); return S==-1 ? null : unescape( F.substring(a1=S+a1.length+2,F.indexOf(';',a1)) ); } }
As with other JS libraries provided by MyersDaily, the functions contained are kept in a distinct container, in this case the Cookie object, i.e. Cookie.function(arguments).
Four functions are provided -- two main make()/read() functions, as well as cnfg() (config) and date() (utility date converter).
This function uses three arguments, the last one being optional. The order they are given in is: (1) cookie-name, (2) cookie-value, (3) cookie-settings. Previous cookie functions would allow you to use cookies with complex text values, but simple names. An improvement here lets you use any name you like.
You should keep in mind that cookies store data as text. Storing a non-textual value is OK, but it will be converted to text for storage. This might give you a surprise if you weren't aware of it.
Just so you can be sure that your cookie creation was completely successful, Cookie.make() returns a Boolean value: true if successful, false if not. Any kind of failure in the process of setting the cookie can be detected by checking this return value. You can easily verify whether cookies are disabled by storing a simple string with Cookie.make() and checking the return value.
Take note that Cookie.make() may return false even if a cookie was created. A problem of this kind could happen when your cookie value was not able to be stored equivalently as text. For example, storing a value of null would really store 'null' (which is not the same). Since cookies are truncated to 4,000 characters in length by the user agent, trying to store a cookie with a longer value (the real escaped value may be longer than the original) will also cause a false value to be returned although the first 4,000 characters are still saved.
Having a return value of false does not necessarily mean that the operation was not completed. For example, deleting a cookie (explained later) with Cookie.make() will return false, but in this case be what you wanted to accomplish.
Cookie.read() does what its name implies -- it attempts to read back the value of a named cookie, returning null if no such cookie is available. Although the values returned will be text, you can use parseFloat() or other functions to convert text into whatever data type you desire.
The third argument to Cookie.make() controls the configuration details of a particular cookie before being set. Cookie.make() really uses another function, Cookie.cnfg(), in the background to handle this process. All statements referring to Cookie.cnfg() apply identically to the third argument of Cookie.make(). Once Cookie.cnfg() has been run, the variable Cookie.pref is set automatically to the last configuration settings.
Using Cookie.cnfg() and Cookie.pref can make cookie processes more efficient. The standard order of cookie settings is (1) expires, (2) path, (3) domain, (4) secure. For backward compatability you should specify them in this order; for future compatability this order is not enforced internally, and you are able to specify other settings as you wish.
The argument to Cookie.cnfg() can be a string or an object literal {} such as { path:'/sub-dir/', domain:'login.site.com', secure:1 }. In this case the information given between the curly braces would be converted to the proper "Set-Cookie" style representation, the Cookie.pref variable would be set to this string, and the value then returned for use.
Once a paticular settings configuration has been stored in Cookie.pref, it is more efficient to use this value for later calls to Cookie.make(), but the difference is negligible in most cases.
These tips should help you understand the available settings. There may be more specified in the future; see my recommendation after the Usage section.
The value of the "expires" field in a cookie indicates to the browser the lifetime of the cookie. Cookies with no value in this field are understood to expire at the end of the current browser session. Such cookies could be called session or "session-state" cookies since they store information only relevant to the current session or state.
I have made the heuristic decision that a non-numeric value (tested with the isNaN() function) for this field should be left unchanged, but that a numeric value should be converted to a standard GMT/UTC date string with a value relative to the current date, being set forward or back by an amount of time as determined by the number given in days. Fractional amounts are valid for this number. For example, 1/24 would make a date value one hour ahead of the current time. Setting a value <=0 will delete the cookie.
Sample Dates:
Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
RFC Notes:
All HTTP date/time stamps MUST be represented in Greenwich Mean Time (GMT), without exception. For the purposes of HTTP, GMT is exactly equal to UTC (Coordinated Universal Time). This is indicated in the first two formats by the inclusion of "GMT" as the three-letter abbreviation for time zone, and MUST be assumed when reading the asctime format.
Expiration dates used in cookies need to be in a certain format, that of an HTTP date stamp. There are a few different formats used presently, however, HTTP 1.1 specifies a preferred format (see RFC # 2616, page 20), i.e. Sat, 16 Sep 2000 15:41:23 GMT; see the excerpt above.
The date strings used by the Cookie.js module are generated by the special purpose Cookie.date() function. Its argument represents a day offset from the current time. Expiration dates are generated with this function if a number is given as the expires parameter.
Every cookie has a path value defined, either explicitly at its creation, or implicity by the user agent. If you do not set a path, it will be decided at the whim of the user agent, which is not consistent between different browsers.
If a path value of '/' is given, a universal cookie is created; all areas within the site will be able to access the cookie. For example, sites using GUIDs (global user ids) would likely set it to this value. Otherwise the path value indicates a restriction on the cookie's "usable area." Giving a value of '/this-sub-dir/' would limit the cookie to pages or directories within the scope of '/this-sub-dir/'.
The Cookie.cnfg() function does not automatically escape characters like '~' in paths, etc. There is good reason for this, but be aware of it. Also see "Creating unique cookies."
A cookie's domain attribute is at the core of the cookie principle. Every cookie has a domain to which it "belongs." It will be sent in the request header with each HTTP request (and will be available to client-side scripts) for documents matching that domain.
For security reasons, the domain value (which defaults to the cookie origin domain) must contain at least two periods, e.g. '.com' is illegal -- that would allow all ".com" websites access to the cookie. Also the domain cannot be set to a value which would not include the origin domain, e.g. '.burger.com' from an origin of '.pizza.com'.
By default, a cookie is not restricted to 'https' (secure) domains. For additional safety you can use the secure keyword with a Boolean true value (e.g. 1, true, etc.) to indicate that a cookie is to be used during secure connections only.
Every time you create a cookie the Cookie.last variable is updated. This lets you examine the contents of the raw encoded cookie data after using Cookie.make(). It also allows you to use this string for other purposes, for example creating an identical cookie without needing the Cookie module at all!
Any time Cookie.cnfg() is used (either by Cookie.make() or directly) it saves that configuration into Cookie.pref. This way you can use Cookie.pref as the preference value for future cookie configurations to save script space and increase efficiency. Also see "Changing Cookie.pref."
The path value of a cookie can be used to distinguish it from those of the same name created at another page. Take the case of a boilerplate script that utilizes cookies. Obviously that script will likely create more than one cookie, creating a problem if the cookies need to be distinguished from each other. Let me illustrate a couple techniques or tricks you can use.
The most straight-forward solution is to use the location.pathname property as part of the cookie name. This automatically assigns each cookie a name exclusive to its location. Another good way is to assign the cookies a path based upon the current location.pathname value.
Even better would be a combination of these two techniques. By assigning a unique path and name to every cookie, you would reduce server load by keeping the Cookie header size at a minimum throughout your website. You would also avoid ambiguity by keeping separate cookie "namespaces," thereby avoiding problems with multiple cookies of the same name.
var cookie_done = Cookie.make('chocolate', 'gazillion', { expires:12, path:'/', domain:'.some-name.dom' } );/*
Once this has run, Cookie.pref contains that configuration and Cookie.last contains the proper representation of that cookie. Assuming that cookie creation was successful, cookie_done contains a value of true, and a cookie named chocolate has been stored with a value of 'gazillion'. If someone has their browser set to prompt before accepting cookies, they may have chosen Cancel. In that case we could alert a message and try again, hoping they would accept it this time.
*/if (!cookie_done) { // unsuccessful - try again alert('Please accept my cookies!');/*
Right here we could use either of the following ways to create an identical cookie. Note that date values may change by a few seconds from the time the preferences were saved. If you really need perfect accuracy on the expiration date (e.g. a cookie which expires in a couple seconds) you should only use direct settings rather than Cookie.pref or Cookie.last to set more cookies.
*/document.cookie = Cookie.last; // -or- // Cookie.make('chocolate', 'gazillion', Cookie.pref); // redirect if not successful this time if (Cookie.read('chocolate') != 'gazillion') location.href = '/error/no-cookies.html'; }/*
Want to know what's really in Cookie.last here?
First of all there is the name 'chocolate' and the equals sign. Then is the value 'gazillion'.
After the name=value string come the configuration settings, first of which is the expiration date. (equivalent of Cookie.date(12)) (That date is not 12 days ahead of the time now, but was when I wrote this.)
The third element in this cookie is the path. Here it is set to '/' to allow universal access.
Fourth comes the domain. Maybe you have been worried about the term "universal access," thinking perhaps everyone could get this cookie. Well, not quite! It's universal only within the scope of the domain '.some-name.dom'.
The line below shows the final result. After all the values are joined together with semicolons and spaces '; ', the cookie is ready.
chocolate=gazillion; expires=Thu, 28 Sep 2000 19:17:52 UTC; path=/; domain=.some-name.dom*/ /*
Here's how you would delete that cookie.
*/Cookie.make('chocolate', 'whatever', { expires:-1 }); // -or- // verify its deletion // Remember, Cookie.make() returns false when you delete if (Cookie.make('chocolate', 'whatever', { expires:-1 })) alert("Couldn't delete the cookie!");/*
Making a direct assignment to Cookie.pref is risky, so just run Cookie.cnfg() with your new configuration settings. Until you use a different configuration, Cookie.pref will store it. Of course you may run Cookie.make() with Cookie.pref as its third argument, using those saved settings.
In the following example the preferences are changed to reflect a member of a hypothetical free web hosting service. They would like to keep their cookies restricted to their own part '/my-state/member-name/' of the entire host web site, as well as having a default expiration of 90 days.
After they do so, the cookie 'some-cookie' made with Cookie.pref as the third argument will automatically have those values as its configuration.
Cookie.cnfg({ expires:90, path:'/my-state/member-name/' }); Cookie.make('some-cookie', 'some-value', Cookie.pref);/*
By the way, if you need to get the path portion of the location.pathname, you can get this dynamically with the following expression. This would be useful, for example, in creating a hierarchical menu of nested directories.
*/(location.pathname||'/').match(/.*\//g)[0];
Cookies presently are used by client-side scripts as well as server-side operations. Many cookies are never intended to be used by both. In fact, some client-side scripts make such heavy use of cookies that every connection between the server and user agent is substantially and needlessly hindered by the excessive size of the Cookie element of the request header.
I have experienced this myself, encountering an error 413, "Request Entity Too Large," largely due to cookie space used by scripts. To resolve this issue I make the recommendation that an additional setting be defined for cookie configurations, a "protocol" value, e.g. "protocol=<protocol>".
This would be set by default to '*' (all protocols), or could be restricted to 'http*' (all http connections), 'https' (http secure only), 'javascript' (JavaScript only), etc. Multiple choices would be separated by commas, e.g. 'http*, javascript'. The protocol context would be compared to the cookie's protocol setting by conforming user agents when determining which cookies to make available to a server or script. The protocol setting would eliminate the need for the '; secure' parameter that is currently used.
MyersDaily created by Joseph K. Myers 1999-2000. Free hosting by Angelfire!!Terms-of-Service |