You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by br...@apache.org on 2013/05/23 23:58:15 UTC

[18/50] Add WP7 and WP8 platform files.

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0fea2dd2/lib/cordova-wp8/templates/standalone/cordovalib/BrowserMouseHelper.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordovalib/BrowserMouseHelper.cs b/lib/cordova-wp8/templates/standalone/cordovalib/BrowserMouseHelper.cs
new file mode 100644
index 0000000..fc83e03
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordovalib/BrowserMouseHelper.cs
@@ -0,0 +1,162 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License. 
+ */
+using System.Linq;
+using System.Windows;
+using System.Windows.Controls;
+using Microsoft.Phone.Controls;
+using System.Windows.Input;
+using System.Diagnostics;
+using System.Windows.Media;
+using System;
+using System.Collections.Generic;
+
+namespace WPCordovaClassLib
+{
+
+    /// <summary>
+    /// Suppresses pinch zoom and optionally scrolling of the WebBrowser control
+    /// </summary>
+    public class BrowserMouseHelper
+    {
+        private WebBrowser _browser;
+
+        /// <summary>
+        /// Gets or sets whether to suppress the scrolling of
+        /// the WebBrowser control;
+        /// </summary>
+        public bool ScrollDisabled {
+            get;
+            set;
+        }
+
+        private bool userScalable = true;
+        private double maxScale = 2.0;
+        private double minScale = 0.5;
+        protected Border border;
+
+        /// <summary>
+        /// Represent min delta value to consider event as a mouse move. Experimental calculated.
+        /// </summary>
+        private const int MouseMoveDeltaThreshold = 10;
+
+        public BrowserMouseHelper(ref WebBrowser browser)
+        {
+            _browser = browser;
+            browser.Loaded += new RoutedEventHandler(browser_Loaded);
+        }
+
+        private void browser_Loaded(object sender, RoutedEventArgs e)
+        {
+            var border0 = VisualTreeHelper.GetChild(_browser, 0);
+            var border1 = VisualTreeHelper.GetChild(border0, 0);
+            var panZoom = VisualTreeHelper.GetChild(border1, 0);
+            var grid = VisualTreeHelper.GetChild(panZoom, 0);             
+            var grid2 = VisualTreeHelper.GetChild(grid, 0);
+            border = VisualTreeHelper.GetChild(grid2, 0) as Border;
+            
+            if (border != null)
+            {
+                border.ManipulationDelta += Border_ManipulationDelta;
+                border.ManipulationCompleted += Border_ManipulationCompleted;
+            }
+
+            _browser.LoadCompleted += Browser_LoadCompleted;
+
+        }
+
+        void ParseViewportMeta()
+        {
+            string metaScript = "(function() { return document.querySelector('meta[name=viewport]').content; })()";
+
+            try
+            {
+                string metaContent = _browser.InvokeScript("eval", new string[] { metaScript }) as string;
+                string[] arr = metaContent.Split(new[] { ' ', ',', ';' }, StringSplitOptions.RemoveEmptyEntries);
+                Dictionary<string, string> metaDictionary = new Dictionary<string, string>();
+                foreach (string val in arr)
+                {
+                    string[] keyVal = val.Split('=');
+                    metaDictionary.Add(keyVal[0], keyVal[1]);
+                }
+
+                this.userScalable = false; // reset to default
+                if (metaDictionary.ContainsKey("user-scalable"))
+                {
+                    this.userScalable = metaDictionary["user-scalable"] == "yes";
+                }
+
+                this.maxScale = 2.0;// reset to default
+                if (metaDictionary.ContainsKey("maximum-scale"))
+                {
+                    this.maxScale = double.Parse(metaDictionary["maximum-scale"]);
+                }
+
+                this.minScale = 0.5;// reset to default
+                if (metaDictionary.ContainsKey("minimum-scale"))
+                {
+                    this.minScale = double.Parse(metaDictionary["minimum-scale"]);
+                }
+            }
+            catch (Exception)
+            {
+
+            }
+        }
+
+        void Browser_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
+        {
+            ParseViewportMeta();
+        }
+
+        #region ManipulationEvents
+
+        private void Border_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
+        {
+            //Debug.WriteLine("Border_ManipulationDelta");
+            // optionally suppress zoom
+            if ((ScrollDisabled || !userScalable) && (e.DeltaManipulation.Scale.X != 0.0 || e.DeltaManipulation.Scale.Y != 0.0))
+            {
+                e.Handled = true;
+            }
+            // optionally suppress scrolling
+            if (ScrollDisabled && (e.DeltaManipulation.Translation.X != 0.0 || e.DeltaManipulation.Translation.Y != 0.0))
+            {
+                e.Handled = true;
+            }
+        }
+
+        private void Border_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
+        {
+            //Debug.WriteLine("Border_ManipulationCompleted");
+            // suppress zoom
+            if (!userScalable && e.FinalVelocities != null)
+            {
+                if (e.FinalVelocities.ExpansionVelocity.X != 0.0 ||
+                   e.FinalVelocities.ExpansionVelocity.Y != 0.0)
+                {
+                    e.Handled = true;
+                }
+            }
+        }
+
+
+        #endregion
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0fea2dd2/lib/cordova-wp8/templates/standalone/cordovalib/CommandFactory.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordovalib/CommandFactory.cs b/lib/cordova-wp8/templates/standalone/cordovalib/CommandFactory.cs
new file mode 100644
index 0000000..974ee79
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordovalib/CommandFactory.cs
@@ -0,0 +1,112 @@
+/*  
+	Licensed under the Apache License, Version 2.0 (the "License");
+	you may not use this file except in compliance with the License.
+	You may obtain a copy of the License at
+	
+	http://www.apache.org/licenses/LICENSE-2.0
+	
+	Unless required by applicable law or agreed to in writing, software
+	distributed under the License is distributed on an "AS IS" BASIS,
+	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+	See the License for the specific language governing permissions and
+	limitations under the License.
+*/
+
+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.Collections.Generic;
+using WPCordovaClassLib.Cordova.Commands;
+using System.Reflection;
+using System.Diagnostics;
+
+namespace WPCordovaClassLib.Cordova
+{
+    /// <summary>
+    /// Provides functionality to create Cordova command by name.
+    /// </summary>
+    public static class CommandFactory
+    {
+        /// <summary>
+        /// Represents predefined namespace name for custom plugins
+        /// </summary>
+        private static readonly string CustomPluginNamespacePrefix = "Cordova.Extension.Commands.";
+
+        private static readonly string BaseCommandNamespacePrefix = "WPCordovaClassLib.Cordova.Commands.";
+
+        /// <summary>
+        /// Cache instantiated commands in a map.
+        /// </summary>
+
+        private static Dictionary<string, BaseCommand> commandMap = new Dictionary<string, BaseCommand>();
+
+        /// <summary>
+        /// Creates command using command class name. Returns null for unknown commands.
+        /// </summary>
+        /// <param name="service">Command class name, for example Device or Notification</param>
+        /// <returns>Command class instance or null</returns>
+        public static BaseCommand CreateByServiceName(string service)
+        {
+
+            if (string.IsNullOrEmpty(service))
+            {
+                throw new ArgumentNullException("service", "service to create can't be null");
+            }
+
+            if (!commandMap.ContainsKey(service))
+            {
+
+                Type t = Type.GetType(BaseCommandNamespacePrefix + service);
+
+                // custom plugin could be defined in own namespace and assembly
+                if (t == null)
+                {
+                    string serviceFullName = service.Contains(".") ? service : CustomPluginNamespacePrefix + service;
+
+                    foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
+                    {
+                        // in this case service name represents full type name including namespace
+                        t = a.GetType(serviceFullName);
+
+                        if (t == null) // try the Commands Namespace
+                        {
+                            t = a.GetType(BaseCommandNamespacePrefix + service);
+                        }
+
+                        if (t != null)
+                        {
+                            break;
+                        }
+                    }
+
+                }
+
+                // unknown command, still didn't find it
+                if (t == null)
+                {
+                    Debug.WriteLine("Unable to locate command :: " + service);
+                    return null;
+                }
+
+                commandMap[service] = Activator.CreateInstance(t) as BaseCommand;
+            }
+
+            return commandMap[service];
+        }
+
+        public static void ResetAllCommands()
+        {
+            foreach (BaseCommand bc in commandMap.Values)
+            {
+                bc.OnReset();
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0fea2dd2/lib/cordova-wp8/templates/standalone/cordovalib/Commands/BaseCommand.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordovalib/Commands/BaseCommand.cs b/lib/cordova-wp8/templates/standalone/cordovalib/Commands/BaseCommand.cs
new file mode 100644
index 0000000..9de0e4d
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordovalib/Commands/BaseCommand.cs
@@ -0,0 +1,187 @@
+/*  
+	Licensed under the Apache License, Version 2.0 (the "License");
+	you may not use this file except in compliance with the License.
+	You may obtain a copy of the License at
+	
+	http://www.apache.org/licenses/LICENSE-2.0
+	
+	Unless required by applicable law or agreed to in writing, software
+	distributed under the License is distributed on an "AS IS" BASIS,
+	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+	See the License for the specific language governing permissions and
+	limitations under the License.
+*/
+
+using System;
+using System.Reflection;
+using Microsoft.Phone.Shell;
+using System.Diagnostics;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+    public abstract class BaseCommand : IDisposable
+    {
+        /*
+         *  All commands + plugins must extend BaseCommand, because they are dealt with as BaseCommands in CordovaView.xaml.cs
+         *  
+         **/
+
+        public event EventHandler<PluginResult> OnCommandResult;
+
+        public event EventHandler<ScriptCallback> OnCustomScript;
+
+        public string CurrentCommandCallbackId { get; set; }
+
+        public BaseCommand()
+        {
+            ResultHandlers = new Dictionary<string, EventHandler<PluginResult>>();
+            PhoneApplicationService service = PhoneApplicationService.Current;
+            service.Activated += this.OnResume;
+            service.Deactivated += this.OnPause;
+        }
+
+        protected Dictionary<string, EventHandler<PluginResult>> ResultHandlers;
+        public void AddResultHandler(string callbackId, EventHandler<PluginResult> handler)
+        {
+            ResultHandlers.Add(callbackId, handler);
+        }
+        public bool RemoveResultHandler(string callbackId)
+        {
+            return ResultHandlers.Remove(callbackId);
+        }
+
+        /*
+         *  InvokeMethodNamed will call the named method of a BaseCommand subclass if it exists and pass the variable arguments list along.
+         **/
+
+        public object InvokeMethodNamed(string callbackId, string methodName, params object[] args)
+        {
+            //Debug.WriteLine(string.Format("InvokeMethodNamed:{0} callbackId:{1}",methodName,callbackId));
+            this.CurrentCommandCallbackId = callbackId;
+            return InvokeMethodNamed(methodName, args);
+        }
+
+        public object InvokeMethodNamed(string methodName, params object[] args)
+        {
+            MethodInfo mInfo = this.GetType().GetMethod(methodName);
+
+            if (mInfo != null)
+            {
+                // every function handles DispatchCommandResult by itself
+                return mInfo.Invoke(this, args);
+            }
+
+            // actually methodName could refer to a property
+            if (args == null || args.Length == 0 ||
+               (args.Length == 1 && "undefined".Equals(args[0])))
+            {
+                PropertyInfo pInfo = this.GetType().GetProperty(methodName);
+                if (pInfo != null)
+                {
+                    object res = pInfo.GetValue(this, null);
+
+                    DispatchCommandResult(new PluginResult(PluginResult.Status.OK, res));
+
+                    return res;
+                }
+            }
+
+            throw new MissingMethodException(methodName);
+
+        }
+
+        [Obsolete]
+        public void InvokeCustomScript(ScriptCallback script, bool removeHandler)
+        {
+            if (this.OnCustomScript != null)
+            {
+                this.OnCustomScript(this, script);
+                if (removeHandler)
+                {
+                    this.OnCustomScript = null;
+                }
+            }
+        }
+
+        public void DispatchCommandResult()
+        {
+            this.DispatchCommandResult(new PluginResult(PluginResult.Status.NO_RESULT));
+        }
+
+        public void DispatchCommandResult(PluginResult result,string callbackId="")
+        {
+            if (!string.IsNullOrEmpty(callbackId)) 
+            {
+                result.CallbackId = callbackId;
+            }
+            else
+            {
+                result.CallbackId = this.CurrentCommandCallbackId;
+            }
+
+            if (ResultHandlers.ContainsKey(result.CallbackId))
+            {
+                ResultHandlers[result.CallbackId](this, result);
+            }
+            else if (this.OnCommandResult != null)
+            {
+                OnCommandResult(this, result);
+            }
+            else
+            {
+                Debug.WriteLine("Failed to locate callback for id : " + result.CallbackId);
+            }
+
+            if (!result.KeepCallback)
+            {
+                this.Dispose();
+            }
+
+        }
+
+
+        /// <summary>
+        /// Occurs when the application is being deactivated.
+        /// </summary>        
+        public virtual void OnReset() {}
+
+        /// <summary>
+        /// Occurs when the application is being loaded, and the config.xml has an autoload entry
+        /// </summary>    
+        public virtual void OnInit() {}
+
+
+        /// <summary>
+        /// Occurs when the application is being deactivated.
+        /// </summary>        
+        public virtual void OnPause(object sender, DeactivatedEventArgs e) {}
+
+        /// <summary>
+        /// Occurs when the application is being made active after previously being put
+        /// into a dormant state or tombstoned.
+        /// </summary>        
+        public virtual void OnResume(object sender, Microsoft.Phone.Shell.ActivatedEventArgs e) {}
+
+        public void Dispose()
+        {
+            PhoneApplicationService service = PhoneApplicationService.Current;
+            service.Activated -= this.OnResume;
+            service.Deactivated -= this.OnPause;
+            this.OnCommandResult = null;
+        }
+
+        public static string GetBaseURL()
+        {
+#if CORDOVA_CLASSLIB
+            return "/WPCordovaClassLib;component/";
+#else
+            return "./";
+#endif
+        }
+    }
+
+
+
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0fea2dd2/lib/cordova-wp8/templates/standalone/cordovalib/ConfigHandler.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordovalib/ConfigHandler.cs b/lib/cordova-wp8/templates/standalone/cordovalib/ConfigHandler.cs
new file mode 100644
index 0000000..06806d3
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordovalib/ConfigHandler.cs
@@ -0,0 +1,242 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Resources;
+using System.Xml.Linq;
+
+namespace WPCordovaClassLib.CordovaLib
+{
+    class ConfigHandler
+    {
+        public class PluginConfig
+        {
+            public PluginConfig(string name, bool autoLoad = false)
+            {
+                Name = name;
+                isAutoLoad = autoLoad;
+            }
+            public string Name;
+            public bool isAutoLoad;
+        }
+
+        protected Dictionary<string, PluginConfig> AllowedPlugins;
+        protected List<string> AllowedDomains;
+        protected Dictionary<string, string> Preferences;
+
+        protected bool AllowAllDomains = false;
+        protected bool AllowAllPlugins = false;
+
+        public ConfigHandler()
+        {
+            AllowedPlugins = new Dictionary<string, PluginConfig>();
+            AllowedDomains = new List<string>();
+            Preferences = new Dictionary<string, string>();
+        }
+
+        public string GetPreference(string key)
+        {
+            return Preferences[key];
+        }
+
+        protected static string[] AllowedSchemes = { "http", "https", "ftp", "ftps" };
+        protected bool SchemeIsAllowed(string scheme)
+        {
+            return AllowedSchemes.Contains(scheme);
+        }
+
+        protected void AddWhiteListEntry(string origin, bool allowSubdomains)
+        {
+
+            if (origin == "*")
+            {
+                AllowAllDomains = true;
+            }
+
+            if (AllowAllDomains)
+            {
+                return;
+            }
+
+            string hostMatchingRegex = "";
+            string hostName;
+
+            try
+            {
+
+                Uri uri = new Uri(origin.Replace("*", "replaced-text"), UriKind.Absolute);
+
+                string tempHostName = uri.Host.Replace("replaced-text", "*");
+                //if (uri.HostNameType == UriHostNameType.Dns){}        
+                // starts with wildcard match - we make the first '.' optional (so '*.org.apache.cordova' will match 'org.apache.cordova')
+                if (tempHostName.StartsWith("*."))
+                {    //"(\\s{0}|*.)"
+                    hostName = @"\w*.*" + tempHostName.Substring(2).Replace(".", @"\.").Replace("*", @"\w*");
+                }
+                else
+                {
+                    hostName = tempHostName.Replace(".", @"\.").Replace("*", @"\w*");
+                }
+                //  "^https?://"
+                hostMatchingRegex = uri.Scheme + "://" + hostName + uri.PathAndQuery;
+                Debug.WriteLine("Adding regex :: " + hostMatchingRegex);
+                AllowedDomains.Add(hostMatchingRegex);
+
+            }
+            catch (Exception)
+            {
+                Debug.WriteLine("Invalid Whitelist entry (probably missing the protocol):: " + origin);
+            }
+
+        }
+
+        /**   
+         
+         An access request is granted for a given URI if there exists an item inside the access-request list such that:
+
+            - The URI's scheme component is the same as scheme; and
+            - if subdomains is false or if the URI's host component is not a domain name (as defined in [RFC1034]), the URI's host component is the same as host; or
+            - if subdomains is true, the URI's host component is either the same as host, or is a subdomain of host (as defined in [RFC1034]); and
+            - the URI's port component is the same as port.
+         
+         **/
+
+        public bool URLIsAllowed(string url)
+        {
+            // Debug.WriteLine("Testing URLIsAllowed : " + url);
+            // easy case first
+            if (this.AllowAllDomains)
+            {
+                return true;
+            }
+            else
+            {
+                // start simple
+                Uri uri = new Uri(url, UriKind.RelativeOrAbsolute);
+                if (uri.IsAbsoluteUri)
+                {
+                    if (this.SchemeIsAllowed(uri.Scheme))
+                    {
+                        // additional test because our pattern will always have a trailing '/'
+                        string matchUrl = url;
+                        if (uri.PathAndQuery == "/")
+                        {
+                            matchUrl = url + "/";
+                        }
+                        foreach (string pattern in AllowedDomains)
+                        {
+                            if (Regex.IsMatch(matchUrl, pattern))
+                            {
+                                // make sure it is at the start, and not part of the query string
+                                // special case :: http://some.other.domain/page.html?x=1&g=http://build.apache.org/
+                                if (Regex.IsMatch(uri.Scheme + "://" + uri.Host + "/", pattern) ||
+                                     (!Regex.IsMatch(uri.PathAndQuery, pattern)))
+                                {
+                                    return true;
+                                }
+                            }
+                        }
+                    }
+                }
+                else
+                {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public bool IsPluginAllowed(string key)
+        {
+            return AllowAllPlugins || AllowedPlugins.Keys.Contains(key);
+        }
+
+        public string[] AutoloadPlugins
+        {
+            get
+            {
+                var res = from results in AllowedPlugins.TakeWhile(p => p.Value.isAutoLoad)
+                          select results.Value.Name;
+
+                foreach (var s in res)
+                {
+                    Debug.WriteLine(s);
+                }
+                //string[] res = from results in (AllowedPlugins.Where(p => p.Value.isAutoLoad) )
+                //                select (string)results.Key;
+
+                return new string[] { "", "asd" };
+            }
+        }
+
+
+        public void LoadAppPackageConfig()
+        {
+            StreamResourceInfo streamInfo = Application.GetResourceStream(new Uri("config.xml", UriKind.Relative));
+
+            if (streamInfo != null)
+            {
+                StreamReader sr = new StreamReader(streamInfo.Stream);
+                //This will Read Keys Collection for the xml file
+                XDocument document = XDocument.Parse(sr.ReadToEnd());
+
+                var plugins = from results in document.Descendants("plugin")
+                              select new
+                              {
+                                  name = (string)results.Attribute("name"),
+                                  autoLoad = results.Attribute("onload")
+                              };
+
+                foreach (var plugin in plugins)
+                {
+                    Debug.WriteLine("plugin " + plugin.name);
+                    PluginConfig pConfig = new PluginConfig(plugin.name, plugin.autoLoad != null && plugin.autoLoad.Value == "true");
+                    if (pConfig.Name == "*")
+                    {
+                        AllowAllPlugins = true;
+                        // break; wait, don't, some still could be autoload
+                    }
+                    else
+                    {
+                        AllowedPlugins.Add(pConfig.Name, pConfig);
+                    }
+                }
+
+                var preferences = from results in document.Descendants("preference")
+                                  select new
+                                  {
+                                      name = (string)results.Attribute("name"),
+                                      value = (string)results.Attribute("value")
+                                  };
+
+                foreach (var pref in preferences)
+                {
+                    Debug.WriteLine("pref" + pref.name + ", " + pref.value);
+                }
+
+                var accessList = from results in document.Descendants("access")
+                                 select new
+                                 {
+                                     origin = (string)results.Attribute("origin"),
+                                     subdomains = (string)results.Attribute("subdomains") == "true"
+                                 };
+
+                foreach (var accessElem in accessList)
+                {
+                    AddWhiteListEntry(accessElem.origin, accessElem.subdomains);
+                }
+            }
+            else
+            {
+                // no config.xml, allow all
+                AllowAllDomains = true;
+                AllowAllPlugins = true;
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0fea2dd2/lib/cordova-wp8/templates/standalone/cordovalib/CordovaCommandCall.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordovalib/CordovaCommandCall.cs b/lib/cordova-wp8/templates/standalone/cordovalib/CordovaCommandCall.cs
new file mode 100644
index 0000000..facc991
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordovalib/CordovaCommandCall.cs
@@ -0,0 +1,99 @@
+/*  
+	Licensed under the Apache License, Version 2.0 (the "License");
+	you may not use this file except in compliance with the License.
+	You may obtain a copy of the License at
+	
+	http://www.apache.org/licenses/LICENSE-2.0
+	
+	Unless required by applicable law or agreed to in writing, software
+	distributed under the License is distributed on an "AS IS" BASIS,
+	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+	See the License for the specific language governing permissions and
+	limitations under the License.
+*/
+
+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.Linq;
+using System.Collections.Generic;
+
+namespace WPCordovaClassLib.Cordova
+{
+    /// <summary>
+    /// Represents Cordova native command call: action callback, etc
+    /// </summary>
+    public class CordovaCommandCall
+    {
+        public String Service { get; private set; }
+        public String Action { get; private set; }
+        public String CallbackId { get; private set; }
+        public String Args { get; private set; }
+
+        /// <summary>
+        /// Retrieves command call parameters and creates wrapper for them
+        /// </summary>
+        /// <param name="commandStr">Command string in the form 'service/action/callback/args'</param>
+        /// <returns>New class instance or null of string does not represent Cordova command</returns>
+        public static CordovaCommandCall Parse(string commandStr)
+        {
+            System.Diagnostics.Debug.WriteLine("CommandString : " + commandStr);
+            if (string.IsNullOrEmpty(commandStr))
+            {
+                return null;
+            }
+
+            string[] split = commandStr.Split('/');
+            if (split.Length < 3)
+            {
+                return null;
+            }
+
+            CordovaCommandCall commandCallParameters = new CordovaCommandCall();
+            commandCallParameters.Service = split[0];
+            commandCallParameters.Action = split[1];
+            commandCallParameters.CallbackId = split[2];
+
+            try
+            {
+                string arg = split.Length <= 3 ? "[]" : String.Join("/", split.Skip(3));
+                if (!arg.StartsWith("[")) // save the exception
+                {
+                    arg = string.Format("[{0}]", arg);
+                }
+                List<string> args = JSON.JsonHelper.Deserialize<List<string>>(arg);
+                args.Add(commandCallParameters.CallbackId);
+                commandCallParameters.Args = JSON.JsonHelper.Serialize(args.ToArray());
+            }
+            catch (Exception)
+            {
+                return null; 
+            }
+            // sanity check for illegal names
+            // was failing with ::
+            // CordovaCommandResult :: 1, Device1, {"status":1,"message":"{\"name\":\"XD.....
+            if (commandCallParameters.Service.IndexOfAny(new char[] { '@', ':', ',', '!', ' ' }) > -1)
+            {
+                return null;
+            }
+
+            return commandCallParameters;
+        }
+
+
+        /// <summary>
+        /// Private ctr to disable class creation.
+        /// New class instance must be initialized via CordovaCommandCall.Parse static method.
+        /// </summary>
+        private CordovaCommandCall() { }
+
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0fea2dd2/lib/cordova-wp8/templates/standalone/cordovalib/CordovaView.xaml
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordovalib/CordovaView.xaml b/lib/cordova-wp8/templates/standalone/cordovalib/CordovaView.xaml
new file mode 100644
index 0000000..41d7631
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordovalib/CordovaView.xaml
@@ -0,0 +1,65 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.  
+-->
+<UserControl x:Class="WPCordovaClassLib.CordovaView"
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    mc:Ignorable="d"
+    FontFamily="{StaticResource PhoneFontFamilyNormal}"
+    FontSize="{StaticResource PhoneFontSizeNormal}"
+    Foreground="{StaticResource PhoneForegroundBrush}"
+    d:DesignHeight="480" d:DesignWidth="480" 
+    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone">
+    
+    <Grid x:Name="LayoutRoot" Background="Transparent">
+        
+        <phone:WebBrowser x:Name="CordovaBrowser" 
+                          Opacity="0"
+                          HorizontalAlignment="Stretch"  
+                          VerticalAlignment="Stretch" 
+                          IsScriptEnabled="True" 
+                          Foreground="White"
+                          Background="Black"
+                          Navigated="CordovaBrowser_Navigated" 
+                          Loaded="CordovaBrowser_Loaded" 
+                          Unloaded="CordovaBrowser_Unloaded" 
+                          ScriptNotify="CordovaBrowser_ScriptNotify" 
+                          LoadCompleted="CordovaBrowser_LoadCompleted" 
+                          Navigating="CordovaBrowser_Navigating" 
+                          NavigationFailed="CordovaBrowser_NavigationFailed" 
+                          IsGeolocationEnabled="True">
+            <phone:WebBrowser.Projection>
+                <PlaneProjection x:Name="BrowserProjector" CenterOfRotationX="0" RotationY="-180"/>
+            </phone:WebBrowser.Projection>
+            <phone:WebBrowser.Resources>
+                <Storyboard x:Name="RotateIn" BeginTime="0:0:0.5">
+                    <DoubleAnimation
+                        Storyboard.TargetName="BrowserProjector"
+                        Storyboard.TargetProperty="RotationY"
+                        To="0" Duration="0:0:0.6"/>
+                </Storyboard>
+            </phone:WebBrowser.Resources>
+
+        </phone:WebBrowser>
+        
+    </Grid>
+</UserControl>
+
+    

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0fea2dd2/lib/cordova-wp8/templates/standalone/cordovalib/CordovaView.xaml.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordovalib/CordovaView.xaml.cs b/lib/cordova-wp8/templates/standalone/cordovalib/CordovaView.xaml.cs
new file mode 100644
index 0000000..7b92f65
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordovalib/CordovaView.xaml.cs
@@ -0,0 +1,503 @@
+/*  
+	Licensed under the Apache License, Version 2.0 (the "License");
+	you may not use this file except in compliance with the License.
+	You may obtain a copy of the License at
+	
+	http://www.apache.org/licenses/LICENSE-2.0
+	
+	Unless required by applicable law or agreed to in writing, software
+	distributed under the License is distributed on an "AS IS" BASIS,
+	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+	See the License for the specific language governing permissions and
+	limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using Microsoft.Phone.Controls;
+using System.IO.IsolatedStorage;
+using System.Windows.Resources;
+using System.Windows.Interop;
+using System.Runtime.Serialization.Json;
+using System.IO;
+using System.ComponentModel;
+using System.Xml.Linq;
+using WPCordovaClassLib.Cordova.Commands;
+using System.Diagnostics;
+using System.Text;
+using WPCordovaClassLib.Cordova;
+using System.Threading;
+using Microsoft.Phone.Shell;
+using WPCordovaClassLib.Cordova.JSON;
+using WPCordovaClassLib.CordovaLib;
+
+
+
+namespace WPCordovaClassLib
+{
+    public partial class CordovaView : UserControl
+    {
+
+        /// <summary>
+        /// Indicates whether web control has been loaded and no additional initialization is needed.
+        /// Prevents data clearing during page transitions.
+        /// </summary>
+        private bool IsBrowserInitialized = false;
+
+        /// <summary>
+        /// Set when the user attaches a back button handler inside the WebBrowser
+        /// </summary>
+        private bool OverrideBackButton = false;
+
+        /// <summary>
+        /// Sentinal to keep track of page changes as a result of the hardware back button
+        /// Set to false when the back-button is pressed, which calls js window.history.back()
+        /// If the page changes as a result of the back button the event is cancelled.
+        /// </summary>
+        private bool PageDidChange = false;
+
+        private static string AppRoot = "";
+
+
+        /// <summary>
+        /// Handles native api calls
+        /// </summary>
+        private NativeExecution nativeExecution;
+
+        protected BrowserMouseHelper bmHelper;
+        protected DOMStorageHelper domStorageHelper;
+        protected OrientationHelper orientationHelper;
+
+        private ConfigHandler configHandler;
+
+        public System.Windows.Controls.Grid _LayoutRoot
+        {
+            get
+            {
+                return ((System.Windows.Controls.Grid)(this.FindName("LayoutRoot")));
+            }
+        }
+
+        public WebBrowser Browser
+        {
+            get
+            {
+                return CordovaBrowser;
+            }
+        }
+
+        /*
+         * Setting StartPageUri only has an effect if called before the view is loaded.
+         **/
+        protected Uri _startPageUri = null;
+        public Uri StartPageUri
+        {
+            get
+            {
+                if (_startPageUri == null)
+                {
+                    // default
+                    return new Uri(AppRoot + "www/index.html", UriKind.Relative);
+                }
+                else
+                {
+                    return _startPageUri;
+                }
+            }
+            set
+            {
+                if (!this.IsBrowserInitialized)
+                {
+                    _startPageUri = value;
+                }
+            }
+        }
+       
+        /// <summary>
+        /// Gets or sets whether to suppress bouncy scrolling of
+        /// the WebBrowser control;
+        /// </summary>
+        public bool DisableBouncyScrolling
+        {
+            get;
+            set;
+        }
+
+        public CordovaView()
+        {
+
+            InitializeComponent();
+
+            if (DesignerProperties.IsInDesignTool)
+            {
+                return;
+            }
+
+
+            StartupMode mode = PhoneApplicationService.Current.StartupMode;
+
+            if (mode == StartupMode.Launch)
+            {
+                PhoneApplicationService service = PhoneApplicationService.Current;
+                service.Activated += new EventHandler<Microsoft.Phone.Shell.ActivatedEventArgs>(AppActivated);
+                service.Launching += new EventHandler<LaunchingEventArgs>(AppLaunching);
+                service.Deactivated += new EventHandler<DeactivatedEventArgs>(AppDeactivated);
+                service.Closing += new EventHandler<ClosingEventArgs>(AppClosing);
+            }
+            else
+            {
+
+            }
+
+            // initializes native execution logic
+            configHandler = new ConfigHandler();
+            configHandler.LoadAppPackageConfig();
+
+            nativeExecution = new NativeExecution(ref this.CordovaBrowser);
+            bmHelper = new BrowserMouseHelper(ref this.CordovaBrowser);
+        }
+
+
+
+        void AppClosing(object sender, ClosingEventArgs e)
+        {
+            Debug.WriteLine("AppClosing");
+        }
+
+        void AppDeactivated(object sender, DeactivatedEventArgs e)
+        {
+            Debug.WriteLine("INFO: AppDeactivated");
+
+            try
+            {
+                CordovaBrowser.InvokeScript("eval", new string[] { "cordova.fireDocumentEvent('pause');" });
+            }
+            catch (Exception)
+            {
+                Debug.WriteLine("ERROR: Pause event error");
+            }
+        }
+
+        void AppLaunching(object sender, LaunchingEventArgs e)
+        {
+            Debug.WriteLine("INFO: AppLaunching");
+        }
+
+        void AppActivated(object sender, Microsoft.Phone.Shell.ActivatedEventArgs e)
+        {
+            Debug.WriteLine("INFO: AppActivated");
+            try
+            {
+                CordovaBrowser.InvokeScript("eval", new string[] { "cordova.fireDocumentEvent('resume');" });
+            }
+            catch (Exception)
+            {
+                Debug.WriteLine("ERROR: Resume event error");
+            }
+        }
+
+        void CordovaBrowser_Loaded(object sender, RoutedEventArgs e)
+        {
+            this.bmHelper.ScrollDisabled = this.DisableBouncyScrolling;
+
+            if (DesignerProperties.IsInDesignTool)
+            {
+                return;
+            }
+
+            // prevents refreshing web control to initial state during pages transitions
+            if (this.IsBrowserInitialized) return;
+
+
+
+            this.domStorageHelper = new DOMStorageHelper(this.CordovaBrowser);
+
+            try
+            {
+
+                // Before we possibly clean the ISO-Store, we need to grab our generated UUID, so we can rewrite it after.
+                string deviceUUID = "";
+
+                using (IsolatedStorageFile appStorage = IsolatedStorageFile.GetUserStoreForApplication())
+                {
+                    try
+                    {
+                        IsolatedStorageFileStream fileStream = new IsolatedStorageFileStream("DeviceID.txt", FileMode.Open, FileAccess.Read, appStorage);
+
+                        using (StreamReader reader = new StreamReader(fileStream))
+                        {
+                            deviceUUID = reader.ReadLine();
+                        }
+                    }
+                    catch (Exception /*ex*/)
+                    {
+                        deviceUUID = Guid.NewGuid().ToString();
+                    }
+
+                    Debug.WriteLine("Updating IsolatedStorage for APP:DeviceID :: " + deviceUUID);
+                    IsolatedStorageFileStream file = new IsolatedStorageFileStream("DeviceID.txt", FileMode.Create, FileAccess.Write, appStorage);
+                    using (StreamWriter writeFile = new StreamWriter(file))
+                    {
+                        writeFile.WriteLine(deviceUUID);
+                        writeFile.Close();
+                    }
+
+                }
+
+                /*
+                 * 11/08/12 Ruslan Kokorev
+                 * Copying files to isolated storage is no more required in WP8. WebBrowser control now works with files located in XAP.
+                */
+
+                //StreamResourceInfo streamInfo = Application.GetResourceStream(new Uri("CordovaSourceDictionary.xml", UriKind.Relative));
+
+                //if (streamInfo != null)
+                //{
+                //    StreamReader sr = new StreamReader(streamInfo.Stream);
+                //    //This will Read Keys Collection for the xml file
+
+                //    XDocument document = XDocument.Parse(sr.ReadToEnd());
+
+                //    var files = from results in document.Descendants("FilePath")
+                //                select new
+                //                {
+                //                    path = (string)results.Attribute("Value")
+                //                };
+                //    StreamResourceInfo fileResourceStreamInfo;
+
+                //    using (IsolatedStorageFile appStorage = IsolatedStorageFile.GetUserStoreForApplication())
+                //    {
+
+                //        foreach (var file in files)
+                //        {
+                //            fileResourceStreamInfo = Application.GetResourceStream(new Uri(file.path, UriKind.Relative));
+
+                //            if (fileResourceStreamInfo != null)
+                //            {
+                //                using (BinaryReader br = new BinaryReader(fileResourceStreamInfo.Stream))
+                //                {
+                //                    byte[] data = br.ReadBytes((int)fileResourceStreamInfo.Stream.Length);
+
+                //                    string strBaseDir = AppRoot + file.path.Substring(0, file.path.LastIndexOf(System.IO.Path.DirectorySeparatorChar));
+
+                //                    if (!appStorage.DirectoryExists(strBaseDir))
+                //                    {
+                //                        Debug.WriteLine("INFO: Creating Directory :: " + strBaseDir);
+                //                        appStorage.CreateDirectory(strBaseDir);
+                //                    }
+
+                //                    // This will truncate/overwrite an existing file, or 
+                //                    using (IsolatedStorageFileStream outFile = appStorage.OpenFile(AppRoot + file.path, FileMode.Create))
+                //                    {
+                //                        Debug.WriteLine("INFO: Writing data for " + AppRoot + file.path + " and length = " + data.Length);
+                //                        using (var writer = new BinaryWriter(outFile))
+                //                        {
+                //                            writer.Write(data);
+                //                        }
+                //                    }
+                //                }
+                //            }
+                //            else
+                //            {
+                //                Debug.WriteLine("ERROR: Failed to write file :: " + file.path + " did you forget to add it to the project?");
+                //            }
+                //        }
+                //    }
+                //}
+
+                CordovaBrowser.Navigate(StartPageUri);
+                IsBrowserInitialized = true;
+                AttachHardwareButtonHandlers();
+            }
+            catch (Exception ex)
+            {
+                Debug.WriteLine("ERROR: Exception in CordovaBrowser_Loaded :: {0}", ex.Message);
+            }
+        }
+
+        void AttachHardwareButtonHandlers()
+        {
+            PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
+            if (frame != null)
+            {
+                PhoneApplicationPage page = frame.Content as PhoneApplicationPage;
+
+                if (page != null)
+                {
+                    page.BackKeyPress += new EventHandler<CancelEventArgs>(page_BackKeyPress);
+
+                    this.orientationHelper = new OrientationHelper(this.CordovaBrowser, page);
+
+                }
+            }
+        }
+
+        void page_BackKeyPress(object sender, CancelEventArgs e)
+        {
+
+            if (OverrideBackButton)
+            {
+                try
+                {
+                    CordovaBrowser.InvokeScript("eval", new string[] { "cordova.fireDocumentEvent('backbutton');" });
+                    e.Cancel = true;
+                }
+                catch (Exception ex)
+                {
+                    Console.WriteLine("Exception while invoking backbutton into cordova view: " + ex.Message);
+                }
+            }
+            else
+            {
+                try
+                {
+                    PageDidChange = false;
+
+                    Uri uriBefore = this.Browser.Source;
+                    // calling js history.back with result in a page change if history was valid.
+                    CordovaBrowser.InvokeScript("eval", new string[] { "(function(){window.history.back();})()" });
+
+                    Uri uriAfter = this.Browser.Source;
+
+                    e.Cancel = PageDidChange || (uriBefore != uriAfter);
+                }
+                catch (Exception)
+                {
+                    e.Cancel = false; // exit the app ... ?
+                }
+            }
+        }
+
+        void CordovaBrowser_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
+        {
+            string[] autoloadPlugs = this.configHandler.AutoloadPlugins;
+            foreach (string plugName in autoloadPlugs)
+            {
+               // nativeExecution.ProcessCommand(commandCallParams); 
+            }
+
+            string nativeReady = "(function(){ cordova.require('cordova/channel').onNativeReady.fire()})();";
+
+            try
+            {
+                CordovaBrowser.InvokeScript("execScript", new string[] { nativeReady });
+            }
+            catch (Exception /*ex*/)
+            {
+                Debug.WriteLine("Error calling js to fire nativeReady event. Did you include cordova-x.x.x.js in your html script tag?");
+            }
+
+            if (this.CordovaBrowser.Opacity < 1)
+            {
+                this.CordovaBrowser.Opacity = 1;
+                RotateIn.Begin();
+            }
+        }
+
+
+        void CordovaBrowser_Navigating(object sender, NavigatingEventArgs e)
+        {
+            if (!configHandler.URLIsAllowed(e.Uri.ToString()))
+            {
+                Debug.WriteLine("Whitelist exception: Stopping browser from navigating to :: " + e.Uri.ToString());
+                e.Cancel = true;
+                return;
+            }
+
+            this.PageDidChange = true;
+            this.nativeExecution.ResetAllCommands();
+        }
+
+        /*
+         *  This method does the work of routing commands
+         *  NotifyEventArgs.Value contains a string passed from JS 
+         *  If the command already exists in our map, we will just attempt to call the method(action) specified, and pass the args along
+         *  Otherwise, we create a new instance of the command, add it to the map, and call it ...
+         *  This method may also receive JS error messages caught by window.onerror, in any case where the commandStr does not appear to be a valid command
+         *  it is simply output to the debugger output, and the method returns.
+         * 
+         **/
+        void CordovaBrowser_ScriptNotify(object sender, NotifyEventArgs e)
+        {
+            string commandStr = e.Value;
+
+            if (commandStr.IndexOf("DOMStorage") == 0)
+            {
+                this.domStorageHelper.HandleStorageCommand(commandStr);
+                return;
+            }
+            else if (commandStr.IndexOf("Orientation") == 0)
+            {
+                this.orientationHelper.HandleCommand(commandStr);
+                return;
+            }
+
+            CordovaCommandCall commandCallParams = CordovaCommandCall.Parse(commandStr);
+
+            if (commandCallParams == null)
+            {
+                // ERROR
+                Debug.WriteLine("ScriptNotify :: " + commandStr);
+            }
+            else if (commandCallParams.Service == "CoreEvents")
+            {
+                switch (commandCallParams.Action.ToLower())
+                {
+                    case "overridebackbutton":
+                        string arg0 = JsonHelper.Deserialize<string[]>(commandCallParams.Args)[0];
+                        this.OverrideBackButton = (arg0 != null && arg0.Length > 0 && arg0.ToLower() == "true"); 
+                        break;
+                }
+            }
+            else
+            {
+                if (configHandler.IsPluginAllowed(commandCallParams.Service))
+                {
+                    nativeExecution.ProcessCommand(commandCallParams);
+                }
+                else
+                {
+                    Debug.WriteLine("Error::Plugin not allowed in config.xml. " + commandCallParams.Service); 
+                }
+            }
+        }
+
+        public void LoadPage(string url)
+        {
+            if (this.configHandler.URLIsAllowed(url))
+            {
+                this.CordovaBrowser.Navigate(new Uri(url, UriKind.RelativeOrAbsolute));
+            }
+            else
+            {
+                Debug.WriteLine("Oops, Can't load url based on config.xml :: " + url);
+            }
+        }
+
+        private void CordovaBrowser_Unloaded(object sender, RoutedEventArgs e)
+        {
+
+        }
+
+        private void CordovaBrowser_NavigationFailed(object sender, System.Windows.Navigation.NavigationFailedEventArgs e)
+        {
+            Debug.WriteLine("CordovaBrowser_NavigationFailed :: " + e.Uri.ToString());
+        }
+
+        private void CordovaBrowser_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
+        {
+            Debug.WriteLine("CordovaBrowser_Navigated :: " + e.Uri.ToString());
+        }
+
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0fea2dd2/lib/cordova-wp8/templates/standalone/cordovalib/DOMStorageHelper.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordovalib/DOMStorageHelper.cs b/lib/cordova-wp8/templates/standalone/cordovalib/DOMStorageHelper.cs
new file mode 100644
index 0000000..01b6273
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordovalib/DOMStorageHelper.cs
@@ -0,0 +1,145 @@
+/*  
+	Licensed under the Apache License, Version 2.0 (the "License");
+	you may not use this file except in compliance with the License.
+	You may obtain a copy of the License at
+	
+	http://www.apache.org/licenses/LICENSE-2.0
+	
+	Unless required by applicable law or agreed to in writing, software
+	distributed under the License is distributed on an "AS IS" BASIS,
+	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+	See the License for the specific language governing permissions and
+	limitations under the License.
+*/
+
+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 WPCordovaClassLib.Cordova.JSON;
+
+/*
+ * Translates DOMStorage API between JS and Isolated Storage
+ * Missing pieces : QUOTA_EXCEEDED_ERR  + StorageEvent  
+ * */
+
+namespace WPCordovaClassLib
+{
+    public class DOMStorageHelper
+    {
+        protected WebBrowser webBrowser1;
+
+        public DOMStorageHelper(WebBrowser aBrowser)
+        {
+            this.webBrowser1 = aBrowser;
+            // 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;
+                }
+
+            }
+
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0fea2dd2/lib/cordova-wp8/templates/standalone/cordovalib/JSON/JsonHelper.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordovalib/JSON/JsonHelper.cs b/lib/cordova-wp8/templates/standalone/cordovalib/JSON/JsonHelper.cs
new file mode 100644
index 0000000..44511f6
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordovalib/JSON/JsonHelper.cs
@@ -0,0 +1,97 @@
+/*  
+	Licensed under the Apache License, Version 2.0 (the "License");
+	you may not use this file except in compliance with the License.
+	You may obtain a copy of the License at
+	
+	http://www.apache.org/licenses/LICENSE-2.0
+	
+	Unless required by applicable law or agreed to in writing, software
+	distributed under the License is distributed on an "AS IS" BASIS,
+	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+	See the License for the specific language governing permissions and
+	limitations under the License.
+*/
+
+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.Runtime.Serialization.Json;
+using System.IO;
+using System.Collections.Generic;
+using System.Text;
+using System.Diagnostics;
+
+namespace WPCordovaClassLib.Cordova.JSON
+{
+    /// <summary>
+    /// Provides JSON serialization/deserialization functionality.
+    /// </summary>
+    public static class JsonHelper
+    {
+        /// <summary>
+        /// Serializes object to JSON string representation
+        /// </summary>
+        /// <param name="obj">object to serialize</param>
+        /// <returns>JSON representation of the object. Returns 'null' string for null passed as argument</returns>
+        public static string Serialize(object obj)
+        {
+            if (obj == null)
+            {
+                return "null";
+            }
+
+            DataContractJsonSerializer ser = new DataContractJsonSerializer(obj.GetType());
+
+            MemoryStream ms = new MemoryStream();
+            ser.WriteObject(ms, obj);
+
+            ms.Position = 0;
+
+            string json = String.Empty;
+
+            using (StreamReader sr = new StreamReader(ms))
+            {
+                json = sr.ReadToEnd();
+            }
+
+            ms.Close();
+
+            return json;
+
+        }
+
+        /// <summary>
+        /// Parses json string to object instance
+        /// </summary>
+        /// <typeparam name="T">type of the object</typeparam>
+        /// <param name="json">json string representation of the object</param>
+        /// <returns>Deserialized object instance</returns>
+        public static T Deserialize<T>(string json)
+        {
+            DataContractJsonSerializer deserializer = new DataContractJsonSerializer(typeof(T));
+            object result = null;
+            try
+            {
+                using (MemoryStream mem = new MemoryStream(Encoding.UTF8.GetBytes(json)))
+                {
+                    result = deserializer.ReadObject(mem);
+                }
+            }
+            catch (Exception ex)
+            {
+                Debug.WriteLine(ex.Message);
+                Debug.WriteLine("Failed to deserialize " + typeof(T) + " with JSON value :: " + json);
+            }
+
+            return (T)result;
+
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0fea2dd2/lib/cordova-wp8/templates/standalone/cordovalib/NativeExecution.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordovalib/NativeExecution.cs b/lib/cordova-wp8/templates/standalone/cordovalib/NativeExecution.cs
new file mode 100644
index 0000000..af6b207
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordovalib/NativeExecution.cs
@@ -0,0 +1,246 @@
+/*  
+	Licensed under the Apache License, Version 2.0 (the "License");
+	you may not use this file except in compliance with the License.
+	You may obtain a copy of the License at
+	
+	http://www.apache.org/licenses/LICENSE-2.0
+	
+	Unless required by applicable law or agreed to in writing, software
+	distributed under the License is distributed on an "AS IS" BASIS,
+	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+	See the License for the specific language governing permissions and
+	limitations under the License.
+*/
+
+using System;
+using System.Diagnostics;
+using System.Threading;
+using Microsoft.Devices;
+using Microsoft.Phone.Controls;
+using WPCordovaClassLib.Cordova.Commands;
+using System.Windows;
+
+namespace WPCordovaClassLib.Cordova
+{
+    /// <summary>
+    /// Implements logic to execute native command and return result back.
+    /// All commands are executed asynchronous.
+    /// </summary>
+    public class NativeExecution
+    {
+        /// <summary>
+        /// Reference to web part where application is hosted
+        /// </summary>
+        private readonly WebBrowser webBrowser;
+
+        /// <summary>
+        /// Creates new instance of a NativeExecution class. 
+        /// </summary>
+        /// <param name="browser">Reference to web part where application is hosted</param>
+        public NativeExecution(ref WebBrowser browser)
+        {
+            if (browser == null)
+            {
+                throw new ArgumentNullException("browser");
+            }
+
+            this.webBrowser = browser;
+        }
+
+        /// <summary>
+        /// Returns where application is running on emulator
+        /// </summary>
+        /// <returns>True if running on emulator, otherwise False</returns>
+        public static bool IsRunningOnEmulator()
+        {
+            return Microsoft.Devices.Environment.DeviceType == DeviceType.Emulator;
+        }
+
+        public void ResetAllCommands()
+        {
+            CommandFactory.ResetAllCommands();
+        }
+
+        public void AutoLoadCommand(string commandService)
+        {
+            BaseCommand bc = CommandFactory.CreateByServiceName(commandService);
+            if (bc != null)
+            {
+                bc.OnInit();
+            }
+
+        }
+
+        /// <summary>
+        /// Executes command and returns result back.
+        /// </summary>
+        /// <param name="commandCallParams">Command to execute</param>
+        public void ProcessCommand(CordovaCommandCall commandCallParams)
+        {
+
+            if (commandCallParams == null)
+            {
+                throw new ArgumentNullException("commandCallParams");
+            }
+
+            try
+            {
+                BaseCommand bc = CommandFactory.CreateByServiceName(commandCallParams.Service);
+
+                if (bc == null)
+                {
+                    this.OnCommandResult(commandCallParams.CallbackId, new PluginResult(PluginResult.Status.CLASS_NOT_FOUND_EXCEPTION));
+                    return;
+                }
+
+                EventHandler<PluginResult> OnCommandResultHandler = delegate(object o, PluginResult res)
+                {
+                    if (res.CallbackId == null || res.CallbackId == commandCallParams.CallbackId)
+                    {
+                        this.OnCommandResult(commandCallParams.CallbackId, res);
+                        if (!res.KeepCallback)
+                        {
+                            bc.RemoveResultHandler(commandCallParams.CallbackId);
+                        }
+                    }
+                };
+
+                //bc.OnCommandResult += OnCommandResultHandler;
+                bc.AddResultHandler(commandCallParams.CallbackId, OnCommandResultHandler);
+
+                EventHandler<ScriptCallback> OnCustomScriptHandler = delegate(object o, ScriptCallback script)
+                {
+                    this.InvokeScriptCallback(script);
+                };
+
+                bc.OnCustomScript += OnCustomScriptHandler;
+
+                ThreadStart methodInvokation = () =>
+                {
+                    try
+                    {
+                        bc.InvokeMethodNamed(commandCallParams.CallbackId,commandCallParams.Action, commandCallParams.Args);
+                    }
+                    catch (Exception ex)
+                    {
+                        Debug.WriteLine("ERROR: Exception in ProcessCommand :: " + ex.Message);
+                        bc.RemoveResultHandler(commandCallParams.CallbackId);
+                        bc.OnCustomScript -= OnCustomScriptHandler;
+
+                        Debug.WriteLine("ERROR: failed to InvokeMethodNamed :: " + commandCallParams.Action + " on Object :: " + commandCallParams.Service);
+                        this.OnCommandResult(commandCallParams.CallbackId, new PluginResult(PluginResult.Status.INVALID_ACTION));
+                        return;
+                    }
+                };
+
+                if ((bc is File) || (bc is Accelerometer))
+                {
+                    // Due to some issues with the IsolatedStorage in current version of WP8 SDK we have to run all File Api commands synchronously.
+                    // TODO: test this in WP8 RTM
+                    methodInvokation.Invoke();
+                }
+                else
+                {
+                    new Thread(methodInvokation).Start();
+                }
+
+
+            }
+            catch (Exception ex)
+            {
+                // ERROR
+                Debug.WriteLine(String.Format("ERROR: Unable to execute command :: {0}:{1}:{3} ",
+                    commandCallParams.Service, commandCallParams.Action, ex.Message));
+
+                this.OnCommandResult(commandCallParams.CallbackId, new PluginResult(PluginResult.Status.ERROR));
+                return;
+            }
+        }
+
+        /// <summary>
+        /// Handles command execution result.
+        /// </summary>
+        /// <param name="callbackId">Command callback identifier on client side</param>
+        /// <param name="result">Execution result</param>
+        private void OnCommandResult(string callbackId, PluginResult result)
+        {
+            #region  args checking
+
+            if (result == null)
+            {
+                Debug.WriteLine("ERROR: OnCommandResult missing result argument");
+                return;
+            }
+
+            if (String.IsNullOrEmpty(callbackId))
+            {
+                Debug.WriteLine("ERROR: OnCommandResult missing callbackId argument");
+                return;
+            }
+
+            if (!String.IsNullOrEmpty(result.CallbackId) && callbackId != result.CallbackId)
+            {
+                Debug.WriteLine("Multiple Overlapping Results :: " + result.CallbackId + " :: " + callbackId);
+                return;
+            }
+
+            #endregion
+
+            string jsonResult = result.ToJSONString();
+
+            string callback;
+            string args = string.Format("('{0}',{1});", callbackId, jsonResult);
+
+            if (result.Result == PluginResult.Status.NO_RESULT ||
+               result.Result == PluginResult.Status.OK)
+            {
+                callback = @"(function(callbackId,args) {
+                try { args.message = JSON.parse(args.message); } catch (ex) { }
+                cordova.callbackSuccess(callbackId,args);
+                })" + args;
+            }
+            else
+            {
+                callback = @"(function(callbackId,args) {
+                try { args.message = JSON.parse(args.message); } catch (ex) { }
+                cordova.callbackError(callbackId,args);
+                })" + args;
+            }
+            this.InvokeScriptCallback(new ScriptCallback("eval", new string[] { callback }));
+
+        }
+
+        /// <summary>
+        /// Executes client java script
+        /// </summary>
+        /// <param name="script">Script to execute on client side</param>
+        private void InvokeScriptCallback(ScriptCallback script)
+        {
+            if (script == null)
+            {
+                throw new ArgumentNullException("script");
+            }
+
+            if (String.IsNullOrEmpty(script.ScriptName))
+            {
+                throw new ArgumentNullException("ScriptName");
+            }
+
+            //Debug.WriteLine("INFO:: About to invoke ::" + script.ScriptName + " with args ::" + script.Args[0]);
+            this.webBrowser.Dispatcher.BeginInvoke((ThreadStart)delegate()
+            {
+                try
+                {
+                    //Debug.WriteLine("INFO:: InvokingScript::" + script.ScriptName + " with args ::" + script.Args[0]);
+                    this.webBrowser.InvokeScript(script.ScriptName, script.Args);
+                }
+                catch (Exception ex)
+                {
+                    Debug.WriteLine("ERROR: Exception in InvokeScriptCallback :: " + ex.Message);
+                }
+
+            });
+        }
+
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0fea2dd2/lib/cordova-wp8/templates/standalone/cordovalib/OrientationHelper.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordovalib/OrientationHelper.cs b/lib/cordova-wp8/templates/standalone/cordovalib/OrientationHelper.cs
new file mode 100644
index 0000000..0e29b22
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordovalib/OrientationHelper.cs
@@ -0,0 +1,128 @@
+/*  
+	Licensed under the Apache License, Version 2.0 (the "License");
+	you may not use this file except in compliance with the License.
+	You may obtain a copy of the License at
+	
+	http://www.apache.org/licenses/LICENSE-2.0
+	
+	Unless required by applicable law or agreed to in writing, software
+	distributed under the License is distributed on an "AS IS" BASIS,
+	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+	See the License for the specific language governing permissions and
+	limitations under the License.
+*/
+
+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 Microsoft.Phone.Controls;
+
+namespace WPCordovaClassLib.Cordova
+{
+    public class OrientationHelper
+    {
+        protected WebBrowser CordovaBrowser;
+        protected PhoneApplicationPage Page;
+        // private PageOrientation CurrentOrientation = PageOrientation.PortraitUp;
+        //private PageOrientation[] SupportedOrientations; // TODO:
+
+        public OrientationHelper(WebBrowser browser, PhoneApplicationPage page)
+        {
+            CordovaBrowser = browser;
+            Page = page;
+
+            Page.OrientationChanged += new EventHandler<OrientationChangedEventArgs>(page_OrientationChanged);
+            CordovaBrowser.LoadCompleted += new System.Windows.Navigation.LoadCompletedEventHandler(browser_LoadCompleted);
+
+
+        }
+
+        void browser_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
+        {
+            int i = 0;
+
+            switch (Page.Orientation)
+            {
+                case PageOrientation.Portrait: // intentional fall through
+                case PageOrientation.PortraitUp:
+                    i = 0;
+                    break;
+                case PageOrientation.PortraitDown:
+                    i = 180;
+                    break;
+                case PageOrientation.Landscape: // intentional fall through
+                case PageOrientation.LandscapeLeft:
+                    i = -90;
+                    break;
+                case PageOrientation.LandscapeRight:
+                    i = 90;
+                    break;
+            }
+            // Cordova.fireEvent('orientationchange', window);
+            string jsCallback = String.Format("window.orientation = {0};", i);
+
+            try
+            {
+                CordovaBrowser.InvokeScript("execScript", jsCallback);
+            }
+            catch (Exception)
+            {
+            }
+        }
+
+        void page_OrientationChanged(object sender, OrientationChangedEventArgs e)
+        {
+            int i = 0;
+
+            switch (e.Orientation)
+            {
+                case PageOrientation.Portrait: // intentional fall through
+                case PageOrientation.PortraitUp:
+                    i = 0;
+                    break;
+                case PageOrientation.PortraitDown:
+                    i = 180;
+                    break;
+                case PageOrientation.Landscape: // intentional fall through
+                case PageOrientation.LandscapeLeft:
+                    i = -90;
+                    break;
+                case PageOrientation.LandscapeRight:
+                    i = 90;
+                    break;
+            }
+            // Cordova.fireEvent('orientationchange', window);
+            string jsCallback = String.Format("window.orientation = {0};", i);
+
+            try
+            {
+
+                CordovaBrowser.InvokeScript("execScript", jsCallback);
+
+                jsCallback = "var evt = document.createEvent('HTMLEvents');";
+                jsCallback += "evt.initEvent( 'orientationchange', true, false );";
+                jsCallback += "window.dispatchEvent(evt);";
+                jsCallback += "if(window.onorientationchange){window.onorientationchange(evt);}";
+
+                CordovaBrowser.InvokeScript("execScript", jsCallback);
+            }
+            catch (Exception)
+            {
+            }
+        }
+
+        public void HandleCommand(string commandStr)
+        {
+
+        }
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0fea2dd2/lib/cordova-wp8/templates/standalone/cordovalib/PluginResult.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordovalib/PluginResult.cs b/lib/cordova-wp8/templates/standalone/cordovalib/PluginResult.cs
new file mode 100644
index 0000000..00017d2
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordovalib/PluginResult.cs
@@ -0,0 +1,139 @@
+/*  
+	Licensed under the Apache License, Version 2.0 (the "License");
+	you may not use this file except in compliance with the License.
+	You may obtain a copy of the License at
+	
+	http://www.apache.org/licenses/LICENSE-2.0
+	
+	Unless required by applicable law or agreed to in writing, software
+	distributed under the License is distributed on an "AS IS" BASIS,
+	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+	See the License for the specific language governing permissions and
+	limitations under the License.
+*/
+
+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.Text;
+using System.Diagnostics;
+
+namespace WPCordovaClassLib.Cordova
+{
+    /// <summary>
+    /// Represents command execution result
+    /// </summary>
+    public class PluginResult : EventArgs
+    {
+        /// <summary>
+        /// Predefined resultant messages
+        /// </summary>
+        public static string[] StatusMessages = new string[] 
+		{
+			"No result",
+			"OK",
+			"Class not found",
+			"Illegal access",
+			"Instantiation error",
+			"Malformed url",
+			"IO error",
+			"Invalid action",
+			"JSON error",
+			"Error"
+		};
+
+        /// <summary>
+        /// Possible command results status codes
+        /// </summary>
+        public enum Status : int
+        {
+            NO_RESULT = 0,
+            OK,
+            CLASS_NOT_FOUND_EXCEPTION,
+            ILLEGAL_ACCESS_EXCEPTION,
+            INSTANTIATION_EXCEPTION,
+            MALFORMED_URL_EXCEPTION,
+            IO_EXCEPTION,
+            INVALID_ACTION,
+            JSON_EXCEPTION,
+            ERROR
+        };
+
+        public Status Result { get; private set; }
+        public string Message { get; set; }
+        public bool KeepCallback { get; set; }
+        public string CallbackId { get; set; }
+
+        /// <summary>
+        /// Whether command succeded or not
+        /// </summary>
+        public bool IsSuccess
+        {
+            get
+            {
+                return this.Result == Status.OK || this.Result == Status.NO_RESULT;
+            }
+        }
+
+        /// <summary>
+        /// Creates new instance of the PluginResult class.
+        /// </summary>
+        /// <param name="status">Execution result</param>
+        public PluginResult(Status status)
+            : this(status, PluginResult.StatusMessages[(int)status])
+        {
+        }
+
+        /// <summary>
+        /// Creates new instance of the PluginResult class.
+        /// </summary>
+        /// <param name="status">Execution result</param>
+        /// <param name="message">The message</param>
+        public PluginResult(Status status, object message)
+        {
+            this.Result = status;
+            this.Message = JSON.JsonHelper.Serialize(message);
+        }
+
+        public string ToJSONString()
+        {
+            string res = String.Format("\"status\":{0},\"message\":{1},\"keepCallback\":{2}",
+                (int)this.Result,
+                this.Message,
+                this.KeepCallback.ToString().ToLower());
+
+            res = "{" + res + "}";
+            return res;
+
+        }
+
+        [Obsolete]
+        public string ToCallbackString(string callbackId, string successCallback, string errorCallback)
+        {
+            if (this.IsSuccess)
+            {
+                StringBuilder buf = new StringBuilder("");
+                buf.Append(String.Format("{0}('{1}',{2});", successCallback, callbackId, this.ToJSONString()));
+                return buf.ToString();
+            }
+            else
+            {
+                return String.Format("{0}('{1}',{2});", errorCallback, callbackId, this.ToJSONString());
+            }
+        }
+
+        public override String ToString()
+        {
+            return this.ToJSONString();
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0fea2dd2/lib/cordova-wp8/templates/standalone/cordovalib/ScriptCallback.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordovalib/ScriptCallback.cs b/lib/cordova-wp8/templates/standalone/cordovalib/ScriptCallback.cs
new file mode 100644
index 0000000..7878134
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordovalib/ScriptCallback.cs
@@ -0,0 +1,80 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License. 
+*/
+
+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 WPCordovaClassLib.Cordova.JSON;
+using System.Diagnostics;
+
+namespace WPCordovaClassLib.Cordova
+{
+    /// <summary>
+    /// Represents client script function to execute
+    /// </summary>
+    public class ScriptCallback : EventArgs
+    {
+        /// <summary>
+        /// The scripting function to execute.
+        /// </summary>
+        public string ScriptName { get; private set; }
+
+        /// <summary>
+        /// A variable number of strings to pass to the function as parameters.
+        /// </summary>
+        public string[] Args { get; private set; }
+
+        /// <summary>
+        /// Creates new instance of a ScriptCallback class.
+        /// </summary>
+        /// <param name="function">The scripting function to execute</param>
+        /// <param name="args">A variable number of strings to pass to the function as parameters</param>
+        public ScriptCallback(string function, string[] args)
+        {
+            this.ScriptName = function;
+            this.Args = args;
+        }
+
+        /// <summary>
+        /// Creates new instance of a ScriptCallback class.
+        /// </summary>
+        /// <param name="function">The scripting function to execute</param>
+        /// <param name="id">The id argument</param>
+        /// <param name="msg">The message argument</param>
+        /// <param name="value">The value argument</param>
+        public ScriptCallback(string function, string id, object msg, object value)
+        {
+            this.ScriptName = function;
+
+            String arg = String.Format("{{\"id\": {0}, \"msg\": {1}, \"value\": {2}}}",
+                 JsonHelper.Serialize(id), JsonHelper.Serialize(msg), JsonHelper.Serialize(value));
+
+            this.Args = new string[] { arg };
+        }
+
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0fea2dd2/lib/cordova-wp8/templates/standalone/cordovalib/resources/notification-beep.wav
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordovalib/resources/notification-beep.wav b/lib/cordova-wp8/templates/standalone/cordovalib/resources/notification-beep.wav
new file mode 100644
index 0000000..d0ad085
Binary files /dev/null and b/lib/cordova-wp8/templates/standalone/cordovalib/resources/notification-beep.wav differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0fea2dd2/lib/cordova-wp8/templates/standalone/resources/notification-beep.wav
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/resources/notification-beep.wav b/lib/cordova-wp8/templates/standalone/resources/notification-beep.wav
new file mode 100644
index 0000000..d0ad085
Binary files /dev/null and b/lib/cordova-wp8/templates/standalone/resources/notification-beep.wav differ