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:24 UTC

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

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0fea2dd2/lib/cordova-wp7/templates/standalone/cordovalib/CordovaCommandCall.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordovalib/CordovaCommandCall.cs b/lib/cordova-wp7/templates/standalone/cordovalib/CordovaCommandCall.cs
new file mode 100644
index 0000000..810f5e2
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/cordovalib/CordovaCommandCall.cs
@@ -0,0 +1,98 @@
+/*  
+	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)
+        {
+            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-wp7/templates/standalone/cordovalib/CordovaView.xaml
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordovalib/CordovaView.xaml b/lib/cordova-wp7/templates/standalone/cordovalib/CordovaView.xaml
new file mode 100644
index 0000000..b993d97
--- /dev/null
+++ b/lib/cordova-wp7/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="GapBrowser_Navigated" 
+                          Loaded="GapBrowser_Loaded" 
+                          Unloaded="GapBrowser_Unloaded" 
+                          ScriptNotify="GapBrowser_ScriptNotify" 
+                          LoadCompleted="GapBrowser_LoadCompleted" 
+                          Navigating="GapBrowser_Navigating" 
+                          NavigationFailed="GapBrowser_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-wp7/templates/standalone/cordovalib/CordovaView.xaml.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordovalib/CordovaView.xaml.cs b/lib/cordova-wp7/templates/standalone/cordovalib/CordovaView.xaml.cs
new file mode 100644
index 0000000..f6584a8
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/cordovalib/CordovaView.xaml.cs
@@ -0,0 +1,485 @@
+/*  
+	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>
+        /// Sentinel 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 = "/app/";
+
+
+        /// <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;
+                }
+            }
+        }
+
+        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
+            {
+
+            }
+
+            configHandler = new ConfigHandler();
+            configHandler.LoadAppPackageConfig();
+
+            // initializes native execution logic
+            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 GapBrowser_Loaded(object sender, RoutedEventArgs e)
+        {
+            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();
+                    }
+
+                }
+
+                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 GapBrowser_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 GapBrowser_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
+        {
+            string nativeReady = "(function(){ cordova.require('cordova/channel').onNativeReady.fire()})();";
+
+            try
+            {
+                CordovaBrowser.InvokeScript("eval", 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 GapBrowser_Navigating(object sender, NavigatingEventArgs e)
+        {
+            if (!configHandler.URLIsAllowed(e.Uri.ToString()))
+            {
+                e.Cancel = true;
+                return;
+            }
+
+            this.PageDidChange = true;
+            // Debug.WriteLine("GapBrowser_Navigating to :: " + e.Uri.ToString());
+            this.nativeExecution.ResetAllCommands();
+
+            // TODO: check whitelist / blacklist
+            // NOTE: Navigation can be cancelled by setting :        e.Cancel = true;
+        }
+
+        /*
+         *  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 GapBrowser_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)
+        {
+            try 
+            {
+                Uri newLoc = new Uri(url,UriKind.RelativeOrAbsolute);
+                CordovaBrowser.Navigate(newLoc);
+            }
+            catch(Exception)
+            {
+
+            }
+        }
+
+        private void GapBrowser_Unloaded(object sender, RoutedEventArgs e)
+        {
+
+        }
+
+        private void GapBrowser_NavigationFailed(object sender, System.Windows.Navigation.NavigationFailedEventArgs e)
+        {
+            Debug.WriteLine("GapBrowser_NavigationFailed :: " + e.Uri.ToString());
+        }
+
+        private void GapBrowser_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
+        {
+            Debug.WriteLine("GapBrowser_Navigated :: " + e.Uri.ToString());
+        }
+
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0fea2dd2/lib/cordova-wp7/templates/standalone/cordovalib/DOMStorageHelper.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordovalib/DOMStorageHelper.cs b/lib/cordova-wp7/templates/standalone/cordovalib/DOMStorageHelper.cs
new file mode 100644
index 0000000..f57bae4
--- /dev/null
+++ b/lib/cordova-wp7/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 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;
+                }
+
+            }
+
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0fea2dd2/lib/cordova-wp7/templates/standalone/cordovalib/JSON/JsonHelper.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordovalib/JSON/JsonHelper.cs b/lib/cordova-wp7/templates/standalone/cordovalib/JSON/JsonHelper.cs
new file mode 100644
index 0000000..44511f6
--- /dev/null
+++ b/lib/cordova-wp7/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-wp7/templates/standalone/cordovalib/NativeExecution.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordovalib/NativeExecution.cs b/lib/cordova-wp7/templates/standalone/cordovalib/NativeExecution.cs
new file mode 100644
index 0000000..af6b207
--- /dev/null
+++ b/lib/cordova-wp7/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-wp7/templates/standalone/cordovalib/OrientationHelper.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordovalib/OrientationHelper.cs b/lib/cordova-wp7/templates/standalone/cordovalib/OrientationHelper.cs
new file mode 100644
index 0000000..81a329e
--- /dev/null
+++ b/lib/cordova-wp7/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 gapBrowser;
+        protected PhoneApplicationPage page;
+        // private PageOrientation CurrentOrientation = PageOrientation.PortraitUp;
+        //private PageOrientation[] SupportedOrientations; // TODO:
+
+        public OrientationHelper(WebBrowser gapBrowser, PhoneApplicationPage gapPage)
+        {
+            this.gapBrowser = gapBrowser;
+            page = gapPage;
+
+            page.OrientationChanged += new EventHandler<OrientationChangedEventArgs>(page_OrientationChanged);
+            gapBrowser.LoadCompleted += new System.Windows.Navigation.LoadCompletedEventHandler(gapBrowser_LoadCompleted);
+
+
+        }
+
+        void gapBrowser_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
+        {
+            int i = 0;
+
+            switch (this.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
+            {
+                gapBrowser.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
+            {
+
+                gapBrowser.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);}";
+
+                gapBrowser.InvokeScript("execScript", jsCallback);
+            }
+            catch (Exception)
+            {
+            }
+        }
+
+        public void HandleCommand(string commandStr)
+        {
+
+        }
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0fea2dd2/lib/cordova-wp7/templates/standalone/cordovalib/PluginResult.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordovalib/PluginResult.cs b/lib/cordova-wp7/templates/standalone/cordovalib/PluginResult.cs
new file mode 100644
index 0000000..00017d2
--- /dev/null
+++ b/lib/cordova-wp7/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-wp7/templates/standalone/cordovalib/ScriptCallback.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordovalib/ScriptCallback.cs b/lib/cordova-wp7/templates/standalone/cordovalib/ScriptCallback.cs
new file mode 100644
index 0000000..7878134
--- /dev/null
+++ b/lib/cordova-wp7/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-wp7/templates/standalone/cordovalib/resources/notification-beep.wav
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordovalib/resources/notification-beep.wav b/lib/cordova-wp7/templates/standalone/cordovalib/resources/notification-beep.wav
new file mode 100644
index 0000000..d0ad085
Binary files /dev/null and b/lib/cordova-wp7/templates/standalone/cordovalib/resources/notification-beep.wav differ

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