cordova-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From agri...@apache.org
Subject [13/22] Android Redirect plugin to reroute cordova.js and menu requests. Put all the web code in a www directory.
Date Mon, 22 Apr 2013 20:14:53 GMT
http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/022ebbbe/js/libs/q.min.js
----------------------------------------------------------------------
diff --git a/js/libs/q.min.js b/js/libs/q.min.js
deleted file mode 100644
index 7a27b9a..0000000
--- a/js/libs/q.min.js
+++ /dev/null
@@ -1,19 +0,0 @@
-(function(k){"function"===typeof bootstrap?bootstrap("promise",k):"object"===typeof exports?module.exports=k():"function"===typeof
define&&define.amd?define(k):"undefined"!==typeof ses?ses.ok()&&(ses.makeQ=k):Q=k()})(function(){function
k(a){var b=Function.call;return function(){return b.apply(a,arguments)}}function L(a,b){b.stack&&("object"===typeof
a&&null!==a&&a.stack&&-1===a.stack.indexOf(M))&&(a.stack=N(a.stack)+"\n"+M+"\n"+N(b.stack))}function
N(a){for(var a=a.split("\n"),b=[],d=0;d<a.length;++d){var j=
-a[d],c;if(c=/at .+ \((.*):(\d+):\d+\)/.exec(j)){var g=c[2];c=c[1]===O&&g>=aa&&g<=ba}else
c=!1;!c&&!(-1!==j.indexOf("(module.js:")||-1!==j.indexOf("(node.js:"))&&b.push(j)}return
b.join("\n")}function P(){if(Error.captureStackTrace){var a,b,d=Error.prepareStackTrace;Error.prepareStackTrace=function(d,c){a=c[1].getFileName();b=c[1].getLineNumber()};Error().stack;Error.prepareStackTrace=d;O=a;return
b}}function c(a){return p(a)}function i(){function a(a){b&&(j=p(a),t(b,function(a,b){l(function(){j.promiseDispatch.apply(j,
-b)})},void 0),d=b=void 0)}var b=[],d=[],j,e=C(i.prototype),g=C(m.prototype);g.promiseDispatch=function(a,c,g){var
e=h(arguments);b?(b.push(e),"when"===c&&g[1]&&d.push(g[1])):l(function(){j.promiseDispatch.apply(j,e)})};g.valueOf=function(){if(b)return
g;var a=o(j);u(a)&&(j=a);return a};Error.captureStackTrace&&0<c.longStackJumpLimit&&(Error.captureStackTrace(g,i),g.stack=g.stack.substring(g.stack.indexOf("\n")+1));e.promise=g;e.resolve=a;e.fulfill=function(b){a(D(b))};e.reject=function(b){a(n(b))};
-e.notify=function(a){b&&t(d,function(b,d){l(function(){d(a)})},void 0)};return e}function
m(a,b,d,c,e){void 0===b&&(b=function(a){return n(Error("Promise does not support operation:
"+a))});var g=C(m.prototype);g.promiseDispatch=function(d,c,j){var e;try{e=a[c]?a[c].apply(g,j):b.call(g,c,j)}catch(f){e=n(f)}d&&d(e)};d&&(g.valueOf=d);e&&(g.exception=c);return
g}function o(a){return u(a)?a.valueOf():a}function u(a){return a&&"function"===typeof
a.promiseDispatch}function E(a){return a&&"function"===
-typeof a.then}function F(a){return!E(o(a))}function R(a){a=o(a);return u(a)&&"exception"in
a}function n(a){var b=m({when:function(b){if(b){var c=ca(G,this);-1!==c&&(v.splice(c,1),G.splice(c,1))}return
b?b(a):this}},function(){return n(a)},function(){return this},a,!0);!S&&("undefined"!==typeof
window&&!window.Touch&&window.console)&&console.log("Should be empty:",v);S=!0;G.push(b);v.push(a);return
b}function D(a){return m({when:function(){return a},get:function(b){return a[b]},set:function(b,d){a[b]=
-d},"delete":function(b){delete a[b]},post:function(b,d){return null===b||void 0===b?a.apply(void
0,d):a[b].apply(a,d)},apply:function(b,d){return a.apply(b,d)},keys:function(){return da(a)}},void
0,function(){return a})}function p(a){if(u(a))return a;a=o(a);if(E(a)){var b=a,d=i();l(function(){try{b.then(d.resolve,d.reject,d.notify)}catch(a){d.reject(a)}});return
d.promise}return D(a)}function f(a,b,d,j){function e(a){try{return"function"===typeof b?b(a):a}catch(d){return
n(d)}}function g(a){if("function"===
-typeof d){L(a,k);try{return d(a)}catch(b){return n(b)}}return n(a)}var f=i(),h=!1,k=p(a);l(function(){k.promiseDispatch(function(a){h||(h=!0,f.resolve(e(a)))},"when",[function(a){h||(h=!0,f.resolve(g(a)))}])});k.promiseDispatch(void
0,"when",[void 0,function(a){var b,d=!1;try{b="function"===typeof j?j(a):a}catch(e){if(d=!0,c.onerror)c.onerror(e);else
throw e;}d||f.notify(b)}]);return f.promise}function T(a,b,d){return f(a,function(a){return
A(a).then(function(a){return b.apply(void 0,a)},d)},d)}function w(a,
-b,d){var c=i();l(function(){p(a).promiseDispatch(c.resolve,b,d)});return c.promise}function
q(a){return function(b){var d=h(arguments,1);return w(b,a,d)}}function U(a,b){var d=h(arguments,2);return
H(a,b,d)}function r(a,b){return w(a,"apply",[void 0,b])}function I(a){var b=h(arguments,1);return
r(a,b)}function A(a){return f(a,function(a){var d=0,c=i();t(a,function(e,g,h){F(g)?a[h]=o(g):(++d,f(g,function(e){a[h]=e;0===--d&&c.resolve(a)},c.reject))},void
0);0===d&&c.resolve(a);return c.promise})}function V(a,
-b){return f(a,void 0,b)}var aa=P(),O,W=function(){},l;if("undefined"!==typeof process)l=process.nextTick;else
if("function"===typeof setImmediate)l="undefined"!==typeof window?setImmediate.bind(window):setImmediate;else{var
X=function(){--s;if(++J>=x){J=0;x*=4;for(var a=y&&Math.min(y-1,x);s<a;)++s,B()}for(;y;)--y,z=z.next,a=z.task,z.task=void
0,a();J=0},z={task:void 0,next:null},Y=z,x=2,s=0,y=0,J=0,B;l=function(a){Y=Y.next={task:a,next:null};s<++y&&s<x&&(++s,B())};if("undefined"!==typeof
MessageChannel){var Z=
-new MessageChannel;Z.port1.onmessage=X;B=function(){Z.port2.postMessage(0)}}else B=function(){setTimeout(X,0)}}var
h=k(Array.prototype.slice),t=k(Array.prototype.reduce||function(a,b){var d=0,c=this.length;if(1===arguments.length){do{if(d
in this){b=this[d++];break}if(++d>=c)throw new TypeError;}while(1)}for(;d<c;d++)d in
this&&(b=a(b,this[d],d));return b}),ca=k(Array.prototype.indexOf||function(a){for(var
b=0;b<this.length;b++)if(this[b]===a)return b;return-1}),$=k(Array.prototype.map||function(a,
-b){var d=this,c=[];t(d,function(e,g,f){c.push(a.call(b,g,f,d))},void 0);return c}),C=Object.create||function(a){function
b(){}b.prototype=a;return new b},ea=k(Object.prototype.hasOwnProperty),da=Object.keys||function(a){var
b=[],d;for(d in a)ea(a,d)&&b.push(d);return b},fa=k(Object.prototype.toString),K;K="undefined"!==typeof
ReturnValue?ReturnValue:function(a){this.value=a};c.longStackJumpLimit=1;var M="From previous
event:";c.nextTick=l;c.defer=i;i.prototype.makeNodeResolver=function(){var a=this;
-return function(b,d){b?a.reject(b):2<arguments.length?a.resolve(h(arguments,1)):a.resolve(d)}};c.promise=function(a){var
b=i();I(a,b.resolve,b.reject,b.notify).fail(b.reject);return b.promise};c.makePromise=m;m.prototype.then=function(a,b,d){return
f(this,a,b,d)};m.prototype.thenResolve=function(a){return f(this,function(){return a})};m.prototype.thenReject=function(a){return
f(this,function(){throw a;})};t("isFulfilled isRejected isPending dispatch when spread get
put set del delete post send invoke keys fapply fcall fbind all allResolved timeout delay
catch finally fail fin progress done nfcall nfapply nfbind denodeify nbind ncall napply nbind
npost nsend ninvoke nodeify".split(" "),
-function(a,b){m.prototype[b]=function(){return c[b].apply(c,[this].concat(h(arguments)))}},void
0);m.prototype.toSource=function(){return this.toString()};m.prototype.toString=function(){return"[object
Promise]"};c.nearer=o;c.isPromise=u;c.isPromiseAlike=E;c.isPending=function(a){return!F(a)&&!R(a)};c.isFulfilled=F;c.isRejected=R;var
G=[],v=[],S;if("undefined"!==typeof process&&process.on)process.on("exit",function(){for(var
a=0;a<v.length;a++){var b=v[a];b&&"undefined"!==typeof b.stack?console.warn("Unhandled
rejected promise:",
-b.stack):console.warn("Unhandled rejected promise (no stack):",b)}});c.reject=n;c.fulfill=D;c.resolve=p;c.master=function(a){return
m({isDef:function(){}},function(b,d){return w(a,b,d)},function(){return o(a)})};c.when=f;c.spread=T;c.async=function(a){return
function(){function b(a,b){var h;try{h=d[a](b)}catch(i){return"[object StopIteration]"===fa(i)||i
instanceof K?i.value:n(i)}return f(h,c,e)}var d=a.apply(this,arguments),c=b.bind(b,"send"),e=b.bind(b,"throw");return
c()}};c["return"]=function(a){throw new K(a);
-};c.promised=function(a){return function(){return T([this,A(arguments)],function(b,d){return
a.apply(b,d)})}};c.dispatch=w;c.dispatcher=q;c.get=q("get");c.set=q("set");c["delete"]=c.del=q("delete");var
H=c.post=q("post");c.send=U;c.invoke=U;c.fapply=r;c["try"]=I;c.fcall=I;c.fbind=function(a){var
b=h(arguments,1);return function(){var d=b.concat(h(arguments));return w(a,"apply",[this,d])}};c.keys=q("keys");c.all=A;c.allResolved=function(a){return
f(a,function(a){a=$(a,p);return f(A($(a,function(a){return f(a,
-W,W)})),function(){return a})})};c["catch"]=c.fail=V;c.progress=function(a,b){return f(a,void
0,void 0,b)};c["finally"]=c.fin=function(a,b){return f(a,function(a){return f(b(),function(){return
a})},function(a){return f(b(),function(){return n(a)})})};c.done=function(a,b,d,j){var e=function(b){l(function(){L(b,a);if(c.onerror)c.onerror(b);else
throw b;})},b=b||d||j?f(a,b,d,j):a;"object"===typeof process&&(process&&process.domain)&&(e=process.domain.bind(e));V(b,e)};c.timeout=function(a,b){var
d=i(),
-c=setTimeout(function(){d.reject(Error("Timed out after "+b+" ms"))},b);f(a,function(a){clearTimeout(c);d.resolve(a)},function(a){clearTimeout(c);d.reject(a)},d.notify);return
d.promise};c.delay=function(a,b){void 0===b&&(b=a,a=void 0);var d=i();f(a,void 0,void
0,d.notify);setTimeout(function(){d.resolve(a)},b);return d.promise};c.nfapply=function(a,b){var
d=h(b),c=i();d.push(c.makeNodeResolver());r(a,d).fail(c.reject);return c.promise};c.nfcall=function(a){var
b=h(arguments,1),d=i();b.push(d.makeNodeResolver());
-r(a,b).fail(d.reject);return d.promise};c.nfbind=function(a){var b=h(arguments,1);return
function(){var d=b.concat(h(arguments)),c=i();d.push(c.makeNodeResolver());r(a,d).fail(c.reject);return
c.promise}};c.denodeify=c.nfbind;c.nbind=function(a,b){var d=h(arguments,2);return function(){var
c=d.concat(h(arguments)),e=i();c.push(e.makeNodeResolver());r(function(){return a.apply(b,arguments)},c).fail(e.reject);return
e.promise}};c.npost=function(a,b,d){var d=h(d||[]),c=i();d.push(c.makeNodeResolver());
-H(a,b,d).fail(c.reject);return c.promise};c.nsend=function(a,b){var c=h(arguments,2),f=i();c.push(f.makeNodeResolver());H(a,b,c).fail(f.reject);return
f.promise};c.ninvoke=c.nsend;c.nodeify=function(a,b){if(b)a.then(function(a){l(function(){b(null,a)})},function(a){l(function(){b(a)})});else
return a};var ba=P();return c});

http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/022ebbbe/plugins/CordovaAppHarnessRedirect/plugin.xml
----------------------------------------------------------------------
diff --git a/plugins/CordovaAppHarnessRedirect/plugin.xml b/plugins/CordovaAppHarnessRedirect/plugin.xml
new file mode 100644
index 0000000..97d0c59
--- /dev/null
+++ b/plugins/CordovaAppHarnessRedirect/plugin.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<plugin xmlns="http://phonegap.com/ns/plugins/1.0"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    id="CordovaAppHarnessRedirect"
+    version="1.0.0">
+  <engines>
+    <engine name="cordova" version=">=2.6.0" />
+  </engines>
+
+  <name>Cordova App Harness Redirect Internal Urls</name>
+
+  <platform name="android">
+    <source-file src="src/android/CordovaAppHarnessRedirect.java" target-dir="src/org/apache/cordova/cordovaappharness"
/>
+
+    <config-file target="res/xml/config.xml" parent="/cordova/plugins">
+        <plugin name="CordovaAppHarnessRedirect" value="org.apache.cordova.cordovaappharness.CordovaAppHarnessRedirect">
+          <url-filter value="file://" />
+        </plugin>
+    </config-file>
+  </platform>
+
+  <platform name="ios">
+
+  </platform>
+</plugin>

http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/022ebbbe/plugins/CordovaAppHarnessRedirect/src/android/CordovaAppHarnessRedirect.java
----------------------------------------------------------------------
diff --git a/plugins/CordovaAppHarnessRedirect/src/android/CordovaAppHarnessRedirect.java
b/plugins/CordovaAppHarnessRedirect/src/android/CordovaAppHarnessRedirect.java
new file mode 100644
index 0000000..0372ed1
--- /dev/null
+++ b/plugins/CordovaAppHarnessRedirect/src/android/CordovaAppHarnessRedirect.java
@@ -0,0 +1,49 @@
+package org.apache.cordova.cordovaappharness;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.cordova.api.CordovaPlugin;
+import org.apache.cordova.FileHelper;
+import android.webkit.WebResourceResponse;
+
+public class CordovaAppHarnessRedirect extends CordovaPlugin {
+
+    // Ensure we we redirect any file:///*/cordova.js uri's to the the cordova.js located
in the assets
+    // Ensure we redirect any file:///*/__cordovaappharness_contextMenu_{menu_choice} uri's
to the correct locations
+    @Override
+    public WebResourceResponse shouldInterceptRequest(String url) {
+
+        String cleanUrl = url.split("\\?")[0].split("#")[0];
+        String[] urlParts = cleanUrl.split("/");
+        String fileName = urlParts[urlParts.length - 1];
+
+        if(fileName.equals("cordova.js")) {
+            url = "cordova.js";
+        } else if(fileName.equals("__cordovaappharness_contextMenu_page.html")) {
+            url = "contextMenu.html";
+        } else if(fileName.equals("__cordovaappharness_contextMenu_script.js")) {
+            url = "js/ContextMenu.js";
+        } else if(fileName.equals("__cordovaappharness_contextMenu_mainmenu")) {
+            this.webView.loadUrl("file:///android_asset/www/index.html");
+            return null;
+        } else {
+            return null;
+        }
+
+        String mimetype = FileHelper.getMimeType(url, this.cordova);
+        String encoding = null;
+        if (mimetype != null && mimetype.startsWith("text/")) {
+            encoding = "UTF-8";
+        }
+
+        InputStream is = null;
+        try {
+            is = this.cordova.getActivity().getAssets().open("www/" + url);
+        } catch (IOException ioe) {
+            return null;
+        }
+
+        return new WebResourceResponse(mimetype, encoding, is);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/022ebbbe/views/add.html
----------------------------------------------------------------------
diff --git a/views/add.html b/views/add.html
deleted file mode 100644
index 3016d4b..0000000
--- a/views/add.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<form name="addForm" ng-controller="AddCtrl">
-    <label for="inputAppName">Enter the App Name</label><br />
-    <input type="text" name="appName" ng-model="appName" ng-pattern="/^[\w ]*$/" ng-maxlength="64"
required />
-    <span ng-show="addForm.appName.$error.required">Required</span>
-    <span ng-show="addForm.appName.$error.pattern">Invalid characters used</span>
-    <span ng-show="addForm.appName.$error.maxlength">Too long</span>
-    <br />
-
-    <input type="radio" ng-model="appSource" name="appSource" value="urlToZip" ng-init="appUrlChecked=true;
appSource='urlToZip'" ng-checked="appUrlChecked" />
-        <label for="inputAppUrl">Enter the URL(should point to a zip file)</label><br
/>
-        <input id="inputAppUrl" type="url" name="appUrl" ng-model="appUrl" ng-disabled="!appUrlChecked"
ng-required="appUrlChecked" />
-        <span ng-show="addForm.appUrl.$error.required">Required</span>
-        <span ng-show="addForm.appUrl.$error.url">Not a URL</span>
-        <br />
-    <button ng-click="addApp(appName, appSource, appUrl)" ng-disabled="!(addForm.$valid)">Add</button>
-</form>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/022ebbbe/views/list.html
----------------------------------------------------------------------
diff --git a/views/list.html b/views/list.html
deleted file mode 100644
index 032ea3a..0000000
--- a/views/list.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<ul>
-	<li ng-repeat="app in appsList"> 
-        <p>{{app}}</p>
-        <button ng-click="launchApp(app)">Launch</button>
-		<button ng-click="refreshApp(app)">Refresh</button>
-		<button ng-click="removeApp(app)">Remove</button>
-        <br />
-	</li>
-</ul>
-<button ng-click="loadAppsList()">Reload Apps List</button>
-<br />
-<a href="#/add">Add new App</a>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/022ebbbe/www/contextMenu.html
----------------------------------------------------------------------
diff --git a/www/contextMenu.html b/www/contextMenu.html
new file mode 100644
index 0000000..27ddd0d
--- /dev/null
+++ b/www/contextMenu.html
@@ -0,0 +1,47 @@
+<!-- Keep stylesheet as a part of the html as this file gets injected into the app -->
+<style>
+#__cordovaappharness_contextMenu_div
+{
+    position: fixed;
+    left : 0px;
+    top : 0px;
+    z-index: 2000;
+    background-color:rgba(0,0,0,0.75);
+    width: 100%;
+    height: 100%;
+    display: none;
+}
+#__cordovaappharness_contextMenu_div p
+{
+    color: white;
+    text-align: center;
+}
+
+#__cordovaappharness_contextMenu_div ul
+{
+    list-style-type: none;
+    margin-left: 20%;
+    margin-right: 20%;
+    padding: 0;
+    width: 60%;
+}
+
+#__cordovaappharness_contextMenu_div li, #__cordovaappharness_contextMenu_div button
+{
+    width: 100%;
+}
+</style>
+<div id="__cordovaappharness_contextMenu_div">
+    <p>Tap Anywhere to Close</p>
+    <ul>
+        <li>
+            <button>Update</button>
+        </li>
+        <li>
+            <button>Restart</button>
+        </li>
+        <li>
+            <a href="file://__cordovaappharness_contextMenu_mainmenu"><button>Back
to Main Menu</button></a>
+        </li>
+    </ul>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/022ebbbe/www/index.html
----------------------------------------------------------------------
diff --git a/www/index.html b/www/index.html
new file mode 100644
index 0000000..c897d14
--- /dev/null
+++ b/www/index.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>Cordova App Harness</title>
+        <script type="text/javascript" src="cordova.js"></script>
+        <script type="text/javascript" src="js/libs/q.min.js"></script>
+        <script type="text/javascript" src="js/libs/angular.min.js"></script>
+        <script type="text/javascript" src="js/app.js"></script>
+        <script type="text/javascript" src="js/AppConstants.js"></script>
+        <script type="text/javascript" src="js/ResourcesLoader.js"></script>
+        <script type="text/javascript" src="js/AppsService.js"></script>
+        <script type="text/javascript" src="js/ListCtrl.js"></script>
+        <script type="text/javascript" src="js/AddCtrl.js"></script>
+    </head>
+    <body ng-app="CordovaAppHarness" ng-view>
+    </body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/022ebbbe/www/js/AddCtrl.js
----------------------------------------------------------------------
diff --git a/www/js/AddCtrl.js b/www/js/AddCtrl.js
new file mode 100644
index 0000000..f828f54
--- /dev/null
+++ b/www/js/AddCtrl.js
@@ -0,0 +1,24 @@
+(function(){
+    "use strict";
+    /* global myApp */
+    myApp.controller("AddCtrl", ["$scope", "AppsService", function ($scope, AppsService)
{
+
+        $scope.addApp = function(appName, appSource, appUrl) {
+            if(appSource === "urlToZip") {
+                if(!appUrl) {
+                    alert("Url not specified");
+                    return;
+                }
+
+                AppsService.addAppFromZipUrl(appName, appUrl)
+                .then(function() {
+                    alert("Successfully installed");
+                }, function(error) {
+                    console.error(error);
+                    alert("Unable to add application because: \n" + JSON.stringify(error));
+                });
+            }
+        };
+    }]);
+
+})();
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/022ebbbe/www/js/AppConstants.js
----------------------------------------------------------------------
diff --git a/www/js/AppConstants.js b/www/js/AppConstants.js
new file mode 100644
index 0000000..461c700
--- /dev/null
+++ b/www/js/AppConstants.js
@@ -0,0 +1,10 @@
+(function() {
+    var TEMP_DIRECTORY = "cordova_app_harness_tempDir/";
+    var INSTALL_DIRECTORY = "cordova_app_harness_installed_apps/";
+    var APPS_JSON = "cordova_app_harness_installed_apps/apps.json";
+
+    /* global myApp */
+    myApp.value("TEMP_DIRECTORY", TEMP_DIRECTORY);
+    myApp.value("INSTALL_DIRECTORY", INSTALL_DIRECTORY);
+    myApp.value("APPS_JSON", APPS_JSON);
+})();
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/022ebbbe/www/js/AppsService.js
----------------------------------------------------------------------
diff --git a/www/js/AppsService.js b/www/js/AppsService.js
new file mode 100644
index 0000000..ba012a9
--- /dev/null
+++ b/www/js/AppsService.js
@@ -0,0 +1,104 @@
+(function() {
+    "use strict";
+    /* global myApp */
+    myApp.factory("AppsService", [ "ResourcesLoader", "INSTALL_DIRECTORY", "TEMP_DIRECTORY",
"APPS_JSON", "$window", function(ResourcesLoader, INSTALL_DIRECTORY, TEMP_DIRECTORY, APPS_JSON,
$window) {
+
+        function addNewAppFromUrl(appName, appUrl) {
+            var fileName = TEMP_DIRECTORY + appName + ".zip";
+            var _fullFilePath;
+
+            return ResourcesLoader.downloadFromUrl(appUrl, fileName)
+            .then(function(fullFilePath){
+                _fullFilePath = fullFilePath;
+                return ResourcesLoader.ensureDirectoryExists(INSTALL_DIRECTORY + appName);
+            })
+            .then(function(directoryPath){
+                return extractZipToDirectory(_fullFilePath, directoryPath);
+            })
+            .then(function(){
+                return registerApp(appName, "urlToZip", appUrl);
+            });
+        }
+
+        function extractZipToDirectory(fileName, outputDirectory){
+            var deferred = Q.defer();
+
+            var onZipDone = function(returnCode) {
+                if(returnCode !== 0) {
+                    deferred.reject(new Error("Something went wrong during the unzipping
of: " + fileName));
+                } else {
+                    deferred.resolve();
+                }
+            };
+
+            /* global zip */
+            zip.unzip(fileName, outputDirectory, onZipDone);
+            return deferred.promise;
+        }
+
+        function registerApp(appName, appSource, appUrl) {
+            return ResourcesLoader.readJSONFileContents(APPS_JSON)
+            .then(function(result){
+                result.installedApps = result.installedApps || [];
+                result.installedApps.push({
+                    "Name" :  appName,
+                    "Source" : appSource,
+                    "Url" : appUrl
+                });
+                return ResourcesLoader.writeJSONFileContents(APPS_JSON, result);
+            });
+        }
+
+        function getAbsoluteUrl(relativeUrl) {
+            // Can't use $document from angularJS as it does not provie the create constructor
+            /* global document */
+            var a = document.createElement("a");
+            a.href = relativeUrl;
+            return a.href;
+        }
+
+        function getAppStartPageFromAppLocation(appLocation) {
+            appLocation += (appLocation.substring(appLocation.length - 1) === "/") ? "" :
"/";
+            var startLocation = appLocation + "www/index.html";
+            return startLocation;
+        }
+
+        return {
+            //return promise with the array of apps
+            getAppsList : function() {
+                return ResourcesLoader.ensureDirectoryExists(APPS_JSON)
+                .then(function() {
+                    return ResourcesLoader.readJSONFileContents(APPS_JSON);
+                })
+                .then(function(result){
+                    result.installedApps = result.installedApps || [];
+                    var newAppsList = [];
+
+                    for(var i = 0; i < result.installedApps.length; i++){
+                        newAppsList.push(result.installedApps[i].Name);
+                    }
+
+                    return newAppsList;
+                });
+            },
+
+            launchApp : function(appName) {
+                return ResourcesLoader.getFullFilePath(INSTALL_DIRECTORY + appName)
+                .then(function(appLocation) {
+                    var startLocation = getAppStartPageFromAppLocation(appLocation);
+                    document.location = startLocation;
+                });
+            },
+
+            addAppFromZipUrl : function(appName, appUrl) {
+                return this.getAppsList()
+                .then(function(appsList){
+                    if(appsList.indexOf(appName) !== -1) {
+                        throw new Error("An app with this name already exists");
+                    }
+                    return addNewAppFromUrl(appName, appUrl);
+                });
+            }
+        };
+    }]);
+})();
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/022ebbbe/www/js/ContextMenu.js
----------------------------------------------------------------------
diff --git a/www/js/ContextMenu.js b/www/js/ContextMenu.js
new file mode 100644
index 0000000..1e3a760
--- /dev/null
+++ b/www/js/ContextMenu.js
@@ -0,0 +1,38 @@
+(function () {
+
+    function initialise() {
+        var contextHTMLUrl = "file://__cordovaappharness_contextMenu_page.html";
+        var xhr = new window.XMLHttpRequest();
+        xhr.onreadystatechange=function()
+        {
+            if (xhr.readyState==4 && xhr.status==200)
+            {
+                var stringifiedHtml = xhr.responseText;
+                onInject(stringifiedHtml);
+            }
+        };
+        // retrieve the context menu
+        xhr.open("GET", contextHTMLUrl, true);
+        xhr.send();
+    }
+
+    function onInject(stringifiedHtml) {
+
+        document.body.innerHTML += stringifiedHtml;
+
+        var contextDiv = "__cordovaappharness_contextMenu_div";
+        // Setup the listeners to toggle the context menu
+        document.addEventListener("touchmove", function (event) {
+            if(event.touches.length >= 3) {
+                document.getElementById(contextDiv).style.display = "inline";
+            }
+        }, false);
+
+        document.getElementById(contextDiv).onclick = function() {
+            document.getElementById(contextDiv).style.display = "none";
+        };
+    }
+
+    initialise();
+})();
+

http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/022ebbbe/www/js/ListCtrl.js
----------------------------------------------------------------------
diff --git a/www/js/ListCtrl.js b/www/js/ListCtrl.js
new file mode 100644
index 0000000..233c0dc
--- /dev/null
+++ b/www/js/ListCtrl.js
@@ -0,0 +1,42 @@
+(function(){
+    "use strict";
+    /* global myApp */
+    myApp.controller("ListCtrl", [ "$scope", "$document", "AppsService", function ($scope,
$document, AppsService) {
+
+        $scope.appsList = [];
+
+        $scope.loadAppsList = function( source ) {
+            AppsService.getAppsList()
+            .then(function(newAppsList){
+                //clear the old apps list
+                $scope.appsList.splice(0, $scope.appsList.length);
+                angular.extend($scope.appsList, newAppsList);
+                if(source === "deviceready") {
+                    $scope.$apply();
+                }
+            }, function(error){
+                var str = "There was an error retrieving the apps list";
+                console.error(str + JSON.stringify(error));
+                alert(str);
+            });
+        };
+
+        $scope.launchApp = function(app){
+            AppsService.launchApp(app)
+            .then(null, function(error){
+                console.error("Error during loading of app: " + error);
+                alert("Something went wrong during the loading of the app. Please try again.");
+            });
+        };
+
+        $scope.refreshApp = function(app) {
+            alert("refreshApp called: " + app);
+        };
+
+        $scope.removeApp = function(app) {
+            alert("removeApp called: " + app);
+        };
+
+        $document.bind("deviceready", function() { $scope.loadAppsList("deviceready"); });
+    }]);
+})();
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/022ebbbe/www/js/ResourcesLoader.js
----------------------------------------------------------------------
diff --git a/www/js/ResourcesLoader.js b/www/js/ResourcesLoader.js
new file mode 100644
index 0000000..2b4f768
--- /dev/null
+++ b/www/js/ResourcesLoader.js
@@ -0,0 +1,241 @@
+(function() {
+    "use strict";
+
+    /* global myApp */
+    myApp.factory("ResourcesLoader", [ "$window", "$document", function ($window, $document)
{
+        var fs;
+        var initialised = false;
+
+        function initialise() {
+            initialised = true;
+
+            var failedFileSystemLookUp = function (error) {
+                var errorString = "An error occurred while reading the file system.";
+                if(error) {
+                    errorString += " " + JSON.stringify(error);
+                }
+                console.error(errorString);
+            };
+
+            var success = function(_fs) {
+                fs = _fs;
+            };
+
+            try {
+                $window.requestFileSystem($window.LocalFileSystem.PERSISTENT, 0, success,
failedFileSystemLookUp);
+            } catch (e) {
+                failedFileSystemLookUp(e);
+            }
+        }
+
+        $document.bind("deviceready", function() { initialise(); });
+
+        //promise returns full path to downloaded file
+        function downloadFromUrl(url, fullFilePath) {
+            var deferred = Q.defer();
+
+            var downloadFail = function(error) {
+                var str = "There was an error while downloading the file " + JSON.stringify(error);
+                deferred.reject(new Error(str));
+            };
+
+            var downloadSuccess = function(fileEntry) {
+                deferred.resolve(fileEntry.fullPath);
+            };
+
+            var fileTransfer = new $window.FileTransfer();
+            var uri = encodeURI(url);
+            fileTransfer.download(uri, fullFilePath, downloadSuccess, downloadFail);
+            return deferred.promise;
+        }
+
+        function trim(str) {
+            return str && str.replace(/^\s+|\s+$/g, "");
+        }
+
+        function makeRelativeToRoot(path) {
+            if(path && (path.charAt(0) === "/")) {
+                path = path.substring(1);
+            } else if(path && path.substring(0, 8) === "file:///") {
+                path = path.substring(8);
+            }
+            return path;
+        }
+
+        //promise returns the file entry
+        function getFileEntry(fileName) {
+            var deferred = Q.defer();
+
+            var errorWhileGettingFileEntry = function(error) {
+                var str = "There was an error while getting the file entry for file " + fileName
+ " " + JSON.stringify(error);
+                deferred.reject(new Error(str));
+            };
+            var success = function(fileEntry) {
+                deferred.resolve(fileEntry);
+            };
+            fs.root.getFile(fileName, {create: true, exclusive: false}, success, errorWhileGettingFileEntry);
+            return deferred.promise;
+        }
+
+        //promise returns the file
+        function getFile(fileName) {
+            return getFileEntry(fileName).
+            then(function(fileEntry){
+                var deferred = Q.defer();
+
+                var errorWhileGettingFile = function(error) {
+                    var str = "There was an error while getting the file for file " + fileName
+ " " + JSON.stringify(error);
+                    deferred.reject(new Error(str));
+                };
+
+                fileEntry.file(deferred.resolve, errorWhileGettingFile);
+                return deferred.promise;
+            });
+        }
+
+        function truncateToDirectoryPath(path) {
+            //remove the filename if it exists
+            var lastLevelIndex = path.search(/[\w ]+(\.[\w ]+)+$/g);
+            if(lastLevelIndex !== -1) {
+                path = path.substring(0, lastLevelIndex);
+            }
+            return path;
+        }
+
+        return {
+            // returns a promise with a full path to the dir
+            ensureDirectoryExists : function(directory) {
+                var deferred = Q.defer();
+
+                directory = truncateToDirectoryPath(directory);
+                directory = makeRelativeToRoot(directory);
+
+                var gotDirEntry = function(dirEntry) {
+                    deferred.resolve(dirEntry.fullPath);
+                };
+
+                var failedToGetDirEntry = function(error) {
+                    var str = "There was an error checking the directory: " + directory +
" " + JSON.stringify(error);
+                    deferred.reject(new Error(str));
+                };
+
+                fs.root.getDirectory(directory, {create: true, exclusive: false}, gotDirEntry,
failedToGetDirEntry);
+                return deferred.promise;
+            },
+
+            // promise returns full path to file
+            getFullFilePath : function(filePath) {
+                var deferred = Q.defer();
+
+                // Use the file's parent folder to get the full path
+                var directory = filePath;
+                var fileName = "";
+
+                //remove the filename if it exists
+                var lastLevelIndex = directory.search(/\/[\w ]+\.[\w ]+$/g);
+                if(lastLevelIndex !== -1) {
+                    directory = filePath.substring(0, lastLevelIndex);
+                    fileName = filePath.substring(lastLevelIndex + 1);
+                }
+
+                //we need the directory name w.r.t the root, so remove any slashes in the
beginning
+                if(directory.indexOf("/") === 0) {
+                    directory = directory.substring(1);
+                }
+
+                var gotFullPath = function(dirEntry) {
+                    var fullFilePath = dirEntry.fullPath + "/" + fileName;
+                    deferred.resolve(fullFilePath);
+                };
+
+                var failedToGetFullPath = function(error) {
+                    var str = "There was an error getting the full path of file: " + filePath
+ " " + JSON.stringify(error);
+                    deferred.reject(new Error(str));
+                };
+
+                fs.root.getDirectory(directory, {create: true, exclusive: false}, gotFullPath,
failedToGetFullPath);
+                return deferred.promise;
+            },
+
+            // returns a promise with a full path to the downloaded file
+            downloadFromUrl : function(url, filePath) {
+                var self = this;
+                return this.ensureDirectoryExists(filePath)
+                .then(function(){
+                    return self.getFullFilePath(filePath);
+                })
+                .then(function(fullFilePath){
+                    return downloadFromUrl(url, fullFilePath);
+                });
+            },
+
+            //returns a promise with the contents of the file
+            readFileContents : function(fileName) {
+                return getFile(fileName)
+                .then(function(file){
+                    var deferred = Q.defer();
+
+                    var reader = new $window.FileReader();
+                    reader.onload = function(evt) {
+                        var text = evt.target.result;
+                        deferred.resolve(text);
+                    };
+                    reader.onerror = function(evt) {
+                        deferred.reject(new Error(evt));
+                    };
+                    reader.readAsText(file);
+
+                    return deferred.promise;
+                });
+            },
+
+            //returns a promise with the json contents of the file
+            readJSONFileContents : function(fileName) {
+                return this.readFileContents(fileName)
+                .then(function (text) {
+                    text = trim(text);
+                    var resultJson = {};
+                    if(text) {
+                        resultJson = JSON.parse(text);
+                    }
+                    return resultJson;
+                });
+            },
+
+            //returns a promise when file is written
+            writeFileContents : function(fileName, contents) {
+                return getFileEntry(fileName)
+                .then(function(fileEntry){
+                    var deferred = Q.defer();
+
+                    var errorGettingFileWriter = function(error) {
+                        var str = "There was an error writing the file." + JSON.stringify(error);
+                        deferred.reject(new Error(str));
+                    };
+
+                    var gotFileWriter = function(writer) {
+                        writer.onwrite = deferred.resolve;
+                        writer.onerror = function(evt) {
+                            deferred.reject(new Error(evt));
+                        };
+                        writer.write(contents);
+                    };
+                    fileEntry.createWriter(gotFileWriter, errorGettingFileWriter);
+                    return deferred.promise;
+                });
+            },
+
+            //returns a promise when json file is written
+            writeJSONFileContents : function(fileName, contents) {
+                var stringContents;
+                if(typeof contents === "string") {
+                    stringContents = contents;
+                } else {
+                    stringContents = JSON.stringify(contents);
+                }
+                return this.writeFileContents(fileName, stringContents);
+            }
+        };
+    }]);
+
+})();
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-app-harness/blob/022ebbbe/www/js/app.js
----------------------------------------------------------------------
diff --git a/www/js/app.js b/www/js/app.js
new file mode 100644
index 0000000..962571e
--- /dev/null
+++ b/www/js/app.js
@@ -0,0 +1,11 @@
+var myApp = angular.module("CordovaAppHarness", []);
+myApp.config(["$routeProvider", function($routeProvider){
+    $routeProvider.when("/", {
+        templateUrl: "views/list.html",
+        controller: "ListCtrl"
+    });
+    $routeProvider.when("/add", {
+        templateUrl: "views/add.html",
+        controller: "AddCtrl"
+    });
+}]);
\ No newline at end of file


Mime
View raw message