Web storage is a mechanism that allows web-based applications to store information on the client-side. The mechanism can store information in two different storage areas: local storage and session storage. A local storage area is shared by all pages from the same origin, and can store information for more than a single session - in other words, a browser context can be closed and re-opened, and still have access to the stored data. A session storage area is shared by all pages from the same origin running within the same browser context, and it is intended to be used for keeping track of the application state as the user progresses through a series of pages. A session storage area discards the data as soon as the browser context is closed.
Web storage is a mechanism that allows web-based applications to store information on the client-side. The mechanism can store information in two different storage areas: local storage and session storage. A local storage area is shared by all pages from the same origin, and can store information for more than a single session - in other words, a browser context can be closed and re-opened, and still have access to the stored data. A session storage area is shared by all pages from the same origin running within the same browser context, and it is intended to be used for keeping track of the application state as the user progresses through a series of pages. A session storage area discards the data as soon as the browser context is closed.
Web storage is based on the Web Storage W3C Working Draft.
Support for accessing a local storage area is represented by the following feature:
cf2:storage.local
Support for accessing a session storage area is represented by the following feature:
cf2:storage.session
A local storage area is accessible through the V$.storage.local property. A session storage area is accessible through the V$.storage.session property.
Each of the storage areas implements the following interface:
The method provides access to the storage, i.e. it returns the value returned from within the access function. Please note that while the function is executing no other changes should be made to the same storage area. In addition, the access function must not make any calls to a JavaScript code that could block the thread while events are processed.
Parameter | Description | Type |
---|---|---|
function | The access function. It takes a single argument that is the storage object. The storage object may not be used outside this function. Attempting to call any methods on the storage object after this method has returned will cause an exception to be thrown. | Function |
An instance of the storage object passed to the access function supports the following methods:
Stores a copy of the value under the specified key. If an item with the specified key already exists, then the method changes the value. If the item cannot be stored, e.g. because the storage area has exceeded capacity, then an error will be thrown.
Parameter | Description | Type |
---|---|---|
key | The key. | String |
value | The value. | boolean, number, string, undefined, Array, Object |
Returns the value that was stored under the specified key. If an item with the specified key does not exist, then the method returns null.
Parameter | Description | Type |
---|---|---|
key | The key. | String |
Removes any value stored under the specified key. If an item with the specified key does not exist, then the method does nothing.
Parameter | Description | Type |
---|---|---|
key | The key. | String |
Clears the storage area.
Returns the number of items in the storage area.
Returns the key at the specified index. It is an error if index is less than 0 or greater than or equal to the value returned by itemCount(). The indexes may change when a key is added or removed, and the order of keys is not guaranteed. The purpose of this method is to allow iterating over the storage area.
Parameter | Description | Type |
---|---|---|
index | The key at the specified index. | Integer |
Keys that start with "cf2" are reserved for internal use by the Client Framework 2.
Whenever an item is stored in or retrieved from a storage area it is copied in order to ensure that items in the storage cannot be changed other than through the storage API. Items that are cloned can contain cycles and or multiple references to the same object. Cloning an object is dependent on its type and described as follows, where input is the object being cloned, and output is the corresponding cloned object set by the first of these rules that match the input:
If input has already been visited and cloned, then let output be the result of that previous cloning.
If input is a primitive value, then let output be that value; primitive values are any of the following:
undefined
null
Any boolean value, i.e. a value such that typeof(input) returns boolean; i.e. either false or true.
Any number value, i.e. a value such that typeof(input) returns number.
Any string value, i.e. a value such that typeof(input) returns string.
If input is an Array, then:
Let output be a newly constructed Array.
Iterate over the indices of input from O to input.length - 1 and for each index i that has a value set:
Let I be the value at that index.
Apply the structured cloning algorithm recursively to I to produce a value O.
Store O in output at index i.
If input is an Object, then:
Let output be a newly constructed Object.
Iterate over the properties of input and for each property P:
Let I be the value for that property.
Apply the structured cloning algorithm recursively to I to produce a value O.
Add a mapping to output from P to O.
This does attempt to preserve the order of the properties from the input Object but the actual order is undefined and must not be relied upon as it is likely to be device specific.
The following restrictions apply:
Objects and Arrays can only contain supported types.
Attempting to store unsupported types or the object representations of the boolean, number and string primitive values, i.e. Boolean, Number and String, will result in inconsistent behavior across devices.
If there is a need to store types such as Date or RegExp, then they should be converted to one of the supported types before storing and converted back again afterwards.
Unless explicitly allowed it is undefined behavior if an attempt is made to store an object that forms part of the Client Framework 2.
During the loading process, all objects are instantiated with "{}" syntax thus the original prototype chain is not recreated and the overall object identity is not persisted, i.e. constructors, methods derived from prototype, etc., are all lost. Generally, only the clean data is stored.
Properties can only be added to Objects.
In Arrays, only properties with non-negative integer keys will be stored.
The security of the mechanism is based on the origin of the JavaScript that is attempting to access a local or session storage area, i.e. two scripts can access the same storage areas if and only if they come from the same origin. As a consequence, applications installed on the same web server can access each other's data. It would be a security threat if one of the applications is untrusted, or could cause conflicts if the applications use the same keys. In order to avoid security issues it is recommended to deploy each application on a virtual host. In addition, when defining keys for an application that is likely to be used with other applications that use the storage, then authors should ensure the uniqueness of keys, for example, the keys could use reverse domain notation similar to Java packages. Please note that typically the person responsible for installing the application and setting up the environment is most likely to be different to the page author and therefore the page author needs to provide clear indication of any security or key conflict issues that may affect the application.
It is important to note that the web storage standard gives browsers a lot of control over how to implement and manage storage areas, and makes very few guarantees about the user's data. Therefore, the web storage mechanism must not be treated as a persistence mechanism for critical data. The list of possible issues includes, but is not limited to:
Browsers can remove both session and local storage areas due to security issues.
A local storage area can be treated as a session storage area, i.e. discarded once all referencing browser contexts are closed.
If a browser has multiple browser contexts for pages from the same origin, then it is likely that each browser context will be running on its own thread sharing the same local storage area, and therefore concurrency issues can occur.
Some devices may allow the user to change the storage limit, either increase or decrease it globally or per origin, and even disable it completely for black listed origins, or enable it only for a set of white listed origins.
Most browsers set the storage limit to 5MB per origin.
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/2002/06/xhtml2"
xmlns:mcs="http://www.volantis.com/xmlns/2006/01/xdime/mcs"
xmlns:cf2="http://www.volantis.com/xmlns/2009/07/cf2"
xmlns:event="http://www.w3.org/2001/xml-events"
xmlns:ui="http://www.volantis.com/xmlns/2009/07/cf2/ui"
xmlns:xforms="http://www.w3.org/2002/xforms"
xmlns:si="http://www.volantis.com/xmlns/2006/01/xdime2/si"
xmlns:sel="http://www.w3.org/2004/06/diselect">
<head>
<title>WebStorage</title>
<mcs:script src="/scripts/web-storage.mscr"/>
<xforms:model id="note">
<xforms:instance>
<si:instance>
<si:item name="content"/>
</si:instance>
</xforms:instance>
</xforms:model>
<sel:select>
<sel:when expr="mcs:feature('cf2:storage.local')">
<mcs:handler id="loadhandler" type="text/javascript">
var value_from_storage = V$.storage.local.access(function (storageObject) {
return storageObject.getItem("stickyNote");
});
if (value_from_storage && typeof value_from_storage === "object"
&& typeof value_from_storage.text === "string" && typeof value_from_storage.timestamp === "number") {
V$E('contentField').value = value_from_storage.text;
V$E('accessDate').innerHTML = "Last edit: " + new Date(value_from_storage.timestamp);
}
</mcs:handler>
<mcs:handler id="unloadhandler" type="text/javascript">
var object_to_store = {
text: V$E('contentField').value,
timestamp: (new Date()).getTime()
};
V$.storage.local.access(function (storageObject) {
storageObject.setItem("stickyNote",object_to_store);
});
</mcs:handler>
<event:listener observer="body" handler="#loadhandler" event="load"/>
<event:listener observer="body" handler="#unloadhandler" event="unload"/>
</sel:when>
</sel:select>
</head>
<body id="body">
<sel:select>
<sel:when expr="mcs:feature('cf2:storage.local')">
<div>Sticky note. Leave a note and when you are back, the note will still be here (unless
you clear the cache). <xforms:textarea model="note" ref="content" id="contentField"
style="mcs-rows: 5; mcs-columns: 20; background-color: yellow;">
<xforms:label/>
</xforms:textarea>
<div id="accessDate">Entry not found</div>
</div>
</sel:when>
<sel:otherwise>
<div class="warning">cf2:storage.local is not supported on this device. </div>
</sel:otherwise>
</sel:select>
</body>
</html>
The web-storage.mscr script module must import two features: cf2:storage.local and cf2:dom.ElementAccess.