Permalink
Browse files

Merge pull request #23 from purplecabbage/DOMStorage

Dom storage
  • Loading branch information...
2 parents 4df9357 + fe7d41f commit c87bf090886cae0fb5bdf0f920d8b6ac49322caf Jesse MacFadyen committed Oct 6, 2011
View
@@ -53,6 +53,8 @@ public partial class PGView : UserControl
/// </summary>
private NativeExecution nativeExecution;
+ protected DOMStorageHelper domStorageHelper;
+
public PGView()
{
@@ -115,6 +117,8 @@ void GapBrowser_Loaded(object sender, RoutedEventArgs e)
// prevents refreshing web control to initial state during pages transitions
if (this.IsBrowserInitialized) return;
+ this.domStorageHelper = new DOMStorageHelper(this.GapBrowser);
+
try
{
@@ -286,6 +290,13 @@ void GapBrowser_Navigating(object sender, NavigatingEventArgs e)
void GapBrowser_ScriptNotify(object sender, NotifyEventArgs e)
{
string commandStr = e.Value;
+
+ // DOMStorage/Local OR DOMStorage/Session
+ if (commandStr.IndexOf("DOMStorage") == 0)
+ {
+ this.domStorageHelper.HandleStorageCommand(commandStr);
+ return;
+ }
PhoneGapCommandCall commandCallParams = PhoneGapCommandCall.Parse(commandStr);
@@ -0,0 +1,131 @@
+using System;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using System.IO.IsolatedStorage;
+using System.Collections.Generic;
+using Microsoft.Phone.Controls;
+using System.Linq;
+using WP7GapClassLib.PhoneGap.JSON;
+
+/*
+ * Translates DOMStorage API between JS and Isolated Storage
+ * Missing pieces : QUOTA_EXCEEDED_ERR + StorageEvent
+ * */
+
+namespace WP7GapClassLib
+{
+ public class DOMStorageHelper
+ {
+ protected WebBrowser webBrowser1;
+
+ public DOMStorageHelper(WebBrowser gapBrowser)
+ {
+ this.webBrowser1 = gapBrowser;
+ // always clear session at creation
+ UserSettings["sessionStorage"] = new Dictionary<string, string>();
+
+ if (!UserSettings.Contains("localStorage"))
+ {
+ UserSettings["localStorage"] = new Dictionary<string, string>();
+ UserSettings.Save();
+ }
+ Application.Current.Exit += new EventHandler(OnAppExit);
+ }
+
+ void OnAppExit(object sender, EventArgs e)
+ {
+ UserSettings.Remove("sessionStorage");
+ UserSettings.Save();
+ }
+
+ protected IsolatedStorageSettings UserSettings
+ {
+ get
+ {
+ return IsolatedStorageSettings.ApplicationSettings;
+ }
+ }
+
+ protected Dictionary<string, string> getStorageByType(string type)
+ {
+ if (!UserSettings.Contains(type))
+ {
+ UserSettings[type] = new Dictionary<string, string>();
+ UserSettings.Save();
+ }
+ return UserSettings[type] as Dictionary<string,string>;
+ }
+
+
+ public void HandleStorageCommand(string commandStr)
+ {
+
+ string[] split = commandStr.Split('/');
+ if (split.Length > 3)
+ {
+ string api = split[0];
+ string type = split[1]; // localStorage || sessionStorage
+ string command = split[2];
+ string param = split[3];
+
+ Dictionary<string, string> currentStorage = getStorageByType(type);
+
+ switch (command)
+ {
+ case "get":
+ {
+
+ if (currentStorage.Keys.Contains(param))
+ {
+ string value = currentStorage[param];
+ webBrowser1.InvokeScript("execScript", "window." + type + ".onResult('" + param + "','" + value + "');");
+ }
+ else
+ {
+ webBrowser1.InvokeScript("execScript", "window." + type + ".onResult('" + param + "');");
+ }
+
+ }
+ break;
+ case "load":
+ {
+ string[] keys = currentStorage.Keys.ToArray();
+ string jsonString = JsonHelper.Serialize(keys);
+ string callbackJS = "window." + type + ".onKeysChanged('" + jsonString + "');";
+ webBrowser1.InvokeScript("execScript", callbackJS);
+ }
+ break;
+ case "set":
+ {
+ // TODO: check that length is not out of bounds
+ currentStorage[param] = split[4];
+ UserSettings.Save();
+ string[] keys = currentStorage.Keys.ToArray();
+ string jsonString = JsonHelper.Serialize(keys);
+ string callbackJS = "window." + type + ".onKeysChanged('" + jsonString + "');";
+ webBrowser1.InvokeScript("execScript", callbackJS);
+ }
+ break;
+ case "remove":
+ currentStorage.Remove(param);
+ UserSettings.Save();
+ break;
+ case "clear":
+ currentStorage = new Dictionary<string, string>();
+ UserSettings[type] = currentStorage;
+ UserSettings.Save();
+ break;
+ }
+
+ }
+
+ }
+ }
+}
@@ -60,6 +60,7 @@
<Compile Include="PhoneGap\Commands\AudioPlayer.cs" />
<Compile Include="PhoneGap\Commands\Compass.cs" />
<Compile Include="PhoneGap\Commands\Media.cs" />
+ <Compile Include="PhoneGap\DOMStorageHelper.cs" />
<Compile Include="PhoneGap\JSON\JsonHelper.cs" />
<Compile Include="PhoneGap\Commands\MimeTypeMapper.cs" />
<Compile Include="PhoneGap\PhoneGapCommandCall.cs" />
View
@@ -0,0 +1,208 @@
+
+// this is a WP7 Only implementation of the Storage API for use in webpages loaded from the local file system
+// inside phonegap application.
+// there is a native implementation which is backing this and providing the persistance of values.
+// webpages loaded from a domain will not need to use this as IE9 has support for WebStorage
+// Javascript Interface is as defined here : http://dev.w3.org/html5/webstorage/#storage-0
+//
+
+if(!window.localStorage)
+{(function()
+{
+ "use strict";
+
+ var DOMStorage = function(type)
+ {
+ // default type is local
+ if(type == "sessionStorage")
+ {
+ this._type = type;
+ }
+ Object.defineProperty( this, "length",
+ {
+ configurable: true,
+ get: function(){ return this.getLength() }
+ });
+
+ };
+
+ DOMStorage.prototype =
+ {
+ _type:"localStorage",
+ _result:null,
+ keys:null,
+
+ onResult:function(key,valueStr)
+ {
+ if(!this.keys)
+ {
+ this.keys = [];
+ }
+ this._result = valueStr;
+ },
+
+ onKeysChanged:function(jsonKeys)
+ {
+ this.keys = JSON.parse(jsonKeys);
+
+ var key;
+ for(var n = 0,len =this.keys.length; n < len; n++)
+ {
+ key = this.keys[n];
+ if(!this.hasOwnProperty(key))
+ {
+ console.log("didn't have a prop, now we do ...");
+ Object.defineProperty( this, key,
+ {
+
+ configurable: true,
+ get: function(){ return this.getItem(key); },
+ set: function(val){ return this.setItem(key,val); }
+ });
+ }
+ }
+
+ },
+
+ initialize:function()
+ {
+ window.external.Notify("DOMStorage/" + this._type + "/load/keys");
+ },
+
+ /*
+ The length attribute must return the number of key/value pairs currently present in the list associated with the object.
+ */
+ getLength:function()
+ {
+ if(!this.keys)
+ {
+ this.initialize();
+ }
+ return this.keys.length;
+ },
+
+ /*
+ The key(n) method must return the name of the nth key in the list.
+ The order of keys is user-agent defined, but must be consistent within an object so long as the number of keys doesn't change.
+ (Thus, adding or removing a key may change the order of the keys, but merely changing the value of an existing key must not.)
+ If n is greater than or equal to the number of key/value pairs in the object, then this method must return null.
+ */
+ key:function(n)
+ {
+ if(!this.keys)
+ {
+ this.initialize();
+ }
+
+ if(n >= this.keys.length)
+ {
+ return null;
+ }
+ else
+ {
+ return this.keys[n];
+ }
+ },
+
+ /*
+ The getItem(key) method must return the current value associated with the given key.
+ If the given key does not exist in the list associated with the object then this method must return null.
+ */
+ getItem:function(key)
+ {
+ if(!this.keys)
+ {
+ this.initialize();
+ }
+
+ var retVal = null;
+ if(this.keys.indexOf(key) > -1)
+ {
+ window.external.Notify("DOMStorage/" + this._type + "/get/" + key);
+ retVal = this._result;
+ this._result = null;
+ }
+ return retVal;
+ },
+ /*
+ The setItem(key, value) method must first check if a key/value pair with the given key already exists
+ in the list associated with the object.
+ If it does not, then a new key/value pair must be added to the list, with the given key and with its value set to value.
+ If the given key does exist in the list, then it must have its value updated to value.
+ If it couldn't set the new value, the method must raise an QUOTA_EXCEEDED_ERR exception.
+ (Setting could fail if, e.g., the user has disabled storage for the site, or if the quota has been exceeded.)
+ */
+ setItem:function(key,value)
+ {
+ if(!this.keys)
+ {
+ this.initialize();
+ }
+ window.external.Notify("DOMStorage/" + this._type + "/set/" + key + "/" + value);
+ },
+
+ /*
+ The removeItem(key) method must cause the key/value pair with the given key to be removed from the list
+ associated with the object, if it exists.
+ If no item with that key exists, the method must do nothing.
+ */
+ removeItem:function(key)
+ {
+ if(!this.keys)
+ {
+ this.initialize();
+ }
+ var index = this.keys.indexOf(key);
+ if(index > -1)
+ {
+ this.keys.splice(index,1);
+ // TODO: need sanity check for keys ? like 'clear','setItem', ...
+ window.external.Notify("DOMStorage/" + this._type + "/remove/" + key);
+ delete this[key];
+ }
+
+ },
+
+ /*
+ The clear() method must atomically cause the list associated with the object to be emptied of all
+ key/value pairs, if there are any.
+ If there are none, then the method must do nothing.
+ */
+ clear:function()
+ {
+ if(!this.keys)
+ {
+ this.initialize();
+ }
+
+ for(var n=0,len=this.keys.length; n < len;n++)
+ {
+ // TODO: do we need a sanity check for keys ? like 'clear','setItem', ...
+ delete this[this.keys[n]];
+ }
+ this.keys = [];
+ window.external.Notify("DOMStorage/" + this._type + "/clear/");
+ }
+ };
+
+ // initialize DOMStorage
+
+ Object.defineProperty( window, "localStorage",
+ {
+ writable: false,
+ configurable: false,
+ value:new DOMStorage("localStorage")
+ });
+ window.localStorage.initialize();
+
+ Object.defineProperty( window, "sessionStorage",
+ {
+ writable: false,
+ configurable: false,
+ value:new DOMStorage("sessionStorage")
+ });
+ window.sessionStorage.initialize();
+
+
+})();};
+
Oops, something went wrong.

0 comments on commit c87bf09

Please sign in to comment.