You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by mw...@apache.org on 2013/05/15 22:35:40 UTC
[01/37] Reorganize specs into cordova-cli/ and platform-script/
Updated Branches:
refs/heads/master 22937060d -> bed35f663
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/platform.spec.js
----------------------------------------------------------------------
diff --git a/spec/platform.spec.js b/spec/platform.spec.js
deleted file mode 100644
index 7138c7e..0000000
--- a/spec/platform.spec.js
+++ /dev/null
@@ -1,339 +0,0 @@
-/**
- 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.
-*/
-var cordova = require('../cordova'),
- path = require('path'),
- shell = require('shelljs'),
- request = require('request'),
- fs = require('fs'),
- et = require('elementtree'),
- config_parser = require('../src/config_parser'),
- helper = require('./helper'),
- util = require('../src/util'),
- hooker = require('../src/hooker'),
- platforms = require('../platforms'),
- tempDir = path.join(__dirname, '..', 'temp');
- android_parser = require('../src/metadata/android_parser'),
- ios_parser = require('../src/metadata/ios_parser'),
- cordova_project = path.join(__dirname, 'fixtures', 'projects', 'cordova'),
- blackberry_parser = require('../src/metadata/blackberry_parser');
-
-var cwd = process.cwd();
-
-describe('platform command', function() {
- beforeEach(function() {
- // Make a temp directory
- shell.rm('-rf', tempDir);
- shell.mkdir('-p', tempDir);
- });
- it('should run inside a Cordova-based project', function() {
- this.after(function() {
- process.chdir(cwd);
- });
-
- cordova.create(tempDir);
-
- process.chdir(tempDir);
-
- expect(function() {
- cordova.platform();
- }).not.toThrow();
- });
- it('should not run outside of a Cordova-based project', function() {
- this.after(function() {
- process.chdir(cwd);
- });
-
- process.chdir(tempDir);
-
- expect(function() {
- cordova.platform();
- }).toThrow();
- });
-
- describe('`ls`', function() {
- beforeEach(function() {
- process.chdir(cordova_project);
- });
-
- afterEach(function() {
- process.chdir(cwd);
- });
-
- it('should list out no platforms for a fresh project', function() {
- shell.mv('-f', path.join(cordova_project, 'platforms', '*'), tempDir);
- this.after(function() {
- shell.mv('-f', path.join(tempDir, '*'), path.join(cordova_project, 'platforms'));
- });
- expect(cordova.platform('list').length).toEqual(0);
- });
-
- it('should list out added platforms in a project', function() {
- expect(cordova.platform('list').length).toEqual(3);
- });
- });
-
- describe('`add`', function() {
- beforeEach(function() {
- cordova.create(tempDir);
- process.chdir(tempDir);
- });
-
- afterEach(function() {
- process.chdir(cwd);
- });
-
- describe('android', function() {
- var sh, cr;
- var fake_reqs_check = function() {
- cr.mostRecentCall.args[0](false);
- };
- var fake_create = function(a_path) {
- shell.mkdir('-p', a_path);
- fs.writeFileSync(path.join(a_path, 'AndroidManifest.xml'), 'hi', 'utf-8');
- sh.mostRecentCall.args[2](0, '');
- };
- beforeEach(function() {
- sh = spyOn(shell, 'exec');
- cr = spyOn(android_parser, 'check_requirements');
- });
-
- it('should shell out to android ./bin/create', function() {
- cordova.platform('add', 'android');
- fake_reqs_check();
- var shell_cmd = sh.mostRecentCall.args[0];
- expect(shell_cmd).toMatch(/android\/bin\/create/);
- });
- it('should call android_parser\'s update_project', function() {
- var s = spyOn(android_parser.prototype, 'update_project');
- cordova.platform('add', 'android');
- fake_reqs_check();
- fake_create(path.join(tempDir, 'platforms', 'android'));
- expect(s).toHaveBeenCalled();
- });
- });
- describe('ios', function() {
- var sh, cr;
- var fake_reqs_check = function() {
- cr.mostRecentCall.args[0](false);
- };
- var fake_create = function(a_path) {
- shell.mkdir('-p', a_path);
- fs.writeFileSync(path.join(a_path, 'poo.xcodeproj'), 'hi', 'utf-8');
- shell.mkdir('-p', path.join(a_path, 'poo'));
- shell.cp(path.join(cordova_project, 'www', 'config.xml'), path.join(a_path, 'poo', 'config.xml'));
- sh.mostRecentCall.args[2](0, '');
- };
- beforeEach(function() {
- sh = spyOn(shell, 'exec');
- cr = spyOn(ios_parser, 'check_requirements');
- });
- it('should shell out to ios ./bin/create', function() {
- cordova.platform('add', 'ios');
- fake_reqs_check();
- var shell_cmd = sh.mostRecentCall.args[0];
- expect(shell_cmd).toMatch(/ios\/bin\/create/);
- });
- it('should call ios_parser\'s update_project', function() {
- var s = spyOn(ios_parser.prototype, 'update_project');
- cordova.platform('add', 'ios');
- fake_reqs_check();
- fake_create(path.join(tempDir, 'platforms', 'ios'));
- expect(s).toHaveBeenCalled();
- });
- });
- describe('blackberry', function() {
- var sh, cr;
- var fake_reqs_check = function() {
- cr.mostRecentCall.args[0](false);
- };
- var fake_create = function(a_path) {
- shell.mkdir('-p', path.join(a_path, 'www'));
- fs.writeFileSync(path.join(a_path, 'project.properties'), 'hi', 'utf-8');
- fs.writeFileSync(path.join(a_path, 'build.xml'), 'hi', 'utf-8');
- shell.cp(path.join(cordova_project, 'www', 'config.xml'), path.join(a_path, 'www', 'config.xml'));
- sh.mostRecentCall.args[2](0, '');
- };
- beforeEach(function() {
- sh = spyOn(shell, 'exec');
- cr = spyOn(blackberry_parser, 'check_requirements');
- });
- it('should shell out to blackberry bin/create', function() {
- cordova.platform('add', 'blackberry');
- fake_reqs_check();
- var shell_cmd = sh.mostRecentCall.args[0];
- expect(shell_cmd).toMatch(/blackberry\/bin\/create/);
- });
- it('should call blackberry_parser\'s update_project', function() {
- var s = spyOn(blackberry_parser.prototype, 'update_project');
- cordova.platform('add', 'blackberry');
- fake_reqs_check();
- fake_create(path.join(tempDir, 'platforms', 'blackberry'));
- expect(s).toHaveBeenCalled();
- });
- });
- it('should handle multiple platforms', function() {
- var arc = spyOn(android_parser, 'check_requirements');
- var irc = spyOn(ios_parser, 'check_requirements');
- var sh = spyOn(shell, 'exec');
- cordova.platform('add', ['android', 'ios']);
- arc.mostRecentCall.args[0](false);
- irc.mostRecentCall.args[0](false);
- expect(sh.argsForCall[0][0]).toMatch(/android\/bin\/create/);
- expect(sh.argsForCall[1][0]).toMatch(/ios\/bin\/create/);
- });
- });
-
- describe('`remove`',function() {
- beforeEach(function() {
- process.chdir(cordova_project);
- shell.cp('-rf', path.join(cordova_project, 'platforms' ,'*'), tempDir);
- });
-
- afterEach(function() {
- process.chdir(cwd);
- shell.cp('-rf', path.join(tempDir, '*'), path.join(cordova_project, 'platforms'));
- });
-
- it('should remove a supported and added platform', function() {
- cordova.platform('remove', 'android');
- expect(cordova.platform('ls').length).toEqual(2);
- });
- it('should be able to remove multiple platforms', function() {
- cordova.platform('remove', ['android','ios']);
- expect(cordova.platform('ls').length).toEqual(1);
- });
- });
-
- describe('hooks', function() {
- var s;
- beforeEach(function() {
- cordova.create(tempDir);
- process.chdir(tempDir);
- s = spyOn(hooker.prototype, 'fire').andReturn(true);
- });
- afterEach(function() {
- process.chdir(cwd);
- shell.rm('-rf', tempDir);
- });
-
- describe('list (ls) hooks', function() {
- it('should fire before hooks through the hooker module', function() {
- cordova.platform();
- expect(s).toHaveBeenCalledWith('before_platform_ls');
- });
- it('should fire after hooks through the hooker module', function() {
- cordova.platform();
- expect(s).toHaveBeenCalledWith('after_platform_ls');
- });
- });
- describe('remove (rm) hooks', function() {
- it('should fire before hooks through the hooker module', function() {
- cordova.platform('rm', 'android');
- expect(s).toHaveBeenCalledWith('before_platform_rm');
- });
- it('should fire after hooks through the hooker module', function() {
- cordova.platform('rm', 'android');
- expect(s).toHaveBeenCalledWith('after_platform_rm');
- });
- });
- describe('add hooks', function() {
- var sh, cr;
- var fake_reqs_check = function() {
- cr.mostRecentCall.args[0](false);
- };
- var fake_create = function(a_path) {
- shell.mkdir('-p', a_path);
- fs.writeFileSync(path.join(a_path, 'AndroidManifest.xml'), 'hi', 'utf-8');
- sh.mostRecentCall.args[2](0, '');
- };
- beforeEach(function() {
- sh = spyOn(shell, 'exec');
- cr = spyOn(android_parser, 'check_requirements');
- });
- it('should fire before and after hooks through the hooker module', function() {
- var ap = spyOn(android_parser.prototype, 'update_project');
- cordova.platform('add', 'android');
- fake_reqs_check();
- fake_create(path.join(tempDir, 'platforms', 'android'));
- ap.mostRecentCall.args[1](); // fake out update_project
- expect(s).toHaveBeenCalledWith('before_platform_add');
- expect(s).toHaveBeenCalledWith('after_platform_add');
- });
- });
- });
-});
-
-describe('platform.supports(name, callback)', function() {
- var androidParser = require('../src/metadata/android_parser');
-
- beforeEach(function() {
- spyOn(androidParser, 'check_requirements');
- });
-
- it('should require a platform name', function() {
- expect(function() {
- cordova.platform.supports(undefined, function(e){});
- }).toThrow();
- });
-
- it('should require a callback function', function() {
- expect(function() {
- cordova.platform.supports('android', undefined);
- }).toThrow();
- });
-
- describe('when platform is unknown', function() {
- it('should trigger callback with false', function(done) {
- cordova.platform.supports('windows-3.1', function(e) {
- expect(e).toEqual(jasmine.any(Error));
- done();
- });
- });
- });
-
- describe('when platform is supported', function() {
- beforeEach(function() {
- androidParser.check_requirements.andCallFake(function(callback) {
- callback(null);
- });
- });
-
- it('should trigger callback without error', function(done) {
- cordova.platform.supports('android', function(e) {
- expect(e).toBeNull();
- done();
- });
- });
- });
-
- describe('when platform is unsupported', function() {
- beforeEach(function() {
- androidParser.check_requirements.andCallFake(function(callback) {
- callback(new Error('could not find the android sdk'));
- });
- });
-
- it('should trigger callback with error', function(done) {
- cordova.platform.supports('android', function(e) {
- expect(e).toEqual(jasmine.any(Error));
- done();
- });
- });
- });
-});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/plugin.spec.js
----------------------------------------------------------------------
diff --git a/spec/plugin.spec.js b/spec/plugin.spec.js
deleted file mode 100644
index 3d370e7..0000000
--- a/spec/plugin.spec.js
+++ /dev/null
@@ -1,164 +0,0 @@
-/**
- 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.
-*/
-var cordova = require('../cordova'),
- path = require('path'),
- shell = require('shelljs'),
- fs = require('fs'),
- hooker = require('../src/hooker'),
- tempDir = path.join(__dirname, '..', 'temp'),
- fixturesDir = path.join(__dirname, 'fixtures'),
- testPlugin = path.join(fixturesDir, 'plugins', 'test'),
- cordova_project = path.join(fixturesDir, 'projects', 'cordova'),
- androidPlugin = path.join(fixturesDir, 'plugins', 'android');
-
-var cwd = process.cwd();
-
-describe('plugin command', function() {
- beforeEach(function() {
- // Make a temp directory
- shell.rm('-rf', tempDir);
- shell.mkdir('-p', tempDir);
- });
-
- it('should run inside a Cordova-based project', function() {
- this.after(function() {
- process.chdir(cwd);
- });
-
- cordova.create(tempDir);
-
- process.chdir(tempDir);
-
- expect(function() {
- cordova.plugin();
- }).not.toThrow();
- });
- it('should not run outside of a Cordova-based project', function() {
- this.after(function() {
- process.chdir(cwd);
- });
-
- process.chdir(tempDir);
-
- expect(function() {
- cordova.plugin();
- }).toThrow();
- });
-
- describe('edge cases', function() {
- beforeEach(function() {
- cordova.create(tempDir);
- process.chdir(tempDir);
- });
-
- afterEach(function() {
- process.chdir(cwd);
- });
-
- it('should not fail when the plugins directory is missing', function() {
- fs.rmdirSync('plugins');
-
- expect(function() {
- cordova.plugin();
- }).not.toThrow();
- });
-
- it('should ignore files, like .gitignore, in the plugins directory', function() {
- var someFile = path.join(tempDir, 'plugins', '.gitignore');
- fs.writeFileSync(someFile, 'not a plugin');
-
- expect(cordova.plugin('list')).toEqual('No plugins added. Use `cordova plugin add <plugin>`.');
- });
- });
-
- describe('`ls`', function() {
- beforeEach(function() {
- cordova.create(tempDir);
- });
-
- afterEach(function() {
- process.chdir(cwd);
- });
-
- it('should list out no plugins for a fresh project', function() {
- process.chdir(tempDir);
-
- expect(cordova.plugin('list')).toEqual('No plugins added. Use `cordova plugin add <plugin>`.');
- });
- });
-
- describe('`add`', function() {
- beforeEach(function() {
- cordova.create(tempDir);
- process.chdir(tempDir);
- });
-
- afterEach(function() {
- process.chdir(cwd);
- });
- describe('failure', function() {
- it('should throw if your app has no platforms added', function() {
- expect(function() {
- cordova.plugin('add', testPlugin);
- }).toThrow('You need at least one platform added to your app. Use `cordova platform add <platform>`.');
- });
- it('should throw if plugin does not support any app platforms', function() {
- process.chdir(cordova_project);
- shell.mv('-f', path.join(cordova_project, 'platforms', 'android'), tempDir);
- shell.mv('-f', path.join(cordova_project, 'platforms', 'blackberry'), tempDir);
- this.after(function() {
- process.chdir(cwd);
- shell.mv('-f', path.join(tempDir, 'android'), path.join(cordova_project, 'platforms'));
- shell.mv('-f', path.join(tempDir, 'blackberry'), path.join(cordova_project, 'platforms'));
- });
- expect(function() {
- cordova.plugin('add', androidPlugin);
- }).toThrow('Plugin "android" does not support any of your application\'s platforms. Plugin platforms: android; your application\'s platforms: ios');
- });
- it('should throw if plugin is already added to project', function() {
- process.chdir(cordova_project);
- var cb = jasmine.createSpy();
- this.after(function() {
- process.chdir(cordova_project);
- cordova.plugin('rm', "test");
- process.chdir(cwd);
- });
- runs(function() {
- cordova.plugin('add', testPlugin, cb);
- });
- waitsFor(function() { return cb.wasCalled; }, 'frst add plugin');
- runs(function(){
- expect(function() {
- cordova.plugin('add', testPlugin);
- }).toThrow('Plugin "test" already added to project.');
- });
- });
- it('should throw if plugin does not have a plugin.xml', function() {
- process.chdir(cordova_project);
- this.after(function() {
- process.chdir(cwd);
- });
- expect(function() {
- cordova.plugin('add', fixturesDir);
- }).toThrow('Plugin "fixtures" does not have a plugin.xml in the root. Plugin must support the Cordova Plugin Specification: https://github.com/alunny/cordova-plugin-spec');
- });
- });
- });
-});
-
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/plugin_parser.spec.js
----------------------------------------------------------------------
diff --git a/spec/plugin_parser.spec.js b/spec/plugin_parser.spec.js
deleted file mode 100644
index 050ee8d..0000000
--- a/spec/plugin_parser.spec.js
+++ /dev/null
@@ -1,42 +0,0 @@
-
-/**
- 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.
-*/
-var cordova = require('../cordova'),
- path = require('path'),
- fs = require('fs'),
- plugin_parser = require('../src/plugin_parser'),
- et = require('elementtree'),
- xml = path.join(__dirname, 'fixtures', 'plugins', 'test', 'plugin.xml');
-
-describe('plugin.xml parser', function () {
- it('should read a proper plugin.xml file', function() {
- var cfg;
- expect(function () {
- cfg = new plugin_parser(xml);
- }).not.toThrow();
- expect(cfg).toBeDefined();
- expect(cfg.doc).toBeDefined();
- });
- it('should be able to figure out which platforms the plugin supports', function() {
- var cfg = new plugin_parser(xml);
- expect(cfg.platforms.length).toBe(1);
- expect(cfg.platforms.indexOf('ios') > -1).toBe(true);
- });
-});
-
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/prepare.spec.js
----------------------------------------------------------------------
diff --git a/spec/prepare.spec.js b/spec/prepare.spec.js
deleted file mode 100644
index f232b3e..0000000
--- a/spec/prepare.spec.js
+++ /dev/null
@@ -1,133 +0,0 @@
-/**
- 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.
-*/
-var cordova = require('../cordova'),
- et = require('elementtree'),
- shell = require('shelljs'),
- path = require('path'),
- fs = require('fs'),
- config_parser = require('../src/config_parser'),
- android_parser = require('../src/metadata/android_parser'),
- ios_parser = require('../src/metadata/ios_parser'),
- blackberry_parser = require('../src/metadata/blackberry_parser'),
- hooker = require('../src/hooker'),
- fixtures = path.join(__dirname, 'fixtures'),
- hooks = path.join(fixtures, 'hooks'),
- tempDir = path.join(__dirname, '..', 'temp'),
- cordova_project = path.join(fixtures, 'projects', 'cordova');
-
-var cwd = process.cwd();
-
-describe('prepare command', function() {
- beforeEach(function() {
- shell.rm('-rf', tempDir);
- shell.mkdir('-p', tempDir);
- });
-
- it('should not run inside a Cordova-based project with no added platforms', function() {
- this.after(function() {
- process.chdir(cwd);
- });
-
- cordova.create(tempDir);
- process.chdir(tempDir);
- expect(function() {
- cordova.prepare();
- }).toThrow();
- });
-
- it('should run inside a Cordova-based project with at least one added platform', function() {
- // move platform project fixtures over to fake cordova into thinking platforms were added
- // TODO: possibly add this to helper?
- shell.mv('-f', path.join(cordova_project, 'platforms', 'blackberry'), path.join(tempDir));
- this.after(function() {
- process.chdir(cwd);
- shell.mv('-f', path.join(tempDir, 'blackberry'), path.join(cordova_project, 'platforms', 'blackberry'));
- });
-
- process.chdir(cordova_project);
-
- var a_parser_spy = spyOn(android_parser.prototype, 'update_project');
- var i_parser_spy = spyOn(ios_parser.prototype, 'update_project');
- expect(function() {
- cordova.prepare();
- expect(a_parser_spy).toHaveBeenCalled();
- expect(i_parser_spy).toHaveBeenCalled();
- }).not.toThrow();
- });
- it('should not run outside of a Cordova-based project', function() {
- this.after(function() {
- process.chdir(cwd);
- });
-
- shell.mkdir('-p', tempDir);
- process.chdir(tempDir);
-
- expect(function() {
- cordova.prepare();
- }).toThrow();
- });
-
- describe('hooks', function() {
- var s;
- beforeEach(function() {
- s = spyOn(hooker.prototype, 'fire').andReturn(true);
- });
-
- describe('when platforms are added', function() {
- beforeEach(function() {
- shell.mv('-f', path.join(cordova_project, 'platforms', 'blackberry'), path.join(tempDir));
- shell.mv('-f', path.join(cordova_project, 'platforms', 'ios'), path.join(tempDir));
- process.chdir(cordova_project);
- });
- afterEach(function() {
- shell.mv('-f', path.join(tempDir, 'blackberry'), path.join(cordova_project, 'platforms', 'blackberry'));
- shell.mv('-f', path.join(tempDir, 'ios'), path.join(cordova_project, 'platforms', 'ios'));
- process.chdir(cwd);
- });
-
- it('should fire before hooks through the hooker module', function() {
- cordova.prepare();
- expect(s).toHaveBeenCalledWith('before_prepare');
- });
- it('should fire after hooks through the hooker module', function() {
- var parser_spy = spyOn(android_parser.prototype, 'update_project');
- cordova.prepare();
- parser_spy.mostRecentCall.args[1](); // parser cb
- expect(s).toHaveBeenCalledWith('after_prepare');
- });
- });
-
- describe('with no platforms added', function() {
- beforeEach(function() {
- cordova.create(tempDir);
- process.chdir(tempDir);
- });
- afterEach(function() {
- process.chdir(cwd);
- });
- it('should not fire the hooker', function() {
- expect(function() {
- cordova.prepare();
- }).toThrow();
- expect(s).not.toHaveBeenCalledWith('before_prepare');
- expect(s).not.toHaveBeenCalledWith('after_prepare');
- });
- });
- });
-});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/serve.spec.js
----------------------------------------------------------------------
diff --git a/spec/serve.spec.js b/spec/serve.spec.js
deleted file mode 100644
index 8d00cab..0000000
--- a/spec/serve.spec.js
+++ /dev/null
@@ -1,132 +0,0 @@
-
-/**
- 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.
-*/
-var cordova = require('../cordova'),
- path = require('path'),
- shell = require('shelljs'),
- request = require('request'),
- fs = require('fs'),
- util = require('../src/util'),
- hooker = require('../src/hooker'),
- tempDir = path.join(__dirname, '..', 'temp'),
- http = require('http'),
- android_parser = require('../src/metadata/android_parser'),
- ios_parser = require('../src/metadata/ios_parser'),
- blackberry_parser = require('../src/metadata/blackberry_parser');
-
-var cwd = process.cwd();
-
-xdescribe('serve command', function() {
- beforeEach(function() {
- // Make a temp directory
- shell.rm('-rf', tempDir);
- shell.mkdir('-p', tempDir);
- });
- it('should not run outside of a Cordova-based project', function() {
- this.after(function() {
- process.chdir(cwd);
- });
-
- process.chdir(tempDir);
-
- expect(function() {
- cordova.serve('android');
- }).toThrow();
- });
-
-
- describe('`serve`', function() {
- var payloads = {
- android: 'This is the Android test file.',
- ios: 'This is the iOS test file.'
- };
-
- beforeEach(function() {
- cordova.create(tempDir);
- process.chdir(tempDir);
- cordova.platform('add', 'android');
- cordova.platform('add', 'ios');
-
- // Write testing HTML files into the directory.
- fs.writeFileSync(path.join(tempDir, 'platforms', 'android', 'assets', 'www', 'test.html'), payloads.android);
- fs.writeFileSync(path.join(tempDir, 'platforms', 'ios', 'www', 'test.html'), payloads.ios);
- });
-
- afterEach(function() {
- process.chdir(cwd);
- });
-
- function test_serve(platform, path, expectedContents, port) {
- return function() {
- var ret;
- runs(function() {
- ret = port ? cordova.serve(platform, port) : cordova.serve(platform);
- });
-
- waitsFor(function() {
- return ret.server;
- }, 'the server should start', 1000);
-
- var done, errorCB;
- runs(function() {
- expect(ret.server).toBeDefined();
- errorCB = jasmine.createSpy();
- http.get({
- host: 'localhost',
- port: port || 8000,
- path: path
- }).on('response', function(res) {
- var response = '';
- res.on('data', function(data) {
- response += data;
- });
- res.on('end', function() {
- expect(res.statusCode).toEqual(200);
- expect(response).toEqual(expectedContents);
- done = true;
- });
- }).on('error', errorCB);
- });
-
- waitsFor(function() {
- return done;
- }, 'the HTTP request should complete', 1000);
-
- runs(function() {
- expect(done).toBeTruthy();
- expect(errorCB).not.toHaveBeenCalled();
-
- ret.server.close();
- });
- };
- };
-
- it('should serve from top-level www if the file exists there', function() {
- var payload = 'This is test file.';
- fs.writeFileSync(path.join(tempDir, 'www', 'test.html'), payload);
- test_serve('android', '/test.html', payload)();
- });
-
- it('should fall back to assets/www on Android', test_serve('android', '/test.html', payloads.android));
- it('should fall back to www on iOS', test_serve('ios', '/test.html', payloads.ios));
-
- it('should honour a custom port setting', test_serve('android', '/test.html', payloads.android, 9001));
- });
-});
-
[34/37] Add Windows support to Android platform-scripts.
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/framework/assets/www/cordova.js
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/assets/www/cordova.js b/lib/cordova-android/framework/assets/www/cordova.js
new file mode 100644
index 0000000..2941307
--- /dev/null
+++ b/lib/cordova-android/framework/assets/www/cordova.js
@@ -0,0 +1,6836 @@
+// Platform: android
+
+// commit d0ffb852378ff018bac2f3b12c38098a19b8ce00
+
+// File generated at :: Thu Apr 18 2013 15:10:54 GMT-0400 (EDT)
+
+/*
+ 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.
+*/
+
+;(function() {
+
+// file: lib/scripts/require.js
+
+var require,
+ define;
+
+(function () {
+ var modules = {};
+ // Stack of moduleIds currently being built.
+ var requireStack = [];
+ // Map of module ID -> index into requireStack of modules currently being built.
+ var inProgressModules = {};
+
+ function build(module) {
+ var factory = module.factory;
+ module.exports = {};
+ delete module.factory;
+ factory(require, module.exports, module);
+ return module.exports;
+ }
+
+ require = function (id) {
+ if (!modules[id]) {
+ throw "module " + id + " not found";
+ } else if (id in inProgressModules) {
+ var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id;
+ throw "Cycle in require graph: " + cycle;
+ }
+ if (modules[id].factory) {
+ try {
+ inProgressModules[id] = requireStack.length;
+ requireStack.push(id);
+ return build(modules[id]);
+ } finally {
+ delete inProgressModules[id];
+ requireStack.pop();
+ }
+ }
+ return modules[id].exports;
+ };
+
+ define = function (id, factory) {
+ if (modules[id]) {
+ throw "module " + id + " already defined";
+ }
+
+ modules[id] = {
+ id: id,
+ factory: factory
+ };
+ };
+
+ define.remove = function (id) {
+ delete modules[id];
+ };
+
+ define.moduleMap = modules;
+})();
+
+//Export for use in node
+if (typeof module === "object" && typeof require === "function") {
+ module.exports.require = require;
+ module.exports.define = define;
+}
+
+// file: lib/cordova.js
+define("cordova", function(require, exports, module) {
+
+
+var channel = require('cordova/channel');
+
+/**
+ * Listen for DOMContentLoaded and notify our channel subscribers.
+ */
+document.addEventListener('DOMContentLoaded', function() {
+ channel.onDOMContentLoaded.fire();
+}, false);
+if (document.readyState == 'complete' || document.readyState == 'interactive') {
+ channel.onDOMContentLoaded.fire();
+}
+
+/**
+ * Intercept calls to addEventListener + removeEventListener and handle deviceready,
+ * resume, and pause events.
+ */
+var m_document_addEventListener = document.addEventListener;
+var m_document_removeEventListener = document.removeEventListener;
+var m_window_addEventListener = window.addEventListener;
+var m_window_removeEventListener = window.removeEventListener;
+
+/**
+ * Houses custom event handlers to intercept on document + window event listeners.
+ */
+var documentEventHandlers = {},
+ windowEventHandlers = {};
+
+document.addEventListener = function(evt, handler, capture) {
+ var e = evt.toLowerCase();
+ if (typeof documentEventHandlers[e] != 'undefined') {
+ documentEventHandlers[e].subscribe(handler);
+ } else {
+ m_document_addEventListener.call(document, evt, handler, capture);
+ }
+};
+
+window.addEventListener = function(evt, handler, capture) {
+ var e = evt.toLowerCase();
+ if (typeof windowEventHandlers[e] != 'undefined') {
+ windowEventHandlers[e].subscribe(handler);
+ } else {
+ m_window_addEventListener.call(window, evt, handler, capture);
+ }
+};
+
+document.removeEventListener = function(evt, handler, capture) {
+ var e = evt.toLowerCase();
+ // If unsubscribing from an event that is handled by a plugin
+ if (typeof documentEventHandlers[e] != "undefined") {
+ documentEventHandlers[e].unsubscribe(handler);
+ } else {
+ m_document_removeEventListener.call(document, evt, handler, capture);
+ }
+};
+
+window.removeEventListener = function(evt, handler, capture) {
+ var e = evt.toLowerCase();
+ // If unsubscribing from an event that is handled by a plugin
+ if (typeof windowEventHandlers[e] != "undefined") {
+ windowEventHandlers[e].unsubscribe(handler);
+ } else {
+ m_window_removeEventListener.call(window, evt, handler, capture);
+ }
+};
+
+function createEvent(type, data) {
+ var event = document.createEvent('Events');
+ event.initEvent(type, false, false);
+ if (data) {
+ for (var i in data) {
+ if (data.hasOwnProperty(i)) {
+ event[i] = data[i];
+ }
+ }
+ }
+ return event;
+}
+
+if(typeof window.console === "undefined") {
+ window.console = {
+ log:function(){}
+ };
+}
+
+var cordova = {
+ define:define,
+ require:require,
+ /**
+ * Methods to add/remove your own addEventListener hijacking on document + window.
+ */
+ addWindowEventHandler:function(event) {
+ return (windowEventHandlers[event] = channel.create(event));
+ },
+ addStickyDocumentEventHandler:function(event) {
+ return (documentEventHandlers[event] = channel.createSticky(event));
+ },
+ addDocumentEventHandler:function(event) {
+ return (documentEventHandlers[event] = channel.create(event));
+ },
+ removeWindowEventHandler:function(event) {
+ delete windowEventHandlers[event];
+ },
+ removeDocumentEventHandler:function(event) {
+ delete documentEventHandlers[event];
+ },
+ /**
+ * Retrieve original event handlers that were replaced by Cordova
+ *
+ * @return object
+ */
+ getOriginalHandlers: function() {
+ return {'document': {'addEventListener': m_document_addEventListener, 'removeEventListener': m_document_removeEventListener},
+ 'window': {'addEventListener': m_window_addEventListener, 'removeEventListener': m_window_removeEventListener}};
+ },
+ /**
+ * Method to fire event from native code
+ * bNoDetach is required for events which cause an exception which needs to be caught in native code
+ */
+ fireDocumentEvent: function(type, data, bNoDetach) {
+ var evt = createEvent(type, data);
+ if (typeof documentEventHandlers[type] != 'undefined') {
+ if( bNoDetach ) {
+ documentEventHandlers[type].fire(evt);
+ }
+ else {
+ setTimeout(function() {
+ // Fire deviceready on listeners that were registered before cordova.js was loaded.
+ if (type == 'deviceready') {
+ document.dispatchEvent(evt);
+ }
+ documentEventHandlers[type].fire(evt);
+ }, 0);
+ }
+ } else {
+ document.dispatchEvent(evt);
+ }
+ },
+ fireWindowEvent: function(type, data) {
+ var evt = createEvent(type,data);
+ if (typeof windowEventHandlers[type] != 'undefined') {
+ setTimeout(function() {
+ windowEventHandlers[type].fire(evt);
+ }, 0);
+ } else {
+ window.dispatchEvent(evt);
+ }
+ },
+
+ /**
+ * Plugin callback mechanism.
+ */
+ // Randomize the starting callbackId to avoid collisions after refreshing or navigating.
+ // This way, it's very unlikely that any new callback would get the same callbackId as an old callback.
+ callbackId: Math.floor(Math.random() * 2000000000),
+ callbacks: {},
+ callbackStatus: {
+ NO_RESULT: 0,
+ OK: 1,
+ CLASS_NOT_FOUND_EXCEPTION: 2,
+ ILLEGAL_ACCESS_EXCEPTION: 3,
+ INSTANTIATION_EXCEPTION: 4,
+ MALFORMED_URL_EXCEPTION: 5,
+ IO_EXCEPTION: 6,
+ INVALID_ACTION: 7,
+ JSON_EXCEPTION: 8,
+ ERROR: 9
+ },
+
+ /**
+ * Called by native code when returning successful result from an action.
+ */
+ callbackSuccess: function(callbackId, args) {
+ try {
+ cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback);
+ } catch (e) {
+ console.log("Error in error callback: " + callbackId + " = "+e);
+ }
+ },
+
+ /**
+ * Called by native code when returning error result from an action.
+ */
+ callbackError: function(callbackId, args) {
+ // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative.
+ // Derive success from status.
+ try {
+ cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback);
+ } catch (e) {
+ console.log("Error in error callback: " + callbackId + " = "+e);
+ }
+ },
+
+ /**
+ * Called by native code when returning the result from an action.
+ */
+ callbackFromNative: function(callbackId, success, status, args, keepCallback) {
+ var callback = cordova.callbacks[callbackId];
+ if (callback) {
+ if (success && status == cordova.callbackStatus.OK) {
+ callback.success && callback.success.apply(null, args);
+ } else if (!success) {
+ callback.fail && callback.fail.apply(null, args);
+ }
+
+ // Clear callback if not expecting any more results
+ if (!keepCallback) {
+ delete cordova.callbacks[callbackId];
+ }
+ }
+ },
+ addConstructor: function(func) {
+ channel.onCordovaReady.subscribe(function() {
+ try {
+ func();
+ } catch(e) {
+ console.log("Failed to run constructor: " + e);
+ }
+ });
+ }
+};
+
+// Register pause, resume and deviceready channels as events on document.
+channel.onPause = cordova.addDocumentEventHandler('pause');
+channel.onResume = cordova.addDocumentEventHandler('resume');
+channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready');
+
+module.exports = cordova;
+
+});
+
+// file: lib/common/argscheck.js
+define("cordova/argscheck", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+var utils = require('cordova/utils');
+
+var moduleExports = module.exports;
+
+var typeMap = {
+ 'A': 'Array',
+ 'D': 'Date',
+ 'N': 'Number',
+ 'S': 'String',
+ 'F': 'Function',
+ 'O': 'Object'
+};
+
+function extractParamName(callee, argIndex) {
+ return (/.*?\((.*?)\)/).exec(callee)[1].split(', ')[argIndex];
+}
+
+function checkArgs(spec, functionName, args, opt_callee) {
+ if (!moduleExports.enableChecks) {
+ return;
+ }
+ var errMsg = null;
+ var typeName;
+ for (var i = 0; i < spec.length; ++i) {
+ var c = spec.charAt(i),
+ cUpper = c.toUpperCase(),
+ arg = args[i];
+ // Asterix means allow anything.
+ if (c == '*') {
+ continue;
+ }
+ typeName = utils.typeName(arg);
+ if ((arg === null || arg === undefined) && c == cUpper) {
+ continue;
+ }
+ if (typeName != typeMap[cUpper]) {
+ errMsg = 'Expected ' + typeMap[cUpper];
+ break;
+ }
+ }
+ if (errMsg) {
+ errMsg += ', but got ' + typeName + '.';
+ errMsg = 'Wrong type for parameter "' + extractParamName(opt_callee || args.callee, i) + '" of ' + functionName + ': ' + errMsg;
+ // Don't log when running jake test.
+ if (typeof jasmine == 'undefined') {
+ console.error(errMsg);
+ }
+ throw TypeError(errMsg);
+ }
+}
+
+function getValue(value, defaultValue) {
+ return value === undefined ? defaultValue : value;
+}
+
+moduleExports.checkArgs = checkArgs;
+moduleExports.getValue = getValue;
+moduleExports.enableChecks = true;
+
+
+});
+
+// file: lib/common/builder.js
+define("cordova/builder", function(require, exports, module) {
+
+var utils = require('cordova/utils');
+
+function each(objects, func, context) {
+ for (var prop in objects) {
+ if (objects.hasOwnProperty(prop)) {
+ func.apply(context, [objects[prop], prop]);
+ }
+ }
+}
+
+function clobber(obj, key, value) {
+ exports.replaceHookForTesting(obj, key);
+ obj[key] = value;
+ // Getters can only be overridden by getters.
+ if (obj[key] !== value) {
+ utils.defineGetter(obj, key, function() {
+ return value;
+ });
+ }
+}
+
+function assignOrWrapInDeprecateGetter(obj, key, value, message) {
+ if (message) {
+ utils.defineGetter(obj, key, function() {
+ console.log(message);
+ delete obj[key];
+ clobber(obj, key, value);
+ return value;
+ });
+ } else {
+ clobber(obj, key, value);
+ }
+}
+
+function include(parent, objects, clobber, merge) {
+ each(objects, function (obj, key) {
+ try {
+ var result = obj.path ? require(obj.path) : {};
+
+ if (clobber) {
+ // Clobber if it doesn't exist.
+ if (typeof parent[key] === 'undefined') {
+ assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+ } else if (typeof obj.path !== 'undefined') {
+ // If merging, merge properties onto parent, otherwise, clobber.
+ if (merge) {
+ recursiveMerge(parent[key], result);
+ } else {
+ assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+ }
+ }
+ result = parent[key];
+ } else {
+ // Overwrite if not currently defined.
+ if (typeof parent[key] == 'undefined') {
+ assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+ } else {
+ // Set result to what already exists, so we can build children into it if they exist.
+ result = parent[key];
+ }
+ }
+
+ if (obj.children) {
+ include(result, obj.children, clobber, merge);
+ }
+ } catch(e) {
+ utils.alert('Exception building cordova JS globals: ' + e + ' for key "' + key + '"');
+ }
+ });
+}
+
+/**
+ * Merge properties from one object onto another recursively. Properties from
+ * the src object will overwrite existing target property.
+ *
+ * @param target Object to merge properties into.
+ * @param src Object to merge properties from.
+ */
+function recursiveMerge(target, src) {
+ for (var prop in src) {
+ if (src.hasOwnProperty(prop)) {
+ if (target.prototype && target.prototype.constructor === target) {
+ // If the target object is a constructor override off prototype.
+ clobber(target.prototype, prop, src[prop]);
+ } else {
+ if (typeof src[prop] === 'object' && typeof target[prop] === 'object') {
+ recursiveMerge(target[prop], src[prop]);
+ } else {
+ clobber(target, prop, src[prop]);
+ }
+ }
+ }
+ }
+}
+
+exports.buildIntoButDoNotClobber = function(objects, target) {
+ include(target, objects, false, false);
+};
+exports.buildIntoAndClobber = function(objects, target) {
+ include(target, objects, true, false);
+};
+exports.buildIntoAndMerge = function(objects, target) {
+ include(target, objects, true, true);
+};
+exports.recursiveMerge = recursiveMerge;
+exports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter;
+exports.replaceHookForTesting = function() {};
+
+});
+
+// file: lib/common/channel.js
+define("cordova/channel", function(require, exports, module) {
+
+var utils = require('cordova/utils'),
+ nextGuid = 1;
+
+/**
+ * Custom pub-sub "channel" that can have functions subscribed to it
+ * This object is used to define and control firing of events for
+ * cordova initialization, as well as for custom events thereafter.
+ *
+ * The order of events during page load and Cordova startup is as follows:
+ *
+ * onDOMContentLoaded* Internal event that is received when the web page is loaded and parsed.
+ * onNativeReady* Internal event that indicates the Cordova native side is ready.
+ * onCordovaReady* Internal event fired when all Cordova JavaScript objects have been created.
+ * onCordovaInfoReady* Internal event fired when device properties are available.
+ * onCordovaConnectionReady* Internal event fired when the connection property has been set.
+ * onDeviceReady* User event fired to indicate that Cordova is ready
+ * onResume User event fired to indicate a start/resume lifecycle event
+ * onPause User event fired to indicate a pause lifecycle event
+ * onDestroy* Internal event fired when app is being destroyed (User should use window.onunload event, not this one).
+ *
+ * The events marked with an * are sticky. Once they have fired, they will stay in the fired state.
+ * All listeners that subscribe after the event is fired will be executed right away.
+ *
+ * The only Cordova events that user code should register for are:
+ * deviceready Cordova native code is initialized and Cordova APIs can be called from JavaScript
+ * pause App has moved to background
+ * resume App has returned to foreground
+ *
+ * Listeners can be registered as:
+ * document.addEventListener("deviceready", myDeviceReadyListener, false);
+ * document.addEventListener("resume", myResumeListener, false);
+ * document.addEventListener("pause", myPauseListener, false);
+ *
+ * The DOM lifecycle events should be used for saving and restoring state
+ * window.onload
+ * window.onunload
+ *
+ */
+
+/**
+ * Channel
+ * @constructor
+ * @param type String the channel name
+ */
+var Channel = function(type, sticky) {
+ this.type = type;
+ // Map of guid -> function.
+ this.handlers = {};
+ // 0 = Non-sticky, 1 = Sticky non-fired, 2 = Sticky fired.
+ this.state = sticky ? 1 : 0;
+ // Used in sticky mode to remember args passed to fire().
+ this.fireArgs = null;
+ // Used by onHasSubscribersChange to know if there are any listeners.
+ this.numHandlers = 0;
+ // Function that is called when the first listener is subscribed, or when
+ // the last listener is unsubscribed.
+ this.onHasSubscribersChange = null;
+},
+ channel = {
+ /**
+ * Calls the provided function only after all of the channels specified
+ * have been fired. All channels must be sticky channels.
+ */
+ join: function(h, c) {
+ var len = c.length,
+ i = len,
+ f = function() {
+ if (!(--i)) h();
+ };
+ for (var j=0; j<len; j++) {
+ if (c[j].state === 0) {
+ throw Error('Can only use join with sticky channels.');
+ }
+ c[j].subscribe(f);
+ }
+ if (!len) h();
+ },
+ create: function(type) {
+ return channel[type] = new Channel(type, false);
+ },
+ createSticky: function(type) {
+ return channel[type] = new Channel(type, true);
+ },
+
+ /**
+ * cordova Channels that must fire before "deviceready" is fired.
+ */
+ deviceReadyChannelsArray: [],
+ deviceReadyChannelsMap: {},
+
+ /**
+ * Indicate that a feature needs to be initialized before it is ready to be used.
+ * This holds up Cordova's "deviceready" event until the feature has been initialized
+ * and Cordova.initComplete(feature) is called.
+ *
+ * @param feature {String} The unique feature name
+ */
+ waitForInitialization: function(feature) {
+ if (feature) {
+ var c = channel[feature] || this.createSticky(feature);
+ this.deviceReadyChannelsMap[feature] = c;
+ this.deviceReadyChannelsArray.push(c);
+ }
+ },
+
+ /**
+ * Indicate that initialization code has completed and the feature is ready to be used.
+ *
+ * @param feature {String} The unique feature name
+ */
+ initializationComplete: function(feature) {
+ var c = this.deviceReadyChannelsMap[feature];
+ if (c) {
+ c.fire();
+ }
+ }
+ };
+
+function forceFunction(f) {
+ if (typeof f != 'function') throw "Function required as first argument!";
+}
+
+/**
+ * Subscribes the given function to the channel. Any time that
+ * Channel.fire is called so too will the function.
+ * Optionally specify an execution context for the function
+ * and a guid that can be used to stop subscribing to the channel.
+ * Returns the guid.
+ */
+Channel.prototype.subscribe = function(f, c) {
+ // need a function to call
+ forceFunction(f);
+ if (this.state == 2) {
+ f.apply(c || this, this.fireArgs);
+ return;
+ }
+
+ var func = f,
+ guid = f.observer_guid;
+ if (typeof c == "object") { func = utils.close(c, f); }
+
+ if (!guid) {
+ // first time any channel has seen this subscriber
+ guid = '' + nextGuid++;
+ }
+ func.observer_guid = guid;
+ f.observer_guid = guid;
+
+ // Don't add the same handler more than once.
+ if (!this.handlers[guid]) {
+ this.handlers[guid] = func;
+ this.numHandlers++;
+ if (this.numHandlers == 1) {
+ this.onHasSubscribersChange && this.onHasSubscribersChange();
+ }
+ }
+};
+
+/**
+ * Unsubscribes the function with the given guid from the channel.
+ */
+Channel.prototype.unsubscribe = function(f) {
+ // need a function to unsubscribe
+ forceFunction(f);
+
+ var guid = f.observer_guid,
+ handler = this.handlers[guid];
+ if (handler) {
+ delete this.handlers[guid];
+ this.numHandlers--;
+ if (this.numHandlers === 0) {
+ this.onHasSubscribersChange && this.onHasSubscribersChange();
+ }
+ }
+};
+
+/**
+ * Calls all functions subscribed to this channel.
+ */
+Channel.prototype.fire = function(e) {
+ var fail = false,
+ fireArgs = Array.prototype.slice.call(arguments);
+ // Apply stickiness.
+ if (this.state == 1) {
+ this.state = 2;
+ this.fireArgs = fireArgs;
+ }
+ if (this.numHandlers) {
+ // Copy the values first so that it is safe to modify it from within
+ // callbacks.
+ var toCall = [];
+ for (var item in this.handlers) {
+ toCall.push(this.handlers[item]);
+ }
+ for (var i = 0; i < toCall.length; ++i) {
+ toCall[i].apply(this, fireArgs);
+ }
+ if (this.state == 2 && this.numHandlers) {
+ this.numHandlers = 0;
+ this.handlers = {};
+ this.onHasSubscribersChange && this.onHasSubscribersChange();
+ }
+ }
+};
+
+
+// defining them here so they are ready super fast!
+// DOM event that is received when the web page is loaded and parsed.
+channel.createSticky('onDOMContentLoaded');
+
+// Event to indicate the Cordova native side is ready.
+channel.createSticky('onNativeReady');
+
+// Event to indicate that all Cordova JavaScript objects have been created
+// and it's time to run plugin constructors.
+channel.createSticky('onCordovaReady');
+
+// Event to indicate that device properties are available
+channel.createSticky('onCordovaInfoReady');
+
+// Event to indicate that the connection property has been set.
+channel.createSticky('onCordovaConnectionReady');
+
+// Event to indicate that all automatically loaded JS plugins are loaded and ready.
+channel.createSticky('onPluginsReady');
+
+// Event to indicate that Cordova is ready
+channel.createSticky('onDeviceReady');
+
+// Event to indicate a resume lifecycle event
+channel.create('onResume');
+
+// Event to indicate a pause lifecycle event
+channel.create('onPause');
+
+// Event to indicate a destroy lifecycle event
+channel.createSticky('onDestroy');
+
+// Channels that must fire before "deviceready" is fired.
+channel.waitForInitialization('onCordovaReady');
+channel.waitForInitialization('onCordovaConnectionReady');
+channel.waitForInitialization('onDOMContentLoaded');
+
+module.exports = channel;
+
+});
+
+// file: lib/common/commandProxy.js
+define("cordova/commandProxy", function(require, exports, module) {
+
+
+// internal map of proxy function
+var CommandProxyMap = {};
+
+module.exports = {
+
+ // example: cordova.commandProxy.add("Accelerometer",{getCurrentAcceleration: function(successCallback, errorCallback, options) {...},...);
+ add:function(id,proxyObj) {
+ console.log("adding proxy for " + id);
+ CommandProxyMap[id] = proxyObj;
+ return proxyObj;
+ },
+
+ // cordova.commandProxy.remove("Accelerometer");
+ remove:function(id) {
+ var proxy = CommandProxyMap[id];
+ delete CommandProxyMap[id];
+ CommandProxyMap[id] = null;
+ return proxy;
+ },
+
+ get:function(service,action) {
+ return ( CommandProxyMap[service] ? CommandProxyMap[service][action] : null );
+ }
+};
+});
+
+// file: lib/android/exec.js
+define("cordova/exec", function(require, exports, module) {
+
+/**
+ * Execute a cordova command. It is up to the native side whether this action
+ * is synchronous or asynchronous. The native side can return:
+ * Synchronous: PluginResult object as a JSON string
+ * Asynchronous: Empty string ""
+ * If async, the native side will cordova.callbackSuccess or cordova.callbackError,
+ * depending upon the result of the action.
+ *
+ * @param {Function} success The success callback
+ * @param {Function} fail The fail callback
+ * @param {String} service The name of the service to use
+ * @param {String} action Action to be run in cordova
+ * @param {String[]} [args] Zero or more arguments to pass to the method
+ */
+var cordova = require('cordova'),
+ nativeApiProvider = require('cordova/plugin/android/nativeapiprovider'),
+ utils = require('cordova/utils'),
+ jsToNativeModes = {
+ PROMPT: 0,
+ JS_OBJECT: 1,
+ // This mode is currently for benchmarking purposes only. It must be enabled
+ // on the native side through the ENABLE_LOCATION_CHANGE_EXEC_MODE
+ // constant within CordovaWebViewClient.java before it will work.
+ LOCATION_CHANGE: 2
+ },
+ nativeToJsModes = {
+ // Polls for messages using the JS->Native bridge.
+ POLLING: 0,
+ // For LOAD_URL to be viable, it would need to have a work-around for
+ // the bug where the soft-keyboard gets dismissed when a message is sent.
+ LOAD_URL: 1,
+ // For the ONLINE_EVENT to be viable, it would need to intercept all event
+ // listeners (both through addEventListener and window.ononline) as well
+ // as set the navigator property itself.
+ ONLINE_EVENT: 2,
+ // Uses reflection to access private APIs of the WebView that can send JS
+ // to be executed.
+ // Requires Android 3.2.4 or above.
+ PRIVATE_API: 3
+ },
+ jsToNativeBridgeMode, // Set lazily.
+ nativeToJsBridgeMode = nativeToJsModes.ONLINE_EVENT,
+ pollEnabled = false,
+ messagesFromNative = [];
+
+function androidExec(success, fail, service, action, args) {
+ // Set default bridge modes if they have not already been set.
+ // By default, we use the failsafe, since addJavascriptInterface breaks too often
+ if (jsToNativeBridgeMode === undefined) {
+ androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);
+ }
+
+ // Process any ArrayBuffers in the args into a string.
+ for (var i = 0; i < args.length; i++) {
+ if (utils.typeName(args[i]) == 'ArrayBuffer') {
+ args[i] = window.btoa(String.fromCharCode.apply(null, new Uint8Array(args[i])));
+ }
+ }
+
+ var callbackId = service + cordova.callbackId++,
+ argsJson = JSON.stringify(args);
+
+ if (success || fail) {
+ cordova.callbacks[callbackId] = {success:success, fail:fail};
+ }
+
+ if (jsToNativeBridgeMode == jsToNativeModes.LOCATION_CHANGE) {
+ window.location = 'http://cdv_exec/' + service + '#' + action + '#' + callbackId + '#' + argsJson;
+ } else {
+ var messages = nativeApiProvider.get().exec(service, action, callbackId, argsJson);
+ // If argsJson was received by Java as null, try again with the PROMPT bridge mode.
+ // This happens in rare circumstances, such as when certain Unicode characters are passed over the bridge on a Galaxy S2. See CB-2666.
+ if (jsToNativeBridgeMode == jsToNativeModes.JS_OBJECT && messages === "@Null arguments.") {
+ androidExec.setJsToNativeBridgeMode(jsToNativeModes.PROMPT);
+ androidExec(success, fail, service, action, args);
+ androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);
+ return;
+ } else {
+ androidExec.processMessages(messages);
+ }
+ }
+}
+
+function pollOnce() {
+ var msg = nativeApiProvider.get().retrieveJsMessages();
+ androidExec.processMessages(msg);
+}
+
+function pollingTimerFunc() {
+ if (pollEnabled) {
+ pollOnce();
+ setTimeout(pollingTimerFunc, 50);
+ }
+}
+
+function hookOnlineApis() {
+ function proxyEvent(e) {
+ cordova.fireWindowEvent(e.type);
+ }
+ // The network module takes care of firing online and offline events.
+ // It currently fires them only on document though, so we bridge them
+ // to window here (while first listening for exec()-releated online/offline
+ // events).
+ window.addEventListener('online', pollOnce, false);
+ window.addEventListener('offline', pollOnce, false);
+ cordova.addWindowEventHandler('online');
+ cordova.addWindowEventHandler('offline');
+ document.addEventListener('online', proxyEvent, false);
+ document.addEventListener('offline', proxyEvent, false);
+}
+
+hookOnlineApis();
+
+androidExec.jsToNativeModes = jsToNativeModes;
+androidExec.nativeToJsModes = nativeToJsModes;
+
+androidExec.setJsToNativeBridgeMode = function(mode) {
+ if (mode == jsToNativeModes.JS_OBJECT && !window._cordovaNative) {
+ console.log('Falling back on PROMPT mode since _cordovaNative is missing. Expected for Android 3.2 and lower only.');
+ mode = jsToNativeModes.PROMPT;
+ }
+ nativeApiProvider.setPreferPrompt(mode == jsToNativeModes.PROMPT);
+ jsToNativeBridgeMode = mode;
+};
+
+androidExec.setNativeToJsBridgeMode = function(mode) {
+ if (mode == nativeToJsBridgeMode) {
+ return;
+ }
+ if (nativeToJsBridgeMode == nativeToJsModes.POLLING) {
+ pollEnabled = false;
+ }
+
+ nativeToJsBridgeMode = mode;
+ // Tell the native side to switch modes.
+ nativeApiProvider.get().setNativeToJsBridgeMode(mode);
+
+ if (mode == nativeToJsModes.POLLING) {
+ pollEnabled = true;
+ setTimeout(pollingTimerFunc, 1);
+ }
+};
+
+// Processes a single message, as encoded by NativeToJsMessageQueue.java.
+function processMessage(message) {
+ try {
+ var firstChar = message.charAt(0);
+ if (firstChar == 'J') {
+ eval(message.slice(1));
+ } else if (firstChar == 'S' || firstChar == 'F') {
+ var success = firstChar == 'S';
+ var keepCallback = message.charAt(1) == '1';
+ var spaceIdx = message.indexOf(' ', 2);
+ var status = +message.slice(2, spaceIdx);
+ var nextSpaceIdx = message.indexOf(' ', spaceIdx + 1);
+ var callbackId = message.slice(spaceIdx + 1, nextSpaceIdx);
+ var payloadKind = message.charAt(nextSpaceIdx + 1);
+ var payload;
+ if (payloadKind == 's') {
+ payload = message.slice(nextSpaceIdx + 2);
+ } else if (payloadKind == 't') {
+ payload = true;
+ } else if (payloadKind == 'f') {
+ payload = false;
+ } else if (payloadKind == 'N') {
+ payload = null;
+ } else if (payloadKind == 'n') {
+ payload = +message.slice(nextSpaceIdx + 2);
+ } else if (payloadKind == 'A') {
+ var data = message.slice(nextSpaceIdx + 2);
+ var bytes = window.atob(data);
+ var arraybuffer = new Uint8Array(bytes.length);
+ for (var i = 0; i < bytes.length; i++) {
+ arraybuffer[i] = bytes.charCodeAt(i);
+ }
+ payload = arraybuffer.buffer;
+ } else if (payloadKind == 'S') {
+ payload = window.atob(message.slice(nextSpaceIdx + 2));
+ } else {
+ payload = JSON.parse(message.slice(nextSpaceIdx + 1));
+ }
+ cordova.callbackFromNative(callbackId, success, status, [payload], keepCallback);
+ } else {
+ console.log("processMessage failed: invalid message:" + message);
+ }
+ } catch (e) {
+ console.log("processMessage failed: Message: " + message);
+ console.log("processMessage failed: Error: " + e);
+ console.log("processMessage failed: Stack: " + e.stack);
+ }
+}
+
+// This is called from the NativeToJsMessageQueue.java.
+androidExec.processMessages = function(messages) {
+ if (messages) {
+ messagesFromNative.push(messages);
+ // Check for the reentrant case, and enqueue the message if that's the case.
+ if (messagesFromNative.length > 1) {
+ return;
+ }
+ while (messagesFromNative.length) {
+ // Don't unshift until the end so that reentrancy can be detected.
+ messages = messagesFromNative[0];
+ // The Java side can send a * message to indicate that it
+ // still has messages waiting to be retrieved.
+ if (messages == '*') {
+ messagesFromNative.shift();
+ window.setTimeout(pollOnce, 0);
+ return;
+ }
+
+ var spaceIdx = messages.indexOf(' ');
+ var msgLen = +messages.slice(0, spaceIdx);
+ var message = messages.substr(spaceIdx + 1, msgLen);
+ messages = messages.slice(spaceIdx + msgLen + 1);
+ processMessage(message);
+ if (messages) {
+ messagesFromNative[0] = messages;
+ } else {
+ messagesFromNative.shift();
+ }
+ }
+ }
+};
+
+module.exports = androidExec;
+
+});
+
+// file: lib/common/modulemapper.js
+define("cordova/modulemapper", function(require, exports, module) {
+
+var builder = require('cordova/builder'),
+ moduleMap = define.moduleMap,
+ symbolList,
+ deprecationMap;
+
+exports.reset = function() {
+ symbolList = [];
+ deprecationMap = {};
+};
+
+function addEntry(strategy, moduleName, symbolPath, opt_deprecationMessage) {
+ if (!(moduleName in moduleMap)) {
+ throw new Error('Module ' + moduleName + ' does not exist.');
+ }
+ symbolList.push(strategy, moduleName, symbolPath);
+ if (opt_deprecationMessage) {
+ deprecationMap[symbolPath] = opt_deprecationMessage;
+ }
+}
+
+// Note: Android 2.3 does have Function.bind().
+exports.clobbers = function(moduleName, symbolPath, opt_deprecationMessage) {
+ addEntry('c', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+exports.merges = function(moduleName, symbolPath, opt_deprecationMessage) {
+ addEntry('m', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+exports.defaults = function(moduleName, symbolPath, opt_deprecationMessage) {
+ addEntry('d', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+function prepareNamespace(symbolPath, context) {
+ if (!symbolPath) {
+ return context;
+ }
+ var parts = symbolPath.split('.');
+ var cur = context;
+ for (var i = 0, part; part = parts[i]; ++i) {
+ cur = cur[part] = cur[part] || {};
+ }
+ return cur;
+}
+
+exports.mapModules = function(context) {
+ var origSymbols = {};
+ context.CDV_origSymbols = origSymbols;
+ for (var i = 0, len = symbolList.length; i < len; i += 3) {
+ var strategy = symbolList[i];
+ var moduleName = symbolList[i + 1];
+ var symbolPath = symbolList[i + 2];
+ var lastDot = symbolPath.lastIndexOf('.');
+ var namespace = symbolPath.substr(0, lastDot);
+ var lastName = symbolPath.substr(lastDot + 1);
+
+ var module = require(moduleName);
+ var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null;
+ var parentObj = prepareNamespace(namespace, context);
+ var target = parentObj[lastName];
+
+ if (strategy == 'm' && target) {
+ builder.recursiveMerge(target, module);
+ } else if ((strategy == 'd' && !target) || (strategy != 'd')) {
+ if (!(symbolPath in origSymbols)) {
+ origSymbols[symbolPath] = target;
+ }
+ builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg);
+ }
+ }
+};
+
+exports.getOriginalSymbol = function(context, symbolPath) {
+ var origSymbols = context.CDV_origSymbols;
+ if (origSymbols && (symbolPath in origSymbols)) {
+ return origSymbols[symbolPath];
+ }
+ var parts = symbolPath.split('.');
+ var obj = context;
+ for (var i = 0; i < parts.length; ++i) {
+ obj = obj && obj[parts[i]];
+ }
+ return obj;
+};
+
+exports.loadMatchingModules = function(matchingRegExp) {
+ for (var k in moduleMap) {
+ if (matchingRegExp.exec(k)) {
+ require(k);
+ }
+ }
+};
+
+exports.reset();
+
+
+});
+
+// file: lib/android/platform.js
+define("cordova/platform", function(require, exports, module) {
+
+module.exports = {
+ id: "android",
+ initialize:function() {
+ var channel = require("cordova/channel"),
+ cordova = require('cordova'),
+ exec = require('cordova/exec'),
+ modulemapper = require('cordova/modulemapper');
+
+ modulemapper.loadMatchingModules(/cordova.*\/symbols$/);
+ modulemapper.clobbers('cordova/plugin/android/app', 'navigator.app');
+
+ modulemapper.mapModules(window);
+
+ // Inject a listener for the backbutton on the document.
+ var backButtonChannel = cordova.addDocumentEventHandler('backbutton');
+ backButtonChannel.onHasSubscribersChange = function() {
+ // If we just attached the first handler or detached the last handler,
+ // let native know we need to override the back button.
+ exec(null, null, "App", "overrideBackbutton", [this.numHandlers == 1]);
+ };
+
+ // Add hardware MENU and SEARCH button handlers
+ cordova.addDocumentEventHandler('menubutton');
+ cordova.addDocumentEventHandler('searchbutton');
+
+ // Let native code know we are all done on the JS side.
+ // Native code will then un-hide the WebView.
+ channel.join(function() {
+ exec(null, null, "App", "show", []);
+ }, [channel.onCordovaReady]);
+ }
+};
+
+});
+
+// file: lib/common/plugin/Acceleration.js
+define("cordova/plugin/Acceleration", function(require, exports, module) {
+
+var Acceleration = function(x, y, z, timestamp) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.timestamp = timestamp || (new Date()).getTime();
+};
+
+module.exports = Acceleration;
+
+});
+
+// file: lib/common/plugin/Camera.js
+define("cordova/plugin/Camera", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ exec = require('cordova/exec'),
+ Camera = require('cordova/plugin/CameraConstants'),
+ CameraPopoverHandle = require('cordova/plugin/CameraPopoverHandle');
+
+var cameraExport = {};
+
+// Tack on the Camera Constants to the base camera plugin.
+for (var key in Camera) {
+ cameraExport[key] = Camera[key];
+}
+
+/**
+ * Gets a picture from source defined by "options.sourceType", and returns the
+ * image as defined by the "options.destinationType" option.
+
+ * The defaults are sourceType=CAMERA and destinationType=FILE_URI.
+ *
+ * @param {Function} successCallback
+ * @param {Function} errorCallback
+ * @param {Object} options
+ */
+cameraExport.getPicture = function(successCallback, errorCallback, options) {
+ argscheck.checkArgs('fFO', 'Camera.getPicture', arguments);
+ options = options || {};
+ var getValue = argscheck.getValue;
+
+ var quality = getValue(options.quality, 50);
+ var destinationType = getValue(options.destinationType, Camera.DestinationType.FILE_URI);
+ var sourceType = getValue(options.sourceType, Camera.PictureSourceType.CAMERA);
+ var targetWidth = getValue(options.targetWidth, -1);
+ var targetHeight = getValue(options.targetHeight, -1);
+ var encodingType = getValue(options.encodingType, Camera.EncodingType.JPEG);
+ var mediaType = getValue(options.mediaType, Camera.MediaType.PICTURE);
+ var allowEdit = !!options.allowEdit;
+ var correctOrientation = !!options.correctOrientation;
+ var saveToPhotoAlbum = !!options.saveToPhotoAlbum;
+ var popoverOptions = getValue(options.popoverOptions, null);
+ var cameraDirection = getValue(options.cameraDirection, Camera.Direction.BACK);
+
+ var args = [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType,
+ mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions, cameraDirection];
+
+ exec(successCallback, errorCallback, "Camera", "takePicture", args);
+ return new CameraPopoverHandle();
+};
+
+cameraExport.cleanup = function(successCallback, errorCallback) {
+ exec(successCallback, errorCallback, "Camera", "cleanup", []);
+};
+
+module.exports = cameraExport;
+
+});
+
+// file: lib/common/plugin/CameraConstants.js
+define("cordova/plugin/CameraConstants", function(require, exports, module) {
+
+module.exports = {
+ DestinationType:{
+ DATA_URL: 0, // Return base64 encoded string
+ FILE_URI: 1, // Return file uri (content://media/external/images/media/2 for Android)
+ NATIVE_URI: 2 // Return native uri (eg. asset-library://... for iOS)
+ },
+ EncodingType:{
+ JPEG: 0, // Return JPEG encoded image
+ PNG: 1 // Return PNG encoded image
+ },
+ MediaType:{
+ PICTURE: 0, // allow selection of still pictures only. DEFAULT. Will return format specified via DestinationType
+ VIDEO: 1, // allow selection of video only, ONLY RETURNS URL
+ ALLMEDIA : 2 // allow selection from all media types
+ },
+ PictureSourceType:{
+ PHOTOLIBRARY : 0, // Choose image from picture library (same as SAVEDPHOTOALBUM for Android)
+ CAMERA : 1, // Take picture from camera
+ SAVEDPHOTOALBUM : 2 // Choose image from picture library (same as PHOTOLIBRARY for Android)
+ },
+ PopoverArrowDirection:{
+ ARROW_UP : 1, // matches iOS UIPopoverArrowDirection constants to specify arrow location on popover
+ ARROW_DOWN : 2,
+ ARROW_LEFT : 4,
+ ARROW_RIGHT : 8,
+ ARROW_ANY : 15
+ },
+ Direction:{
+ BACK: 0,
+ FRONT: 1
+ }
+};
+
+});
+
+// file: lib/common/plugin/CameraPopoverHandle.js
+define("cordova/plugin/CameraPopoverHandle", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+
+/**
+ * A handle to an image picker popover.
+ */
+var CameraPopoverHandle = function() {
+ this.setPosition = function(popoverOptions) {
+ console.log('CameraPopoverHandle.setPosition is only supported on iOS.');
+ };
+};
+
+module.exports = CameraPopoverHandle;
+
+});
+
+// file: lib/common/plugin/CameraPopoverOptions.js
+define("cordova/plugin/CameraPopoverOptions", function(require, exports, module) {
+
+var Camera = require('cordova/plugin/CameraConstants');
+
+/**
+ * Encapsulates options for iOS Popover image picker
+ */
+var CameraPopoverOptions = function(x,y,width,height,arrowDir){
+ // information of rectangle that popover should be anchored to
+ this.x = x || 0;
+ this.y = y || 32;
+ this.width = width || 320;
+ this.height = height || 480;
+ // The direction of the popover arrow
+ this.arrowDir = arrowDir || Camera.PopoverArrowDirection.ARROW_ANY;
+};
+
+module.exports = CameraPopoverOptions;
+
+});
+
+// file: lib/common/plugin/CaptureAudioOptions.js
+define("cordova/plugin/CaptureAudioOptions", function(require, exports, module) {
+
+/**
+ * Encapsulates all audio capture operation configuration options.
+ */
+var CaptureAudioOptions = function(){
+ // Upper limit of sound clips user can record. Value must be equal or greater than 1.
+ this.limit = 1;
+ // Maximum duration of a single sound clip in seconds.
+ this.duration = 0;
+ // The selected audio mode. Must match with one of the elements in supportedAudioModes array.
+ this.mode = null;
+};
+
+module.exports = CaptureAudioOptions;
+
+});
+
+// file: lib/common/plugin/CaptureError.js
+define("cordova/plugin/CaptureError", function(require, exports, module) {
+
+/**
+ * The CaptureError interface encapsulates all errors in the Capture API.
+ */
+var CaptureError = function(c) {
+ this.code = c || null;
+};
+
+// Camera or microphone failed to capture image or sound.
+CaptureError.CAPTURE_INTERNAL_ERR = 0;
+// Camera application or audio capture application is currently serving other capture request.
+CaptureError.CAPTURE_APPLICATION_BUSY = 1;
+// Invalid use of the API (e.g. limit parameter has value less than one).
+CaptureError.CAPTURE_INVALID_ARGUMENT = 2;
+// User exited camera application or audio capture application before capturing anything.
+CaptureError.CAPTURE_NO_MEDIA_FILES = 3;
+// The requested capture operation is not supported.
+CaptureError.CAPTURE_NOT_SUPPORTED = 20;
+
+module.exports = CaptureError;
+
+});
+
+// file: lib/common/plugin/CaptureImageOptions.js
+define("cordova/plugin/CaptureImageOptions", function(require, exports, module) {
+
+/**
+ * Encapsulates all image capture operation configuration options.
+ */
+var CaptureImageOptions = function(){
+ // Upper limit of images user can take. Value must be equal or greater than 1.
+ this.limit = 1;
+ // The selected image mode. Must match with one of the elements in supportedImageModes array.
+ this.mode = null;
+};
+
+module.exports = CaptureImageOptions;
+
+});
+
+// file: lib/common/plugin/CaptureVideoOptions.js
+define("cordova/plugin/CaptureVideoOptions", function(require, exports, module) {
+
+/**
+ * Encapsulates all video capture operation configuration options.
+ */
+var CaptureVideoOptions = function(){
+ // Upper limit of videos user can record. Value must be equal or greater than 1.
+ this.limit = 1;
+ // Maximum duration of a single video clip in seconds.
+ this.duration = 0;
+ // The selected video mode. Must match with one of the elements in supportedVideoModes array.
+ this.mode = null;
+};
+
+module.exports = CaptureVideoOptions;
+
+});
+
+// file: lib/common/plugin/CompassError.js
+define("cordova/plugin/CompassError", function(require, exports, module) {
+
+/**
+ * CompassError.
+ * An error code assigned by an implementation when an error has occurred
+ * @constructor
+ */
+var CompassError = function(err) {
+ this.code = (err !== undefined ? err : null);
+};
+
+CompassError.COMPASS_INTERNAL_ERR = 0;
+CompassError.COMPASS_NOT_SUPPORTED = 20;
+
+module.exports = CompassError;
+
+});
+
+// file: lib/common/plugin/CompassHeading.js
+define("cordova/plugin/CompassHeading", function(require, exports, module) {
+
+var CompassHeading = function(magneticHeading, trueHeading, headingAccuracy, timestamp) {
+ this.magneticHeading = magneticHeading;
+ this.trueHeading = trueHeading;
+ this.headingAccuracy = headingAccuracy;
+ this.timestamp = timestamp || new Date().getTime();
+};
+
+module.exports = CompassHeading;
+
+});
+
+// file: lib/common/plugin/ConfigurationData.js
+define("cordova/plugin/ConfigurationData", function(require, exports, module) {
+
+/**
+ * Encapsulates a set of parameters that the capture device supports.
+ */
+function ConfigurationData() {
+ // The ASCII-encoded string in lower case representing the media type.
+ this.type = null;
+ // The height attribute represents height of the image or video in pixels.
+ // In the case of a sound clip this attribute has value 0.
+ this.height = 0;
+ // The width attribute represents width of the image or video in pixels.
+ // In the case of a sound clip this attribute has value 0
+ this.width = 0;
+}
+
+module.exports = ConfigurationData;
+
+});
+
+// file: lib/common/plugin/Connection.js
+define("cordova/plugin/Connection", function(require, exports, module) {
+
+/**
+ * Network status
+ */
+module.exports = {
+ UNKNOWN: "unknown",
+ ETHERNET: "ethernet",
+ WIFI: "wifi",
+ CELL_2G: "2g",
+ CELL_3G: "3g",
+ CELL_4G: "4g",
+ CELL:"cellular",
+ NONE: "none"
+};
+
+});
+
+// file: lib/common/plugin/Contact.js
+define("cordova/plugin/Contact", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ exec = require('cordova/exec'),
+ ContactError = require('cordova/plugin/ContactError'),
+ utils = require('cordova/utils');
+
+/**
+* Converts primitives into Complex Object
+* Currently only used for Date fields
+*/
+function convertIn(contact) {
+ var value = contact.birthday;
+ try {
+ contact.birthday = new Date(parseFloat(value));
+ } catch (exception){
+ console.log("Cordova Contact convertIn error: exception creating date.");
+ }
+ return contact;
+}
+
+/**
+* Converts Complex objects into primitives
+* Only conversion at present is for Dates.
+**/
+
+function convertOut(contact) {
+ var value = contact.birthday;
+ if (value !== null) {
+ // try to make it a Date object if it is not already
+ if (!utils.isDate(value)){
+ try {
+ value = new Date(value);
+ } catch(exception){
+ value = null;
+ }
+ }
+ if (utils.isDate(value)){
+ value = value.valueOf(); // convert to milliseconds
+ }
+ contact.birthday = value;
+ }
+ return contact;
+}
+
+/**
+* Contains information about a single contact.
+* @constructor
+* @param {DOMString} id unique identifier
+* @param {DOMString} displayName
+* @param {ContactName} name
+* @param {DOMString} nickname
+* @param {Array.<ContactField>} phoneNumbers array of phone numbers
+* @param {Array.<ContactField>} emails array of email addresses
+* @param {Array.<ContactAddress>} addresses array of addresses
+* @param {Array.<ContactField>} ims instant messaging user ids
+* @param {Array.<ContactOrganization>} organizations
+* @param {DOMString} birthday contact's birthday
+* @param {DOMString} note user notes about contact
+* @param {Array.<ContactField>} photos
+* @param {Array.<ContactField>} categories
+* @param {Array.<ContactField>} urls contact's web sites
+*/
+var Contact = function (id, displayName, name, nickname, phoneNumbers, emails, addresses,
+ ims, organizations, birthday, note, photos, categories, urls) {
+ this.id = id || null;
+ this.rawId = null;
+ this.displayName = displayName || null;
+ this.name = name || null; // ContactName
+ this.nickname = nickname || null;
+ this.phoneNumbers = phoneNumbers || null; // ContactField[]
+ this.emails = emails || null; // ContactField[]
+ this.addresses = addresses || null; // ContactAddress[]
+ this.ims = ims || null; // ContactField[]
+ this.organizations = organizations || null; // ContactOrganization[]
+ this.birthday = birthday || null;
+ this.note = note || null;
+ this.photos = photos || null; // ContactField[]
+ this.categories = categories || null; // ContactField[]
+ this.urls = urls || null; // ContactField[]
+};
+
+/**
+* Removes contact from device storage.
+* @param successCB success callback
+* @param errorCB error callback
+*/
+Contact.prototype.remove = function(successCB, errorCB) {
+ argscheck.checkArgs('FF', 'Contact.remove', arguments);
+ var fail = errorCB && function(code) {
+ errorCB(new ContactError(code));
+ };
+ if (this.id === null) {
+ fail(ContactError.UNKNOWN_ERROR);
+ }
+ else {
+ exec(successCB, fail, "Contacts", "remove", [this.id]);
+ }
+};
+
+/**
+* Creates a deep copy of this Contact.
+* With the contact ID set to null.
+* @return copy of this Contact
+*/
+Contact.prototype.clone = function() {
+ var clonedContact = utils.clone(this);
+ clonedContact.id = null;
+ clonedContact.rawId = null;
+
+ function nullIds(arr) {
+ if (arr) {
+ for (var i = 0; i < arr.length; ++i) {
+ arr[i].id = null;
+ }
+ }
+ }
+
+ // Loop through and clear out any id's in phones, emails, etc.
+ nullIds(clonedContact.phoneNumbers);
+ nullIds(clonedContact.emails);
+ nullIds(clonedContact.addresses);
+ nullIds(clonedContact.ims);
+ nullIds(clonedContact.organizations);
+ nullIds(clonedContact.categories);
+ nullIds(clonedContact.photos);
+ nullIds(clonedContact.urls);
+ return clonedContact;
+};
+
+/**
+* Persists contact to device storage.
+* @param successCB success callback
+* @param errorCB error callback
+*/
+Contact.prototype.save = function(successCB, errorCB) {
+ argscheck.checkArgs('FFO', 'Contact.save', arguments);
+ var fail = errorCB && function(code) {
+ errorCB(new ContactError(code));
+ };
+ var success = function(result) {
+ if (result) {
+ if (successCB) {
+ var fullContact = require('cordova/plugin/contacts').create(result);
+ successCB(convertIn(fullContact));
+ }
+ }
+ else {
+ // no Entry object returned
+ fail(ContactError.UNKNOWN_ERROR);
+ }
+ };
+ var dupContact = convertOut(utils.clone(this));
+ exec(success, fail, "Contacts", "save", [dupContact]);
+};
+
+
+module.exports = Contact;
+
+});
+
+// file: lib/common/plugin/ContactAddress.js
+define("cordova/plugin/ContactAddress", function(require, exports, module) {
+
+/**
+* Contact address.
+* @constructor
+* @param {DOMString} id unique identifier, should only be set by native code
+* @param formatted // NOTE: not a W3C standard
+* @param streetAddress
+* @param locality
+* @param region
+* @param postalCode
+* @param country
+*/
+
+var ContactAddress = function(pref, type, formatted, streetAddress, locality, region, postalCode, country) {
+ this.id = null;
+ this.pref = (typeof pref != 'undefined' ? pref : false);
+ this.type = type || null;
+ this.formatted = formatted || null;
+ this.streetAddress = streetAddress || null;
+ this.locality = locality || null;
+ this.region = region || null;
+ this.postalCode = postalCode || null;
+ this.country = country || null;
+};
+
+module.exports = ContactAddress;
+
+});
+
+// file: lib/common/plugin/ContactError.js
+define("cordova/plugin/ContactError", function(require, exports, module) {
+
+/**
+ * ContactError.
+ * An error code assigned by an implementation when an error has occurred
+ * @constructor
+ */
+var ContactError = function(err) {
+ this.code = (typeof err != 'undefined' ? err : null);
+};
+
+/**
+ * Error codes
+ */
+ContactError.UNKNOWN_ERROR = 0;
+ContactError.INVALID_ARGUMENT_ERROR = 1;
+ContactError.TIMEOUT_ERROR = 2;
+ContactError.PENDING_OPERATION_ERROR = 3;
+ContactError.IO_ERROR = 4;
+ContactError.NOT_SUPPORTED_ERROR = 5;
+ContactError.PERMISSION_DENIED_ERROR = 20;
+
+module.exports = ContactError;
+
+});
+
+// file: lib/common/plugin/ContactField.js
+define("cordova/plugin/ContactField", function(require, exports, module) {
+
+/**
+* Generic contact field.
+* @constructor
+* @param {DOMString} id unique identifier, should only be set by native code // NOTE: not a W3C standard
+* @param type
+* @param value
+* @param pref
+*/
+var ContactField = function(type, value, pref) {
+ this.id = null;
+ this.type = (type && type.toString()) || null;
+ this.value = (value && value.toString()) || null;
+ this.pref = (typeof pref != 'undefined' ? pref : false);
+};
+
+module.exports = ContactField;
+
+});
+
+// file: lib/common/plugin/ContactFindOptions.js
+define("cordova/plugin/ContactFindOptions", function(require, exports, module) {
+
+/**
+ * ContactFindOptions.
+ * @constructor
+ * @param filter used to match contacts against
+ * @param multiple boolean used to determine if more than one contact should be returned
+ */
+
+var ContactFindOptions = function(filter, multiple) {
+ this.filter = filter || '';
+ this.multiple = (typeof multiple != 'undefined' ? multiple : false);
+};
+
+module.exports = ContactFindOptions;
+
+});
+
+// file: lib/common/plugin/ContactName.js
+define("cordova/plugin/ContactName", function(require, exports, module) {
+
+/**
+* Contact name.
+* @constructor
+* @param formatted // NOTE: not part of W3C standard
+* @param familyName
+* @param givenName
+* @param middle
+* @param prefix
+* @param suffix
+*/
+var ContactName = function(formatted, familyName, givenName, middle, prefix, suffix) {
+ this.formatted = formatted || null;
+ this.familyName = familyName || null;
+ this.givenName = givenName || null;
+ this.middleName = middle || null;
+ this.honorificPrefix = prefix || null;
+ this.honorificSuffix = suffix || null;
+};
+
+module.exports = ContactName;
+
+});
+
+// file: lib/common/plugin/ContactOrganization.js
+define("cordova/plugin/ContactOrganization", function(require, exports, module) {
+
+/**
+* Contact organization.
+* @constructor
+* @param {DOMString} id unique identifier, should only be set by native code // NOTE: not a W3C standard
+* @param name
+* @param dept
+* @param title
+* @param startDate
+* @param endDate
+* @param location
+* @param desc
+*/
+
+var ContactOrganization = function(pref, type, name, dept, title) {
+ this.id = null;
+ this.pref = (typeof pref != 'undefined' ? pref : false);
+ this.type = type || null;
+ this.name = name || null;
+ this.department = dept || null;
+ this.title = title || null;
+};
+
+module.exports = ContactOrganization;
+
+});
+
+// file: lib/common/plugin/Coordinates.js
+define("cordova/plugin/Coordinates", function(require, exports, module) {
+
+/**
+ * This class contains position information.
+ * @param {Object} lat
+ * @param {Object} lng
+ * @param {Object} alt
+ * @param {Object} acc
+ * @param {Object} head
+ * @param {Object} vel
+ * @param {Object} altacc
+ * @constructor
+ */
+var Coordinates = function(lat, lng, alt, acc, head, vel, altacc) {
+ /**
+ * The latitude of the position.
+ */
+ this.latitude = lat;
+ /**
+ * The longitude of the position,
+ */
+ this.longitude = lng;
+ /**
+ * The accuracy of the position.
+ */
+ this.accuracy = acc;
+ /**
+ * The altitude of the position.
+ */
+ this.altitude = (alt !== undefined ? alt : null);
+ /**
+ * The direction the device is moving at the position.
+ */
+ this.heading = (head !== undefined ? head : null);
+ /**
+ * The velocity with which the device is moving at the position.
+ */
+ this.speed = (vel !== undefined ? vel : null);
+
+ if (this.speed === 0 || this.speed === null) {
+ this.heading = NaN;
+ }
+
+ /**
+ * The altitude accuracy of the position.
+ */
+ this.altitudeAccuracy = (altacc !== undefined) ? altacc : null;
+};
+
+module.exports = Coordinates;
+
+});
+
+// file: lib/common/plugin/DirectoryEntry.js
+define("cordova/plugin/DirectoryEntry", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ utils = require('cordova/utils'),
+ exec = require('cordova/exec'),
+ Entry = require('cordova/plugin/Entry'),
+ FileError = require('cordova/plugin/FileError'),
+ DirectoryReader = require('cordova/plugin/DirectoryReader');
+
+/**
+ * An interface representing a directory on the file system.
+ *
+ * {boolean} isFile always false (readonly)
+ * {boolean} isDirectory always true (readonly)
+ * {DOMString} name of the directory, excluding the path leading to it (readonly)
+ * {DOMString} fullPath the absolute full path to the directory (readonly)
+ * TODO: implement this!!! {FileSystem} filesystem on which the directory resides (readonly)
+ */
+var DirectoryEntry = function(name, fullPath) {
+ DirectoryEntry.__super__.constructor.call(this, false, true, name, fullPath);
+};
+
+utils.extend(DirectoryEntry, Entry);
+
+/**
+ * Creates a new DirectoryReader to read entries from this directory
+ */
+DirectoryEntry.prototype.createReader = function() {
+ return new DirectoryReader(this.fullPath);
+};
+
+/**
+ * Creates or looks up a directory
+ *
+ * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a directory
+ * @param {Flags} options to create or exclusively create the directory
+ * @param {Function} successCallback is called with the new entry
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryEntry.prototype.getDirectory = function(path, options, successCallback, errorCallback) {
+ argscheck.checkArgs('sOFF', 'DirectoryEntry.getDirectory', arguments);
+ var win = successCallback && function(result) {
+ var entry = new DirectoryEntry(result.name, result.fullPath);
+ successCallback(entry);
+ };
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(win, fail, "File", "getDirectory", [this.fullPath, path, options]);
+};
+
+/**
+ * Deletes a directory and all of it's contents
+ *
+ * @param {Function} successCallback is called with no parameters
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryEntry.prototype.removeRecursively = function(successCallback, errorCallback) {
+ argscheck.checkArgs('FF', 'DirectoryEntry.removeRecursively', arguments);
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(successCallback, fail, "File", "removeRecursively", [this.fullPath]);
+};
+
+/**
+ * Creates or looks up a file
+ *
+ * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a file
+ * @param {Flags} options to create or exclusively create the file
+ * @param {Function} successCallback is called with the new entry
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryEntry.prototype.getFile = function(path, options, successCallback, errorCallback) {
+ argscheck.checkArgs('sOFF', 'DirectoryEntry.getFile', arguments);
+ var win = successCallback && function(result) {
+ var FileEntry = require('cordova/plugin/FileEntry');
+ var entry = new FileEntry(result.name, result.fullPath);
+ successCallback(entry);
+ };
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(win, fail, "File", "getFile", [this.fullPath, path, options]);
+};
+
+module.exports = DirectoryEntry;
+
+});
+
+// file: lib/common/plugin/DirectoryReader.js
+define("cordova/plugin/DirectoryReader", function(require, exports, module) {
+
+var exec = require('cordova/exec'),
+ FileError = require('cordova/plugin/FileError') ;
+
+/**
+ * An interface that lists the files and directories in a directory.
+ */
+function DirectoryReader(path) {
+ this.path = path || null;
+}
+
+/**
+ * Returns a list of entries from a directory.
+ *
+ * @param {Function} successCallback is called with a list of entries
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryReader.prototype.readEntries = function(successCallback, errorCallback) {
+ var win = typeof successCallback !== 'function' ? null : function(result) {
+ var retVal = [];
+ for (var i=0; i<result.length; i++) {
+ var entry = null;
+ if (result[i].isDirectory) {
+ entry = new (require('cordova/plugin/DirectoryEntry'))();
+ }
+ else if (result[i].isFile) {
+ entry = new (require('cordova/plugin/FileEntry'))();
+ }
+ entry.isDirectory = result[i].isDirectory;
+ entry.isFile = result[i].isFile;
+ entry.name = result[i].name;
+ entry.fullPath = result[i].fullPath;
+ retVal.push(entry);
+ }
+ successCallback(retVal);
+ };
+ var fail = typeof errorCallback !== 'function' ? null : function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(win, fail, "File", "readEntries", [this.path]);
+};
+
+module.exports = DirectoryReader;
+
+});
+
+// file: lib/common/plugin/Entry.js
+define("cordova/plugin/Entry", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ exec = require('cordova/exec'),
+ FileError = require('cordova/plugin/FileError'),
+ Metadata = require('cordova/plugin/Metadata');
+
+/**
+ * Represents a file or directory on the local file system.
+ *
+ * @param isFile
+ * {boolean} true if Entry is a file (readonly)
+ * @param isDirectory
+ * {boolean} true if Entry is a directory (readonly)
+ * @param name
+ * {DOMString} name of the file or directory, excluding the path
+ * leading to it (readonly)
+ * @param fullPath
+ * {DOMString} the absolute full path to the file or directory
+ * (readonly)
+ */
+function Entry(isFile, isDirectory, name, fullPath, fileSystem) {
+ this.isFile = !!isFile;
+ this.isDirectory = !!isDirectory;
+ this.name = name || '';
+ this.fullPath = fullPath || '';
+ this.filesystem = fileSystem || null;
+}
+
+/**
+ * Look up the metadata of the entry.
+ *
+ * @param successCallback
+ * {Function} is called with a Metadata object
+ * @param errorCallback
+ * {Function} is called with a FileError
+ */
+Entry.prototype.getMetadata = function(successCallback, errorCallback) {
+ argscheck.checkArgs('FF', 'Entry.getMetadata', arguments);
+ var success = successCallback && function(lastModified) {
+ var metadata = new Metadata(lastModified);
+ successCallback(metadata);
+ };
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+
+ exec(success, fail, "File", "getMetadata", [this.fullPath]);
+};
+
+/**
+ * Set the metadata of the entry.
+ *
+ * @param successCallback
+ * {Function} is called with a Metadata object
+ * @param errorCallback
+ * {Function} is called with a FileError
+ * @param metadataObject
+ * {Object} keys and values to set
+ */
+Entry.prototype.setMetadata = function(successCallback, errorCallback, metadataObject) {
+ argscheck.checkArgs('FFO', 'Entry.setMetadata', arguments);
+ exec(successCallback, errorCallback, "File", "setMetadata", [this.fullPath, metadataObject]);
+};
+
+/**
+ * Move a file or directory to a new location.
+ *
+ * @param parent
+ * {DirectoryEntry} the directory to which to move this entry
+ * @param newName
+ * {DOMString} new name of the entry, defaults to the current name
+ * @param successCallback
+ * {Function} called with the new DirectoryEntry object
+ * @param errorCallback
+ * {Function} called with a FileError
+ */
+Entry.prototype.moveTo = function(parent, newName, successCallback, errorCallback) {
+ argscheck.checkArgs('oSFF', 'Entry.moveTo', arguments);
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ // source path
+ var srcPath = this.fullPath,
+ // entry name
+ name = newName || this.name,
+ success = function(entry) {
+ if (entry) {
+ if (successCallback) {
+ // create appropriate Entry object
+ var result = (entry.isDirectory) ? new (require('cordova/plugin/DirectoryEntry'))(entry.name, entry.fullPath) : new (require('cordova/plugin/FileEntry'))(entry.name, entry.fullPath);
+ successCallback(result);
+ }
+ }
+ else {
+ // no Entry object returned
+ fail && fail(FileError.NOT_FOUND_ERR);
+ }
+ };
+
+ // copy
+ exec(success, fail, "File", "moveTo", [srcPath, parent.fullPath, name]);
+};
+
+/**
+ * Copy a directory to a different location.
+ *
+ * @param parent
+ * {DirectoryEntry} the directory to which to copy the entry
+ * @param newName
+ * {DOMString} new name of the entry, defaults to the current name
+ * @param successCallback
+ * {Function} called with the new Entry object
+ * @param errorCallback
+ * {Function} called with a FileError
+ */
+Entry.prototype.copyTo = function(parent, newName, successCallback, errorCallback) {
+ argscheck.checkArgs('oSFF', 'Entry.copyTo', arguments);
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+
+ // source path
+ var srcPath = this.fullPath,
+ // entry name
+ name = newName || this.name,
+ // success callback
+ success = function(entry) {
+ if (entry) {
+ if (successCallback) {
+ // create appropriate Entry object
+ var result = (entry.isDirectory) ? new (require('cordova/plugin/DirectoryEntry'))(entry.name, entry.fullPath) : new (require('cordova/plugin/FileEntry'))(entry.name, entry.fullPath);
+ successCallback(result);
+ }
+ }
+ else {
+ // no Entry object returned
+ fail && fail(FileError.NOT_FOUND_ERR);
+ }
+ };
+
+ // copy
+ exec(success, fail, "File", "copyTo", [srcPath, parent.fullPath, name]);
+};
+
+/**
+ * Return a URL that can be used to identify this entry.
+ */
+Entry.prototype.toURL = function() {
+ // fullPath attribute contains the full URL
+ return this.fullPath;
+};
+
+/**
+ * Returns a URI that can be used to identify this entry.
+ *
+ * @param {DOMString} mimeType for a FileEntry, the mime type to be used to interpret the file, when loaded through this URI.
+ * @return uri
+ */
+Entry.prototype.toURI = function(mimeType) {
+ console.log("DEPRECATED: Update your code to use 'toURL'");
+ // fullPath attribute contains the full URI
+ return this.toURL();
+};
+
+/**
+ * Remove a file or directory. It is an error to attempt to delete a
+ * directory that is not empty. It is an error to attempt to delete a
+ * root directory of a file system.
+ *
+ * @param successCallback {Function} called with no parameters
+ * @param errorCallback {Function} called with a FileError
+ */
+Entry.prototype.remove = function(successCallback, errorCallback) {
+ argscheck.checkArgs('FF', 'Entry.remove', arguments);
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(successCallback, fail, "File", "remove", [this.fullPath]);
+};
+
+/**
+ * Look up the parent DirectoryEntry of this entry.
+ *
+ * @param successCallback {Function} called with the parent DirectoryEntry object
+ * @param errorCallback {Function} called with a FileError
+ */
+Entry.prototype.getParent = function(successCallback, errorCallback) {
+ argscheck.checkArgs('FF', 'Entry.getParent', arguments);
+ var win = successCallback && function(result) {
+ var DirectoryEntry = require('cordova/plugin/DirectoryEntry');
+ var entry = new DirectoryEntry(result.name, result.fullPath);
+ successCallback(entry);
+ };
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(win, fail, "File", "getParent", [this.fullPath]);
+};
+
+module.exports = Entry;
+
+});
+
+// file: lib/common/plugin/File.js
+define("cordova/plugin/File", function(require, exports, module) {
+
+/**
+ * Constructor.
+ * name {DOMString} name of the file, without path information
+ * fullPath {DOMString} the full path of the file, including the name
+ * type {DOMString} mime type
+ * lastModifiedDate {Date} last modified date
+ * size {Number} size of the file in bytes
+ */
+
+var File = function(name, fullPath, type, lastModifiedDate, size){
+ this.name = name || '';
+ this.fullPath = fullPath || null;
+ this.type = type || null;
+ this.lastModifiedDate = lastModifiedDate || null;
+ this.size = size || 0;
+
+ // These store the absolute start and end for slicing the file.
+ this.start = 0;
+ this.end = this.size;
+};
+
+/**
+ * Returns a "slice" of the file. Since Cordova Files don't contain the actual
+ * content, this really returns a File with adjusted start and end.
+ * Slices of slices are supported.
+ * start {Number} The index at which to start the slice (inclusive).
+ * end {Number} The index at which to end the slice (exclusive).
+ */
+File.prototype.slice = function(start, end) {
+ var size = this.end - this.start;
+ var newStart = 0;
+ var newEnd = size;
+ if (arguments.length) {
+ if (start < 0) {
+ newStart = Math.max(size + start, 0);
+ } else {
+ newStart = Math.min(size, start);
+ }
+ }
+
+ if (arguments.length >= 2) {
+ if (end < 0) {
+ newEnd = Math.max(size + end, 0);
+ } else {
+ newEnd = Math.min(end, size);
+ }
+ }
+
+ var newFile = new File(this.name, this.fullPath, this.type, this.lastModifiedData, this.size);
+ newFile.start = this.start + newStart;
+ newFile.end = this.start + newEnd;
+ return newFile;
+};
+
+
+module.exports = File;
+
+});
+
+// file: lib/common/plugin/FileEntry.js
+define("cordova/plugin/FileEntry", function(require, exports, module) {
+
+var utils = require('cordova/utils'),
+ exec = require('cordova/exec'),
+ Entry = require('cordova/plugin/Entry'),
+ FileWriter = require('cordova/plugin/FileWriter'),
+ File = require('cordova/plugin/File'),
+ FileError = require('cordova/plugin/FileError');
+
+/**
+ * An interface representing a file on the file system.
+ *
+ * {boolean} isFile always true (readonly)
+ * {boolean} isDirectory always false (readonly)
+ * {DOMString} name of the file, excluding the path leading to it (readonly)
+ * {DOMString} fullPath the absolute full path to the file (readonly)
+ * {FileSystem} filesystem on which the file resides (readonly)
+ */
+var FileEntry = function(name, fullPath) {
+ FileEntry.__super__.constructor.apply(this, [true, false, name, fullPath]);
+};
+
+utils.extend(FileEntry, Entry);
+
+/**
+ * Creates a new FileWriter associated with the file that this FileEntry represents.
+ *
+ * @param {Function} successCallback is called with the new FileWriter
+ * @param {Function} errorCallback is called with a FileError
+ */
+FileEntry.prototype.createWriter = function(successCallback, errorCallback) {
+ this.file(function(filePointer) {
+ var writer = new FileWriter(filePointer);
+
+ if (writer.fileName === null || writer.fileName === "") {
+ errorCallback && errorCallback(new FileError(FileError.INVALID_STATE_ERR));
+ } else {
+ successCallback && successCallback(writer);
+ }
+ }, errorCallback);
+};
+
+/**
+ * Returns a File that represents the current state of the file that this FileEntry represents.
+ *
+ * @param {Function} successCallback is called with the new File object
+ * @param {Function} errorCallback is called with a FileError
+ */
+FileEntry.prototype.file = function(successCallback, errorCallback) {
+ var win = successCallback && function(f) {
+ var file = new File(f.name, f.fullPath, f.type, f.lastModifiedDate, f.size);
+ successCallback(file);
+ };
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(win, fail, "File", "getFileMetadata", [this.fullPath]);
+};
+
+
+module.exports = FileEntry;
+
+});
+
+// file: lib/common/plugin/FileError.js
+define("cordova/plugin/FileError", function(require, exports, module) {
+
+/**
+ * FileError
+ */
+function FileError(error) {
+ this.code = error || null;
+}
+
+// File error codes
+// Found in DOMException
+FileError.NOT_FOUND_ERR = 1;
+FileError.SECURITY_ERR = 2;
+FileError.ABORT_ERR = 3;
+
+// Added by File API specification
+FileError.NOT_READABLE_ERR = 4;
+FileError.ENCODING_ERR = 5;
+FileError.NO_MODIFICATION_ALLOWED_ERR = 6;
+FileError.INVALID_STATE_ERR = 7;
+FileError.SYNTAX_ERR = 8;
+FileError.INVALID_MODIFICATION_ERR = 9;
+FileError.QUOTA_EXCEEDED_ERR = 10;
+FileError.TYPE_MISMATCH_ERR = 11;
+FileError.PATH_EXISTS_ERR = 12;
+
+module.exports = FileError;
+
+});
+
+// file: lib/common/plugin/FileReader.js
+define("cordova/plugin/FileReader", function(require, exports, module) {
+
+var exec = require('cordova/exec'),
+ modulemapper = require('cordova/modulemapper'),
+ utils = require('cordova/utils'),
+ File = require('cordova/plugin/File'),
+ FileError = require('cordova/plugin/FileError'),
+ ProgressEvent = require('cordova/plugin/ProgressEvent'),
+ origFileReader = modulemapper.getOriginalSymbol(this, 'FileReader');
+
+/**
+ * This class reads the mobile device file system.
+ *
+ * For Android:
+ * The root directory is the root of the file system.
+ * To read from the SD card, the file name is "sdcard/my_file.txt"
+ * @constructor
+ */
+var FileReader = function() {
+ this._readyState = 0;
+ this._error = null;
+ this._result = null;
+ this._fileName = '';
+ this._realReader = origFileReader ? new origFileReader() : {};
+};
+
+// States
+FileReader.EMPTY = 0;
+FileReader.LOADING = 1;
+FileReader.DONE = 2;
+
+utils.defineGetter(FileReader.prototype, 'readyState', function() {
+ return this._fileName ? this._readyState : this._realReader.readyState;
+});
+
+utils.defineGetter(FileReader.prototype, 'error', function() {
+ return this._fileName ? this._error: this._realReader.error;
+});
+
+utils.defineGetter(FileReader.prototype, 'result', function() {
+ return this._fileName ? this._result: this._realReader.result;
+});
+
+function defineEvent(eventName) {
+ utils.defineGetterSetter(FileReader.prototype, eventName, function() {
+ return this._realReader[eventName] || null;
+ }, function(value) {
+ this._realReader[eventName] = value;
+ });
+}
+defineEvent('onloadstart'); // When the read starts.
+defineEvent('onprogress'); // While reading (and decoding) file or fileBlob data, and reporting partial file data (progress.loaded/progress.total)
+defineEvent('onload'); // When the read has successfully completed.
+defineEvent('onerror'); // When the read has failed (see errors).
+defineEvent('onloadend'); // When the request has completed (either in success or failure).
+defineEvent('onabort'); // When the read has been aborted. For instance, by invoking the abort() method.
+
+function initRead(reader, file) {
+ // Already loading something
+ if (reader.readyState == FileReader.LOADING) {
+ throw new FileError(FileError.INVALID_STATE_ERR);
+ }
+
+ reader._result = null;
+ reader._error = null;
+ reader._readyState = FileReader.LOADING;
+
+ if (typeof file == 'string') {
+ // Deprecated in Cordova 2.4.
+ console.warn('Using a string argument with FileReader.readAs functions is deprecated.');
+ reader._fileName = file;
+ } else if (typeof file.fullPath == 'string') {
+ reader._fileName = file.fullPath;
+ } else {
+ reader._fileName = '';
+ return true;
+ }
+
+ reader.onloadstart && reader.onloadstart(new ProgressEvent("loadstart", {target:reader}));
+}
+
+/**
+ * Abort reading file.
+ */
+FileReader.prototype.abort = function() {
+ if (origFileReader && !this._fileName) {
+ return this._realReader.abort();
+ }
+ this._result = null;
+
+ if (this._readyState == FileReader.DONE || this._readyState == FileReader.EMPTY) {
+ return;
+ }
+
+ this._readyState = FileReader.DONE;
+
+ // If abort callback
+ if (typeof this.onabort === 'function') {
+ this.onabort(new ProgressEvent('abort', {target:this}));
+ }
+ // If load end callback
+ if (typeof this.onloadend === 'function') {
+ this.onloadend(new ProgressEvent('loadend', {target:this}));
+ }
+};
+
+/**
+ * Read text file.
+ *
+ * @param file {File} File object containing file properties
+ * @param encoding [Optional] (see http://www.iana.org/assignments/character-sets)
+ */
+FileReader.prototype.readAsText = function(file, encoding) {
+ if (initRead(this, file)) {
+ return this._realReader.readAsText(file, encoding);
+ }
+
+ // Default encoding is UTF-8
+ var enc = encoding ? encoding : "UTF-8";
+ var me = this;
+ var execArgs = [this._fileName, enc, file.start, file.end];
+
+ // Read file
+ exec(
+ // Success callback
+ function(r) {
+ // If DONE (cancelled), then don't do anything
+ if (me._readyState === FileReader.DONE) {
+ return;
+ }
+
+ // Save result
+ me._result = r;
+
+ // If onload callback
+ if (typeof me.onload === "function") {
+ me.onload(new ProgressEvent("load", {target:me}));
+ }
+
+ // DONE state
+ me._readyState = FileReader.DONE;
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ me.onloadend(new ProgressEvent("loadend", {target:me}));
+ }
+ },
+ // Error callback
+ function(e) {
+ // If DONE (cancelled), then don't do anything
+ if (me._readyState === FileReader.DONE) {
+ return;
+ }
+
+ // DONE state
+ me._readyState = FileReader.DONE;
+
+ // null result
+ me._result = null;
+
+ // Save error
+ me._error = new FileError(e);
+
+ // If onerror callback
+ if (typeof me.onerror === "function") {
+ me.onerror(new ProgressEvent("error", {target:me}));
+ }
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ me.onloadend(new ProgressEvent("loadend", {target:me}));
+ }
+ }, "File", "readAsText", execArgs);
+};
+
+
+/**
+ * Read file and return data as a base64 encoded data url.
+ * A data url is of the form:
+ * data:[<mediatype>][;base64],<data>
+ *
+ * @param file {File} File object containing file properties
+ */
+FileReader.prototype.readAsDataURL = function(file) {
+ if (initRead(this, file)) {
+ return this._realReader.readAsDataURL(file);
+ }
+
+ var me = this;
+ var execArgs = [this._fileName, file.start, file.end];
+
+ // Read file
+ exec(
+ // Success callback
+ function(r) {
+ // If DONE (cancelled), then don't do anything
+ if (me._readyState === FileReader.DONE) {
+ return;
+ }
+
+ // DONE state
+ me._readyState = FileReader.DONE;
+
+ // Save result
+ me._result = r;
+
+ // If onload callback
+ if (typeof me.onload === "function") {
+ me.onload(new ProgressEvent("load", {target:me}));
+ }
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ me.onloadend(new ProgressEvent("loadend", {target:me}));
+ }
+ },
+ // Error callback
+ function(e) {
+ // If DONE (cancelled), then don't do anything
+ if (me._readyState === FileReader.DONE) {
+ return;
+ }
+
+ // DONE state
+ me._readyState = FileReader.DONE;
+
+ me._result = null;
+
+ // Save error
+ me._error = new FileError(e);
+
+ // If onerror callback
+ if (typeof me.onerror === "function") {
+ me.onerror(new ProgressEvent("error", {target:me}));
+ }
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ me.onloadend(new ProgressEvent("loadend", {target:me}));
+ }
+ }, "File", "readAsDataURL", execArgs);
+};
+
+/**
+ * Read file and return data as a binary data.
+ *
+ * @param file {File} File object containing file properties
+ */
+FileReader.prototype.readAsBinaryString = function(file) {
+ if (initRead(this, file)) {
+ return this._realReader.readAsBinaryString(file);
+ }
+
+ var me = this;
+ var execArgs = [this._fileName, file.start, file.end];
+
+ // Read file
+ exec(
+ // Success callback
+ function(r) {
+ // If DONE (cancelled), then don't do anything
+ if (me._readyState === FileReader.DONE) {
+ return;
+ }
+
+ // DONE state
+ me._readyState = FileReader.DONE;
+
+ me._result = r;
+
+ // If onload callback
+ if (typeof me.onload === "function") {
+ me.onload(new ProgressEvent("load", {target:me}));
+ }
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ me.onloadend(new ProgressEvent("loadend", {target:me}));
+ }
+ },
+ // Error callback
+ function(e) {
+ // If DONE (cancelled), then don't do anything
+ if (me._readyState === FileReader.DONE) {
+ return;
+ }
+
+ // DONE state
+ me._readyState = FileReader.DONE;
+
+ me._result = null;
+
+ // Save error
+ me._error = new FileError(e);
+
+ // If onerror callback
+ if (typeof me.onerror === "function") {
+ me.onerror(new ProgressEvent("error", {target:me}));
+ }
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ me.onloadend(new ProgressEvent("loadend", {target:me}));
+ }
+ }, "File", "readAsBinaryString", execArgs);
+};
+
+/**
+ * Read file and return data as a binary data.
+ *
+ * @param file {File} File object containing file properties
+ */
+FileReader.prototype.readAsArrayBuffer = function(file) {
+ if (initRead(this, file)) {
+ return this._realReader.readAsArrayBuffer(file);
+ }
+
+ var me = this;
+ var execArgs = [this._fileName, file.start, file.end];
+
+ // Read file
+ exec(
+ // Success callback
+ function(r) {
+ // If DONE (cancelled), then don't do anything
+ if (me._readyState === FileReader.DONE) {
+ return;
+ }
+
+ // DONE state
+ me._readyState = FileReader.DONE;
+
+ me._result = r;
+
+ // If onload callback
+ if (typeof me.onload === "function") {
+ me.onload(new ProgressEvent("load", {target:me}));
+ }
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ me.onloadend(new Prog
<TRUNCATED>
[30/37] git commit: Add WP7 and WP8 platform files.
Posted by mw...@apache.org.
Add WP7 and WP8 platform files.
Project: http://git-wip-us.apache.org/repos/asf/cordova-cli/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-cli/commit/f59ddbbd
Tree: http://git-wip-us.apache.org/repos/asf/cordova-cli/tree/f59ddbbd
Diff: http://git-wip-us.apache.org/repos/asf/cordova-cli/diff/f59ddbbd
Branch: refs/heads/master
Commit: f59ddbbdebe9d3530685baa1739962238e676c74
Parents: b50b528
Author: Benn Mapes <be...@gmail.com>
Authored: Tue May 14 15:23:30 2013 -0700
Committer: Michael Brooks <mi...@michaelbrooks.ca>
Committed: Wed May 15 10:21:22 2013 -0700
----------------------------------------------------------------------
.gitignore | 2 +
lib/cordova-wp7/LICENSE | 12 +
lib/cordova-wp7/NOTICE | 5 +
lib/cordova-wp7/README.md | 50 +
lib/cordova-wp7/VERSION | 1 +
lib/cordova-wp7/bin/create.js | 252 +
.../framework/Images/appbar.back.rest.png | Bin 0 -> 375 bytes
.../framework/Images/appbar.close.rest.png | Bin 0 -> 359 bytes
.../framework/Images/appbar.feature.video.rest.png | Bin 0 -> 433 bytes
.../framework/Images/appbar.next.rest.png | Bin 0 -> 388 bytes
.../framework/Images/appbar.save.rest.png | Bin 0 -> 297 bytes
.../framework/Images/appbar.stop.rest.png | Bin 0 -> 350 bytes
.../framework/Properties/AssemblyInfo.cs | 37 +
lib/cordova-wp7/framework/WPCordovaClassLib.csproj | 297 +
lib/cordova-wp7/framework/WPCordovaClassLib.sln | 20 +
.../framework/resources/notification-beep.wav | Bin 0 -> 16630 bytes
lib/cordova-wp7/templates/standalone/App.xaml | 37 +
lib/cordova-wp7/templates/standalone/App.xaml.cs | 154 +
.../templates/standalone/ApplicationIcon.png | Bin 0 -> 4951 bytes
.../templates/standalone/Background.png | Bin 0 -> 10259 bytes
.../templates/standalone/BuildManifestProcessor.js | 106 +
.../templates/standalone/CordovaAppProj.csproj | 197 +
.../templates/standalone/CordovaSolution.sln | 22 +
.../standalone/CordovaSourceDictionary.xml | 9 +
.../standalone/Images/appbar.back.rest.png | Bin 0 -> 375 bytes
.../standalone/Images/appbar.close.rest.png | Bin 0 -> 359 bytes
.../Images/appbar.feature.video.rest.png | Bin 0 -> 433 bytes
.../standalone/Images/appbar.next.rest.png | Bin 0 -> 388 bytes
.../standalone/Images/appbar.save.rest.png | Bin 0 -> 297 bytes
.../standalone/Images/appbar.stop.rest.png | Bin 0 -> 350 bytes
lib/cordova-wp7/templates/standalone/MainPage.xaml | 35 +
.../templates/standalone/MainPage.xaml.cs | 72 +
.../templates/standalone/Plugins/Accelerometer.cs | 196 +
.../standalone/Plugins/AudioFormatsHelper.cs | 89 +
.../templates/standalone/Plugins/AudioPlayer.cs | 620 ++
.../templates/standalone/Plugins/Battery.cs | 79 +
.../templates/standalone/Plugins/Camera.cs | 490 ++
.../templates/standalone/Plugins/Capture.cs | 736 ++
.../templates/standalone/Plugins/Compass.cs | 362 +
.../templates/standalone/Plugins/Contacts.cs | 664 ++
.../templates/standalone/Plugins/DebugConsole.cs | 49 +
.../templates/standalone/Plugins/Device.cs | 135 +
.../templates/standalone/Plugins/File.cs | 1676 ++++
.../templates/standalone/Plugins/FileTransfer.cs | 526 ++
.../templates/standalone/Plugins/GeoLocation.cs | 34 +
.../templates/standalone/Plugins/Globalization.cs | 1178 +++
.../standalone/Plugins/ImageExifHelper.cs | 209 +
.../templates/standalone/Plugins/InAppBrowser.cs | 268 +
.../templates/standalone/Plugins/Media.cs | 532 ++
.../templates/standalone/Plugins/MimeTypeMapper.cs | 99 +
.../templates/standalone/Plugins/NetworkStatus.cs | 129 +
.../templates/standalone/Plugins/Notification.cs | 367 +
.../standalone/Plugins/UI/AudioCaptureTask.cs | 107 +
.../standalone/Plugins/UI/AudioRecorder.xaml | 66 +
.../standalone/Plugins/UI/AudioRecorder.xaml.cs | 306 +
.../standalone/Plugins/UI/ImageCapture.xaml | 26 +
.../standalone/Plugins/UI/ImageCapture.xaml.cs | 109 +
.../standalone/Plugins/UI/NotificationBox.xaml | 62 +
.../standalone/Plugins/UI/NotificationBox.xaml.cs | 41 +
.../standalone/Plugins/UI/VideoCaptureTask.cs | 105 +
.../standalone/Plugins/UI/VideoRecorder.xaml | 52 +
.../standalone/Plugins/UI/VideoRecorder.xaml.cs | 405 +
.../standalone/Properties/AppManifest.xml | 6 +
.../standalone/Properties/AssemblyInfo.cs | 38 +
.../standalone/Properties/WMAppManifest.xml | 41 +
lib/cordova-wp7/templates/standalone/README.md | 13 +
.../templates/standalone/SplashScreenImage.jpg | Bin 0 -> 33248 bytes
lib/cordova-wp7/templates/standalone/VERSION | 1 +
lib/cordova-wp7/templates/standalone/config.xml | 49 +
.../templates/standalone/cordova/build.bat | 9 +
.../templates/standalone/cordova/clean.bat | 9 +
.../cordova/lib/CordovaDeploy/CordovaDeploy.sln | 20 +
.../CordovaDeploy/CordovaDeploy.csproj | 79 +
.../lib/CordovaDeploy/CordovaDeploy/Program.cs | 235 +
.../CordovaDeploy/Properties/AssemblyInfo.cs | 36 +
.../templates/standalone/cordova/lib/build.js | 181 +
.../templates/standalone/cordova/lib/clean.js | 124 +
.../templates/standalone/cordova/lib/deploy.js | 326 +
.../standalone/cordova/lib/install-device.bat | 9 +
.../standalone/cordova/lib/install-emulator.bat | 9 +
.../standalone/cordova/lib/list-devices.bat | 9 +
.../cordova/lib/list-emulator-images.bat | 9 +
.../cordova/lib/list-started-emulators.bat | 3 +
.../templates/standalone/cordova/lib/log.js | 77 +
.../standalone/cordova/lib/start-emulator.bat | 3 +
.../standalone/cordova/lib/target-list.js | 233 +
.../templates/standalone/cordova/log.bat | 3 +
.../templates/standalone/cordova/run.bat | 9 +
.../standalone/cordovalib/BrowserMouseHelper.cs | 345 +
.../standalone/cordovalib/CommandFactory.cs | 112 +
.../standalone/cordovalib/Commands/BaseCommand.cs | 187 +
.../standalone/cordovalib/ConfigHandler.cs | 249 +
.../standalone/cordovalib/CordovaCommandCall.cs | 98 +
.../standalone/cordovalib/CordovaView.xaml | 65 +
.../standalone/cordovalib/CordovaView.xaml.cs | 485 ++
.../standalone/cordovalib/DOMStorageHelper.cs | 145 +
.../standalone/cordovalib/JSON/JsonHelper.cs | 97 +
.../standalone/cordovalib/NativeExecution.cs | 246 +
.../standalone/cordovalib/OrientationHelper.cs | 128 +
.../standalone/cordovalib/PluginResult.cs | 139 +
.../standalone/cordovalib/ScriptCallback.cs | 80 +
.../cordovalib/resources/notification-beep.wav | Bin 0 -> 16630 bytes
.../standalone/resources/notification-beep.wav | Bin 0 -> 16630 bytes
.../templates/standalone/www/cordova-2.7.0.js | 6700 +++++++++++++++
.../templates/standalone/www/css/index.css | 115 +
.../templates/standalone/www/img/logo.png | Bin 0 -> 21814 bytes
.../templates/standalone/www/index.html | 42 +
.../templates/standalone/www/js/index.js | 49 +
.../templates/vs/MyTemplateStandAlone.vstemplate | 115 +
lib/cordova-wp7/templates/vs/description.txt | 4 +
lib/cordova-wp7/templates/vs/pg_templateIcon.png | Bin 0 -> 6546 bytes
.../templates/vs/pg_templatePreview.jpg | Bin 0 -> 25875 bytes
lib/cordova-wp7/tests/README.md | 7 +
lib/cordova-wp7/tooling/scripts/buildjs.bat | 2 +
lib/cordova-wp7/tooling/scripts/buildjs.js | 209 +
lib/cordova-wp7/tooling/scripts/dist.bat | 2 +
lib/cordova-wp7/tooling/scripts/dist.js | 217 +
lib/cordova-wp7/tooling/scripts/new.bat | 2 +
lib/cordova-wp7/tooling/scripts/new.js | 151 +
lib/cordova-wp7/tooling/scripts/package.bat | 2 +
lib/cordova-wp7/tooling/scripts/package.js | 213 +
lib/cordova-wp7/tooling/scripts/reversion.bat | 2 +
lib/cordova-wp7/tooling/scripts/reversion.js | 277 +
lib/cordova-wp7/tooling/scripts/win-zip.js | 32 +
lib/cordova-wp8/LICENSE | 12 +
lib/cordova-wp8/NOTICE | 5 +
lib/cordova-wp8/README.md | 42 +
lib/cordova-wp8/VERSION | 1 +
.../framework/Images/appbar.back.rest.png | Bin 0 -> 375 bytes
.../framework/Images/appbar.close.rest.png | Bin 0 -> 359 bytes
.../framework/Images/appbar.feature.video.rest.png | Bin 0 -> 433 bytes
.../framework/Images/appbar.next.rest.png | Bin 0 -> 388 bytes
.../framework/Images/appbar.save.rest.png | Bin 0 -> 297 bytes
.../framework/Images/appbar.stop.rest.png | Bin 0 -> 350 bytes
.../framework/Properties/AssemblyInfo.cs | 35 +
lib/cordova-wp8/framework/WPCordovaClassLib.csproj | 313 +
lib/cordova-wp8/framework/WPCordovaClassLib.sln | 32 +
.../framework/resources/notification-beep.wav | Bin 0 -> 16630 bytes
lib/cordova-wp8/templates/standalone/App.xaml | 37 +
lib/cordova-wp8/templates/standalone/App.xaml.cs | 154 +
.../templates/standalone/ApplicationIcon.png | Bin 0 -> 4951 bytes
.../templates/standalone/Background.png | Bin 0 -> 10259 bytes
.../templates/standalone/CordovaAppProj.csproj | 228 +
.../templates/standalone/CordovaSolution.sln | 30 +
.../standalone/Images/appbar.back.rest.png | Bin 0 -> 375 bytes
.../standalone/Images/appbar.close.rest.png | Bin 0 -> 359 bytes
.../Images/appbar.feature.video.rest.png | Bin 0 -> 433 bytes
.../standalone/Images/appbar.next.rest.png | Bin 0 -> 388 bytes
.../standalone/Images/appbar.save.rest.png | Bin 0 -> 297 bytes
.../standalone/Images/appbar.stop.rest.png | Bin 0 -> 350 bytes
lib/cordova-wp8/templates/standalone/MainPage.xaml | 53 +
.../templates/standalone/MainPage.xaml.cs | 72 +
.../templates/standalone/Plugins/Accelerometer.cs | 196 +
.../standalone/Plugins/AudioFormatsHelper.cs | 89 +
.../templates/standalone/Plugins/AudioPlayer.cs | 620 ++
.../templates/standalone/Plugins/Battery.cs | 79 +
.../templates/standalone/Plugins/Camera.cs | 490 ++
.../templates/standalone/Plugins/Capture.cs | 736 ++
.../templates/standalone/Plugins/Compass.cs | 362 +
.../templates/standalone/Plugins/Contacts.cs | 664 ++
.../templates/standalone/Plugins/DebugConsole.cs | 49 +
.../templates/standalone/Plugins/Device.cs | 135 +
.../templates/standalone/Plugins/File.cs | 1676 ++++
.../templates/standalone/Plugins/FileTransfer.cs | 526 ++
.../templates/standalone/Plugins/GeoLocation.cs | 34 +
.../templates/standalone/Plugins/Globalization.cs | 1177 +++
.../standalone/Plugins/ImageExifHelper.cs | 209 +
.../templates/standalone/Plugins/InAppBrowser.cs | 271 +
.../templates/standalone/Plugins/Media.cs | 547 ++
.../templates/standalone/Plugins/MimeTypeMapper.cs | 101 +
.../templates/standalone/Plugins/NetworkStatus.cs | 129 +
.../templates/standalone/Plugins/Notification.cs | 361 +
.../standalone/Plugins/UI/AudioCaptureTask.cs | 107 +
.../standalone/Plugins/UI/AudioRecorder.xaml | 66 +
.../standalone/Plugins/UI/AudioRecorder.xaml.cs | 307 +
.../standalone/Plugins/UI/ImageCapture.xaml | 26 +
.../standalone/Plugins/UI/ImageCapture.xaml.cs | 109 +
.../standalone/Plugins/UI/NotificationBox.xaml | 62 +
.../standalone/Plugins/UI/NotificationBox.xaml.cs | 41 +
.../standalone/Plugins/UI/VideoCaptureTask.cs | 105 +
.../standalone/Plugins/UI/VideoRecorder.xaml | 52 +
.../standalone/Plugins/UI/VideoRecorder.xaml.cs | 405 +
.../standalone/Properties/AppManifest.xml | 6 +
.../standalone/Properties/AssemblyInfo.cs | 39 +
.../standalone/Properties/WMAppManifest.xml | 53 +
.../templates/standalone/SplashScreenImage.jpg | Bin 0 -> 33248 bytes
lib/cordova-wp8/templates/standalone/VERSION | 1 +
lib/cordova-wp8/templates/standalone/config.xml | 49 +
.../templates/standalone/cordova/build.bat | 9 +
.../templates/standalone/cordova/clean.bat | 9 +
.../cordova/lib/CordovaDeploy/CordovaDeploy.sln | 20 +
.../CordovaDeploy/CordovaDeploy.csproj | 96 +
.../lib/CordovaDeploy/CordovaDeploy/Program.cs | 424 +
.../CordovaDeploy/Properties/AssemblyInfo.cs | 36 +
.../lib/CordovaDeploy/CordovaDeploy/app.config | 3 +
.../templates/standalone/cordova/lib/build.js | 181 +
.../templates/standalone/cordova/lib/clean.js | 124 +
.../templates/standalone/cordova/lib/deploy.js | 326 +
.../standalone/cordova/lib/install-device.bat | 9 +
.../standalone/cordova/lib/install-emulator.bat | 9 +
.../standalone/cordova/lib/list-devices.bat | 9 +
.../cordova/lib/list-emulator-images.bat | 9 +
.../cordova/lib/list-started-emulators.bat | 3 +
.../templates/standalone/cordova/lib/log.js | 77 +
.../standalone/cordova/lib/start-emulator.bat | 3 +
.../standalone/cordova/lib/target-list.js | 233 +
.../templates/standalone/cordova/log.bat | 3 +
.../templates/standalone/cordova/run.bat | 9 +
.../standalone/cordovalib/BrowserMouseHelper.cs | 162 +
.../standalone/cordovalib/CommandFactory.cs | 112 +
.../standalone/cordovalib/Commands/BaseCommand.cs | 187 +
.../standalone/cordovalib/ConfigHandler.cs | 242 +
.../standalone/cordovalib/CordovaCommandCall.cs | 99 +
.../standalone/cordovalib/CordovaView.xaml | 65 +
.../standalone/cordovalib/CordovaView.xaml.cs | 503 ++
.../standalone/cordovalib/DOMStorageHelper.cs | 145 +
.../standalone/cordovalib/JSON/JsonHelper.cs | 97 +
.../standalone/cordovalib/NativeExecution.cs | 246 +
.../standalone/cordovalib/OrientationHelper.cs | 128 +
.../standalone/cordovalib/PluginResult.cs | 139 +
.../standalone/cordovalib/ScriptCallback.cs | 80 +
.../cordovalib/resources/notification-beep.wav | Bin 0 -> 16630 bytes
.../standalone/resources/notification-beep.wav | Bin 0 -> 16630 bytes
.../templates/standalone/www/cordova-2.7.0.js | 6700 +++++++++++++++
.../templates/standalone/www/css/index.css | 115 +
.../templates/standalone/www/img/logo.png | Bin 0 -> 21814 bytes
.../templates/standalone/www/index.html | 42 +
.../templates/standalone/www/js/index.js | 49 +
.../templates/vs/MyTemplateStandAlone.vstemplate | 113 +
lib/cordova-wp8/templates/vs/description.txt | 8 +
lib/cordova-wp8/templates/vs/pg_templateIcon.png | Bin 0 -> 6546 bytes
.../templates/vs/pg_templatePreview.jpg | Bin 0 -> 25875 bytes
lib/cordova-wp8/tests/MobileSpecUnitTests/App.xaml | 38 +
.../tests/MobileSpecUnitTests/App.xaml.cs | 158 +
.../tests/MobileSpecUnitTests/ApplicationIcon.png | Bin 0 -> 4951 bytes
.../tests/MobileSpecUnitTests/Background.png | Bin 0 -> 10259 bytes
.../tests/MobileSpecUnitTests/MainPage.xaml | 52 +
.../tests/MobileSpecUnitTests/MainPage.xaml.cs | 42 +
.../MobileSpecUnitTests/MobileSpecUnitTests.csproj | 247 +
.../MobileSpecUnitTests/MobileSpecUnitTests.sln | 44 +
.../MobileSpecUnitTests/Properties/AppManifest.xml | 6 +
.../MobileSpecUnitTests/Properties/AssemblyInfo.cs | 35 +
.../Properties/WMAppManifest.xml | 51 +
.../MobileSpecUnitTests/SplashScreenImage.jpg | Bin 0 -> 22066 bytes
.../www/accelerometer/index.html | 138 +
.../tests/MobileSpecUnitTests/www/audio/index.html | 394 +
.../www/autotest/html/HtmlReporter.js | 101 +
.../www/autotest/html/HtmlReporterHelpers.js | 60 +
.../www/autotest/html/ReporterView.js | 164 +
.../www/autotest/html/SpecView.js | 79 +
.../www/autotest/html/SuiteView.js | 22 +
.../www/autotest/html/TrivialReporter.js | 192 +
.../MobileSpecUnitTests/www/autotest/index.html | 37 +
.../MobileSpecUnitTests/www/autotest/jasmine.css | 81 +
.../MobileSpecUnitTests/www/autotest/jasmine.js | 2530 ++++++
.../www/autotest/pages/accelerometer.html | 48 +
.../www/autotest/pages/all.html | 85 +
.../www/autotest/pages/battery.html | 44 +
.../www/autotest/pages/bridge.html | 71 +
.../www/autotest/pages/camera.html | 49 +
.../www/autotest/pages/capture.html | 49 +
.../www/autotest/pages/compass.html | 49 +
.../www/autotest/pages/contacts.html | 49 +
.../www/autotest/pages/datauri.html | 69 +
.../www/autotest/pages/device.html | 49 +
.../www/autotest/pages/file.html | 68 +
.../www/autotest/pages/filetransfer.html | 69 +
.../www/autotest/pages/geolocation.html | 49 +
.../www/autotest/pages/globalization.html | 70 +
.../www/autotest/pages/media.html | 49 +
.../www/autotest/pages/network.html | 49 +
.../www/autotest/pages/notification.html | 49 +
.../www/autotest/pages/platform.html | 49 +
.../www/autotest/pages/storage.html | 49 +
.../www/autotest/test-runner.js | 41 +
.../www/autotest/tests/accelerometer.tests.js | 193 +
.../www/autotest/tests/battery.tests.js | 5 +
.../www/autotest/tests/bridge.tests.js | 128 +
.../www/autotest/tests/camera.tests.js | 47 +
.../www/autotest/tests/capture.tests.js | 95 +
.../www/autotest/tests/compass.tests.js | 76 +
.../www/autotest/tests/contacts.tests.js | 451 +
.../www/autotest/tests/datauri.tests.js | 36 +
.../www/autotest/tests/device.tests.js | 34 +
.../www/autotest/tests/file.tests.js | 3462 ++++++++
.../www/autotest/tests/filetransfer.tests.js | 513 ++
.../www/autotest/tests/geolocation.tests.js | 119 +
.../www/autotest/tests/globalization.tests.js | 808 ++
.../www/autotest/tests/media.tests.js | 144 +
.../www/autotest/tests/network.tests.js | 25 +
.../www/autotest/tests/notification.tests.js | 20 +
.../www/autotest/tests/platform.tests.js | 10 +
.../www/autotest/tests/storage.tests.js | 174 +
.../MobileSpecUnitTests/www/battery/index.html | 96 +
.../MobileSpecUnitTests/www/camera/index.html | 96 +
.../MobileSpecUnitTests/www/compass/index.html | 128 +
.../MobileSpecUnitTests/www/contacts/index.html | 112 +
.../tests/MobileSpecUnitTests/www/cordova-2.5.0.js | 6446 ++++++++++++++
.../tests/MobileSpecUnitTests/www/cordova.js | 14 +
.../MobileSpecUnitTests/www/events/index.html | 88 +
.../tests/MobileSpecUnitTests/www/index.html | 38 +
.../MobileSpecUnitTests/www/location/index.html | 147 +
.../tests/MobileSpecUnitTests/www/main.js | 140 +
.../tests/MobileSpecUnitTests/www/master.css | 136 +
.../tests/MobileSpecUnitTests/www/misc/index.html | 59 +
.../tests/MobileSpecUnitTests/www/misc/page2.html | 25 +
.../MobileSpecUnitTests/www/network/index.html | 59 +
.../www/notification/index.html | 81 +
.../tests/MobileSpecUnitTests/www/sql/index.html | 132 +
.../MobileSpecUnitTests/www/storage/index.html | 50 +
lib/cordova-wp8/tests/README.md | 7 +
lib/cordova-wp8/tooling/scripts/buildjs.bat | 2 +
lib/cordova-wp8/tooling/scripts/buildjs.js | 214 +
lib/cordova-wp8/tooling/scripts/dist.bat | 2 +
lib/cordova-wp8/tooling/scripts/dist.js | 202 +
lib/cordova-wp8/tooling/scripts/new.bat | 2 +
lib/cordova-wp8/tooling/scripts/new.js | 151 +
lib/cordova-wp8/tooling/scripts/package.bat | 2 +
lib/cordova-wp8/tooling/scripts/package.js | 213 +
lib/cordova-wp8/tooling/scripts/reversion.bat | 2 +
lib/cordova-wp8/tooling/scripts/reversion.js | 280 +
lib/cordova-wp8/tooling/scripts/win-zip.js | 43 +
322 files changed, 65672 insertions(+), 0 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index 6a593f6..07b36d5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,8 @@ spec/fixtures/projects/cordova
lib/cordova-android/framework/bin
lib/cordova-android/framework/gen
lib/cordova-android/framework/local.properties
+lib/cordova-wp7/example
+lib/cordova-wp8/example
.idea/*
spec/fixtures/*
.gitcore
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/LICENSE
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/LICENSE b/lib/cordova-wp7/LICENSE
new file mode 100644
index 0000000..6a504ba
--- /dev/null
+++ b/lib/cordova-wp7/LICENSE
@@ -0,0 +1,12 @@
+
+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.
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/NOTICE
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/NOTICE b/lib/cordova-wp7/NOTICE
new file mode 100644
index 0000000..c38e7d7
--- /dev/null
+++ b/lib/cordova-wp7/NOTICE
@@ -0,0 +1,5 @@
+Apache Cordova
+Copyright 2012 The Apache Software Foundation
+
+This product includes software developed by
+The Apache Software Foundation (http://www.apache.org)
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/README.md
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/README.md b/lib/cordova-wp7/README.md
new file mode 100644
index 0000000..0235986
--- /dev/null
+++ b/lib/cordova-wp7/README.md
@@ -0,0 +1,50 @@
+Apache Cordova for Windows Phone 7
+===
+
+Apache Cordova WP7 is a .net application library that lets you create Apache Cordova applications targeting Windows Phone 7 devices.
+Apache Cordova based applications are, at the core, an application written with web technology: HTML, CSS and JavaScript.
+
+Requires
+---
+
+- Windows Phone SDK 7.1 [http://create.msdn.com/en-us/home/getting_started]
+
+
+Getting Started
+---
+
+- copy the file templates/CordovaStarter-x.x.x.zip to the folder : \My Documents\Visual Studio 2010\Templates\ProjectTemplates\
+ - if you have just installed VisualStudio, you should launch it once to create this folder
+ - if you prefer, you may add the project instead to the "Silverlight for Windows Phone" subfolder of "Visual C#". This is up to you, and only affects where the project template is shown when creating a new project. Also, You may need to create this folder.
+- Launch Visual Studio 2010 and select to create a new project
+ - CordovaStarter should be listed as an option, give your new project a name
+ - Note: The description will let you know the version of Cordova you are targeting, if you have multiple templates.
+ - If you do not see it, you may have to select the top level 'Visual C#' to see it
+- Build and Run it!
+
+Important!!!
+---
+
+When you add or remove files/folders in the www folder you will need to do the following :
+
+- ensure the new item is included in the project ( Content ) This includes ALL images/css/html/js/* and anything that you want available at runtime.
+- Do not modify the CordovaSourceDictionary.xml file which is included in the project, it is auto-generated for you when you build.
+
+Known Problem Areas
+---
+
+Many of the Media APIs will not function as expected when debugging while connect to the device with the Zune software.
+To get around this, you need to use the Windows Phone Connect tool. For details, please check out this [MSDN blog article](http://blogs.msdn.com/b/jaimer/archive/2010/11/03/tips-for-debugging-wp7-media-apps-with-wpconnect.aspx).
+
+
+BUGS?
+-----
+File them at Apache Incubator
+https://issues.apache.org/jira/browse/CB
+
+
+Further Reading
+---
+
+- [http://docs.cordova.io](http://docs.cordova.io)
+- [http://wiki.cordova.io](http://wiki.cordova.io)
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/VERSION
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/VERSION b/lib/cordova-wp7/VERSION
new file mode 100644
index 0000000..9aa3464
--- /dev/null
+++ b/lib/cordova-wp7/VERSION
@@ -0,0 +1 @@
+2.7.0
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/bin/create.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/bin/create.js b/lib/cordova-wp7/bin/create.js
new file mode 100644
index 0000000..dac48de
--- /dev/null
+++ b/lib/cordova-wp7/bin/create.js
@@ -0,0 +1,252 @@
+/*
+ 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.
+*/
+
+/*
+ * create a cordova/wp7 project
+ *
+ * USAGE
+ * ./create [path package activity]
+
+ ./bin/create.bat C:\Users\Me\MyTestProj "test.proj" "TestProject"
+ */
+
+
+var fso=WScript.CreateObject("Scripting.FileSystemObject");
+var wscript_shell = WScript.CreateObject("WScript.Shell");
+// working dir
+var ROOT = WScript.ScriptFullName.split('\\bin\\create.js').join('');
+
+var args = WScript.Arguments,
+ FRAMEWORK_PATH = '\\framework',
+ TOOLING_PATH = '\\tooling',
+ TEMPLATES_PATH = '\\templates',
+ // sub folder for standalone project
+ STANDALONE_PATH = TEMPLATES_PATH + '\\standalone',
+ // default template to use when creating the project
+ CREATE_TEMPLATE = STANDALONE_PATH,
+ USE_DLL = false,
+ PROJECT_PATH,
+ PACKAGE,
+ NAME;
+
+ // get version number
+var VERSION=read(ROOT+'\\VERSION').replace(/\r\n/,'').replace(/\n/,'');
+var BASE_VERSION = VERSION.split('rc', 1) + ".0";
+
+function Usage() {
+ Log("Usage: create PathTONewProject [ PackageName AppName ]");
+ Log(" PathTONewProject : The path to where you wish to create the project");
+ Log(" PackageName : The namespace for the project (default is Cordova.Example)")
+ Log(" AppName : The name of the application (default is CordovaAppProj)");
+ Log("examples:");
+ Log(" create C:\\Users\\anonymous\\Desktop\\MyProject");
+ Log(" create C:\\Users\\anonymous\\Desktop\\MyProject io.Cordova.Example AnApp");
+}
+
+// logs messaged to stdout and stderr
+function Log(msg, error) {
+ if (error) {
+ WScript.StdErr.WriteLine(msg);
+ }
+ else {
+ WScript.StdOut.WriteLine(msg);
+ }
+}
+
+var ForReading = 1, ForWriting = 2, ForAppending = 8;
+var TristateUseDefault = -2, TristateTrue = -1, TristateFalse = 0;
+
+function read(filename) {
+ var f=fso.OpenTextFile(filename, 1,2);
+ var s=f.ReadAll();
+ f.Close();
+ return s;
+}
+
+function write(filename, contents) {
+ var f=fso.OpenTextFile(filename, ForWriting, TristateTrue);
+ f.Write(contents);
+ f.Close();
+}
+
+function replaceInFile(filename, regexp, replacement) {
+ write(filename,read(filename).replace(regexp,replacement));
+}
+
+
+// executes a commmand in the shell
+function exec(command) {
+ var oShell=wscript_shell.Exec(command);
+ while (oShell.Status == 0) {
+ WScript.sleep(100);
+ }
+}
+
+// executes a commmand in the shell
+function exec_verbose(command) {
+ //Log("Command: " + command);
+ var oShell=wscript_shell.Exec(command);
+ while (oShell.Status == 0) {
+ //Wait a little bit so we're not super looping
+ WScript.sleep(100);
+ //Print any stdout output from the script
+ if (!oShell.StdOut.AtEndOfStream) {
+ var line = oShell.StdOut.ReadLine();
+ Log(line);
+ }
+ }
+ //Check to make sure our scripts did not encounter an error
+ if (!oShell.StdErr.AtEndOfStream) {
+ var line = oShell.StdErr.ReadAll();
+ Log(line, true);
+ WScript.Quit(1);
+ }
+}
+
+//generate guid for the project
+function genGuid() {
+ var TypeLib = WScript.CreateObject("Scriptlet.TypeLib");
+ strGuid = TypeLib.Guid.split("}")[0]; // there is extra crap after the } that is causing file streams to break, probably an EOF ...
+ strGuid = strGuid.replace(/[\{\}]/g,"");
+ return strGuid;
+}
+
+// builds the new cordova dll from the framework
+function build_dll(path) {
+ if (fso.FolderExists(path + FRAMEWORK_PATH + '\\Bin')) {
+ fso.DeleteFolder(path + FRAMEWORK_PATH + '\\Bin');
+ }
+ if (fso.FolderExists(path + FRAMEWORK_PATH + '\\obj')) {
+ fso.DeleteFolder(path + FRAMEWORK_PATH + '\\obj');
+ }
+ // move to framework directory
+ wscript_shell.CurrentDirectory = path + FRAMEWORK_PATH;
+ // build .dll in Release
+ exec_verbose('msbuild /clp:NoSummary;NoItemAndPropertyList;Verbosity=minimal /nologo /p:Configuration=Release;VersionNumber=' + VERSION + ';BaseVersionNumber=' + BASE_VERSION);
+ //Check if file dll was created
+ if (!fso.FileExists(path + FRAMEWORK_PATH + '\\Bin\\Release\\WPCordovaClassLib.dll')) {
+ Log('ERROR: MSBuild failed to create .dll when building WPCordovaClassLib.dll', true);
+ WScript.Quit(1);
+ }
+ Log("SUCCESS BUILDING DLL");
+}
+
+// creates new project in path, with the given package and app name
+function create(path, namespace, name) {
+ Log("Creating Cordova-WP7 Project:");
+ Log("\tApp Name : " + name);
+ Log("\tNamespace : " + namespace);
+ Log("\tPath : " + path);
+
+ // Copy the template source files to the new destination
+ fso.CopyFolder(ROOT + CREATE_TEMPLATE, path);
+
+ var newProjGuid = genGuid();
+ // replace the guid in the AppManifest
+ replaceInFile(path + "\\Properties\\WMAppManifest.xml","$guid1$",newProjGuid);
+ // replace safe-project-name in AppManifest
+ replaceInFile(path + "\\Properties\\WMAppManifest.xml",/\$safeprojectname\$/g,name);
+ replaceInFile(path + "\\Properties\\WMAppManifest.xml",/\$projectname\$/g,name);
+
+
+ replaceInFile(path + "\\App.xaml",/\$safeprojectname\$/g,namespace);
+ replaceInFile(path + "\\App.xaml.cs",/\$safeprojectname\$/g,namespace);
+
+ replaceInFile(path + "\\MainPage.xaml",/\$safeprojectname\$/g,namespace);
+ replaceInFile(path + "\\MainPage.xaml.cs",/\$safeprojectname\$/g,namespace);
+ replaceInFile(path + "\\CordovaAppProj.csproj",/\$safeprojectname\$/g,namespace);
+ if (NAME != "CordovaAppProj") {
+ var valid_name = NAME.replace(/(\.\s|\s\.|\s+|\.+)/g, '_');
+ replaceInFile(path + "\\CordovaSolution.sln", /CordovaAppProj/g, valid_name);
+ // rename project and solution
+ exec('%comspec% /c ren ' + path + "\\CordovaSolution.sln " + valid_name + '.sln');
+ exec('%comspec% /c ren ' + path + "\\CordovaAppProj.csproj " + valid_name + '.csproj');
+ }
+
+ //copy .dll if necessary
+ if (USE_DLL) {
+ var dllPath = ROOT + FRAMEWORK_PATH + '\\Bin\\Release\\WPCordovaClassLib.dll';
+ if (fso.FileExists(dllPath)) {
+ Log("WPCordovaClassLib.dll Found, creating project");
+ }
+ else {
+ Log("WPCordovaClassLib.dll was not Found in " + dllPath);
+ Log('BUILDING: WPCordovaClassLib.dll');
+ build_dll(ROOT);
+ }
+
+ if (!fso.FolderExists(path + '\\CordovaLib')) {
+ fso.CreateFolder(path + '\\CordovaLib');
+ }
+ exec('%comspec% /c xcopy ' + ROOT + FRAMEWORK_PATH + '\\Bin\\Release\\WPCordovaClassLib.dll ' + path + '\\CordovaLib');
+ if (!fso.FileExists(path + '\\CordovaLib\\WPCordovaClassLib.dll')) {
+ Log('ERROR: Failed to copy WPCordovaClassLib.dll to project from', true);
+ Log('\t' + ROOT + FRAMEWORK_PATH + '\\Bin\\Release\\WPCordovaClassLib.dll', true);
+ Log('\tto', true);
+ Log('\t' + path + '\\CordovaLib', true)
+ WScript.Quit(1);
+ }
+ }
+
+ Log("CREATE SUCCESS : " + path);
+
+ // TODO: Name the project according to the arguments
+ // update the solution to include the new project by name
+ // version BS
+ // index.html title set to project name ?
+
+}
+
+if (args.Count() > 0) {
+ // support help flags
+ if (args(0) == "--help" || args(0) == "/?" ||
+ args(0) == "help" || args(0) == "-help" || args(0) == "/help" || args(0) == "-h") {
+ Usage();
+ WScript.Quit(1);
+ }
+
+ PROJECT_PATH = args(0);
+ if (fso.FolderExists(PROJECT_PATH)) {
+ Log("Project directory already exists:", true);
+ Log("\t" + PROJECT_PATH, true);
+ Log("CREATE FAILED.", true);
+ WScript.Quit(1);
+ }
+
+ if (args.Count() > 1) {
+ PACKAGE = args(1);
+ }
+ else {
+ PACKAGE = "Cordova.Example";
+ }
+
+ if (args.Count() > 2) {
+ NAME = args(2);
+ }
+ else {
+ NAME = "CordovaAppProj";
+ }
+
+ create(PROJECT_PATH, PACKAGE, NAME);
+}
+else {
+ Usage();
+ WScript.Quit(1);
+}
+
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/framework/Images/appbar.back.rest.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/framework/Images/appbar.back.rest.png b/lib/cordova-wp7/framework/Images/appbar.back.rest.png
new file mode 100644
index 0000000..4bc2b92
Binary files /dev/null and b/lib/cordova-wp7/framework/Images/appbar.back.rest.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/framework/Images/appbar.close.rest.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/framework/Images/appbar.close.rest.png b/lib/cordova-wp7/framework/Images/appbar.close.rest.png
new file mode 100644
index 0000000..8166a1c
Binary files /dev/null and b/lib/cordova-wp7/framework/Images/appbar.close.rest.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/framework/Images/appbar.feature.video.rest.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/framework/Images/appbar.feature.video.rest.png b/lib/cordova-wp7/framework/Images/appbar.feature.video.rest.png
new file mode 100644
index 0000000..baff565
Binary files /dev/null and b/lib/cordova-wp7/framework/Images/appbar.feature.video.rest.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/framework/Images/appbar.next.rest.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/framework/Images/appbar.next.rest.png b/lib/cordova-wp7/framework/Images/appbar.next.rest.png
new file mode 100644
index 0000000..ed577d7
Binary files /dev/null and b/lib/cordova-wp7/framework/Images/appbar.next.rest.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/framework/Images/appbar.save.rest.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/framework/Images/appbar.save.rest.png b/lib/cordova-wp7/framework/Images/appbar.save.rest.png
new file mode 100644
index 0000000..d49940e
Binary files /dev/null and b/lib/cordova-wp7/framework/Images/appbar.save.rest.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/framework/Images/appbar.stop.rest.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/framework/Images/appbar.stop.rest.png b/lib/cordova-wp7/framework/Images/appbar.stop.rest.png
new file mode 100644
index 0000000..4dd724f
Binary files /dev/null and b/lib/cordova-wp7/framework/Images/appbar.stop.rest.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/framework/Properties/AssemblyInfo.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/framework/Properties/AssemblyInfo.cs b/lib/cordova-wp7/framework/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..62c7964
--- /dev/null
+++ b/lib/cordova-wp7/framework/Properties/AssemblyInfo.cs
@@ -0,0 +1,37 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("WPCordovaClassLib")]
+[assembly: AssemblyDescription("2.7.0")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Cordova")]
+[assembly: AssemblyProduct("WPCordovaClassLib")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("633ee7ad-9a75-4b68-96e9-281528c50275")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+
+[assembly: AssemblyVersion("2.7.0.0")]
+[assembly: AssemblyFileVersion("2.6.0rc1")]
+
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/framework/WPCordovaClassLib.csproj
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/framework/WPCordovaClassLib.csproj b/lib/cordova-wp7/framework/WPCordovaClassLib.csproj
new file mode 100644
index 0000000..1292286
--- /dev/null
+++ b/lib/cordova-wp7/framework/WPCordovaClassLib.csproj
@@ -0,0 +1,297 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>10.0.20506</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{FC6A1A70-892D-46AD-9E4A-9793F72AF780}</ProjectGuid>
+ <ProjectTypeGuids>{C089C8C0-30E0-4E22-80C0-CE093F111A43};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>WPCordovaClassLib</RootNamespace>
+ <AssemblyName>WPCordovaClassLib</AssemblyName>
+ <AssemblyVersion>$(BaseVersionNumber)</AssemblyVersion>
+ <AssemblyFileVersion>$(VersionNumber)</AssemblyFileVersion>
+ <AssemblyDescription>$(VersionNumber)</AssemblyDescription>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+ <SilverlightVersion>$(TargetFrameworkVersion)</SilverlightVersion>
+ <TargetFrameworkProfile>WindowsPhone71</TargetFrameworkProfile>
+ <TargetFrameworkIdentifier>Silverlight</TargetFrameworkIdentifier>
+ <SilverlightApplication>false</SilverlightApplication>
+ <ValidateXaml>true</ValidateXaml>
+ <ThrowErrorsInValidation>true</ThrowErrorsInValidation>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>Bin\Debug</OutputPath>
+ <DefineConstants>TRACE;DEBUG;SILVERLIGHT;WINDOWS_PHONE;CORDOVA_CLASSLIB</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>Bin\Release</OutputPath>
+ <DefineConstants>TRACE;DEBUG;SILVERLIGHT;WINDOWS_PHONE;CORDOVA_CLASSLIB</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <DocumentationFile>
+ </DocumentationFile>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="Microsoft.Devices.Sensors" />
+ <Reference Include="Microsoft.Phone" />
+ <Reference Include="Microsoft.Phone.Interop" />
+ <Reference Include="Microsoft.Xna.Framework" />
+ <Reference Include="System.Device" />
+ <Reference Include="System.Runtime.Serialization" />
+ <Reference Include="System.Servicemodel" />
+ <Reference Include="System.Servicemodel.Web" />
+ <Reference Include="System.Windows" />
+ <Reference Include="system" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml" />
+ <Reference Include="System.Net" />
+ <Reference Include="System.Xml.Linq" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\templates\standalone\cordovalib\BrowserMouseHelper.cs">
+ <Link>CordovaLib\BrowserMouseHelper.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\cordovalib\CommandFactory.cs">
+ <Link>CordovaLib\CommandFactory.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\cordovalib\Commands\BaseCommand.cs">
+ <Link>CordovaLib\Commands\BaseCommand.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\cordovalib\ConfigHandler.cs">
+ <Link>CordovaLib\ConfigHandler.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\cordovalib\CordovaCommandCall.cs">
+ <Link>CordovaLib\CordovaCommandCall.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\cordovalib\CordovaView.xaml.cs">
+ <Link>CordovaLib\CordovaView.xaml.cs</Link>
+ <DependentUpon>CordovaView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="..\templates\standalone\cordovalib\DOMStorageHelper.cs">
+ <Link>CordovaLib\DOMStorageHelper.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\cordovalib\JSON\JsonHelper.cs">
+ <Link>CordovaLib\JSON\JsonHelper.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\cordovalib\NativeExecution.cs">
+ <Link>CordovaLib\NativeExecution.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\cordovalib\OrientationHelper.cs">
+ <Link>CordovaLib\OrientationHelper.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\cordovalib\PluginResult.cs">
+ <Link>CordovaLib\PluginResult.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\cordovalib\ScriptCallback.cs">
+ <Link>CordovaLib\ScriptCallback.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\Accelerometer.cs">
+ <Link>CordovaLib\Plugins\Accelerometer.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\AudioFormatsHelper.cs">
+ <Link>CordovaLib\Plugins\AudioFormatsHelper.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\AudioPlayer.cs">
+ <Link>CordovaLib\Plugins\AudioPlayer.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\Battery.cs">
+ <Link>CordovaLib\Plugins\Battery.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\Camera.cs">
+ <Link>CordovaLib\Plugins\Camera.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\Capture.cs">
+ <Link>CordovaLib\Plugins\Capture.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\Compass.cs">
+ <Link>CordovaLib\Plugins\Compass.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\Contacts.cs">
+ <Link>CordovaLib\Plugins\Contacts.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\DebugConsole.cs">
+ <Link>CordovaLib\Plugins\DebugConsole.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\Device.cs">
+ <Link>CordovaLib\Plugins\Device.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\File.cs">
+ <Link>CordovaLib\Plugins\File.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\FileTransfer.cs">
+ <Link>CordovaLib\Plugins\FileTransfer.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\GeoLocation.cs">
+ <Link>CordovaLib\Plugins\GeoLocation.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\Globalization.cs">
+ <Link>CordovaLib\Plugins\Globalization.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\ImageExifHelper.cs">
+ <Link>CordovaLib\Plugins\ImageExifHelper.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\InAppBrowser.cs">
+ <Link>CordovaLib\Plugins\InAppBrowser.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\Media.cs">
+ <Link>CordovaLib\Plugins\Media.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\MimeTypeMapper.cs">
+ <Link>CordovaLib\Plugins\MimeTypeMapper.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\NetworkStatus.cs">
+ <Link>CordovaLib\Plugins\NetworkStatus.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\Notification.cs">
+ <Link>CordovaLib\Plugins\Notification.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\UI\AudioCaptureTask.cs">
+ <Link>CordovaLib\Plugins\UI\AudioCaptureTask.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\UI\AudioRecorder.xaml.cs">
+ <Link>CordovaLib\Plugins\UI\AudioRecorder.xaml.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\UI\ImageCapture.xaml.cs">
+ <Link>CordovaLib\Plugins\UI\ImageCapture.xaml.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\UI\NotificationBox.xaml.cs">
+ <Link>CordovaLib\Plugins\UI\NotificationBox.xaml.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\UI\VideoCaptureTask.cs">
+ <Link>CordovaLib\Plugins\UI\VideoCaptureTask.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\UI\VideoRecorder.xaml.cs">
+ <Link>CordovaLib\Plugins\UI\VideoRecorder.xaml.cs</Link>
+ </Compile>
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Content Include="..\templates\standalone\cordovalib\resources\notification-beep.wav">
+ <Link>CordovaLib\resources\notification-beep.wav</Link>
+ </Content>
+ <Content Include="..\templates\standalone\Images\appbar.back.rest.png">
+ <Link>CordovaLib\Images\appbar.back.rest.png</Link>
+ </Content>
+ <Content Include="..\templates\standalone\Images\appbar.close.rest.png">
+ <Link>CordovaLib\Images\appbar.close.rest.png</Link>
+ </Content>
+ <Content Include="..\templates\standalone\Images\appbar.feature.video.rest.png">
+ <Link>CordovaLib\Images\appbar.feature.video.rest.png</Link>
+ </Content>
+ <Content Include="..\templates\standalone\Images\appbar.next.rest.png">
+ <Link>CordovaLib\Images\appbar.next.rest.png</Link>
+ </Content>
+ <Content Include="..\templates\standalone\Images\appbar.save.rest.png">
+ <Link>CordovaLib\Images\appbar.save.rest.png</Link>
+ </Content>
+ <Content Include="..\templates\standalone\Images\appbar.stop.rest.png">
+ <Link>CordovaLib\Images\appbar.stop.rest.png</Link>
+ </Content>
+ <Content Include="Images\appbar.back.rest.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="Images\appbar.close.rest.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="Images\appbar.feature.video.rest.png">
+ <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+ </Content>
+ <Content Include="Images\appbar.next.rest.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="Images\appbar.stop.rest.png">
+ <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+ </Content>
+ <Content Include="Images\appbar.save.rest.png">
+ <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+ </Content>
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="resources\notification-beep.wav" />
+ </ItemGroup>
+ <ItemGroup>
+ <Page Include="..\templates\standalone\cordovalib\CordovaView.xaml">
+ <Link>CordovaLib\CordovaView.xaml</Link>
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="..\templates\standalone\Plugins\UI\AudioRecorder.xaml">
+ <Link>CordovaLib\Plugins\UI\AudioRecorder.xaml</Link>
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="..\templates\standalone\Plugins\UI\ImageCapture.xaml">
+ <Link>CordovaLib\Plugins\UI\ImageCapture.xaml</Link>
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="..\templates\standalone\Plugins\UI\NotificationBox.xaml">
+ <Link>CordovaLib\Plugins\UI\NotificationBox.xaml</Link>
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="..\templates\standalone\Plugins\UI\VideoRecorder.xaml">
+ <Link>CordovaLib\Plugins\UI\VideoRecorder.xaml</Link>
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ </ItemGroup>
+ <Import Project="$(MSBuildExtensionsPath)\Microsoft\Silverlight for Phone\$(TargetFrameworkVersion)\Microsoft.Silverlight.$(TargetFrameworkProfile).Overrides.targets" />
+ <Import Project="$(MSBuildExtensionsPath)\Microsoft\Silverlight for Phone\$(TargetFrameworkVersion)\Microsoft.Silverlight.CSharp.targets" />
+ <ProjectExtensions />
+ <PropertyGroup>
+ <PreBuildEvent>
+ </PreBuildEvent>
+ </PropertyGroup>
+ <PropertyGroup>
+ <PostBuildEvent>
+ </PostBuildEvent>
+ </PropertyGroup>
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ <AssemblyInfo
+ AssemblyVersion="$(BaseVersion)"
+ AssemblyFileVersion="$(BaseVersion)"
+ AssemblyDescription="$(VersionNumber)"
+ >
+ </AssemblyInfo>
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>-->
+</Project>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/framework/WPCordovaClassLib.sln
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/framework/WPCordovaClassLib.sln b/lib/cordova-wp7/framework/WPCordovaClassLib.sln
new file mode 100644
index 0000000..2d5e088
--- /dev/null
+++ b/lib/cordova-wp7/framework/WPCordovaClassLib.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WPCordovaClassLib", "WPCordovaClassLib.csproj", "{FC6A1A70-892D-46AD-9E4A-9793F72AF780}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {FC6A1A70-892D-46AD-9E4A-9793F72AF780}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FC6A1A70-892D-46AD-9E4A-9793F72AF780}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FC6A1A70-892D-46AD-9E4A-9793F72AF780}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FC6A1A70-892D-46AD-9E4A-9793F72AF780}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/framework/resources/notification-beep.wav
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/framework/resources/notification-beep.wav b/lib/cordova-wp7/framework/resources/notification-beep.wav
new file mode 100644
index 0000000..d0ad085
Binary files /dev/null and b/lib/cordova-wp7/framework/resources/notification-beep.wav differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/App.xaml
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/App.xaml b/lib/cordova-wp7/templates/standalone/App.xaml
new file mode 100644
index 0000000..18072fe
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/App.xaml
@@ -0,0 +1,37 @@
+<!--
+ 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.
+-->
+<Application
+ x:Class="$safeprojectname$.App"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
+ xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone">
+
+ <!--Application Resources-->
+ <Application.Resources>
+ </Application.Resources>
+
+ <Application.ApplicationLifetimeObjects>
+ <!--Required object that handles lifetime events for the application-->
+ <shell:PhoneApplicationService
+ Launching="Application_Launching" Closing="Application_Closing"
+ Activated="Application_Activated" Deactivated="Application_Deactivated"/>
+ </Application.ApplicationLifetimeObjects>
+
+</Application>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/App.xaml.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/App.xaml.cs b/lib/cordova-wp7/templates/standalone/App.xaml.cs
new file mode 100644
index 0000000..2b7306d
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/App.xaml.cs
@@ -0,0 +1,154 @@
+/*
+ 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.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.Navigation;
+using System.Windows.Shapes;
+using Microsoft.Phone.Controls;
+using Microsoft.Phone.Shell;
+
+namespace $safeprojectname$
+{
+ public partial class App : Application
+ {
+ /// <summary>
+ /// Provides easy access to the root frame of the Phone Application.
+ /// </summary>
+ /// <returns>The root frame of the Phone Application.</returns>
+ public PhoneApplicationFrame RootFrame { get; private set; }
+
+ /// <summary>
+ /// Constructor for the Application object.
+ /// </summary>
+ public App()
+ {
+ // Global handler for uncaught exceptions.
+ UnhandledException += Application_UnhandledException;
+
+ // Show graphics profiling information while debugging.
+ if (System.Diagnostics.Debugger.IsAttached)
+ {
+ // Display the current frame rate counters.
+ //Application.Current.Host.Settings.EnableFrameRateCounter = true;
+
+ // Show the areas of the app that are being redrawn in each frame.
+ //Application.Current.Host.Settings.EnableRedrawRegions = true;
+
+ // Enable non-production analysis visualization mode,
+ // which shows areas of a page that are being GPU accelerated with a colored overlay.
+ //Application.Current.Host.Settings.EnableCacheVisualization = true;
+ }
+
+ // Standard Silverlight initialization
+ InitializeComponent();
+
+ // Phone-specific initialization
+ InitializePhoneApplication();
+ }
+
+ // Code to execute when the application is launching (eg, from Start)
+ // This code will not execute when the application is reactivated
+ private void Application_Launching(object sender, LaunchingEventArgs e)
+ {
+ }
+
+ // Code to execute when the application is activated (brought to foreground)
+ // This code will not execute when the application is first launched
+ private void Application_Activated(object sender, ActivatedEventArgs e)
+ {
+ }
+
+ // Code to execute when the application is deactivated (sent to background)
+ // This code will not execute when the application is closing
+ private void Application_Deactivated(object sender, DeactivatedEventArgs e)
+ {
+ }
+
+ // Code to execute when the application is closing (eg, user hit Back)
+ // This code will not execute when the application is deactivated
+ private void Application_Closing(object sender, ClosingEventArgs e)
+ {
+ }
+
+ // Code to execute if a navigation fails
+ private void RootFrame_NavigationFailed(object sender, NavigationFailedEventArgs e)
+ {
+ if (System.Diagnostics.Debugger.IsAttached)
+ {
+ // A navigation has failed; break into the debugger
+ System.Diagnostics.Debugger.Break();
+ }
+ }
+
+ // Code to execute on Unhandled Exceptions
+ private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
+ {
+ if (System.Diagnostics.Debugger.IsAttached)
+ {
+ // An unhandled exception has occurred; break into the debugger
+ System.Diagnostics.Debugger.Break();
+ }
+ }
+
+ #region Phone application initialization
+
+ // Avoid double-initialization
+ private bool phoneApplicationInitialized = false;
+
+ // Do not add any additional code to this method
+ private void InitializePhoneApplication()
+ {
+ if (phoneApplicationInitialized)
+ return;
+
+ // Create the frame but don't set it as RootVisual yet; this allows the splash
+ // screen to remain active until the application is ready to render.
+ RootFrame = new PhoneApplicationFrame();
+ RootFrame.Navigated += CompleteInitializePhoneApplication;
+
+ // Handle navigation failures
+ RootFrame.NavigationFailed += RootFrame_NavigationFailed;
+
+ // Ensure we don't initialize again
+ phoneApplicationInitialized = true;
+ }
+
+ // Do not add any additional code to this method
+ private void CompleteInitializePhoneApplication(object sender, NavigationEventArgs e)
+ {
+ // Set the root visual to allow the application to render
+ if (RootVisual != RootFrame)
+ RootVisual = RootFrame;
+
+ // Remove this handler since it is no longer needed
+ RootFrame.Navigated -= CompleteInitializePhoneApplication;
+ }
+
+ #endregion
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/ApplicationIcon.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/ApplicationIcon.png b/lib/cordova-wp7/templates/standalone/ApplicationIcon.png
new file mode 100644
index 0000000..6b69046
Binary files /dev/null and b/lib/cordova-wp7/templates/standalone/ApplicationIcon.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Background.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Background.png b/lib/cordova-wp7/templates/standalone/Background.png
new file mode 100644
index 0000000..2667df4
Binary files /dev/null and b/lib/cordova-wp7/templates/standalone/Background.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/BuildManifestProcessor.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/BuildManifestProcessor.js b/lib/cordova-wp7/templates/standalone/BuildManifestProcessor.js
new file mode 100644
index 0000000..ab2ac9d
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/BuildManifestProcessor.js
@@ -0,0 +1,106 @@
+/*
+ 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.
+*/
+var objArgs = WScript.Arguments;
+for (i = 0; i < objArgs.length; i++) {
+ WScript.Echo("Arg :: " + objArgs(i));
+}
+
+var projectFilePath = null;
+if (objArgs && objArgs.length > 0) {
+ projectFilePath = objArgs(0);
+}
+
+
+var fso = WScript.CreateObject("Scripting.FileSystemObject");
+var outFile = fso.CreateTextFile("..\\..\\CordovaSourceDictionary.xml", true);
+
+outFile.WriteLine('<?xml version="1.0" encoding="utf-8"?>');
+outFile.WriteLine('<!-- This file is auto-generated, do not edit! -jm -->');
+outFile.WriteLine('<CordovaSourceDictionary>');
+
+
+function getDirectoryListing(path) {
+ var retList = [];
+ var fso = new ActiveXObject("Scripting.FileSystemObject");
+ var folder = fso.GetFolder(path);
+ // iterate over the files in the folder
+ for (var files = new Enumerator(folder.files) ; !files.atEnd() ; files.moveNext()) {
+ retList.push(path + files.item().name);
+ }
+ // iterate over the child folders in the folder
+ for (var subFlds = new Enumerator(folder.SubFolders) ; !subFlds.atEnd() ; subFlds.moveNext()) {
+ var subDirList = getDirectoryListing(path + subFlds.item().name + "\\");
+ retList = retList.concat(subDirList);
+ }
+ return retList;
+}
+
+
+// We need to get any Linked files from the project
+
+WScript.Echo("Adding Source Files ...");
+if (projectFilePath != null) {
+ var projXml = WScript.CreateObject("Microsoft.XMLDOM");
+
+ projXml.async = false;
+ if (projXml.load(projectFilePath)) {
+
+ // add linked content ( windows shortcuts )
+ var nodes = projXml.selectNodes("/Project/ItemGroup/Content/Link");
+ WScript.Echo("/Project/ItemGroup/Content/Link nodes.length" + nodes.length);
+ for (var n = 0; n < nodes.length; n++) {
+ outFile.WriteLine(' <FilePath Value="' + nodes[n].text + '"/>');
+ }
+
+ // add files of type Resource
+ nodes = projXml.selectNodes("/Project/ItemGroup/Resource/Link");
+ WScript.Echo("/Project/ItemGroup/Resource/Link nodes.length" + nodes.length);
+ for (n = 0; n < nodes.length; n++) {
+ outFile.WriteLine(' <FilePath Value="' + nodes[n].text + '"/>');
+ }
+
+ // add Content files from www folder
+ nodes = projXml.selectNodes("/Project/ItemGroup/Content[@Include]");
+ WScript.Echo("/Project/ItemGroup/Content nodes.length" + nodes.length);
+ for (n = 0; n < nodes.length; n++) {
+ for (var i = 0; i < nodes[n].attributes.length; i++) {
+
+ if (nodes[n].attributes[i].name == "Include") {
+ var val = nodes[n].attributes[i].value;
+ if (val.indexOf("www\\**") == 0 ){
+ WScript.echo("adding wildcard files");
+ var fileList = getDirectoryListing("..\\..\\www\\");
+ for (var index = 0 ; index < fileList.length; index++)
+ {
+ outFile.WriteLine(' <FilePath Value="' + fileList[index].replace(/..\\..\\www/g,"www") + '"/>');
+ }
+ }
+ else if (val.indexOf("www") == 0) {
+ WScript.Echo("adding value :: " + val);
+ outFile.WriteLine(' <FilePath Value="' + val + '"/>');
+ }
+ }
+ }
+
+ }
+ }
+}
+
+outFile.WriteLine('</CordovaSourceDictionary>');
+
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/CordovaAppProj.csproj
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/CordovaAppProj.csproj b/lib/cordova-wp7/templates/standalone/CordovaAppProj.csproj
new file mode 100644
index 0000000..61b3be1
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/CordovaAppProj.csproj
@@ -0,0 +1,197 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>10.0.20506</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{3677C1B7-D68B-4CF9-BF8A-E869D437A6DF}</ProjectGuid>
+ <ProjectTypeGuids>{C089C8C0-30E0-4E22-80C0-CE093F111A43};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>$safeprojectname$</RootNamespace>
+ <AssemblyName>$safeprojectname$</AssemblyName>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+ <SilverlightVersion>$(TargetFrameworkVersion)</SilverlightVersion>
+ <TargetFrameworkProfile>WindowsPhone71</TargetFrameworkProfile>
+ <TargetFrameworkIdentifier>Silverlight</TargetFrameworkIdentifier>
+ <SilverlightApplication>true</SilverlightApplication>
+ <SupportedCultures>
+ </SupportedCultures>
+ <XapOutputs>true</XapOutputs>
+ <GenerateSilverlightManifest>true</GenerateSilverlightManifest>
+ <XapFilename>$safeprojectname$.xap</XapFilename>
+ <SilverlightManifestTemplate>Properties\AppManifest.xml</SilverlightManifestTemplate>
+ <SilverlightAppEntry>$safeprojectname$.App</SilverlightAppEntry>
+ <ValidateXaml>true</ValidateXaml>
+ <ThrowErrorsInValidation>true</ThrowErrorsInValidation>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>Bin\Debug</OutputPath>
+ <DefineConstants>DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>Bin\Release</OutputPath>
+ <DefineConstants>TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="Microsoft.Devices.Sensors" />
+ <Reference Include="Microsoft.Phone" />
+ <Reference Include="Microsoft.Phone.Interop" />
+ <Reference Include="Microsoft.Xna.Framework" />
+ <Reference Include="System.Device" />
+ <Reference Include="System.Runtime.Serialization" />
+ <Reference Include="System.Servicemodel.Web" />
+ <Reference Include="System.Windows" />
+ <Reference Include="system" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Net" />
+ <Reference Include="System.Xml" />
+ <Reference Include="System.Xml.Linq" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="App.xaml.cs">
+ <DependentUpon>App.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="cordovalib\BrowserMouseHelper.cs" />
+ <Compile Include="cordovalib\CommandFactory.cs" />
+ <Compile Include="cordovalib\Commands\BaseCommand.cs" />
+ <Compile Include="cordovalib\ConfigHandler.cs" />
+ <Compile Include="cordovalib\CordovaCommandCall.cs" />
+ <Compile Include="cordovalib\CordovaView.xaml.cs">
+ <DependentUpon>CordovaView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="cordovalib\DOMStorageHelper.cs" />
+ <Compile Include="cordovalib\JSON\JsonHelper.cs" />
+ <Compile Include="cordovalib\NativeExecution.cs" />
+ <Compile Include="cordovalib\OrientationHelper.cs" />
+ <Compile Include="cordovalib\PluginResult.cs" />
+ <Compile Include="cordovalib\ScriptCallback.cs" />
+
+
+
+ <Compile Include="MainPage.xaml.cs">
+ <DependentUpon>MainPage.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ApplicationDefinition Include="App.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </ApplicationDefinition>
+ <Page Include="cordovalib\CordovaView.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+
+ <Page Include="MainPage.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
+
+ <Page Include="Plugins\UI\AudioRecorder.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="Plugins\UI\ImageCapture.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="Plugins\UI\NotificationBox.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="Plugins\UI\VideoRecorder.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+
+ </ItemGroup>
+ <ItemGroup>
+ <Content Include="www\**" />
+ <Content Include="config.xml" />
+ <Content Include="Images\**" />
+
+ <Content Include="resources\notification-beep.wav" />
+ <None Include="VERSION" />
+
+ <Content Include="CordovaSourceDictionary.xml">
+ <SubType>Designer</SubType>
+ </Content>
+ <None Include="BuildManifestProcessor.js" />
+ <None Include="Properties\AppManifest.xml">
+ <SubType>Designer</SubType>
+ </None>
+ <None Include="Properties\WMAppManifest.xml">
+ <SubType>Designer</SubType>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <Content Include="ApplicationIcon.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="Background.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="SplashScreenImage.jpg" />
+ </ItemGroup>
+ <ItemGroup>
+ <WCFMetadata Include="Service References\" />
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Plugins\*" />
+ <Compile Include="Plugins\UI\*.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildExtensionsPath)\Microsoft\Silverlight for Phone\$(TargetFrameworkVersion)\Microsoft.Silverlight.$(TargetFrameworkProfile).Overrides.targets" />
+ <Import Project="$(MSBuildExtensionsPath)\Microsoft\Silverlight for Phone\$(TargetFrameworkVersion)\Microsoft.Silverlight.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+ <ProjectExtensions />
+ <PropertyGroup>
+ <PreBuildEvent>CScript "$(ProjectDir)/BuildManifestProcessor.js" "$(ProjectPath)"</PreBuildEvent>
+ </PropertyGroup>
+ <PropertyGroup>
+ <PostBuildEvent>
+ </PostBuildEvent>
+ </PropertyGroup>
+</Project>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/CordovaSolution.sln
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/CordovaSolution.sln b/lib/cordova-wp7/templates/standalone/CordovaSolution.sln
new file mode 100644
index 0000000..5ce2292
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/CordovaSolution.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010 Express for Windows Phone
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CordovaAppProj", "CordovaAppProj.csproj", "{3677C1B7-D68B-4CF9-BF8A-E869D437A6DF}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {3677C1B7-D68B-4CF9-BF8A-E869D437A6DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3677C1B7-D68B-4CF9-BF8A-E869D437A6DF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3677C1B7-D68B-4CF9-BF8A-E869D437A6DF}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {3677C1B7-D68B-4CF9-BF8A-E869D437A6DF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3677C1B7-D68B-4CF9-BF8A-E869D437A6DF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3677C1B7-D68B-4CF9-BF8A-E869D437A6DF}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/CordovaSourceDictionary.xml
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/CordovaSourceDictionary.xml b/lib/cordova-wp7/templates/standalone/CordovaSourceDictionary.xml
new file mode 100644
index 0000000..74f51b7
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/CordovaSourceDictionary.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- This file is auto-generated, do not edit! -jm -->
+<CordovaSourceDictionary>
+ <FilePath Value="www\cordova-2.6.0.js"/>
+ <FilePath Value="www\index.html"/>
+ <FilePath Value="www\css\index.css"/>
+ <FilePath Value="www\img\logo.png"/>
+ <FilePath Value="www\js\index.js"/>
+</CordovaSourceDictionary>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Images/appbar.back.rest.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Images/appbar.back.rest.png b/lib/cordova-wp7/templates/standalone/Images/appbar.back.rest.png
new file mode 100644
index 0000000..4bc2b92
Binary files /dev/null and b/lib/cordova-wp7/templates/standalone/Images/appbar.back.rest.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Images/appbar.close.rest.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Images/appbar.close.rest.png b/lib/cordova-wp7/templates/standalone/Images/appbar.close.rest.png
new file mode 100644
index 0000000..8166a1c
Binary files /dev/null and b/lib/cordova-wp7/templates/standalone/Images/appbar.close.rest.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Images/appbar.feature.video.rest.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Images/appbar.feature.video.rest.png b/lib/cordova-wp7/templates/standalone/Images/appbar.feature.video.rest.png
new file mode 100644
index 0000000..baff565
Binary files /dev/null and b/lib/cordova-wp7/templates/standalone/Images/appbar.feature.video.rest.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Images/appbar.next.rest.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Images/appbar.next.rest.png b/lib/cordova-wp7/templates/standalone/Images/appbar.next.rest.png
new file mode 100644
index 0000000..ed577d7
Binary files /dev/null and b/lib/cordova-wp7/templates/standalone/Images/appbar.next.rest.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Images/appbar.save.rest.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Images/appbar.save.rest.png b/lib/cordova-wp7/templates/standalone/Images/appbar.save.rest.png
new file mode 100644
index 0000000..d49940e
Binary files /dev/null and b/lib/cordova-wp7/templates/standalone/Images/appbar.save.rest.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Images/appbar.stop.rest.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Images/appbar.stop.rest.png b/lib/cordova-wp7/templates/standalone/Images/appbar.stop.rest.png
new file mode 100644
index 0000000..4dd724f
Binary files /dev/null and b/lib/cordova-wp7/templates/standalone/Images/appbar.stop.rest.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/MainPage.xaml
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/MainPage.xaml b/lib/cordova-wp7/templates/standalone/MainPage.xaml
new file mode 100644
index 0000000..8b1e84b
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/MainPage.xaml
@@ -0,0 +1,35 @@
+
+<phone:PhoneApplicationPage
+ x:Class="$safeprojectname$.MainPage"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
+ xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
+ 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}"
+ Background="Black"
+ SupportedOrientations="PortraitOrLandscape" Orientation="Portrait"
+ shell:SystemTray.IsVisible="True" d:DesignHeight="768" d:DesignWidth="480"
+ xmlns:my="clr-namespace:WPCordovaClassLib">
+ <Grid x:Name="LayoutRoot" Background="Transparent" HorizontalAlignment="Stretch">
+ <Grid.RowDefinitions>
+ <RowDefinition Height="*"/>
+ </Grid.RowDefinitions>
+ <my:CordovaView HorizontalAlignment="Stretch"
+ Margin="0,0,0,0"
+ x:Name="CordovaView"
+ VerticalAlignment="Stretch" />
+ <Image Source="SplashScreenImage.jpg"
+ x:Name="SplashImage"
+ VerticalAlignment="Center"
+ HorizontalAlignment="Stretch">
+ <Image.Projection>
+ <PlaneProjection x:Name="SplashProjector" CenterOfRotationX="0"/>
+ </Image.Projection>
+ </Image>
+ </Grid>
+
+</phone:PhoneApplicationPage>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/MainPage.xaml.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/MainPage.xaml.cs b/lib/cordova-wp7/templates/standalone/MainPage.xaml.cs
new file mode 100644
index 0000000..b9ec7e1
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/MainPage.xaml.cs
@@ -0,0 +1,72 @@
+/*
+ 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.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;
+using System.Windows.Media.Imaging;
+using System.Windows.Resources;
+
+
+namespace $safeprojectname$
+{
+ public partial class MainPage : PhoneApplicationPage
+ {
+ // Constructor
+ public MainPage()
+ {
+ InitializeComponent();
+ this.CordovaView.Loaded += CordovaView_Loaded;
+ }
+
+ private void CordovaView_Loaded(object sender, RoutedEventArgs e)
+ {
+ this.CordovaView.Loaded -= CordovaView_Loaded;
+ // first time load will have an animation
+ Storyboard _storyBoard = new Storyboard();
+ DoubleAnimation animation = new DoubleAnimation()
+ {
+ From = 0,
+ Duration = TimeSpan.FromSeconds(0.6),
+ To = 90
+ };
+ Storyboard.SetTarget(animation, SplashProjector);
+ Storyboard.SetTargetProperty(animation, new PropertyPath("RotationY"));
+ _storyBoard.Children.Add(animation);
+ _storyBoard.Begin();
+ _storyBoard.Completed += Splash_Completed;
+ }
+
+ void Splash_Completed(object sender, EventArgs e)
+ {
+ (sender as Storyboard).Completed -= Splash_Completed;
+ LayoutRoot.Children.Remove(SplashImage);
+ }
+ }
+}
[15/37] Add WP7 and WP8 platform files.
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/UI/VideoRecorder.xaml.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/UI/VideoRecorder.xaml.cs b/lib/cordova-wp8/templates/standalone/Plugins/UI/VideoRecorder.xaml.cs
new file mode 100644
index 0000000..6ab1cc3
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/UI/VideoRecorder.xaml.cs
@@ -0,0 +1,405 @@
+/*
+ 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.IO;
+using System.IO.IsolatedStorage;
+using System.Windows.Media;
+using System.Windows.Navigation;
+using Microsoft.Phone.Controls;
+using Microsoft.Phone.Shell;
+using Microsoft.Phone.Tasks;
+using VideoResult = WPCordovaClassLib.Cordova.UI.VideoCaptureTask.VideoResult;
+
+namespace WPCordovaClassLib.Cordova.UI
+{
+ public partial class VideoRecorder : PhoneApplicationPage
+ {
+
+ #region Constants
+
+ /// <summary>
+ /// Caption for record button in ready state
+ /// </summary>
+ private const string RecordingStartCaption = "Record";
+
+ /// <summary>
+ /// Caption for record button in recording state
+ /// </summary>
+ private const string RecordingStopCaption = "Stop";
+
+ /// <summary>
+ /// Start record icon URI
+ /// </summary>
+ private const string StartIconUri = "/Images/appbar.feature.video.rest.png";
+
+ /// <summary>
+ /// Stop record icon URI
+ /// </summary>
+ private const string StopIconUri = "/Images/appbar.stop.rest.png";
+
+ /// <summary>
+ /// Folder to save video clips
+ /// </summary>
+ private const string LocalFolderName = "VideoCache";
+
+ /// <summary>
+ /// File name format
+ /// </summary>
+ private const string FileNameFormat = "Video-{0}.mp4";
+
+ /// <summary>
+ /// Temporary file name
+ /// </summary>
+ private const string defaultFileName = "NewVideoFile.mp4";
+
+ #endregion
+
+ #region Callbacks
+ /// <summary>
+ /// Occurs when a video recording task is completed.
+ /// </summary>
+ public event EventHandler<VideoResult> Completed;
+
+ #endregion
+
+ #region Fields
+
+ /// <summary>
+ /// Viewfinder for capturing video
+ /// </summary>
+ private VideoBrush videoRecorderBrush;
+
+ /// <summary>
+ /// Path to save video clip
+ /// </summary>
+ private string filePath;
+
+ /// <summary>
+ /// Source for capturing video.
+ /// </summary>
+ private CaptureSource captureSource;
+
+ /// <summary>
+ /// Video device
+ /// </summary>
+ private VideoCaptureDevice videoCaptureDevice;
+
+ /// <summary>
+ /// File sink so save recording video in Isolated Storage
+ /// </summary>
+ private FileSink fileSink;
+
+ /// <summary>
+ /// For managing button and application state
+ /// </summary>
+ private enum VideoState { Initialized, Ready, Recording, CameraNotSupported };
+
+ /// <summary>
+ /// Current video state
+ /// </summary>
+ private VideoState currentVideoState;
+
+ /// <summary>
+ /// Stream to return result
+ /// </summary>
+ private MemoryStream memoryStream;
+
+ /// <summary>
+ /// Recording result, dispatched back when recording page is closed
+ /// </summary>
+ private VideoResult result = new VideoResult(TaskResult.Cancel);
+
+ #endregion
+
+ /// <summary>
+ /// Initializes components
+ /// </summary>
+ public VideoRecorder()
+ {
+ InitializeComponent();
+
+ PhoneAppBar = (ApplicationBar)ApplicationBar;
+ PhoneAppBar.IsVisible = true;
+ btnStartRecording = ((ApplicationBarIconButton)ApplicationBar.Buttons[0]);
+ btnTakeVideo = ((ApplicationBarIconButton)ApplicationBar.Buttons[1]);
+ }
+
+ /// <summary>
+ /// Initializes the video recorder then page is loading
+ /// </summary>
+ protected override void OnNavigatedTo(NavigationEventArgs e)
+ {
+ base.OnNavigatedTo(e);
+ this.InitializeVideoRecorder();
+ }
+
+ /// <summary>
+ /// Disposes camera and media objects then leave the page
+ /// </summary>
+ protected override void OnNavigatedFrom(NavigationEventArgs e)
+ {
+ this.DisposeVideoRecorder();
+
+ if (this.Completed != null)
+ {
+ this.Completed(this, result);
+ }
+ base.OnNavigatedFrom(e);
+ }
+
+ /// <summary>
+ /// Handles TakeVideo button click
+ /// </summary>
+ private void TakeVideo_Click(object sender, EventArgs e)
+ {
+ this.result = this.SaveVideoClip();
+ this.NavigateBack();
+ }
+
+ private void NavigateBack()
+ {
+ if (this.NavigationService.CanGoBack)
+ {
+ this.NavigationService.GoBack();
+ }
+ }
+
+ /// <summary>
+ /// Resaves video clip from temporary directory to persistent
+ /// </summary>
+ private VideoResult SaveVideoClip()
+ {
+ try
+ {
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ if (string.IsNullOrEmpty(filePath) || (!isoFile.FileExists(filePath)))
+ {
+ return new VideoResult(TaskResult.Cancel);
+ }
+
+ string fileName = String.Format(FileNameFormat, Guid.NewGuid().ToString());
+ string newPath = Path.Combine("/" + LocalFolderName + "/", fileName);
+ isoFile.CopyFile(filePath, newPath);
+ isoFile.DeleteFile(filePath);
+
+ memoryStream = new MemoryStream();
+ using (IsolatedStorageFileStream fileStream = new IsolatedStorageFileStream(newPath, FileMode.Open, isoFile))
+ {
+ fileStream.CopyTo(memoryStream);
+ }
+
+ VideoResult result = new VideoResult(TaskResult.OK);
+ result.VideoFileName = newPath;
+ result.VideoFile = this.memoryStream;
+ result.VideoFile.Seek(0, SeekOrigin.Begin);
+ return result;
+ }
+
+ }
+ catch (Exception)
+ {
+ return new VideoResult(TaskResult.None);
+ }
+ }
+
+ /// <summary>
+ /// Updates the buttons on the UI thread based on current state.
+ /// </summary>
+ /// <param name="currentState">current UI state</param>
+ private void UpdateUI(VideoState currentState)
+ {
+ Dispatcher.BeginInvoke(delegate
+ {
+ switch (currentState)
+ {
+ case VideoState.CameraNotSupported:
+ btnStartRecording.IsEnabled = false;
+ btnTakeVideo.IsEnabled = false;
+ break;
+
+ case VideoState.Initialized:
+ btnStartRecording.Text = RecordingStartCaption;
+ btnStartRecording.IconUri = new Uri(StartIconUri, UriKind.Relative);
+ btnTakeVideo.IsEnabled = false;
+ break;
+
+ case VideoState.Ready:
+ btnStartRecording.Text = RecordingStartCaption;
+ btnStartRecording.IconUri = new Uri(StartIconUri, UriKind.Relative);
+ btnTakeVideo.IsEnabled = true;
+ break;
+
+ case VideoState.Recording:
+ btnStartRecording.Text = RecordingStopCaption;
+ btnStartRecording.IconUri = new Uri(StopIconUri, UriKind.Relative);
+ btnTakeVideo.IsEnabled = false;
+ break;
+
+ default:
+ break;
+ }
+ currentVideoState = currentState;
+ });
+ }
+
+ /// <summary>
+ /// Initializes VideoRecorder
+ /// </summary>
+ public void InitializeVideoRecorder()
+ {
+ if (captureSource == null)
+ {
+ captureSource = new CaptureSource();
+ fileSink = new FileSink();
+ videoCaptureDevice = CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice();
+
+ if (videoCaptureDevice != null)
+ {
+ videoRecorderBrush = new VideoBrush();
+ videoRecorderBrush.SetSource(captureSource);
+ viewfinderRectangle.Fill = videoRecorderBrush;
+ captureSource.Start();
+ this.UpdateUI(VideoState.Initialized);
+ }
+ else
+ {
+ this.UpdateUI(VideoState.CameraNotSupported);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Sets recording state: start recording
+ /// </summary>
+ private void StartVideoRecording()
+ {
+ try
+ {
+ if ((captureSource.VideoCaptureDevice != null) && (captureSource.State == CaptureState.Started))
+ {
+ captureSource.Stop();
+ fileSink.CaptureSource = captureSource;
+ filePath = System.IO.Path.Combine("/" + LocalFolderName + "/", defaultFileName);
+
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ if (!isoFile.DirectoryExists(LocalFolderName))
+ {
+ isoFile.CreateDirectory(LocalFolderName);
+ }
+
+ if (isoFile.FileExists(filePath))
+ {
+ isoFile.DeleteFile(filePath);
+ }
+ }
+
+ fileSink.IsolatedStorageFileName = filePath;
+ }
+
+ if (captureSource.VideoCaptureDevice != null
+ && captureSource.State == CaptureState.Stopped)
+ {
+ captureSource.Start();
+ }
+ this.UpdateUI(VideoState.Recording);
+ }
+ catch (Exception)
+ {
+ this.result = new VideoResult(TaskResult.None);
+ this.NavigateBack();
+ }
+ }
+
+ /// <summary>
+ /// Sets the recording state: stop recording
+ /// </summary>
+ private void StopVideoRecording()
+ {
+ try
+ {
+ if ((captureSource.VideoCaptureDevice != null) && (captureSource.State == CaptureState.Started))
+ {
+ captureSource.Stop();
+ fileSink.CaptureSource = null;
+ fileSink.IsolatedStorageFileName = null;
+ this.StartVideoPreview();
+ }
+ }
+ catch (Exception)
+ {
+ this.result = new VideoResult(TaskResult.None);
+ this.NavigateBack();
+ }
+ }
+
+ /// <summary>
+ /// Sets the recording state: display the video on the viewfinder.
+ /// </summary>
+ private void StartVideoPreview()
+ {
+ try
+ {
+ if ((captureSource.VideoCaptureDevice != null) && (captureSource.State == CaptureState.Stopped))
+ {
+ videoRecorderBrush.SetSource(captureSource);
+ viewfinderRectangle.Fill = videoRecorderBrush;
+ captureSource.Start();
+ this.UpdateUI(VideoState.Ready);
+ }
+ }
+ catch (Exception)
+ {
+ this.result = new VideoResult(TaskResult.None);
+ this.NavigateBack();
+ }
+ }
+
+ /// <summary>
+ /// Starts video recording
+ /// </summary>
+ private void StartRecording_Click(object sender, EventArgs e)
+ {
+ if (currentVideoState == VideoState.Recording)
+ {
+ this.StopVideoRecording();
+ }
+ else
+ {
+ this.StartVideoRecording();
+ }
+ }
+
+ /// <summary>
+ /// Releases resources
+ /// </summary>
+ private void DisposeVideoRecorder()
+ {
+ if (captureSource != null)
+ {
+ if ((captureSource.VideoCaptureDevice != null) && (captureSource.State == CaptureState.Started))
+ {
+ captureSource.Stop();
+ }
+ captureSource = null;
+ videoCaptureDevice = null;
+ fileSink = null;
+ videoRecorderBrush = null;
+ }
+ }
+
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Properties/AppManifest.xml
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Properties/AppManifest.xml b/lib/cordova-wp8/templates/standalone/Properties/AppManifest.xml
new file mode 100644
index 0000000..877ea4b
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Properties/AppManifest.xml
@@ -0,0 +1,6 @@
+<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+>
+ <Deployment.Parts>
+ </Deployment.Parts>
+</Deployment>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Properties/AssemblyInfo.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Properties/AssemblyInfo.cs b/lib/cordova-wp8/templates/standalone/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..8d9eb89
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Properties/AssemblyInfo.cs
@@ -0,0 +1,39 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Resources;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("CordovaAppProj")]
+[assembly: AssemblyDescription("2.0.0.0")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Cordova")]
+[assembly: AssemblyProduct("CordovaAppProj")]
+[assembly: AssemblyCopyright("Copyright © Apache Cordova 2013")]
+[assembly: AssemblyTrademark("Apache Cordova")]
+[assembly: AssemblyCulture("")]
+
+
+[assembly: NeutralResourcesLanguageAttribute("en-US")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("9e27b972-0825-4386-ba17-63c695262c3d")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Properties/WMAppManifest.xml
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Properties/WMAppManifest.xml b/lib/cordova-wp8/templates/standalone/Properties/WMAppManifest.xml
new file mode 100644
index 0000000..3c18727
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Properties/WMAppManifest.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Deployment xmlns="http://schemas.microsoft.com/windowsphone/2012/deployment" AppPlatformVersion="8.0">
+ <DefaultLanguage xmlns="" code="en-US" />
+ <Languages xmlns="">
+ <Language code="en-US" />
+ </Languages>
+ <App xmlns="" ProductID="{13b7ec4f-d4cf-422b-90ef-cd9c48af66ab}" Title="$safeprojectname$" RuntimeType="Silverlight" Version="1.0.0.0" Genre="apps.normal" Author="$safeprojectname$ author" BitsPerPixel="32" Description="Apache Cordova for Windows Phone" Publisher="$safeprojectname$" PublisherID="{db093ed5-53b1-45f7-af72-751e8f36ab80}">
+ <IconPath IsRelative="true" IsResource="false">ApplicationIcon.png</IconPath>
+ <Capabilities>
+ <Capability Name="ID_CAP_IDENTITY_DEVICE" />
+ <Capability Name="ID_CAP_IDENTITY_USER" />
+ <Capability Name="ID_CAP_LOCATION" />
+ <Capability Name="ID_CAP_NETWORKING" />
+ <Capability Name="ID_CAP_WEBBROWSERCOMPONENT" />
+ <Capability Name="ID_CAP_APPOINTMENTS" />
+ <Capability Name="ID_CAP_CONTACTS" />
+ <Capability Name="ID_CAP_ISV_CAMERA" />
+ <Capability Name="ID_CAP_MICROPHONE" />
+ <Capability Name="ID_CAP_PHONEDIALER" />
+ <Capability Name="ID_CAP_PUSH_NOTIFICATION" />
+ <Capability Name="ID_CAP_SENSORS" />
+ <Capability Name="ID_CAP_MEDIALIB_AUDIO" />
+ <Capability Name="ID_CAP_MEDIALIB_PHOTO" />
+ <Capability Name="ID_CAP_MEDIALIB_PLAYBACK" />
+ </Capabilities>
+ <Tasks>
+ <DefaultTask Name="_default" NavigationPage="MainPage.xaml" />
+ </Tasks>
+ <Tokens>
+ <PrimaryToken TokenID="$safeprojectname$Token" TaskName="_default">
+ <TemplateFlip>
+ <SmallImageURI IsResource="false" IsRelative="true">Background.png</SmallImageURI>
+ <Count>0</Count>
+ <BackgroundImageURI IsResource="false" IsRelative="true">Background.png</BackgroundImageURI>
+ <Title>$safeprojectname$</Title>
+ <BackContent></BackContent>
+ <BackBackgroundImageURI></BackBackgroundImageURI>
+ <BackTitle></BackTitle>
+ <LargeBackgroundImageURI></LargeBackgroundImageURI>
+ <LargeBackContent></LargeBackContent>
+ <LargeBackBackgroundImageURI></LargeBackBackgroundImageURI>
+ <DeviceLockImageURI></DeviceLockImageURI>
+ <HasLarge>false</HasLarge>
+ </TemplateFlip>
+ </PrimaryToken>
+ </Tokens>
+ <ScreenResolutions>
+ <ScreenResolution Name="ID_RESOLUTION_WVGA" />
+ <ScreenResolution Name="ID_RESOLUTION_WXGA" />
+ <ScreenResolution Name="ID_RESOLUTION_HD720P" />
+ </ScreenResolutions>
+ </App>
+</Deployment>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/SplashScreenImage.jpg
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/SplashScreenImage.jpg b/lib/cordova-wp8/templates/standalone/SplashScreenImage.jpg
new file mode 100644
index 0000000..d35501d
Binary files /dev/null and b/lib/cordova-wp8/templates/standalone/SplashScreenImage.jpg differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/VERSION
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/VERSION b/lib/cordova-wp8/templates/standalone/VERSION
new file mode 100644
index 0000000..9aa3464
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/VERSION
@@ -0,0 +1 @@
+2.7.0
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/config.xml
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/config.xml b/lib/cordova-wp8/templates/standalone/config.xml
new file mode 100644
index 0000000..170f9fe
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/config.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+#
+# 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.
+#
+-->
+<widget>
+
+ <plugins>
+ <plugin name="Device"/>
+ <plugin name="Logger"/>
+ <plugin name="Compass"/>
+ <plugin name="Accelerometer"/>
+ <plugin name="Camera"/>
+ <plugin name="NetworkStatus"/>
+ <plugin name="Contacts"/>
+ <plugin name="DebugConsole" />
+ <plugin name="Echo"/>
+ <plugin name="File"/>
+ <plugin name="FileTransfer"/>
+ <plugin name="Geolocation"/>
+ <plugin name="Notification"/>
+ <plugin name="Media"/>
+ <plugin name="Capture"/>
+ <plugin name="SplashScreen"/>
+ <plugin name="Battery"/>
+ <plugin name="Globalization"/>
+ <plugin name="InAppBrowser"/>
+ </plugins>
+
+
+ <access origin="*"/>
+
+</widget>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordova/build.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordova/build.bat b/lib/cordova-wp8/templates/standalone/cordova/build.bat
new file mode 100644
index 0000000..b48598a
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordova/build.bat
@@ -0,0 +1,9 @@
+@ECHO OFF
+SET full_path=%~dp0
+IF EXIST %full_path%lib\build.js (
+ cscript "%full_path%lib\build.js" %* //nologo
+) ELSE (
+ ECHO.
+ ECHO ERROR: Could not find 'build.js' in cordova/lib, aborting...>&2
+ EXIT /B 1
+)
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordova/clean.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordova/clean.bat b/lib/cordova-wp8/templates/standalone/cordova/clean.bat
new file mode 100644
index 0000000..1bafe1b
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordova/clean.bat
@@ -0,0 +1,9 @@
+@ECHO OFF
+SET full_path=%~dp0
+IF EXIST %full_path%lib\clean.js (
+ cscript "%full_path%lib\clean.js" %* //nologo
+) ELSE (
+ ECHO.
+ ECHO ERROR: Could not find 'clean.js' in cordova/lib, aborting...>&2
+ EXIT /B 1
+)
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy.sln
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy.sln b/lib/cordova-wp8/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy.sln
new file mode 100644
index 0000000..3305276
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CordovaDeploy", "CordovaDeploy\CordovaDeploy.csproj", "{E752165B-AF59-4FF0-8601-A2A69FE09E0E}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x86 = Debug|x86
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {E752165B-AF59-4FF0-8601-A2A69FE09E0E}.Debug|x86.ActiveCfg = Debug|x86
+ {E752165B-AF59-4FF0-8601-A2A69FE09E0E}.Debug|x86.Build.0 = Debug|x86
+ {E752165B-AF59-4FF0-8601-A2A69FE09E0E}.Release|x86.ActiveCfg = Release|x86
+ {E752165B-AF59-4FF0-8601-A2A69FE09E0E}.Release|x86.Build.0 = Release|x86
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy/CordovaDeploy.csproj
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy/CordovaDeploy.csproj b/lib/cordova-wp8/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy/CordovaDeploy.csproj
new file mode 100644
index 0000000..a52b532
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy/CordovaDeploy.csproj
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+ <ProductVersion>8.0.30703</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{E752165B-AF59-4FF0-8601-A2A69FE09E0E}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>CordovaDeploy</RootNamespace>
+ <AssemblyName>CordovaDeploy</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <TargetFrameworkProfile>
+ </TargetFrameworkProfile>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+ <PlatformTarget>x86</PlatformTarget>
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <Prefer32Bit>false</Prefer32Bit>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+ <PlatformTarget>x86</PlatformTarget>
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <Prefer32Bit>false</Prefer32Bit>
+ </PropertyGroup>
+ <PropertyGroup>
+ <StartupObject>CordovaDeploy.DeployTool</StartupObject>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="Microsoft.Smartdevice.Connectivity, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\..\..\..\..\..\Windows\Microsoft.NET\assembly\GAC_MSIL\Microsoft.SmartDevice.Connectivity\v4.0_11.0.0.0__b03f5f7f11d50a3a\Microsoft.Smartdevice.Connectivity.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Smartdevice.Connectivity.Interface, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\..\..\..\..\..\Windows\Microsoft.NET\assembly\GAC_MSIL\Microsoft.SmartDevice.Connectivity.Interface\v4.0_11.0.0.0__b03f5f7f11d50a3a\Microsoft.Smartdevice.Connectivity.Interface.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Smartdevice.MultiTargeting.Connectivity, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\..\..\..\..\..\Windows\Microsoft.NET\assembly\GAC_MSIL\Microsoft.SmartDevice.MultiTargeting.Connectivity\v4.0_11.0.0.0__b03f5f7f11d50a3a\Microsoft.Smartdevice.MultiTargeting.Connectivity.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Program.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="app.config" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy/Program.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy/Program.cs b/lib/cordova-wp8/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy/Program.cs
new file mode 100644
index 0000000..c7e5e74
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy/Program.cs
@@ -0,0 +1,424 @@
+/*
+ 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.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Collections.ObjectModel;
+using System.Diagnostics;
+using System.IO;
+using System.Xml.XPath;
+using System.Xml;
+using System.Xml.Linq;
+using System.Globalization;
+// Windows Phone Emulator Libraries
+using Microsoft.SmartDevice.Connectivity;
+using Microsoft.SmartDevice.Connectivity.Interface;
+using Microsoft.SmartDevice.MultiTargeting.Connectivity;
+
+
+namespace CordovaDeploy
+{
+
+ class DeployTool
+ {
+
+ static void Usage()
+ {
+ Log("Usage: CordovaDeploy [ -devices BuildOutputPath -d:DeviceIndex ]");
+ Log(" -devices : lists the devices and exits");
+ Log(" BuildOutputPath : path to the built application, typically Bin/Debug/ or Bin/Release/");
+ Log(" -d : index of the device to deploy, default is 0 ");
+ Log("examples:");
+ Log(" CordovaDeploy -devices");
+ Log(" CordovaDeploy Bin/Debug");
+ Log(" CordovaDeploy Bin/Release -d:1");
+ }
+
+ static void ReadWait()
+ {
+ // This is used when running in Visual Studio, the Command Window is created at launch, and disappears at the
+ // end of the program run, this let's us see the output before the window is closed.
+
+ /*
+ Console.WriteLine("\nPress ENTER to continue...");
+ Console.Read();
+ */
+ }
+
+ static void Log(string msg, bool error = false)
+ {
+ Debug.WriteLine(msg);
+ if (error)
+ {
+ Console.Error.WriteLine(msg);
+ }
+ else
+ {
+ Console.Out.WriteLine(msg);
+ }
+ }
+
+ static Guid ReadAppId(string root)
+ {
+ Guid appID = Guid.Empty;
+ string manifestFilePath = root + @"\Properties\WMAppManifest.xml";
+
+ if (File.Exists(manifestFilePath))
+ {
+ XDocument xdoc = XDocument.Load(manifestFilePath);
+ var appNode = xdoc.Root.Descendants("App").FirstOrDefault();
+ if (appNode != null)
+ {
+ string guidStr = appNode.Attribute("ProductID").Value;
+ appID = new Guid(guidStr);
+ }
+ else
+ {
+ Log(string.Format("Unable to find appID, expected to find an App.ProductID property defined in the file {0}", manifestFilePath), true);
+ }
+ }
+ else
+ {
+ Log(string.Format("Error: the file {0} does not exist", manifestFilePath), true);
+ }
+ return appID;
+ }
+
+ static void ListDevices()
+ {
+ MultiTargetingConnectivity mtConn = new MultiTargetingConnectivity(CultureInfo.CurrentUICulture.LCID);
+ Collection<ConnectableDevice> deviceList = mtConn.GetConnectableDevices();
+
+ for (int index = 0; index < deviceList.Count; index++)
+ {
+ ConnectableDevice d = deviceList[index];
+ string info = string.Format("{0} : {1} : {2}", index.ToString(), d.Id, d.Name);
+ Log(info);
+ }
+ }
+
+ static ConnectableDevice GetDeviceAtIndex(int index)
+ {
+ MultiTargetingConnectivity mtConn = new MultiTargetingConnectivity(CultureInfo.CurrentUICulture.LCID);
+ Collection<ConnectableDevice> deviceList = mtConn.GetConnectableDevices();
+ return deviceList[index];
+ }
+
+ static void Main(string[] args)
+ {
+ int deviceIndex = 0;
+
+ string iconFilePath = "";
+ string xapFilePath = "";
+ Guid appID = Guid.Empty;
+
+ string root = Directory.GetCurrentDirectory();
+
+ if (args.Length < 1)
+ {
+ Usage();
+ ReadWait();
+ return;
+ }
+ else if (args[0] == "-devices")
+ {
+ ListDevices();
+ ReadWait();
+ return;
+ }
+ else if (args.Length > 1 && args[1].StartsWith("-d:"))
+ {
+ deviceIndex = int.Parse(args[1].Substring(3));
+ }
+
+
+ if (Directory.Exists(args[0]))
+ {
+ DirectoryInfo info = new DirectoryInfo(args[0]);
+ root = info.FullName;
+ }
+
+ appID = ReadAppId(root);
+ if (appID == Guid.Empty)
+ {
+ return; // Logging of errors is done in ReadAppId
+ }
+
+ if (File.Exists(root + @"\ApplicationIcon.png"))
+ {
+ iconFilePath = root + @"\ApplicationIcon.png";
+ }
+ else
+ {
+ Log(string.Format("Error: could not find application icon at {0}", root + @"\ApplicationIcon.png"), true);
+ ReadWait();
+ return;
+ }
+
+ try {
+ xapFilePath = Directory.GetFiles(root + @"\Bin\Debug", "*.xap").FirstOrDefault();
+ } catch (DirectoryNotFoundException e) {
+ try {
+ xapFilePath = Directory.GetFiles(root + @"\Bin\Release", "*.xap").FirstOrDefault();
+ } catch (DirectoryNotFoundException ex) {
+ Log(string.Format("Error: could not find project build directoy in {0}", root), true);
+ Log("make sure your app has been successfully built before deploying.", true);
+ }
+ }
+
+ if (string.IsNullOrEmpty(xapFilePath))
+ {
+ Log(string.Format("Error: could not find application .xap in folder {0}", root), true);
+ ReadWait();
+ return;
+ }
+
+ ConnectableDevice deviceConn = GetDeviceAtIndex(deviceIndex);
+ Log("Connecting to device :: " + deviceConn.Id + " : " + deviceConn.Name);
+ try
+ {
+ IDevice device = deviceConn.Connect();
+ IRemoteApplication app = null;
+ if (device.IsApplicationInstalled(appID))
+ {
+ Log("Uninstalling XAP from " + deviceConn.Name);
+ app = device.GetApplication(appID);
+ app.Uninstall();
+ }
+
+ Log("Installing app on " + deviceConn.Name);
+ app = device.InstallApplication(appID, appID, "NormalApp", iconFilePath, xapFilePath);
+
+ Log("Launching app on " + deviceConn.Name);
+ app.Launch();
+
+ // To Stop :
+ //app.TerminateRunningInstances();
+
+ device.Disconnect();
+
+ ReadWait();
+
+ }
+ catch (Exception ex)
+ {
+ Log("Error :: " + ex.Message, true);
+ }
+ }
+
+ // To read and write ISO storage files!! :
+ /*
+ try
+ {
+ IRemoteIsolatedStorageFile isoStore = app.GetIsolatedStore();
+ remoteIsolatedStorageFile.ReceiveFile("sourcePath", "destPath", true);
+ }
+ catch (Exception ex) { }
+ */
+
+ }
+ class Program
+ {
+ static void Usage()
+ {
+ Log("Usage: CordovaDeploy [ -devices BuildOutputPath -d:DeviceIndex ]");
+ Log(" -devices : lists the devices and exits");
+ Log(" BuildOutputPath : path to the built application, typically Bin/Debug/ or Bin/Release/");
+ Log(" -d : index of the device to deploy, default is 0 ");
+ Log("examples:");
+ Log(" CordovaDeploy -devices");
+ Log(" CordovaDeploy Bin/Debug");
+ Log(" CordovaDeploy Bin/Release -d:1");
+ }
+
+ static void ReadWait()
+ {
+ // This is used when running in Visual Studio, the Command Window is created at launch, and disappears at the
+ // end of the program run, this let's us see the output before the window is closed.
+
+ /*
+ Console.WriteLine("\nPress ENTER to continue...");
+ Console.Read();
+ */
+ }
+
+ static void Log(string msg, bool error = false)
+ {
+ Debug.WriteLine(msg);
+ if (error)
+ {
+ Console.Error.WriteLine(msg);
+ }
+ else
+ {
+ Console.Out.WriteLine(msg);
+ }
+ }
+
+ static Guid ReadAppId(string root)
+ {
+ Guid appID = Guid.Empty;
+ string manifestFilePath = root + @"\Properties\WMAppManifest.xml";
+
+ if (File.Exists(manifestFilePath))
+ {
+ XDocument xdoc = XDocument.Load(manifestFilePath);
+ var appNode = xdoc.Root.Descendants("App").FirstOrDefault();
+ if (appNode != null)
+ {
+ string guidStr = appNode.Attribute("ProductID").Value;
+ appID = new Guid(guidStr);
+ }
+ else
+ {
+ Log(string.Format("Unable to find appID, expected to find an App.ProductID property defined in the file {0}", manifestFilePath), true);
+ }
+ }
+ else
+ {
+ Log(string.Format("Error: the file {0} does not exist", manifestFilePath), true);
+ }
+ return appID;
+ }
+
+ static void ListDevices()
+ {
+ MultiTargetingConnectivity mtConn = new MultiTargetingConnectivity(CultureInfo.CurrentUICulture.LCID);
+ Collection<ConnectableDevice> deviceList = mtConn.GetConnectableDevices();
+
+ for (int index = 0; index < deviceList.Count; index++)
+ {
+ ConnectableDevice d = deviceList[index];
+ string info = string.Format("{0} : {1} : {2}", index.ToString(), d.Id, d.Name);
+ Log(info);
+ }
+ }
+
+ static ConnectableDevice GetDeviceAtIndex(int index)
+ {
+ MultiTargetingConnectivity mtConn = new MultiTargetingConnectivity(CultureInfo.CurrentUICulture.LCID);
+ Collection<ConnectableDevice> deviceList = mtConn.GetConnectableDevices();
+ return deviceList[index];
+ }
+
+ static void Main(string[] args)
+ {
+ int deviceIndex = 0;
+
+ string iconFilePath = "";
+ string xapFilePath = "";
+ Guid appID = Guid.Empty;
+
+ string root = Directory.GetCurrentDirectory();
+
+ if (args.Length < 1)
+ {
+ Usage();
+ ReadWait();
+ return;
+ }
+ else if (args[0] == "-devices")
+ {
+ ListDevices();
+ ReadWait();
+ return;
+ }
+ else if (args.Length > 1 && args[1].StartsWith("-d:"))
+ {
+ deviceIndex = int.Parse(args[1].Substring(3));
+ }
+
+
+ if (Directory.Exists(args[0]))
+ {
+ DirectoryInfo info = new DirectoryInfo(args[0]);
+ root = info.FullName;
+ }
+
+ appID = ReadAppId(root);
+ if (appID == Guid.Empty)
+ {
+ return; // Logging of errors is done in ReadAppId
+ }
+
+ if (File.Exists(root + @"\ApplicationIcon.png"))
+ {
+ iconFilePath = root + @"\ApplicationIcon.png";
+ }
+ else
+ {
+ Log(string.Format("Error: could not find application icon at {0}", root + @"\ApplicationIcon.png"), true);
+ ReadWait();
+ return;
+ }
+
+ xapFilePath = Directory.GetFiles(root + @"\Bin\Debug", "*.xap").FirstOrDefault();
+ if (string.IsNullOrEmpty(xapFilePath))
+ {
+ Log(string.Format("Error: could not find application .xap in folder {0}", root), true);
+ ReadWait();
+ return;
+ }
+
+ ConnectableDevice deviceConn = GetDeviceAtIndex(deviceIndex);
+ Log("Connecting to device :: " + deviceConn.Id + " : " + deviceConn.Name);
+ try
+ {
+ IDevice device = deviceConn.Connect();
+ IRemoteApplication app = null;
+ if (device.IsApplicationInstalled(appID))
+ {
+ Log("Uninstalling XAP from " + deviceConn.Name);
+ app = device.GetApplication(appID);
+ app.Uninstall();
+ }
+
+ Log("Installing app on " + deviceConn.Name);
+ app = device.InstallApplication(appID, appID, "NormalApp", iconFilePath, xapFilePath);
+
+ Log("Launching app on " + deviceConn.Name);
+ app.Launch();
+
+ // To Stop :
+ //app.TerminateRunningInstances();
+
+ device.Disconnect();
+
+ ReadWait();
+
+ }
+ catch (Exception ex)
+ {
+ Log("Error :: " + ex.Message, true);
+ }
+ }
+
+ // To read and write ISO storage files!! :
+ /*
+ try
+ {
+ IRemoteIsolatedStorageFile isoStore = app.GetIsolatedStore();
+ remoteIsolatedStorageFile.ReceiveFile("sourcePath", "destPath", true);
+ }
+ catch (Exception ex) { }
+ */
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy/Properties/AssemblyInfo.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy/Properties/AssemblyInfo.cs b/lib/cordova-wp8/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..3c26c87
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("CordovaDeploy")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("CordovaDeploy")]
+[assembly: AssemblyCopyright("Copyright © 2012")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("256b11aa-d4bb-48cf-8024-7c040421fa8d")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy/app.config
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy/app.config b/lib/cordova-wp8/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy/app.config
new file mode 100644
index 0000000..c5e1dae
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy/app.config
@@ -0,0 +1,3 @@
+<?xml version="1.0"?>
+<configuration>
+<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/></startup></configuration>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordova/lib/build.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordova/lib/build.js b/lib/cordova-wp8/templates/standalone/cordova/lib/build.js
new file mode 100644
index 0000000..9986a7e
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordova/lib/build.js
@@ -0,0 +1,181 @@
+/*
+ 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.
+*/
+
+
+var fso = WScript.CreateObject('Scripting.FileSystemObject');
+var wscript_shell = WScript.CreateObject("WScript.Shell");
+
+var args = WScript.Arguments;
+
+// working dir
+var ROOT = WScript.ScriptFullName.split('\\cordova\\lib\\build.js').join('');
+
+// help/usage function
+function Usage() {
+ Log("");
+ Log("Usage: build [ --debug | --release ]");
+ Log(" --help : Displays this dialog.");
+ Log(" --debug : Cleans and builds project in debug mode.");
+ Log(" --release : Cleans and builds project in release mode.");
+ Log("examples:");
+ Log(" build ");
+ Log(" build --debug");
+ Log(" build --release");
+ Log("");
+}
+
+// logs messaged to stdout and stderr
+function Log(msg, error) {
+ if (error) {
+ WScript.StdErr.WriteLine(msg);
+ }
+ else {
+ WScript.StdOut.WriteLine(msg);
+ }
+}
+
+// executes a commmand in the shell
+function exec_verbose(command) {
+ //Log("Command: " + command);
+ var oShell=wscript_shell.Exec(command);
+ while (oShell.Status == 0) {
+ //Wait a little bit so we're not super looping
+ WScript.sleep(100);
+ //Print any stdout output from the script
+ if (!oShell.StdOut.AtEndOfStream) {
+ var line = oShell.StdOut.ReadLine();
+ Log(line);
+ }
+ }
+ //Check to make sure our scripts did not encounter an error
+ if (!oShell.StdErr.AtEndOfStream) {
+ var line = oShell.StdErr.ReadAll();
+ Log(line, true);
+ WScript.Quit(2);
+ }
+}
+
+// checks to see if a .csproj file exists in the project root
+function is_cordova_project(path) {
+ if (fso.FolderExists(path)) {
+ var proj_folder = fso.GetFolder(path);
+ var proj_files = new Enumerator(proj_folder.Files);
+ for (;!proj_files.atEnd(); proj_files.moveNext()) {
+ if (fso.GetExtensionName(proj_files.item()) == 'csproj') {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+// builds the project and .xap in release mode
+function build_xap_release(path) {
+ Log("Building Cordova-WP8 Project:");
+ Log("\tConfiguration : Release");
+ Log("\tDirectory : " + path);
+
+ wscript_shell.CurrentDirectory = path;
+ exec_verbose('msbuild /clp:NoSummary;NoItemAndPropertyList;Verbosity=minimal /nologo /p:Configuration=Release');
+
+ // check if file xap was created
+ if (fso.FolderExists(path + '\\Bin\\Release')) {
+ var out_folder = fso.GetFolder(path + '\\Bin\\Release');
+ var out_files = new Enumerator(out_folder.Files);
+ for (;!out_files.atEnd(); out_files.moveNext()) {
+ if (fso.GetExtensionName(out_files.item()) == 'xap') {
+ Log("BUILD SUCCESS.");
+ return;
+ }
+ }
+ }
+ Log('ERROR: MSBuild failed to create .xap when building cordova-wp8 for release.', true);
+ WScript.Quit(2);
+}
+
+// builds the project and .xap in debug mode
+function build_xap_debug(path) {
+ Log("Building Cordova-WP8 Project:");
+ Log("\tConfiguration : Debug");
+ Log("\tDirectory : " + path);
+
+ wscript_shell.CurrentDirectory = path;
+ exec_verbose('msbuild /clp:NoSummary;NoItemAndPropertyList;Verbosity=minimal /nologo /p:Configuration=Debug');
+
+ // check if file xap was created
+ if (fso.FolderExists(path + '\\Bin\\Debug')) {
+ var out_folder = fso.GetFolder(path + '\\Bin\\Debug');
+ var out_files = new Enumerator(out_folder.Files);
+ for (;!out_files.atEnd(); out_files.moveNext()) {
+ if (fso.GetExtensionName(out_files.item()) == 'xap') {
+ Log("BUILD SUCCESS.");
+ return;
+ }
+ }
+ }
+ Log('ERROR: MSBuild failed to create .xap when building cordova-wp8 for debugging.', true);
+ WScript.Quit(2);
+}
+
+
+Log("");
+
+if (args.Count() > 0) {
+ // support help flags
+ if (args(0) == "--help" || args(0) == "/?" ||
+ args(0) == "help" || args(0) == "-help" || args(0) == "/help") {
+ Usage();
+ WScript.Quit(2);
+ }
+ else if (args.Count() > 1) {
+ Log("Error: Too many arguments.", true);
+ Usage();
+ WScript.Quit(2);
+ }
+ else if (fso.FolderExists(ROOT)) {
+ if (!is_cordova_project(ROOT)) {
+ Log('Error: .csproj file not found in ' + ROOT, true);
+ Log('could not build project.', true);
+ WScript.Quit(2);
+ }
+
+ if (args(0) == "--debug" || args(0) == "-d") {
+ exec_verbose('%comspec% /c ' + ROOT + '\\cordova\\clean');
+ build_xap_debug(ROOT);
+ }
+ else if (args(0) == "--release" || args(0) == "-r") {
+ exec_verbose('%comspec% /c ' + ROOT + '\\cordova\\clean');
+ build_xap_release(ROOT);
+ }
+ else {
+ Log("Error: \"" + args(0) + "\" is not recognized as a build option", true);
+ Usage();
+ WScript.Quit(2);
+ }
+ }
+ else {
+ Log("Error: Project directory not found,", true);
+ Usage();
+ WScript.Quit(2);
+ }
+}
+else {
+ Log("WARNING: [ --debug | --release ] not specified, defaulting to debug...");
+ build_xap_debug(ROOT);
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordova/lib/clean.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordova/lib/clean.js b/lib/cordova-wp8/templates/standalone/cordova/lib/clean.js
new file mode 100644
index 0000000..3a8c871
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordova/lib/clean.js
@@ -0,0 +1,124 @@
+/*
+ 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.
+*/
+
+
+var fso = WScript.CreateObject('Scripting.FileSystemObject');
+var wscript_shell = WScript.CreateObject("WScript.Shell");
+var args = WScript.Arguments;
+// working dir
+var ROOT = WScript.ScriptFullName.split('\\cordova\\lib\\clean.js').join('');
+
+
+// help function
+function Usage() {
+ Log("");
+ Log("Usage: clean [ --debug | --release ]");
+ Log(" --debug : Cleans generated debug files in project.");
+ Log(" --release : Cleans generated release files in project.");
+ Log("examples:");
+ Log(" clean --debug");
+ Log(" clean");
+ Log(" - deletes all generated files in project");
+ Log("");
+}
+
+// logs to stdout or stderr
+function Log(msg, error) {
+ if (error) {
+ WScript.StdErr.WriteLine(msg);
+ }
+ else {
+ WScript.StdOut.WriteLine(msg);
+ }
+}
+
+// cleans any generated files in the cordova project
+function clean_project(path) {
+ if (fso.FolderExists(path + "\\obj")) {
+ fso.DeleteFolder(path + "\\obj");
+ }
+ if (fso.FolderExists(path + "\\Bin")) {
+ fso.DeleteFolder(path + "\\Bin");
+ }
+ //TODO: delete CordovaAppProj.csproj.user as well? Service References?
+}
+
+// cleans any files generated by build --debug
+function clean_debug(path) {
+ if (fso.FolderExists(path + "\\obj\\Debug")) {
+ fso.DeleteFolder(path + "\\obj\\Debug");
+ }
+ if (fso.FolderExists(path + "\\Bin\\Debug")) {
+ fso.DeleteFolder(path + "\\Bin\\Debug");
+ }
+}
+
+// cleans any files generated by build --release
+function clean_release(path) {
+ if (fso.FolderExists(path + "\\obj\\Release")) {
+ fso.DeleteFolder(path + "\\obj\\Release");
+ }
+ if (fso.FolderExists(path + "\\Bin\\Release")) {
+ fso.DeleteFolder(path + "\\Bin\\Release");
+ }
+}
+
+
+if (args.Count() > 0) {
+ // support help flags
+ if (args(0) == "--help" || args(0) == "/?" ||
+ args(0) == "help" || args(0) == "-help" || args(0) == "/help") {
+ Usage();
+ WScript.Quit(2);
+ }
+ else if (args.Count() > 1) {
+ Log("Error: Too many arguments.", true);
+ Usage();
+ WScript.Quit(2);
+ }
+ else if (fso.FolderExists(ROOT)) {
+ if (args(0) == "--debug" || args(0) == "-d") {
+ clean_debug(ROOT);
+ }
+ else if (args(0) == "--release" || args(0) == "-r") {
+ clean_release(ROOT);
+ }
+ else {
+ Log("Error: \"" + args(0) + "\" is not recognized as a build option", true);
+ Usage();
+ WScript.Quit(2);
+ }
+ }
+ else {
+ Log("Error: Project directory not found,", true);
+ Usage();
+ WScript.Quit(2);
+ }
+}
+else {
+ if (fso.FolderExists(ROOT)) {
+ Log("Cleaning cordova project...");
+ clean_project(ROOT);
+ }
+ else {
+ Log("Error: Project directory not found,", true);
+ Usage();
+ WScript.Quit(2);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordova/lib/deploy.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordova/lib/deploy.js b/lib/cordova-wp8/templates/standalone/cordova/lib/deploy.js
new file mode 100644
index 0000000..29a3f7d
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordova/lib/deploy.js
@@ -0,0 +1,326 @@
+/*
+ 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.
+*/
+
+
+var fso = WScript.CreateObject('Scripting.FileSystemObject');
+var wscript_shell = WScript.CreateObject("WScript.Shell");
+
+var args = WScript.Arguments;
+// working dir
+var ROOT = WScript.ScriptFullName.split('\\cordova\\lib\\deploy.js').join('');
+ // path to CordovaDeploy.exe
+var CORDOVA_DEPLOY_EXE = '\\cordova\\lib\\CordovaDeploy\\CordovaDeploy\\bin\\Debug\\CordovaDeploy.exe';
+ // path to CordovaDeploy
+var CORDOVA_DEPLOY = '\\cordova\\lib\\CordovaDeploy';
+
+//build types
+var NONE = 0,
+ DEBUG = 1,
+ RELEASE = 2,
+ NO_BUILD = 3;
+var build_type = NONE;
+
+
+// help function
+function Usage() {
+ Log("");
+ Log("Usage: run [ --device | --emulator | --target=<id> ] [ --debug | --release | --nobuild ]");
+ Log(" --device : Deploys and runs the project on the connected device.");
+ Log(" --emulator : Deploys and runs the project on an emulator.");
+ Log(" --target=<id> : Deploys and runs the project on the specified target.");
+ Log(" --debug : Builds project in debug mode.");
+ Log(" --release : Builds project in release mode.");
+ Log(" --nobuild : Ueses pre-built xap, or errors if project is not built.");
+ Log("examples:");
+ Log(" run");
+ Log(" run --emulator");
+ Log(" run --device");
+ Log(" run --target=7988B8C3-3ADE-488d-BA3E-D052AC9DC710");
+ Log(" run --device --release");
+ Log(" run --emulator --debug");
+ Log("");
+}
+
+// log to stdout or stderr
+function Log(msg, error) {
+ if (error) {
+ WScript.StdErr.WriteLine(msg);
+ }
+ else {
+ WScript.StdOut.WriteLine(msg);
+ }
+}
+
+var ForReading = 1, ForWriting = 2, ForAppending = 8;
+var TristateUseDefault = 2, TristateTrue = 1, TristateFalse = 0;
+
+
+// executes a commmand in the shell
+function exec(command) {
+ var oShell=wscript_shell.Exec(command);
+ while (oShell.Status == 0) {
+ WScript.sleep(100);
+ }
+}
+
+// executes a commmand in the shell
+function exec_verbose(command) {
+ //Log("Command: " + command);
+ var oShell=wscript_shell.Exec(command);
+ while (oShell.Status == 0) {
+ //Wait a little bit so we're not super looping
+ WScript.sleep(100);
+ //Print any stdout output from the script
+ if (!oShell.StdOut.AtEndOfStream) {
+ var line = oShell.StdOut.ReadAll();
+ Log(line);
+ }
+ }
+ //Check to make sure our scripts did not encounter an error
+ if (!oShell.StdErr.AtEndOfStream) {
+ var line = oShell.StdErr.ReadAll();
+ Log(line, true);
+ WScript.Quit(2);
+ }
+}
+
+// returns the contents of a file
+function read(filename) {
+ if (fso.FileExists(filename)) {
+ var f=fso.OpenTextFile(filename, 1,2);
+ var s=f.ReadAll();
+ f.Close();
+ return s;
+ }
+ else {
+ Log('Cannot read non-existant file : ' + filename, true);
+ WScript.Quit(2);
+ }
+ return null;
+}
+
+// builds the CordovaDeploy.exe if it does not already exist
+function cordovaDeploy(path) {
+ if (fso.FileExists(path + CORDOVA_DEPLOY_EXE)) {
+ return;
+ }
+
+ Log('CordovaDeploy.exe not found, attempting to build CordovaDeploy.exe...');
+
+ // build CordovaDeploy.exe
+ if (fso.FolderExists(path + '\\cordova') && fso.FolderExists(path + CORDOVA_DEPLOY) &&
+ fso.FileExists(path + CORDOVA_DEPLOY + '\\CordovaDeploy.sln')) {
+ // delete any previously generated files
+ if (fso.FolderExists(path + CORDOVA_DEPLOY + '\\CordovaDeploy\\obj')) {
+ fso.DeleteFolder(path + CORDOVA_DEPLOY + '\\CordovaDeploy\\obj');
+ }
+ if (fso.FolderExists(path + CORDOVA_DEPLOY + '\\CordovaDeploy\\Bin')) {
+ fso.DeleteFolder(path + CORDOVA_DEPLOY + '\\CordovaDeploy\\Bin');
+ }
+ exec_verbose('msbuild ' + path + CORDOVA_DEPLOY + '\\CordovaDeploy.sln');
+
+ if (fso.FileExists(path + CORDOVA_DEPLOY_EXE)) {
+ Log('CordovaDeploy.exe compiled, SUCCESS.');
+ }
+ else {
+ Log('ERROR: MSBUILD FAILED TO COMPILE CordovaDeploy.exe', true);
+ WScript.Quit(2);
+ }
+ }
+ else {
+ Log('ERROR: CordovaDeploy.sln not found, unable to compile CordovaDeploy tool.', true);
+ WScript.Quit(2);
+ }
+}
+
+// launches project on device
+function device(path)
+{
+ cordovaDeploy(path);
+ if (fso.FileExists(path + CORDOVA_DEPLOY_EXE)) {
+ Log('Deploying to device ...');
+ //TODO: get device ID from list-devices and deploy to first one
+ exec_verbose('%comspec% /c ' + path + CORDOVA_DEPLOY_EXE + ' ' + path + ' -d:0');
+ }
+ else
+ {
+ Log('Error: Failed to find CordovaDeploy.exe in ' + path, true);
+ Log('DEPLOY FAILED.', true);
+ WScript.Quit(2);
+ }
+}
+
+// launches project on emulator
+function emulator(path)
+{
+ cordovaDeploy(path);
+ if (fso.FileExists(path + CORDOVA_DEPLOY_EXE)) {
+ Log('Deploying to emulator ...');
+ //TODO: get emulator ID from list-emulators and deploy to first one
+ exec_verbose('%comspec% /c ' + path + CORDOVA_DEPLOY_EXE + ' ' + path + ' -d:1');
+ }
+ else
+ {
+ Log('Error: Failed to find CordovaDeploy.exe in ' + path, true);
+ Log('DEPLOY FAILED.', true);
+ WScript.Quit(2);
+ }
+}
+
+// builds and launches the project on the specified target
+function target(path, device_id) {
+ if (!fso.FileExists(path + CORDOVA_DEPLOY_EXE)) {
+ cordovaDeploy(path);
+ }
+ wscript_shell.CurrentDirectory = path + CORDOVA_DEPLOY + '\\CordovaDeploy\\bin\\Debug';
+ var cmd = 'CordovaDeploy -devices';
+ var out = wscript_shell.Exec(cmd);
+ while(out.Status == 0) {
+ WScript.Sleep(100);
+ }
+ if (!out.StdErr.AtEndOfStream) {
+ var line = out.StdErr.ReadAll();
+ Log("Error calling CordovaDeploy : ", true);
+ Log(line, true);
+ WScript.Quit(2);
+ }
+ else {
+ if (!out.StdOut.AtEndOfStream) {
+ var line = out.StdOut.ReadAll();
+ var targets = line.split('\r\n');
+ var check_id = new RegExp(device_id);
+ for (target in targets) {
+ if (targets[target].match(check_id)) {
+ //TODO: this only gets single digit index, account for device index of 10+?
+ var index = targets[target].substr(0,1);
+ exec_verbose(path + CORDOVA_DEPLOY_EXE + ' ' + path + ' -d:' + index);
+ return;
+ }
+ }
+ Log('Error : target ' + device_id + ' was not found.', true);
+ Log('DEPLOY FAILED.', true);
+ WScript.Quit(2);
+ }
+ else {
+ Log('Error : CordovaDeploy Failed to find any devices', true);
+ Log('DEPLOY FAILED.', true);
+ WScript.Quit(2);
+ }
+ }
+}
+
+function build(path) {
+ switch (build_type) {
+ case DEBUG :
+ exec_verbose('%comspec% /c ' + ROOT + '\\cordova\\build --debug');
+ break;
+ case RELEASE :
+ exec_verbose('%comspec% /c ' + ROOT + '\\cordova\\build --release');
+ break;
+ case NO_BUILD :
+ break;
+ case NONE :
+ Log("WARNING: [ --debug | --release | --nobuild ] not specified, defaulting to --debug.");
+ exec_verbose('%comspec% /c ' + ROOT + '\\cordova\\build --debug');
+ break;
+ default :
+ Log("Build option not recognized: " + build_type, true);
+ WScript.Quit(2);
+ break;
+ }
+}
+
+
+if (args.Count() > 0) {
+ // support help flags
+ if (args(0) == "--help" || args(0) == "/?" ||
+ args(0) == "help" || args(0) == "-help" || args(0) == "/help") {
+ Usage();
+ WScript.Quit(2);
+ }
+ else if (args.Count() > 2) {
+ Log('Error: Too many arguments.', true);
+ Usage();
+ WScript.Quit(2);
+ }
+ else if (fso.FolderExists(ROOT)) {
+ if (args.Count() > 1) {
+ if (args(1) == "--release") {
+ build_type = RELEASE;
+ }
+ else if (args(1) == "--debug") {
+ build_type = DEBUG;
+ }
+ else if (args(1) == "--nobuild") {
+ build_type = NO_BUILD;
+ }
+ else {
+ Log('Error: \"' + args(1) + '\" is not recognized as a deploy option', true);
+ Usage();
+ WScript.Quit(2);
+ }
+ }
+
+ if (args(0) == "--emulator" || args(0) == "-e") {
+ build(ROOT);
+ emulator(ROOT);
+ }
+ else if (args(0) == "--device" || args(0) == "-d") {
+ build(ROOT);
+ device(ROOT);
+ }
+ else if (args(0).substr(0,9) == "--target=") {
+ build(ROOT);
+ var device_id = args(0).split("--target=").join("");
+ target(ROOT, device_id);
+ }
+ else {
+ Log("WARNING: [ --target=<ID> | --emulator | --device ] not specified, defaulting to --emulator");
+ if (args(0) == "--release") {
+ build_type = RELEASE;
+ build(ROOT);
+ emulator(ROOT);
+ }
+ else if (args(0) == "--debug") {
+ build_type = DEBUG;
+ build(ROOT);
+ emulator(ROOT);
+ }
+ else if (args(0) == "--nobuild") {
+ build_type = NO_BUILD;
+ emulator(ROOT);
+ }
+ else {
+ Log('Error: \"' + args(0) + '\" is not recognized as a deploy option', true);
+ Usage();
+ WScript.Quit(2);
+ }
+ }
+ }
+ else {
+ Log('Error: Project directory not found,', true);
+ Usage();
+ WScript.Quit(2);
+ }
+}
+else {
+ Log("WARNING: [ --target=<ID> | --emulator | --device ] not specified, defaulting to --emulator");
+ build(ROOT);
+ emulator(ROOT);
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordova/lib/install-device.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordova/lib/install-device.bat b/lib/cordova-wp8/templates/standalone/cordova/lib/install-device.bat
new file mode 100644
index 0000000..9507c36
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordova/lib/install-device.bat
@@ -0,0 +1,9 @@
+@ECHO OFF
+SET full_path=%~dp0
+IF EXIST %full_path%deploy.js (
+ cscript "%full_path%deploy.js" %* --device --nobuild //nologo
+) ELSE (
+ ECHO.
+ ECHO ERROR: Could not find 'deploy.js' in cordova/lib, aborting...>&2
+ EXIT /B 1
+)
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordova/lib/install-emulator.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordova/lib/install-emulator.bat b/lib/cordova-wp8/templates/standalone/cordova/lib/install-emulator.bat
new file mode 100644
index 0000000..b3ee451
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordova/lib/install-emulator.bat
@@ -0,0 +1,9 @@
+@ECHO OFF
+SET full_path=%~dp0
+IF EXIST %full_path%deploy.js (
+ cscript "%full_path%deploy.js" %* --emulator --nobuild //nologo
+) ELSE (
+ ECHO.
+ ECHO ERROR: Could not find 'deploy.js' in cordova/lib, aborting...>&2
+ EXIT /B 1
+)
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordova/lib/list-devices.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordova/lib/list-devices.bat b/lib/cordova-wp8/templates/standalone/cordova/lib/list-devices.bat
new file mode 100644
index 0000000..bf4492b
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordova/lib/list-devices.bat
@@ -0,0 +1,9 @@
+@ECHO OFF
+SET full_path=%~dp0
+IF EXIST %full_path%target-list.js (
+ cscript "%full_path%target-list.js" %* --devices //nologo
+) ELSE (
+ ECHO.
+ ECHO ERROR: Could not find 'target-list.js' in cordova/lib, aborting...>&2
+ EXIT /B 1
+)
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordova/lib/list-emulator-images.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordova/lib/list-emulator-images.bat b/lib/cordova-wp8/templates/standalone/cordova/lib/list-emulator-images.bat
new file mode 100644
index 0000000..3f571c7
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordova/lib/list-emulator-images.bat
@@ -0,0 +1,9 @@
+@ECHO OFF
+SET full_path=%~dp0
+IF EXIST %full_path%target-list.js (
+ cscript "%full_path%target-list.js" %* --emulators //nologo
+) ELSE (
+ ECHO.
+ ECHO ERROR: Could not find 'target-list.js' in cordova/lib, aborting...>&2
+ EXIT /B 1
+)
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordova/lib/list-started-emulators.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordova/lib/list-started-emulators.bat b/lib/cordova-wp8/templates/standalone/cordova/lib/list-started-emulators.bat
new file mode 100644
index 0000000..d779b5d
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordova/lib/list-started-emulators.bat
@@ -0,0 +1,3 @@
+@ECHO OFF
+ECHO Sorry, list-started-emulators is not availible yet for Windows Phone. 1>&2
+EXIT /B 1
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordova/lib/log.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordova/lib/log.js b/lib/cordova-wp8/templates/standalone/cordova/lib/log.js
new file mode 100644
index 0000000..0b4ea7d
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordova/lib/log.js
@@ -0,0 +1,77 @@
+/*
+ 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.
+*/
+
+
+var fso = WScript.CreateObject('Scripting.FileSystemObject');
+var wscript_shell = WScript.CreateObject("WScript.Shell");
+var args = WScript.Arguments;
+// working dir
+var ROOT = WScript.ScriptFullName.split('\\cordova\\lib\\log.js').join('');
+
+
+// help function
+function Usage() {
+ Log("");
+ Log("Usage: log");
+ Log("examples:");
+ Log(" log");
+ Log(" - logs output from running application *NOT IMPLIMENTED*");
+ Log("");
+}
+
+// logs to stdout or stderr
+function Log(msg, error) {
+ if (error) {
+ WScript.StdErr.WriteLine(msg);
+ }
+ else {
+ WScript.StdOut.WriteLine(msg);
+ }
+}
+
+// log output from running projects *NOT IMPLEMENTED*
+function log_output(path) {
+ Log("ERROR: Logging is not supported on Windows Phone", true);
+ WScript.Quit(1);
+}
+
+
+if (args.Count() > 0) {
+ // support help flags
+ if (args(0) == "--help" || args(0) == "/?" ||
+ args(0) == "help" || args(0) == "-help" || args(0) == "/help") {
+ Usage();
+ WScript.Quit(2);
+ }
+ else {
+ Log("Error: \"" + args(0) + "\" is not recognized as a log option.", true);
+ Usage();
+ WScript.Quit(2);
+ }
+}
+else {
+ if (fso.FolderExists(ROOT)) {
+ log_output(ROOT);
+ }
+ else {
+ Log("Error: Project directory not found,", true);
+ Usage();
+ WScript.Quit(2);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordova/lib/start-emulator.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordova/lib/start-emulator.bat b/lib/cordova-wp8/templates/standalone/cordova/lib/start-emulator.bat
new file mode 100644
index 0000000..19983fd
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordova/lib/start-emulator.bat
@@ -0,0 +1,3 @@
+@ECHO OFF
+ECHO Sorry, start-emulator is not availible yet for Windows Phone. 1>&2
+EXIT /B 1
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordova/lib/target-list.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordova/lib/target-list.js b/lib/cordova-wp8/templates/standalone/cordova/lib/target-list.js
new file mode 100644
index 0000000..805eea5
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordova/lib/target-list.js
@@ -0,0 +1,233 @@
+/*
+ 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.
+*/
+
+
+var fso = WScript.CreateObject('Scripting.FileSystemObject');
+var wscript_shell = WScript.CreateObject("WScript.Shell");
+
+var args = WScript.Arguments;
+// working dir
+var ROOT = WScript.ScriptFullName.split('\\cordova\\lib\\target-list.js').join('');
+ // path to CordovaDeploy.exe
+var CORDOVA_DEPLOY_EXE = '\\cordova\\lib\\CordovaDeploy\\CordovaDeploy\\bin\\Debug\\CordovaDeploy.exe';
+ // path to CordovaDeploy
+var CORDOVA_DEPLOY = '\\cordova\\lib\\CordovaDeploy';
+
+// help/usage function
+function Usage() {
+ Log("");
+ Log("Usage: cscript target-list.js [ --emulators | --devices | --started_emulators | --all ]");
+ Log(" --emulators : List the possible target emulators availible.");
+ Log(" --devices : List the possible target devices availible. *NOT IMPLEMENTED YET*");
+ Log(" --started_emulators : List any started emulators availible. *NOT IMPLEMENTED YET*");
+ Log(" --all : List all devices returned by CordovaDeploy.exe -devices ");
+ Log("examples:");
+ Log(" cscript target-list.js --emulators");
+ Log(" cscript target-list.js --devices");
+ Log(" cscript target-list.js --started_emulators");
+ Log(" cscript target-list.js --all");
+ Log("");
+}
+
+// logs messaged to stdout and stderr
+function Log(msg, error) {
+ if (error) {
+ WScript.StdErr.WriteLine(msg);
+ }
+ else {
+ WScript.StdOut.WriteLine(msg);
+ }
+}
+
+// executes a commmand in the shell
+function exec(command) {
+ var oShell=wscript_shell.Exec(command);
+ while (oShell.Status == 0) {
+ //Wait a little bit so we're not super looping
+ WScript.sleep(100);
+ //Print output? Naa.....
+ if (!oShell.StdOut.AtEndOfStream) {
+ var line = oShell.StdOut.ReadAll();
+ //Log(line);
+ }
+ }
+ //Check to make sure our scripts did not encounter an error
+ if (!oShell.StdErr.AtEndOfStream) {
+ var line = oShell.StdErr.ReadAll();
+ Log(line, true);
+ WScript.Quit(2);
+ }
+}
+
+// returns all possible targets generated by the CordovaDeploy tool
+function get_targets(path) {
+ if (!fso.FileExists(path + CORDOVA_DEPLOY_EXE)) {
+ cordovaDeploy(path);
+ }
+ wscript_shell.CurrentDirectory = path + CORDOVA_DEPLOY + '\\CordovaDeploy\\bin\\Debug';
+ var cmd = 'CordovaDeploy -devices';
+ var out = wscript_shell.Exec(cmd);
+ while(out.Status == 0) {
+ WScript.Sleep(100);
+ }
+ //Check to make sure our script did not encounter an error
+ if (!out.StdErr.AtEndOfStream) {
+ var line = out.StdErr.ReadAll();
+ Log("Error calling CordovaDeploy : ", true);
+ Log(line, true);
+ WScript.Quit(2);
+ }
+ else {
+ if (!out.StdOut.AtEndOfStream) {
+ var line = out.StdOut.ReadAll();
+ var targets = line.split('\r\n');
+ //format (ID DESCRIPTION)
+ for (i in targets) {
+ // remove device index and separator colen
+ targets[i] = targets[i].replace(/\d*\s\:\s/, '').replace(/\:\s/, '');
+ }
+ return targets;
+ }
+ else {
+ Log('Error : CordovaDeploy Failed to find any devices', true);
+ WScript.Quit(2);
+ }
+ }
+}
+
+function list_targets(path) {
+ var targets = get_targets(path);
+ for (i in targets) {
+ Log(targets[i]);
+ }
+}
+
+// lists the Device returned by CordovaDeploy (NOTE: this does not indicate that a device is connected)
+function list_devices(path) {
+ var targets = get_targets(path);
+ var device_found = false;
+ for (i in targets) {
+ if (targets[i].match(/Device/)) {
+ Log(targets[i]);
+ device_found = true;
+ }
+ }
+ if (device_found) {
+ Log('');
+ Log('WARNING : This does not mean that a device is connected, make');
+ Log(' sure your device is connected before deploying to it.');
+ }
+}
+
+// lists the emulators availible to CordovaDeploy
+function list_emulator_images(path) {
+ var targets = get_targets(path);
+ for (i in targets) {
+ if (targets[i].match(/Emulator/)) {
+ Log(targets[i]);
+ }
+ }
+}
+
+// lists any started emulators *NOT IMPLEMENTED*
+function list_started_emulators(path) {
+ Log('ERROR : list-started-emulators is not supported on Windows Phone.', true);
+ WScript.Quit(1);
+}
+
+// builds the CordovaDeploy.exe if it does not already exist
+function cordovaDeploy(path) {
+ if (fso.FileExists(path + CORDOVA_DEPLOY_EXE)) {
+ return;
+ }
+
+ // build CordovaDeploy.exe
+ if (fso.FolderExists(path + '\\cordova') && fso.FolderExists(path + CORDOVA_DEPLOY) &&
+ fso.FileExists(path + CORDOVA_DEPLOY + '\\CordovaDeploy.sln')) {
+ // delete any previously generated files
+ if (fso.FolderExists(path + CORDOVA_DEPLOY + "\\CordovaDeploy\\obj")) {
+ fso.DeleteFolder(path + CORDOVA_DEPLOY + "\\CordovaDeploy\\obj");
+ }
+ if (fso.FolderExists(path + CORDOVA_DEPLOY + "\\CordovaDeploy\\Bin")) {
+ fso.DeleteFolder(path + CORDOVA_DEPLOY + "\\CordovaDeploy\\Bin");
+ }
+ exec('msbuild ' + path + CORDOVA_DEPLOY + '\\CordovaDeploy.sln');
+
+ if (fso.FileExists(path + CORDOVA_DEPLOY_EXE)) {
+ return;
+ }
+ else {
+ Log("ERROR: MSBUILD FAILED TO COMPILE CordovaDeploy.exe", true);
+ WScript.Quit(2);
+ }
+ }
+ else {
+ Log("ERROR: CordovaDeploy.sln not found, unable to compile CordovaDeploy tool.", true);
+ WScript.Quit(2);
+ }
+}
+
+
+if (args.Count() > 0) {
+ // support help flags
+ if (args(0) == "--help" || args(0) == "/?" ||
+ args(0) == "help" || args(0) == "-help" || args(0) == "/help") {
+ Usage();
+ WScript.Quit(2);
+ }
+ else if (args.Count() > 1) {
+ Log("Error: Too many arguments.", true);
+ Usage();
+ WScript.Quit(2);
+ }
+ else if (fso.FolderExists(ROOT)) {
+ if (!fso.FolderExists(ROOT + '\\cordova')) {
+ Log("Error: cordova tooling folder not found in project directory,", true);
+ Log("could not lsit targets.", true);
+ WScript.Quit(2);
+ }
+
+ if (args(0) == "--emulators" || args(0) == "-e") {
+ list_emulator_images(ROOT);
+ }
+ else if (args(0) == "--devices" || args(0) == "-d") {
+ list_devices(ROOT);
+ }
+ else if (args(0) == "--started_emulators" || args(0) == "-s") {
+ list_started_emulators(ROOT);
+ }
+ else if (args(0) == "--all" || args(0) == "-a") {
+ list_targets(ROOT);
+ }
+ else {
+ Log("Error: \"" + args(0) + "\" is not recognized as a target-list option", true);
+ Usage();
+ WScript.Quit(2);
+ }
+ }
+ else {
+ Log("Error: Project directory not found,", true);
+ Usage();
+ WScript.Quit(2);
+ }
+}
+else {
+ Log("WARNING: target list not specified, showing all targets...");
+ list_targets(ROOT);
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordova/log.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordova/log.bat b/lib/cordova-wp8/templates/standalone/cordova/log.bat
new file mode 100644
index 0000000..46dbe5c
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordova/log.bat
@@ -0,0 +1,3 @@
+@ECHO OFF
+ECHO Sorry, loging is yet supported for Windows Phone. 1>&2
+EXIT /B 1
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordova/run.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordova/run.bat b/lib/cordova-wp8/templates/standalone/cordova/run.bat
new file mode 100644
index 0000000..b966856
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordova/run.bat
@@ -0,0 +1,9 @@
+@ECHO OFF
+SET full_path=%~dp0
+IF EXIST %full_path%lib\deploy.js (
+ cscript "%full_path%lib\deploy.js" %* //nologo
+) ELSE (
+ ECHO.
+ ECHO ERROR: Could not find 'deploy.js' in cordova/lib, aborting...>&2
+ EXIT /B 1
+)
[10/37] Add WP7 and WP8 platform files.
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/jasmine.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/jasmine.js b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/jasmine.js
new file mode 100644
index 0000000..bccb66c
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/jasmine.js
@@ -0,0 +1,2530 @@
+var isCommonJS = typeof window == "undefined";
+
+/**
+ * Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework.
+ *
+ * @namespace
+ */
+var jasmine = {};
+if (isCommonJS) exports.jasmine = jasmine;
+/**
+ * @private
+ */
+jasmine.unimplementedMethod_ = function() {
+ throw new Error("unimplemented method");
+};
+
+/**
+ * Use <code>jasmine.undefined</code> instead of <code>undefined</code>, since <code>undefined</code> is just
+ * a plain old variable and may be redefined by somebody else.
+ *
+ * @private
+ */
+jasmine.undefined = jasmine.___undefined___;
+
+/**
+ * Show diagnostic messages in the console if set to true
+ *
+ */
+jasmine.VERBOSE = false;
+
+/**
+ * Default interval in milliseconds for event loop yields (e.g. to allow network activity or to refresh the screen with the HTML-based runner). Small values here may result in slow test running. Zero means no updates until all tests have completed.
+ *
+ */
+jasmine.DEFAULT_UPDATE_INTERVAL = 250;
+
+/**
+ * Default timeout interval in milliseconds for waitsFor() blocks.
+ */
+jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
+
+jasmine.getGlobal = function() {
+ function getGlobal() {
+ return this;
+ }
+
+ return getGlobal();
+};
+
+/**
+ * Allows for bound functions to be compared. Internal use only.
+ *
+ * @ignore
+ * @private
+ * @param base {Object} bound 'this' for the function
+ * @param name {Function} function to find
+ */
+jasmine.bindOriginal_ = function(base, name) {
+ var original = base[name];
+ if (original.apply) {
+ return function() {
+ return original.apply(base, arguments);
+ };
+ } else {
+ // IE support
+ return jasmine.getGlobal()[name];
+ }
+};
+
+jasmine.setTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'setTimeout');
+jasmine.clearTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearTimeout');
+jasmine.setInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'setInterval');
+jasmine.clearInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearInterval');
+
+jasmine.MessageResult = function(values) {
+ this.type = 'log';
+ this.values = values;
+ this.trace = new Error(); // todo: test better
+};
+
+jasmine.MessageResult.prototype.toString = function() {
+ var text = "";
+ for (var i = 0; i < this.values.length; i++) {
+ if (i > 0) text += " ";
+ if (jasmine.isString_(this.values[i])) {
+ text += this.values[i];
+ } else {
+ text += jasmine.pp(this.values[i]);
+ }
+ }
+ return text;
+};
+
+jasmine.ExpectationResult = function(params) {
+ this.type = 'expect';
+ this.matcherName = params.matcherName;
+ this.passed_ = params.passed;
+ this.expected = params.expected;
+ this.actual = params.actual;
+ this.message = this.passed_ ? 'Passed.' : params.message;
+
+ var trace = (params.trace || new Error(this.message));
+ this.trace = this.passed_ ? '' : trace;
+};
+
+jasmine.ExpectationResult.prototype.toString = function () {
+ return this.message;
+};
+
+jasmine.ExpectationResult.prototype.passed = function () {
+ return this.passed_;
+};
+
+/**
+ * Getter for the Jasmine environment. Ensures one gets created
+ */
+jasmine.getEnv = function() {
+ var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env();
+ return env;
+};
+
+/**
+ * @ignore
+ * @private
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isArray_ = function(value) {
+ return jasmine.isA_("Array", value);
+};
+
+/**
+ * @ignore
+ * @private
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isString_ = function(value) {
+ return jasmine.isA_("String", value);
+};
+
+/**
+ * @ignore
+ * @private
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isNumber_ = function(value) {
+ return jasmine.isA_("Number", value);
+};
+
+/**
+ * @ignore
+ * @private
+ * @param {String} typeName
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isA_ = function(typeName, value) {
+ return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
+};
+
+/**
+ * Pretty printer for expecations. Takes any object and turns it into a human-readable string.
+ *
+ * @param value {Object} an object to be outputted
+ * @returns {String}
+ */
+jasmine.pp = function(value) {
+ var stringPrettyPrinter = new jasmine.StringPrettyPrinter();
+ stringPrettyPrinter.format(value);
+ return stringPrettyPrinter.string;
+};
+
+/**
+ * Returns true if the object is a DOM Node.
+ *
+ * @param {Object} obj object to check
+ * @returns {Boolean}
+ */
+jasmine.isDomNode = function(obj) {
+ return obj.nodeType > 0;
+};
+
+/**
+ * Returns a matchable 'generic' object of the class type. For use in expecations of type when values don't matter.
+ *
+ * @example
+ * // don't care about which function is passed in, as long as it's a function
+ * expect(mySpy).toHaveBeenCalledWith(jasmine.any(Function));
+ *
+ * @param {Class} clazz
+ * @returns matchable object of the type clazz
+ */
+jasmine.any = function(clazz) {
+ return new jasmine.Matchers.Any(clazz);
+};
+
+/**
+ * Returns a matchable subset of a JSON object. For use in expectations when you don't care about all of the
+ * attributes on the object.
+ *
+ * @example
+ * // don't care about any other attributes than foo.
+ * expect(mySpy).toHaveBeenCalledWith(jasmine.objectContaining({foo: "bar"});
+ *
+ * @param sample {Object} sample
+ * @returns matchable object for the sample
+ */
+jasmine.objectContaining = function (sample) {
+ return new jasmine.Matchers.ObjectContaining(sample);
+};
+
+/**
+ * Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks.
+ *
+ * Spies should be created in test setup, before expectations. They can then be checked, using the standard Jasmine
+ * expectation syntax. Spies can be checked if they were called or not and what the calling params were.
+ *
+ * A Spy has the following fields: wasCalled, callCount, mostRecentCall, and argsForCall (see docs).
+ *
+ * Spies are torn down at the end of every spec.
+ *
+ * Note: Do <b>not</b> call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj.
+ *
+ * @example
+ * // a stub
+ * var myStub = jasmine.createSpy('myStub'); // can be used anywhere
+ *
+ * // spy example
+ * var foo = {
+ * not: function(bool) { return !bool; }
+ * }
+ *
+ * // actual foo.not will not be called, execution stops
+ * spyOn(foo, 'not');
+
+ // foo.not spied upon, execution will continue to implementation
+ * spyOn(foo, 'not').andCallThrough();
+ *
+ * // fake example
+ * var foo = {
+ * not: function(bool) { return !bool; }
+ * }
+ *
+ * // foo.not(val) will return val
+ * spyOn(foo, 'not').andCallFake(function(value) {return value;});
+ *
+ * // mock example
+ * foo.not(7 == 7);
+ * expect(foo.not).toHaveBeenCalled();
+ * expect(foo.not).toHaveBeenCalledWith(true);
+ *
+ * @constructor
+ * @see spyOn, jasmine.createSpy, jasmine.createSpyObj
+ * @param {String} name
+ */
+jasmine.Spy = function(name) {
+ /**
+ * The name of the spy, if provided.
+ */
+ this.identity = name || 'unknown';
+ /**
+ * Is this Object a spy?
+ */
+ this.isSpy = true;
+ /**
+ * The actual function this spy stubs.
+ */
+ this.plan = function() {
+ };
+ /**
+ * Tracking of the most recent call to the spy.
+ * @example
+ * var mySpy = jasmine.createSpy('foo');
+ * mySpy(1, 2);
+ * mySpy.mostRecentCall.args = [1, 2];
+ */
+ this.mostRecentCall = {};
+
+ /**
+ * Holds arguments for each call to the spy, indexed by call count
+ * @example
+ * var mySpy = jasmine.createSpy('foo');
+ * mySpy(1, 2);
+ * mySpy(7, 8);
+ * mySpy.mostRecentCall.args = [7, 8];
+ * mySpy.argsForCall[0] = [1, 2];
+ * mySpy.argsForCall[1] = [7, 8];
+ */
+ this.argsForCall = [];
+ this.calls = [];
+};
+
+/**
+ * Tells a spy to call through to the actual implemenatation.
+ *
+ * @example
+ * var foo = {
+ * bar: function() { // do some stuff }
+ * }
+ *
+ * // defining a spy on an existing property: foo.bar
+ * spyOn(foo, 'bar').andCallThrough();
+ */
+jasmine.Spy.prototype.andCallThrough = function() {
+ this.plan = this.originalValue;
+ return this;
+};
+
+/**
+ * For setting the return value of a spy.
+ *
+ * @example
+ * // defining a spy from scratch: foo() returns 'baz'
+ * var foo = jasmine.createSpy('spy on foo').andReturn('baz');
+ *
+ * // defining a spy on an existing property: foo.bar() returns 'baz'
+ * spyOn(foo, 'bar').andReturn('baz');
+ *
+ * @param {Object} value
+ */
+jasmine.Spy.prototype.andReturn = function(value) {
+ this.plan = function() {
+ return value;
+ };
+ return this;
+};
+
+/**
+ * For throwing an exception when a spy is called.
+ *
+ * @example
+ * // defining a spy from scratch: foo() throws an exception w/ message 'ouch'
+ * var foo = jasmine.createSpy('spy on foo').andThrow('baz');
+ *
+ * // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch'
+ * spyOn(foo, 'bar').andThrow('baz');
+ *
+ * @param {String} exceptionMsg
+ */
+jasmine.Spy.prototype.andThrow = function(exceptionMsg) {
+ this.plan = function() {
+ throw exceptionMsg;
+ };
+ return this;
+};
+
+/**
+ * Calls an alternate implementation when a spy is called.
+ *
+ * @example
+ * var baz = function() {
+ * // do some stuff, return something
+ * }
+ * // defining a spy from scratch: foo() calls the function baz
+ * var foo = jasmine.createSpy('spy on foo').andCall(baz);
+ *
+ * // defining a spy on an existing property: foo.bar() calls an anonymnous function
+ * spyOn(foo, 'bar').andCall(function() { return 'baz';} );
+ *
+ * @param {Function} fakeFunc
+ */
+jasmine.Spy.prototype.andCallFake = function(fakeFunc) {
+ this.plan = fakeFunc;
+ return this;
+};
+
+/**
+ * Resets all of a spy's the tracking variables so that it can be used again.
+ *
+ * @example
+ * spyOn(foo, 'bar');
+ *
+ * foo.bar();
+ *
+ * expect(foo.bar.callCount).toEqual(1);
+ *
+ * foo.bar.reset();
+ *
+ * expect(foo.bar.callCount).toEqual(0);
+ */
+jasmine.Spy.prototype.reset = function() {
+ this.wasCalled = false;
+ this.callCount = 0;
+ this.argsForCall = [];
+ this.calls = [];
+ this.mostRecentCall = {};
+};
+
+jasmine.createSpy = function(name) {
+
+ var spyObj = function() {
+ spyObj.wasCalled = true;
+ spyObj.callCount++;
+ var args = jasmine.util.argsToArray(arguments);
+ spyObj.mostRecentCall.object = this;
+ spyObj.mostRecentCall.args = args;
+ spyObj.argsForCall.push(args);
+ spyObj.calls.push({object: this, args: args});
+ return spyObj.plan.apply(this, arguments);
+ };
+
+ var spy = new jasmine.Spy(name);
+
+ for (var prop in spy) {
+ spyObj[prop] = spy[prop];
+ }
+
+ spyObj.reset();
+
+ return spyObj;
+};
+
+/**
+ * Determines whether an object is a spy.
+ *
+ * @param {jasmine.Spy|Object} putativeSpy
+ * @returns {Boolean}
+ */
+jasmine.isSpy = function(putativeSpy) {
+ return putativeSpy && putativeSpy.isSpy;
+};
+
+/**
+ * Creates a more complicated spy: an Object that has every property a function that is a spy. Used for stubbing something
+ * large in one call.
+ *
+ * @param {String} baseName name of spy class
+ * @param {Array} methodNames array of names of methods to make spies
+ */
+jasmine.createSpyObj = function(baseName, methodNames) {
+ if (!jasmine.isArray_(methodNames) || methodNames.length === 0) {
+ throw new Error('createSpyObj requires a non-empty array of method names to create spies for');
+ }
+ var obj = {};
+ for (var i = 0; i < methodNames.length; i++) {
+ obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]);
+ }
+ return obj;
+};
+
+/**
+ * All parameters are pretty-printed and concatenated together, then written to the current spec's output.
+ *
+ * Be careful not to leave calls to <code>jasmine.log</code> in production code.
+ */
+jasmine.log = function() {
+ var spec = jasmine.getEnv().currentSpec;
+ spec.log.apply(spec, arguments);
+};
+
+/**
+ * Function that installs a spy on an existing object's method name. Used within a Spec to create a spy.
+ *
+ * @example
+ * // spy example
+ * var foo = {
+ * not: function(bool) { return !bool; }
+ * }
+ * spyOn(foo, 'not'); // actual foo.not will not be called, execution stops
+ *
+ * @see jasmine.createSpy
+ * @param obj
+ * @param methodName
+ * @returns a Jasmine spy that can be chained with all spy methods
+ */
+var spyOn = function(obj, methodName) {
+ return jasmine.getEnv().currentSpec.spyOn(obj, methodName);
+};
+if (isCommonJS) exports.spyOn = spyOn;
+
+/**
+ * Creates a Jasmine spec that will be added to the current suite.
+ *
+ * // TODO: pending tests
+ *
+ * @example
+ * it('should be true', function() {
+ * expect(true).toEqual(true);
+ * });
+ *
+ * @param {String} desc description of this specification
+ * @param {Function} func defines the preconditions and expectations of the spec
+ */
+var it = function(desc, func) {
+ return jasmine.getEnv().it(desc, func);
+};
+if (isCommonJS) exports.it = it;
+
+/**
+ * Creates a <em>disabled</em> Jasmine spec.
+ *
+ * A convenience method that allows existing specs to be disabled temporarily during development.
+ *
+ * @param {String} desc description of this specification
+ * @param {Function} func defines the preconditions and expectations of the spec
+ */
+var xit = function(desc, func) {
+ return jasmine.getEnv().xit(desc, func);
+};
+if (isCommonJS) exports.xit = xit;
+
+/**
+ * Starts a chain for a Jasmine expectation.
+ *
+ * It is passed an Object that is the actual value and should chain to one of the many
+ * jasmine.Matchers functions.
+ *
+ * @param {Object} actual Actual value to test against and expected value
+ */
+var expect = function(actual) {
+ return jasmine.getEnv().currentSpec.expect(actual);
+};
+if (isCommonJS) exports.expect = expect;
+
+/**
+ * Defines part of a jasmine spec. Used in cominbination with waits or waitsFor in asynchrnous specs.
+ *
+ * @param {Function} func Function that defines part of a jasmine spec.
+ */
+var runs = function(func) {
+ jasmine.getEnv().currentSpec.runs(func);
+};
+if (isCommonJS) exports.runs = runs;
+
+/**
+ * Waits a fixed time period before moving to the next block.
+ *
+ * @deprecated Use waitsFor() instead
+ * @param {Number} timeout milliseconds to wait
+ */
+var waits = function(timeout) {
+ jasmine.getEnv().currentSpec.waits(timeout);
+};
+if (isCommonJS) exports.waits = waits;
+
+/**
+ * Waits for the latchFunction to return true before proceeding to the next block.
+ *
+ * @param {Function} latchFunction
+ * @param {String} optional_timeoutMessage
+ * @param {Number} optional_timeout
+ */
+var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
+ jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments);
+};
+if (isCommonJS) exports.waitsFor = waitsFor;
+
+/**
+ * A function that is called before each spec in a suite.
+ *
+ * Used for spec setup, including validating assumptions.
+ *
+ * @param {Function} beforeEachFunction
+ */
+var beforeEach = function(beforeEachFunction) {
+ jasmine.getEnv().beforeEach(beforeEachFunction);
+};
+if (isCommonJS) exports.beforeEach = beforeEach;
+
+/**
+ * A function that is called after each spec in a suite.
+ *
+ * Used for restoring any state that is hijacked during spec execution.
+ *
+ * @param {Function} afterEachFunction
+ */
+var afterEach = function(afterEachFunction) {
+ jasmine.getEnv().afterEach(afterEachFunction);
+};
+if (isCommonJS) exports.afterEach = afterEach;
+
+/**
+ * Defines a suite of specifications.
+ *
+ * Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared
+ * are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization
+ * of setup in some tests.
+ *
+ * @example
+ * // TODO: a simple suite
+ *
+ * // TODO: a simple suite with a nested describe block
+ *
+ * @param {String} description A string, usually the class under test.
+ * @param {Function} specDefinitions function that defines several specs.
+ */
+var describe = function(description, specDefinitions) {
+ return jasmine.getEnv().describe(description, specDefinitions);
+};
+if (isCommonJS) exports.describe = describe;
+
+/**
+ * Disables a suite of specifications. Used to disable some suites in a file, or files, temporarily during development.
+ *
+ * @param {String} description A string, usually the class under test.
+ * @param {Function} specDefinitions function that defines several specs.
+ */
+var xdescribe = function(description, specDefinitions) {
+ return jasmine.getEnv().xdescribe(description, specDefinitions);
+};
+if (isCommonJS) exports.xdescribe = xdescribe;
+
+
+// Provide the XMLHttpRequest class for IE 5.x-6.x:
+jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() {
+ function tryIt(f) {
+ try {
+ return f();
+ } catch(e) {
+ }
+ return null;
+ }
+
+ var xhr = tryIt(function() {
+ return new ActiveXObject("Msxml2.XMLHTTP.6.0");
+ }) ||
+ tryIt(function() {
+ return new ActiveXObject("Msxml2.XMLHTTP.3.0");
+ }) ||
+ tryIt(function() {
+ return new ActiveXObject("Msxml2.XMLHTTP");
+ }) ||
+ tryIt(function() {
+ return new ActiveXObject("Microsoft.XMLHTTP");
+ });
+
+ if (!xhr) throw new Error("This browser does not support XMLHttpRequest.");
+
+ return xhr;
+} : XMLHttpRequest;
+/**
+ * @namespace
+ */
+jasmine.util = {};
+
+/**
+ * Declare that a child class inherit it's prototype from the parent class.
+ *
+ * @private
+ * @param {Function} childClass
+ * @param {Function} parentClass
+ */
+jasmine.util.inherit = function(childClass, parentClass) {
+ /**
+ * @private
+ */
+ var subclass = function() {
+ };
+ subclass.prototype = parentClass.prototype;
+ childClass.prototype = new subclass();
+};
+
+jasmine.util.formatException = function(e) {
+ var lineNumber;
+ if (e.line) {
+ lineNumber = e.line;
+ }
+ else if (e.lineNumber) {
+ lineNumber = e.lineNumber;
+ }
+
+ var file;
+
+ if (e.sourceURL) {
+ file = e.sourceURL;
+ }
+ else if (e.fileName) {
+ file = e.fileName;
+ }
+
+ var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString();
+
+ if (file && lineNumber) {
+ message += ' in ' + file + ' (line ' + lineNumber + ')';
+ }
+
+ return message;
+};
+
+jasmine.util.htmlEscape = function(str) {
+ if (!str) return str;
+ return str.replace(/&/g, '&')
+ .replace(/</g, '<')
+ .replace(/>/g, '>');
+};
+
+jasmine.util.argsToArray = function(args) {
+ var arrayOfArgs = [];
+ for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]);
+ return arrayOfArgs;
+};
+
+jasmine.util.extend = function(destination, source) {
+ for (var property in source) destination[property] = source[property];
+ return destination;
+};
+
+/**
+ * Environment for Jasmine
+ *
+ * @constructor
+ */
+jasmine.Env = function() {
+ this.currentSpec = null;
+ this.currentSuite = null;
+ this.currentRunner_ = new jasmine.Runner(this);
+
+ this.reporter = new jasmine.MultiReporter();
+
+ this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL;
+ this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL;
+ this.lastUpdate = 0;
+ this.specFilter = function() {
+ return true;
+ };
+
+ this.nextSpecId_ = 0;
+ this.nextSuiteId_ = 0;
+ this.equalityTesters_ = [];
+
+ // wrap matchers
+ this.matchersClass = function() {
+ jasmine.Matchers.apply(this, arguments);
+ };
+ jasmine.util.inherit(this.matchersClass, jasmine.Matchers);
+
+ jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass);
+};
+
+
+jasmine.Env.prototype.setTimeout = jasmine.setTimeout;
+jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout;
+jasmine.Env.prototype.setInterval = jasmine.setInterval;
+jasmine.Env.prototype.clearInterval = jasmine.clearInterval;
+
+/**
+ * @returns an object containing jasmine version build info, if set.
+ */
+jasmine.Env.prototype.version = function () {
+ if (jasmine.version_) {
+ return jasmine.version_;
+ } else {
+ throw new Error('Version not set');
+ }
+};
+
+/**
+ * @returns string containing jasmine version build info, if set.
+ */
+jasmine.Env.prototype.versionString = function() {
+ if (!jasmine.version_) {
+ return "version unknown";
+ }
+
+ var version = this.version();
+ var versionString = version.major + "." + version.minor + "." + version.build;
+ if (version.release_candidate) {
+ versionString += ".rc" + version.release_candidate;
+ }
+ versionString += " revision " + version.revision;
+ return versionString;
+};
+
+/**
+ * @returns a sequential integer starting at 0
+ */
+jasmine.Env.prototype.nextSpecId = function () {
+ return this.nextSpecId_++;
+};
+
+/**
+ * @returns a sequential integer starting at 0
+ */
+jasmine.Env.prototype.nextSuiteId = function () {
+ return this.nextSuiteId_++;
+};
+
+/**
+ * Register a reporter to receive status updates from Jasmine.
+ * @param {jasmine.Reporter} reporter An object which will receive status updates.
+ */
+jasmine.Env.prototype.addReporter = function(reporter) {
+ this.reporter.addReporter(reporter);
+};
+
+jasmine.Env.prototype.execute = function() {
+ this.currentRunner_.execute();
+};
+
+jasmine.Env.prototype.describe = function(description, specDefinitions) {
+ var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite);
+
+ var parentSuite = this.currentSuite;
+ if (parentSuite) {
+ parentSuite.add(suite);
+ } else {
+ this.currentRunner_.add(suite);
+ }
+
+ this.currentSuite = suite;
+
+ var declarationError = null;
+ try {
+ specDefinitions.call(suite);
+ } catch(e) {
+ declarationError = e;
+ }
+
+ if (declarationError) {
+ this.it("encountered a declaration exception", function() {
+ throw declarationError;
+ });
+ }
+
+ this.currentSuite = parentSuite;
+
+ return suite;
+};
+
+jasmine.Env.prototype.beforeEach = function(beforeEachFunction) {
+ if (this.currentSuite) {
+ this.currentSuite.beforeEach(beforeEachFunction);
+ } else {
+ this.currentRunner_.beforeEach(beforeEachFunction);
+ }
+};
+
+jasmine.Env.prototype.currentRunner = function () {
+ return this.currentRunner_;
+};
+
+jasmine.Env.prototype.afterEach = function(afterEachFunction) {
+ if (this.currentSuite) {
+ this.currentSuite.afterEach(afterEachFunction);
+ } else {
+ this.currentRunner_.afterEach(afterEachFunction);
+ }
+
+};
+
+jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) {
+ return {
+ execute: function() {
+ }
+ };
+};
+
+jasmine.Env.prototype.it = function(description, func) {
+ var spec = new jasmine.Spec(this, this.currentSuite, description);
+ this.currentSuite.add(spec);
+ this.currentSpec = spec;
+
+ if (func) {
+ spec.runs(func);
+ }
+
+ return spec;
+};
+
+jasmine.Env.prototype.xit = function(desc, func) {
+ return {
+ id: this.nextSpecId(),
+ runs: function() {
+ }
+ };
+};
+
+jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) {
+ if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) {
+ return true;
+ }
+
+ a.__Jasmine_been_here_before__ = b;
+ b.__Jasmine_been_here_before__ = a;
+
+ var hasKey = function(obj, keyName) {
+ return obj !== null && obj[keyName] !== jasmine.undefined;
+ };
+
+ for (var property in b) {
+ if (!hasKey(a, property) && hasKey(b, property)) {
+ mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
+ }
+ }
+ for (property in a) {
+ if (!hasKey(b, property) && hasKey(a, property)) {
+ mismatchKeys.push("expected missing key '" + property + "', but present in actual.");
+ }
+ }
+ for (property in b) {
+ if (property == '__Jasmine_been_here_before__') continue;
+ if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) {
+ mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual.");
+ }
+ }
+
+ if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) {
+ mismatchValues.push("arrays were not the same length");
+ }
+
+ delete a.__Jasmine_been_here_before__;
+ delete b.__Jasmine_been_here_before__;
+ return (mismatchKeys.length === 0 && mismatchValues.length === 0);
+};
+
+jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) {
+ mismatchKeys = mismatchKeys || [];
+ mismatchValues = mismatchValues || [];
+
+ for (var i = 0; i < this.equalityTesters_.length; i++) {
+ var equalityTester = this.equalityTesters_[i];
+ var result = equalityTester(a, b, this, mismatchKeys, mismatchValues);
+ if (result !== jasmine.undefined) return result;
+ }
+
+ if (a === b) return true;
+
+ if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) {
+ return (a == jasmine.undefined && b == jasmine.undefined);
+ }
+
+ if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) {
+ return a === b;
+ }
+
+ if (a instanceof Date && b instanceof Date) {
+ return a.getTime() == b.getTime();
+ }
+
+ if (a.jasmineMatches) {
+ return a.jasmineMatches(b);
+ }
+
+ if (b.jasmineMatches) {
+ return b.jasmineMatches(a);
+ }
+
+ if (a instanceof jasmine.Matchers.ObjectContaining) {
+ return a.matches(b);
+ }
+
+ if (b instanceof jasmine.Matchers.ObjectContaining) {
+ return b.matches(a);
+ }
+
+ if (jasmine.isString_(a) && jasmine.isString_(b)) {
+ return (a == b);
+ }
+
+ if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) {
+ return (a == b);
+ }
+
+ if (typeof a === "object" && typeof b === "object") {
+ return this.compareObjects_(a, b, mismatchKeys, mismatchValues);
+ }
+
+ //Straight check
+ return (a === b);
+};
+
+jasmine.Env.prototype.contains_ = function(haystack, needle) {
+ if (jasmine.isArray_(haystack)) {
+ for (var i = 0; i < haystack.length; i++) {
+ if (this.equals_(haystack[i], needle)) return true;
+ }
+ return false;
+ }
+ return haystack.indexOf(needle) >= 0;
+};
+
+jasmine.Env.prototype.addEqualityTester = function(equalityTester) {
+ this.equalityTesters_.push(equalityTester);
+};
+/** No-op base class for Jasmine reporters.
+ *
+ * @constructor
+ */
+jasmine.Reporter = function() {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportRunnerStarting = function(runner) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportRunnerResults = function(runner) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportSuiteResults = function(suite) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportSpecStarting = function(spec) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportSpecResults = function(spec) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.log = function(str) {
+};
+
+/**
+ * Blocks are functions with executable code that make up a spec.
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param {Function} func
+ * @param {jasmine.Spec} spec
+ */
+jasmine.Block = function(env, func, spec) {
+ this.env = env;
+ this.func = func;
+ this.spec = spec;
+};
+
+jasmine.Block.prototype.execute = function(onComplete) {
+ try {
+ this.func.apply(this.spec);
+ } catch (e) {
+ this.spec.fail(e);
+ }
+ onComplete();
+};
+/** JavaScript API reporter.
+ *
+ * @constructor
+ */
+jasmine.JsApiReporter = function() {
+ this.started = false;
+ this.finished = false;
+ this.suites_ = [];
+ this.results_ = {};
+};
+
+jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) {
+ this.started = true;
+ var suites = runner.topLevelSuites();
+ for (var i = 0; i < suites.length; i++) {
+ var suite = suites[i];
+ this.suites_.push(this.summarize_(suite));
+ }
+};
+
+jasmine.JsApiReporter.prototype.suites = function() {
+ return this.suites_;
+};
+
+jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) {
+ var isSuite = suiteOrSpec instanceof jasmine.Suite;
+ var summary = {
+ id: suiteOrSpec.id,
+ name: suiteOrSpec.description,
+ type: isSuite ? 'suite' : 'spec',
+ children: []
+ };
+
+ if (isSuite) {
+ var children = suiteOrSpec.children();
+ for (var i = 0; i < children.length; i++) {
+ summary.children.push(this.summarize_(children[i]));
+ }
+ }
+ return summary;
+};
+
+jasmine.JsApiReporter.prototype.results = function() {
+ return this.results_;
+};
+
+jasmine.JsApiReporter.prototype.resultsForSpec = function(specId) {
+ return this.results_[specId];
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) {
+ this.finished = true;
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.reportSpecResults = function(spec) {
+ this.results_[spec.id] = {
+ messages: spec.results().getItems(),
+ result: spec.results().failedCount > 0 ? "failed" : "passed"
+ };
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.log = function(str) {
+};
+
+jasmine.JsApiReporter.prototype.resultsForSpecs = function(specIds){
+ var results = {};
+ for (var i = 0; i < specIds.length; i++) {
+ var specId = specIds[i];
+ results[specId] = this.summarizeResult_(this.results_[specId]);
+ }
+ return results;
+};
+
+jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){
+ var summaryMessages = [];
+ var messagesLength = result.messages.length;
+ for (var messageIndex = 0; messageIndex < messagesLength; messageIndex++) {
+ var resultMessage = result.messages[messageIndex];
+ summaryMessages.push({
+ text: resultMessage.type == 'log' ? resultMessage.toString() : jasmine.undefined,
+ passed: resultMessage.passed ? resultMessage.passed() : true,
+ type: resultMessage.type,
+ message: resultMessage.message,
+ trace: {
+ stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : jasmine.undefined
+ }
+ });
+ }
+
+ return {
+ result : result.result,
+ messages : summaryMessages
+ };
+};
+
+/**
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param actual
+ * @param {jasmine.Spec} spec
+ */
+jasmine.Matchers = function(env, actual, spec, opt_isNot) {
+ this.env = env;
+ this.actual = actual;
+ this.spec = spec;
+ this.isNot = opt_isNot || false;
+ this.reportWasCalled_ = false;
+};
+
+// todo: @deprecated as of Jasmine 0.11, remove soon [xw]
+jasmine.Matchers.pp = function(str) {
+ throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!");
+};
+
+// todo: @deprecated Deprecated as of Jasmine 0.10. Rewrite your custom matchers to return true or false. [xw]
+jasmine.Matchers.prototype.report = function(result, failing_message, details) {
+ throw new Error("As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs");
+};
+
+jasmine.Matchers.wrapInto_ = function(prototype, matchersClass) {
+ for (var methodName in prototype) {
+ if (methodName == 'report') continue;
+ var orig = prototype[methodName];
+ matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig);
+ }
+};
+
+jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) {
+ return function() {
+ var matcherArgs = jasmine.util.argsToArray(arguments);
+ var result = matcherFunction.apply(this, arguments);
+
+ if (this.isNot) {
+ result = !result;
+ }
+
+ if (this.reportWasCalled_) return result;
+
+ var message;
+ if (!result) {
+ if (this.message) {
+ message = this.message.apply(this, arguments);
+ if (jasmine.isArray_(message)) {
+ message = message[this.isNot ? 1 : 0];
+ }
+ } else {
+ var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
+ message = "Expected " + jasmine.pp(this.actual) + (this.isNot ? " not " : " ") + englishyPredicate;
+ if (matcherArgs.length > 0) {
+ for (var i = 0; i < matcherArgs.length; i++) {
+ if (i > 0) message += ",";
+ message += " " + jasmine.pp(matcherArgs[i]);
+ }
+ }
+ message += ".";
+ }
+ }
+ var expectationResult = new jasmine.ExpectationResult({
+ matcherName: matcherName,
+ passed: result,
+ expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0],
+ actual: this.actual,
+ message: message
+ });
+ this.spec.addMatcherResult(expectationResult);
+ return jasmine.undefined;
+ };
+};
+
+
+
+
+/**
+ * toBe: compares the actual to the expected using ===
+ * @param expected
+ */
+jasmine.Matchers.prototype.toBe = function(expected) {
+ return this.actual === expected;
+};
+
+/**
+ * toNotBe: compares the actual to the expected using !==
+ * @param expected
+ * @deprecated as of 1.0. Use not.toBe() instead.
+ */
+jasmine.Matchers.prototype.toNotBe = function(expected) {
+ return this.actual !== expected;
+};
+
+/**
+ * toEqual: compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc.
+ *
+ * @param expected
+ */
+jasmine.Matchers.prototype.toEqual = function(expected) {
+ return this.env.equals_(this.actual, expected);
+};
+
+/**
+ * toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual
+ * @param expected
+ * @deprecated as of 1.0. Use not.toEqual() instead.
+ */
+jasmine.Matchers.prototype.toNotEqual = function(expected) {
+ return !this.env.equals_(this.actual, expected);
+};
+
+/**
+ * Matcher that compares the actual to the expected using a regular expression. Constructs a RegExp, so takes
+ * a pattern or a String.
+ *
+ * @param expected
+ */
+jasmine.Matchers.prototype.toMatch = function(expected) {
+ return new RegExp(expected).test(this.actual);
+};
+
+/**
+ * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch
+ * @param expected
+ * @deprecated as of 1.0. Use not.toMatch() instead.
+ */
+jasmine.Matchers.prototype.toNotMatch = function(expected) {
+ return !(new RegExp(expected).test(this.actual));
+};
+
+/**
+ * Matcher that compares the actual to jasmine.undefined.
+ */
+jasmine.Matchers.prototype.toBeDefined = function() {
+ return (this.actual !== jasmine.undefined);
+};
+
+/**
+ * Matcher that compares the actual to jasmine.undefined.
+ */
+jasmine.Matchers.prototype.toBeUndefined = function() {
+ return (this.actual === jasmine.undefined);
+};
+
+/**
+ * Matcher that compares the actual to null.
+ */
+jasmine.Matchers.prototype.toBeNull = function() {
+ return (this.actual === null);
+};
+
+/**
+ * Matcher that boolean not-nots the actual.
+ */
+jasmine.Matchers.prototype.toBeTruthy = function() {
+ return !!this.actual;
+};
+
+
+/**
+ * Matcher that boolean nots the actual.
+ */
+jasmine.Matchers.prototype.toBeFalsy = function() {
+ return !this.actual;
+};
+
+
+/**
+ * Matcher that checks to see if the actual, a Jasmine spy, was called.
+ */
+jasmine.Matchers.prototype.toHaveBeenCalled = function() {
+ if (arguments.length > 0) {
+ throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
+ }
+
+ if (!jasmine.isSpy(this.actual)) {
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+ }
+
+ this.message = function() {
+ return [
+ "Expected spy " + this.actual.identity + " to have been called.",
+ "Expected spy " + this.actual.identity + " not to have been called."
+ ];
+ };
+
+ return this.actual.wasCalled;
+};
+
+/** @deprecated Use expect(xxx).toHaveBeenCalled() instead */
+jasmine.Matchers.prototype.wasCalled = jasmine.Matchers.prototype.toHaveBeenCalled;
+
+/**
+ * Matcher that checks to see if the actual, a Jasmine spy, was not called.
+ *
+ * @deprecated Use expect(xxx).not.toHaveBeenCalled() instead
+ */
+jasmine.Matchers.prototype.wasNotCalled = function() {
+ if (arguments.length > 0) {
+ throw new Error('wasNotCalled does not take arguments');
+ }
+
+ if (!jasmine.isSpy(this.actual)) {
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+ }
+
+ this.message = function() {
+ return [
+ "Expected spy " + this.actual.identity + " to not have been called.",
+ "Expected spy " + this.actual.identity + " to have been called."
+ ];
+ };
+
+ return !this.actual.wasCalled;
+};
+
+/**
+ * Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters.
+ *
+ * @example
+ *
+ */
+jasmine.Matchers.prototype.toHaveBeenCalledWith = function() {
+ var expectedArgs = jasmine.util.argsToArray(arguments);
+ if (!jasmine.isSpy(this.actual)) {
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+ }
+ this.message = function() {
+ if (this.actual.callCount === 0) {
+ // todo: what should the failure message for .not.toHaveBeenCalledWith() be? is this right? test better. [xw]
+ return [
+ "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called.",
+ "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was."
+ ];
+ } else {
+ return [
+ "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall),
+ "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall)
+ ];
+ }
+ };
+
+ return this.env.contains_(this.actual.argsForCall, expectedArgs);
+};
+
+/** @deprecated Use expect(xxx).toHaveBeenCalledWith() instead */
+jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.prototype.toHaveBeenCalledWith;
+
+/** @deprecated Use expect(xxx).not.toHaveBeenCalledWith() instead */
+jasmine.Matchers.prototype.wasNotCalledWith = function() {
+ var expectedArgs = jasmine.util.argsToArray(arguments);
+ if (!jasmine.isSpy(this.actual)) {
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+ }
+
+ this.message = function() {
+ return [
+ "Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but it was",
+ "Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but it was"
+ ];
+ };
+
+ return !this.env.contains_(this.actual.argsForCall, expectedArgs);
+};
+
+/**
+ * Matcher that checks that the expected item is an element in the actual Array.
+ *
+ * @param {Object} expected
+ */
+jasmine.Matchers.prototype.toContain = function(expected) {
+ return this.env.contains_(this.actual, expected);
+};
+
+/**
+ * Matcher that checks that the expected item is NOT an element in the actual Array.
+ *
+ * @param {Object} expected
+ * @deprecated as of 1.0. Use not.toContain() instead.
+ */
+jasmine.Matchers.prototype.toNotContain = function(expected) {
+ return !this.env.contains_(this.actual, expected);
+};
+
+jasmine.Matchers.prototype.toBeLessThan = function(expected) {
+ return this.actual < expected;
+};
+
+jasmine.Matchers.prototype.toBeGreaterThan = function(expected) {
+ return this.actual > expected;
+};
+
+/**
+ * Matcher that checks that the expected item is equal to the actual item
+ * up to a given level of decimal precision (default 2).
+ *
+ * @param {Number} expected
+ * @param {Number} precision
+ */
+jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) {
+ if (!(precision === 0)) {
+ precision = precision || 2;
+ }
+ var multiplier = Math.pow(10, precision);
+ var actual = Math.round(this.actual * multiplier);
+ expected = Math.round(expected * multiplier);
+ return expected == actual;
+};
+
+/**
+ * Matcher that checks that the expected exception was thrown by the actual.
+ *
+ * @param {String} expected
+ */
+jasmine.Matchers.prototype.toThrow = function(expected) {
+ var result = false;
+ var exception;
+ if (typeof this.actual != 'function') {
+ throw new Error('Actual is not a function');
+ }
+ try {
+ this.actual();
+ } catch (e) {
+ exception = e;
+ }
+ if (exception) {
+ result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected));
+ }
+
+ var not = this.isNot ? "not " : "";
+
+ this.message = function() {
+ if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) {
+ return ["Expected function " + not + "to throw", expected ? expected.message || expected : "an exception", ", but it threw", exception.message || exception].join(' ');
+ } else {
+ return "Expected function to throw an exception.";
+ }
+ };
+
+ return result;
+};
+
+jasmine.Matchers.Any = function(expectedClass) {
+ this.expectedClass = expectedClass;
+};
+
+jasmine.Matchers.Any.prototype.jasmineMatches = function(other) {
+ if (this.expectedClass == String) {
+ return typeof other == 'string' || other instanceof String;
+ }
+
+ if (this.expectedClass == Number) {
+ return typeof other == 'number' || other instanceof Number;
+ }
+
+ if (this.expectedClass == Function) {
+ return typeof other == 'function' || other instanceof Function;
+ }
+
+ if (this.expectedClass == Object) {
+ return typeof other == 'object';
+ }
+
+ return other instanceof this.expectedClass;
+};
+
+jasmine.Matchers.Any.prototype.jasmineToString = function() {
+ return '<jasmine.any(' + this.expectedClass + ')>';
+};
+
+jasmine.Matchers.ObjectContaining = function (sample) {
+ this.sample = sample;
+};
+
+jasmine.Matchers.ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) {
+ mismatchKeys = mismatchKeys || [];
+ mismatchValues = mismatchValues || [];
+
+ var env = jasmine.getEnv();
+
+ var hasKey = function(obj, keyName) {
+ return obj != null && obj[keyName] !== jasmine.undefined;
+ };
+
+ for (var property in this.sample) {
+ if (!hasKey(other, property) && hasKey(this.sample, property)) {
+ mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
+ }
+ else if (!env.equals_(this.sample[property], other[property], mismatchKeys, mismatchValues)) {
+ mismatchValues.push("'" + property + "' was '" + (other[property] ? jasmine.util.htmlEscape(other[property].toString()) : other[property]) + "' in expected, but was '" + (this.sample[property] ? jasmine.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in actual.");
+ }
+ }
+
+ return (mismatchKeys.length === 0 && mismatchValues.length === 0);
+};
+
+jasmine.Matchers.ObjectContaining.prototype.jasmineToString = function () {
+ return "<jasmine.objectContaining(" + jasmine.pp(this.sample) + ")>";
+};
+// Mock setTimeout, clearTimeout
+// Contributed by Pivotal Computer Systems, www.pivotalsf.com
+
+jasmine.FakeTimer = function() {
+ this.reset();
+
+ var self = this;
+ self.setTimeout = function(funcToCall, millis) {
+ self.timeoutsMade++;
+ self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false);
+ return self.timeoutsMade;
+ };
+
+ self.setInterval = function(funcToCall, millis) {
+ self.timeoutsMade++;
+ self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true);
+ return self.timeoutsMade;
+ };
+
+ self.clearTimeout = function(timeoutKey) {
+ self.scheduledFunctions[timeoutKey] = jasmine.undefined;
+ };
+
+ self.clearInterval = function(timeoutKey) {
+ self.scheduledFunctions[timeoutKey] = jasmine.undefined;
+ };
+
+};
+
+jasmine.FakeTimer.prototype.reset = function() {
+ this.timeoutsMade = 0;
+ this.scheduledFunctions = {};
+ this.nowMillis = 0;
+};
+
+jasmine.FakeTimer.prototype.tick = function(millis) {
+ var oldMillis = this.nowMillis;
+ var newMillis = oldMillis + millis;
+ this.runFunctionsWithinRange(oldMillis, newMillis);
+ this.nowMillis = newMillis;
+};
+
+jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) {
+ var scheduledFunc;
+ var funcsToRun = [];
+ for (var timeoutKey in this.scheduledFunctions) {
+ scheduledFunc = this.scheduledFunctions[timeoutKey];
+ if (scheduledFunc != jasmine.undefined &&
+ scheduledFunc.runAtMillis >= oldMillis &&
+ scheduledFunc.runAtMillis <= nowMillis) {
+ funcsToRun.push(scheduledFunc);
+ this.scheduledFunctions[timeoutKey] = jasmine.undefined;
+ }
+ }
+
+ if (funcsToRun.length > 0) {
+ funcsToRun.sort(function(a, b) {
+ return a.runAtMillis - b.runAtMillis;
+ });
+ for (var i = 0; i < funcsToRun.length; ++i) {
+ try {
+ var funcToRun = funcsToRun[i];
+ this.nowMillis = funcToRun.runAtMillis;
+ funcToRun.funcToCall();
+ if (funcToRun.recurring) {
+ this.scheduleFunction(funcToRun.timeoutKey,
+ funcToRun.funcToCall,
+ funcToRun.millis,
+ true);
+ }
+ } catch(e) {
+ }
+ }
+ this.runFunctionsWithinRange(oldMillis, nowMillis);
+ }
+};
+
+jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) {
+ this.scheduledFunctions[timeoutKey] = {
+ runAtMillis: this.nowMillis + millis,
+ funcToCall: funcToCall,
+ recurring: recurring,
+ timeoutKey: timeoutKey,
+ millis: millis
+ };
+};
+
+/**
+ * @namespace
+ */
+jasmine.Clock = {
+ defaultFakeTimer: new jasmine.FakeTimer(),
+
+ reset: function() {
+ jasmine.Clock.assertInstalled();
+ jasmine.Clock.defaultFakeTimer.reset();
+ },
+
+ tick: function(millis) {
+ jasmine.Clock.assertInstalled();
+ jasmine.Clock.defaultFakeTimer.tick(millis);
+ },
+
+ runFunctionsWithinRange: function(oldMillis, nowMillis) {
+ jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis);
+ },
+
+ scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) {
+ jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring);
+ },
+
+ useMock: function() {
+ if (!jasmine.Clock.isInstalled()) {
+ var spec = jasmine.getEnv().currentSpec;
+ spec.after(jasmine.Clock.uninstallMock);
+
+ jasmine.Clock.installMock();
+ }
+ },
+
+ installMock: function() {
+ jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer;
+ },
+
+ uninstallMock: function() {
+ jasmine.Clock.assertInstalled();
+ jasmine.Clock.installed = jasmine.Clock.real;
+ },
+
+ real: {
+ setTimeout: jasmine.getGlobal().setTimeout,
+ clearTimeout: jasmine.getGlobal().clearTimeout,
+ setInterval: jasmine.getGlobal().setInterval,
+ clearInterval: jasmine.getGlobal().clearInterval
+ },
+
+ assertInstalled: function() {
+ if (!jasmine.Clock.isInstalled()) {
+ throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
+ }
+ },
+
+ isInstalled: function() {
+ return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer;
+ },
+
+ installed: null
+};
+jasmine.Clock.installed = jasmine.Clock.real;
+
+//else for IE support
+jasmine.getGlobal().setTimeout = function(funcToCall, millis) {
+ if (jasmine.Clock.installed.setTimeout.apply) {
+ return jasmine.Clock.installed.setTimeout.apply(this, arguments);
+ } else {
+ return jasmine.Clock.installed.setTimeout(funcToCall, millis);
+ }
+};
+
+jasmine.getGlobal().setInterval = function(funcToCall, millis) {
+ if (jasmine.Clock.installed.setInterval.apply) {
+ return jasmine.Clock.installed.setInterval.apply(this, arguments);
+ } else {
+ return jasmine.Clock.installed.setInterval(funcToCall, millis);
+ }
+};
+
+jasmine.getGlobal().clearTimeout = function(timeoutKey) {
+ if (jasmine.Clock.installed.clearTimeout.apply) {
+ return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
+ } else {
+ return jasmine.Clock.installed.clearTimeout(timeoutKey);
+ }
+};
+
+jasmine.getGlobal().clearInterval = function(timeoutKey) {
+ if (jasmine.Clock.installed.clearTimeout.apply) {
+ return jasmine.Clock.installed.clearInterval.apply(this, arguments);
+ } else {
+ return jasmine.Clock.installed.clearInterval(timeoutKey);
+ }
+};
+
+/**
+ * @constructor
+ */
+jasmine.MultiReporter = function() {
+ this.subReporters_ = [];
+};
+jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter);
+
+jasmine.MultiReporter.prototype.addReporter = function(reporter) {
+ this.subReporters_.push(reporter);
+};
+
+(function() {
+ var functionNames = [
+ "reportRunnerStarting",
+ "reportRunnerResults",
+ "reportSuiteResults",
+ "reportSpecStarting",
+ "reportSpecResults",
+ "log"
+ ];
+ for (var i = 0; i < functionNames.length; i++) {
+ var functionName = functionNames[i];
+ jasmine.MultiReporter.prototype[functionName] = (function(functionName) {
+ return function() {
+ for (var j = 0; j < this.subReporters_.length; j++) {
+ var subReporter = this.subReporters_[j];
+ if (subReporter[functionName]) {
+ subReporter[functionName].apply(subReporter, arguments);
+ }
+ }
+ };
+ })(functionName);
+ }
+})();
+/**
+ * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults
+ *
+ * @constructor
+ */
+jasmine.NestedResults = function() {
+ /**
+ * The total count of results
+ */
+ this.totalCount = 0;
+ /**
+ * Number of passed results
+ */
+ this.passedCount = 0;
+ /**
+ * Number of failed results
+ */
+ this.failedCount = 0;
+ /**
+ * Was this suite/spec skipped?
+ */
+ this.skipped = false;
+ /**
+ * @ignore
+ */
+ this.items_ = [];
+};
+
+/**
+ * Roll up the result counts.
+ *
+ * @param result
+ */
+jasmine.NestedResults.prototype.rollupCounts = function(result) {
+ this.totalCount += result.totalCount;
+ this.passedCount += result.passedCount;
+ this.failedCount += result.failedCount;
+};
+
+/**
+ * Adds a log message.
+ * @param values Array of message parts which will be concatenated later.
+ */
+jasmine.NestedResults.prototype.log = function(values) {
+ this.items_.push(new jasmine.MessageResult(values));
+};
+
+/**
+ * Getter for the results: message & results.
+ */
+jasmine.NestedResults.prototype.getItems = function() {
+ return this.items_;
+};
+
+/**
+ * Adds a result, tracking counts (total, passed, & failed)
+ * @param {jasmine.ExpectationResult|jasmine.NestedResults} result
+ */
+jasmine.NestedResults.prototype.addResult = function(result) {
+ if (result.type != 'log') {
+ if (result.items_) {
+ this.rollupCounts(result);
+ } else {
+ this.totalCount++;
+ if (result.passed()) {
+ this.passedCount++;
+ } else {
+ this.failedCount++;
+ }
+ }
+ }
+ this.items_.push(result);
+};
+
+/**
+ * @returns {Boolean} True if <b>everything</b> below passed
+ */
+jasmine.NestedResults.prototype.passed = function() {
+ return this.passedCount === this.totalCount;
+};
+/**
+ * Base class for pretty printing for expectation results.
+ */
+jasmine.PrettyPrinter = function() {
+ this.ppNestLevel_ = 0;
+};
+
+/**
+ * Formats a value in a nice, human-readable string.
+ *
+ * @param value
+ */
+jasmine.PrettyPrinter.prototype.format = function(value) {
+ if (this.ppNestLevel_ > 40) {
+ throw new Error('jasmine.PrettyPrinter: format() nested too deeply!');
+ }
+
+ this.ppNestLevel_++;
+ try {
+ if (value === jasmine.undefined) {
+ this.emitScalar('undefined');
+ } else if (value === null) {
+ this.emitScalar('null');
+ } else if (value === jasmine.getGlobal()) {
+ this.emitScalar('<global>');
+ } else if (value.jasmineToString) {
+ this.emitScalar(value.jasmineToString());
+ } else if (typeof value === 'string') {
+ this.emitString(value);
+ } else if (jasmine.isSpy(value)) {
+ this.emitScalar("spy on " + value.identity);
+ } else if (value instanceof RegExp) {
+ this.emitScalar(value.toString());
+ } else if (typeof value === 'function') {
+ this.emitScalar('Function');
+ } else if (typeof value.nodeType === 'number') {
+ this.emitScalar('HTMLNode');
+ } else if (value instanceof Date) {
+ this.emitScalar('Date(' + value + ')');
+ } else if (value.__Jasmine_been_here_before__) {
+ this.emitScalar('<circular reference: ' + (jasmine.isArray_(value) ? 'Array' : 'Object') + '>');
+ } else if (jasmine.isArray_(value) || typeof value == 'object') {
+ value.__Jasmine_been_here_before__ = true;
+ if (jasmine.isArray_(value)) {
+ this.emitArray(value);
+ } else {
+ this.emitObject(value);
+ }
+ delete value.__Jasmine_been_here_before__;
+ } else {
+ this.emitScalar(value.toString());
+ }
+ } finally {
+ this.ppNestLevel_--;
+ }
+};
+
+jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) {
+ for (var property in obj) {
+ if (property == '__Jasmine_been_here_before__') continue;
+ fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) !== jasmine.undefined &&
+ obj.__lookupGetter__(property) !== null) : false);
+ }
+};
+
+jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_;
+jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_;
+jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_;
+jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_;
+
+jasmine.StringPrettyPrinter = function() {
+ jasmine.PrettyPrinter.call(this);
+
+ this.string = '';
+};
+jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter);
+
+jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) {
+ this.append(value);
+};
+
+jasmine.StringPrettyPrinter.prototype.emitString = function(value) {
+ this.append("'" + value + "'");
+};
+
+jasmine.StringPrettyPrinter.prototype.emitArray = function(array) {
+ this.append('[ ');
+ for (var i = 0; i < array.length; i++) {
+ if (i > 0) {
+ this.append(', ');
+ }
+ this.format(array[i]);
+ }
+ this.append(' ]');
+};
+
+jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) {
+ var self = this;
+ this.append('{ ');
+ var first = true;
+
+ this.iterateObject(obj, function(property, isGetter) {
+ if (first) {
+ first = false;
+ } else {
+ self.append(', ');
+ }
+
+ self.append(property);
+ self.append(' : ');
+ if (isGetter) {
+ self.append('<getter>');
+ } else {
+ self.format(obj[property]);
+ }
+ });
+
+ this.append(' }');
+};
+
+jasmine.StringPrettyPrinter.prototype.append = function(value) {
+ this.string += value;
+};
+jasmine.Queue = function(env) {
+ this.env = env;
+ this.blocks = [];
+ this.running = false;
+ this.index = 0;
+ this.offset = 0;
+ this.abort = false;
+};
+
+jasmine.Queue.prototype.addBefore = function(block) {
+ this.blocks.unshift(block);
+};
+
+jasmine.Queue.prototype.add = function(block) {
+ this.blocks.push(block);
+};
+
+jasmine.Queue.prototype.insertNext = function(block) {
+ this.blocks.splice((this.index + this.offset + 1), 0, block);
+ this.offset++;
+};
+
+jasmine.Queue.prototype.start = function(onComplete) {
+ this.running = true;
+ this.onComplete = onComplete;
+ this.next_();
+};
+
+jasmine.Queue.prototype.isRunning = function() {
+ return this.running;
+};
+
+jasmine.Queue.LOOP_DONT_RECURSE = true;
+
+jasmine.Queue.prototype.next_ = function() {
+ var self = this;
+ var goAgain = true;
+
+ while (goAgain) {
+ goAgain = false;
+
+ if (self.index < self.blocks.length && !this.abort) {
+ var calledSynchronously = true;
+ var completedSynchronously = false;
+
+ var onComplete = function () {
+ if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) {
+ completedSynchronously = true;
+ return;
+ }
+
+ if (self.blocks[self.index].abort) {
+ self.abort = true;
+ }
+
+ self.offset = 0;
+ self.index++;
+
+ var now = new Date().getTime();
+ if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) {
+ self.env.lastUpdate = now;
+ self.env.setTimeout(function() {
+ self.next_();
+ }, 0);
+ } else {
+ if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) {
+ goAgain = true;
+ } else {
+ self.next_();
+ }
+ }
+ };
+ self.blocks[self.index].execute(onComplete);
+
+ calledSynchronously = false;
+ if (completedSynchronously) {
+ onComplete();
+ }
+
+ } else {
+ self.running = false;
+ if (self.onComplete) {
+ self.onComplete();
+ }
+ }
+ }
+};
+
+jasmine.Queue.prototype.results = function() {
+ var results = new jasmine.NestedResults();
+ for (var i = 0; i < this.blocks.length; i++) {
+ if (this.blocks[i].results) {
+ results.addResult(this.blocks[i].results());
+ }
+ }
+ return results;
+};
+
+
+/**
+ * Runner
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ */
+jasmine.Runner = function(env) {
+ var self = this;
+ self.env = env;
+ self.queue = new jasmine.Queue(env);
+ self.before_ = [];
+ self.after_ = [];
+ self.suites_ = [];
+};
+
+jasmine.Runner.prototype.execute = function() {
+ var self = this;
+ if (self.env.reporter.reportRunnerStarting) {
+ self.env.reporter.reportRunnerStarting(this);
+ }
+ self.queue.start(function () {
+ self.finishCallback();
+ });
+};
+
+jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) {
+ beforeEachFunction.typeName = 'beforeEach';
+ this.before_.splice(0,0,beforeEachFunction);
+};
+
+jasmine.Runner.prototype.afterEach = function(afterEachFunction) {
+ afterEachFunction.typeName = 'afterEach';
+ this.after_.splice(0,0,afterEachFunction);
+};
+
+
+jasmine.Runner.prototype.finishCallback = function() {
+ this.env.reporter.reportRunnerResults(this);
+};
+
+jasmine.Runner.prototype.addSuite = function(suite) {
+ this.suites_.push(suite);
+};
+
+jasmine.Runner.prototype.add = function(block) {
+ if (block instanceof jasmine.Suite) {
+ this.addSuite(block);
+ }
+ this.queue.add(block);
+};
+
+jasmine.Runner.prototype.specs = function () {
+ var suites = this.suites();
+ var specs = [];
+ for (var i = 0; i < suites.length; i++) {
+ specs = specs.concat(suites[i].specs());
+ }
+ return specs;
+};
+
+jasmine.Runner.prototype.suites = function() {
+ return this.suites_;
+};
+
+jasmine.Runner.prototype.topLevelSuites = function() {
+ var topLevelSuites = [];
+ for (var i = 0; i < this.suites_.length; i++) {
+ if (!this.suites_[i].parentSuite) {
+ topLevelSuites.push(this.suites_[i]);
+ }
+ }
+ return topLevelSuites;
+};
+
+jasmine.Runner.prototype.results = function() {
+ return this.queue.results();
+};
+/**
+ * Internal representation of a Jasmine specification, or test.
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param {jasmine.Suite} suite
+ * @param {String} description
+ */
+jasmine.Spec = function(env, suite, description) {
+ if (!env) {
+ throw new Error('jasmine.Env() required');
+ }
+ if (!suite) {
+ throw new Error('jasmine.Suite() required');
+ }
+ var spec = this;
+ spec.id = env.nextSpecId ? env.nextSpecId() : null;
+ spec.env = env;
+ spec.suite = suite;
+ spec.description = description;
+ spec.queue = new jasmine.Queue(env);
+
+ spec.afterCallbacks = [];
+ spec.spies_ = [];
+
+ spec.results_ = new jasmine.NestedResults();
+ spec.results_.description = description;
+ spec.matchersClass = null;
+};
+
+jasmine.Spec.prototype.getFullName = function() {
+ return this.suite.getFullName() + ' ' + this.description + '.';
+};
+
+
+jasmine.Spec.prototype.results = function() {
+ return this.results_;
+};
+
+/**
+ * All parameters are pretty-printed and concatenated together, then written to the spec's output.
+ *
+ * Be careful not to leave calls to <code>jasmine.log</code> in production code.
+ */
+jasmine.Spec.prototype.log = function() {
+ return this.results_.log(arguments);
+};
+
+jasmine.Spec.prototype.runs = function (func) {
+ var block = new jasmine.Block(this.env, func, this);
+ this.addToQueue(block);
+ return this;
+};
+
+jasmine.Spec.prototype.addToQueue = function (block) {
+ if (this.queue.isRunning()) {
+ this.queue.insertNext(block);
+ } else {
+ this.queue.add(block);
+ }
+};
+
+/**
+ * @param {jasmine.ExpectationResult} result
+ */
+jasmine.Spec.prototype.addMatcherResult = function(result) {
+ this.results_.addResult(result);
+};
+
+jasmine.Spec.prototype.expect = function(actual) {
+ var positive = new (this.getMatchersClass_())(this.env, actual, this);
+ positive.not = new (this.getMatchersClass_())(this.env, actual, this, true);
+ return positive;
+};
+
+/**
+ * Waits a fixed time period before moving to the next block.
+ *
+ * @deprecated Use waitsFor() instead
+ * @param {Number} timeout milliseconds to wait
+ */
+jasmine.Spec.prototype.waits = function(timeout) {
+ var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this);
+ this.addToQueue(waitsFunc);
+ return this;
+};
+
+/**
+ * Waits for the latchFunction to return true before proceeding to the next block.
+ *
+ * @param {Function} latchFunction
+ * @param {String} optional_timeoutMessage
+ * @param {Number} optional_timeout
+ */
+jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
+ var latchFunction_ = null;
+ var optional_timeoutMessage_ = null;
+ var optional_timeout_ = null;
+
+ for (var i = 0; i < arguments.length; i++) {
+ var arg = arguments[i];
+ switch (typeof arg) {
+ case 'function':
+ latchFunction_ = arg;
+ break;
+ case 'string':
+ optional_timeoutMessage_ = arg;
+ break;
+ case 'number':
+ optional_timeout_ = arg;
+ break;
+ }
+ }
+
+ var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this);
+ this.addToQueue(waitsForFunc);
+ return this;
+};
+
+jasmine.Spec.prototype.fail = function (e) {
+ var expectationResult = new jasmine.ExpectationResult({
+ passed: false,
+ message: e ? jasmine.util.formatException(e) : 'Exception',
+ trace: { stack: e.stack }
+ });
+ this.results_.addResult(expectationResult);
+};
+
+jasmine.Spec.prototype.getMatchersClass_ = function() {
+ return this.matchersClass || this.env.matchersClass;
+};
+
+jasmine.Spec.prototype.addMatchers = function(matchersPrototype) {
+ var parent = this.getMatchersClass_();
+ var newMatchersClass = function() {
+ parent.apply(this, arguments);
+ };
+ jasmine.util.inherit(newMatchersClass, parent);
+ jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass);
+ this.matchersClass = newMatchersClass;
+};
+
+jasmine.Spec.prototype.finishCallback = function() {
+ this.env.reporter.reportSpecResults(this);
+};
+
+jasmine.Spec.prototype.finish = function(onComplete) {
+ this.removeAllSpies();
+ this.finishCallback();
+ if (onComplete) {
+ onComplete();
+ }
+};
+
+jasmine.Spec.prototype.after = function(doAfter) {
+ if (this.queue.isRunning()) {
+ this.queue.add(new jasmine.Block(this.env, doAfter, this));
+ } else {
+ this.afterCallbacks.unshift(doAfter);
+ }
+};
+
+jasmine.Spec.prototype.execute = function(onComplete) {
+ var spec = this;
+ if (!spec.env.specFilter(spec)) {
+ spec.results_.skipped = true;
+ spec.finish(onComplete);
+ return;
+ }
+
+ this.env.reporter.reportSpecStarting(this);
+
+ spec.env.currentSpec = spec;
+
+ spec.addBeforesAndAftersToQueue();
+
+ spec.queue.start(function () {
+ spec.finish(onComplete);
+ });
+};
+
+jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() {
+ var runner = this.env.currentRunner();
+ var i;
+
+ for (var suite = this.suite; suite; suite = suite.parentSuite) {
+ for (i = 0; i < suite.before_.length; i++) {
+ this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this));
+ }
+ }
+ for (i = 0; i < runner.before_.length; i++) {
+ this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this));
+ }
+ for (i = 0; i < this.afterCallbacks.length; i++) {
+ this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this));
+ }
+ for (suite = this.suite; suite; suite = suite.parentSuite) {
+ for (i = 0; i < suite.after_.length; i++) {
+ this.queue.add(new jasmine.Block(this.env, suite.after_[i], this));
+ }
+ }
+ for (i = 0; i < runner.after_.length; i++) {
+ this.queue.add(new jasmine.Block(this.env, runner.after_[i], this));
+ }
+};
+
+jasmine.Spec.prototype.explodes = function() {
+ throw 'explodes function should not have been called';
+};
+
+jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) {
+ if (obj == jasmine.undefined) {
+ throw "spyOn could not find an object to spy upon for " + methodName + "()";
+ }
+
+ if (!ignoreMethodDoesntExist && obj[methodName] === jasmine.undefined) {
+ throw methodName + '() method does not exist';
+ }
+
+ if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) {
+ throw new Error(methodName + ' has already been spied upon');
+ }
+
+ var spyObj = jasmine.createSpy(methodName);
+
+ this.spies_.push(spyObj);
+ spyObj.baseObj = obj;
+ spyObj.methodName = methodName;
+ spyObj.originalValue = obj[methodName];
+
+ obj[methodName] = spyObj;
+
+ return spyObj;
+};
+
+jasmine.Spec.prototype.removeAllSpies = function() {
+ for (var i = 0; i < this.spies_.length; i++) {
+ var spy = this.spies_[i];
+ spy.baseObj[spy.methodName] = spy.originalValue;
+ }
+ this.spies_ = [];
+};
+
+/**
+ * Internal representation of a Jasmine suite.
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param {String} description
+ * @param {Function} specDefinitions
+ * @param {jasmine.Suite} parentSuite
+ */
+jasmine.Suite = function(env, description, specDefinitions, parentSuite) {
+ var self = this;
+ self.id = env.nextSuiteId ? env.nextSuiteId() : null;
+ self.description = description;
+ self.queue = new jasmine.Queue(env);
+ self.parentSuite = parentSuite;
+ self.env = env;
+ self.before_ = [];
+ self.after_ = [];
+ self.children_ = [];
+ self.suites_ = [];
+ self.specs_ = [];
+};
+
+jasmine.Suite.prototype.getFullName = function() {
+ var fullName = this.description;
+ for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
+ fullName = parentSuite.description + ' ' + fullName;
+ }
+ return fullName;
+};
+
+jasmine.Suite.prototype.finish = function(onComplete) {
+ this.env.reporter.reportSuiteResults(this);
+ this.finished = true;
+ if (typeof(onComplete) == 'function') {
+ onComplete();
+ }
+};
+
+jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) {
+ beforeEachFunction.typeName = 'beforeEach';
+ this.before_.unshift(beforeEachFunction);
+};
+
+jasmine.Suite.prototype.afterEach = function(afterEachFunction) {
+ afterEachFunction.typeName = 'afterEach';
+ this.after_.unshift(afterEachFunction);
+};
+
+jasmine.Suite.prototype.results = function() {
+ return this.queue.results();
+};
+
+jasmine.Suite.prototype.add = function(suiteOrSpec) {
+ this.children_.push(suiteOrSpec);
+ if (suiteOrSpec instanceof jasmine.Suite) {
+ this.suites_.push(suiteOrSpec);
+ this.env.currentRunner().addSuite(suiteOrSpec);
+ } else {
+ this.specs_.push(suiteOrSpec);
+ }
+ this.queue.add(suiteOrSpec);
+};
+
+jasmine.Suite.prototype.specs = function() {
+ return this.specs_;
+};
+
+jasmine.Suite.prototype.suites = function() {
+ return this.suites_;
+};
+
+jasmine.Suite.prototype.children = function() {
+ return this.children_;
+};
+
+jasmine.Suite.prototype.execute = function(onComplete) {
+ var self = this;
+ this.queue.start(function () {
+ self.finish(onComplete);
+ });
+};
+jasmine.WaitsBlock = function(env, timeout, spec) {
+ this.timeout = timeout;
+ jasmine.Block.call(this, env, null, spec);
+};
+
+jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block);
+
+jasmine.WaitsBlock.prototype.execute = function (onComplete) {
+ if (jasmine.VERBOSE) {
+ this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...');
+ }
+ this.env.setTimeout(function () {
+ onComplete();
+ }, this.timeout);
+};
+/**
+ * A block which waits for some condition to become true, with timeout.
+ *
+ * @constructor
+ * @extends jasmine.Block
+ * @param {jasmine.Env} env The Jasmine environment.
+ * @param {Number} timeout The maximum time in milliseconds to wait for the condition to become true.
+ * @param {Function} latchFunction A function which returns true when the desired condition has been met.
+ * @param {String} message The message to display if the desired condition hasn't been met within the given time period.
+ * @param {jasmine.Spec} spec The Jasmine spec.
+ */
+jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) {
+ this.timeout = timeout || env.defaultTimeoutInterval;
+ this.latchFunction = latchFunction;
+ this.message = message;
+ this.totalTimeSpentWaitingForLatch = 0;
+ jasmine.Block.call(this, env, null, spec);
+};
+jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block);
+
+jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 10;
+
+jasmine.WaitsForBlock.prototype.execute = function(onComplete) {
+ if (jasmine.VERBOSE) {
+ this.env.reporter.log('>> Jasmine waiting for ' + (this.message || 'something to happen'));
+ }
+ var latchFunctionResult;
+ try {
+ latchFunctionResult = this.latchFunction.apply(this.spec);
+ } catch (e) {
+ this.spec.fail(e);
+ onComplete();
+ return;
+ }
+
+ if (latchFunctionResult) {
+ onComplete();
+ } else if (this.totalTimeSpentWaitingForLatch >= this.timeout) {
+ var message = 'timed out after ' + this.timeout + ' msec waiting for ' + (this.message || 'something to happen');
+ this.spec.fail({
+ name: 'timeout',
+ message: message
+ });
+
+ this.abort = true;
+ onComplete();
+ } else {
+ this.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT;
+ var self = this;
+ this.env.setTimeout(function() {
+ self.execute(onComplete);
+ }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT);
+ }
+};
+
+jasmine.version_= {
+ "major": 1,
+ "minor": 2,
+ "build": 0,
+ "revision": 1333310630,
+ "release_candidate": 1
+};
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/accelerometer.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/accelerometer.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/accelerometer.html
new file mode 100644
index 0000000..bac1836
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/accelerometer.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Cordova: Accelerometer API Specs</title>
+
+ <meta name="viewport" content="width=device-width, height=device-height, user-scalable=yes, initial-scale=1.0;" />
+
+ <!-- Load jasmine -->
+ <link href="../jasmine.css" rel="stylesheet"/>
+ <script type="text/javascript" src="../jasmine.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporterHelpers.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporter.js"></script>
+ <script type="text/javascript" src="../html/ReporterView.js"></script>
+ <script type="text/javascript" src="../html/SpecView.js"></script>
+ <script type="text/javascript" src="../html/SuiteView.js"></script>
+ <script type="text/javascript" src="../html/TrivialReporter.js"></script>
+
+ <!-- Source -->
+ <script type="text/javascript" src="../../cordova.js"></script>
+
+ <!-- Load Test Runner -->
+ <script type="text/javascript" src="../test-runner.js"></script>
+
+ <!-- Tests -->
+ <script type="text/javascript" src="../tests/accelerometer.tests.js"></script>
+
+ <script type="text/javascript">
+ document.addEventListener('deviceready', function () {
+ var jasmineEnv = jasmine.getEnv();
+ jasmineEnv.updateInterval = 1000;
+
+ var htmlReporter = new jasmine.HtmlReporter();
+
+ jasmineEnv.addReporter(htmlReporter);
+
+ jasmineEnv.specFilter = function(spec) {
+ return htmlReporter.specFilter(spec);
+ };
+
+ jasmineEnv.execute();
+ }, false);
+ </script>
+</head>
+
+<body>
+ <a href="javascript:" class="backBtn" onclick="backHome();">Back</a>
+</body>
+</html>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/all.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/all.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/all.html
new file mode 100644
index 0000000..c6cc910
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/all.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Cordova: API Specs</title>
+
+ <meta name="viewport" content="width=device-width, height=device-height, user-scalable=yes, initial-scale=1.0;" />
+
+ <!-- Load jasmine -->
+ <link href="../jasmine.css" rel="stylesheet"/>
+ <script type="text/javascript" src="../jasmine.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporterHelpers.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporter.js"></script>
+ <script type="text/javascript" src="../html/ReporterView.js"></script>
+ <script type="text/javascript" src="../html/SpecView.js"></script>
+ <script type="text/javascript" src="../html/SuiteView.js"></script>
+ <script type="text/javascript" src="../html/TrivialReporter.js"></script>
+
+ <!-- Source -->
+ <script type="text/javascript" src="../../cordova.js"></script>
+
+ <!-- Load Test Runner -->
+ <script type="text/javascript" src="../test-runner.js"></script>
+
+ <!-- Tests -->
+ <script type="text/javascript" src="../tests/accelerometer.tests.js"></script>
+ <script type="text/javascript" src="../tests/battery.tests.js"></script>
+ <script type="text/javascript" src="../tests/capture.tests.js"></script>
+ <script type="text/javascript" src="../tests/compass.tests.js"></script>
+ <script type="text/javascript" src="../tests/contacts.tests.js"></script>
+ <script type="text/javascript" src="../tests/camera.tests.js"></script>
+ <script type="text/javascript" src="../tests/datauri.tests.js"></script>
+ <script type="text/javascript" src="../tests/device.tests.js"></script>
+ <script type="text/javascript" src="../tests/file.tests.js"></script>
+ <script type="text/javascript" src="../tests/filetransfer.tests.js"></script>
+ <script type="text/javascript" src="../tests/geolocation.tests.js"></script>
+ <!-- script type="text/javascript" src="../tests/globalization.tests.js"></script -->
+ <script type="text/javascript" src="../tests/media.tests.js"></script>
+ <script type="text/javascript" src="../tests/network.tests.js"></script>
+ <script type="text/javascript" src="../tests/notification.tests.js"></script>
+ <script type="text/javascript" src="../tests/platform.tests.js"></script>
+ <script type="text/javascript" src="../tests/storage.tests.js"></script>
+
+ <script type="text/javascript">
+ var root, temp_root, persistent_root;
+
+ document.addEventListener('deviceready', function () {
+ // one-time retrieval of the root file system entry
+ var onError = function(e) {
+ console.log('[ERROR] Problem setting up root filesystem for test running! Error to follow.');
+ console.log(JSON.stringify(e));
+ };
+
+ window.requestFileSystem(LocalFileSystem.PERSISTENT, 0,
+ function(fileSystem) {
+ console.log('File API test Init: Setting PERSISTENT FS.');
+ root = fileSystem.root; // set in file.tests.js
+ persistent_root = root;
+
+ // Once root is set up, fire off tests
+ var jasmineEnv = jasmine.getEnv();
+ jasmineEnv.updateInterval = 1000;
+
+ var htmlReporter = new jasmine.HtmlReporter();
+
+ jasmineEnv.addReporter(htmlReporter);
+
+ jasmineEnv.specFilter = function(spec) {
+ return htmlReporter.specFilter(spec);
+ };
+
+ jasmineEnv.execute();
+ }, onError);
+ window.requestFileSystem(LocalFileSystem.TEMPORARY, 0,
+ function(fileSystem) {
+ console.log('File API test Init: Setting TEMPORARY FS.');
+ temp_root = fileSystem.root; // set in file.tests.js
+ }, onError);
+ }, false);
+ </script>
+</head>
+
+<body>
+ <a href="javascript:" class="backBtn" onclick="backHome();">Back</a>
+</body>
+</html>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/battery.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/battery.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/battery.html
new file mode 100644
index 0000000..8441950
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/battery.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Cordova: Battery API Specs</title>
+
+ <meta name="viewport" content="width=device-width, height=device-height, user-scalable=yes, initial-scale=1.0;" />
+
+ <link href="../jasmine.css" rel="stylesheet"/>
+ <script type="text/javascript" src="../jasmine.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporterHelpers.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporter.js"></script>
+ <script type="text/javascript" src="../html/ReporterView.js"></script>
+ <script type="text/javascript" src="../html/SpecView.js"></script>
+ <script type="text/javascript" src="../html/SuiteView.js"></script>
+ <script type="text/javascript" src="../html/TrivialReporter.js"></script>
+ <script type="text/javascript" src="../../cordova.js"></script>
+
+ <!-- Load Test Runner -->
+ <script type="text/javascript" src="../test-runner.js"></script>
+
+ <!-- Tests -->
+ <script type="text/javascript" src="../tests/battery.tests.js"></script>
+ <script type="text/javascript">
+ document.addEventListener('deviceready', function () {
+ var jasmineEnv = jasmine.getEnv();
+ jasmineEnv.updateInterval = 1000;
+
+ var htmlReporter = new jasmine.HtmlReporter();
+
+ jasmineEnv.addReporter(htmlReporter);
+
+ jasmineEnv.specFilter = function(spec) {
+ return htmlReporter.specFilter(spec);
+ };
+
+ jasmineEnv.execute();
+ }, false);
+ </script>
+</head>
+
+<body>
+ <a href="javascript:" class="backBtn" onclick="backHome();">Back</a>
+</body>
+</html>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/bridge.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/bridge.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/bridge.html
new file mode 100644
index 0000000..a1d0a90
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/bridge.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<!--
+
+ 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.
+
+-->
+
+
+<html>
+
+<head>
+ <title>Cordova: Device API Specs</title>
+
+ <meta name="viewport" content="width=device-width, height=device-height, user-scalable=yes, initial-scale=1.0;" />
+ <!-- Load jasmine -->
+ <link href="../jasmine.css" rel="stylesheet"/>
+ <script type="text/javascript" src="../jasmine.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporterHelpers.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporter.js"></script>
+ <script type="text/javascript" src="../html/ReporterView.js"></script>
+ <script type="text/javascript" src="../html/SpecView.js"></script>
+ <script type="text/javascript" src="../html/SuiteView.js"></script>
+ <script type="text/javascript" src="../html/TrivialReporter.js"></script>
+
+ <!-- Source -->
+ <script type="text/javascript" src="../../cordova.js"></script>
+
+ <!-- Load Test Runner -->
+ <script type="text/javascript" src="../test-runner.js"></script>
+
+ <!-- Tests -->
+ <script type="text/javascript" src="../tests/bridge.tests.js"></script>
+
+ <script type="text/javascript">
+ document.addEventListener('deviceready', function () {
+ var jasmineEnv = jasmine.getEnv();
+ jasmineEnv.updateInterval = 1000;
+
+ var htmlReporter = new jasmine.HtmlReporter();
+
+ jasmineEnv.addReporter(htmlReporter);
+
+ jasmineEnv.specFilter = function(spec) {
+ return htmlReporter.specFilter(spec);
+ };
+
+ jasmineEnv.execute();
+ }, false);
+ </script>
+</head>
+
+<body>
+ <a href="javascript:" class="backBtn" onclick="backHome();">Back</a>
+</body>
+</html>
+
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/camera.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/camera.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/camera.html
new file mode 100644
index 0000000..e136f27
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/camera.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <title>Cordova: Camera API Specs</title>
+
+ <meta name="viewport" content="width=device-width, height=device-height, user-scalable=yes, initial-scale=1.0;" />
+
+ <!-- Load jasmine -->
+ <link href="../jasmine.css" rel="stylesheet"/>
+ <script type="text/javascript" src="../jasmine.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporterHelpers.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporter.js"></script>
+ <script type="text/javascript" src="../html/ReporterView.js"></script>
+ <script type="text/javascript" src="../html/SpecView.js"></script>
+ <script type="text/javascript" src="../html/SuiteView.js"></script>
+ <script type="text/javascript" src="../html/TrivialReporter.js"></script>
+
+ <!-- Source -->
+ <script type="text/javascript" src="../../cordova.js"></script>
+
+ <!-- Load Test Runner -->
+ <script type="text/javascript" src="../test-runner.js"></script>
+
+ <!-- Tests -->
+ <script type="text/javascript" src="../tests/camera.tests.js"></script>
+
+ <script type="text/javascript">
+ document.addEventListener('deviceready', function () {
+ var jasmineEnv = jasmine.getEnv();
+ jasmineEnv.updateInterval = 1000;
+
+ var htmlReporter = new jasmine.HtmlReporter();
+
+ jasmineEnv.addReporter(htmlReporter);
+
+ jasmineEnv.specFilter = function(spec) {
+ return htmlReporter.specFilter(spec);
+ };
+
+ jasmineEnv.execute();
+ }, false);
+ </script>
+</head>
+
+<body>
+ <a href="javascript:" class="backBtn" onclick="backHome();">Back</a>
+</body>
+</html>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/capture.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/capture.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/capture.html
new file mode 100644
index 0000000..0cb2baf
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/capture.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <title>Cordova: Capture API Specs</title>
+
+ <meta name="viewport" content="width=device-width, height=device-height, user-scalable=yes, initial-scale=1.0;" />
+ <!-- Load jasmine -->
+ <link href="../jasmine.css" rel="stylesheet"/>
+ <script type="text/javascript" src="../jasmine.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporterHelpers.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporter.js"></script>
+ <script type="text/javascript" src="../html/ReporterView.js"></script>
+ <script type="text/javascript" src="../html/SpecView.js"></script>
+ <script type="text/javascript" src="../html/SuiteView.js"></script>
+ <script type="text/javascript" src="../html/TrivialReporter.js"></script>
+
+ <!-- Source -->
+ <script type="text/javascript" src="../../cordova.js"></script>
+
+ <!-- Load Test Runner -->
+ <script type="text/javascript" src="../test-runner.js"></script>
+
+ <!-- Tests -->
+ <script type="text/javascript" src="../tests/capture.tests.js"></script>
+
+ <script type="text/javascript">
+ document.addEventListener('deviceready', function () {
+ var jasmineEnv = jasmine.getEnv();
+ jasmineEnv.updateInterval = 1000;
+
+ var htmlReporter = new jasmine.HtmlReporter();
+
+ jasmineEnv.addReporter(htmlReporter);
+
+ jasmineEnv.specFilter = function(spec) {
+ return htmlReporter.specFilter(spec);
+ };
+
+ jasmineEnv.execute();
+ }, false);
+ </script>
+</head>
+
+<body>
+ <a href="javascript:" class="backBtn" onclick="backHome();">Back</a>
+</body>
+</html>
+
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/compass.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/compass.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/compass.html
new file mode 100644
index 0000000..dfd9975
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/compass.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <title>Cordova: Compass API Specs</title>
+
+ <meta name="viewport" content="width=device-width, height=device-height, user-scalable=yes, initial-scale=1.0;" />
+ <!-- Load jasmine -->
+ <link href="../jasmine.css" rel="stylesheet"/>
+ <script type="text/javascript" src="../jasmine.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporterHelpers.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporter.js"></script>
+ <script type="text/javascript" src="../html/ReporterView.js"></script>
+ <script type="text/javascript" src="../html/SpecView.js"></script>
+ <script type="text/javascript" src="../html/SuiteView.js"></script>
+ <script type="text/javascript" src="../html/TrivialReporter.js"></script>
+
+ <!-- Source -->
+ <script type="text/javascript" src="../../cordova.js"></script>
+
+ <!-- Load Test Runner -->
+ <script type="text/javascript" src="../test-runner.js"></script>
+
+ <!-- Tests -->
+ <script type="text/javascript" src="../tests/compass.tests.js"></script>
+
+ <script type="text/javascript">
+ document.addEventListener('deviceready', function () {
+ var jasmineEnv = jasmine.getEnv();
+ jasmineEnv.updateInterval = 1000;
+
+ var htmlReporter = new jasmine.HtmlReporter();
+
+ jasmineEnv.addReporter(htmlReporter);
+
+ jasmineEnv.specFilter = function(spec) {
+ return htmlReporter.specFilter(spec);
+ };
+
+ jasmineEnv.execute();
+ }, false);
+ </script>
+</head>
+
+<body>
+ <a href="javascript:" class="backBtn" onclick="backHome();">Back</a>
+</body>
+</html>
+
[28/37] Add WP7 and WP8 platform files.
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/Compass.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/Compass.cs b/lib/cordova-wp7/templates/standalone/Plugins/Compass.cs
new file mode 100644
index 0000000..c9e1c4d
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/Compass.cs
@@ -0,0 +1,362 @@
+/*
+ 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 DeviceCompass = Microsoft.Devices.Sensors.Compass;
+using System.Windows.Threading;
+using System.Runtime.Serialization;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.Threading;
+using Microsoft.Devices.Sensors;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+
+ public class Compass : BaseCommand
+ {
+ #region Static members
+
+ /// <summary>
+ /// Status of listener
+ /// </summary>
+ private static int currentStatus;
+
+ /// <summary>
+ /// Id for get getCompass method
+ /// </summary>
+ private static string getCompassId = "getCompassId";
+
+ /// <summary>
+ /// Compass
+ /// </summary>
+ private static DeviceCompass compass = new DeviceCompass();
+
+ /// <summary>
+ /// Listeners for callbacks
+ /// </summary>
+ private static Dictionary<string, Compass> watchers = new Dictionary<string, Compass>();
+
+ #endregion
+
+ #region Status codes
+
+ public const int Stopped = 0;
+ public const int Starting = 1;
+ public const int Running = 2;
+ public const int ErrorFailedToStart = 4;
+ public const int Not_Supported = 20;
+
+ /*
+ * // Capture error codes
+ CompassError.COMPASS_INTERNAL_ERR = 0;
+ CompassError.COMPASS_NOT_SUPPORTED = 20;
+ * */
+
+ #endregion
+
+ #region CompassOptions class
+ /// <summary>
+ /// Represents Accelerometer options.
+ /// </summary>
+ [DataContract]
+ public class CompassOptions
+ {
+ /// <summary>
+ /// How often to retrieve the Acceleration in milliseconds
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "frequency")]
+ public int Frequency { get; set; }
+
+ /// <summary>
+ /// The change in degrees required to initiate a watchHeadingFilter success callback.
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "filter")]
+ public int Filter { get; set; }
+
+ /// <summary>
+ /// Watcher id
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "id")]
+ public string Id { get; set; }
+
+ }
+ #endregion
+
+
+ /// <summary>
+ /// Time the value was last changed
+ /// </summary>
+ //private DateTime lastValueChangedTime;
+
+ /// <summary>
+ /// Accelerometer options
+ /// </summary>
+ private CompassOptions compassOptions;
+
+ //bool isDataValid;
+
+ //bool calibrating = false;
+
+ public Compass()
+ {
+
+ }
+
+ /// <summary>
+ /// Formats current coordinates into JSON format
+ /// </summary>
+ /// <returns>Coordinates in JSON format</returns>
+ private string GetHeadingFormatted(CompassReading reading)
+ {
+ // NOTE: timestamp is generated on the JS side, to avoid issues with format conversions
+ string result = String.Format("\"magneticHeading\":{0},\"headingAccuracy\":{1},\"trueHeading\":{2}",
+ reading.MagneticHeading.ToString("0.0", CultureInfo.InvariantCulture),
+ reading.HeadingAccuracy.ToString("0.0", CultureInfo.InvariantCulture),
+ reading.TrueHeading.ToString("0.0", CultureInfo.InvariantCulture));
+ return "{" + result + "}";
+ }
+
+ public void getHeading(string options)
+ {
+ if (!DeviceCompass.IsSupported)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "{code:" + Not_Supported + "}"));
+ }
+ else
+ {
+ //if (compass == null)
+ //{
+ // // Instantiate the compass.
+ // compass = new DeviceCompass();
+ // compass.TimeBetweenUpdates = TimeSpan.FromMilliseconds(40);
+ // compass.CurrentValueChanged += new EventHandler<Microsoft.Devices.Sensors.SensorReadingEventArgs<Microsoft.Devices.Sensors.CompassReading>>(compass_CurrentValueChanged);
+ // compass.Calibrate += new EventHandler<Microsoft.Devices.Sensors.CalibrationEventArgs>(compass_Calibrate);
+ //}
+
+
+ //compass.Start();
+
+ }
+
+ try
+ {
+ if (currentStatus != Running)
+ {
+ lock (compass)
+ {
+ compass.CurrentValueChanged += compass_SingleHeadingValueChanged;
+ compass.Start();
+ this.SetStatus(Starting);
+ }
+
+ long timeout = 2000;
+ while ((currentStatus == Starting) && (timeout > 0))
+ {
+ timeout = timeout - 100;
+ Thread.Sleep(100);
+ }
+
+ if (currentStatus != Running)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, ErrorFailedToStart));
+ return;
+ }
+ }
+ lock (compass)
+ {
+ compass.CurrentValueChanged -= compass_SingleHeadingValueChanged;
+ if (watchers.Count < 1)
+ {
+ compass.Stop();
+ this.SetStatus(Stopped);
+ }
+ }
+ }
+ catch (UnauthorizedAccessException)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ILLEGAL_ACCESS_EXCEPTION, ErrorFailedToStart));
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, ErrorFailedToStart));
+ }
+ }
+
+ void compass_SingleHeadingValueChanged(object sender, Microsoft.Devices.Sensors.SensorReadingEventArgs<CompassReading> e)
+ {
+ this.SetStatus(Running);
+ if (compass.IsDataValid)
+ {
+ // trueHeading :: The heading in degrees from 0 - 359.99 at a single moment in time.
+ // magneticHeading:: The heading relative to the geographic North Pole in degrees 0 - 359.99 at a single moment in time.
+ // A negative value indicates that the true heading could not be determined.
+ // headingAccuracy :: The deviation in degrees between the reported heading and the true heading.
+ //rawMagnetometerReading = e.SensorReading.MagnetometerReading;
+
+ //Debug.WriteLine("Compass Result :: " + GetHeadingFormatted(e.SensorReading));
+
+ PluginResult result = new PluginResult(PluginResult.Status.OK, GetHeadingFormatted(e.SensorReading));
+
+ DispatchCommandResult(result);
+ }
+ }
+
+ /// <summary>
+ /// Starts listening for compass sensor
+ /// </summary>
+ /// <returns>status of listener</returns>
+ private int start()
+ {
+ if ((currentStatus == Running) || (currentStatus == Starting))
+ {
+ return currentStatus;
+ }
+ try
+ {
+ lock (compass)
+ {
+ watchers.Add(getCompassId, this);
+ compass.CurrentValueChanged += watchers[getCompassId].compass_CurrentValueChanged;
+ compass.Start();
+ this.SetStatus(Starting);
+ }
+ }
+ catch (Exception)
+ {
+ this.SetStatus(ErrorFailedToStart);
+ }
+ return currentStatus;
+ }
+
+ public void startWatch(string options)
+ {
+ if (!DeviceCompass.IsSupported)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, Not_Supported));
+ }
+
+ try
+ {
+ compassOptions = JSON.JsonHelper.Deserialize<CompassOptions>(options);
+ }
+ catch (Exception ex)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, ex.Message));
+ return;
+ }
+
+ if (string.IsNullOrEmpty(compassOptions.Id))
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ try
+ {
+ lock (compass)
+ {
+ watchers.Add(compassOptions.Id, this);
+ compass.CurrentValueChanged += watchers[compassOptions.Id].compass_CurrentValueChanged;
+ compass.Start();
+ this.SetStatus(Starting);
+ }
+ }
+ catch (Exception)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, ErrorFailedToStart));
+ return;
+ }
+ }
+
+ public void stopWatch(string options)
+ {
+ try
+ {
+ compassOptions = JSON.JsonHelper.Deserialize<CompassOptions>(options);
+ }
+ catch (Exception ex)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, ex.Message));
+ return;
+ }
+
+ if (string.IsNullOrEmpty(compassOptions.Id))
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ if (currentStatus != Stopped)
+ {
+ lock (compass)
+ {
+ Compass watcher = watchers[compassOptions.Id];
+ compass.CurrentValueChanged -= watcher.compass_CurrentValueChanged;
+ watchers.Remove(compassOptions.Id);
+ watcher.Dispose();
+ }
+ }
+ this.SetStatus(Stopped);
+
+ this.DispatchCommandResult();
+ }
+
+ void compass_Calibrate(object sender, Microsoft.Devices.Sensors.CalibrationEventArgs e)
+ {
+ //throw new NotImplementedException();
+ // TODO: pass calibration error to JS
+ }
+
+ void compass_CurrentValueChanged(object sender, Microsoft.Devices.Sensors.SensorReadingEventArgs<CompassReading> e)
+ {
+ this.SetStatus(Running);
+ if (compass.IsDataValid)
+ {
+ // trueHeading :: The heading in degrees from 0 - 359.99 at a single moment in time.
+ // magneticHeading:: The heading relative to the geographic North Pole in degrees 0 - 359.99 at a single moment in time.
+ // A negative value indicates that the true heading could not be determined.
+ // headingAccuracy :: The deviation in degrees between the reported heading and the true heading.
+ //rawMagnetometerReading = e.SensorReading.MagnetometerReading;
+
+ //Debug.WriteLine("Compass Result :: " + GetHeadingFormatted(e.SensorReading));
+
+ PluginResult result = new PluginResult(PluginResult.Status.OK, GetHeadingFormatted(e.SensorReading));
+ result.KeepCallback = true;
+
+ DispatchCommandResult(result);
+ }
+ }
+
+ /// <summary>
+ /// Sets current status
+ /// </summary>
+ /// <param name="status">current status</param>
+ private void SetStatus(int status)
+ {
+ currentStatus = status;
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/Contacts.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/Contacts.cs b/lib/cordova-wp7/templates/standalone/Plugins/Contacts.cs
new file mode 100644
index 0000000..6789bb8
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/Contacts.cs
@@ -0,0 +1,664 @@
+/*
+ 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 Microsoft.Phone.Tasks;
+using Microsoft.Phone.UserData;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Runtime.Serialization;
+using System.Windows;
+using DeviceContacts = Microsoft.Phone.UserData.Contacts;
+
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ [DataContract]
+ public class SearchOptions
+ {
+ [DataMember]
+ public string filter { get; set; }
+ [DataMember]
+ public bool multiple { get; set; }
+ }
+
+ [DataContract]
+ public class ContactSearchParams
+ {
+ [DataMember]
+ public string[] fields { get; set; }
+ [DataMember]
+ public SearchOptions options { get; set; }
+ }
+
+ [DataContract]
+ public class JSONContactAddress
+ {
+ [DataMember]
+ public string formatted { get; set; }
+ [DataMember]
+ public string type { get; set; }
+ [DataMember]
+ public string streetAddress { get; set; }
+ [DataMember]
+ public string locality { get; set; }
+ [DataMember]
+ public string region { get; set; }
+ [DataMember]
+ public string postalCode { get; set; }
+ [DataMember]
+ public string country { get; set; }
+ [DataMember]
+ public bool pref { get; set; }
+ }
+
+ [DataContract]
+ public class JSONContactName
+ {
+ [DataMember]
+ public string formatted { get; set; }
+ [DataMember]
+ public string familyName { get; set; }
+ [DataMember]
+ public string givenName { get; set; }
+ [DataMember]
+ public string middleName { get; set; }
+ [DataMember]
+ public string honorificPrefix { get; set; }
+ [DataMember]
+ public string honorificSuffix { get; set; }
+ }
+
+ [DataContract]
+ public class JSONContactField
+ {
+ [DataMember]
+ public string type { get; set; }
+ [DataMember]
+ public string value { get; set; }
+ [DataMember]
+ public bool pref { get; set; }
+ }
+
+ [DataContract]
+ public class JSONContactOrganization
+ {
+ [DataMember]
+ public string type { get; set; }
+ [DataMember]
+ public string name { get; set; }
+ [DataMember]
+ public bool pref { get; set; }
+ [DataMember]
+ public string department { get; set; }
+ [DataMember]
+ public string title { get; set; }
+ }
+
+ [DataContract]
+ public class JSONContact
+ {
+ [DataMember]
+ public string id { get; set; }
+ [DataMember]
+ public string rawId { get; set; }
+ [DataMember]
+ public string displayName { get; set; }
+ [DataMember]
+ public string nickname { get; set; }
+ [DataMember]
+ public string note { get; set; }
+
+ [DataMember]
+ public JSONContactName name { get; set; }
+
+ [DataMember]
+ public JSONContactField[] emails { get; set; }
+
+ [DataMember]
+ public JSONContactField[] phoneNumbers { get; set; }
+
+ [DataMember]
+ public JSONContactField[] ims { get; set; }
+
+ [DataMember]
+ public JSONContactField[] photos { get; set; }
+
+ [DataMember]
+ public JSONContactField[] categories { get; set; }
+
+ [DataMember]
+ public JSONContactField[] urls { get; set; }
+
+ [DataMember]
+ public JSONContactOrganization[] organizations { get; set; }
+
+ [DataMember]
+ public JSONContactAddress[] addresses { get; set; }
+ }
+
+
+ public class Contacts : BaseCommand
+ {
+
+ public const int UNKNOWN_ERROR = 0;
+ public const int INVALID_ARGUMENT_ERROR = 1;
+ public const int TIMEOUT_ERROR = 2;
+ public const int PENDING_OPERATION_ERROR = 3;
+ public const int IO_ERROR = 4;
+ public const int NOT_SUPPORTED_ERROR = 5;
+ public const int PERMISSION_DENIED_ERROR = 20;
+ public const int SYNTAX_ERR = 8;
+
+ public Contacts()
+ {
+
+ }
+
+ // refer here for contact properties we can access: http://msdn.microsoft.com/en-us/library/microsoft.phone.tasks.savecontacttask_members%28v=VS.92%29.aspx
+ public void save(string jsonContact)
+ {
+
+ // jsonContact is actually an array of 1 {contact}
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(jsonContact);
+
+
+ JSONContact contact = JSON.JsonHelper.Deserialize<JSONContact>(args[0]);
+
+ SaveContactTask contactTask = new SaveContactTask();
+
+ if (contact.nickname != null)
+ {
+ contactTask.Nickname = contact.nickname;
+ }
+ if (contact.urls != null && contact.urls.Length > 0)
+ {
+ contactTask.Website = contact.urls[0].value;
+ }
+ if (contact.note != null)
+ {
+ contactTask.Notes = contact.note;
+ }
+
+ #region contact.name
+ if (contact.name != null)
+ {
+ if (contact.name.givenName != null)
+ contactTask.FirstName = contact.name.givenName;
+ if (contact.name.familyName != null)
+ contactTask.LastName = contact.name.familyName;
+ if (contact.name.middleName != null)
+ contactTask.MiddleName = contact.name.middleName;
+ if (contact.name.honorificSuffix != null)
+ contactTask.Suffix = contact.name.honorificSuffix;
+ if (contact.name.honorificPrefix != null)
+ contactTask.Title = contact.name.honorificPrefix;
+ }
+ #endregion
+
+ #region contact.org
+ if (contact.organizations != null && contact.organizations.Count() > 0)
+ {
+ contactTask.Company = contact.organizations[0].name;
+ contactTask.JobTitle = contact.organizations[0].title;
+ }
+ #endregion
+
+ #region contact.phoneNumbers
+ if (contact.phoneNumbers != null && contact.phoneNumbers.Length > 0)
+ {
+ foreach (JSONContactField field in contact.phoneNumbers)
+ {
+ string fieldType = field.type.ToLower();
+ if (fieldType == "work")
+ {
+ contactTask.WorkPhone = field.value;
+ }
+ else if (fieldType == "home")
+ {
+ contactTask.HomePhone = field.value;
+ }
+ else if (fieldType == "mobile")
+ {
+ contactTask.MobilePhone = field.value;
+ }
+ }
+ }
+ #endregion
+
+ #region contact.emails
+
+ if (contact.emails != null && contact.emails.Length > 0)
+ {
+
+ // set up different email types if they are not explicitly defined
+ foreach (string type in new string[] { "personal", "work", "other" })
+ {
+ foreach (JSONContactField field in contact.emails)
+ {
+ if (field != null && String.IsNullOrEmpty(field.type))
+ {
+ field.type = type;
+ break;
+ }
+ }
+ }
+
+ foreach (JSONContactField field in contact.emails)
+ {
+ if (field != null)
+ {
+ if (field.type != null && field.type != "other")
+ {
+ string fieldType = field.type.ToLower();
+ if (fieldType == "work")
+ {
+ contactTask.WorkEmail = field.value;
+ }
+ else if (fieldType == "home" || fieldType == "personal")
+ {
+ contactTask.PersonalEmail = field.value;
+ }
+ }
+ else
+ {
+ contactTask.OtherEmail = field.value;
+ }
+ }
+
+ }
+ }
+ #endregion
+
+ if (contact.note != null && contact.note.Length > 0)
+ {
+ contactTask.Notes = contact.note;
+ }
+
+ #region contact.addresses
+ if (contact.addresses != null && contact.addresses.Length > 0)
+ {
+ foreach (JSONContactAddress address in contact.addresses)
+ {
+ if (address.type == null)
+ {
+ address.type = "home"; // set a default
+ }
+ string fieldType = address.type.ToLower();
+ if (fieldType == "work")
+ {
+ contactTask.WorkAddressCity = address.locality;
+ contactTask.WorkAddressCountry = address.country;
+ contactTask.WorkAddressState = address.region;
+ contactTask.WorkAddressStreet = address.streetAddress;
+ contactTask.WorkAddressZipCode = address.postalCode;
+ }
+ else if (fieldType == "home" || fieldType == "personal")
+ {
+ contactTask.HomeAddressCity = address.locality;
+ contactTask.HomeAddressCountry = address.country;
+ contactTask.HomeAddressState = address.region;
+ contactTask.HomeAddressStreet = address.streetAddress;
+ contactTask.HomeAddressZipCode = address.postalCode;
+ }
+ else
+ {
+ // no other address fields available ...
+ Debug.WriteLine("Creating contact with unsupported address type :: " + address.type);
+ }
+ }
+ }
+ #endregion
+
+
+ contactTask.Completed += new EventHandler<SaveContactResult>(ContactSaveTaskCompleted);
+ contactTask.Show();
+ }
+
+ void ContactSaveTaskCompleted(object sender, SaveContactResult e)
+ {
+ SaveContactTask task = sender as SaveContactTask;
+
+ if (e.TaskResult == TaskResult.OK)
+ {
+
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ DeviceContacts deviceContacts = new DeviceContacts();
+ deviceContacts.SearchCompleted += new EventHandler<ContactsSearchEventArgs>(postAdd_SearchCompleted);
+
+ string displayName = String.Format("{0}{2}{1}", task.FirstName, task.LastName, String.IsNullOrEmpty(task.FirstName) ? "" : " ");
+
+ deviceContacts.SearchAsync(displayName, FilterKind.DisplayName, task);
+ });
+
+
+ }
+ else if (e.TaskResult == TaskResult.Cancel)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Operation cancelled."));
+ }
+ }
+
+ void postAdd_SearchCompleted(object sender, ContactsSearchEventArgs e)
+ {
+ if (e.Results.Count() > 0)
+ {
+ List<Contact> foundContacts = new List<Contact>();
+
+ int n = (from Contact contact in e.Results select contact.GetHashCode()).Max();
+ Contact newContact = (from Contact contact in e.Results
+ where contact.GetHashCode() == n
+ select contact).First();
+
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, FormatJSONContact(newContact, null)));
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.NO_RESULT));
+ }
+ }
+
+
+
+ public void remove(string id)
+ {
+ // note id is wrapped in [] and always has exactly one string ...
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "{\"code\":" + NOT_SUPPORTED_ERROR + "}"));
+ }
+
+ public void search(string searchCriteria)
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(searchCriteria);
+
+ ContactSearchParams searchParams = new ContactSearchParams();
+ try
+ {
+ searchParams.fields = JSON.JsonHelper.Deserialize<string[]>(args[0]);
+ searchParams.options = JSON.JsonHelper.Deserialize<SearchOptions>(args[1]);
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, INVALID_ARGUMENT_ERROR));
+ return;
+ }
+
+ if (searchParams.options == null)
+ {
+ searchParams.options = new SearchOptions();
+ searchParams.options.filter = "";
+ searchParams.options.multiple = true;
+ }
+
+ DeviceContacts deviceContacts = new DeviceContacts();
+ deviceContacts.SearchCompleted += new EventHandler<ContactsSearchEventArgs>(contacts_SearchCompleted);
+
+ // default is to search all fields
+ FilterKind filterKind = FilterKind.None;
+ // if only one field is specified, we will try the 3 available DeviceContact search filters
+ if (searchParams.fields.Count() == 1)
+ {
+ if (searchParams.fields.Contains("name"))
+ {
+ filterKind = FilterKind.DisplayName;
+ }
+ else if (searchParams.fields.Contains("emails"))
+ {
+ filterKind = FilterKind.EmailAddress;
+ }
+ else if (searchParams.fields.Contains("phoneNumbers"))
+ {
+ filterKind = FilterKind.PhoneNumber;
+ }
+ }
+
+ try
+ {
+
+ deviceContacts.SearchAsync(searchParams.options.filter, filterKind, searchParams);
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine("search contacts exception :: " + ex.Message);
+ }
+ }
+
+ private void contacts_SearchCompleted(object sender, ContactsSearchEventArgs e)
+ {
+ ContactSearchParams searchParams = (ContactSearchParams)e.State;
+
+ List<Contact> foundContacts = null;
+
+ // if we have multiple search fields
+ if (searchParams.options.filter.Length > 0 && searchParams.fields.Count() > 1)
+ {
+ foundContacts = new List<Contact>();
+ if (searchParams.fields.Contains("emails"))
+ {
+ foundContacts.AddRange(from Contact con in e.Results
+ from ContactEmailAddress a in con.EmailAddresses
+ where a.EmailAddress.Contains(searchParams.options.filter)
+ select con);
+ }
+ if (searchParams.fields.Contains("displayName"))
+ {
+ foundContacts.AddRange(from Contact con in e.Results
+ where con.DisplayName.Contains(searchParams.options.filter)
+ select con);
+ }
+ if (searchParams.fields.Contains("name"))
+ {
+ foundContacts.AddRange(from Contact con in e.Results
+ where con.CompleteName != null && con.CompleteName.ToString().Contains(searchParams.options.filter)
+ select con);
+ }
+ if (searchParams.fields.Contains("phoneNumbers"))
+ {
+ foundContacts.AddRange(from Contact con in e.Results
+ from ContactPhoneNumber a in con.PhoneNumbers
+ where a.PhoneNumber.Contains(searchParams.options.filter)
+ select con);
+ }
+ if (searchParams.fields.Contains("urls"))
+ {
+ foundContacts.AddRange(from Contact con in e.Results
+ from string a in con.Websites
+ where a.Contains(searchParams.options.filter)
+ select con);
+ }
+ }
+ else
+ {
+ foundContacts = new List<Contact>(e.Results);
+ }
+
+ //List<string> contactList = new List<string>();
+
+ string strResult = "";
+
+ IEnumerable<Contact> distinctContacts = foundContacts.Distinct();
+
+ foreach (Contact contact in distinctContacts)
+ {
+ strResult += FormatJSONContact(contact, null) + ",";
+ //contactList.Add(FormatJSONContact(contact, null));
+ if (!searchParams.options.multiple)
+ {
+ break; // just return the first item
+ }
+ }
+ PluginResult result = new PluginResult(PluginResult.Status.OK);
+ result.Message = "[" + strResult.TrimEnd(',') + "]";
+ DispatchCommandResult(result);
+
+ }
+
+ private string FormatJSONPhoneNumbers(Contact con)
+ {
+ string retVal = "";
+ string contactFieldFormat = "\"type\":\"{0}\",\"value\":\"{1}\",\"pref\":\"false\"";
+ foreach (ContactPhoneNumber number in con.PhoneNumbers)
+ {
+
+ string contactField = string.Format(contactFieldFormat,
+ number.Kind.ToString(),
+ number.PhoneNumber);
+
+ retVal += "{" + contactField + "},";
+ }
+ return retVal.TrimEnd(',');
+ }
+
+ private string FormatJSONEmails(Contact con)
+ {
+ string retVal = "";
+ string contactFieldFormat = "\"type\":\"{0}\",\"value\":\"{1}\",\"pref\":\"false\"";
+ foreach (ContactEmailAddress address in con.EmailAddresses)
+ {
+ string contactField = string.Format(contactFieldFormat,
+ address.Kind.ToString(),
+ address.EmailAddress);
+
+ retVal += "{" + contactField + "},";
+ }
+ return retVal.TrimEnd(',');
+ }
+
+ private string getFormattedJSONAddress(ContactAddress address, bool isPreferred)
+ {
+
+ string addressFormatString = "\"pref\":{0}," + // bool
+ "\"type\":\"{1}\"," +
+ "\"formatted\":\"{2}\"," +
+ "\"streetAddress\":\"{3}\"," +
+ "\"locality\":\"{4}\"," +
+ "\"region\":\"{5}\"," +
+ "\"postalCode\":\"{6}\"," +
+ "\"country\":\"{7}\"";
+
+ string formattedAddress = address.PhysicalAddress.AddressLine1 + " "
+ + address.PhysicalAddress.AddressLine2 + " "
+ + address.PhysicalAddress.City + " "
+ + address.PhysicalAddress.StateProvince + " "
+ + address.PhysicalAddress.CountryRegion + " "
+ + address.PhysicalAddress.PostalCode;
+
+ string jsonAddress = string.Format(addressFormatString,
+ isPreferred ? "\"true\"" : "\"false\"",
+ address.Kind.ToString(),
+ formattedAddress,
+ address.PhysicalAddress.AddressLine1 + " " + address.PhysicalAddress.AddressLine2,
+ address.PhysicalAddress.City,
+ address.PhysicalAddress.StateProvince,
+ address.PhysicalAddress.PostalCode,
+ address.PhysicalAddress.CountryRegion);
+
+ //Debug.WriteLine("getFormattedJSONAddress returning :: " + jsonAddress);
+
+ return "{" + jsonAddress + "}";
+ }
+
+ private string FormatJSONAddresses(Contact con)
+ {
+ string retVal = "";
+ foreach (ContactAddress address in con.Addresses)
+ {
+ retVal += this.getFormattedJSONAddress(address, false) + ",";
+ }
+
+ //Debug.WriteLine("FormatJSONAddresses returning :: " + retVal);
+ return retVal.TrimEnd(',');
+ }
+
+ private string FormatJSONWebsites(Contact con)
+ {
+ string retVal = "";
+ foreach (string website in con.Websites)
+ {
+ retVal += "\"" + website + "\",";
+ }
+ return retVal.TrimEnd(',');
+ }
+
+ /*
+ * formatted: The complete name of the contact. (DOMString)
+ familyName: The contacts family name. (DOMString)
+ givenName: The contacts given name. (DOMString)
+ middleName: The contacts middle name. (DOMString)
+ honorificPrefix: The contacts prefix (example Mr. or Dr.) (DOMString)
+ honorificSuffix: The contacts suffix (example Esq.). (DOMString)
+ */
+ private string FormatJSONName(Contact con)
+ {
+ string retVal = "";
+ string formatStr = "\"formatted\":\"{0}\"," +
+ "\"familyName\":\"{1}\"," +
+ "\"givenName\":\"{2}\"," +
+ "\"middleName\":\"{3}\"," +
+ "\"honorificPrefix\":\"{4}\"," +
+ "\"honorificSuffix\":\"{5}\"";
+
+ if (con.CompleteName != null)
+ {
+ retVal = string.Format(formatStr,
+ con.CompleteName.FirstName + " " + con.CompleteName.LastName, // TODO: does this need suffix? middlename?
+ con.CompleteName.LastName,
+ con.CompleteName.FirstName,
+ con.CompleteName.MiddleName,
+ con.CompleteName.Title,
+ con.CompleteName.Suffix);
+ }
+ else
+ {
+ retVal = string.Format(formatStr,"","","","","","");
+ }
+
+ return "{" + retVal + "}";
+ }
+
+ private string FormatJSONContact(Contact con, string[] fields)
+ {
+
+ string contactFormatStr = "\"id\":\"{0}\"," +
+ "\"displayName\":\"{1}\"," +
+ "\"nickname\":\"{2}\"," +
+ "\"phoneNumbers\":[{3}]," +
+ "\"emails\":[{4}]," +
+ "\"addresses\":[{5}]," +
+ "\"urls\":[{6}]," +
+ "\"name\":{7}," +
+ "\"note\":\"{8}\"," +
+ "\"birthday\":\"{9}\"";
+
+
+ string jsonContact = String.Format(contactFormatStr,
+ con.GetHashCode(),
+ con.DisplayName,
+ con.CompleteName != null ? con.CompleteName.Nickname : "",
+ FormatJSONPhoneNumbers(con),
+ FormatJSONEmails(con),
+ FormatJSONAddresses(con),
+ FormatJSONWebsites(con),
+ FormatJSONName(con),
+ con.Notes.FirstOrDefault(),
+ con.Birthdays.FirstOrDefault());
+
+ //Debug.WriteLine("jsonContact = " + jsonContact);
+ // JSON requires new line characters be escaped
+ return "{" + jsonContact.Replace("\n", "\\n") + "}";
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/DebugConsole.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/DebugConsole.cs b/lib/cordova-wp7/templates/standalone/Plugins/DebugConsole.cs
new file mode 100644
index 0000000..fa9863a
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/DebugConsole.cs
@@ -0,0 +1,49 @@
+/*
+ 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.Diagnostics;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+
+ public class DebugConsole : BaseCommand
+ {
+ // warn, error
+ public void log(string msg)
+ {
+ Debug.WriteLine("Log:" + msg);
+ }
+
+ public void error(string msg)
+ {
+ Debug.WriteLine("Error:" + msg);
+ }
+
+ public void warn(string msg)
+ {
+ Debug.WriteLine("Warn:" + msg);
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/Device.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/Device.cs b/lib/cordova-wp7/templates/standalone/Plugins/Device.cs
new file mode 100644
index 0000000..07100ae
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/Device.cs
@@ -0,0 +1,135 @@
+/*
+ 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.Info;
+using System.IO.IsolatedStorage;
+using System.Windows.Resources;
+using System.IO;
+using System.Diagnostics;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ public class Device : BaseCommand
+ {
+ public void getDeviceInfo(string notused)
+ {
+
+ string res = String.Format("\"name\":\"{0}\",\"cordova\":\"{1}\",\"platform\":\"{2}\",\"uuid\":\"{3}\",\"version\":\"{4}\",\"model\":\"{5}\"",
+ this.name,
+ this.cordova,
+ this.platform,
+ this.uuid,
+ this.version,
+ this.model);
+
+
+
+ res = "{" + res + "}";
+ //Debug.WriteLine("Result::" + res);
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, res));
+ }
+
+ public string model
+ {
+ get
+ {
+ return DeviceStatus.DeviceName;
+ //return String.Format("{0},{1},{2}", DeviceStatus.DeviceManufacturer, DeviceStatus.DeviceHardwareVersion, DeviceStatus.DeviceFirmwareVersion);
+ }
+ }
+
+ public string name
+ {
+ get
+ {
+ return DeviceStatus.DeviceName;
+
+ }
+ }
+
+ public string cordova
+ {
+ get
+ {
+ // TODO: should be able to dynamically read the Cordova version from somewhere...
+ return "2.7.0";
+ }
+ }
+
+ public string platform
+ {
+ get
+ {
+ return Environment.OSVersion.Platform.ToString();
+ }
+ }
+
+ public string uuid
+ {
+ get
+ {
+ string returnVal = "";
+ object id;
+ UserExtendedProperties.TryGetValue("ANID", out id);
+
+ if (id != null)
+ {
+ returnVal = id.ToString().Substring(2, 32);
+ }
+ else
+ {
+ returnVal = "???unknown???";
+
+ using (IsolatedStorageFile appStorage = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ try
+ {
+ IsolatedStorageFileStream fileStream = new IsolatedStorageFileStream("DeviceID.txt", FileMode.Open, FileAccess.Read, appStorage);
+
+ using (StreamReader reader = new StreamReader(fileStream))
+ {
+ returnVal = reader.ReadLine();
+ }
+ }
+ catch (Exception /*ex*/)
+ {
+
+ }
+ }
+ }
+
+ return returnVal;
+ }
+ }
+
+ public string version
+ {
+ get
+ {
+ return Environment.OSVersion.Version.ToString();
+ }
+ }
+
+ }
+}
[26/37] Add WP7 and WP8 platform files.
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/Globalization.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/Globalization.cs b/lib/cordova-wp7/templates/standalone/Plugins/Globalization.cs
new file mode 100644
index 0000000..1528807
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/Globalization.cs
@@ -0,0 +1,1178 @@
+/*
+ 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.Globalization;
+using System.Runtime.Serialization;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ /// <summary>
+ /// Provides information about system locale, culture settings, number formats, ect.
+ /// </summary>
+ public class Globalization : BaseCommand
+ {
+
+ #region Globalization errors
+
+ /// <summary>
+ /// Globalization error codes.
+ /// </summary>
+ public enum ErrorCode : int
+ {
+ UnknownError = 0,
+ FormattingError = 1,
+ ParsingError = 2,
+ PatternError = 3
+ }
+
+ /// <summary>
+ /// Represents globalization error object.
+ /// </summary>
+ [DataContract]
+ public class GlobalizationError
+ {
+ #region Error messages
+ /// <summary>
+ /// Error messages
+ /// </summary>
+ public const string UnknownError = "UNKNOWN_ERROR";
+ public const string FormattingError = "FORMATTIN_ERROR";
+ public const string ParsingError = "PARSING_ERROR";
+ public const string PatternError = "PATTERN_ERROR";
+
+ #endregion
+
+ /// <summary>
+ /// Error code
+ /// </summary>
+ [DataMember(Name = "code", IsRequired = false)]
+ public ErrorCode Code { get; set; }
+
+ /// <summary>
+ /// Error message
+ /// </summary>
+ [DataMember(Name = "message", IsRequired = false)]
+ public string Message { get; set; }
+
+ /// <summary>
+ /// Default constructor
+ /// </summary>
+ public GlobalizationError()
+ {
+ this.Code = ErrorCode.UnknownError;
+ this.Message = UnknownError;
+ }
+
+ /// <summary>
+ /// Constructor setting error code
+ /// </summary>
+ public GlobalizationError(ErrorCode error)
+ {
+ this.Code = error;
+
+ switch (error)
+ {
+ case ErrorCode.ParsingError:
+ {
+ this.Message = ParsingError;
+ break;
+ }
+ case ErrorCode.FormattingError:
+ {
+ this.Message = FormattingError;
+ break;
+ }
+ case ErrorCode.PatternError:
+ {
+ this.Message = PatternError;
+ break;
+ }
+ default:
+ {
+ this.Message = UnknownError;
+ break;
+ }
+ }
+ }
+ }
+
+ #endregion
+
+ #region Globalization options
+
+ /// <summary>
+ /// Represents globalization options.
+ /// </summary>
+ [DataContract]
+ public class GlobalizationOptions
+ {
+ #region available option values
+ /// <summary>
+ /// Number pattern types.
+ /// </summary>
+ public const string Percent = "percent";
+ public const string Currency = "currency";
+ public const string Decimal = "decimal";
+
+ /// <summary>
+ /// Format length types
+ /// </summary>
+ public const string Short = "short";
+ public const string Medium = "medium";
+ public const string Long = "long";
+ public const string Full = "full";
+
+ /// <summary>
+ /// Selector types
+ /// </summary>
+ public const string TimeSelector = "time";
+ public const string DateSelector = "date";
+ public const string DateAndTimeSelector = "date and time";
+
+ /// <summary>
+ /// Date name types
+ /// </summary>
+ public const string Narrow = "narrow";
+ public const string Wide = "wide";
+
+ /// <summary>
+ /// Date name items
+ /// </summary>
+ public const string Months = "months";
+ public const string Days = "days";
+
+ #endregion
+
+ /// <summary>
+ /// Additional options
+ /// </summary>
+ [DataMember(Name = "options", IsRequired = false)]
+ public Options AdditionalOptions { get; set; }
+
+ /// <summary>
+ /// Date to convert
+ /// </summary>
+ [DataMember(Name = "date", IsRequired = false)]
+ public long Date { get; set; }
+
+ /// <summary>
+ /// Date as stirng
+ /// </summary>
+ [DataMember(Name = "dateString", IsRequired = false)]
+ public string DateString { get; set; }
+
+ /// <summary>
+ /// Currency code
+ /// </summary>
+ [DataMember(Name = "currencyCode", IsRequired = false)]
+ public string CurrencyCode { get; set; }
+
+ /// <summary>
+ /// Number as string
+ /// </summary>
+ [DataMember(Name = "numberString", IsRequired = false)]
+ public string NumberString { get; set; }
+
+ /// <summary>
+ /// Number to convert
+ /// </summary>
+ [DataMember(Name = "number", IsRequired = false)]
+ public double Number { get; set; }
+ }
+
+ /// <summary>
+ /// Represents additional options
+ /// </summary>
+ [DataContract]
+ public class Options
+ {
+ /// <summary>
+ /// Pattern type
+ /// </summary>
+ [DataMember(Name = "type", IsRequired = false)]
+ public string Type { get; set; }
+
+ /// <summary>
+ /// Format length
+ /// </summary>
+ [DataMember(Name = "formatLength", IsRequired = false)]
+ public string FormatLength { get; set; }
+
+ /// <summary>
+ /// Selector
+ /// </summary>
+ [DataMember(Name = "selector", IsRequired = false)]
+ public string Selector { get; set; }
+
+ /// <summary>
+ /// Date name item
+ /// </summary>
+ [DataMember(Name = "item", IsRequired = false)]
+ public string Item { get; set; }
+ }
+
+ #endregion
+
+ #region returned objects
+
+ #region Number pattern object
+
+ /// <summary>
+ /// Represents number pattern
+ /// </summary>
+ [DataContract]
+ public class NumberPattern
+ {
+ /// <summary>
+ /// Pattern
+ /// </summary>
+ [DataMember(Name = "pattern", IsRequired = false)]
+ public string Pattern { get; set; }
+
+ /// <summary>
+ /// Symbol
+ /// </summary>
+ [DataMember(Name = "symbol", IsRequired = false)]
+ public string Symbol { get; set; }
+
+ /// <summary>
+ /// Fraction
+ /// </summary>
+ [DataMember(Name = "fraction", IsRequired = false)]
+ public int Fraction { get; set; }
+
+ /// <summary>
+ /// Positive
+ /// </summary>
+ [DataMember(Name = "positive", IsRequired = false)]
+ public string Positive { get; set; }
+
+ /// <summary>
+ /// Negative
+ /// </summary>
+ [DataMember(Name = "negative", IsRequired = false)]
+ public string Negative { get; set; }
+
+ /// <summary>
+ /// Rounding
+ /// </summary>
+ [DataMember(Name = "rounding", IsRequired = false)]
+ public int Rounding { get; set; }
+
+ /// <summary>
+ /// Decimal
+ /// </summary>
+ [DataMember(Name = "decimal", IsRequired = false)]
+ public string Decimal { get; set; }
+
+ /// <summary>
+ /// Grouping
+ /// </summary>
+ [DataMember(Name = "grouping", IsRequired = false)]
+ public string Grouping { get; set; }
+
+ /// <summary>
+ /// Constructor of the class
+ /// </summary>
+ /// <param name="pattern"></param>
+ /// <param name="symbol"></param>
+ /// <param name="fraction"></param>
+ /// <param name="positive"></param>
+ /// <param name="negative"></param>
+ /// <param name="rounding"></param>
+ /// <param name="dec"></param>
+ /// <param name="grouping"></param>
+ public NumberPattern(string pattern, string symbol, int fraction, string positive, string negative, int rounding, string dec, string grouping)
+ {
+ this.Pattern = pattern;
+ this.Symbol = symbol;
+ this.Fraction = fraction;
+ this.Positive = positive;
+ this.Negative = negative;
+ this.Rounding = rounding;
+ this.Decimal = dec;
+ this.Grouping = grouping;
+ }
+ }
+ #endregion
+
+ #region Date format object
+
+ /// <summary>
+ /// Represents date format
+ /// </summary>
+ [DataContract]
+ public class DateFormat
+ {
+ /// <summary>
+ /// Year
+ /// </summary>
+ [DataMember(Name = "year", IsRequired = false)]
+ public int Year { get; set; }
+
+ /// <summary>
+ /// Month
+ /// </summary>
+ [DataMember(Name = "month", IsRequired = false)]
+ public int Month { get; set; }
+
+ /// <summary>
+ /// Day
+ /// </summary>
+ [DataMember(Name = "day", IsRequired = false)]
+ public int Day { get; set; }
+
+ /// <summary>
+ /// Hour
+ /// </summary>
+ [DataMember(Name = "hour", IsRequired = false)]
+ public int Hour { get; set; }
+
+ /// <summary>
+ /// Minute
+ /// </summary>
+ [DataMember(Name = "minute", IsRequired = false)]
+ public int Minute { get; set; }
+
+ /// <summary>
+ /// Second
+ /// </summary>
+ [DataMember(Name = "second", IsRequired = false)]
+ public int Second { get; set; }
+
+ /// <summary>
+ /// Millisecond
+ /// </summary>
+ [DataMember(Name = "millisecond", IsRequired = false)]
+ public int Millisecond { get; set; }
+
+ public DateFormat(int year, int month, int day, int hour, int minute, int second, int millisecond)
+ {
+ this.Year = year;
+ this.Month = month;
+ this.Day = day;
+ this.Hour = hour;
+ this.Minute = minute;
+ this.Millisecond = millisecond;
+ }
+
+ }
+ #endregion
+
+ #region Date pattern object
+
+ /// <summary>
+ /// Represents date pattern object
+ /// </summary>
+ [DataContract]
+ public class DatePattern
+ {
+
+ /// <summary>
+ /// Date pattern
+ /// </summary>
+ [DataMember(Name = "pattern", IsRequired = false)]
+ public string Pattern { get; set; }
+
+ /// <summary>
+ /// TimeZone
+ /// </summary>
+ [DataMember(Name = "timezone", IsRequired = false)]
+ public string TimeZone { get; set; }
+
+ /// <summary>
+ /// UTC offset
+ /// </summary>
+ [DataMember(Name = "utc_offset", IsRequired = false)]
+ public double UtcOffset { get; set; }
+
+ /// <summary>
+ /// Dst offset
+ /// </summary>
+ [DataMember(Name = "dst_offset", IsRequired = false)]
+ public double DstOffset { get; set; }
+
+ /// <summary>
+ /// Constructor of the class
+ /// </summary>
+ /// <param name="pattern"></param>
+ /// <param name="timezone"></param>
+ /// <param name="utcOffset"></param>
+ /// <param name="dstOffset"></param>
+ public DatePattern(string pattern, string timezone, double utcOffset, double dstOffset)
+ {
+ this.Pattern = pattern;
+ this.TimeZone = timezone;
+ this.UtcOffset = utcOffset;
+ this.DstOffset = dstOffset;
+ }
+
+ }
+
+ #endregion
+
+ #endregion
+
+ #region Locale info
+
+ /// <summary>
+ /// Gets the string identifier for the client's current locale setting.
+ /// </summary>
+ /// <param name="options"></param>
+ public void getLocaleName(string options)
+ {
+ try
+ {
+ var locale = RegionInfo.CurrentRegion.TwoLetterISORegionName;
+ PluginResult result = new PluginResult(PluginResult.Status.OK, this.WrapIntoJSON(locale));
+ this.DispatchCommandResult(result);
+ }
+ catch (Exception e)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError()));
+ }
+ }
+
+ /// <summary>
+ /// Gets the string identifier for the client's current language.
+ /// </summary>
+ /// <param name="options"></param>
+ public void getPreferredLanguage(string options)
+ {
+ try
+ {
+ var language = CultureInfo.CurrentCulture.TwoLetterISOLanguageName;
+ PluginResult result = new PluginResult(PluginResult.Status.OK, this.WrapIntoJSON(language));
+ this.DispatchCommandResult(result);
+ }
+ catch (Exception e)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError()));
+ }
+ }
+
+ #endregion
+
+ #region Date and time info
+
+ /// <summary>
+ /// Gets whether daylight savings time is in effect for a given date using the client's
+ /// time zone and calendar.
+ /// </summary>
+ /// <param name="opitons">Date to daylight savings check.</param>
+ public void isDayLightSavingsTime(string options)
+ {
+ GlobalizationOptions globalOptions;
+
+ try
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+ globalOptions = JSON.JsonHelper.Deserialize<GlobalizationOptions>(args[0]);
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ try
+ {
+ DateTime start = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+ DateTime date = start.AddMilliseconds(globalOptions.Date).ToLocalTime();
+ TimeZoneInfo localZone = TimeZoneInfo.Local;
+ bool isDaylightSavingTime = localZone.IsDaylightSavingTime(date);
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.OK, this.WrapIntoJSON(isDaylightSavingTime, "dst")));
+ }
+ catch (Exception e)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError()));
+ }
+ }
+
+ /// <summary>
+ /// Gets the first day of the week according to the client's user preferences and calendar.
+ /// The days of the week are numbered starting from 1 where 1 is considered to be Sunday.
+ /// </summary>
+ /// <param name="options"></param>
+ public void getFirstDayOfWeek(string options)
+ {
+ try
+ {
+ // DateTimeFormat returns days of the week numbered from zero, so we have to increase returned value by one.
+ var firstDayOfWeek = (int)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek + 1;
+ PluginResult result = new PluginResult(PluginResult.Status.OK, this.WrapIntoJSON(firstDayOfWeek));
+ this.DispatchCommandResult(result);
+ }
+ catch (Exception e)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError()));
+ }
+ }
+
+ #endregion
+
+ #region Formatting
+
+ /// <summary>
+ /// Gets a date formatted as a string according to the client's user preferences and calendar using the time zone of the client.
+ /// </summary>
+ /// <param name="options"></param>
+ public void dateToString(string options)
+ {
+ GlobalizationOptions globalOptions;
+
+ try
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+ globalOptions = JSON.JsonHelper.Deserialize<GlobalizationOptions>(args[0]);
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ try
+ {
+ DateTime start = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+ DateTime date = start.AddMilliseconds(globalOptions.Date).ToLocalTime();
+
+ string format = "{0:M/dd/yy H:m:s}"; //short datetime by default
+ int formatLength = 0; //default format
+ int selector = 0; //default selector
+
+ if (globalOptions.AdditionalOptions != null)
+ {
+ if (globalOptions.AdditionalOptions.FormatLength != null)
+ {
+ string t = globalOptions.AdditionalOptions.FormatLength;
+
+ if (t.Equals(GlobalizationOptions.Full))
+ {
+ formatLength++;
+ }
+ }
+
+ if (globalOptions.AdditionalOptions.Selector != null)
+ {
+ string t = globalOptions.AdditionalOptions.Selector;
+
+ if (t.Equals(GlobalizationOptions.DateSelector))
+ {
+ selector += 10;
+ }
+ else if (t.Equals(GlobalizationOptions.TimeSelector))
+ {
+ selector += 20;
+ }
+ }
+
+ //determine return value
+ int method = formatLength + selector;
+
+ switch (method)
+ {
+ case 1: // full datetime
+ {
+ format = "{0:MMMM/dddd/yyyy HH:mm:ss tt}";
+ break;
+ }
+ case 10: // short date
+ {
+ format = "{0:d}";
+ break;
+ }
+ case 11: // full date
+ {
+ format = "{0:D}";
+ break;
+ }
+ case 20: // short time
+ {
+ format = "{0:t}";
+ break;
+ }
+ case 21: // full time
+ {
+ format = "{0:T}";
+ break;
+ }
+ default: // short datetime
+ {
+ format = "{0:M/dd/yy H:m:s}";
+ break;
+ }
+ }
+ }
+
+ string formattedValue = string.Format(CultureInfo.CurrentCulture, format, date);
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.OK, this.WrapIntoJSON(formattedValue)));
+ }
+ catch (Exception e)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError(ErrorCode.FormattingError)));
+ }
+ }
+
+ /// <summary>
+ /// Parses a date formatted as a string according to the client's user preferences and calendar using the time zone of the client and returns the corresponding date object
+ /// </summary>
+ /// <param name="options"></param>
+ public void stringToDate(string options)
+ {
+ GlobalizationOptions globalOptions;
+
+ try
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+ globalOptions = JSON.JsonHelper.Deserialize<GlobalizationOptions>(args[0]);
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ try
+ {
+ if (string.IsNullOrEmpty(globalOptions.DateString))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ string format = "M/dd/yy H:m:s"; // short datetime by default
+ int formatLength = 0; //default format
+ int selector = 0; //default selector
+
+ if (globalOptions.AdditionalOptions != null)
+ {
+ if (globalOptions.AdditionalOptions.FormatLength != null)
+ {
+ string t = globalOptions.AdditionalOptions.FormatLength;
+
+ if (t.Equals(GlobalizationOptions.Full))
+ {
+ formatLength++;
+ }
+ }
+
+ if (globalOptions.AdditionalOptions.Selector != null)
+ {
+ string t = globalOptions.AdditionalOptions.Selector;
+
+ if (t.Equals(GlobalizationOptions.DateSelector))
+ {
+ selector += 10;
+ }
+ else if (t.Equals(GlobalizationOptions.TimeSelector))
+ {
+ selector += 20;
+ }
+ }
+
+ //determine return value
+ int method = formatLength + selector;
+
+ switch (method)
+ {
+ case 1: // full datetime
+ {
+ format = "MMMM/dddd/yyyy HH:mm:ss tt";
+ break;
+ }
+ case 10: // short date
+ {
+ format = "d";
+ break;
+ }
+ case 11: // full date
+ {
+ format = "D";
+ break;
+ }
+ case 20: // short time
+ {
+ format = "t";
+ break;
+ }
+ case 21: // full time
+ {
+ format = "T";
+ break;
+ }
+ default: // short datetime
+ {
+ format = "M/dd/yy H:m:s";
+ break;
+ }
+ }
+ }
+
+ DateTime date = DateTime.ParseExact(globalOptions.DateString, format, CultureInfo.CurrentCulture);
+ DateFormat dateFormat = new DateFormat(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, date.Millisecond);
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.OK, dateFormat));
+
+ }
+ catch (Exception e)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError(ErrorCode.ParsingError)));
+ }
+ }
+
+ /// <summary>
+ /// Gets a pattern string for formatting and parsing dates according to the client's user preferences.
+ /// </summary>
+ /// <param name="options"></param>
+ public void getDatePattern(string options)
+ {
+ GlobalizationOptions globalOptions;
+
+ try
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+ globalOptions = JSON.JsonHelper.Deserialize<GlobalizationOptions>(args[0]);
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ try
+ {
+ DateTimeFormatInfo dateFormatInfo = DateTimeFormatInfo.CurrentInfo;
+ string pattern = dateFormatInfo.FullDateTimePattern; // full datetime by default
+ int formatLength = 0; //default format
+ int selector = 0; //default selector
+
+ if (globalOptions.AdditionalOptions != null)
+ {
+ if (globalOptions.AdditionalOptions.FormatLength != null)
+ {
+ string t = globalOptions.AdditionalOptions.FormatLength;
+
+ if (t.Equals(GlobalizationOptions.Full))
+ {
+ formatLength++;
+ }
+ }
+
+ if (globalOptions.AdditionalOptions.Selector != null)
+ {
+ string t = globalOptions.AdditionalOptions.Selector;
+
+ if (t.Equals(GlobalizationOptions.DateSelector))
+ {
+ selector += 10;
+ }
+ else if (t.Equals(GlobalizationOptions.TimeSelector))
+ {
+ selector += 20;
+ }
+ }
+
+ //determine return value
+ int method = formatLength + selector;
+
+ switch (method)
+ {
+ case 1: // full datetime
+ {
+ pattern = dateFormatInfo.FullDateTimePattern;
+ break;
+ }
+ case 10: // short date
+ {
+ pattern = dateFormatInfo.ShortDatePattern;
+ break;
+ }
+ case 11: // full date
+ {
+ pattern = dateFormatInfo.LongDatePattern;
+ break;
+ }
+ case 20: // short time
+ {
+ pattern = dateFormatInfo.ShortTimePattern;
+ break;
+ }
+ case 21: // full time
+ {
+ pattern = dateFormatInfo.LongTimePattern;
+ break;
+ }
+ default: // short datetime
+ {
+ // Seems like C# doesn't support short datetime pattern so we use full format
+ // http://msdn.microsoft.com/en-us/library/1at0z4ew%28v=vs.71%29.aspx
+ pattern = dateFormatInfo.FullDateTimePattern;
+ break;
+ }
+ }
+ }
+
+ TimeZoneInfo localZone = TimeZoneInfo.Local;
+ DatePattern datePattern = new DatePattern(pattern, localZone.DisplayName, localZone.BaseUtcOffset.TotalSeconds, 0);
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.OK, datePattern));
+ }
+ catch (Exception e)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError(ErrorCode.PatternError)));
+ }
+ }
+
+ /// <summary>
+ /// Gets an array of either the names of the months or days of the week according to the client's user preferences and calendar.
+ /// </summary>
+ /// <param name="options"></param>
+ public void getDateNames(string options)
+ {
+ GlobalizationOptions globalOptions;
+
+ try
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+ globalOptions = JSON.JsonHelper.Deserialize<GlobalizationOptions>(args[0]);
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ try
+ {
+ int type = 0; //default wide
+ int item = 0; //default months
+
+ if (globalOptions.AdditionalOptions != null)
+ {
+ if (globalOptions.AdditionalOptions.Type != null)
+ {
+ string t = globalOptions.AdditionalOptions.Type;
+
+ if (t.Equals(GlobalizationOptions.Narrow))
+ {
+ type++;
+ }
+ }
+
+ if (globalOptions.AdditionalOptions.Item != null)
+ {
+ string t = globalOptions.AdditionalOptions.Item;
+
+ if (t.Equals(GlobalizationOptions.Days))
+ {
+ item += 10;
+ }
+ }
+ }
+
+ //determine return value
+ int method = item + type;
+ string[] namesArray;
+ CultureInfo currentCulture = CultureInfo.CurrentCulture;
+
+ if (method == 1) //months and narrow
+ {
+ namesArray = currentCulture.DateTimeFormat.AbbreviatedMonthNames;
+ }
+ else if (method == 10) //days and wide
+ {
+ namesArray = currentCulture.DateTimeFormat.DayNames;
+ }
+ else if (method == 11) //days and narrow
+ {
+ namesArray = currentCulture.DateTimeFormat.AbbreviatedDayNames;
+ }
+ else //default: months and wide
+ {
+ namesArray = currentCulture.DateTimeFormat.MonthNames;
+ }
+
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.OK, this.WrapIntoJSON(namesArray)));
+ }
+ catch (Exception e)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError()));
+ }
+ }
+
+ /// <summary>
+ /// Gets a number formatted as a string according to the client's user preferences.
+ /// </summary>
+ /// <param name="options"></param>
+ public void numberToString(string options)
+ {
+ GlobalizationOptions globalOptions;
+
+ try
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+ globalOptions = JSON.JsonHelper.Deserialize<GlobalizationOptions>(args[0]);
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ try
+ {
+ string format = string.Empty;
+ string numberFormatType = (globalOptions.AdditionalOptions == null || string.IsNullOrEmpty(globalOptions.AdditionalOptions.Type)) ?
+ GlobalizationOptions.Decimal : globalOptions.AdditionalOptions.Type;
+
+ switch (numberFormatType)
+ {
+ case GlobalizationOptions.Percent:
+ {
+ format = "{0:p}";
+ break;
+ }
+
+ case GlobalizationOptions.Currency:
+ {
+ format = "{0:c}";
+ break;
+ }
+
+ default:
+ {
+ format = "{0:f}";
+ break;
+ }
+ }
+
+ string formattedValue = string.Format(CultureInfo.CurrentCulture, format, globalOptions.Number);
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.OK, this.WrapIntoJSON(formattedValue)));
+
+ }
+ catch (Exception e)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError(ErrorCode.FormattingError)));
+ }
+ }
+
+ /// <summary>
+ /// Gets a number formatted as a string according to the client's user preferences and returns the corresponding number.
+ /// </summary>
+ /// <param name="options"></param>
+ public void stringToNumber(string options)
+ {
+ GlobalizationOptions globalOptions;
+
+ try
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+ globalOptions = JSON.JsonHelper.Deserialize<GlobalizationOptions>(args[0]);
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ try
+ {
+ if (string.IsNullOrEmpty(globalOptions.NumberString))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ string numberString = globalOptions.NumberString;
+ string numberFormatType = (globalOptions.AdditionalOptions == null || string.IsNullOrEmpty(globalOptions.AdditionalOptions.Type)) ?
+ GlobalizationOptions.Decimal : globalOptions.AdditionalOptions.Type;
+
+ NumberStyles numberStyle;
+
+ switch (numberFormatType)
+ {
+ case GlobalizationOptions.Percent:
+ {
+ numberStyle = NumberStyles.Any;
+ numberString = numberString.Replace(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.PercentSymbol, "");
+ break;
+ }
+
+ case GlobalizationOptions.Currency:
+ {
+ numberStyle = NumberStyles.Currency;
+ break;
+ }
+
+ default:
+ {
+ numberStyle = NumberStyles.Number;
+ break;
+ }
+ }
+
+ double value = double.Parse(numberString, numberStyle, CultureInfo.CurrentCulture);
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.OK, this.WrapIntoJSON(value)));
+
+ }
+ catch (Exception e)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError(ErrorCode.ParsingError)));
+ }
+ }
+
+
+ /// <summary>
+ /// Gets a pattern string for formatting and parsing numbers according to the client's user preferences.
+ /// </summary>
+ /// <param name="options"></param>
+ public void getNumberPattern(string options)
+ {
+ GlobalizationOptions globalOptions;
+
+ try
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+ globalOptions = JSON.JsonHelper.Deserialize<GlobalizationOptions>(args[0]);
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ try
+ {
+ CultureInfo cultureInfo = CultureInfo.CurrentCulture;
+ NumberFormatInfo formatInfo = cultureInfo.NumberFormat;
+ string numberFormatType = (globalOptions.AdditionalOptions == null || string.IsNullOrEmpty(globalOptions.AdditionalOptions.Type)) ?
+ GlobalizationOptions.Decimal : globalOptions.AdditionalOptions.Type;
+ NumberPattern pattern = null;
+ string symbol;
+
+ // TODO find out how to get format pattern and the number of fraction digits
+ switch (numberFormatType)
+ {
+ case GlobalizationOptions.Percent:
+ {
+ symbol = formatInfo.PercentSymbol;
+ pattern = new NumberPattern("", symbol, 0, formatInfo.PercentPositivePattern.ToString(), formatInfo.PercentNegativePattern.ToString(), 0, formatInfo.PercentDecimalSeparator, formatInfo.PercentGroupSeparator);
+ break;
+ }
+ case GlobalizationOptions.Currency:
+ {
+ symbol = formatInfo.CurrencySymbol;
+ pattern = new NumberPattern("", symbol, 0, formatInfo.CurrencyPositivePattern.ToString(), formatInfo.CurrencyNegativePattern.ToString(), 0, formatInfo.CurrencyDecimalSeparator, formatInfo.CurrencyGroupSeparator);
+ break;
+ }
+ default:
+ {
+ symbol = formatInfo.NumberDecimalSeparator;
+ pattern = new NumberPattern("", symbol, 0, "", formatInfo.NumberNegativePattern.ToString(), 0, formatInfo.NumberDecimalSeparator, formatInfo.NumberGroupSeparator);
+ break;
+ }
+ }
+
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.OK, pattern));
+ }
+ catch (Exception e)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError(ErrorCode.PatternError)));
+ }
+ }
+
+ /// <summary>
+ /// Gets a pattern string for formatting and parsing currency values according to the client's user preferences and ISO 4217 currency code.
+ /// </summary>
+ /// <param name="options"></param>
+ public void getCurrencyPattern(string options)
+ {
+ GlobalizationOptions globalOptions;
+
+ try
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+ globalOptions = JSON.JsonHelper.Deserialize<GlobalizationOptions>(args[0]);
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ try
+ {
+ if (string.IsNullOrEmpty(globalOptions.CurrencyCode))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ string currencyCode = globalOptions.CurrencyCode;
+
+ // temporary not supported via lack of api required
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.INVALID_ACTION, "Not supported"));
+ return;
+
+ // TODO find the way to get currency info from currency code
+ // http://stackoverflow.com/questions/12373800/3-digit-currency-code-to-currency-symbol
+ // http://stackoverflow.com/questions/6924067/how-to-get-specific-culture-currency-pattern
+ // CultureInfo cultureInfo = new CultureInfo(currencyCode);
+ // NumberFormatInfo numberFormat = cultureInfo.NumberFormat;
+ }
+ catch (Exception e)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError(ErrorCode.FormattingError)));
+ }
+ }
+
+ #endregion
+
+
+ #region private methods
+
+ /// <summary>
+ /// Wraps data into JSON format
+ /// </summary>
+ /// <param name="data">data</param>
+ /// <returns>data formatted as JSON object</returns>
+ private string WrapIntoJSON<T>(T data, string keyName = "value")
+ {
+ string param = "{0}";
+ string stringifiedData = data.ToString();
+
+ if (data.GetType() == typeof(string))
+ {
+ param = "\"" + param + "\"";
+ }
+
+ if (data.GetType() == typeof(bool))
+ {
+ stringifiedData = stringifiedData.ToLower();
+ }
+
+ if (data.GetType() == typeof(string[]))
+ {
+ stringifiedData = JSON.JsonHelper.Serialize(data);
+ }
+
+ var formattedData = string.Format("\"" + keyName + "\":" + param, stringifiedData);
+ formattedData = "{" + formattedData + "}";
+
+ return formattedData;
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/ImageExifHelper.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/ImageExifHelper.cs b/lib/cordova-wp7/templates/standalone/Plugins/ImageExifHelper.cs
new file mode 100644
index 0000000..62b6462
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/ImageExifHelper.cs
@@ -0,0 +1,209 @@
+/*
+ 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.IO;
+using System.Windows.Media.Imaging;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ public class ImageExifOrientation
+ {
+ public const int Portrait = 1;
+ public const int PortraitUpsideDown = 3;
+ public const int LandscapeLeft = 6;
+ public const int LandscapeRight = 8;
+ }
+
+ public class ImageExifHelper
+ {
+
+ public static Stream RotateStream(Stream stream, int angle)
+ {
+ stream.Position = 0;
+ if (angle % 90 != 0 || angle < 0)
+ {
+ throw new ArgumentException();
+ }
+ if (angle % 360 == 0)
+ {
+ return stream;
+ }
+
+ angle = angle % 360;
+
+ BitmapImage bitmap = new BitmapImage();
+ bitmap.SetSource(stream);
+ WriteableBitmap wbSource = new WriteableBitmap(bitmap);
+
+ WriteableBitmap wbTarget = null;
+
+ int srcPixelWidth = wbSource.PixelWidth;
+ int srcPixelHeight = wbSource.PixelHeight;
+
+ if (angle % 180 == 0)
+ {
+ wbTarget = new WriteableBitmap(srcPixelWidth, srcPixelHeight);
+ }
+ else
+ {
+ wbTarget = new WriteableBitmap(srcPixelHeight, srcPixelWidth);
+ }
+
+ int destPixelWidth = wbTarget.PixelWidth;
+ int[] srcPxls = wbSource.Pixels;
+ int[] destPxls = wbTarget.Pixels;
+
+ // this ugly if/else is to avoid a conditional check for every pixel
+ if (angle == 90)
+ {
+ for (int x = 0; x < srcPixelWidth; x++)
+ {
+ for (int y = 0; y < srcPixelHeight; y++)
+ {
+ destPxls[(srcPixelHeight - y - 1) + (x * destPixelWidth)] = srcPxls[x + y * srcPixelWidth];
+ }
+ }
+ }
+ else if (angle == 180)
+ {
+ for (int x = 0; x < srcPixelWidth; x++)
+ {
+ for (int y = 0; y < srcPixelHeight; y++)
+ {
+ destPxls[(srcPixelWidth - x - 1) + (srcPixelHeight - y - 1) * srcPixelWidth] = srcPxls[x + y * srcPixelWidth];
+ }
+ }
+ }
+ else if (angle == 270)
+ {
+ for (int x = 0; x < srcPixelWidth; x++)
+ {
+ for (int y = 0; y < srcPixelHeight; y++)
+ {
+ destPxls[y + (srcPixelWidth - x - 1) * destPixelWidth] = srcPxls[x + y * srcPixelWidth];
+ }
+ }
+ }
+
+ MemoryStream targetStream = new MemoryStream();
+ wbTarget.SaveJpeg(targetStream, destPixelWidth, wbTarget.PixelHeight, 0, 100);
+ return targetStream;
+ }
+
+ public static int getImageOrientationFromStream(Stream imgStream)
+ {
+
+ // 0xFFD8 : jpgHeader
+ // 0xFFE1 :
+ // 0x???? : length of exif data
+ // 0x????, 0x???? : Chars 'E','x','i','f'
+ // 0x0000 : 2 empty bytes
+ // <== mark beginning of tags SIZE:ID:VALUE
+ // 0x???? : 'II' or 'MM' for Intel or Motorola ( always getting II on my WP7 devices ), determines littleEndian-ness
+ // 0x002A : marker value
+ // 0x???? : offset to the Image File Data
+
+ // XXXX possible space before actual tag data ... we skip to mark + offset
+
+ // 0x???? number of exif tags present
+
+ // make sure we are at the beginning
+ imgStream.Seek(0, SeekOrigin.Begin);
+ BinaryReader reader = new BinaryReader(imgStream);
+
+ byte[] jpgHdr = reader.ReadBytes(2); // always (0xFFD8)
+
+ byte start = reader.ReadByte(); // 0xFF
+ byte index = reader.ReadByte(); // 0xE1
+
+ while (start == 0xFF && index != 0xE1) // This never seems to happen, todo: optimize
+ {
+ // Get the data length
+ ushort dLen = BitConverter.ToUInt16(reader.ReadBytes(2), 0);
+ // skip along
+ reader.ReadBytes(dLen - 2);
+ start = reader.ReadByte();
+ index = reader.ReadByte();
+ }
+
+ // It's only success if we found the 0xFFE1 marker
+ if (start != 0xFF || index != 0xE1)
+ {
+ // throw new Exception("Could not find Exif data block");
+ Debug.WriteLine("Did not find EXIF data");
+ return 0;
+ }
+
+ // read 2 byte length of EXIF data
+ ushort exifLen = BitConverter.ToUInt16(reader.ReadBytes(2), 0);
+ String exif = ""; // build the string
+ for (var n = 0; n < 4; n++)
+ {
+ exif += reader.ReadChar();
+ }
+ if (exif != "Exif")
+ {
+ // did not find exif data ...
+ Debug.WriteLine("Did not find EXIF data");
+ return 0;
+ }
+
+ // read 2 empty bytes
+ //ushort emptyBytes = BitConverter.ToUInt16(reader.ReadBytes(2), 0);
+ reader.ReadBytes(2);
+
+ long headerMark = reader.BaseStream.Position; // where are we now <==
+
+ //bool isLEndian = (reader.ReadChar() + "" + reader.ReadChar()) == "II";
+ reader.ReadBytes(2); // 'II' or 'MM', but we don't care
+
+ if (0x002A != BitConverter.ToUInt16(reader.ReadBytes(2), 0))
+ {
+ Debug.WriteLine("Error in data != 0x002A");
+ return 0;
+ }
+
+ // Get the offset to the IFD (image file directory)
+ ushort imgOffset = BitConverter.ToUInt16(reader.ReadBytes(2), 0);
+
+ imgStream.Position = headerMark + imgOffset;
+ ushort tagCount = BitConverter.ToUInt16(reader.ReadBytes(2), 0);
+ for (ushort x = 0; x < tagCount; x++)
+ {
+ // Orientation = 0x112, aka 274
+ if (0x112 == BitConverter.ToUInt16(reader.ReadBytes(2), 0))
+ {
+ ushort dType = BitConverter.ToUInt16(reader.ReadBytes(2), 0);
+ // don't care ..
+ uint comps = reader.ReadUInt32();
+ byte[] tagData = reader.ReadBytes(4);
+ int orientation = (int)tagData[0];
+ Debug.WriteLine("orientation = " + orientation.ToString());
+ return orientation;
+ // 6 means rotate clockwise 90 deg
+ // 8 means rotate counter-clockwise 90 deg
+ // 1 means all is good
+ // 3 means flip vertical
+ }
+ // skip to the next item, 12 bytes each
+ reader.BaseStream.Seek(10, SeekOrigin.Current);
+ }
+ return 0;
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/InAppBrowser.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/InAppBrowser.cs b/lib/cordova-wp7/templates/standalone/Plugins/InAppBrowser.cs
new file mode 100644
index 0000000..425f5ae
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/InAppBrowser.cs
@@ -0,0 +1,268 @@
+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;
+using System.Diagnostics;
+using System.Runtime.Serialization;
+using WPCordovaClassLib.Cordova;
+using WPCordovaClassLib.Cordova.Commands;
+using WPCordovaClassLib.Cordova.JSON;
+using Microsoft.Phone.Shell;
+using Microsoft.Phone.Tasks;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ [DataContract]
+ public class BrowserOptions
+ {
+ [DataMember]
+ public string url;
+
+ [DataMember]
+ public bool isGeolocationEnabled;
+ }
+
+ public class InAppBrowser : BaseCommand
+ {
+
+ private static WebBrowser browser;
+ private static ApplicationBarIconButton backButton;
+ private static ApplicationBarIconButton fwdButton;
+
+ public void open(string options)
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+ //BrowserOptions opts = JSON.JsonHelper.Deserialize<BrowserOptions>(options);
+ string urlLoc = args[0];
+ string target = args[1];
+ /*
+ _self - opens in the Cordova WebView if url is in the white-list, else it opens in the InAppBrowser
+ _blank - always open in the InAppBrowser
+ _system - always open in the system web browser
+ */
+ switch (target)
+ {
+ case "_blank":
+ ShowInAppBrowser(urlLoc);
+ break;
+ case "_self":
+ ShowCordovaBrowser(urlLoc);
+ break;
+ case "_system":
+ ShowSystemBrowser(urlLoc);
+ break;
+ }
+
+
+ }
+
+ private void ShowCordovaBrowser(string url)
+ {
+ Uri loc = new Uri(url, UriKind.RelativeOrAbsolute);
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
+ if (frame != null)
+ {
+ PhoneApplicationPage page = frame.Content as PhoneApplicationPage;
+ if (page != null)
+ {
+ CordovaView cView = page.FindName("CordovaView") as CordovaView;
+ if (cView != null)
+ {
+ WebBrowser br = cView.Browser;
+ br.Navigate(loc);
+ }
+ }
+
+ }
+ });
+ }
+
+ private void ShowSystemBrowser(string url)
+ {
+ WebBrowserTask webBrowserTask = new WebBrowserTask();
+ webBrowserTask.Uri = new Uri(url, UriKind.Absolute);
+ webBrowserTask.Show();
+ }
+
+
+ // Display an inderminate progress indicator
+ private void ShowInAppBrowser(string url)
+ {
+ Uri loc = new Uri(url);
+
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ if (browser != null)
+ {
+ //browser.IsGeolocationEnabled = opts.isGeolocationEnabled;
+ browser.Navigate(loc);
+ }
+ else
+ {
+ PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
+ if (frame != null)
+ {
+ PhoneApplicationPage page = frame.Content as PhoneApplicationPage;
+
+ if (page != null)
+ {
+ Grid grid = page.FindName("LayoutRoot") as Grid;
+ if (grid != null)
+ {
+ browser = new WebBrowser();
+ browser.IsScriptEnabled = true;
+ browser.LoadCompleted += new System.Windows.Navigation.LoadCompletedEventHandler(browser_LoadCompleted);
+ browser.Navigating += new EventHandler<NavigatingEventArgs>(browser_Navigating);
+ browser.NavigationFailed += new System.Windows.Navigation.NavigationFailedEventHandler(browser_NavigationFailed);
+ browser.Navigated += new EventHandler<System.Windows.Navigation.NavigationEventArgs>(browser_Navigated);
+
+ browser.Navigate(loc);
+ //browser.IsGeolocationEnabled = opts.isGeolocationEnabled;
+ grid.Children.Add(browser);
+ }
+
+ ApplicationBar bar = new ApplicationBar();
+ bar.BackgroundColor = Colors.Gray;
+ bar.IsMenuEnabled = false;
+
+ backButton = new ApplicationBarIconButton();
+ backButton.Text = "Back";
+ backButton.IconUri = new Uri("/Images/appbar.back.rest.png", UriKind.Relative);
+ backButton.Click += new EventHandler(backButton_Click);
+ //backButton.IsEnabled = false;
+ bar.Buttons.Add(backButton);
+
+
+ fwdButton = new ApplicationBarIconButton();
+ fwdButton.Text = "Forward";
+ fwdButton.IconUri = new Uri("/Images/appbar.next.rest.png", UriKind.Relative);
+ fwdButton.Click += new EventHandler(fwdButton_Click);
+ //fwdButton.IsEnabled = false;
+ bar.Buttons.Add(fwdButton);
+
+ ApplicationBarIconButton closeBtn = new ApplicationBarIconButton();
+ closeBtn.Text = "Close";
+ closeBtn.IconUri = new Uri("/Images/appbar.close.rest.png", UriKind.Relative);
+ closeBtn.Click += new EventHandler(closeBtn_Click);
+ bar.Buttons.Add(closeBtn);
+
+ page.ApplicationBar = bar;
+ }
+
+ }
+ }
+ });
+ }
+
+ void browser_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
+ {
+
+ }
+
+ void fwdButton_Click(object sender, EventArgs e)
+ {
+ if (browser != null)
+ {
+ try
+ {
+ //browser.GoForward();
+ browser.InvokeScript("execScript", "history.forward();");
+ }
+ catch (Exception)
+ {
+
+ }
+ }
+ }
+
+ void backButton_Click(object sender, EventArgs e)
+ {
+ if (browser != null)
+ {
+ try
+ {
+ //browser.GoBack();
+ browser.InvokeScript("execScript", "history.back();");
+ }
+ catch (Exception)
+ {
+
+ }
+ }
+ }
+
+ void closeBtn_Click(object sender, EventArgs e)
+ {
+ this.close();
+ }
+
+
+ public void close(string options = "")
+ {
+ if (browser != null)
+ {
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
+ if (frame != null)
+ {
+ PhoneApplicationPage page = frame.Content as PhoneApplicationPage;
+ if (page != null)
+ {
+ Grid grid = page.FindName("LayoutRoot") as Grid;
+ if (grid != null)
+ {
+ grid.Children.Remove(browser);
+ }
+ page.ApplicationBar = null;
+ }
+ }
+ browser = null;
+ string message = "{\"type\":\"exit\"}";
+ PluginResult result = new PluginResult(PluginResult.Status.OK, message);
+ result.KeepCallback = false;
+ this.DispatchCommandResult(result);
+ });
+ }
+ }
+
+ void browser_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
+ {
+ //if (browser != null)
+ //{
+ // backButton.IsEnabled = browser.CanGoBack;
+ // fwdButton.IsEnabled = browser.CanGoForward;
+ //}
+ string message = "{\"type\":\"loadstop\", \"url\":\"" + e.Uri.AbsoluteUri + "\"}";
+ PluginResult result = new PluginResult(PluginResult.Status.OK, message);
+ result.KeepCallback = true;
+ this.DispatchCommandResult(result);
+ }
+
+ void browser_NavigationFailed(object sender, System.Windows.Navigation.NavigationFailedEventArgs e)
+ {
+ string message = "{\"type\":\"error\",\"url\":\"" + e.Uri.AbsoluteUri + "\"}";
+ PluginResult result = new PluginResult(PluginResult.Status.ERROR, message);
+ result.KeepCallback = true;
+ this.DispatchCommandResult(result);
+ }
+
+ void browser_Navigating(object sender, NavigatingEventArgs e)
+ {
+ string message = "{\"type\":\"loadstart\",\"url\":\"" + e.Uri.AbsoluteUri + "\"}";
+ PluginResult result = new PluginResult(PluginResult.Status.OK, message);
+ result.KeepCallback = true;
+ this.DispatchCommandResult(result);
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/Media.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/Media.cs b/lib/cordova-wp7/templates/standalone/Plugins/Media.cs
new file mode 100644
index 0000000..90c54f1
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/Media.cs
@@ -0,0 +1,532 @@
+/*
+ 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.Runtime.Serialization;
+using System.Windows;
+using System.Diagnostics;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ /// <summary>
+ /// Provides the ability to record and play back audio files on a device.
+ /// </summary>
+ public class Media : BaseCommand
+ {
+ /// <summary>
+ /// Audio player objects
+ /// </summary>
+ private static Dictionary<string, AudioPlayer> players = new Dictionary<string, AudioPlayer>();
+
+ /// <summary>
+ /// Represents Media action options.
+ /// </summary>
+ [DataContract]
+ public class MediaOptions
+ {
+ /// <summary>
+ /// Audio id
+ /// </summary>
+ [DataMember(Name = "id", IsRequired = true)]
+ public string Id { get; set; }
+
+ /// <summary>
+ /// Path to audio file
+ /// </summary>
+ [DataMember(Name = "src")]
+ public string Src { get; set; }
+
+ /// <summary>
+ /// New track position
+ /// </summary>
+ [DataMember(Name = "milliseconds")]
+ public int Milliseconds { get; set; }
+ }
+
+ /// <summary>
+ /// Releases the audio player instance to save memory.
+ /// </summary>
+ public void release(string options)
+ {
+ try
+ {
+ MediaOptions mediaOptions;
+
+ try
+ {
+ string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options);
+ mediaOptions = new MediaOptions();
+ mediaOptions.Id = optionsString[0];
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ if (!Media.players.ContainsKey(mediaOptions.Id))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, false));
+ return;
+ }
+
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ try
+ {
+ AudioPlayer audio = Media.players[mediaOptions.Id];
+ Media.players.Remove(mediaOptions.Id);
+ audio.Dispose();
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, true));
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ });
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ }
+
+ /// <summary>
+ /// Starts recording and save the specified file
+ /// </summary>
+ public void startRecordingAudio(string options)
+ {
+ try
+ {
+ MediaOptions mediaOptions;
+
+ try
+ {
+ string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options);
+ mediaOptions = new MediaOptions();
+ mediaOptions.Id = optionsString[0];
+ mediaOptions.Src = optionsString[1];
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ if (mediaOptions != null)
+ {
+
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ try
+ {
+ if (!Media.players.ContainsKey(mediaOptions.Id))
+ {
+ AudioPlayer audio = new AudioPlayer(this, mediaOptions.Id);
+ Media.players.Add(mediaOptions.Id, audio);
+ audio.startRecording(mediaOptions.Src);
+ }
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+
+ });
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ }
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ }
+
+ /// <summary>
+ /// Stops recording and save to the file specified when recording started
+ /// </summary>
+ public void stopRecordingAudio(string options)
+ {
+ try
+ {
+ string mediaId = JSON.JsonHelper.Deserialize<string[]>(options)[0];
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ try
+ {
+ if (Media.players.ContainsKey(mediaId))
+ {
+ AudioPlayer audio = Media.players[mediaId];
+ audio.stopRecording();
+ Media.players.Remove(mediaId);
+ }
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ });
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ }
+ }
+
+ public void setVolume(string options) // id,volume
+ {
+ try
+ {
+ string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options);
+ string id = optionsString[0];
+ double volume = double.Parse(optionsString[1]);
+
+ if (Media.players.ContainsKey(id))
+ {
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ try
+ {
+ AudioPlayer player = Media.players[id];
+ player.setVolume(volume);
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ });
+ }
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, "Error parsing options into setVolume method"));
+ return;
+ }
+ }
+
+ // Some Audio Notes:
+ // In the Windows Phone Emulator, playback of video or audio content using the MediaElement control is not supported.
+ // While playing, a MediaElement stops all other media playback on the phone.
+ // Multiple MediaElement controls are NOT supported
+
+ // Called when you create a new Media('blah') object in JS.
+ public void create(string options)
+ {
+ // Debug.WriteLine("Creating Audio :: " + options);
+ try
+ {
+ MediaOptions mediaOptions;
+ try
+ {
+ string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options);
+ mediaOptions = new MediaOptions();
+ mediaOptions.Id = optionsString[0];
+ mediaOptions.Src = optionsString[1];
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, "Error parsing options into create method"));
+ return;
+ }
+
+ AudioPlayer audio = new AudioPlayer(this, mediaOptions.Id);
+ Media.players.Add(mediaOptions.Id, audio);
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ }
+
+ /// <summary>
+ /// Starts or resume playing audio file
+ /// </summary>
+ public void startPlayingAudio(string options)
+ {
+ try
+ {
+ MediaOptions mediaOptions;
+ try
+ {
+ string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options);
+ mediaOptions = new MediaOptions();
+ mediaOptions.Id = optionsString[0];
+ mediaOptions.Src = optionsString[1];
+ if (optionsString.Length > 2 && optionsString[2] != null)
+ {
+ mediaOptions.Milliseconds = int.Parse(optionsString[2]);
+ }
+
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ AudioPlayer audio;
+
+ if (!Media.players.ContainsKey(mediaOptions.Id))
+ {
+ audio = new AudioPlayer(this, mediaOptions.Id);
+ Media.players[mediaOptions.Id] = audio;
+ }
+ else
+ {
+ Debug.WriteLine("INFO: startPlayingAudio FOUND mediaPlayer for " + mediaOptions.Id);
+ audio = Media.players[mediaOptions.Id];
+ }
+
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ try
+ {
+ audio.startPlaying(mediaOptions.Src);
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ });
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ }
+
+
+ /// <summary>
+ /// Seeks to a location
+ /// </summary>
+ public void seekToAudio(string options)
+ {
+ try
+ {
+ MediaOptions mediaOptions;
+
+ try
+ {
+ string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options);
+ mediaOptions = new MediaOptions();
+ mediaOptions.Id = optionsString[0];
+ if (optionsString.Length > 1 && optionsString[1] != null)
+ {
+ mediaOptions.Milliseconds = int.Parse(optionsString[1]);
+ }
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ try
+ {
+ if (Media.players.ContainsKey(mediaOptions.Id))
+ {
+ AudioPlayer audio = Media.players[mediaOptions.Id];
+ audio.seekToPlaying(mediaOptions.Milliseconds);
+ }
+ else
+ {
+ Debug.WriteLine("ERROR: seekToAudio could not find mediaPlayer for " + mediaOptions.Id);
+ }
+
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ });
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ }
+
+ /// <summary>
+ /// Pauses playing
+ /// </summary>
+ public void pausePlayingAudio(string options)
+ {
+
+ try
+ {
+ string mediaId = JSON.JsonHelper.Deserialize<string[]>(options)[0];
+
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ try
+ {
+ if (Media.players.ContainsKey(mediaId))
+ {
+ AudioPlayer audio = Media.players[mediaId];
+ audio.pausePlaying();
+ }
+ else
+ {
+ Debug.WriteLine("ERROR: pausePlayingAudio could not find mediaPlayer for " + mediaId);
+ }
+
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ });
+
+
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ }
+
+
+ }
+
+
+ /// <summary>
+ /// Stops playing the audio file
+ /// </summary>
+ public void stopPlayingAudio(String options)
+ {
+ try
+ {
+ string mediaId = JSON.JsonHelper.Deserialize<string[]>(options)[0];
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ try
+ {
+ if (Media.players.ContainsKey(mediaId))
+ {
+ AudioPlayer audio = Media.players[mediaId];
+ audio.stopPlaying();
+ }
+ else
+ {
+ Debug.WriteLine("stopPlaying could not find mediaPlayer for " + mediaId);
+ }
+
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ });
+
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ }
+ }
+
+ /// <summary>
+ /// Gets current position of playback
+ /// </summary>
+ public void getCurrentPositionAudio(string options)
+ {
+ try
+ {
+ string mediaId = JSON.JsonHelper.Deserialize<string[]>(options)[0];
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ try
+ {
+ if (Media.players.ContainsKey(mediaId))
+ {
+ AudioPlayer audio = Media.players[mediaId];
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, audio.getCurrentPosition()));
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, -1));
+ }
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ });
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+ }
+
+
+ /// <summary>
+ /// Gets the duration of the audio file
+ /// </summary>
+
+ [Obsolete("This method will be removed shortly")]
+ public void getDurationAudio(string options)
+ {
+ try
+ {
+ MediaOptions mediaOptions;
+
+ try
+ {
+ mediaOptions = JSON.JsonHelper.Deserialize<MediaOptions>(options);
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ AudioPlayer audio;
+ if (Media.players.ContainsKey(mediaOptions.Id))
+ {
+ audio = Media.players[mediaOptions.Id];
+ }
+ else
+ {
+ Debug.WriteLine("ERROR: getDurationAudio could not find mediaPlayer for " + mediaOptions.Id);
+ audio = new AudioPlayer(this, mediaOptions.Id);
+ Media.players.Add(mediaOptions.Id, audio);
+ }
+
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, audio.getDuration(mediaOptions.Src)));
+ });
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ }
+ }
+}
[33/37] Add Windows support to Android platform-scripts.
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/framework/build.xml
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/build.xml b/lib/cordova-android/framework/build.xml
index 9e7b127..989dbb2 100644
--- a/lib/cordova-android/framework/build.xml
+++ b/lib/cordova-android/framework/build.xml
@@ -26,8 +26,7 @@
</filterchain>
</loadfile>
- <!-- check that the version of ant is at least 1.8.0, as is needed
- for the dblQuote property -->
+ <!-- check that the version of ant is at least 1.8.0 -->
<antversion property="thisantversion" atleast="1.8.0" />
<fail message="The required minimum version of ant is 1.8.0, you have ${ant.version}"
unless="thisantversion" />
@@ -80,9 +79,6 @@
-->
<property file="ant.properties" />
- <!-- We need to setup the double quote. -->
- <property name="dblQuote">"</property>
-
<!-- The project.properties file is created and updated by the 'android'
tool, as well as ADT.
@@ -136,33 +132,10 @@
-->
<import file="${sdk.dir}/tools/ant/build.xml" />
- <!-- Combine JavaScript files into one cordova-uncompressed.js file. -->
- <target name="build-javascript" depends="clean">
-
- <!-- Clean up existing files -->
- <!--<delete file="assets/www/cordova_${version}.js"/>-->
-
- <!-- Create uncompressed JS file -->
- <concat destfile="assets/www/cordova-${version}.js">
- <filelist dir="assets/js" files="cordova.android.js"/>
- </concat>
-
- <!-- update project files to reference cordova-x.x.x.min.js -->
- <replaceregexp match="cordova(.*)\.js" replace="cordova-${version}.js" byline="true">
- <fileset file="assets/www/index.html" />
- <fileset file="../bin/templates/project/assets/www/index.html" />
- </replaceregexp>
-
- <!-- This is sketchy, but it works, ${dblQuote} does not -->
- <replaceregexp match="cordovaVersion = [\u0022].*[\u0022];" replace='cordovaVersion = ${dblQuote}${version}${dblQuote};' byline="true">
- <fileset file="src/org/apache/cordova/Device.java" />
- </replaceregexp>
- </target>
-
<!-- Build Cordova jar file that includes all native code, and Cordova JS file
that includes all JavaScript code.
-->
- <target name="jar" depends="build-javascript, -compile">
+ <target name="jar" depends="-compile">
<jar jarfile="cordova-${version}.jar" basedir="bin/classes" excludes="org/apache/cordova/R.class,org/apache/cordova/R$*.class"/>
</target>
@@ -195,10 +168,10 @@
</junit>
</target>
- <target name="cordova_debug" depends="build-javascript, debug">
+ <target name="cordova_debug" depends="debug">
</target>
- <target name="cordova_release" depends="build-javascript, release">
+ <target name="cordova_release" depends="release">
</target>
</project>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/src/metadata/android_parser.js
----------------------------------------------------------------------
diff --git a/src/metadata/android_parser.js b/src/metadata/android_parser.js
index 3dfaf22..09b379f 100644
--- a/src/metadata/android_parser.js
+++ b/src/metadata/android_parser.js
@@ -136,7 +136,7 @@ module.exports.prototype = {
shell.cp('-rf', www, platformWww);
// write out android lib's cordova.js
- var jsPath = path.join(util.libDirectory, 'cordova-android', 'framework', 'assets', 'js', 'cordova.android.js');
+ var jsPath = path.join(util.libDirectory, 'cordova-android', 'framework', 'assets', 'www', 'cordova.js');
fs.writeFileSync(path.join(this.www_dir(), 'cordova.js'), fs.readFileSync(jsPath, 'utf-8'), 'utf-8');
},
[16/37] Add WP7 and WP8 platform files.
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/Media.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/Media.cs b/lib/cordova-wp8/templates/standalone/Plugins/Media.cs
new file mode 100644
index 0000000..5de4884
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/Media.cs
@@ -0,0 +1,547 @@
+/*
+ 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.Runtime.Serialization;
+using System.Windows;
+using System.Diagnostics;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ /// <summary>
+ /// Provides the ability to record and play back audio files on a device.
+ /// </summary>
+ public class Media : BaseCommand
+ {
+ /// <summary>
+ /// Audio player objects
+ /// </summary>
+ private static Dictionary<string, AudioPlayer> players = new Dictionary<string, AudioPlayer>();
+
+ /// <summary>
+ /// Represents Media action options.
+ /// </summary>
+ [DataContract]
+ public class MediaOptions
+ {
+ /// <summary>
+ /// Audio id
+ /// </summary>
+ [DataMember(Name = "id", IsRequired = true)]
+ public string Id { get; set; }
+
+ /// <summary>
+ /// Path to audio file
+ /// </summary>
+ [DataMember(Name = "src")]
+ public string Src { get; set; }
+
+ /// <summary>
+ /// New track position
+ /// </summary>
+ [DataMember(Name = "milliseconds")]
+ public int Milliseconds { get; set; }
+ }
+
+ /// <summary>
+ /// Releases the audio player instance to save memory.
+ /// </summary>
+ public void release(string options)
+ {
+ try
+ {
+ MediaOptions mediaOptions;
+
+ try
+ {
+ string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options);
+ mediaOptions = new MediaOptions();
+ mediaOptions.Id = optionsString[0];
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ if (!Media.players.ContainsKey(mediaOptions.Id))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, false));
+ return;
+ }
+
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ try
+ {
+ AudioPlayer audio = Media.players[mediaOptions.Id];
+ Media.players.Remove(mediaOptions.Id);
+ audio.Dispose();
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, true));
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ });
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ }
+
+ /// <summary>
+ /// Starts recording and save the specified file
+ /// </summary>
+ public void startRecordingAudio(string options)
+ {
+ try
+ {
+ MediaOptions mediaOptions;
+
+ try
+ {
+ string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options);
+ mediaOptions = new MediaOptions();
+ mediaOptions.Id = optionsString[0];
+ mediaOptions.Src = optionsString[1];
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ if (mediaOptions != null)
+ {
+
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ try
+ {
+ AudioPlayer audio;
+ if (!Media.players.ContainsKey(mediaOptions.Id))
+ {
+ audio = new AudioPlayer(this, mediaOptions.Id);
+ Media.players.Add(mediaOptions.Id, audio);
+ }
+ else
+ {
+ audio = Media.players[mediaOptions.Id];
+ }
+
+ if (audio != null)
+ {
+ audio.startRecording(mediaOptions.Src);
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Error accessing AudioPlayer for key " + mediaOptions.Id));
+ }
+
+
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+
+ });
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ }
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ }
+
+ /// <summary>
+ /// Stops recording and save to the file specified when recording started
+ /// </summary>
+ public void stopRecordingAudio(string options)
+ {
+ try
+ {
+ string mediaId = JSON.JsonHelper.Deserialize<string[]>(options)[0];
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ try
+ {
+ if (Media.players.ContainsKey(mediaId))
+ {
+ AudioPlayer audio = Media.players[mediaId];
+ audio.stopRecording();
+ Media.players.Remove(mediaId);
+ }
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ });
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ }
+ }
+
+ public void setVolume(string options) // id,volume
+ {
+ try
+ {
+ string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options);
+ string id = optionsString[0];
+ double volume = double.Parse(optionsString[1]);
+
+ if (Media.players.ContainsKey(id))
+ {
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ try
+ {
+ AudioPlayer player = Media.players[id];
+ player.setVolume(volume);
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ });
+ }
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, "Error parsing options into setVolume method"));
+ return;
+ }
+ }
+
+ // Some Audio Notes:
+ // In the Windows Phone Emulator, playback of video or audio content using the MediaElement control is not supported.
+ // While playing, a MediaElement stops all other media playback on the phone.
+ // Multiple MediaElement controls are NOT supported
+
+ // Called when you create a new Media('blah') object in JS.
+ public void create(string options)
+ {
+ // Debug.WriteLine("Creating Audio :: " + options);
+ try
+ {
+ MediaOptions mediaOptions;
+ try
+ {
+ string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options);
+ mediaOptions = new MediaOptions();
+ mediaOptions.Id = optionsString[0];
+ mediaOptions.Src = optionsString[1];
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, "Error parsing options into create method"));
+ return;
+ }
+
+ AudioPlayer audio = new AudioPlayer(this, mediaOptions.Id);
+ Media.players.Add(mediaOptions.Id, audio);
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ }
+
+ /// <summary>
+ /// Starts or resume playing audio file
+ /// </summary>
+ public void startPlayingAudio(string options)
+ {
+ try
+ {
+ MediaOptions mediaOptions;
+ try
+ {
+ string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options);
+ mediaOptions = new MediaOptions();
+ mediaOptions.Id = optionsString[0];
+ mediaOptions.Src = optionsString[1];
+ if (optionsString.Length > 2 && optionsString[2] != null)
+ {
+ mediaOptions.Milliseconds = int.Parse(optionsString[2]);
+ }
+
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ AudioPlayer audio;
+
+ if (!Media.players.ContainsKey(mediaOptions.Id))
+ {
+ audio = new AudioPlayer(this, mediaOptions.Id);
+ Media.players.Add(mediaOptions.Id, audio);
+ }
+ else
+ {
+ //Debug.WriteLine("INFO: startPlayingAudio FOUND mediaPlayer for " + mediaOptions.Id);
+ audio = Media.players[mediaOptions.Id];
+ }
+
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ try
+ {
+ audio.startPlaying(mediaOptions.Src);
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ });
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ }
+
+
+ /// <summary>
+ /// Seeks to a location
+ /// </summary>
+ public void seekToAudio(string options)
+ {
+ try
+ {
+ MediaOptions mediaOptions;
+
+ try
+ {
+ string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options);
+ mediaOptions = new MediaOptions();
+ mediaOptions.Id = optionsString[0];
+ if (optionsString.Length > 1 && optionsString[1] != null)
+ {
+ mediaOptions.Milliseconds = int.Parse(optionsString[1]);
+ }
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ try
+ {
+ if (Media.players.ContainsKey(mediaOptions.Id))
+ {
+ AudioPlayer audio = Media.players[mediaOptions.Id];
+ audio.seekToPlaying(mediaOptions.Milliseconds);
+ }
+ else
+ {
+ Debug.WriteLine("ERROR: seekToAudio could not find mediaPlayer for " + mediaOptions.Id);
+ }
+
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ });
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ }
+
+ /// <summary>
+ /// Pauses playing
+ /// </summary>
+ public void pausePlayingAudio(string options)
+ {
+
+ try
+ {
+ string mediaId = JSON.JsonHelper.Deserialize<string[]>(options)[0];
+
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ try
+ {
+ if (Media.players.ContainsKey(mediaId))
+ {
+ AudioPlayer audio = Media.players[mediaId];
+ audio.pausePlaying();
+ }
+ else
+ {
+ Debug.WriteLine("ERROR: pausePlayingAudio could not find mediaPlayer for " + mediaId);
+ }
+
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ });
+
+
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ }
+
+
+ }
+
+
+ /// <summary>
+ /// Stops playing the audio file
+ /// </summary>
+ public void stopPlayingAudio(String options)
+ {
+ try
+ {
+ string mediaId = JSON.JsonHelper.Deserialize<string[]>(options)[0];
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ try
+ {
+ if (Media.players.ContainsKey(mediaId))
+ {
+ AudioPlayer audio = Media.players[mediaId];
+ audio.stopPlaying();
+ }
+ else
+ {
+ Debug.WriteLine("stopPlaying could not find mediaPlayer for " + mediaId);
+ }
+
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ });
+
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ }
+ }
+
+ /// <summary>
+ /// Gets current position of playback
+ /// </summary>
+ public void getCurrentPositionAudio(string options)
+ {
+ try
+ {
+ string mediaId = JSON.JsonHelper.Deserialize<string[]>(options)[0];
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ try
+ {
+ if (Media.players.ContainsKey(mediaId))
+ {
+ AudioPlayer audio = Media.players[mediaId];
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, audio.getCurrentPosition()));
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, -1));
+ }
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ });
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+ }
+
+
+ /// <summary>
+ /// Gets the duration of the audio file
+ /// </summary>
+
+ [Obsolete("This method will be removed shortly")]
+ public void getDurationAudio(string options)
+ {
+ try
+ {
+ MediaOptions mediaOptions;
+
+ try
+ {
+ mediaOptions = JSON.JsonHelper.Deserialize<MediaOptions>(options);
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ AudioPlayer audio;
+ if (Media.players.ContainsKey(mediaOptions.Id))
+ {
+ audio = Media.players[mediaOptions.Id];
+ }
+ else
+ {
+ Debug.WriteLine("ERROR: getDurationAudio could not find mediaPlayer for " + mediaOptions.Id);
+ audio = new AudioPlayer(this, mediaOptions.Id);
+ Media.players.Add(mediaOptions.Id, audio);
+ }
+
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, audio.getDuration(mediaOptions.Src)));
+ });
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/MimeTypeMapper.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/MimeTypeMapper.cs b/lib/cordova-wp8/templates/standalone/Plugins/MimeTypeMapper.cs
new file mode 100644
index 0000000..a2794f5
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/MimeTypeMapper.cs
@@ -0,0 +1,101 @@
+/*
+ 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.Collections.Generic;
+using System.IO;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ /// <summary>
+ /// Represents file extension to mime type mapper.
+ /// </summary>
+ public static class MimeTypeMapper
+ {
+ /// <summary>
+ /// For unknown type it is recommended to use 'application/octet-stream'
+ /// http://stackoverflow.com/questions/1176022/unknown-file-type-mime
+ /// </summary>
+ private static string DefaultMimeType = "application/octet-stream";
+
+ /// <summary>
+ /// Stores mime type for all necessary extension
+ /// </summary>
+ private static readonly Dictionary<string, string> MIMETypesDictionary = new Dictionary<string, string>
+ {
+ {"avi", "video/x-msvideo"},
+ {"bmp", "image/bmp"},
+ {"gif", "image/gif"},
+ {"html","text/html"},
+ {"jpe", "image/jpeg"},
+ {"jpeg", "image/jpeg"},
+ {"jpg", "image/jpeg"},
+ {"js","text/javascript"},
+ {"mov", "video/quicktime"},
+ {"mp2", "audio/mpeg"},
+ {"mp3", "audio/mpeg"},
+ {"mp4", "video/mp4"},
+ {"mpe", "video/mpeg"},
+ {"mpeg", "video/mpeg"},
+ {"mpg", "video/mpeg"},
+ {"mpga", "audio/mpeg"},
+ {"pbm", "image/x-portable-bitmap"},
+ {"pcm", "audio/x-pcm"},
+ {"pct", "image/pict"},
+ {"pgm", "image/x-portable-graymap"},
+ {"pic", "image/pict"},
+ {"pict", "image/pict"},
+ {"png", "image/png"},
+ {"pnm", "image/x-portable-anymap"},
+ {"pnt", "image/x-macpaint"},
+ {"pntg", "image/x-macpaint"},
+ {"ppm", "image/x-portable-pixmap"},
+ {"qt", "video/quicktime"},
+ {"ra", "audio/x-pn-realaudio"},
+ {"ram", "audio/x-pn-realaudio"},
+ {"ras", "image/x-cmu-raster"},
+ {"rgb", "image/x-rgb"},
+ {"snd", "audio/basic"},
+ {"txt", "text/plain"},
+ {"tif", "image/tiff"},
+ {"tiff", "image/tiff"},
+ {"wav", "audio/x-wav"},
+ {"wbmp", "image/vnd.wap.wbmp"},
+
+ };
+ /// <summary>
+ /// Gets mime type by file extension
+ /// </summary>
+ /// <param name="fileName">file name to extract extension</param>
+ /// <returns>mime type</returns>
+ public static string GetMimeType(string fileName)
+ {
+ string ext = Path.GetExtension(fileName);
+
+ // invalid extension
+ if (string.IsNullOrEmpty(ext) || !ext.StartsWith("."))
+ {
+ return DefaultMimeType;
+ }
+
+ ext = ext.Remove(0, 1);
+
+ if (MIMETypesDictionary.ContainsKey(ext))
+ {
+ return MIMETypesDictionary[ext];
+ }
+
+ return DefaultMimeType;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/NetworkStatus.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/NetworkStatus.cs b/lib/cordova-wp8/templates/standalone/Plugins/NetworkStatus.cs
new file mode 100644
index 0000000..12eb061
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/NetworkStatus.cs
@@ -0,0 +1,129 @@
+/*
+ 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.Net;
+using System.Net.NetworkInformation;
+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.Net.NetworkInformation;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+
+ // http://msdn.microsoft.com/en-us/library/microsoft.phone.net.networkinformation(v=VS.92).aspx
+ // http://msdn.microsoft.com/en-us/library/microsoft.phone.net.networkinformation.devicenetworkinformation(v=VS.92).aspx
+
+ public class NetworkStatus : BaseCommand
+ {
+ const string UNKNOWN = "unknown";
+ const string ETHERNET = "ethernet";
+ const string WIFI = "wifi";
+ const string CELL_2G = "2g";
+ const string CELL_3G = "3g";
+ const string CELL_4G = "4g";
+ const string NONE = "none";
+ const string CELL = "cellular";
+
+ private bool HasCallback = false;
+
+ public NetworkStatus()
+ {
+ DeviceNetworkInformation.NetworkAvailabilityChanged += new EventHandler<NetworkNotificationEventArgs>(ChangeDetected);
+ }
+
+ public override void OnResume(object sender, Microsoft.Phone.Shell.ActivatedEventArgs e)
+ {
+ this.getConnectionInfo("");
+ }
+
+ public void getConnectionInfo(string empty)
+ {
+ HasCallback = true;
+ updateConnectionType(checkConnectionType());
+ }
+
+ private string checkConnectionType()
+ {
+ if (DeviceNetworkInformation.IsNetworkAvailable)
+ {
+ if (DeviceNetworkInformation.IsWiFiEnabled)
+ {
+ return WIFI;
+ }
+ else
+ {
+ return DeviceNetworkInformation.IsCellularDataEnabled ? CELL : UNKNOWN;
+ }
+ }
+ return NONE;
+ }
+
+ private string checkConnectionType(NetworkInterfaceSubType type)
+ {
+ switch (type)
+ {
+ case NetworkInterfaceSubType.Cellular_1XRTT: //cell
+ case NetworkInterfaceSubType.Cellular_GPRS: //cell
+ return CELL;
+ case NetworkInterfaceSubType.Cellular_EDGE: //2
+ return CELL_2G;
+ case NetworkInterfaceSubType.Cellular_3G:
+ case NetworkInterfaceSubType.Cellular_EVDO: //3
+ case NetworkInterfaceSubType.Cellular_EVDV: //3
+ case NetworkInterfaceSubType.Cellular_HSPA: //3
+ return CELL_3G;
+ case NetworkInterfaceSubType.WiFi:
+ return WIFI;
+ case NetworkInterfaceSubType.Unknown:
+ case NetworkInterfaceSubType.Desktop_PassThru:
+ default:
+ return UNKNOWN;
+ }
+ }
+
+ void ChangeDetected(object sender, NetworkNotificationEventArgs e)
+ {
+ switch (e.NotificationType)
+ {
+ case NetworkNotificationType.InterfaceConnected:
+ updateConnectionType(checkConnectionType(e.NetworkInterface.InterfaceSubtype));
+ break;
+ case NetworkNotificationType.InterfaceDisconnected:
+ updateConnectionType(NONE);
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void updateConnectionType(string type)
+ {
+ // This should also implicitly fire offline/online events as that is handled on the JS side
+ if (this.HasCallback)
+ {
+ PluginResult result = new PluginResult(PluginResult.Status.OK, type);
+ result.KeepCallback = true;
+ DispatchCommandResult(result);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/Notification.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/Notification.cs b/lib/cordova-wp8/templates/standalone/Plugins/Notification.cs
new file mode 100644
index 0000000..0759c72
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/Notification.cs
@@ -0,0 +1,361 @@
+/*
+ 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.Windows;
+using System.Windows.Controls;
+using Microsoft.Devices;
+using System.Runtime.Serialization;
+using System.Threading;
+using System.Windows.Resources;
+using Microsoft.Phone.Controls;
+using Microsoft.Xna.Framework.Audio;
+using WPCordovaClassLib.Cordova.UI;
+using System.Diagnostics;
+
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ public class Notification : BaseCommand
+ {
+ static ProgressBar progressBar = null;
+ const int DEFAULT_DURATION = 5;
+
+ private NotificationBox notifyBox;
+
+ private PhoneApplicationPage Page
+ {
+ get
+ {
+ PhoneApplicationPage page = null;
+ PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
+ if (frame != null)
+ {
+ page = frame.Content as PhoneApplicationPage;
+ }
+ return page;
+ }
+ }
+
+ // blink api - doesn't look like there is an equivalent api we can use...
+
+ [DataContract]
+ public class AlertOptions
+ {
+ [OnDeserializing]
+ public void OnDeserializing(StreamingContext context)
+ {
+ // set defaults
+ this.message = "message";
+ this.title = "Alert";
+ this.buttonLabel = "ok";
+ }
+
+ /// <summary>
+ /// message to display in the alert box
+ /// </summary>
+ [DataMember]
+ public string message;
+
+ /// <summary>
+ /// title displayed on the alert window
+ /// </summary>
+ [DataMember]
+ public string title;
+
+ /// <summary>
+ /// text to display on the button
+ /// </summary>
+ [DataMember]
+ public string buttonLabel;
+ }
+
+ public void alert(string options)
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+ AlertOptions alertOpts = new AlertOptions();
+ alertOpts.message = args[0];
+ alertOpts.title = args[1];
+ alertOpts.buttonLabel = args[2];
+ string aliasCurrentCommandCallbackId = args[3];
+
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ PhoneApplicationPage page = Page;
+ if (page != null)
+ {
+ Grid grid = page.FindName("LayoutRoot") as Grid;
+ if (grid != null)
+ {
+ var previous = notifyBox;
+ notifyBox = new NotificationBox();
+ notifyBox.Tag = new { previous = previous, callbackId = aliasCurrentCommandCallbackId };
+ notifyBox.PageTitle.Text = alertOpts.title;
+ notifyBox.SubTitle.Text = alertOpts.message;
+ Button btnOK = new Button();
+ btnOK.Content = alertOpts.buttonLabel;
+ btnOK.Click += new RoutedEventHandler(btnOK_Click);
+ btnOK.Tag = 1;
+ notifyBox.ButtonPanel.Children.Add(btnOK);
+ grid.Children.Add(notifyBox);
+
+ if (previous == null)
+ {
+ page.BackKeyPress += page_BackKeyPress;
+ }
+ }
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.INSTANTIATION_EXCEPTION));
+ }
+ });
+ }
+
+ public void confirm(string options)
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+ AlertOptions alertOpts = new AlertOptions();
+ alertOpts.message = args[0];
+ alertOpts.title = args[1];
+ alertOpts.buttonLabel = args[2];
+ string aliasCurrentCommandCallbackId = args[3];
+
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ PhoneApplicationPage page = Page;
+ if (page != null)
+ {
+ Grid grid = page.FindName("LayoutRoot") as Grid;
+ if (grid != null)
+ {
+ var previous = notifyBox;
+ notifyBox = new NotificationBox();
+ notifyBox.Tag = new { previous = previous, callbackId = aliasCurrentCommandCallbackId };
+ notifyBox.PageTitle.Text = alertOpts.title;
+ notifyBox.SubTitle.Text = alertOpts.message;
+
+ string[] labels = JSON.JsonHelper.Deserialize<string[]>(alertOpts.buttonLabel);
+
+ if (labels == null)
+ {
+ labels = alertOpts.buttonLabel.Split(',');
+ }
+
+ for (int n = 0; n < labels.Length; n++)
+ {
+ Button btn = new Button();
+ btn.Content = labels[n];
+ btn.Tag = n;
+ btn.Click += new RoutedEventHandler(btnOK_Click);
+ notifyBox.ButtonPanel.Children.Add(btn);
+ }
+
+ grid.Children.Add(notifyBox);
+ if (previous == null)
+ {
+ page.BackKeyPress += page_BackKeyPress;
+ }
+ }
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.INSTANTIATION_EXCEPTION));
+ }
+ });
+ }
+
+ void page_BackKeyPress(object sender, System.ComponentModel.CancelEventArgs e)
+ {
+ PhoneApplicationPage page = sender as PhoneApplicationPage;
+ string callbackId = "";
+ if (page != null && notifyBox != null)
+ {
+ Grid grid = page.FindName("LayoutRoot") as Grid;
+ if (grid != null)
+ {
+ grid.Children.Remove(notifyBox);
+ dynamic notifBoxData = notifyBox.Tag;
+ notifyBox = notifBoxData.previous as NotificationBox;
+ callbackId = notifBoxData.callbackId as string;
+ }
+ if (notifyBox == null)
+ {
+ page.BackKeyPress -= page_BackKeyPress;
+ }
+ e.Cancel = true;
+ }
+
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, 0), callbackId);
+ }
+
+ void btnOK_Click(object sender, RoutedEventArgs e)
+ {
+ Button btn = sender as Button;
+ FrameworkElement notifBoxParent = null;
+ int retVal = 0;
+ string callbackId = "";
+ if (btn != null)
+ {
+ retVal = (int)btn.Tag + 1;
+
+ notifBoxParent = btn.Parent as FrameworkElement;
+ while ((notifBoxParent = notifBoxParent.Parent as FrameworkElement) != null &&
+ !(notifBoxParent is NotificationBox)) ;
+ }
+ if (notifBoxParent != null)
+ {
+ PhoneApplicationPage page = Page;
+ if (page != null)
+ {
+ Grid grid = page.FindName("LayoutRoot") as Grid;
+ if (grid != null)
+ {
+ grid.Children.Remove(notifBoxParent);
+ }
+
+ dynamic notifBoxData = notifBoxParent.Tag;
+ notifyBox = notifBoxData.previous as NotificationBox;
+ callbackId = notifBoxData.callbackId as string;
+
+ if (notifyBox == null)
+ {
+ page.BackKeyPress -= page_BackKeyPress;
+ }
+ }
+
+ }
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, retVal),callbackId);
+ }
+
+
+
+ public void beep(string options)
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+ int times = int.Parse(args[0]);
+
+ string resourcePath = BaseCommand.GetBaseURL() + "resources/notification-beep.wav";
+
+ StreamResourceInfo sri = Application.GetResourceStream(new Uri(resourcePath, UriKind.Relative));
+
+ if (sri != null)
+ {
+ SoundEffect effect = SoundEffect.FromStream(sri.Stream);
+ SoundEffectInstance inst = effect.CreateInstance();
+ ThreadPool.QueueUserWorkItem((o) =>
+ {
+ // cannot interact with UI !!
+ do
+ {
+ inst.Play();
+ Thread.Sleep(effect.Duration + TimeSpan.FromMilliseconds(100));
+ }
+ while (--times > 0);
+
+ });
+
+ }
+
+ // TODO: may need a listener to trigger DispatchCommandResult after the alarm has finished executing...
+ DispatchCommandResult();
+ }
+
+ // Display an indeterminate progress indicator
+ public void activityStart(string unused)
+ {
+
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
+
+ if (frame != null)
+ {
+ PhoneApplicationPage page = frame.Content as PhoneApplicationPage;
+
+ if (page != null)
+ {
+ var temp = page.FindName("LayoutRoot");
+ Grid grid = temp as Grid;
+ if (grid != null)
+ {
+ if (progressBar != null)
+ {
+ grid.Children.Remove(progressBar);
+ }
+ progressBar = new ProgressBar();
+ progressBar.IsIndeterminate = true;
+ progressBar.IsEnabled = true;
+
+ grid.Children.Add(progressBar);
+ }
+ }
+ }
+ });
+ }
+
+
+ // Remove our indeterminate progress indicator
+ public void activityStop(string unused)
+ {
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ if (progressBar != null)
+ {
+ progressBar.IsEnabled = false;
+ PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
+ if (frame != null)
+ {
+ PhoneApplicationPage page = frame.Content as PhoneApplicationPage;
+ if (page != null)
+ {
+ Grid grid = page.FindName("LayoutRoot") as Grid;
+ if (grid != null)
+ {
+ grid.Children.Remove(progressBar);
+ }
+ }
+ }
+ progressBar = null;
+ }
+ });
+ }
+
+ public void vibrate(string vibrateDuration)
+ {
+
+ int msecs = 200; // set default
+
+ try
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(vibrateDuration);
+
+ msecs = int.Parse(args[0]);
+ if (msecs < 1)
+ {
+ msecs = 1;
+ }
+ }
+ catch (FormatException)
+ {
+
+ }
+
+ VibrateController.Default.Start(TimeSpan.FromMilliseconds(msecs));
+
+ // TODO: may need to add listener to trigger DispatchCommandResult when the vibration ends...
+ DispatchCommandResult();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/UI/AudioCaptureTask.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/UI/AudioCaptureTask.cs b/lib/cordova-wp8/templates/standalone/Plugins/UI/AudioCaptureTask.cs
new file mode 100644
index 0000000..3d7d60f
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/UI/AudioCaptureTask.cs
@@ -0,0 +1,107 @@
+/*
+ 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.IO;
+using System.Windows;
+using Microsoft.Phone.Controls;
+using Microsoft.Phone.Tasks;
+
+namespace WPCordovaClassLib.Cordova.UI
+{
+ /// <summary>
+ /// Allows an application to launch the Audio Recording application.
+ /// Use this to allow users to record audio from your application.
+ /// </summary>
+ public class AudioCaptureTask
+ {
+ /// <summary>
+ /// Represents recorded audio returned from a call to the Show method of
+ /// a WPCordovaClassLib.Cordova.Controls.AudioCaptureTask object
+ /// </summary>
+ public class AudioResult : TaskEventArgs
+ {
+ /// <summary>
+ /// Initializes a new instance of the AudioResult class.
+ /// </summary>
+ public AudioResult()
+ { }
+
+ /// <summary>
+ /// Initializes a new instance of the AudioResult class
+ /// with the specified Microsoft.Phone.Tasks.TaskResult.
+ /// </summary>
+ /// <param name="taskResult">Associated Microsoft.Phone.Tasks.TaskResult</param>
+ public AudioResult(TaskResult taskResult)
+ : base(taskResult)
+ { }
+
+ /// <summary>
+ /// Gets the file name of the recorded audio.
+ /// </summary>
+ public Stream AudioFile { get; internal set; }
+
+ /// <summary>
+ /// Gets the stream containing the data for the recorded audio.
+ /// </summary>
+ public string AudioFileName { get; internal set; }
+ }
+
+ /// <summary>
+ /// Occurs when a audio recording task is completed.
+ /// </summary>
+ public event EventHandler<AudioResult> Completed;
+
+ /// <summary>
+ /// Shows Audio Recording application
+ /// </summary>
+ public void Show()
+ {
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ var root = Application.Current.RootVisual as PhoneApplicationFrame;
+
+ root.Navigated += new System.Windows.Navigation.NavigatedEventHandler(NavigationService_Navigated);
+
+ string baseUrl = WPCordovaClassLib.Cordova.Commands.BaseCommand.GetBaseURL();
+ // dummy parameter is used to always open a fresh version
+ root.Navigate(new System.Uri( baseUrl + "CordovaLib/UI/AudioRecorder.xaml?dummy=" + Guid.NewGuid().ToString(), UriKind.Relative));
+
+ });
+ }
+
+ /// <summary>
+ /// Performs additional configuration of the recording application.
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="e"></param>
+ private void NavigationService_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
+ {
+ if (!(e.Content is AudioRecorder)) return;
+
+ (Application.Current.RootVisual as PhoneApplicationFrame).Navigated -= NavigationService_Navigated;
+
+ AudioRecorder audioRecorder = (AudioRecorder)e.Content;
+
+ if (audioRecorder != null)
+ {
+ audioRecorder.Completed += this.Completed;
+ }
+ else if (this.Completed != null)
+ {
+ this.Completed(this, new AudioResult(TaskResult.Cancel));
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/UI/AudioRecorder.xaml
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/UI/AudioRecorder.xaml b/lib/cordova-wp8/templates/standalone/Plugins/UI/AudioRecorder.xaml
new file mode 100644
index 0000000..0fd26ab
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/UI/AudioRecorder.xaml
@@ -0,0 +1,66 @@
+<!--
+ 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.
+-->
+<phone:PhoneApplicationPage
+ x:Class="WPCordovaClassLib.Cordova.UI.AudioRecorder"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
+ xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ FontFamily="{StaticResource PhoneFontFamilyNormal}"
+ FontSize="{StaticResource PhoneFontSizeNormal}"
+ Foreground="{StaticResource PhoneForegroundBrush}"
+ SupportedOrientations="Portrait" Orientation="Portrait"
+ mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
+ shell:SystemTray.IsVisible="True">
+
+ <!--LayoutRoot is the root grid where all page content is placed-->
+ <Grid x:Name="LayoutRoot" Background="Transparent">
+ <Grid.RowDefinitions>
+ <RowDefinition Height="Auto"/>
+ <RowDefinition Height="*"/>
+ </Grid.RowDefinitions>
+
+ <!--TitlePanel contains the name of the application and page title-->
+ <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="0,17,0,28">
+ <TextBlock x:Name="PageTitle" Text="Audio recorder" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
+ </StackPanel>
+
+ <!--ContentPanel - place additional content here-->
+ <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
+ <Button Name="btnStartStop" Content="Start" Height="72" HorizontalAlignment="Left" Margin="156,96,0,0" VerticalAlignment="Top" Width="160" Click="btnStartStop_Click" />
+ <Button Name="btnTake" Content="Take" IsEnabled="False" Height="72" HorizontalAlignment="Left" Margin="155,182,0,0" VerticalAlignment="Top" Width="160" Click="btnTake_Click" />
+ <TextBlock Height="30" HorizontalAlignment="Left" Margin="168,60,0,0" Name="txtDuration" Text="Duration: 00:00" VerticalAlignment="Top" />
+ </Grid>
+ </Grid>
+
+ <!--Sample code showing usage of ApplicationBar-->
+ <!--<phone:PhoneApplicationPage.ApplicationBar>
+ <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
+ <shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="Button 1"/>
+ <shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="Button 2"/>
+ <shell:ApplicationBar.MenuItems>
+ <shell:ApplicationBarMenuItem Text="MenuItem 1"/>
+ <shell:ApplicationBarMenuItem Text="MenuItem 2"/>
+ </shell:ApplicationBar.MenuItems>
+ </shell:ApplicationBar>
+ </phone:PhoneApplicationPage.ApplicationBar>-->
+
+</phone:PhoneApplicationPage>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/UI/AudioRecorder.xaml.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/UI/AudioRecorder.xaml.cs b/lib/cordova-wp8/templates/standalone/Plugins/UI/AudioRecorder.xaml.cs
new file mode 100644
index 0000000..01a0832
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/UI/AudioRecorder.xaml.cs
@@ -0,0 +1,307 @@
+/*
+ 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 Microsoft.Phone.Controls;
+using Microsoft.Phone.Tasks;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Audio;
+using System;
+using System.IO;
+using System.IO.IsolatedStorage;
+using System.Windows;
+using System.Windows.Threading;
+using WPCordovaClassLib.Cordova.Commands;
+using AudioResult = WPCordovaClassLib.Cordova.UI.AudioCaptureTask.AudioResult;
+
+namespace WPCordovaClassLib.Cordova.UI
+{
+ /// <summary>
+ /// Implements Audio Recording application
+ /// </summary>
+ public partial class AudioRecorder : PhoneApplicationPage
+ {
+
+ #region Constants
+
+ private const string RecordingStartCaption = "Start";
+ private const string RecordingStopCaption = "Stop";
+
+ private const string LocalFolderName = "AudioCache";
+ private const string FileNameFormat = "Audio-{0}.wav";
+
+ #endregion
+
+ #region Callbacks
+
+ /// <summary>
+ /// Occurs when a audio recording task is completed.
+ /// </summary>
+ public event EventHandler<AudioResult> Completed;
+
+ #endregion
+
+ #region Fields
+
+ /// <summary>
+ /// Audio source
+ /// </summary>
+ private Microphone microphone;
+
+ /// <summary>
+ /// Temporary buffer to store audio chunk
+ /// </summary>
+ private byte[] buffer;
+
+ /// <summary>
+ /// Recording duration
+ /// </summary>
+ private TimeSpan duration;
+
+ /// <summary>
+ /// Output buffer
+ /// </summary>
+ private MemoryStream memoryStream;
+
+ /// <summary>
+ /// Xna game loop dispatcher
+ /// </summary>
+ DispatcherTimer dtXna;
+
+ /// <summary>
+ /// Recording result, dispatched back when recording page is closed
+ /// </summary>
+ private AudioResult result = new AudioResult(TaskResult.Cancel);
+
+ /// <summary>
+ /// Whether we are recording audio now
+ /// </summary>
+ private bool IsRecording
+ {
+ get
+ {
+ return (this.microphone != null && this.microphone.State == MicrophoneState.Started);
+ }
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Creates new instance of the AudioRecorder class.
+ /// </summary>
+ public AudioRecorder()
+ {
+
+ this.InitializeXnaGameLoop();
+
+ // microphone requires special XNA initialization to work
+ InitializeComponent();
+ }
+
+ /// <summary>
+ /// Starts recording, data is stored in memory
+ /// </summary>
+ private void StartRecording()
+ {
+ this.microphone = Microphone.Default;
+ this.microphone.BufferDuration = TimeSpan.FromMilliseconds(500);
+
+ this.btnTake.IsEnabled = false;
+ this.btnStartStop.Content = RecordingStopCaption;
+
+ this.buffer = new byte[microphone.GetSampleSizeInBytes(this.microphone.BufferDuration)];
+ this.microphone.BufferReady += new EventHandler<EventArgs>(MicrophoneBufferReady);
+
+ this.memoryStream = new MemoryStream();
+ this.memoryStream.InitializeWavStream(this.microphone.SampleRate);
+
+ this.duration = new TimeSpan(0);
+
+ this.microphone.Start();
+ }
+
+ /// <summary>
+ /// Stops recording
+ /// </summary>
+ private void StopRecording()
+ {
+ this.microphone.Stop();
+
+ this.microphone.BufferReady -= MicrophoneBufferReady;
+
+ this.microphone = null;
+
+ btnStartStop.Content = RecordingStartCaption;
+
+ // check there is some data
+ this.btnTake.IsEnabled = true;
+ }
+
+ /// <summary>
+ /// Handles Start/Stop events
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="e"></param>
+ private void btnStartStop_Click(object sender, RoutedEventArgs e)
+ {
+
+ if (this.IsRecording)
+ {
+ this.StopRecording();
+ }
+ else
+ {
+ this.StartRecording();
+ }
+ }
+
+ /// <summary>
+ /// Handles Take button click
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="e"></param>
+ private void btnTake_Click(object sender, RoutedEventArgs e)
+ {
+ this.result = this.SaveAudioClipToLocalStorage();
+
+ if (Completed != null)
+ {
+ Completed(this, result);
+ }
+
+ if (this.NavigationService.CanGoBack)
+ {
+ this.NavigationService.GoBack();
+ }
+ }
+
+ /// <summary>
+ /// Handles page closing event, stops recording if needed and dispatches results.
+ /// </summary>
+ /// <param name="e"></param>
+ protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
+ {
+ if (IsRecording)
+ {
+ StopRecording();
+ }
+
+ this.FinalizeXnaGameLoop();
+
+ base.OnNavigatedFrom(e);
+ }
+
+ /// <summary>
+ /// Copies data from microphone to memory storages and updates recording state
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="e"></param>
+ private void MicrophoneBufferReady(object sender, EventArgs e)
+ {
+ this.microphone.GetData(this.buffer);
+ this.memoryStream.Write(this.buffer, 0, this.buffer.Length);
+ TimeSpan bufferDuration = this.microphone.BufferDuration;
+
+ this.Dispatcher.BeginInvoke(() =>
+ {
+ this.duration += bufferDuration;
+
+ this.txtDuration.Text = "Duration: " +
+ this.duration.Minutes.ToString().PadLeft(2, '0') + ":" +
+ this.duration.Seconds.ToString().PadLeft(2, '0');
+ });
+
+ }
+
+ /// <summary>
+ /// Writes audio data from memory to isolated storage
+ /// </summary>
+ /// <returns></returns>
+ private AudioResult SaveAudioClipToLocalStorage()
+ {
+ if (this.memoryStream == null || this.memoryStream.Length <= 0)
+ {
+ return new AudioResult(TaskResult.Cancel);
+ }
+
+ this.memoryStream.UpdateWavStream();
+
+ // save audio data to local isolated storage
+
+ string filename = String.Format(FileNameFormat, Guid.NewGuid().ToString());
+
+ try
+ {
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+
+ if (!isoFile.DirectoryExists(LocalFolderName))
+ {
+ isoFile.CreateDirectory(LocalFolderName);
+ }
+
+ string filePath = System.IO.Path.Combine("/" + LocalFolderName + "/", filename);
+
+ this.memoryStream.Seek(0, SeekOrigin.Begin);
+
+ using (IsolatedStorageFileStream fileStream = isoFile.CreateFile(filePath))
+ {
+
+ this.memoryStream.CopyTo(fileStream);
+ }
+
+ AudioResult result = new AudioResult(TaskResult.OK);
+ result.AudioFileName = filePath;
+
+ result.AudioFile = this.memoryStream;
+ result.AudioFile.Seek(0, SeekOrigin.Begin);
+
+ return result;
+ }
+
+
+
+ }
+ catch (Exception)
+ {
+ //TODO: log or do something else
+ throw;
+ }
+ }
+
+ /// <summary>
+ /// Special initialization required for the microphone: XNA game loop
+ /// </summary>
+ private void InitializeXnaGameLoop()
+ {
+ // Timer to simulate the XNA game loop (Microphone is from XNA)
+ this.dtXna = new DispatcherTimer();
+ this.dtXna.Interval = TimeSpan.FromMilliseconds(33);
+ this.dtXna.Tick += delegate { try { FrameworkDispatcher.Update(); } catch { } };
+ this.dtXna.Start();
+ }
+ /// <summary>
+ /// Finalizes XNA game loop for microphone
+ /// </summary>
+ private void FinalizeXnaGameLoop()
+ {
+ // Timer to simulate the XNA game loop (Microphone is from XNA)
+ if (dtXna != null)
+ {
+ dtXna.Stop();
+ dtXna = null;
+ }
+ }
+
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/UI/ImageCapture.xaml
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/UI/ImageCapture.xaml b/lib/cordova-wp8/templates/standalone/Plugins/UI/ImageCapture.xaml
new file mode 100644
index 0000000..a7eee21
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/UI/ImageCapture.xaml
@@ -0,0 +1,26 @@
+<phone:PhoneApplicationPage
+ x:Class="WPCordovaClassLib.Cordova.UI.ImageCapture"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
+ xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ FontFamily="{StaticResource PhoneFontFamilyNormal}"
+ FontSize="{StaticResource PhoneFontSizeNormal}"
+ Foreground="{StaticResource PhoneForegroundBrush}"
+ SupportedOrientations="PortraitOrLandscape" Orientation="Portrait"
+ mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
+ shell:SystemTray.IsVisible="True">
+
+ <!--LayoutRoot is the root grid where all page content is placed-->
+ <Grid x:Name="LayoutRoot" Background="Yellow">
+ <Grid.RowDefinitions>
+ <RowDefinition Height="Auto"/>
+ <RowDefinition Height="*"/>
+ </Grid.RowDefinitions>
+
+ </Grid>
+
+
+</phone:PhoneApplicationPage>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/UI/ImageCapture.xaml.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/UI/ImageCapture.xaml.cs b/lib/cordova-wp8/templates/standalone/Plugins/UI/ImageCapture.xaml.cs
new file mode 100644
index 0000000..234b444
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/UI/ImageCapture.xaml.cs
@@ -0,0 +1,109 @@
+/*
+ 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.IO;
+using System.Windows;
+using Microsoft.Phone.Controls;
+using Microsoft.Phone.Tasks;
+
+namespace WPCordovaClassLib.Cordova.UI
+{
+ public partial class ImageCapture : PhoneApplicationPage
+ {
+ public ImageCapture()
+ {
+ InitializeComponent();
+ }
+ }
+
+ public class ImageCaptureTask
+ {
+ /// <summary>
+ /// Represents an image returned from a call to the Show method of
+ /// a WPCordovaClassLib.Cordova.Controls.ImageCaptureTask object
+ /// </summary>
+ //public class AudioResult : TaskEventArgs
+ //{
+ // /// <summary>
+ // /// Initializes a new instance of the AudioResult class.
+ // /// </summary>
+ // public AudioResult()
+ // { }
+
+ // /// <summary>
+ // /// Initializes a new instance of the AudioResult class
+ // /// with the specified Microsoft.Phone.Tasks.TaskResult.
+ // /// </summary>
+ // /// <param name="taskResult">Associated Microsoft.Phone.Tasks.TaskResult</param>
+ // public AudioResult(TaskResult taskResult)
+ // : base(taskResult)
+ // { }
+
+ // /// <summary>
+ // /// Gets the file name of the recorded audio.
+ // /// </summary>
+ // public Stream AudioFile { get; internal set; }
+
+ // /// <summary>
+ // /// Gets the stream containing the data for the recorded audio.
+ // /// </summary>
+ // public string AudioFileName { get; internal set; }
+ //}
+
+ ///// <summary>
+ ///// Occurs when a audio recording task is completed.
+ ///// </summary>
+ //public event EventHandler<AudioResult> Completed;
+
+ /// <summary>
+ /// Shows Audio Recording application
+ /// </summary>
+ public void Show()
+ {
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ var root = Application.Current.RootVisual as PhoneApplicationFrame;
+
+ root.Navigated += new System.Windows.Navigation.NavigatedEventHandler(NavigationService_Navigated);
+
+ string baseUrl = WPCordovaClassLib.Cordova.Commands.BaseCommand.GetBaseURL();
+
+ // dummy parameter is used to always open a fresh version
+ root.Navigate(new System.Uri(baseUrl + "Cordova/UI/ImageCapture.xaml?dummy=" + Guid.NewGuid().ToString(), UriKind.Relative));
+ });
+ }
+
+ /// <summary>
+ /// Performs additional configuration of the recording application.
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="e"></param>
+ private void NavigationService_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
+ {
+ ImageCapture imageCapture = e.Content as ImageCapture;
+ if (imageCapture != null)
+ {
+ (Application.Current.RootVisual as PhoneApplicationFrame).Navigated -= NavigationService_Navigated;
+
+ //imageCapture.Completed += this.Completed;
+ //else if (this.Completed != null)
+ //{
+ // this.Completed(this, new AudioResult(TaskResult.Cancel));
+ //}
+ }
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/UI/NotificationBox.xaml
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/UI/NotificationBox.xaml b/lib/cordova-wp8/templates/standalone/Plugins/UI/NotificationBox.xaml
new file mode 100644
index 0000000..1ca5d5f
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/UI/NotificationBox.xaml
@@ -0,0 +1,62 @@
+<!--
+ 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.Cordova.UI.NotificationBox"
+ 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="800" d:DesignWidth="480" VerticalAlignment="Stretch">
+
+ <Grid x:Name="LayoutRoot"
+ Background="{StaticResource PhoneSemitransparentBrush}" VerticalAlignment="Stretch">
+
+ <Grid.RowDefinitions>
+ <RowDefinition Height="Auto"/>
+ <RowDefinition Height="*"/>
+ </Grid.RowDefinitions>
+
+
+ <!--TitlePanel contains the name of the application and page title-->
+ <StackPanel x:Name="TitlePanel"
+ Grid.Row="0"
+ Background="{StaticResource PhoneSemitransparentBrush}">
+ <TextBlock x:Name="PageTitle"
+ Text="Title"
+ Margin="10,10"
+ Style="{StaticResource PhoneTextTitle2Style}"/>
+
+ <TextBlock x:Name="SubTitle"
+ Text="Subtitle"
+ TextWrapping="Wrap"
+ Margin="10,10"
+ Style="{StaticResource PhoneTextTitle3Style}"/>
+
+ <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled">
+ <StackPanel x:Name="ButtonPanel"
+ Margin="10,10"
+ Orientation="Horizontal"/>
+ </ScrollViewer>
+
+ </StackPanel>
+ </Grid>
+</UserControl>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/UI/NotificationBox.xaml.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/UI/NotificationBox.xaml.cs b/lib/cordova-wp8/templates/standalone/Plugins/UI/NotificationBox.xaml.cs
new file mode 100644
index 0000000..50b2f2a
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/UI/NotificationBox.xaml.cs
@@ -0,0 +1,41 @@
+/*
+ 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.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;
+
+namespace WPCordovaClassLib.Cordova.UI
+{
+ public partial class NotificationBox : UserControl
+ {
+ public NotificationBox()
+ {
+ InitializeComponent();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/UI/VideoCaptureTask.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/UI/VideoCaptureTask.cs b/lib/cordova-wp8/templates/standalone/Plugins/UI/VideoCaptureTask.cs
new file mode 100644
index 0000000..958c05c
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/UI/VideoCaptureTask.cs
@@ -0,0 +1,105 @@
+/*
+ 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.IO;
+using System.Windows;
+using Microsoft.Phone.Controls;
+using Microsoft.Phone.Tasks;
+
+namespace WPCordovaClassLib.Cordova.UI
+{
+ /// <summary>
+ /// Allows an application to launch the Video Recording application.
+ /// Use this to allow users to record video from your application.
+ /// </summary>
+ public class VideoCaptureTask
+ {
+ /// <summary>
+ /// Represents recorded video returned from a call to the Show method of
+ /// a WPCordovaClassLib.Cordova.Controls.VideoCaptureTask object
+ /// </summary>
+ public class VideoResult : TaskEventArgs
+ {
+ /// <summary>
+ /// Initializes a new instance of the VideoResult class.
+ /// </summary>
+ public VideoResult()
+ { }
+
+ /// <summary>
+ /// Initializes a new instance of the VideoResult class
+ /// with the specified Microsoft.Phone.Tasks.TaskResult.
+ /// </summary>
+ /// <param name="taskResult">Associated Microsoft.Phone.Tasks.TaskResult</param>
+ public VideoResult(TaskResult taskResult)
+ : base(taskResult)
+ { }
+
+ /// <summary>
+ /// Gets the file name of the recorded Video.
+ /// </summary>
+ public Stream VideoFile { get; internal set; }
+
+ /// <summary>
+ /// Gets the stream containing the data for the recorded Video.
+ /// </summary>
+ public string VideoFileName { get; internal set; }
+ }
+
+ /// <summary>
+ /// Occurs when a Video recording task is completed.
+ /// </summary>
+ public event EventHandler<VideoResult> Completed;
+
+ /// <summary>
+ /// Shows Video Recording application
+ /// </summary>
+ public void Show()
+ {
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ var root = Application.Current.RootVisual as PhoneApplicationFrame;
+
+ root.Navigated += new System.Windows.Navigation.NavigatedEventHandler(NavigationService_Navigated);
+
+ string baseUrl = WPCordovaClassLib.Cordova.Commands.BaseCommand.GetBaseURL();
+ // dummy parameter is used to always open a fresh version
+ root.Navigate(new System.Uri( baseUrl + "CordovaLib/UI/VideoRecorder.xaml?dummy=" + Guid.NewGuid().ToString(), UriKind.Relative));
+ });
+ }
+
+ /// <summary>
+ /// Performs additional configuration of the recording application.
+ /// </summary>
+ private void NavigationService_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
+ {
+ if (!(e.Content is VideoRecorder)) return;
+
+ (Application.Current.RootVisual as PhoneApplicationFrame).Navigated -= NavigationService_Navigated;
+
+ VideoRecorder VideoRecorder = (VideoRecorder)e.Content;
+
+ if (VideoRecorder != null)
+ {
+ VideoRecorder.Completed += this.Completed;
+ }
+ else if (this.Completed != null)
+ {
+ this.Completed(this, new VideoResult(TaskResult.Cancel));
+ }
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/UI/VideoRecorder.xaml
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/UI/VideoRecorder.xaml b/lib/cordova-wp8/templates/standalone/Plugins/UI/VideoRecorder.xaml
new file mode 100644
index 0000000..c78fdb0
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/UI/VideoRecorder.xaml
@@ -0,0 +1,52 @@
+<!--
+ 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.
+-->
+<phone:PhoneApplicationPage
+ x:Class="WPCordovaClassLib.Cordova.UI.VideoRecorder"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
+ xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="480"
+ FontFamily="{StaticResource PhoneFontFamilyNormal}"
+ FontSize="{StaticResource PhoneFontSizeNormal}"
+ Foreground="{StaticResource PhoneForegroundBrush}"
+ SupportedOrientations="Landscape" Orientation="LandscapeLeft"
+ shell:SystemTray.IsVisible="False">
+
+ <Canvas x:Name="LayoutRoot" Background="Transparent" Grid.ColumnSpan="1" Grid.Column="0">
+
+ <Rectangle
+ x:Name="viewfinderRectangle"
+ Width="640"
+ Height="480"
+ HorizontalAlignment="Left"
+ Canvas.Left="80"/>
+
+ </Canvas>
+
+ <phone:PhoneApplicationPage.ApplicationBar>
+ <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True" x:Name="PhoneAppBar" Opacity="0.0">
+ <shell:ApplicationBarIconButton IconUri="/Images/appbar.feature.video.rest.png" Text="Record" x:Name="btnStartRecording" Click="StartRecording_Click" />
+ <shell:ApplicationBarIconButton IconUri="/Images/appbar.save.rest.png" Text="Take" x:Name="btnTakeVideo" Click="TakeVideo_Click"/>
+ </shell:ApplicationBar>
+ </phone:PhoneApplicationPage.ApplicationBar>
+
+</phone:PhoneApplicationPage>
[36/37] Add Windows support to Android platform-scripts.
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/templates/cordova/lib/list-started-emulators
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/list-started-emulators b/lib/cordova-android/bin/templates/cordova/lib/list-started-emulators
new file mode 100644
index 0000000..7911763
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/lib/list-started-emulators
@@ -0,0 +1,23 @@
+#!/bin/bash
+# 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.
+
+set -e
+
+CORDOVA_LIB_PATH=$( cd "$( dirname "$0" )" && pwd )
+
+bash "$CORDOVA_LIB_PATH"/cordova list-started-emulators
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/templates/cordova/lib/list-started-emulators.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/list-started-emulators.bat b/lib/cordova-android/bin/templates/cordova/lib/list-started-emulators.bat
new file mode 100644
index 0000000..f1b3c5d
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/lib/list-started-emulators.bat
@@ -0,0 +1,9 @@
+@ECHO OFF
+SET full_path=%~dp0
+IF EXIST %full_path%cordova.js (
+ cscript "%full_path%cordova.js" list-started-emulators //nologo
+) ELSE (
+ ECHO.
+ ECHO ERROR: Could not find 'cordova.js' in cordova/lib, aborting...>&2
+ EXIT /B 1
+)
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/templates/cordova/lib/start-emulator
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/start-emulator b/lib/cordova-android/bin/templates/cordova/lib/start-emulator
new file mode 100644
index 0000000..8e8964d
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/lib/start-emulator
@@ -0,0 +1,23 @@
+#!/bin/bash
+# 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.
+
+set -e
+
+CORDOVA_LIB_PATH=$( cd "$( dirname "$0" )" && pwd )
+
+bash "$CORDOVA_LIB_PATH"/cordova start-emulator "$@"
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/templates/cordova/lib/start-emulator.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/start-emulator.bat b/lib/cordova-android/bin/templates/cordova/lib/start-emulator.bat
new file mode 100644
index 0000000..4f3fb5d
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/lib/start-emulator.bat
@@ -0,0 +1,9 @@
+@ECHO OFF
+SET full_path=%~dp0
+IF EXIST %full_path%cordova.js (
+ cscript "%full_path%cordova.js" start-emulator %* //nologo
+) ELSE (
+ ECHO.
+ ECHO ERROR: Could not find 'cordova.js' in cordova/lib, aborting...>&2
+ EXIT /B 1
+)
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/templates/cordova/log
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/log b/lib/cordova-android/bin/templates/cordova/log
index 087a200..01fe107 100755
--- a/lib/cordova-android/bin/templates/cordova/log
+++ b/lib/cordova-android/bin/templates/cordova/log
@@ -1,3 +1,4 @@
+#!/bin/bash
# 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
@@ -15,10 +16,8 @@
# specific language governing permissions and limitations
# under the License.
-#!/bin/bash
-
set -e
CORDOVA_PATH=$( cd "$( dirname "$0" )/.." && pwd )
-bash "$CORDOVA_PATH"/cordova/cordova log
+bash "$CORDOVA_PATH"/cordova/lib/cordova log "$@"
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/templates/cordova/log.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/log.bat b/lib/cordova-android/bin/templates/cordova/log.bat
index b8cc6be..2c492e7 100644
--- a/lib/cordova-android/bin/templates/cordova/log.bat
+++ b/lib/cordova-android/bin/templates/cordova/log.bat
@@ -1,18 +1,2 @@
-:: 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.
-
-%~dp0\cordova.bat log
+@ECHO OFF
+%~dp0\cordova.bat log %*
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/templates/cordova/release
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/release b/lib/cordova-android/bin/templates/cordova/release
deleted file mode 100755
index 73d873e..0000000
--- a/lib/cordova-android/bin/templates/cordova/release
+++ /dev/null
@@ -1,24 +0,0 @@
-# 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.
-
-#!/bin/bash
-
-set -e
-
-CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd )
-
-bash "$CORDOVA_PATH"/cordova release
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/templates/cordova/run
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/run b/lib/cordova-android/bin/templates/cordova/run
index 840a8d5..ec352b0 100755
--- a/lib/cordova-android/bin/templates/cordova/run
+++ b/lib/cordova-android/bin/templates/cordova/run
@@ -1,3 +1,4 @@
+#!/bin/bash
# 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
@@ -15,10 +16,8 @@
# specific language governing permissions and limitations
# under the License.
-#!/bin/bash
-
set -e
CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd )
-bash "$CORDOVA_PATH"/cordova run
+bash "$CORDOVA_PATH"/lib/cordova run "$@"
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/templates/cordova/run.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/run.bat b/lib/cordova-android/bin/templates/cordova/run.bat
index 7c470ed..b1cab64 100644
--- a/lib/cordova-android/bin/templates/cordova/run.bat
+++ b/lib/cordova-android/bin/templates/cordova/run.bat
@@ -1 +1,2 @@
-%~dp0\cordova.bat run
+@ECHO OFF
+%~dp0\cordova.bat run %*
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/templates/cordova/version
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/version b/lib/cordova-android/bin/templates/cordova/version
new file mode 100644
index 0000000..21147ab
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/version
@@ -0,0 +1,32 @@
+#!/bin/bash
+# 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.
+
+set -e
+
+CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd -P)
+PROJECT_PATH="$(dirname "$CORDOVA_PATH")"
+
+VERSION_FILE_PATH="$PROJECT_PATH/assets/www/cordova.js"
+
+if [ -f "$VERSION_FILE_PATH" ]; then
+ JSVersion=$(sed -n '2,2p' assets/www/cordova.js)
+ echo $JSVersion | sed -e 's/\/\/ //'| cut -f 1 -d '-'
+else
+ echo "The file \"$VERSION_FILE_PATH\" does not exist."
+ exit 1
+fi
[05/37] Add WP7 and WP8 platform files.
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/cordova-2.5.0.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/cordova-2.5.0.js b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/cordova-2.5.0.js
new file mode 100644
index 0000000..5989d67
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/cordova-2.5.0.js
@@ -0,0 +1,6446 @@
+// Platform: windowsphone
+
+// commit 54660e97952c558518cad8c4eecc67cfa42b2993
+
+// File generated at :: Tue Feb 26 2013 16:24:06 GMT-0800 (Pacific Standard Time)
+
+/*
+ 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.
+*/
+
+;(function() {
+
+// file: lib\scripts\require.js
+
+var require,
+ define;
+
+(function () {
+ var modules = {};
+ // Stack of moduleIds currently being built.
+ var requireStack = [];
+ // Map of module ID -> index into requireStack of modules currently being built.
+ var inProgressModules = {};
+
+ function build(module) {
+ var factory = module.factory;
+ module.exports = {};
+ delete module.factory;
+ factory(require, module.exports, module);
+ return module.exports;
+ }
+
+ require = function (id) {
+ if (!modules[id]) {
+ throw "module " + id + " not found";
+ } else if (id in inProgressModules) {
+ var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id;
+ throw "Cycle in require graph: " + cycle;
+ }
+ if (modules[id].factory) {
+ try {
+ inProgressModules[id] = requireStack.length;
+ requireStack.push(id);
+ return build(modules[id]);
+ } finally {
+ delete inProgressModules[id];
+ requireStack.pop();
+ }
+ }
+ return modules[id].exports;
+ };
+
+ define = function (id, factory) {
+ if (modules[id]) {
+ throw "module " + id + " already defined";
+ }
+
+ modules[id] = {
+ id: id,
+ factory: factory
+ };
+ };
+
+ define.remove = function (id) {
+ delete modules[id];
+ };
+
+ define.moduleMap = modules;
+})();
+
+//Export for use in node
+if (typeof module === "object" && typeof require === "function") {
+ module.exports.require = require;
+ module.exports.define = define;
+}
+
+// file: lib/cordova.js
+define("cordova", function(require, exports, module) {
+
+
+var channel = require('cordova/channel');
+
+/**
+ * Listen for DOMContentLoaded and notify our channel subscribers.
+ */
+document.addEventListener('DOMContentLoaded', function() {
+ channel.onDOMContentLoaded.fire();
+}, false);
+if (document.readyState == 'complete' || document.readyState == 'interactive') {
+ channel.onDOMContentLoaded.fire();
+}
+
+/**
+ * Intercept calls to addEventListener + removeEventListener and handle deviceready,
+ * resume, and pause events.
+ */
+var m_document_addEventListener = document.addEventListener;
+var m_document_removeEventListener = document.removeEventListener;
+var m_window_addEventListener = window.addEventListener;
+var m_window_removeEventListener = window.removeEventListener;
+
+/**
+ * Houses custom event handlers to intercept on document + window event listeners.
+ */
+var documentEventHandlers = {},
+ windowEventHandlers = {};
+
+document.addEventListener = function(evt, handler, capture) {
+ var e = evt.toLowerCase();
+ if (typeof documentEventHandlers[e] != 'undefined') {
+ documentEventHandlers[e].subscribe(handler);
+ } else {
+ m_document_addEventListener.call(document, evt, handler, capture);
+ }
+};
+
+window.addEventListener = function(evt, handler, capture) {
+ var e = evt.toLowerCase();
+ if (typeof windowEventHandlers[e] != 'undefined') {
+ windowEventHandlers[e].subscribe(handler);
+ } else {
+ m_window_addEventListener.call(window, evt, handler, capture);
+ }
+};
+
+document.removeEventListener = function(evt, handler, capture) {
+ var e = evt.toLowerCase();
+ // If unsubscribing from an event that is handled by a plugin
+ if (typeof documentEventHandlers[e] != "undefined") {
+ documentEventHandlers[e].unsubscribe(handler);
+ } else {
+ m_document_removeEventListener.call(document, evt, handler, capture);
+ }
+};
+
+window.removeEventListener = function(evt, handler, capture) {
+ var e = evt.toLowerCase();
+ // If unsubscribing from an event that is handled by a plugin
+ if (typeof windowEventHandlers[e] != "undefined") {
+ windowEventHandlers[e].unsubscribe(handler);
+ } else {
+ m_window_removeEventListener.call(window, evt, handler, capture);
+ }
+};
+
+function createEvent(type, data) {
+ var event = document.createEvent('Events');
+ event.initEvent(type, false, false);
+ if (data) {
+ for (var i in data) {
+ if (data.hasOwnProperty(i)) {
+ event[i] = data[i];
+ }
+ }
+ }
+ return event;
+}
+
+if(typeof window.console === "undefined") {
+ window.console = {
+ log:function(){}
+ };
+}
+
+var cordova = {
+ define:define,
+ require:require,
+ /**
+ * Methods to add/remove your own addEventListener hijacking on document + window.
+ */
+ addWindowEventHandler:function(event) {
+ return (windowEventHandlers[event] = channel.create(event));
+ },
+ addStickyDocumentEventHandler:function(event) {
+ return (documentEventHandlers[event] = channel.createSticky(event));
+ },
+ addDocumentEventHandler:function(event) {
+ return (documentEventHandlers[event] = channel.create(event));
+ },
+ removeWindowEventHandler:function(event) {
+ delete windowEventHandlers[event];
+ },
+ removeDocumentEventHandler:function(event) {
+ delete documentEventHandlers[event];
+ },
+ /**
+ * Retrieve original event handlers that were replaced by Cordova
+ *
+ * @return object
+ */
+ getOriginalHandlers: function() {
+ return {'document': {'addEventListener': m_document_addEventListener, 'removeEventListener': m_document_removeEventListener},
+ 'window': {'addEventListener': m_window_addEventListener, 'removeEventListener': m_window_removeEventListener}};
+ },
+ /**
+ * Method to fire event from native code
+ * bNoDetach is required for events which cause an exception which needs to be caught in native code
+ */
+ fireDocumentEvent: function(type, data, bNoDetach) {
+ var evt = createEvent(type, data);
+ if (typeof documentEventHandlers[type] != 'undefined') {
+ if( bNoDetach ) {
+ documentEventHandlers[type].fire(evt);
+ }
+ else {
+ setTimeout(function() {
+ documentEventHandlers[type].fire(evt);
+ }, 0);
+ }
+ } else {
+ document.dispatchEvent(evt);
+ }
+ },
+ fireWindowEvent: function(type, data) {
+ var evt = createEvent(type,data);
+ if (typeof windowEventHandlers[type] != 'undefined') {
+ setTimeout(function() {
+ windowEventHandlers[type].fire(evt);
+ }, 0);
+ } else {
+ window.dispatchEvent(evt);
+ }
+ },
+
+ /**
+ * Plugin callback mechanism.
+ */
+ // Randomize the starting callbackId to avoid collisions after refreshing or navigating.
+ // This way, it's very unlikely that any new callback would get the same callbackId as an old callback.
+ callbackId: Math.floor(Math.random() * 2000000000),
+ callbacks: {},
+ callbackStatus: {
+ NO_RESULT: 0,
+ OK: 1,
+ CLASS_NOT_FOUND_EXCEPTION: 2,
+ ILLEGAL_ACCESS_EXCEPTION: 3,
+ INSTANTIATION_EXCEPTION: 4,
+ MALFORMED_URL_EXCEPTION: 5,
+ IO_EXCEPTION: 6,
+ INVALID_ACTION: 7,
+ JSON_EXCEPTION: 8,
+ ERROR: 9
+ },
+
+ /**
+ * Called by native code when returning successful result from an action.
+ */
+ callbackSuccess: function(callbackId, args) {
+ try {
+ cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback);
+ } catch (e) {
+ console.log("Error in error callback: " + callbackId + " = "+e);
+ }
+ },
+
+ /**
+ * Called by native code when returning error result from an action.
+ */
+ callbackError: function(callbackId, args) {
+ // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative.
+ // Derive success from status.
+ try {
+ cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback);
+ } catch (e) {
+ console.log("Error in error callback: " + callbackId + " = "+e);
+ }
+ },
+
+ /**
+ * Called by native code when returning the result from an action.
+ */
+ callbackFromNative: function(callbackId, success, status, args, keepCallback) {
+ var callback = cordova.callbacks[callbackId];
+ if (callback) {
+ if (success && status == cordova.callbackStatus.OK) {
+ callback.success && callback.success.apply(null, args);
+ } else if (!success) {
+ callback.fail && callback.fail.apply(null, args);
+ }
+
+ // Clear callback if not expecting any more results
+ if (!keepCallback) {
+ delete cordova.callbacks[callbackId];
+ }
+ }
+ },
+ addConstructor: function(func) {
+ channel.onCordovaReady.subscribe(function() {
+ try {
+ func();
+ } catch(e) {
+ console.log("Failed to run constructor: " + e);
+ }
+ });
+ }
+};
+
+// Register pause, resume and deviceready channels as events on document.
+channel.onPause = cordova.addDocumentEventHandler('pause');
+channel.onResume = cordova.addDocumentEventHandler('resume');
+channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready');
+
+module.exports = cordova;
+
+});
+
+// file: lib\common\argscheck.js
+define("cordova/argscheck", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+var utils = require('cordova/utils');
+
+var moduleExports = module.exports;
+
+var typeMap = {
+ 'A': 'Array',
+ 'D': 'Date',
+ 'N': 'Number',
+ 'S': 'String',
+ 'F': 'Function',
+ 'O': 'Object'
+};
+
+function extractParamName(callee, argIndex) {
+ return (/.*?\((.*?)\)/).exec(callee)[1].split(', ')[argIndex];
+}
+
+function checkArgs(spec, functionName, args, opt_callee) {
+ if (!moduleExports.enableChecks) {
+ return;
+ }
+ var errMsg = null;
+ var typeName;
+ for (var i = 0; i < spec.length; ++i) {
+ var c = spec.charAt(i),
+ cUpper = c.toUpperCase(),
+ arg = args[i];
+ // Asterix means allow anything.
+ if (c == '*') {
+ continue;
+ }
+ typeName = utils.typeName(arg);
+ if ((arg === null || arg === undefined) && c == cUpper) {
+ continue;
+ }
+ if (typeName != typeMap[cUpper]) {
+ errMsg = 'Expected ' + typeMap[cUpper];
+ break;
+ }
+ }
+ if (errMsg) {
+ errMsg += ', but got ' + typeName + '.';
+ errMsg = 'Wrong type for parameter "' + extractParamName(opt_callee || args.callee, i) + '" of ' + functionName + ': ' + errMsg;
+ // Don't log when running jake test.
+ if (typeof jasmine == 'undefined') {
+ console.error(errMsg);
+ }
+ throw TypeError(errMsg);
+ }
+}
+
+function getValue(value, defaultValue) {
+ return value === undefined ? defaultValue : value;
+}
+
+moduleExports.checkArgs = checkArgs;
+moduleExports.getValue = getValue;
+moduleExports.enableChecks = true;
+
+
+});
+
+// file: lib\common\builder.js
+define("cordova/builder", function(require, exports, module) {
+
+var utils = require('cordova/utils');
+
+function each(objects, func, context) {
+ for (var prop in objects) {
+ if (objects.hasOwnProperty(prop)) {
+ func.apply(context, [objects[prop], prop]);
+ }
+ }
+}
+
+function clobber(obj, key, value) {
+ exports.replaceHookForTesting(obj, key);
+ obj[key] = value;
+ // Getters can only be overridden by getters.
+ if (obj[key] !== value) {
+ utils.defineGetter(obj, key, function() {
+ return value;
+ });
+ }
+}
+
+function assignOrWrapInDeprecateGetter(obj, key, value, message) {
+ if (message) {
+ utils.defineGetter(obj, key, function() {
+ console.log(message);
+ delete obj[key];
+ clobber(obj, key, value);
+ return value;
+ });
+ } else {
+ clobber(obj, key, value);
+ }
+}
+
+function include(parent, objects, clobber, merge) {
+ each(objects, function (obj, key) {
+ try {
+ var result = obj.path ? require(obj.path) : {};
+
+ if (clobber) {
+ // Clobber if it doesn't exist.
+ if (typeof parent[key] === 'undefined') {
+ assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+ } else if (typeof obj.path !== 'undefined') {
+ // If merging, merge properties onto parent, otherwise, clobber.
+ if (merge) {
+ recursiveMerge(parent[key], result);
+ } else {
+ assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+ }
+ }
+ result = parent[key];
+ } else {
+ // Overwrite if not currently defined.
+ if (typeof parent[key] == 'undefined') {
+ assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+ } else {
+ // Set result to what already exists, so we can build children into it if they exist.
+ result = parent[key];
+ }
+ }
+
+ if (obj.children) {
+ include(result, obj.children, clobber, merge);
+ }
+ } catch(e) {
+ utils.alert('Exception building cordova JS globals: ' + e + ' for key "' + key + '"');
+ }
+ });
+}
+
+/**
+ * Merge properties from one object onto another recursively. Properties from
+ * the src object will overwrite existing target property.
+ *
+ * @param target Object to merge properties into.
+ * @param src Object to merge properties from.
+ */
+function recursiveMerge(target, src) {
+ for (var prop in src) {
+ if (src.hasOwnProperty(prop)) {
+ if (target.prototype && target.prototype.constructor === target) {
+ // If the target object is a constructor override off prototype.
+ clobber(target.prototype, prop, src[prop]);
+ } else {
+ if (typeof src[prop] === 'object' && typeof target[prop] === 'object') {
+ recursiveMerge(target[prop], src[prop]);
+ } else {
+ clobber(target, prop, src[prop]);
+ }
+ }
+ }
+ }
+}
+
+exports.buildIntoButDoNotClobber = function(objects, target) {
+ include(target, objects, false, false);
+};
+exports.buildIntoAndClobber = function(objects, target) {
+ include(target, objects, true, false);
+};
+exports.buildIntoAndMerge = function(objects, target) {
+ include(target, objects, true, true);
+};
+exports.recursiveMerge = recursiveMerge;
+exports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter;
+exports.replaceHookForTesting = function() {};
+
+});
+
+// file: lib\common\channel.js
+define("cordova/channel", function(require, exports, module) {
+
+var utils = require('cordova/utils'),
+ nextGuid = 1;
+
+/**
+ * Custom pub-sub "channel" that can have functions subscribed to it
+ * This object is used to define and control firing of events for
+ * cordova initialization, as well as for custom events thereafter.
+ *
+ * The order of events during page load and Cordova startup is as follows:
+ *
+ * onDOMContentLoaded* Internal event that is received when the web page is loaded and parsed.
+ * onNativeReady* Internal event that indicates the Cordova native side is ready.
+ * onCordovaReady* Internal event fired when all Cordova JavaScript objects have been created.
+ * onCordovaInfoReady* Internal event fired when device properties are available.
+ * onCordovaConnectionReady* Internal event fired when the connection property has been set.
+ * onDeviceReady* User event fired to indicate that Cordova is ready
+ * onResume User event fired to indicate a start/resume lifecycle event
+ * onPause User event fired to indicate a pause lifecycle event
+ * onDestroy* Internal event fired when app is being destroyed (User should use window.onunload event, not this one).
+ *
+ * The events marked with an * are sticky. Once they have fired, they will stay in the fired state.
+ * All listeners that subscribe after the event is fired will be executed right away.
+ *
+ * The only Cordova events that user code should register for are:
+ * deviceready Cordova native code is initialized and Cordova APIs can be called from JavaScript
+ * pause App has moved to background
+ * resume App has returned to foreground
+ *
+ * Listeners can be registered as:
+ * document.addEventListener("deviceready", myDeviceReadyListener, false);
+ * document.addEventListener("resume", myResumeListener, false);
+ * document.addEventListener("pause", myPauseListener, false);
+ *
+ * The DOM lifecycle events should be used for saving and restoring state
+ * window.onload
+ * window.onunload
+ *
+ */
+
+/**
+ * Channel
+ * @constructor
+ * @param type String the channel name
+ */
+var Channel = function(type, sticky) {
+ this.type = type;
+ // Map of guid -> function.
+ this.handlers = {};
+ // 0 = Non-sticky, 1 = Sticky non-fired, 2 = Sticky fired.
+ this.state = sticky ? 1 : 0;
+ // Used in sticky mode to remember args passed to fire().
+ this.fireArgs = null;
+ // Used by onHasSubscribersChange to know if there are any listeners.
+ this.numHandlers = 0;
+ // Function that is called when the first listener is subscribed, or when
+ // the last listener is unsubscribed.
+ this.onHasSubscribersChange = null;
+},
+ channel = {
+ /**
+ * Calls the provided function only after all of the channels specified
+ * have been fired. All channels must be sticky channels.
+ */
+ join: function(h, c) {
+ var len = c.length,
+ i = len,
+ f = function() {
+ if (!(--i)) h();
+ };
+ for (var j=0; j<len; j++) {
+ if (c[j].state === 0) {
+ throw Error('Can only use join with sticky channels.');
+ }
+ c[j].subscribe(f);
+ }
+ if (!len) h();
+ },
+ create: function(type) {
+ return channel[type] = new Channel(type, false);
+ },
+ createSticky: function(type) {
+ return channel[type] = new Channel(type, true);
+ },
+
+ /**
+ * cordova Channels that must fire before "deviceready" is fired.
+ */
+ deviceReadyChannelsArray: [],
+ deviceReadyChannelsMap: {},
+
+ /**
+ * Indicate that a feature needs to be initialized before it is ready to be used.
+ * This holds up Cordova's "deviceready" event until the feature has been initialized
+ * and Cordova.initComplete(feature) is called.
+ *
+ * @param feature {String} The unique feature name
+ */
+ waitForInitialization: function(feature) {
+ if (feature) {
+ var c = channel[feature] || this.createSticky(feature);
+ this.deviceReadyChannelsMap[feature] = c;
+ this.deviceReadyChannelsArray.push(c);
+ }
+ },
+
+ /**
+ * Indicate that initialization code has completed and the feature is ready to be used.
+ *
+ * @param feature {String} The unique feature name
+ */
+ initializationComplete: function(feature) {
+ var c = this.deviceReadyChannelsMap[feature];
+ if (c) {
+ c.fire();
+ }
+ }
+ };
+
+function forceFunction(f) {
+ if (typeof f != 'function') throw "Function required as first argument!";
+}
+
+/**
+ * Subscribes the given function to the channel. Any time that
+ * Channel.fire is called so too will the function.
+ * Optionally specify an execution context for the function
+ * and a guid that can be used to stop subscribing to the channel.
+ * Returns the guid.
+ */
+Channel.prototype.subscribe = function(f, c) {
+ // need a function to call
+ forceFunction(f);
+ if (this.state == 2) {
+ f.apply(c || this, this.fireArgs);
+ return;
+ }
+
+ var func = f,
+ guid = f.observer_guid;
+ if (typeof c == "object") { func = utils.close(c, f); }
+
+ if (!guid) {
+ // first time any channel has seen this subscriber
+ guid = '' + nextGuid++;
+ }
+ func.observer_guid = guid;
+ f.observer_guid = guid;
+
+ // Don't add the same handler more than once.
+ if (!this.handlers[guid]) {
+ this.handlers[guid] = func;
+ this.numHandlers++;
+ if (this.numHandlers == 1) {
+ this.onHasSubscribersChange && this.onHasSubscribersChange();
+ }
+ }
+};
+
+/**
+ * Unsubscribes the function with the given guid from the channel.
+ */
+Channel.prototype.unsubscribe = function(f) {
+ // need a function to unsubscribe
+ forceFunction(f);
+
+ var guid = f.observer_guid,
+ handler = this.handlers[guid];
+ if (handler) {
+ delete this.handlers[guid];
+ this.numHandlers--;
+ if (this.numHandlers === 0) {
+ this.onHasSubscribersChange && this.onHasSubscribersChange();
+ }
+ }
+};
+
+/**
+ * Calls all functions subscribed to this channel.
+ */
+Channel.prototype.fire = function(e) {
+ var fail = false,
+ fireArgs = Array.prototype.slice.call(arguments);
+ // Apply stickiness.
+ if (this.state == 1) {
+ this.state = 2;
+ this.fireArgs = fireArgs;
+ }
+ if (this.numHandlers) {
+ // Copy the values first so that it is safe to modify it from within
+ // callbacks.
+ var toCall = [];
+ for (var item in this.handlers) {
+ toCall.push(this.handlers[item]);
+ }
+ for (var i = 0; i < toCall.length; ++i) {
+ toCall[i].apply(this, fireArgs);
+ }
+ if (this.state == 2 && this.numHandlers) {
+ this.numHandlers = 0;
+ this.handlers = {};
+ this.onHasSubscribersChange && this.onHasSubscribersChange();
+ }
+ }
+};
+
+
+// defining them here so they are ready super fast!
+// DOM event that is received when the web page is loaded and parsed.
+channel.createSticky('onDOMContentLoaded');
+
+// Event to indicate the Cordova native side is ready.
+channel.createSticky('onNativeReady');
+
+// Event to indicate that all Cordova JavaScript objects have been created
+// and it's time to run plugin constructors.
+channel.createSticky('onCordovaReady');
+
+// Event to indicate that device properties are available
+channel.createSticky('onCordovaInfoReady');
+
+// Event to indicate that the connection property has been set.
+channel.createSticky('onCordovaConnectionReady');
+
+// Event to indicate that all automatically loaded JS plugins are loaded and ready.
+// This is used in conjunction with the automatic plugin JS loading CLI prototype.
+channel.createSticky('onPluginsReady');
+
+// Event to indicate that Cordova is ready
+channel.createSticky('onDeviceReady');
+
+// Event to indicate a resume lifecycle event
+channel.create('onResume');
+
+// Event to indicate a pause lifecycle event
+channel.create('onPause');
+
+// Event to indicate a destroy lifecycle event
+channel.createSticky('onDestroy');
+
+// Channels that must fire before "deviceready" is fired.
+channel.waitForInitialization('onCordovaReady');
+channel.waitForInitialization('onCordovaConnectionReady');
+
+module.exports = channel;
+
+});
+
+// file: lib\common\commandProxy.js
+define("cordova/commandProxy", function(require, exports, module) {
+
+
+// internal map of proxy function
+var CommandProxyMap = {};
+
+module.exports = {
+
+ // example: cordova.commandProxy.add("Accelerometer",{getCurrentAcceleration: function(successCallback, errorCallback, options) {...},...);
+ add:function(id,proxyObj) {
+ console.log("adding proxy for " + id);
+ CommandProxyMap[id] = proxyObj;
+ return proxyObj;
+ },
+
+ // cordova.commandProxy.remove("Accelerometer");
+ remove:function(id) {
+ var proxy = CommandProxyMap[id];
+ delete CommandProxyMap[id];
+ CommandProxyMap[id] = null;
+ return proxy;
+ },
+
+ get:function(service,action) {
+ return ( CommandProxyMap[service] ? CommandProxyMap[service][action] : null );
+ }
+};
+});
+
+// file: lib\windowsphone\exec.js
+define("cordova/exec", function(require, exports, module) {
+
+var cordova = require('cordova');
+
+/**
+ * Execute a cordova command. It is up to the native side whether this action
+ * is synchronous or asynchronous. The native side can return:
+ * Synchronous: PluginResult object as a JSON string
+ * Asynchronous: Empty string ""
+ * If async, the native side will cordova.callbackSuccess or cordova.callbackError,
+ * depending upon the result of the action.
+ *
+ * @param {Function} success The success callback
+ * @param {Function} fail The fail callback
+ * @param {String} service The name of the service to use
+ * @param {String} action Action to be run in cordova
+ * @param {String[]} [args] Zero or more arguments to pass to the method
+
+ */
+
+module.exports = function(success, fail, service, action, args) {
+
+ var callbackId = service + cordova.callbackId++;
+ if (typeof success == "function" || typeof fail == "function") {
+ cordova.callbacks[callbackId] = {success:success, fail:fail};
+ }
+ // generate a new command string, ex. DebugConsole/log/DebugConsole23/["wtf dude?"]
+ for(var n = 0; n < args.length; n++)
+ {
+ if(typeof args[n] !== "string")
+ {
+ args[n] = JSON.stringify(args[n]);
+ }
+ }
+ var command = service + "/" + action + "/" + callbackId + "/" + JSON.stringify(args);
+ // pass it on to Notify
+ try {
+ if(window.external) {
+ window.external.Notify(command);
+ }
+ else {
+ console.log("window.external not available :: command=" + command);
+ }
+ }
+ catch(e) {
+ console.log("Exception calling native with command :: " + command + " :: exception=" + e);
+ }
+};
+
+
+});
+
+// file: lib\common\modulemapper.js
+define("cordova/modulemapper", function(require, exports, module) {
+
+var builder = require('cordova/builder'),
+ moduleMap = define.moduleMap,
+ symbolList,
+ deprecationMap;
+
+exports.reset = function() {
+ symbolList = [];
+ deprecationMap = {};
+};
+
+function addEntry(strategy, moduleName, symbolPath, opt_deprecationMessage) {
+ if (!(moduleName in moduleMap)) {
+ throw new Error('Module ' + moduleName + ' does not exist.');
+ }
+ symbolList.push(strategy, moduleName, symbolPath);
+ if (opt_deprecationMessage) {
+ deprecationMap[symbolPath] = opt_deprecationMessage;
+ }
+}
+
+// Note: Android 2.3 does have Function.bind().
+exports.clobbers = function(moduleName, symbolPath, opt_deprecationMessage) {
+ addEntry('c', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+exports.merges = function(moduleName, symbolPath, opt_deprecationMessage) {
+ addEntry('m', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+exports.defaults = function(moduleName, symbolPath, opt_deprecationMessage) {
+ addEntry('d', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+function prepareNamespace(symbolPath, context) {
+ if (!symbolPath) {
+ return context;
+ }
+ var parts = symbolPath.split('.');
+ var cur = context;
+ for (var i = 0, part; part = parts[i]; ++i) {
+ cur = cur[part] = cur[part] || {};
+ }
+ return cur;
+}
+
+exports.mapModules = function(context) {
+ var origSymbols = {};
+ context.CDV_origSymbols = origSymbols;
+ for (var i = 0, len = symbolList.length; i < len; i += 3) {
+ var strategy = symbolList[i];
+ var moduleName = symbolList[i + 1];
+ var symbolPath = symbolList[i + 2];
+ var lastDot = symbolPath.lastIndexOf('.');
+ var namespace = symbolPath.substr(0, lastDot);
+ var lastName = symbolPath.substr(lastDot + 1);
+
+ var module = require(moduleName);
+ var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null;
+ var parentObj = prepareNamespace(namespace, context);
+ var target = parentObj[lastName];
+
+ if (strategy == 'm' && target) {
+ builder.recursiveMerge(target, module);
+ } else if ((strategy == 'd' && !target) || (strategy != 'd')) {
+ if (!(symbolPath in origSymbols)) {
+ origSymbols[symbolPath] = target;
+ }
+ builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg);
+ }
+ }
+};
+
+exports.getOriginalSymbol = function(context, symbolPath) {
+ var origSymbols = context.CDV_origSymbols;
+ if (origSymbols && (symbolPath in origSymbols)) {
+ return origSymbols[symbolPath];
+ }
+ var parts = symbolPath.split('.');
+ var obj = context;
+ for (var i = 0; i < parts.length; ++i) {
+ obj = obj && obj[parts[i]];
+ }
+ return obj;
+};
+
+exports.loadMatchingModules = function(matchingRegExp) {
+ for (var k in moduleMap) {
+ if (matchingRegExp.exec(k)) {
+ require(k);
+ }
+ }
+};
+
+exports.reset();
+
+
+});
+
+// file: lib\windowsphone\platform.js
+define("cordova/platform", function(require, exports, module) {
+
+var cordova = require('cordova'),
+ exec = require('cordova/exec');
+
+// specifically require the following patches :
+
+// localStorage+SessionStorage APIs
+require("cordova/plugin/windowsphone/DOMStorage");
+
+// Fix XHR calls to local file-system
+require("cordova/plugin/windowsphone/XHRPatch");
+
+
+module.exports = {
+ id: "windowsphone",
+ initialize:function() {
+ var modulemapper = require('cordova/modulemapper');
+
+ modulemapper.loadMatchingModules(/cordova.*\/symbols$/);
+ modulemapper.mapModules(window);
+
+ window.alert = window.alert || require("cordova/plugin/notification").alert;
+ window.confirm = window.confirm || require("cordova/plugin/notification").confirm;
+
+ // Inject a listener for the backbutton, and tell native to override the flag (true/false) when we have 1 or more, or 0, listeners
+ var backButtonChannel = cordova.addDocumentEventHandler('backbutton');
+ backButtonChannel.onHasSubscribersChange = function() {
+ exec(null, null, "CoreEvents", "overridebackbutton", [this.numHandlers == 1]);
+ };
+ },
+ clobbers: {
+ CordovaCommandResult: {
+ path:"cordova/plugin/windowsphone/CordovaCommandResult"
+ },
+ navigator: {
+ children: {
+ console: {
+ path: "cordova/plugin/windowsphone/console"
+
+ }
+ }
+ },
+ console:{
+ path: "cordova/plugin/windowsphone/console"
+ },
+ FileTransfer: {
+ path: 'cordova/plugin/windowsphone/FileTransfer'
+ },
+ open : {
+ path: 'cordova/plugin/InAppBrowser'
+ }
+ }
+};
+
+});
+
+// file: lib\common\plugin\Acceleration.js
+define("cordova/plugin/Acceleration", function(require, exports, module) {
+
+var Acceleration = function(x, y, z, timestamp) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.timestamp = timestamp || (new Date()).getTime();
+};
+
+module.exports = Acceleration;
+
+});
+
+// file: lib\common\plugin\Camera.js
+define("cordova/plugin/Camera", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ exec = require('cordova/exec'),
+ Camera = require('cordova/plugin/CameraConstants'),
+ CameraPopoverHandle = require('cordova/plugin/CameraPopoverHandle');
+
+var cameraExport = {};
+
+// Tack on the Camera Constants to the base camera plugin.
+for (var key in Camera) {
+ cameraExport[key] = Camera[key];
+}
+
+/**
+ * Gets a picture from source defined by "options.sourceType", and returns the
+ * image as defined by the "options.destinationType" option.
+
+ * The defaults are sourceType=CAMERA and destinationType=FILE_URI.
+ *
+ * @param {Function} successCallback
+ * @param {Function} errorCallback
+ * @param {Object} options
+ */
+cameraExport.getPicture = function(successCallback, errorCallback, options) {
+ argscheck.checkArgs('fFO', 'Camera.getPicture', arguments);
+ options = options || {};
+ var getValue = argscheck.getValue;
+
+ var quality = getValue(options.quality, 50);
+ var destinationType = getValue(options.destinationType, Camera.DestinationType.FILE_URI);
+ var sourceType = getValue(options.sourceType, Camera.PictureSourceType.CAMERA);
+ var targetWidth = getValue(options.targetWidth, -1);
+ var targetHeight = getValue(options.targetHeight, -1);
+ var encodingType = getValue(options.encodingType, Camera.EncodingType.JPEG);
+ var mediaType = getValue(options.mediaType, Camera.MediaType.PICTURE);
+ var allowEdit = !!options.allowEdit;
+ var correctOrientation = !!options.correctOrientation;
+ var saveToPhotoAlbum = !!options.saveToPhotoAlbum;
+ var popoverOptions = getValue(options.popoverOptions, null);
+
+ var args = [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType,
+ mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions];
+
+ exec(successCallback, errorCallback, "Camera", "takePicture", args);
+ return new CameraPopoverHandle();
+};
+
+cameraExport.cleanup = function(successCallback, errorCallback) {
+ exec(successCallback, errorCallback, "Camera", "cleanup", []);
+};
+
+module.exports = cameraExport;
+
+});
+
+// file: lib\common\plugin\CameraConstants.js
+define("cordova/plugin/CameraConstants", function(require, exports, module) {
+
+module.exports = {
+ DestinationType:{
+ DATA_URL: 0, // Return base64 encoded string
+ FILE_URI: 1, // Return file uri (content://media/external/images/media/2 for Android)
+ NATIVE_URI: 2 // Return native uri (eg. asset-library://... for iOS)
+ },
+ EncodingType:{
+ JPEG: 0, // Return JPEG encoded image
+ PNG: 1 // Return PNG encoded image
+ },
+ MediaType:{
+ PICTURE: 0, // allow selection of still pictures only. DEFAULT. Will return format specified via DestinationType
+ VIDEO: 1, // allow selection of video only, ONLY RETURNS URL
+ ALLMEDIA : 2 // allow selection from all media types
+ },
+ PictureSourceType:{
+ PHOTOLIBRARY : 0, // Choose image from picture library (same as SAVEDPHOTOALBUM for Android)
+ CAMERA : 1, // Take picture from camera
+ SAVEDPHOTOALBUM : 2 // Choose image from picture library (same as PHOTOLIBRARY for Android)
+ },
+ PopoverArrowDirection:{
+ ARROW_UP : 1, // matches iOS UIPopoverArrowDirection constants to specify arrow location on popover
+ ARROW_DOWN : 2,
+ ARROW_LEFT : 4,
+ ARROW_RIGHT : 8,
+ ARROW_ANY : 15
+ }
+};
+
+});
+
+// file: lib\common\plugin\CameraPopoverHandle.js
+define("cordova/plugin/CameraPopoverHandle", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+
+/**
+ * A handle to an image picker popover.
+ */
+var CameraPopoverHandle = function() {
+ this.setPosition = function(popoverOptions) {
+ console.log('CameraPopoverHandle.setPosition is only supported on iOS.');
+ };
+};
+
+module.exports = CameraPopoverHandle;
+
+});
+
+// file: lib\common\plugin\CameraPopoverOptions.js
+define("cordova/plugin/CameraPopoverOptions", function(require, exports, module) {
+
+var Camera = require('cordova/plugin/CameraConstants');
+
+/**
+ * Encapsulates options for iOS Popover image picker
+ */
+var CameraPopoverOptions = function(x,y,width,height,arrowDir){
+ // information of rectangle that popover should be anchored to
+ this.x = x || 0;
+ this.y = y || 32;
+ this.width = width || 320;
+ this.height = height || 480;
+ // The direction of the popover arrow
+ this.arrowDir = arrowDir || Camera.PopoverArrowDirection.ARROW_ANY;
+};
+
+module.exports = CameraPopoverOptions;
+
+});
+
+// file: lib\common\plugin\CaptureAudioOptions.js
+define("cordova/plugin/CaptureAudioOptions", function(require, exports, module) {
+
+/**
+ * Encapsulates all audio capture operation configuration options.
+ */
+var CaptureAudioOptions = function(){
+ // Upper limit of sound clips user can record. Value must be equal or greater than 1.
+ this.limit = 1;
+ // Maximum duration of a single sound clip in seconds.
+ this.duration = 0;
+ // The selected audio mode. Must match with one of the elements in supportedAudioModes array.
+ this.mode = null;
+};
+
+module.exports = CaptureAudioOptions;
+
+});
+
+// file: lib\common\plugin\CaptureError.js
+define("cordova/plugin/CaptureError", function(require, exports, module) {
+
+/**
+ * The CaptureError interface encapsulates all errors in the Capture API.
+ */
+var CaptureError = function(c) {
+ this.code = c || null;
+};
+
+// Camera or microphone failed to capture image or sound.
+CaptureError.CAPTURE_INTERNAL_ERR = 0;
+// Camera application or audio capture application is currently serving other capture request.
+CaptureError.CAPTURE_APPLICATION_BUSY = 1;
+// Invalid use of the API (e.g. limit parameter has value less than one).
+CaptureError.CAPTURE_INVALID_ARGUMENT = 2;
+// User exited camera application or audio capture application before capturing anything.
+CaptureError.CAPTURE_NO_MEDIA_FILES = 3;
+// The requested capture operation is not supported.
+CaptureError.CAPTURE_NOT_SUPPORTED = 20;
+
+module.exports = CaptureError;
+
+});
+
+// file: lib\common\plugin\CaptureImageOptions.js
+define("cordova/plugin/CaptureImageOptions", function(require, exports, module) {
+
+/**
+ * Encapsulates all image capture operation configuration options.
+ */
+var CaptureImageOptions = function(){
+ // Upper limit of images user can take. Value must be equal or greater than 1.
+ this.limit = 1;
+ // The selected image mode. Must match with one of the elements in supportedImageModes array.
+ this.mode = null;
+};
+
+module.exports = CaptureImageOptions;
+
+});
+
+// file: lib\common\plugin\CaptureVideoOptions.js
+define("cordova/plugin/CaptureVideoOptions", function(require, exports, module) {
+
+/**
+ * Encapsulates all video capture operation configuration options.
+ */
+var CaptureVideoOptions = function(){
+ // Upper limit of videos user can record. Value must be equal or greater than 1.
+ this.limit = 1;
+ // Maximum duration of a single video clip in seconds.
+ this.duration = 0;
+ // The selected video mode. Must match with one of the elements in supportedVideoModes array.
+ this.mode = null;
+};
+
+module.exports = CaptureVideoOptions;
+
+});
+
+// file: lib\common\plugin\CompassError.js
+define("cordova/plugin/CompassError", function(require, exports, module) {
+
+/**
+ * CompassError.
+ * An error code assigned by an implementation when an error has occurred
+ * @constructor
+ */
+var CompassError = function(err) {
+ this.code = (err !== undefined ? err : null);
+};
+
+CompassError.COMPASS_INTERNAL_ERR = 0;
+CompassError.COMPASS_NOT_SUPPORTED = 20;
+
+module.exports = CompassError;
+
+});
+
+// file: lib\common\plugin\CompassHeading.js
+define("cordova/plugin/CompassHeading", function(require, exports, module) {
+
+var CompassHeading = function(magneticHeading, trueHeading, headingAccuracy, timestamp) {
+ this.magneticHeading = magneticHeading;
+ this.trueHeading = trueHeading;
+ this.headingAccuracy = headingAccuracy;
+ this.timestamp = timestamp || new Date().getTime();
+};
+
+module.exports = CompassHeading;
+
+});
+
+// file: lib\common\plugin\ConfigurationData.js
+define("cordova/plugin/ConfigurationData", function(require, exports, module) {
+
+/**
+ * Encapsulates a set of parameters that the capture device supports.
+ */
+function ConfigurationData() {
+ // The ASCII-encoded string in lower case representing the media type.
+ this.type = null;
+ // The height attribute represents height of the image or video in pixels.
+ // In the case of a sound clip this attribute has value 0.
+ this.height = 0;
+ // The width attribute represents width of the image or video in pixels.
+ // In the case of a sound clip this attribute has value 0
+ this.width = 0;
+}
+
+module.exports = ConfigurationData;
+
+});
+
+// file: lib\common\plugin\Connection.js
+define("cordova/plugin/Connection", function(require, exports, module) {
+
+/**
+ * Network status
+ */
+module.exports = {
+ UNKNOWN: "unknown",
+ ETHERNET: "ethernet",
+ WIFI: "wifi",
+ CELL_2G: "2g",
+ CELL_3G: "3g",
+ CELL_4G: "4g",
+ CELL:"cellular",
+ NONE: "none"
+};
+
+});
+
+// file: lib\common\plugin\Contact.js
+define("cordova/plugin/Contact", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ exec = require('cordova/exec'),
+ ContactError = require('cordova/plugin/ContactError'),
+ utils = require('cordova/utils');
+
+/**
+* Converts primitives into Complex Object
+* Currently only used for Date fields
+*/
+function convertIn(contact) {
+ var value = contact.birthday;
+ try {
+ contact.birthday = new Date(parseFloat(value));
+ } catch (exception){
+ console.log("Cordova Contact convertIn error: exception creating date.");
+ }
+ return contact;
+}
+
+/**
+* Converts Complex objects into primitives
+* Only conversion at present is for Dates.
+**/
+
+function convertOut(contact) {
+ var value = contact.birthday;
+ if (value !== null) {
+ // try to make it a Date object if it is not already
+ if (!utils.isDate(value)){
+ try {
+ value = new Date(value);
+ } catch(exception){
+ value = null;
+ }
+ }
+ if (utils.isDate(value)){
+ value = value.valueOf(); // convert to milliseconds
+ }
+ contact.birthday = value;
+ }
+ return contact;
+}
+
+/**
+* Contains information about a single contact.
+* @constructor
+* @param {DOMString} id unique identifier
+* @param {DOMString} displayName
+* @param {ContactName} name
+* @param {DOMString} nickname
+* @param {Array.<ContactField>} phoneNumbers array of phone numbers
+* @param {Array.<ContactField>} emails array of email addresses
+* @param {Array.<ContactAddress>} addresses array of addresses
+* @param {Array.<ContactField>} ims instant messaging user ids
+* @param {Array.<ContactOrganization>} organizations
+* @param {DOMString} birthday contact's birthday
+* @param {DOMString} note user notes about contact
+* @param {Array.<ContactField>} photos
+* @param {Array.<ContactField>} categories
+* @param {Array.<ContactField>} urls contact's web sites
+*/
+var Contact = function (id, displayName, name, nickname, phoneNumbers, emails, addresses,
+ ims, organizations, birthday, note, photos, categories, urls) {
+ this.id = id || null;
+ this.rawId = null;
+ this.displayName = displayName || null;
+ this.name = name || null; // ContactName
+ this.nickname = nickname || null;
+ this.phoneNumbers = phoneNumbers || null; // ContactField[]
+ this.emails = emails || null; // ContactField[]
+ this.addresses = addresses || null; // ContactAddress[]
+ this.ims = ims || null; // ContactField[]
+ this.organizations = organizations || null; // ContactOrganization[]
+ this.birthday = birthday || null;
+ this.note = note || null;
+ this.photos = photos || null; // ContactField[]
+ this.categories = categories || null; // ContactField[]
+ this.urls = urls || null; // ContactField[]
+};
+
+/**
+* Removes contact from device storage.
+* @param successCB success callback
+* @param errorCB error callback
+*/
+Contact.prototype.remove = function(successCB, errorCB) {
+ argscheck.checkArgs('FF', 'Contact.remove', arguments);
+ var fail = errorCB && function(code) {
+ errorCB(new ContactError(code));
+ };
+ if (this.id === null) {
+ fail(ContactError.UNKNOWN_ERROR);
+ }
+ else {
+ exec(successCB, fail, "Contacts", "remove", [this.id]);
+ }
+};
+
+/**
+* Creates a deep copy of this Contact.
+* With the contact ID set to null.
+* @return copy of this Contact
+*/
+Contact.prototype.clone = function() {
+ var clonedContact = utils.clone(this);
+ clonedContact.id = null;
+ clonedContact.rawId = null;
+
+ function nullIds(arr) {
+ if (arr) {
+ for (var i = 0; i < arr.length; ++i) {
+ arr[i].id = null;
+ }
+ }
+ }
+
+ // Loop through and clear out any id's in phones, emails, etc.
+ nullIds(clonedContact.phoneNumbers);
+ nullIds(clonedContact.emails);
+ nullIds(clonedContact.addresses);
+ nullIds(clonedContact.ims);
+ nullIds(clonedContact.organizations);
+ nullIds(clonedContact.categories);
+ nullIds(clonedContact.photos);
+ nullIds(clonedContact.urls);
+ return clonedContact;
+};
+
+/**
+* Persists contact to device storage.
+* @param successCB success callback
+* @param errorCB error callback
+*/
+Contact.prototype.save = function(successCB, errorCB) {
+ argscheck.checkArgs('FFO', 'Contact.save', arguments);
+ var fail = errorCB && function(code) {
+ errorCB(new ContactError(code));
+ };
+ var success = function(result) {
+ if (result) {
+ if (successCB) {
+ var fullContact = require('cordova/plugin/contacts').create(result);
+ successCB(convertIn(fullContact));
+ }
+ }
+ else {
+ // no Entry object returned
+ fail(ContactError.UNKNOWN_ERROR);
+ }
+ };
+ var dupContact = convertOut(utils.clone(this));
+ exec(success, fail, "Contacts", "save", [dupContact]);
+};
+
+
+module.exports = Contact;
+
+});
+
+// file: lib\common\plugin\ContactAddress.js
+define("cordova/plugin/ContactAddress", function(require, exports, module) {
+
+/**
+* Contact address.
+* @constructor
+* @param {DOMString} id unique identifier, should only be set by native code
+* @param formatted // NOTE: not a W3C standard
+* @param streetAddress
+* @param locality
+* @param region
+* @param postalCode
+* @param country
+*/
+
+var ContactAddress = function(pref, type, formatted, streetAddress, locality, region, postalCode, country) {
+ this.id = null;
+ this.pref = (typeof pref != 'undefined' ? pref : false);
+ this.type = type || null;
+ this.formatted = formatted || null;
+ this.streetAddress = streetAddress || null;
+ this.locality = locality || null;
+ this.region = region || null;
+ this.postalCode = postalCode || null;
+ this.country = country || null;
+};
+
+module.exports = ContactAddress;
+
+});
+
+// file: lib\common\plugin\ContactError.js
+define("cordova/plugin/ContactError", function(require, exports, module) {
+
+/**
+ * ContactError.
+ * An error code assigned by an implementation when an error has occurred
+ * @constructor
+ */
+var ContactError = function(err) {
+ this.code = (typeof err != 'undefined' ? err : null);
+};
+
+/**
+ * Error codes
+ */
+ContactError.UNKNOWN_ERROR = 0;
+ContactError.INVALID_ARGUMENT_ERROR = 1;
+ContactError.TIMEOUT_ERROR = 2;
+ContactError.PENDING_OPERATION_ERROR = 3;
+ContactError.IO_ERROR = 4;
+ContactError.NOT_SUPPORTED_ERROR = 5;
+ContactError.PERMISSION_DENIED_ERROR = 20;
+
+module.exports = ContactError;
+
+});
+
+// file: lib\common\plugin\ContactField.js
+define("cordova/plugin/ContactField", function(require, exports, module) {
+
+/**
+* Generic contact field.
+* @constructor
+* @param {DOMString} id unique identifier, should only be set by native code // NOTE: not a W3C standard
+* @param type
+* @param value
+* @param pref
+*/
+var ContactField = function(type, value, pref) {
+ this.id = null;
+ this.type = (type && type.toString()) || null;
+ this.value = (value && value.toString()) || null;
+ this.pref = (typeof pref != 'undefined' ? pref : false);
+};
+
+module.exports = ContactField;
+
+});
+
+// file: lib\common\plugin\ContactFindOptions.js
+define("cordova/plugin/ContactFindOptions", function(require, exports, module) {
+
+/**
+ * ContactFindOptions.
+ * @constructor
+ * @param filter used to match contacts against
+ * @param multiple boolean used to determine if more than one contact should be returned
+ */
+
+var ContactFindOptions = function(filter, multiple) {
+ this.filter = filter || '';
+ this.multiple = (typeof multiple != 'undefined' ? multiple : false);
+};
+
+module.exports = ContactFindOptions;
+
+});
+
+// file: lib\common\plugin\ContactName.js
+define("cordova/plugin/ContactName", function(require, exports, module) {
+
+/**
+* Contact name.
+* @constructor
+* @param formatted // NOTE: not part of W3C standard
+* @param familyName
+* @param givenName
+* @param middle
+* @param prefix
+* @param suffix
+*/
+var ContactName = function(formatted, familyName, givenName, middle, prefix, suffix) {
+ this.formatted = formatted || null;
+ this.familyName = familyName || null;
+ this.givenName = givenName || null;
+ this.middleName = middle || null;
+ this.honorificPrefix = prefix || null;
+ this.honorificSuffix = suffix || null;
+};
+
+module.exports = ContactName;
+
+});
+
+// file: lib\common\plugin\ContactOrganization.js
+define("cordova/plugin/ContactOrganization", function(require, exports, module) {
+
+/**
+* Contact organization.
+* @constructor
+* @param {DOMString} id unique identifier, should only be set by native code // NOTE: not a W3C standard
+* @param name
+* @param dept
+* @param title
+* @param startDate
+* @param endDate
+* @param location
+* @param desc
+*/
+
+var ContactOrganization = function(pref, type, name, dept, title) {
+ this.id = null;
+ this.pref = (typeof pref != 'undefined' ? pref : false);
+ this.type = type || null;
+ this.name = name || null;
+ this.department = dept || null;
+ this.title = title || null;
+};
+
+module.exports = ContactOrganization;
+
+});
+
+// file: lib\common\plugin\Coordinates.js
+define("cordova/plugin/Coordinates", function(require, exports, module) {
+
+/**
+ * This class contains position information.
+ * @param {Object} lat
+ * @param {Object} lng
+ * @param {Object} alt
+ * @param {Object} acc
+ * @param {Object} head
+ * @param {Object} vel
+ * @param {Object} altacc
+ * @constructor
+ */
+var Coordinates = function(lat, lng, alt, acc, head, vel, altacc) {
+ /**
+ * The latitude of the position.
+ */
+ this.latitude = lat;
+ /**
+ * The longitude of the position,
+ */
+ this.longitude = lng;
+ /**
+ * The accuracy of the position.
+ */
+ this.accuracy = acc;
+ /**
+ * The altitude of the position.
+ */
+ this.altitude = (alt !== undefined ? alt : null);
+ /**
+ * The direction the device is moving at the position.
+ */
+ this.heading = (head !== undefined ? head : null);
+ /**
+ * The velocity with which the device is moving at the position.
+ */
+ this.speed = (vel !== undefined ? vel : null);
+
+ if (this.speed === 0 || this.speed === null) {
+ this.heading = NaN;
+ }
+
+ /**
+ * The altitude accuracy of the position.
+ */
+ this.altitudeAccuracy = (altacc !== undefined) ? altacc : null;
+};
+
+module.exports = Coordinates;
+
+});
+
+// file: lib\common\plugin\DirectoryEntry.js
+define("cordova/plugin/DirectoryEntry", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ utils = require('cordova/utils'),
+ exec = require('cordova/exec'),
+ Entry = require('cordova/plugin/Entry'),
+ FileError = require('cordova/plugin/FileError'),
+ DirectoryReader = require('cordova/plugin/DirectoryReader');
+
+/**
+ * An interface representing a directory on the file system.
+ *
+ * {boolean} isFile always false (readonly)
+ * {boolean} isDirectory always true (readonly)
+ * {DOMString} name of the directory, excluding the path leading to it (readonly)
+ * {DOMString} fullPath the absolute full path to the directory (readonly)
+ * TODO: implement this!!! {FileSystem} filesystem on which the directory resides (readonly)
+ */
+var DirectoryEntry = function(name, fullPath) {
+ DirectoryEntry.__super__.constructor.call(this, false, true, name, fullPath);
+};
+
+utils.extend(DirectoryEntry, Entry);
+
+/**
+ * Creates a new DirectoryReader to read entries from this directory
+ */
+DirectoryEntry.prototype.createReader = function() {
+ return new DirectoryReader(this.fullPath);
+};
+
+/**
+ * Creates or looks up a directory
+ *
+ * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a directory
+ * @param {Flags} options to create or exclusively create the directory
+ * @param {Function} successCallback is called with the new entry
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryEntry.prototype.getDirectory = function(path, options, successCallback, errorCallback) {
+ argscheck.checkArgs('sOFF', 'DirectoryEntry.getDirectory', arguments);
+ var win = successCallback && function(result) {
+ var entry = new DirectoryEntry(result.name, result.fullPath);
+ successCallback(entry);
+ };
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(win, fail, "File", "getDirectory", [this.fullPath, path, options]);
+};
+
+/**
+ * Deletes a directory and all of it's contents
+ *
+ * @param {Function} successCallback is called with no parameters
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryEntry.prototype.removeRecursively = function(successCallback, errorCallback) {
+ argscheck.checkArgs('FF', 'DirectoryEntry.removeRecursively', arguments);
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(successCallback, fail, "File", "removeRecursively", [this.fullPath]);
+};
+
+/**
+ * Creates or looks up a file
+ *
+ * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a file
+ * @param {Flags} options to create or exclusively create the file
+ * @param {Function} successCallback is called with the new entry
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryEntry.prototype.getFile = function(path, options, successCallback, errorCallback) {
+ argscheck.checkArgs('sOFF', 'DirectoryEntry.getFile', arguments);
+ var win = successCallback && function(result) {
+ var FileEntry = require('cordova/plugin/FileEntry');
+ var entry = new FileEntry(result.name, result.fullPath);
+ successCallback(entry);
+ };
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(win, fail, "File", "getFile", [this.fullPath, path, options]);
+};
+
+module.exports = DirectoryEntry;
+
+});
+
+// file: lib\common\plugin\DirectoryReader.js
+define("cordova/plugin/DirectoryReader", function(require, exports, module) {
+
+var exec = require('cordova/exec'),
+ FileError = require('cordova/plugin/FileError') ;
+
+/**
+ * An interface that lists the files and directories in a directory.
+ */
+function DirectoryReader(path) {
+ this.path = path || null;
+}
+
+/**
+ * Returns a list of entries from a directory.
+ *
+ * @param {Function} successCallback is called with a list of entries
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryReader.prototype.readEntries = function(successCallback, errorCallback) {
+ var win = typeof successCallback !== 'function' ? null : function(result) {
+ var retVal = [];
+ for (var i=0; i<result.length; i++) {
+ var entry = null;
+ if (result[i].isDirectory) {
+ entry = new (require('cordova/plugin/DirectoryEntry'))();
+ }
+ else if (result[i].isFile) {
+ entry = new (require('cordova/plugin/FileEntry'))();
+ }
+ entry.isDirectory = result[i].isDirectory;
+ entry.isFile = result[i].isFile;
+ entry.name = result[i].name;
+ entry.fullPath = result[i].fullPath;
+ retVal.push(entry);
+ }
+ successCallback(retVal);
+ };
+ var fail = typeof errorCallback !== 'function' ? null : function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(win, fail, "File", "readEntries", [this.path]);
+};
+
+module.exports = DirectoryReader;
+
+});
+
+// file: lib\common\plugin\Entry.js
+define("cordova/plugin/Entry", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ exec = require('cordova/exec'),
+ FileError = require('cordova/plugin/FileError'),
+ Metadata = require('cordova/plugin/Metadata');
+
+/**
+ * Represents a file or directory on the local file system.
+ *
+ * @param isFile
+ * {boolean} true if Entry is a file (readonly)
+ * @param isDirectory
+ * {boolean} true if Entry is a directory (readonly)
+ * @param name
+ * {DOMString} name of the file or directory, excluding the path
+ * leading to it (readonly)
+ * @param fullPath
+ * {DOMString} the absolute full path to the file or directory
+ * (readonly)
+ */
+function Entry(isFile, isDirectory, name, fullPath, fileSystem) {
+ this.isFile = !!isFile;
+ this.isDirectory = !!isDirectory;
+ this.name = name || '';
+ this.fullPath = fullPath || '';
+ this.filesystem = fileSystem || null;
+}
+
+/**
+ * Look up the metadata of the entry.
+ *
+ * @param successCallback
+ * {Function} is called with a Metadata object
+ * @param errorCallback
+ * {Function} is called with a FileError
+ */
+Entry.prototype.getMetadata = function(successCallback, errorCallback) {
+ argscheck.checkArgs('FF', 'Entry.getMetadata', arguments);
+ var success = successCallback && function(lastModified) {
+ var metadata = new Metadata(lastModified);
+ successCallback(metadata);
+ };
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+
+ exec(success, fail, "File", "getMetadata", [this.fullPath]);
+};
+
+/**
+ * Set the metadata of the entry.
+ *
+ * @param successCallback
+ * {Function} is called with a Metadata object
+ * @param errorCallback
+ * {Function} is called with a FileError
+ * @param metadataObject
+ * {Object} keys and values to set
+ */
+Entry.prototype.setMetadata = function(successCallback, errorCallback, metadataObject) {
+ argscheck.checkArgs('FFO', 'Entry.setMetadata', arguments);
+ exec(successCallback, errorCallback, "File", "setMetadata", [this.fullPath, metadataObject]);
+};
+
+/**
+ * Move a file or directory to a new location.
+ *
+ * @param parent
+ * {DirectoryEntry} the directory to which to move this entry
+ * @param newName
+ * {DOMString} new name of the entry, defaults to the current name
+ * @param successCallback
+ * {Function} called with the new DirectoryEntry object
+ * @param errorCallback
+ * {Function} called with a FileError
+ */
+Entry.prototype.moveTo = function(parent, newName, successCallback, errorCallback) {
+ argscheck.checkArgs('oSFF', 'Entry.moveTo', arguments);
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ // source path
+ var srcPath = this.fullPath,
+ // entry name
+ name = newName || this.name,
+ success = function(entry) {
+ if (entry) {
+ if (successCallback) {
+ // create appropriate Entry object
+ var result = (entry.isDirectory) ? new (require('cordova/plugin/DirectoryEntry'))(entry.name, entry.fullPath) : new (require('cordova/plugin/FileEntry'))(entry.name, entry.fullPath);
+ successCallback(result);
+ }
+ }
+ else {
+ // no Entry object returned
+ fail && fail(FileError.NOT_FOUND_ERR);
+ }
+ };
+
+ // copy
+ exec(success, fail, "File", "moveTo", [srcPath, parent.fullPath, name]);
+};
+
+/**
+ * Copy a directory to a different location.
+ *
+ * @param parent
+ * {DirectoryEntry} the directory to which to copy the entry
+ * @param newName
+ * {DOMString} new name of the entry, defaults to the current name
+ * @param successCallback
+ * {Function} called with the new Entry object
+ * @param errorCallback
+ * {Function} called with a FileError
+ */
+Entry.prototype.copyTo = function(parent, newName, successCallback, errorCallback) {
+ argscheck.checkArgs('oSFF', 'Entry.copyTo', arguments);
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+
+ // source path
+ var srcPath = this.fullPath,
+ // entry name
+ name = newName || this.name,
+ // success callback
+ success = function(entry) {
+ if (entry) {
+ if (successCallback) {
+ // create appropriate Entry object
+ var result = (entry.isDirectory) ? new (require('cordova/plugin/DirectoryEntry'))(entry.name, entry.fullPath) : new (require('cordova/plugin/FileEntry'))(entry.name, entry.fullPath);
+ successCallback(result);
+ }
+ }
+ else {
+ // no Entry object returned
+ fail && fail(FileError.NOT_FOUND_ERR);
+ }
+ };
+
+ // copy
+ exec(success, fail, "File", "copyTo", [srcPath, parent.fullPath, name]);
+};
+
+/**
+ * Return a URL that can be used to identify this entry.
+ */
+Entry.prototype.toURL = function() {
+ // fullPath attribute contains the full URL
+ return this.fullPath;
+};
+
+/**
+ * Returns a URI that can be used to identify this entry.
+ *
+ * @param {DOMString} mimeType for a FileEntry, the mime type to be used to interpret the file, when loaded through this URI.
+ * @return uri
+ */
+Entry.prototype.toURI = function(mimeType) {
+ console.log("DEPRECATED: Update your code to use 'toURL'");
+ // fullPath attribute contains the full URI
+ return this.toURL();
+};
+
+/**
+ * Remove a file or directory. It is an error to attempt to delete a
+ * directory that is not empty. It is an error to attempt to delete a
+ * root directory of a file system.
+ *
+ * @param successCallback {Function} called with no parameters
+ * @param errorCallback {Function} called with a FileError
+ */
+Entry.prototype.remove = function(successCallback, errorCallback) {
+ argscheck.checkArgs('FF', 'Entry.remove', arguments);
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(successCallback, fail, "File", "remove", [this.fullPath]);
+};
+
+/**
+ * Look up the parent DirectoryEntry of this entry.
+ *
+ * @param successCallback {Function} called with the parent DirectoryEntry object
+ * @param errorCallback {Function} called with a FileError
+ */
+Entry.prototype.getParent = function(successCallback, errorCallback) {
+ argscheck.checkArgs('FF', 'Entry.getParent', arguments);
+ var win = successCallback && function(result) {
+ var DirectoryEntry = require('cordova/plugin/DirectoryEntry');
+ var entry = new DirectoryEntry(result.name, result.fullPath);
+ successCallback(entry);
+ };
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(win, fail, "File", "getParent", [this.fullPath]);
+};
+
+module.exports = Entry;
+
+});
+
+// file: lib\common\plugin\File.js
+define("cordova/plugin/File", function(require, exports, module) {
+
+/**
+ * Constructor.
+ * name {DOMString} name of the file, without path information
+ * fullPath {DOMString} the full path of the file, including the name
+ * type {DOMString} mime type
+ * lastModifiedDate {Date} last modified date
+ * size {Number} size of the file in bytes
+ */
+
+var File = function(name, fullPath, type, lastModifiedDate, size){
+ this.name = name || '';
+ this.fullPath = fullPath || null;
+ this.type = type || null;
+ this.lastModifiedDate = lastModifiedDate || null;
+ this.size = size || 0;
+
+ // These store the absolute start and end for slicing the file.
+ this.start = 0;
+ this.end = this.size;
+};
+
+/**
+ * Returns a "slice" of the file. Since Cordova Files don't contain the actual
+ * content, this really returns a File with adjusted start and end.
+ * Slices of slices are supported.
+ * start {Number} The index at which to start the slice (inclusive).
+ * end {Number} The index at which to end the slice (exclusive).
+ */
+File.prototype.slice = function(start, end) {
+ var size = this.end - this.start;
+ var newStart = 0;
+ var newEnd = size;
+ if (arguments.length) {
+ if (start < 0) {
+ newStart = Math.max(size + start, 0);
+ } else {
+ newStart = Math.min(size, start);
+ }
+ }
+
+ if (arguments.length >= 2) {
+ if (end < 0) {
+ newEnd = Math.max(size + end, 0);
+ } else {
+ newEnd = Math.min(end, size);
+ }
+ }
+
+ var newFile = new File(this.name, this.fullPath, this.type, this.lastModifiedData, this.size);
+ newFile.start = this.start + newStart;
+ newFile.end = this.start + newEnd;
+ return newFile;
+};
+
+
+module.exports = File;
+
+});
+
+// file: lib\common\plugin\FileEntry.js
+define("cordova/plugin/FileEntry", function(require, exports, module) {
+
+var utils = require('cordova/utils'),
+ exec = require('cordova/exec'),
+ Entry = require('cordova/plugin/Entry'),
+ FileWriter = require('cordova/plugin/FileWriter'),
+ File = require('cordova/plugin/File'),
+ FileError = require('cordova/plugin/FileError');
+
+/**
+ * An interface representing a file on the file system.
+ *
+ * {boolean} isFile always true (readonly)
+ * {boolean} isDirectory always false (readonly)
+ * {DOMString} name of the file, excluding the path leading to it (readonly)
+ * {DOMString} fullPath the absolute full path to the file (readonly)
+ * {FileSystem} filesystem on which the file resides (readonly)
+ */
+var FileEntry = function(name, fullPath) {
+ FileEntry.__super__.constructor.apply(this, [true, false, name, fullPath]);
+};
+
+utils.extend(FileEntry, Entry);
+
+/**
+ * Creates a new FileWriter associated with the file that this FileEntry represents.
+ *
+ * @param {Function} successCallback is called with the new FileWriter
+ * @param {Function} errorCallback is called with a FileError
+ */
+FileEntry.prototype.createWriter = function(successCallback, errorCallback) {
+ this.file(function(filePointer) {
+ var writer = new FileWriter(filePointer);
+
+ if (writer.fileName === null || writer.fileName === "") {
+ errorCallback && errorCallback(new FileError(FileError.INVALID_STATE_ERR));
+ } else {
+ successCallback && successCallback(writer);
+ }
+ }, errorCallback);
+};
+
+/**
+ * Returns a File that represents the current state of the file that this FileEntry represents.
+ *
+ * @param {Function} successCallback is called with the new File object
+ * @param {Function} errorCallback is called with a FileError
+ */
+FileEntry.prototype.file = function(successCallback, errorCallback) {
+ var win = successCallback && function(f) {
+ var file = new File(f.name, f.fullPath, f.type, f.lastModifiedDate, f.size);
+ successCallback(file);
+ };
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(win, fail, "File", "getFileMetadata", [this.fullPath]);
+};
+
+
+module.exports = FileEntry;
+
+});
+
+// file: lib\common\plugin\FileError.js
+define("cordova/plugin/FileError", function(require, exports, module) {
+
+/**
+ * FileError
+ */
+function FileError(error) {
+ this.code = error || null;
+}
+
+// File error codes
+// Found in DOMException
+FileError.NOT_FOUND_ERR = 1;
+FileError.SECURITY_ERR = 2;
+FileError.ABORT_ERR = 3;
+
+// Added by File API specification
+FileError.NOT_READABLE_ERR = 4;
+FileError.ENCODING_ERR = 5;
+FileError.NO_MODIFICATION_ALLOWED_ERR = 6;
+FileError.INVALID_STATE_ERR = 7;
+FileError.SYNTAX_ERR = 8;
+FileError.INVALID_MODIFICATION_ERR = 9;
+FileError.QUOTA_EXCEEDED_ERR = 10;
+FileError.TYPE_MISMATCH_ERR = 11;
+FileError.PATH_EXISTS_ERR = 12;
+
+module.exports = FileError;
+
+});
+
+// file: lib\common\plugin\FileReader.js
+define("cordova/plugin/FileReader", function(require, exports, module) {
+
+var exec = require('cordova/exec'),
+ modulemapper = require('cordova/modulemapper'),
+ utils = require('cordova/utils'),
+ File = require('cordova/plugin/File'),
+ FileError = require('cordova/plugin/FileError'),
+ ProgressEvent = require('cordova/plugin/ProgressEvent'),
+ origFileReader = modulemapper.getOriginalSymbol(this, 'FileReader');
+
+/**
+ * This class reads the mobile device file system.
+ *
+ * For Android:
+ * The root directory is the root of the file system.
+ * To read from the SD card, the file name is "sdcard/my_file.txt"
+ * @constructor
+ */
+var FileReader = function() {
+ this._readyState = 0;
+ this._error = null;
+ this._result = null;
+ this._fileName = '';
+ this._realReader = origFileReader ? new origFileReader() : {};
+};
+
+// States
+FileReader.EMPTY = 0;
+FileReader.LOADING = 1;
+FileReader.DONE = 2;
+
+utils.defineGetter(FileReader.prototype, 'readyState', function() {
+ return this._fileName ? this._readyState : this._realReader.readyState;
+});
+
+utils.defineGetter(FileReader.prototype, 'error', function() {
+ return this._fileName ? this._error: this._realReader.error;
+});
+
+utils.defineGetter(FileReader.prototype, 'result', function() {
+ return this._fileName ? this._result: this._realReader.result;
+});
+
+function defineEvent(eventName) {
+ utils.defineGetterSetter(FileReader.prototype, eventName, function() {
+ return this._realReader[eventName] || null;
+ }, function(value) {
+ this._realReader[eventName] = value;
+ });
+}
+defineEvent('onloadstart'); // When the read starts.
+defineEvent('onprogress'); // While reading (and decoding) file or fileBlob data, and reporting partial file data (progress.loaded/progress.total)
+defineEvent('onload'); // When the read has successfully completed.
+defineEvent('onerror'); // When the read has failed (see errors).
+defineEvent('onloadend'); // When the request has completed (either in success or failure).
+defineEvent('onabort'); // When the read has been aborted. For instance, by invoking the abort() method.
+
+function initRead(reader, file) {
+ // Already loading something
+ if (reader.readyState == FileReader.LOADING) {
+ throw new FileError(FileError.INVALID_STATE_ERR);
+ }
+
+ reader._result = null;
+ reader._error = null;
+ reader._readyState = FileReader.LOADING;
+
+ if (typeof file == 'string') {
+ // Deprecated in Cordova 2.4.
+ console.warning('Using a string argument with FileReader.readAs functions is deprecated.');
+ reader._fileName = file;
+ } else if (typeof file.fullPath == 'string') {
+ reader._fileName = file.fullPath;
+ } else {
+ reader._fileName = '';
+ return true;
+ }
+
+ reader.onloadstart && reader.onloadstart(new ProgressEvent("loadstart", {target:reader}));
+}
+
+/**
+ * Abort reading file.
+ */
+FileReader.prototype.abort = function() {
+ if (origFileReader && !this._fileName) {
+ return this._realReader.abort();
+ }
+ this._result = null;
+
+ if (this._readyState == FileReader.DONE || this._readyState == FileReader.EMPTY) {
+ return;
+ }
+
+ this._readyState = FileReader.DONE;
+
+ // If abort callback
+ if (typeof this.onabort === 'function') {
+ this.onabort(new ProgressEvent('abort', {target:this}));
+ }
+ // If load end callback
+ if (typeof this.onloadend === 'function') {
+ this.onloadend(new ProgressEvent('loadend', {target:this}));
+ }
+};
+
+/**
+ * Read text file.
+ *
+ * @param file {File} File object containing file properties
+ * @param encoding [Optional] (see http://www.iana.org/assignments/character-sets)
+ */
+FileReader.prototype.readAsText = function(file, encoding) {
+ if (initRead(this, file)) {
+ return this._realReader.readAsText(file, encoding);
+ }
+
+ // Default encoding is UTF-8
+ var enc = encoding ? encoding : "UTF-8";
+ var me = this;
+ var execArgs = [this._fileName, enc];
+
+ // Maybe add slice parameters.
+ if (file.end < file.size) {
+ execArgs.push(file.start, file.end);
+ } else if (file.start > 0) {
+ execArgs.push(file.start);
+ }
+
+ // Read file
+ exec(
+ // Success callback
+ function(r) {
+ // If DONE (cancelled), then don't do anything
+ if (me._readyState === FileReader.DONE) {
+ return;
+ }
+
+ // Save result
+ me._result = r;
+
+ // If onload callback
+ if (typeof me.onload === "function") {
+ me.onload(new ProgressEvent("load", {target:me}));
+ }
+
+ // DONE state
+ me._readyState = FileReader.DONE;
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ me.onloadend(new ProgressEvent("loadend", {target:me}));
+ }
+ },
+ // Error callback
+ function(e) {
+ // If DONE (cancelled), then don't do anything
+ if (me._readyState === FileReader.DONE) {
+ return;
+ }
+
+ // DONE state
+ me._readyState = FileReader.DONE;
+
+ // null result
+ me._result = null;
+
+ // Save error
+ me._error = new FileError(e);
+
+ // If onerror callback
+ if (typeof me.onerror === "function") {
+ me.onerror(new ProgressEvent("error", {target:me}));
+ }
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ me.onloadend(new ProgressEvent("loadend", {target:me}));
+ }
+ }, "File", "readAsText", execArgs);
+};
+
+
+/**
+ * Read file and return data as a base64 encoded data url.
+ * A data url is of the form:
+ * data:[<mediatype>][;base64],<data>
+ *
+ * @param file {File} File object containing file properties
+ */
+FileReader.prototype.readAsDataURL = function(file) {
+ if (initRead(this, file)) {
+ return this._realReader.readAsDataURL(file);
+ }
+
+ var me = this;
+ var execArgs = [this._fileName];
+
+ // Maybe add slice parameters.
+ if (file.end < file.size) {
+ execArgs.push(file.start, file.end);
+ } else if (file.start > 0) {
+ execArgs.push(file.start);
+ }
+
+ // Read file
+ exec(
+ // Success callback
+ function(r) {
+ // If DONE (cancelled), then don't do anything
+ if (me._readyState === FileReader.DONE) {
+ return;
+ }
+
+ // DONE state
+ me._readyState = FileReader.DONE;
+
+ // Save result
+ me._result = r;
+
+ // If onload callback
+ if (typeof me.onload === "function") {
+ me.onload(new ProgressEvent("load", {target:me}));
+ }
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ me.onloadend(new ProgressEvent("loadend", {target:me}));
+ }
+ },
+ // Error callback
+ function(e) {
+ // If DONE (cancelled), then don't do anything
+ if (me._readyState === FileReader.DONE) {
+ return;
+ }
+
+ // DONE state
+ me._readyState = FileReader.DONE;
+
+ me._result = null;
+
+ // Save error
+ me._error = new FileError(e);
+
+ // If onerror callback
+ if (typeof me.onerror === "function") {
+ me.onerror(new ProgressEvent("error", {target:me}));
+ }
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ me.onloadend(new ProgressEvent("loadend", {target:me}));
+ }
+ }, "File", "readAsDataURL", execArgs);
+};
+
+/**
+ * Read file and return data as a binary data.
+ *
+ * @param file {File} File object containing file properties
+ */
+FileReader.prototype.readAsBinaryString = function(file) {
+ if (initRead(this, file)) {
+ return this._realReader.readAsBinaryString(file);
+ }
+ // TODO - Can't return binary data to browser.
+ console.log('method "readAsBinaryString" is not supported at this time.');
+ this.abort();
+};
+
+/**
+ * Read file and return data as a binary data.
+ *
+ * @param file {File} File object containing file properties
+ */
+FileReader.prototype.readAsArrayBuffer = function(file) {
+ if (initRead(this, file)) {
+ return this._realReader.readAsArrayBuffer(file);
+ }
+ // TODO - Can't return binary data to browser.
+ console.log('This method is not supported at this time.');
+ this.abort();
+};
+
+module.exports = FileReader;
+
+});
+
+// file: lib\common\plugin\FileSystem.js
+define("cordova/plugin/FileSystem", function(require, exports, module) {
+
+var DirectoryEntry = require('cordova/plugin/DirectoryEntry');
+
+/**
+ * An interface representing a file system
+ *
+ * @constructor
+ * {DOMString} name the unique name of the file system (readonly)
+ * {DirectoryEntry} root directory of the file system (readonly)
+ */
+var FileSystem = function(name, root) {
+ this.name = name || null;
+ if (root) {
+ this.root = new DirectoryEntry(root.name, root.fullPath);
+ }
+};
+
+module.exports = FileSystem;
+
+});
+
+// file: lib\common\plugin\FileTransfer.js
+define("cordova/plugin/FileTransfer", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ exec = require('cordova/exec'),
+ FileTransferError = require('cordova/plugin/FileTransferError'),
+ ProgressEvent = require('cordova/plugin/ProgressEvent');
+
+function newProgressEvent(result) {
+ var pe = new ProgressEvent();
+ pe.lengthComputable = result.lengthComputable;
+ pe.loaded = result.loaded;
+ pe.total = result.total;
+ return pe;
+}
+
+var idCounter = 0;
+
+/**
+ * FileTransfer uploads a file to a remote server.
+ * @constructor
+ */
+var FileTransfer = function() {
+ this._id = ++idCounter;
+ this.onprogress = null; // optional callback
+};
+
+/**
+* Given an absolute file path, uploads a file on the device to a remote server
+* using a multipart HTTP request.
+* @param filePath {String} Full path of the file on the device
+* @param server {String} URL of the server to receive the file
+* @param successCallback (Function} Callback to be invoked when upload has completed
+* @param errorCallback {Function} Callback to be invoked upon error
+* @param options {FileUploadOptions} Optional parameters such as file name and mimetype
+* @param trustAllHosts {Boolean} Optional trust all hosts (e.g. for self-signed certs), defaults to false
+*/
+FileTransfer.prototype.upload = function(filePath, server, successCallback, errorCallback, options, trustAllHosts) {
+ argscheck.checkArgs('ssFFO*', 'FileTransfer.upload', arguments);
+ // check for options
+ var fileKey = null;
+ var fileName = null;
+ var mimeType = null;
+ var params = null;
+ var chunkedMode = true;
+ var headers = null;
+ if (options) {
+ fileKey = options.fileKey;
+ fileName = options.fileName;
+ mimeType = options.mimeType;
+ headers = options.headers;
+ if (options.chunkedMode !== null || typeof options.chunkedMode != "undefined") {
+ chunkedMode = options.chunkedMode;
+ }
+ if (options.params) {
+ params = options.params;
+ }
+ else {
+ params = {};
+ }
+ }
+
+ var fail = errorCallback && function(e) {
+ var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body);
+ errorCallback(error);
+ };
+
+ var self = this;
+ var win = function(result) {
+ if (typeof result.lengthComputable != "undefined") {
+ if (self.onprogress) {
+ self.onprogress(newProgressEvent(result));
+ }
+ } else {
+ successCallback && successCallback(result);
+ }
+ };
+ exec(win, fail, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode, headers, this._id]);
+};
+
+/**
+ * Downloads a file form a given URL and saves it to the specified directory.
+ * @param source {String} URL of the server to receive the file
+ * @param target {String} Full path of the file on the device
+ * @param successCallback (Function} Callback to be invoked when upload has completed
+ * @param errorCallback {Function} Callback to be invoked upon error
+ * @param trustAllHosts {Boolean} Optional trust all hosts (e.g. for self-signed certs), defaults to false
+ */
+FileTransfer.prototype.download = function(source, target, successCallback, errorCallback, trustAllHosts) {
+ argscheck.checkArgs('ssFF*', 'FileTransfer.download', arguments);
+ var self = this;
+ var win = function(result) {
+ if (typeof result.lengthComputable != "undefined") {
+ if (self.onprogress) {
+ return self.onprogress(newProgressEvent(result));
+ }
+ } else if (successCallback) {
+ var entry = null;
+ if (result.isDirectory) {
+ entry = new (require('cordova/plugin/DirectoryEntry'))();
+ }
+ else if (result.isFile) {
+ entry = new (require('cordova/plugin/FileEntry'))();
+ }
+ entry.isDirectory = result.isDirectory;
+ entry.isFile = result.isFile;
+ entry.name = result.name;
+ entry.fullPath = result.fullPath;
+ successCallback(entry);
+ }
+ };
+
+ var fail = errorCallback && function(e) {
+ var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body);
+ errorCallback(error);
+ };
+
+ exec(win, fail, 'FileTransfer', 'download', [source, target, trustAllHosts, this._id]);
+};
+
+/**
+ * Aborts the ongoing file transfer on this object
+ * @param successCallback {Function} Callback to be invoked upon success
+ * @param errorCallback {Function} Callback to be invoked upon error
+ */
+FileTransfer.prototype.abort = function(successCallback, errorCallback) {
+ exec(successCallback, errorCallback, 'FileTransfer', 'abort', [this._id]);
+};
+
+module.exports = FileTransfer;
+
+});
+
+// file: lib\common\plugin\FileTransferError.js
+define("cordova/plugin/FileTransferError", function(require, exports, module) {
+
+/**
+ * FileTransferError
+ * @constructor
+ */
+var FileTransferError = function(code, source, target, status, body) {
+ this.code = code || null;
+ this.source = source || null;
+ this.target = target || null;
+ this.http_status = status || null;
+ this.body = body || null;
+};
+
+FileTransferError.FILE_NOT_FOUND_ERR = 1;
+FileTransferError.INVALID_URL_ERR = 2;
+FileTransferError.CONNECTION_ERR = 3;
+FileTransferError.ABORT_ERR = 4;
+
+module.exports = FileTransferError;
+
+});
+
+// file: lib\common\plugin\FileUploadOptions.js
+define("cordova/plugin/FileUploadOptions", function(require, exports, module) {
+
+/**
+ * Options to customize the HTTP request used to upload files.
+ * @constructor
+ * @param fileKey {String} Name of file request parameter.
+ * @param fileName {String} Filename to be used by the server. Defaults to image.jpg.
+ * @param mimeType {String} Mimetype of the uploaded file. Defaults to image/jpeg.
+ * @param params {Object} Object with key: value params to send to the server.
+ * @param headers {Object} Keys are header names, values are header values. Multiple
+ * headers of the same name are not supported.
+ */
+var FileUploadOptions = function(fileKey, fileName, mimeType, params, headers) {
+ this.fileKey = fileKey || null;
+ this.fileName = fileName || null;
+ this.mimeType = mimeType || null;
+ this.params = params || null;
+ this.headers = headers || null;
+};
+
+module.exports = FileUploadOptions;
+
+});
+
+// file: lib\common\plugin\FileUploadResult.js
+define("cordova/plugin/FileUploadResult", function(require, exports, module) {
+
+/**
+ * FileUploadResult
+ * @constructor
+ */
+var FileUploadResult = function() {
+ this.bytesSent = 0;
+ this.responseCode = null;
+ this.response = null;
+};
+
+module.exports = FileUploadResult;
+
+});
+
+// file: lib\common\plugin\FileWriter.js
+define("cordova/plugin/FileWriter", function(require, exports, module) {
+
+var exec = require('cordova/exec'),
+ FileError = require('cordova/plugin/FileError'),
+ ProgressEvent = require('cordova/plugin/ProgressEvent');
+
+/**
+ * This class writes to the mobile device file system.
+ *
+ * For Android:
+ * The root directory is the root of the file system.
+ * To write to the SD card, the file name is "sdcard/my_file.txt"
+ *
+ * @constructor
+ * @param file {File} File object containing file properties
+ * @param append if true write to the end of the file, otherwise overwrite the file
+ */
+var FileWriter = function(file) {
+ this.fileName = "";
+ this.length = 0;
+ if (file) {
+ this.fileName = file.fullPath || file;
+ this.length = file.size || 0;
+ }
+ // default is to write at the beginning of the file
+ this.position = 0;
+
+ this.readyState = 0; // EMPTY
+
+ this.result = null;
+
+ // Error
+ this.error = null;
+
+ // Event handlers
+ this.onwritestart = null; // When writing starts
+ this.onprogress = null; // While writing the file, and reporting partial file data
+ this.onwrite = null; // When the write has successfully completed.
+ this.onwriteend = null; // When the request has completed (either in success or failure).
+ this.onabort = null; // When the write has been aborted. For instance, by invoking the abort() method.
+ this.
<TRUNCATED>
[37/37] git commit: Add Windows support to Android platform-scripts.
Posted by mw...@apache.org.
Add Windows support to Android platform-scripts.
Project: http://git-wip-us.apache.org/repos/asf/cordova-cli/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-cli/commit/bed35f66
Tree: http://git-wip-us.apache.org/repos/asf/cordova-cli/tree/bed35f66
Diff: http://git-wip-us.apache.org/repos/asf/cordova-cli/diff/bed35f66
Branch: refs/heads/master
Commit: bed35f663ed251c43f69b2c0c165a3bd5be378ce
Parents: ddfa083
Author: Benn Mapes <be...@gmail.com>
Authored: Tue May 14 19:23:16 2013 -0700
Committer: Michael Brooks <mi...@michaelbrooks.ca>
Committed: Wed May 15 13:27:23 2013 -0700
----------------------------------------------------------------------
lib/cordova-android/bin/check_reqs | 34 +
lib/cordova-android/bin/check_reqs.bat | 9 +
lib/cordova-android/bin/check_reqs.js | 81 +
lib/cordova-android/bin/create | 30 +-
lib/cordova-android/bin/create.bat | 34 +-
lib/cordova-android/bin/create.js | 125 +-
lib/cordova-android/bin/templates/cordova/build | 5 +-
.../bin/templates/cordova/build.bat | 20 +-
lib/cordova-android/bin/templates/cordova/clean | 5 +-
.../bin/templates/cordova/clean.bat | 20 +-
lib/cordova-android/bin/templates/cordova/cordova | 159 -
.../bin/templates/cordova/cordova.bat | 7 +-
.../bin/templates/cordova/cordova.js | 137 -
.../bin/templates/cordova/lib/cordova | 386 +
.../bin/templates/cordova/lib/cordova.js | 593 ++
.../bin/templates/cordova/lib/install-device | 23 +
.../bin/templates/cordova/lib/install-device.bat | 9 +
.../bin/templates/cordova/lib/install-emulator | 23 +
.../bin/templates/cordova/lib/install-emulator.bat | 9 +
.../bin/templates/cordova/lib/list-devices | 23 +
.../bin/templates/cordova/lib/list-devices.bat | 9 +
.../bin/templates/cordova/lib/list-emulator-images | 23 +
.../templates/cordova/lib/list-emulator-images.bat | 9 +
.../templates/cordova/lib/list-started-emulators | 23 +
.../cordova/lib/list-started-emulators.bat | 9 +
.../bin/templates/cordova/lib/start-emulator | 23 +
.../bin/templates/cordova/lib/start-emulator.bat | 9 +
lib/cordova-android/bin/templates/cordova/log | 5 +-
lib/cordova-android/bin/templates/cordova/log.bat | 20 +-
lib/cordova-android/bin/templates/cordova/release | 24 -
lib/cordova-android/bin/templates/cordova/run | 5 +-
lib/cordova-android/bin/templates/cordova/run.bat | 3 +-
lib/cordova-android/bin/templates/cordova/version | 32 +
.../framework/assets/js/cordova.android.js | 6836 ---------------
.../framework/assets/www/cordova.js | 6836 +++++++++++++++
lib/cordova-android/framework/build.xml | 35 +-
src/metadata/android_parser.js | 2 +-
37 files changed, 8301 insertions(+), 7334 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/check_reqs
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/check_reqs b/lib/cordova-android/bin/check_reqs
new file mode 100755
index 0000000..0032778
--- /dev/null
+++ b/lib/cordova-android/bin/check_reqs
@@ -0,0 +1,34 @@
+#! /bin/bash
+# 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.
+#
+ROOT="$( cd "$( dirname "$0" )/.." && pwd )"
+cmd=`android list target`
+if [[ $? != 0 ]]; then
+ echo "The command `android` failed. Make sure you have the latest Android SDK installed, and the `android` command (inside the tools/ folder) added to your path."
+ exit 2
+elif [[ ! $cmd =~ "android-17" ]]; then
+ echo "Please install Android target 17 (the Android 4.2 SDK). Make sure you have the latest Android tools installed as well. Run `android` from your command-line to install/update any missing SDKs or tools."
+ exit 2
+else
+ cmd="android update project -p $ROOT -t android-17 1> /dev/null 2>&1"
+ eval $cmd
+ if [[ $? != 0 ]]; then
+ echo "Error updating the Cordova library to work with your Android environment."
+ exit 2
+ fi
+fi
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/check_reqs.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/check_reqs.bat b/lib/cordova-android/bin/check_reqs.bat
new file mode 100644
index 0000000..65514c8
--- /dev/null
+++ b/lib/cordova-android/bin/check_reqs.bat
@@ -0,0 +1,9 @@
+@ECHO OFF
+SET full_path=%~dp0
+IF EXIST %full_path%check_reqs.js (
+ cscript "%full_path%check_reqs.js" //nologo
+) ELSE (
+ ECHO.
+ ECHO ERROR: Could not find 'check_reqs.js' in 'bin' folder, aborting...>&2
+ EXIT /B 1
+)
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/check_reqs.js
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/check_reqs.js b/lib/cordova-android/bin/check_reqs.js
new file mode 100644
index 0000000..ef30991
--- /dev/null
+++ b/lib/cordova-android/bin/check_reqs.js
@@ -0,0 +1,81 @@
+// 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.
+
+var ROOT = WScript.ScriptFullName.split('\\bin\\check_reqs.js').join(''),
+ shell = WScript.CreateObject("WScript.Shell"),
+ fso = WScript.CreateObject('Scripting.FileSystemObject');
+
+
+// executes a command in the shell, returns stdout or stderr if error
+function exec_out(command) {
+ var oExec=shell.Exec(command);
+ var output = new String();
+ while (oExec.Status == 0) {
+ if (!oExec.StdOut.AtEndOfStream) {
+ var line = oExec.StdOut.ReadAll();
+ // XXX: Change to verbose mode
+ // WScript.StdOut.WriteLine(line);
+ output += line;
+ }
+ WScript.sleep(100);
+ }
+ //Check to make sure our scripts did not encounter an error
+ if (!oExec.StdErr.AtEndOfStream) {
+ var line = oExec.StdErr.ReadAll();
+ return {'error' : true, 'output' : line};
+ } else if (!oExec.StdOut.AtEndOfStream) {
+ var line = oExec.StdOut.ReadAll();
+ // XXX: Change to verbose mode
+ // WScript.StdOut.WriteLine(line);
+ output += line;
+ }
+ return {'error' : false, 'output' : output};
+}
+
+// log to stdout or stderr
+function Log(msg, error) {
+ if (error) {
+ WScript.StdErr.WriteLine(msg);
+ }
+ else {
+ WScript.StdOut.WriteLine(msg);
+ }
+}
+
+// checks that android requirements are met
+function check_requirements() {
+ var result = exec_out('%comspec% /c android list target');
+ if(result.error) {
+ Log('The command `android` failed. Make sure you have the latest Android SDK installed, and the `android` command (inside the tools/ folder) added to your path. Output: ' + result.output, true);
+ WScript.Quit(2);
+ }
+ else if(!result.output.match(/android[-]17/)) {
+ Log('Please install Android target 17 (the Android 4.2 SDK). Make sure you have the latest Android tools installed as well. Run `android` from your command-line to install/update any missing SDKs or tools.', true);
+ Log('Output : ' + result.output);
+ WScript.Quit(2);
+ }
+ else {
+ var cmd = '%comspec% /c android update project -p ' + ROOT + '\\framework -t android-17';
+ result = exec_out(cmd);
+ if(result.error) {
+ Log('Error updating the Cordova library to work with your Android environment. Command run: "' + cmd + '", output: ' + result.output, true);
+ WScript.Quit(2);
+ }
+ }
+}
+
+check_requirements();
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/create
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/create b/lib/cordova-android/bin/create
index 35d3363..39aff6b 100755
--- a/lib/cordova-android/bin/create
+++ b/lib/cordova-android/bin/create
@@ -47,20 +47,6 @@ then
exit 1
fi
-# cleanup after exit and/or on error
-function on_exit {
- # [ -f "$BUILD_PATH"/framework/libs/commons-codec-1.6.jar ] && rm "$BUILD_PATH"/framework/libs/commons-codec-1.6.jar
- # [ -d "$BUILD_PATH"/framework/libs ] && rmdir "$BUILD_PATH"/framework/libs
- if [ -f "$BUILD_PATH"/framework/assets/www/cordova-$VERSION.js ]
- then
- rm "$BUILD_PATH"/framework/assets/www/cordova-$VERSION.js
- fi
- if [ -f "$BUILD_PATH"/framework/cordova-$VERSION.jar ]
- then
- rm "$BUILD_PATH"/framework/cordova-$VERSION.jar
- fi
-}
-
function createAppInfoJar {
pushd "$BUILD_PATH"/bin/templates/cordova/ApplicationInfo > /dev/null
javac ApplicationInfo.java
@@ -91,7 +77,6 @@ function replace {
# we do not want the script to silently fail
trap 'previous_command=$this_command; this_command=$BASH_COMMAND' DEBUG
trap on_error ERR
-trap on_exit EXIT
ANDROID_BIN="${ANDROID_BIN:=$( which android )}"
PACKAGE_AS_PATH=$(echo $PACKAGE | sed 's/\./\//g')
@@ -141,11 +126,11 @@ cp -r "$BUILD_PATH"/bin/templates/project/res "$PROJECT_PATH"
if [ -d "$BUILD_PATH"/framework ]
then
cp -r "$BUILD_PATH"/framework/res/xml "$PROJECT_PATH"/res
- cp "$BUILD_PATH"/framework/assets/www/cordova-$VERSION.js "$PROJECT_PATH"/assets/www/cordova-$VERSION.js
+ cp "$BUILD_PATH"/framework/assets/www/cordova.js "$PROJECT_PATH"/assets/www/cordova.js
cp "$BUILD_PATH"/framework/cordova-$VERSION.jar "$PROJECT_PATH"/libs/cordova-$VERSION.jar
else
cp -r "$BUILD_PATH"/xml "$PROJECT_PATH"/res/xml
- cp "$BUILD_PATH"/cordova-$VERSION.js "$PROJECT_PATH"/assets/www/cordova-$VERSION.js
+ cp "$BUILD_PATH"/cordova.js "$PROJECT_PATH"/assets/www/cordova.js
cp "$BUILD_PATH"/cordova-$VERSION.jar "$PROJECT_PATH"/libs/cordova-$VERSION.jar
fi
@@ -161,11 +146,18 @@ replace "s/__APILEVEL__/${API_LEVEL}/g" "$MANIFEST_PATH"
# creating cordova folder and copying run/build/log/launch scripts
mkdir "$PROJECT_PATH"/cordova
+mkdir "$PROJECT_PATH"/cordova/lib
createAppInfoJar
cp "$BUILD_PATH"/bin/templates/cordova/appinfo.jar "$PROJECT_PATH"/cordova/appinfo.jar
-cp "$BUILD_PATH"/bin/templates/cordova/cordova "$PROJECT_PATH"/cordova/cordova
cp "$BUILD_PATH"/bin/templates/cordova/build "$PROJECT_PATH"/cordova/build
-cp "$BUILD_PATH"/bin/templates/cordova/release "$PROJECT_PATH"/cordova/release
cp "$BUILD_PATH"/bin/templates/cordova/clean "$PROJECT_PATH"/cordova/clean
cp "$BUILD_PATH"/bin/templates/cordova/log "$PROJECT_PATH"/cordova/log
cp "$BUILD_PATH"/bin/templates/cordova/run "$PROJECT_PATH"/cordova/run
+cp "$BUILD_PATH"/bin/templates/cordova/lib/cordova "$PROJECT_PATH"/cordova/lib/cordova
+cp "$BUILD_PATH"/bin/templates/cordova/lib/install-device "$PROJECT_PATH"/cordova/lib/install-device
+cp "$BUILD_PATH"/bin/templates/cordova/lib/install-emulator "$PROJECT_PATH"/cordova/lib/install-emulator
+cp "$BUILD_PATH"/bin/templates/cordova/lib/list-devices "$PROJECT_PATH"/cordova/lib/list-devices
+cp "$BUILD_PATH"/bin/templates/cordova/lib/list-emulator-images "$PROJECT_PATH"/cordova/lib/list-emulator-images
+cp "$BUILD_PATH"/bin/templates/cordova/lib/list-started-emulators "$PROJECT_PATH"/cordova/lib/list-started-emulators
+cp "$BUILD_PATH"/bin/templates/cordova/lib/start-emulator "$PROJECT_PATH"/cordova/lib/start-emulator
+
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/create.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/create.bat b/lib/cordova-android/bin/create.bat
index cdbd611..7f0346f 100644
--- a/lib/cordova-android/bin/create.bat
+++ b/lib/cordova-android/bin/create.bat
@@ -1,3 +1,5 @@
+@ECHO OFF
+GOTO BEGIN
:: 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
@@ -15,23 +17,23 @@
:: specific language governing permissions and limitations
:: under the License.
-@ECHO OFF
-IF NOT DEFINED JAVA_HOME GOTO MISSING_JAVA_HOME
+:BEGIN
+ IF NOT DEFINED JAVA_HOME GOTO MISSING_JAVA_HOME
-FOR %%X in (java.exe javac.exe ant.bat android.bat) do (
- IF [%%~$PATH:X]==[] (
- ECHO Cannot locate %%X using the PATH environment variable.
- ECHO Retry after adding directory containing %%X to the PATH variable.
- ECHO Remember to open a new command window after updating the PATH variable.
- IF "%%X"=="java.exe" GOTO GET_JAVA
- IF "%%X"=="javac.exe" GOTO GET_JAVA
- IF "%%X"=="ant.bat" GOTO GET_ANT
- IF "%%X"=="android.bat" GOTO GET_ANDROID
- GOTO ERROR
- )
-)
-cscript "%~dp0\create.js" %*
-GOTO END
+ FOR %%X in (java.exe javac.exe ant.bat android.bat) do (
+ IF [%%~$PATH:X]==[] (
+ ECHO Cannot locate %%X using the PATH environment variable.
+ ECHO Retry after adding directory containing %%X to the PATH variable.
+ ECHO Remember to open a new command window after updating the PATH variable.
+ IF "%%X"=="java.exe" GOTO GET_JAVA
+ IF "%%X"=="javac.exe" GOTO GET_JAVA
+ IF "%%X"=="ant.bat" GOTO GET_ANT
+ IF "%%X"=="android.bat" GOTO GET_ANDROID
+ GOTO ERROR
+ )
+ )
+ cscript "%~dp0\create.js" %* //nologo
+ GOTO END
:MISSING_JAVA_HOME
ECHO The JAVA_HOME environment variable is not set.
ECHO Set JAVA_HOME to an existing JRE directory.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/create.js
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/create.js b/lib/cordova-android/bin/create.js
index d0d9999..b1de5fe 100644
--- a/lib/cordova-android/bin/create.js
+++ b/lib/cordova-android/bin/create.js
@@ -24,7 +24,30 @@
* ./create [path package activity]
*/
-var fso = WScript.CreateObject('Scripting.FileSystemObject');
+var args = WScript.Arguments, PROJECT_PATH="example",
+ PACKAGE="org.apache.cordova.example", ACTIVITY="cordovaExample",
+ shell=WScript.CreateObject("WScript.Shell"),
+ fso = WScript.CreateObject('Scripting.FileSystemObject');
+
+function Usage() {
+ Log("Usage: create PathTONewProject [ PackageName AppName ]");
+ Log(" PathTONewProject : The path to where you wish to create the project");
+ Log(" PackageName : The package for the project (default is org.apache.cordova.example)")
+ Log(" AppName : The name of the application/activity (default is cordovaExample)");
+ Log("examples:");
+ Log(" create C:\\Users\\anonymous\\Desktop\\MyProject");
+ Log(" create C:\\Users\\anonymous\\Desktop\\MyProject io.Cordova.Example AnApp");
+}
+
+// logs messaged to stdout and stderr
+function Log(msg, error) {
+ if (error) {
+ WScript.StdErr.WriteLine(msg);
+ }
+ else {
+ WScript.StdOut.WriteLine(msg);
+ }
+}
function read(filename) {
var fso=WScript.CreateObject("Scripting.FileSystemObject");
@@ -36,7 +59,7 @@ function read(filename) {
function checkTargets(targets) {
if(!targets) {
- WScript.Echo("You do not have any android targets setup. Please create at least one target with the `android` command");
+ Log("You do not have any android targets setup. Please create at least one target with the `android` command", true);
WScript.Quit(69);
}
}
@@ -74,7 +97,7 @@ function exec(command) {
function createAppInfoJar() {
if(!fso.FileExists(ROOT+"\\bin\\templates\\cordova\\appinfo.jar")) {
- WScript.Echo("Creating appinfo.jar...");
+ Log("Creating appinfo.jar...");
var cur = shell.CurrentDirectory;
shell.CurrentDirectory = ROOT+"\\bin\\templates\\cordova\\ApplicationInfo";
exec("javac ApplicationInfo.java");
@@ -120,7 +143,7 @@ function downloadCommonsCodec() {
stream.SaveToFile(savePath);
stream.Close();
} else {
- WScript.Echo('Could not retrieve the commons-codec. Please download it yourself and put into the framework/libs directory. This process may fail now. Sorry.');
+ Log('Could not retrieve the commons-codec. Please download it yourself and put into the framework/libs directory. This process may fail now. Sorry.');
}
}
var app = WScript.CreateObject('Shell.Application');
@@ -136,84 +159,104 @@ function downloadCommonsCodec() {
fso.DeleteFolder(ROOT + '\\framework\\libs\\commons-codec-1.7', true);
}
}
-
-var args = WScript.Arguments, PROJECT_PATH="example",
- PACKAGE="org.apache.cordova.example", ACTIVITY="cordovaExample",
- shell=WScript.CreateObject("WScript.Shell");
// working dir
var ROOT = WScript.ScriptFullName.split('\\bin\\create.js').join('');
+if (args.Count() > 0) {
+ // support help flags
+ if (args(0) == "--help" || args(0) == "/?" ||
+ args(0) == "help" || args(0) == "-help" || args(0) == "/help" || args(0) == "-h") {
+ Usage();
+ WScript.Quit(2);
+ }
-if (args.Count() == 3) {
PROJECT_PATH=args(0);
- PACKAGE=args(1);
- ACTIVITY=args(2);
+ if (args.Count() > 1) {
+ PACKAGE = args(1);
+ }
+ if (args.Count() > 2) {
+ ACTIVITY = args(2);
+ }
+}
+else {
+ Log("Error : No project path provided.");
+ Usage();
+ WScript.Quit(2);
}
if(fso.FolderExists(PROJECT_PATH)) {
- WScript.Echo("Project already exists!");
- WScript.Quit(1);
+ Log("Project path already exists!", true);
+ WScript.Quit(2);
}
var PACKAGE_AS_PATH=PACKAGE.replace(/\./g, '\\');
-var ACTIVITY_PATH=PROJECT_PATH+'\\src\\'+PACKAGE_AS_PATH+'\\'+ACTIVITY+'.java';
+var ACTIVITY_DIR=PROJECT_PATH + '\\src\\' + PACKAGE_AS_PATH;
+var ACTIVITY_PATH=ACTIVITY_DIR+'\\'+ACTIVITY+'.java';
var MANIFEST_PATH=PROJECT_PATH+'\\AndroidManifest.xml';
var TARGET=setTarget();
var API_LEVEL=setApiLevel();
var VERSION=read(ROOT+'\\VERSION').replace(/\r\n/,'').replace(/\n/,'');
// create the project
-WScript.Echo("Creating new android project...");
-exec('android.bat create project --target '+TARGET+' --path '+PROJECT_PATH+' --package '+PACKAGE+' --activity '+ACTIVITY);
+Log("Creating new android project...");
+exec('android.bat create project --target "'+TARGET+'" --path "'+PROJECT_PATH+'" --package "'+PACKAGE+'" --activity "'+ACTIVITY+'"');
// build from source. distro should have these files
if (!fso.FileExists(ROOT+'\\cordova-'+VERSION+'.jar') &&
- !fso.FileExists(ROOT+'\\cordova-'+VERSION+'.js')) {
- WScript.Echo("Building jar and js files...");
+ !fso.FileExists(ROOT+'\\cordova.js')) {
+ Log("Building jar and js files...");
// update the cordova framework project to a target that exists on this machine
- exec('android.bat update project --target '+TARGET+' --path '+ROOT+'\\framework');
+ exec('android.bat update project --target "'+TARGET+'" --path "'+ROOT+'\\framework"');
// pull down commons codec if necessary
downloadCommonsCodec();
- exec('ant.bat -f \"'+ ROOT +'\\framework\\build.xml\" jar');
+ exec('ant.bat -f "'+ ROOT +'\\framework\\build.xml" jar');
}
// copy in the project template
-WScript.Echo("Copying template files...");
-exec('%comspec% /c xcopy "'+ ROOT + '"\\bin\\templates\\project\\res '+PROJECT_PATH+'\\res\\ /E /Y');
-exec('%comspec% /c xcopy "'+ ROOT + '"\\bin\\templates\\project\\assets '+PROJECT_PATH+'\\assets\\ /E /Y');
-exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\project\\AndroidManifest.xml ' + PROJECT_PATH + '\\AndroidManifest.xml /Y');
-exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\project\\Activity.java '+ ACTIVITY_PATH +' /Y');
+Log("Copying template files...");
+exec('%comspec% /c xcopy "'+ ROOT + '\\bin\\templates\\project\\res" "'+PROJECT_PATH+'\\res\\" /E /Y');
+exec('%comspec% /c xcopy "'+ ROOT + '\\bin\\templates\\project\\assets" "'+PROJECT_PATH+'\\assets\\" /E /Y');
+exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\project\\AndroidManifest.xml" "' + PROJECT_PATH + '\\AndroidManifest.xml" /Y');
+exec('%comspec% /c mkdir "' + ACTIVITY_DIR + '"');
+exec('%comspec% /c copy "' + ROOT + '"\\bin\\templates\\project\\Activity.java "' + ACTIVITY_PATH + '" /Y');
// check if we have the source or the distro files
-WScript.Echo("Copying js, jar & config.xml files...");
+Log("Copying js, jar & config.xml files...");
if(fso.FolderExists(ROOT + '\\framework')) {
- exec('%comspec% /c copy "'+ROOT+'"\\framework\\assets\\www\\cordova-'+VERSION+'.js '+PROJECT_PATH+'\\assets\\www\\cordova-'+VERSION+'.js /Y');
- exec('%comspec% /c copy "'+ROOT+'"\\framework\\cordova-'+VERSION+'.jar '+PROJECT_PATH+'\\libs\\cordova-'+VERSION+'.jar /Y');
+ exec('%comspec% /c copy "'+ROOT+'\\framework\\assets\\www\\cordova.js" "'+PROJECT_PATH+'\\assets\\www\\cordova.js" /Y');
+ exec('%comspec% /c copy "'+ROOT+'\\framework\\cordova-'+VERSION+'.jar" "'+PROJECT_PATH+'\\libs\\cordova-'+VERSION+'.jar" /Y');
fso.CreateFolder(PROJECT_PATH + '\\res\\xml');
- exec('%comspec% /c copy "'+ROOT+'"\\framework\\res\\xml\\config.xml ' + PROJECT_PATH + '\\res\\xml\\config.xml /Y');
+ exec('%comspec% /c copy "'+ROOT+'\\framework\\res\\xml\\config.xml" "' + PROJECT_PATH + '\\res\\xml\\config.xml" /Y');
} else {
// copy in cordova.js
- exec('%comspec% /c copy "'+ROOT+'"\\cordova-'+VERSION+'.js '+PROJECT_PATH+'\\assets\\www\\cordova-'+VERSION+'.js /Y');
+ exec('%comspec% /c copy "'+ROOT+'\\cordova.js" "'+PROJECT_PATH+'\\assets\\www\\cordova.js" /Y');
// copy in cordova.jar
- exec('%comspec% /c copy "'+ROOT+'"\\cordova-'+VERSION+'.jar '+PROJECT_PATH+'\\libs\\cordova-'+VERSION+'.jar /Y');
+ exec('%comspec% /c copy "'+ROOT+'\\cordova-'+VERSION+'.jar" "'+PROJECT_PATH+'\\libs\\cordova-'+VERSION+'.jar" /Y');
// copy in xml
fso.CreateFolder(PROJECT_PATH + '\\res\\xml');
- exec('%comspec% /c copy "'+ROOT+'"\\xml\\config.xml ' + PROJECT_PATH + '\\res\\xml\\config.xml /Y');
+ exec('%comspec% /c copy "'+ROOT+'\\xml\\config.xml" "' + PROJECT_PATH + '\\res\\xml\\config.xml" /Y');
}
// copy cordova scripts
fso.CreateFolder(PROJECT_PATH + '\\cordova');
+fso.CreateFolder(PROJECT_PATH + '\\cordova\\lib');
createAppInfoJar();
-WScript.Echo("Copying cordova command tools...");
-exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\appinfo.jar ' + PROJECT_PATH + '\\cordova\\appinfo.jar /Y');
-exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\cordova.js ' + PROJECT_PATH + '\\cordova\\cordova.js /Y');
-exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\cordova.bat ' + PROJECT_PATH + '\\cordova\\cordova.bat /Y');
-exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\clean.bat ' + PROJECT_PATH + '\\cordova\\clean.bat /Y');
-exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\build.bat ' + PROJECT_PATH + '\\cordova\\build.bat /Y');
-exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\log.bat ' + PROJECT_PATH + '\\cordova\\log.bat /Y');
-exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\run.bat ' + PROJECT_PATH + '\\cordova\\run.bat /Y');
+Log("Copying cordova command tools...");
+exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\appinfo.jar" "' + PROJECT_PATH + '\\cordova\\appinfo.jar" /Y');
+exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\lib\\cordova.js" "' + PROJECT_PATH + '\\cordova\\lib\\cordova.js" /Y');
+exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\lib\\install-device.bat" "' + PROJECT_PATH + '\\cordova\\lib\\install-device.bat" /Y');
+exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\lib\\install-emulator.bat" "' + PROJECT_PATH + '\\cordova\\lib\\install-emulator.bat" /Y');
+exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\lib\\list-emulator-images.bat" "' + PROJECT_PATH + '\\cordova\\lib\\list-emulator-images.bat" /Y');
+exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\lib\\list-devices.bat" "' + PROJECT_PATH + '\\cordova\\lib\\list-devices.bat" /Y');
+exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\lib\\list-started-emulators.bat" "' + PROJECT_PATH + '\\cordova\\lib\\list-started-emulators.bat" /Y');
+exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\lib\\start-emulator.bat" "' + PROJECT_PATH + '\\cordova\\lib\\start-emulator.bat" /Y');
+exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\cordova.bat" "' + PROJECT_PATH + '\\cordova\\cordova.bat" /Y');
+exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\clean.bat" "' + PROJECT_PATH + '\\cordova\\clean.bat" /Y');
+exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\build.bat" "' + PROJECT_PATH + '\\cordova\\build.bat" /Y');
+exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\log.bat" "' + PROJECT_PATH + '\\cordova\\log.bat" /Y');
+exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\run.bat" "' + PROJECT_PATH + '\\cordova\\run.bat" /Y');
// interpolate the activity name and package
-WScript.Echo("Updating AndroidManifest.xml and Main Activity...");
+Log("Updating AndroidManifest.xml and Main Activity...");
replaceInFile(ACTIVITY_PATH, /__ACTIVITY__/, ACTIVITY);
replaceInFile(ACTIVITY_PATH, /__ID__/, PACKAGE);
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/templates/cordova/build
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/build b/lib/cordova-android/bin/templates/cordova/build
index e586e4d..3cbd9c1 100755
--- a/lib/cordova-android/bin/templates/cordova/build
+++ b/lib/cordova-android/bin/templates/cordova/build
@@ -1,3 +1,4 @@
+#!/bin/bash
# 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
@@ -15,10 +16,8 @@
# specific language governing permissions and limitations
# under the License.
-#!/bin/bash
-
set -e
CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd )
-bash "$CORDOVA_PATH"/cordova build
+bash "$CORDOVA_PATH"/lib/cordova build "$@"
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/templates/cordova/build.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/build.bat b/lib/cordova-android/bin/templates/cordova/build.bat
index 8e6ca9a..7aa7c75 100644
--- a/lib/cordova-android/bin/templates/cordova/build.bat
+++ b/lib/cordova-android/bin/templates/cordova/build.bat
@@ -1,18 +1,2 @@
-:: 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.
-
-%~dp0\cordova.bat build
+@ECHO OFF
+%~dp0\cordova.bat build %*
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/templates/cordova/clean
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/clean b/lib/cordova-android/bin/templates/cordova/clean
index 53b7f9a..f52966a 100755
--- a/lib/cordova-android/bin/templates/cordova/clean
+++ b/lib/cordova-android/bin/templates/cordova/clean
@@ -1,3 +1,4 @@
+#!/bin/bash
# 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
@@ -15,10 +16,8 @@
# specific language governing permissions and limitations
# under the License.
-#!/bin/bash
-
set -e
CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd )
-bash "$CORDOVA_PATH"/cordova clean
+bash "$CORDOVA_PATH"/lib/cordova clean "$@"
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/templates/cordova/clean.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/clean.bat b/lib/cordova-android/bin/templates/cordova/clean.bat
index fe5c09f..b41bdc9 100644
--- a/lib/cordova-android/bin/templates/cordova/clean.bat
+++ b/lib/cordova-android/bin/templates/cordova/clean.bat
@@ -1,18 +1,2 @@
-:: 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.
-
-%~dp0\cordova.bat clean
+@ECHO OFF
+%~dp0\cordova.bat clean %*
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/templates/cordova/cordova
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/cordova b/lib/cordova-android/bin/templates/cordova/cordova
deleted file mode 100755
index 1945a4c..0000000
--- a/lib/cordova-android/bin/templates/cordova/cordova
+++ /dev/null
@@ -1,159 +0,0 @@
-# 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.
-
-#!/bin/bash
-
-
-PROJECT_PATH=$( cd "$( dirname "$0" )/.." && pwd )
-
-function check_devices {
-# FIXME
- local devices=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep device`
- if [ -z "$devices" ] ; then
- echo "1"
- else
- echo "0"
- fi
-}
-
-function emulate {
- declare -a avd_list=($(android list avd | grep "Name:" | cut -f 2 -d ":" | xargs))
- # we need to start adb-server
- adb start-server 1>/dev/null
-
- # Do not launch an emulator if there is already one running or if a device is attached
- if [ $(check_devices) == 0 ] ; then
- return
- fi
-
- local avd_id="1000" #FIXME: hopefully user does not have 1000 AVDs
- # User has no AVDs
- if [ ${#avd_list[@]} == 0 ]
- then
- echo "You don't have any Android Virtual Devices. Please create at least one AVD."
- echo "android"
- fi
- # User has only one AVD
- if [ ${#avd_list[@]} == 1 ]
- then
- emulator -cpu-delay 0 -no-boot-anim -cache /tmp/cache -avd ${avd_list[0]} 1> /dev/null 2>&1 &
- # User has more than 1 AVD
- elif [ ${#avd_list[@]} -gt 1 ]
- then
- while [ -z ${avd_list[$avd_id]} ]
- do
- echo "Choose from one of the following Android Virtual Devices [0 to $((${#avd_list[@]}-1))]:"
- for(( i = 0 ; i < ${#avd_list[@]} ; i++ ))
- do
- echo "$i) ${avd_list[$i]}"
- done
- read -t 5 -p "> " avd_id
- # default value if input timeout
- if [ $avd_id -eq 1000 ] ; then avd_id=0 ; fi
- done
- emulator -cpu-delay 0 -no-boot-anim -cache /tmp/cache -avd ${avd_list[$avd_id]} 1> /dev/null 2>&1 &
- fi
-
-}
-
-function clean {
- ant clean
-}
-# has to be used independently and not in conjunction with other commands
-function log {
- adb logcat
-}
-
-function run {
- clean && emulate && wait_for_device && install && launch
-}
-
-function install {
-
- declare -a devices=($(adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep device | cut -f 1))
- local device_id="1000" #FIXME: hopefully user does not have 1000 AVDs
-
- if [ ${#devices[@]} == 0 ]
- then
- # should not reach here. Emulator should launch or device should be attached
- echo "Emulator not running or device not attached. Could not install debug package"
- exit 70
- fi
-
- if [ ${#devices[@]} == 1 ]
- then
- export ANDROID_SERIAL=${devices[0]}
- # User has more than 1 AVD
- elif [ ${#devices[@]} -gt 1 ]
- then
- while [ -z ${devices[$device_id]} ]
- do
- echo "Choose from one of the following devices/emulators [0 to $((${#devices[@]}-1))]:"
- for(( i = 0 ; i < ${#devices[@]} ; i++ ))
- do
- echo "$i) ${devices[$i]}"
- done
- read -t 5 -p "> " device_id
- # default value if input timeout
- if [ $device_id -eq 1000 ] ; then device_id=0 ; fi
- done
- export ANDROID_SERIAL=${devices[$device_id]}
- fi
-
- ant debug install
-}
-
-function build {
- ant debug
-}
-
-function release {
- ant release
-}
-
-function wait_for_device {
- local i="0"
- echo -n "Waiting for device..."
-
- while [ $i -lt 300 ]
- do
- if [ $(check_devices) -eq 0 ]
- then
- break
- else
- sleep 1
- i=$[i+1]
- echo -n "."
- fi
- done
- # Device timeout: emulator has not started in time or device not attached
- if [ $i -eq 300 ]
- then
- echo "device timeout!"
- exit 69
- else
- echo "connected!"
- fi
-}
-
-function launch {
- local launch_str=$(java -jar "$PROJECT_PATH"/cordova/appinfo.jar "$PROJECT_PATH"/AndroidManifest.xml)
- adb shell am start -n $launch_str
-}
-
-# TODO parse arguments
-(cd "$PROJECT_PATH" && $1)
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/templates/cordova/cordova.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/cordova.bat b/lib/cordova-android/bin/templates/cordova/cordova.bat
index 22c289a..9b56199 100644
--- a/lib/cordova-android/bin/templates/cordova/cordova.bat
+++ b/lib/cordova-android/bin/templates/cordova/cordova.bat
@@ -1,3 +1,5 @@
+@ECHO OFF
+GOTO BEGIN
:: 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
@@ -14,14 +16,13 @@
:: KIND, either express or implied. See the License for the
:: specific language governing permissions and limitations
:: under the License.
-
-@ECHO OFF
+:BEGIN
IF NOT DEFINED JAVA_HOME GOTO MISSING
FOR %%X in (java.exe ant.bat android.bat) do (
SET FOUND=%%~$PATH:X
IF NOT DEFINED FOUND GOTO MISSING
)
-cscript %~dp0\cordova.js %*
+cscript %~dp0\lib\cordova.js %* //nologo
GOTO END
:MISSING
ECHO Missing one of the following:
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/templates/cordova/cordova.js
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/cordova.js b/lib/cordova-android/bin/templates/cordova/cordova.js
deleted file mode 100644
index 51533cb..0000000
--- a/lib/cordova-android/bin/templates/cordova/cordova.js
+++ /dev/null
@@ -1,137 +0,0 @@
-// 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.
-
-var ROOT = WScript.ScriptFullName.split('\\cordova\\cordova.js').join(''),
- shell=WScript.CreateObject("WScript.Shell");
-
-function exec(command) {
- var oExec=shell.Exec(command);
- var output = new String();
- while(oExec.Status == 0) {
- if(!oExec.StdOut.AtEndOfStream) {
- var line = oExec.StdOut.ReadLine();
- // XXX: Change to verbose mode
- // WScript.StdOut.WriteLine(line);
- output += line;
- }
- WScript.sleep(100);
- }
-
- return output;
-}
-
-function device_running() {
- var local_devices = shell.Exec("%comspec% /c adb devices").StdOut.ReadAll();
- if(local_devices.match(/\w+\tdevice/)) {
- WScript.Echo("Yes");
- return true;
- }
- WScript.Echo("No");
- return false;
-}
-function emulate() {
- // don't run emulator if a device is plugged in or if emulator is already running
- if(device_running()) {
- //WScript.Echo("Device or Emulator already running!");
- return;
- }
- var oExec = shell.Exec("%comspec% /c android.bat list avd");
- var avd_list = [];
- var avd_id = -10;
- while(!oExec.StdOut.AtEndOfStream) {
- var output = oExec.StdOut.ReadLine();
- if(output.match(/Name: (.)*/)) {
- avd_list.push(output.replace(/ *Name:\s/, ""));
- }
- }
- // user has no AVDs
- if(avd_list.length == 0) {
- WScript.Echo("You don't have any Android Virtual Devices. Please create at least one AVD.");
- WScript.Echo("android");
- WScript.Quit(1);
- }
- // user has only one AVD so we launch that one
- if(avd_list.length == 1) {
-
- shell.Run("emulator -cpu-delay 0 -no-boot-anim -cache %Temp%\cache -avd "+avd_list[0]);
- }
-
- // user has more than one avd so we ask them to choose
- if(avd_list.length > 1) {
- while(!avd_list[avd_id]) {
- WScript.Echo("Choose from one of the following Android Virtual Devices [0 to "+(avd_list.length - 1)+"]:")
- for(i = 0, j = avd_list.length ; i < j ; i++) {
- WScript.Echo((i)+") "+avd_list[i]);
- }
- WScript.StdOut.Write("> ");
- avd_id = new Number(WScript.StdIn.ReadLine());
- }
-
- shell.Run("emulator -cpu-delay 0 -no-boot-anim -cache %Temp%\\cache -avd "+avd_list[avd_id], 0, false);
- }
-}
-
-function clean() {
- WScript.Echo("Cleaning project...");
- exec("%comspec% /c ant.bat clean -f "+ROOT+"\\build.xml 2>&1");
-}
-
-function build() {
- WScript.Echo("Building project...");
- exec("%comspec% /c ant.bat debug -f "+ROOT+"\\build.xml 2>&1");
-}
-
-function install() {
- WScript.Echo("Building/Installing project...");
- exec("%comspec% /c ant.bat debug install -f "+ROOT+"\\build.xml 2>&1");
-}
-
-function log() {
- shell.Run("%comspec% /c adb logcat");
-}
-
-function launch() {
- WScript.Echo("Launching app...");
- var launch_str=exec("%comspec% /c java -jar "+ROOT+"\\cordova\\appinfo.jar "+ROOT+"\\AndroidManifest.xml");
- //WScript.Echo(launch_str);
- exec("%comspec% /c adb shell am start -n "+launch_str+" 2>&1");
-}
-
-function run() {
- var i=0;
- clean();
- emulate();
- WScript.Stdout.Write('Waiting for device...');
- while(!device_running() && i < 300) {
- WScript.Stdout.Write('.');
- WScript.sleep(1000);
- i += 1;
- }
- if(i == 300) {
- WScript.Stderr.WriteLine("device/emulator timeout!");
- } else {
- WScript.Stdout.WriteLine("connected!");
- }
- install();
- launch();
-}
-var args = WScript.Arguments;
-if(args.count() != 1) {
- WScript.StdErr.Write("An error has occured!\n");
- WScript.Quit(1);
-}
-eval(args(0)+"()");
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/templates/cordova/lib/cordova
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/cordova b/lib/cordova-android/bin/templates/cordova/lib/cordova
new file mode 100644
index 0000000..294df49
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/lib/cordova
@@ -0,0 +1,386 @@
+#!/bin/bash
+# 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.
+
+PROJECT_PATH=$( cd "$( dirname "$0" )/../.." && pwd )
+
+function list_devices {
+ IFS=$'\n'
+ devices=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep 'device' | grep -v 'emulator'`
+ device_list=($devices)
+ if [[ ${#device_list[@]} > 0 ]] ; then
+ for i in ${devices[@]}
+ do
+ # remove space and 'device'
+ echo ${i/[^a-zA-Z0-9._]device/}
+ done
+ else
+ echo "No devices found."
+ exit 2
+ fi
+}
+
+function list_started_emulators {
+ IFS=$'\n'
+ devices=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep 'device' | grep 'emulator'`
+ emulator_list=($devices)
+ if [[ ${#emulator_list[@]} > 0 ]] ; then
+ for i in ${emulator_list[@]}
+ do
+ # remove space and 'device'
+ echo ${i/[^a-zA-Z0-9._]device/}
+ done
+ else
+ echo "No started emulators found, you can start an emulator by using the command"
+ echo " 'cordova/lib/start-emulator'"
+ exit 2
+ fi
+}
+
+function list_emulator_images {
+ emulator_images=`android list avds | grep "Name:" | cut -f 2 -d ":"`
+ emulator_list=($emulator_images)
+ if [[ ${#emulator_list[@]} > 0 ]] ; then
+ for i in ${emulator_list[@]}
+ do
+ echo ${i/[^a-zA-Z0-9._]/}
+ done
+ else
+ echo "No emulators found, if you would like to create an emulator follow the instructions"
+ echo " provided here : http://developer.android.com/tools/devices/index.html"
+ echo " Or run 'android create avd --name <name> --target <targetID>' in on the command line."
+ exit 2
+ fi
+}
+
+function start_emulator {
+ emulator_images=`android list avds | grep "Name:" | cut -f 2 -d ":"`
+ # if target emulator is provided
+ if [[ "$#" -eq 1 ]] ; then
+ # check that it exists
+ if [[ $emulator_images =~ $1 ]] ; then
+ #xterm -e emulator -avd $1 &
+ emulator -avd $1 1> /dev/null 2>&1 &
+ else
+ echo "Could not find the provided emulator, make sure the emulator exists"
+ echo " by checking 'cordova/lib/list-emulator-images'"
+ exit 2
+ fi
+ else
+ # start first emulator
+ emulator_list=($emulator_images)
+ if [[ ${#emulator_list[@]} > 0 ]] ; then
+ #xterm -e emulator -avd ${emulator_list[0]} &
+ emulator -avd ${emulator_list[0]/[^a-zA-Z0-9._]/} 1> /dev/null 2>&1 &
+ else
+ echo "No emulators found, if you would like to create an emulator follow the instructions"
+ echo " provided here : http://developer.android.com/tools/devices/index.html"
+ echo " Or run 'android create avd --name <name> --target <targetID>' in on the command line."
+ exit 2
+ fi
+ fi
+}
+
+function install_device {
+ IFS=$'\n'
+ devices=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep 'device' | grep -v 'emulator'`
+ device_list=($devices)
+ if [[ ${#device_list[@]} > 0 ]] ; then
+ apks=`find $PROJECT_PATH/bin -type f -maxdepth 1 | egrep '\.apk$'`
+ apk_list=($apks)
+ if [[ ${#apk_list[@]} > 0 ]] ; then
+ local target
+ # handle target emulator
+ if [[ "$#" -eq 1 ]] ; then
+ # deploy to given target
+ target=${1/--target=/}
+ else
+ # delete trailing space and 'device' after device ID
+ target=${device_list[0]/[^a-zA-Z0-9._]device/}
+ fi
+ echo "Installing ${apk_list[0]} onto device $target..."
+ adb -s $target install -r ${apk_list[0]};
+ echo "Launching application..."
+ local launch_str=$(java -jar "$PROJECT_PATH"/cordova/appinfo.jar "$PROJECT_PATH"/AndroidManifest.xml)
+ adb -s $target shell am start -W -a android.intent.action.MAIN -n $launch_str
+ else
+ echo "Application package not found, could not install to device"
+ echo " make sure your application is built before deploying."
+ exit 2
+ fi
+ else
+ echo "No devices found to deploy to. Please make sure your device is connected"
+ echo " and you can view it using the 'cordova/lib/list-devices' command."
+ exit 2
+ fi
+}
+
+function install_emulator {
+ IFS=$'\n'
+ # check that there is an emulator to deploy to
+ emulator_string=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep 'emulator'`
+ emulator_list=($emulator_string)
+ if [[ ${#emulator_list[@]} > 0 ]] ; then
+ apks=`find $PROJECT_PATH/bin -type f -maxdepth 1 | egrep '\.apk$'`
+ apk_list=($apks)
+ if [[ ${#apk_list[@]} > 0 ]] ; then
+ local target
+ # handle target emulator
+ if [[ "$#" -eq 1 ]] ; then
+ # deploy to given target
+ target=${1/--target=/}
+ else
+ # delete trailing space and 'device' after emulator ID
+ target=${emulator_list[0]/[^a-zA-Z0-9._]device/}
+ fi
+ echo "Installing ${apk_list[0]} onto $target..."
+ adb -s $target install -r ${apk_list[0]};
+ echo "Launching application..."
+ local launch_str=$(java -jar "$PROJECT_PATH"/cordova/appinfo.jar "$PROJECT_PATH"/AndroidManifest.xml)
+ adb -s $target shell am start -W -a android.intent.action.MAIN -n $launch_str
+
+ else
+ echo "Application package not found, could not install to device"
+ echo " make sure your application is built before deploying."
+ exit 2
+ fi
+ else
+ echo "No emulators found to deploy to. Please make sure your emulator is started"
+ echo " and you can view it using the 'cordova/lib/list-started-emulators' command."
+ exit 2
+ fi
+}
+
+# cleans the project
+function clean {
+ echo "Cleaning project..."
+ ant clean
+}
+
+# has to be used independently and not in conjunction with other commands
+function log {
+ # filter out nativeGetEnabledTags spam from latest sdk bug.
+ adb logcat | grep -v nativeGetEnabledTags
+}
+
+
+function build {
+ if [[ "$#" -eq 1 ]] ; then
+ if [[ $1 == "--debug" ]] ; then
+ clean
+ ant debug -f "$PROJECT_PATH"/build.xml
+ elif [[ $1 == "--release" ]] ; then
+ clean
+ ant release -f "$PROJECT_PATH"/build.xml
+ elif [[ $1 == "--nobuild" ]] ; then
+ echo "Skipping build..."
+ else
+ echo "Error : Build command '$1' not recognized."
+ exit 2
+ fi
+ else
+ echo "Warning : [ --debug | --release | --nobuild ] not specified, defaulting to --debug"
+ clean
+ ant debug -f "$PROJECT_PATH"/build.xml
+ fi
+}
+
+
+function wait_for_emulator {
+ emulator_string=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep 'device' | grep 'emulator'`
+ old_started=($emulator_string)
+ local new_started
+ local new_emulator_name
+ local i="0"
+ echo -n "Waiting for emulator..."
+ while [ $i -lt 300 ]
+ do
+ emulator_string=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep 'device' | grep 'emulator'`
+ new_started=($emulator_string)
+ if [[ ${#new_started[@]} > ${#old_started[@]} && -z "$new_emulator_name" ]] ; then
+ # get the name of the started emulator
+ local count="0"
+ if [[ ${#old_started[@]} == 0 ]] ; then
+ new_emulator_name=${new_started[$count]/[^a-zA-Z0-9._]device/}
+ else
+ for count in {0...${#old_started[@]}}
+ do
+ if [[ ! ${new_started[$count]} == ${old_started[$count]} ]] ; then
+ new_emulator_name=${new_started[$count]/[^a-zA-Z0-9._]device/}
+ fi
+ done
+ if [[ -z "$new_emulator_name" ]] ; then
+ count=$[count+1]
+ new_emulator_name=${new_started[$count]/[^a-zA-Z0-9._]device/}
+ fi
+ fi
+ elif [[ "$new_emulator_name" ]] ; then
+ boot_anim=`adb -s $new_emulator_name shell getprop init.svc.bootanim`
+ if [[ $boot_anim =~ "stopped" ]] ; then
+ break
+ else
+ sleep 1
+ i=$[i+1]
+ echo -n "."
+ fi
+ else
+ sleep 1
+ i=$[i+1]
+ echo -n "."
+ fi
+ done
+ # Device timeout: emulator has not started in time
+ if [ $i -eq 300 ]
+ then
+ echo "emulator timeout!"
+ exit 69
+ else
+ echo "connected!"
+ fi
+}
+
+function run {
+ IFS=$'\n'
+ if [[ "$#" -eq 2 ]] ; then
+ build $2
+ if [[ $1 == "--device" ]] ; then
+ install_device
+ elif [[ $1 == "--emulator" ]] ; then
+ install_emulator
+ elif [[ $1 =~ "--target=" ]]; then
+ install_device $1
+ else
+ echo "Error : '$1' is not recognized as an install option"
+ fi
+ elif [[ "$#" -eq 1 ]] ; then
+ if [[ $1 == "--debug" || $1 == "--release" || $1 == "--nobuild" ]] ; then
+ build $1
+ elif [[ $1 == "--device" ]] ; then
+ install_device
+ elif [[ $1 == "--emulator" ]] ; then
+ install_emulator
+ elif [[ $1 =~ "--target=" ]]; then
+ install_device $1
+ else
+ echo "Error : '$1' is not recognized as an install option"
+ fi
+ else
+ echo "Warning : [ --device | --emulate | --target=<targetID> ] not specified, using defaults."
+ build
+ devices=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep 'device' | grep -v 'emulator'`
+ device_list=($devices)
+ emulator_string=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep 'device' | grep 'emulator'`
+ emulator_list=($emulator_string)
+ if [[ ${#device_list[@]} > 0 ]] ; then
+ install_device
+ elif [[ ${#emulator_list[@]} > 0 ]] ; then
+ install_emulator
+ else
+ emulator_images=`android list avds | grep "Name:" | cut -f 2 -d ":"`
+ echo $emulator_images
+ emulator_image_list=($emulator_images)
+ if [[ ${#emulator_image_list[@]} > 0 ]] ; then
+ echo "Starting emulator : ${emulator_image_list[0]}"
+ emulator -avd ${emulator_image_list[0]/[^.\w]/} 1> /dev/null 2>&1 &
+ wait_for_emulator
+ install_emulator
+ else
+ # TODO : look for emulator images and start one if it's availible
+ echo "Error : there are no availible devices or emulators to deploy to."
+ echo " create an emulator or connect your device to run this command."
+ echo "If you would like to create an emulator follow the instructions"
+ echo " provided here : http://developer.android.com/tools/devices/index.html"
+ echo " Or run 'android create avd --name <name> --target <targetID>' in on the command line."
+ exit 2
+ fi
+ fi
+ fi
+}
+
+# parse command line arguments
+
+if [[ $# > 3 ]] ; then
+ echo "Error : too many arguments."
+ exit 2
+elif [[ $# == 3 ]] ; then
+ if [[ $1 == "run" ]] ; then
+ run $2 $3
+ else
+ echo "Error : too many arguments for '$1'"
+ exit 2
+ fi
+elif [[ $# == 2 ]] ; then
+ if [[ $1 == "run" ]] ; then
+ if [[ $2 == "--emulator" || $2 == "--device" || $2 =~ "--target=" ]] ; then
+ run $2 ''
+ elif [[ $2 == "--debug" || $2 == "--release" || $2 == "--nobuild" ]] ; then
+ run '' $2
+ else
+ echo "Error : '$2' is not recognized as a run option."
+ exit 2
+ fi
+ elif [[ $1 == "build" ]] ; then
+ build $2
+ elif [[ $1 == "start-emulator" ]] ; then
+ start_emulator $2
+ elif [[ $1 == "install-device" ]] ; then
+ if [[ $2 =~ "--target=" ]] ; then
+ install_device $2
+ else
+ echo "Error : '$2' is not recognized as an install option"
+ exit 2
+ fi
+ elif [[ $1 == "install-emulator" ]] ; then
+ if [[ $2 =~ "--target=" ]] ; then
+ install_emulator $2
+ else
+ echo "Error : '$2' is not recognized as an install option"
+ exit 2
+ fi
+ else
+ echo "Error : '$1' is not recognized as an option that takes arguments"
+ exit 2
+ fi
+elif [[ $# == 1 ]] ; then
+ if [[ $1 == "run" ]] ; then
+ run
+ elif [[ $1 == "build" ]]; then
+ build
+ elif [[ $1 == "clean" ]]; then
+ clean
+ elif [[ $1 == "log" ]]; then
+ log
+ elif [[ $1 == "list-devices" ]]; then
+ list_devices
+ elif [[ $1 == "list-emulator-images" ]]; then
+ list_emulator_images
+ elif [[ $1 == "list-started-emulators" ]]; then
+ list_started_emulators
+ elif [[ $1 == "install-device" ]]; then
+ install_device
+ elif [[ $1 == "install-emulator" ]]; then
+ install_emulator
+ elif [[ $1 == "start-emulator" ]]; then
+ start_emulator
+ else
+ echo "Error : '$1' is not recognized as a tooling command."
+ exit 2
+ fi
+else
+ echo "Error : No command recieved, exiting..."
+ exit 2
+fi
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/templates/cordova/lib/cordova.js
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/cordova.js b/lib/cordova-android/bin/templates/cordova/lib/cordova.js
new file mode 100644
index 0000000..28f9b3e
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/lib/cordova.js
@@ -0,0 +1,593 @@
+// 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.
+
+var ROOT = WScript.ScriptFullName.split('\\cordova\\lib\\cordova.js').join(''),
+ shell = WScript.CreateObject("WScript.Shell"),
+ fso = WScript.CreateObject('Scripting.FileSystemObject');
+
+
+// log to stdout or stderr
+function Log(msg, error) {
+ if (error) {
+ WScript.StdErr.WriteLine(msg);
+ }
+ else {
+ WScript.StdOut.WriteLine(msg);
+ }
+}
+
+// executes a commmand in the shell, returning stdout
+function exec(command) {
+ var oExec=shell.Exec(command);
+ var output = new String();
+ while (oExec.Status == 0) {
+ if (!oExec.StdOut.AtEndOfStream) {
+ var line = oExec.StdOut.ReadLine();
+ output += line;
+ }
+ WScript.sleep(100);
+ }
+ return output;
+}
+
+// executes a command in the shell, returns stdout or stderr if error
+function exec_out(command) {
+ var oExec=shell.Exec(command);
+ var output = new String();
+ while (oExec.Status == 0) {
+ if (!oExec.StdOut.AtEndOfStream) {
+ var line = oExec.StdOut.ReadLine();
+ // XXX: Change to verbose mode
+ // WScript.StdOut.WriteLine(line);
+ output += line;
+ }
+ WScript.sleep(100);
+ }
+ //Check to make sure our scripts did not encounter an error
+ if (!oExec.StdErr.AtEndOfStream) {
+ var line = oExec.StdErr.ReadAll();
+ return {'error' : true, 'output' : line};
+ }
+ return {'error' : false, 'output' : output};
+}
+
+// executes a commmand in the shell and outputs stdout and fails on stderr
+function exec_verbose(command) {
+ //Log("Command: " + command);
+ var oShell=shell.Exec(command);
+ while (oShell.Status == 0) {
+ //Wait a little bit so we're not super looping
+ WScript.sleep(100);
+ //Print any stdout output from the script
+ if (!oShell.StdOut.AtEndOfStream) {
+ var line = oShell.StdOut.ReadLine();
+ Log(line);
+ }
+ }
+ //Check to make sure our scripts did not encounter an error
+ if (!oShell.StdErr.AtEndOfStream) {
+ var line = oShell.StdErr.ReadAll();
+ Log(line, true);
+ WScript.Quit(2);
+ }
+}
+
+function get_devices() {
+ var device_list = []
+ var local_devices = shell.Exec("%comspec% /c adb devices").StdOut.ReadAll();
+ if (local_devices.match(/\w+\tdevice/)) {
+ devices = local_devices.split('\r\n');
+ //format (ID DESCRIPTION)
+ for (i in devices) {
+ if (devices[i].match(/\w+\tdevice/) && !devices[i].match(/emulator/)) {
+ device_list.push(devices[i].replace(/\t/, ' '));
+ }
+ }
+ }
+ return device_list
+}
+
+function list_devices() {
+ var devices = get_devices();
+ if (devices.length > 0) {
+ for (i in devices) {
+ Log(devices[i]);
+ }
+ }
+ else {
+ Log('No devices found, if your device is connected and not showing,');
+ Log(' then try and install the drivers for your device.');
+ Log(' http://developer.android.com/tools/extras/oem-usb.html');
+ }
+
+}
+
+function get_emulator_images() {
+ // discription contains all data recieved squashed onto one line
+ var add_description = true;
+ var avd_list = [];
+ var local_emulators = shell.Exec("%comspec% /c android list avds").StdOut.ReadAll();
+ if (local_emulators.match(/Name\:/)) {
+ emulators = local_emulators.split('\n');
+ //format (ID DESCRIPTION)
+ var count = 0;
+ var output = '';
+ for (i in emulators) {
+ if (emulators[i].match(/Name\:/)) {
+ var emulator_name = emulators[i].replace(/\s*Name\:\s/, '') + ' ';
+ if (add_description) {
+ count = 1;
+ output += emulator_name
+ }
+ else {
+ avd_list.push(emulator_name);
+ }
+ }
+ // add description if indicated (all data squeezed onto one line)
+ if (count > 0) {
+ var emulator_description = emulators[i].replace(/\s*/g, '');
+ if (count > 4) {
+ avd_list.push(output + emulator_description);
+ count = 0;
+ output = '';
+ }
+ else {
+ count++;
+ output += emulator_description + ' '
+ }
+ }
+ }
+ }
+ return avd_list;
+}
+
+function list_emulator_images() {
+ var images = get_emulator_images();
+ if (images.length > 0) {
+ for(i in images) {
+ Log(images[i]);
+ }
+ }
+ else {
+ Log('No emulators found, if you would like to create an emulator follow the instructions');
+ Log(' provided here : http://developer.android.com/tools/devices/index.html');
+ Log(' Or run \'android create avd --name <name> --target <targetID>\' in on the command line.');
+ }
+}
+
+function get_started_emulators() {
+ var started_emulators = [];
+ var local_devices = shell.Exec("%comspec% /c adb devices").StdOut.ReadAll();
+ if (local_devices.match(/emulator/)) {
+ devices = local_devices.split('\r\n');
+ //format (ID DESCRIPTION)
+ for (i in devices) {
+ if (devices[i].match(/\w+\tdevice/) && devices[i].match(/emulator/)) {
+ started_emulators.push(devices[i].replace(/\t/, ' '));
+ }
+ }
+ }
+ return started_emulators
+}
+
+function list_started_emulators() {
+ var images = get_started_emulators();
+ if (images.length > 0) {
+ for(i in images) {
+ Log(images[i]);
+ }
+ }
+ else {
+ Log('No started emulators found, if you would like to start an emulator call \'list-emulator-images\'');
+ Log(' to get the name of an emulator and then start the emulator with \'start-emulator <Name>\'');
+ }
+}
+
+function start_emulator(name) {
+ var emulators = get_emulator_images();
+ var started_emulators = get_started_emulators();
+ var num_started = started_emulators.length;
+ var emulator_name;
+ var started = false;
+ if (name) {
+ for (i in emulators) {
+ if (emulators[i].substr(0,name.length) == name) {
+ Log("Starting emulator : " + name);
+ shell.Run("%comspec% /c start cmd /c emulator -avd " + name);
+ //shell.Run("%comspec% /c start cmd /c emulator -cpu-delay 0 -no-boot-anim -cache %Temp%\cache -avd " + name);
+ started = true;
+ }
+ }
+ }
+ else {
+ if (emulators.length > 0 && started_emulators < 1) {
+ emulator_name = emulators[0].split(' ', 1)[0];
+ start_emulator(emulator_name);
+ return;
+ } else if (started_emulators.length > 0) {
+ Log("Emulator already started : " + started_emulators[0].split(' ', 1));
+ return;
+ } else {
+ Log("Error : unable to start emulator, ensure you have emulators availible by checking \'list-emulator-images\'", true);
+ WScript.Quit(2);
+ }
+ }
+ if (!started) {
+ Log("Error : unable to start emulator, ensure you have emulators availible by checking \'list-emulator-images\'", true);
+ WScript.Quit(2);
+ }
+ else { // wait for emulator to boot before returning
+ WScript.Stdout.Write('Booting up emulator..');
+ var boot_anim = null;
+ var emulator_ID = null;
+ var new_started = get_started_emulators();
+ var i = 0;
+ // use boot animation property to tell when boot is complete.
+ while ((boot_anim == null || !boot_anim.output.match(/stopped/)) && i < 100) {
+ if (new_started.length > started_emulators.length && emulator_ID == null) {
+ // find new emulator that was just started to get it's ID
+ for(var i = 0; i < new_started.length; i++) {
+ if (new_started[i] != started_emulators[i]) {
+ emulator_ID = new_started[i].split(' ', 1)[0];
+ boot_anim = exec_out('%comspec% /c adb -s ' + emulator_ID + ' shell getprop init.svc.bootanim');
+ break;
+ }
+ }
+ }
+ else if (boot_anim == null) {
+ new_started = get_started_emulators();
+ }
+ else {
+ boot_anim = exec_out('%comspec% /c adb -s ' + emulator_ID + ' shell getprop init.svc.bootanim');
+ }
+ i++;
+ WScript.Stdout.Write('.');
+ WScript.Sleep(2000);
+ }
+ if (i < 100) {
+ Log('\nBoot Complete!');
+ } else {
+ Log('\nEmulator boot timed out. Failed to load emulator');
+ WScript.Quit(2);
+ }
+ }
+}
+
+function install_device(target) {
+ var devices = get_devices();
+ var use_target = false;
+ if (devices.length < 1) {
+ Log("Error : No devices found to install to, make sure there are devices", true);
+ Log(" availible by checking \'<project_dir>\\cordova\\lib\\list-devices\'", true);
+ WScript.Quit(2);
+ }
+ if (target) {
+ var exists = false;
+ for (i in devices) {
+ if (devices[i].substr(0,target.length) == target)
+ {
+ exists = true;
+ break;
+ }
+ }
+ if (!exists) {
+ Log("Error : Unable to find target " + target, true);
+ Log("Please ensure the target exists by checking \'<project>\\cordova\\lib\\list-devices'");
+ WScript.Quit(2);
+ }
+ use_target = true;
+ }
+ // check if file .apk has been created
+ if (fso.FolderExists(ROOT + '\\bin')) {
+ var path_to_apk;
+ var out_folder = fso.GetFolder(ROOT + '\\bin');
+ var out_files = new Enumerator(out_folder.Files);
+ for (;!out_files.atEnd(); out_files.moveNext()) {
+ var path = out_files.item() + '';
+ if (fso.GetExtensionName(path) == 'apk' && !path.match(/unaligned/)) {
+ path_to_apk = out_files.item();
+ break;
+ }
+ }
+ if (path_to_apk) {
+ var launch_name = exec_out("%comspec% /c java -jar "+ROOT+"\\cordova\\appinfo.jar "+ROOT+"\\AndroidManifest.xml");
+ if (launch_name.error) {
+ Log("Failed to get application name from appinfo.jar + AndroidManifest : ", true);
+ Log("Output : " + launch_name.output, true);
+ WScript.Quit(2);
+ }
+ // install on device (-d)
+ Log("Installing app on device...");
+ var cmd;
+ if (use_target) {
+ cmd = '%comspec% /c adb -s ' + target + ' install -r ' + path_to_apk;
+ } else {
+ cmd = '%comspec% /c adb -s ' + devices[0].split(' ', 1)[0] + ' install -r ' + path_to_apk;
+ }
+ var install = exec_out(cmd);
+ if ( install.error && install.output.match(/Failure/)) {
+ Log("Error : Could not install apk to device : ", true);
+ Log(install.output, true);
+ WScript.Quit(2);
+ }
+ else {
+ Log(install.output);
+ }
+ // run on device
+ Log("Launching application...");
+ cmd;
+ if (use_target) {
+ cmd = '%comspec% /c adb -s ' + target + ' shell am start -W -a android.intent.action.MAIN -n ' + launch_name.output;
+ } else {
+ cmd = '%comspec% /c adb -s ' + devices[0].split(' ', 1)[0] + ' shell am start -W -a android.intent.action.MAIN -n ' + launch_name.output;
+ }
+ exec_verbose(cmd);
+ }
+ else {
+ Log('Failed to find apk, make sure you project is built and there is an ', true);
+ Log(' apk in <project>\\bin\\. To build your project use \'<project>\\cordova\\build\'', true);
+ WScript.Quit(2);
+ }
+ }
+}
+
+function install_emulator(target) {
+ var emulators = get_started_emulators();
+ var use_target = false;
+ if (emulators.length < 1) {
+ Log("Error : No emulators found to install to, make sure there are emulators", true);
+ Log(" availible by checking \'<project_dir>\\cordova\\lib\\list-started-emulators\'", true);
+ WScript.Quit(2);
+ }
+ if (target) {
+ var exists = false;
+ for (i in emulators) {
+ if (emulators[i].substr(0,target.length) == target)
+ {
+ exists = true;
+ break;
+ }
+ }
+ if (!exists) {
+ Log("Error : Unable to find target " + target, true);
+ Log("Please ensure the target exists by checking \'<project>\\cordova\\lib\\list-started-emulators'")
+ }
+ use_target = true;
+ } else {
+ target = emulators[0].split(' ', 1)[0];
+ Log("Deploying to emulator : " + target);
+ }
+ // check if file .apk has been created
+ if (fso.FolderExists(ROOT + '\\bin')) {
+ var path_to_apk;
+ var out_folder = fso.GetFolder(ROOT + '\\bin');
+ var out_files = new Enumerator(out_folder.Files);
+ for (;!out_files.atEnd(); out_files.moveNext()) {
+ var path = out_files.item() + '';
+ if (fso.GetExtensionName(path) == 'apk' && !path.match(/unaligned/)) {
+ path_to_apk = out_files.item();
+ break;
+ }
+ }
+ if (path_to_apk) {
+ var launch_name = exec_out("%comspec% /c java -jar "+ROOT+"\\cordova\\appinfo.jar "+ROOT+"\\AndroidManifest.xml");
+ if (launch_name.error) {
+ Log("Failed to get application name from appinfo.jar + AndroidManifest : ", true);
+ Log("Output : " + launch_name.output, true);
+ WScript.Quit(2);
+ }
+ // install on emulator (-e)
+ Log("Installing app on emulator...");
+ var cmd = '%comspec% /c adb -s ' + target + ' install -r ' + path_to_apk;
+ var install = exec_out(cmd);
+ if ( install.error && install.output.match(/Failure/)) {
+ Log("Error : Could not install apk to emulator : ", true);
+ Log(install.output, true);
+ WScript.Quit(2);
+ }
+ else {
+ Log(install.output);
+ }
+ // run on emulator
+ Log("Launching application...");
+ cmd;
+ if (use_target) {
+ cmd = '%comspec% /c adb -s ' + target + ' shell am start -W -a android.intent.action.MAIN -n ' + launch_name.output;
+ } else {
+ cmd = '%comspec% /c adb -s ' + emulators[0].split(' ', 1)[0] + ' shell am start -W -a android.intent.action.MAIN -n ' + launch_name.output
+ }
+ exec_verbose(cmd);
+ }
+ else {
+ Log('Failed to find apk, make sure you project is built and there is an ', true);
+ Log(' apk in <project>\\bin\\. To build your project use \'<project>\\cordova\\build\'', true);
+ WScript.Quit(2);
+ }
+ }
+ else {
+ Log('Failed to find apk, make sure you project is built and there is an ', true);
+ Log(' apk in <project>\\bin\\. To build your project use \'<project>\\cordova\\build\'', true);
+ WScript.Quit(2);
+ }
+}
+
+function clean() {
+ Log("Cleaning project...");
+ exec("%comspec% /c ant.bat clean -f "+ROOT+"\\build.xml 2>&1");
+}
+
+function build(build_type) {
+ if (build_type) {
+ switch (build_type) {
+ case "--debug" :
+ clean();
+ Log("Building project...");
+ exec_verbose("%comspec% /c ant.bat debug -f "+ROOT+"\\build.xml 2>&1");
+ break;
+ case "--release" :
+ clean();
+ Log("Building project...");
+ exec_verbose("%comspec% /c ant.bat release -f "+ROOT+"\\build.xml 2>&1");
+ break;
+ case "--nobuild" :
+ Log("Skipping build process.");
+ break;
+ default :
+ Log("Build option not recognized: " + build_type, true);
+ WScript.Quit(2);
+ break;
+ }
+ }
+ else {
+ Log("WARNING: [ --debug | --release | --nobuild ] not specified, defaulting to --debug.");
+ exec_verbose("%comspec% /c ant.bat debug -f "+ROOT+"\\build.xml 2>&1");
+ }
+}
+
+function log() {
+ // filter out nativeGetEnabledTags spam from latest sdk bug.
+ shell.Run("%comspec% /c adb logcat | grep -v nativeGetEnabledTags");
+}
+
+function run(target, build_type) {
+ var use_target = false;
+ if (!target) {
+ Log("WARNING: [ --target=<ID> | --emulator | --device ] not specified, using defaults");
+ }
+ // build application
+ build(build_type);
+ // attempt to deploy to connected device
+ var devices = get_devices();
+ if (devices.length > 0 || target == "--device") {
+ if (target) {
+ if (target.substr(0,9) == "--target=") {
+ install_device(target.split('--target=').join(''))
+ } else if (target == "--device") {
+ install_device();
+ } else {
+ Log("Did not regognize " + target + " as a run option.", true);
+ WScript.Quit(2);
+ }
+ }
+ else {
+ Log("WARNING: [ --target=<ID> | --emulator | --device ] not specified, using defaults");
+ install_device();
+ }
+ }
+ else {
+ var emulators = get_started_emulators();
+ if (emulators.length > 0) {
+ install_emulator();
+ }
+ else {
+ var emulator_images = get_emulator_images();
+ if (emulator_images.length < 1) {
+ Log('No emulators found, if you would like to create an emulator follow the instructions', true);
+ Log(' provided here : http://developer.android.com/tools/devices/index.html', true);
+ Log(' Or run \'android create avd --name <name> --target <targetID>\' in on the command line.', true);
+ WScript.Quit(2);
+ }
+ start_emulator(emulator_images[0].split(' ')[0]);
+ emulators = get_started_emulators();
+ if (emulators.length > 0) {
+ install_emulator();
+ }
+ else {
+ Log("Error : emulator failed to start.", true);
+ WScript.Quit(2);
+ }
+ }
+ }
+}
+
+var args = WScript.Arguments;
+if (args.count() == 0) {
+ Log("Error: no args provided.");
+ WScript.Quit(2);
+}
+else {
+ if (args(0) == "build") {
+ if (args.Count() > 1) {
+ build(args(1))
+ } else {
+ build();
+ }
+ } else if (args(0) == "clean") {
+ clean();
+ } else if (args(0) == "list-devices") {
+ list_devices();
+ } else if (args(0) == "list-emulator-images") {
+ list_emulator_images();
+ } else if (args(0) == "list-started-emulators") {
+ list_started_emulators();
+ } else if (args(0) == "start-emulator") {
+ if (args.Count() > 1) {
+ start_emulator(args(1))
+ } else {
+ start_emulator();
+ }
+ } else if (args(0) == "log") {
+ log();
+ } else if (args(0) == "install-emulator") {
+ if (args.Count() == 2) {
+ if (args(1).substr(0,9) == "--target=") {
+ install_emulator(args(1).split('--target=').join(''));
+ } else {
+ Log('Error: \"' + args(1) + '\" is not recognized as an install option', true);
+ WScript.Quit(2);
+ }
+ } else {
+ install_emulator();
+ }
+ } else if (args(0) == "install-device") {
+ if (args.Count() == 2) {
+ if (args(1).substr(0,9) == "--target=") {
+ install_device(args(1).split('--target=').join(''));
+ } else {
+ Log('Error: \"' + args(1) + '\" is not recognized as an install option', true);
+ WScript.Quit(2);
+ }
+ } else {
+ install_device();
+ }
+ } else if (args(0) == "run") {
+ if (args.Count() == 3) {
+ run(args(1), args(2));
+ }
+ else if (args.Count() == 2) {
+ if (args(1).substr(0,9) == "--target=" ||
+ args(1) == "--emulator" ||
+ args(1) == "--device") {
+ run(args(1));
+ } else if (args(1) == "--debug" ||
+ args(1) == "--release" ||
+ args(1) == "--nobuild") {
+ run(null, args(1))
+ } else {
+ Log('Error: \"' + args(1) + '\" is not recognized as a run option', true);
+ WScript.Quit(2);
+ }
+ }
+ else {
+ run();
+ }
+ } else {
+ Log('Error: \"' + args(0) + '\" is not recognized as a tooling command', true);
+ WScript.Quit(2);
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/templates/cordova/lib/install-device
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/install-device b/lib/cordova-android/bin/templates/cordova/lib/install-device
new file mode 100644
index 0000000..604b5ae
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/lib/install-device
@@ -0,0 +1,23 @@
+#!/bin/bash
+# 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.
+
+set -e
+
+CORDOVA_LIB_PATH=$( cd "$( dirname "$0" )" && pwd )
+
+bash "$CORDOVA_LIB_PATH"/cordova install-device "$@"
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/templates/cordova/lib/install-device.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/install-device.bat b/lib/cordova-android/bin/templates/cordova/lib/install-device.bat
new file mode 100644
index 0000000..52d9775
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/lib/install-device.bat
@@ -0,0 +1,9 @@
+@ECHO OFF
+SET full_path=%~dp0
+IF EXIST %full_path%cordova.js (
+ cscript "%full_path%cordova.js" install-device %* //nologo
+) ELSE (
+ ECHO.
+ ECHO ERROR: Could not find 'cordova.js' in cordova/lib, aborting...>&2
+ EXIT /B 1
+)
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/templates/cordova/lib/install-emulator
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/install-emulator b/lib/cordova-android/bin/templates/cordova/lib/install-emulator
new file mode 100644
index 0000000..105e2ee
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/lib/install-emulator
@@ -0,0 +1,23 @@
+#!/bin/bash
+# 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.
+
+set -e
+
+CORDOVA_LIB_PATH=$( cd "$( dirname "$0" )" && pwd )
+
+bash "$CORDOVA_LIB_PATH"/cordova install-emulator "$@"
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/templates/cordova/lib/install-emulator.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/install-emulator.bat b/lib/cordova-android/bin/templates/cordova/lib/install-emulator.bat
new file mode 100644
index 0000000..d11a7be
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/lib/install-emulator.bat
@@ -0,0 +1,9 @@
+@ECHO OFF
+SET full_path=%~dp0
+IF EXIST %full_path%cordova.js (
+ cscript "%full_path%cordova.js" install-emulator %* //nologo
+) ELSE (
+ ECHO.
+ ECHO ERROR: Could not find 'cordova.js' in cordova/lib, aborting...>&2
+ EXIT /B 1
+)
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/templates/cordova/lib/list-devices
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/list-devices b/lib/cordova-android/bin/templates/cordova/lib/list-devices
new file mode 100644
index 0000000..7a5b2f5
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/lib/list-devices
@@ -0,0 +1,23 @@
+#!/bin/bash
+# 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.
+
+set -e
+
+CORDOVA_LIB_PATH=$( cd "$( dirname "$0" )" && pwd )
+
+bash "$CORDOVA_LIB_PATH"/cordova list-devices
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/templates/cordova/lib/list-devices.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/list-devices.bat b/lib/cordova-android/bin/templates/cordova/lib/list-devices.bat
new file mode 100644
index 0000000..c146f10
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/lib/list-devices.bat
@@ -0,0 +1,9 @@
+@ECHO OFF
+SET full_path=%~dp0
+IF EXIST %full_path%cordova.js (
+ cscript "%full_path%cordova.js" list-devices //nologo
+) ELSE (
+ ECHO.
+ ECHO ERROR: Could not find 'cordova.js' in cordova/lib, aborting...>&2
+ EXIT /B 1
+)
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/templates/cordova/lib/list-emulator-images
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/list-emulator-images b/lib/cordova-android/bin/templates/cordova/lib/list-emulator-images
new file mode 100644
index 0000000..db8e563
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/lib/list-emulator-images
@@ -0,0 +1,23 @@
+#!/bin/bash
+# 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.
+
+set -e
+
+CORDOVA_LIB_PATH=$( cd "$( dirname "$0" )" && pwd )
+
+bash "$CORDOVA_LIB_PATH"/cordova list-emulator-images
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/bin/templates/cordova/lib/list-emulator-images.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/list-emulator-images.bat b/lib/cordova-android/bin/templates/cordova/lib/list-emulator-images.bat
new file mode 100644
index 0000000..172520b
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/lib/list-emulator-images.bat
@@ -0,0 +1,9 @@
+@ECHO OFF
+SET full_path=%~dp0
+IF EXIST %full_path%cordova.js (
+ cscript "%full_path%cordova.js" list-emulator-images //nologo
+) ELSE (
+ ECHO.
+ ECHO ERROR: Could not find 'cordova.js' in cordova/lib, aborting...>&2
+ EXIT /B 1
+)
\ No newline at end of file
[19/37] Add WP7 and WP8 platform files.
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/Camera.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/Camera.cs b/lib/cordova-wp8/templates/standalone/Plugins/Camera.cs
new file mode 100644
index 0000000..5ff8045
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/Camera.cs
@@ -0,0 +1,490 @@
+/*
+ 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.Collections.Generic;
+using Microsoft.Phone.Tasks;
+using System.Runtime.Serialization;
+using System.IO;
+using System.IO.IsolatedStorage;
+using System.Windows.Media.Imaging;
+using Microsoft.Phone;
+using Microsoft.Xna.Framework.Media;
+using System.Diagnostics;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ public class Camera : BaseCommand
+ {
+
+ /// <summary>
+ /// Return base64 encoded string
+ /// </summary>
+ private const int DATA_URL = 0;
+
+ /// <summary>
+ /// Return file uri
+ /// </summary>
+ private const int FILE_URI = 1;
+
+ /// <summary>
+ /// Choose image from picture library
+ /// </summary>
+ private const int PHOTOLIBRARY = 0;
+
+ /// <summary>
+ /// Take picture from camera
+ /// </summary>
+
+ private const int CAMERA = 1;
+
+ /// <summary>
+ /// Choose image from picture library
+ /// </summary>
+ private const int SAVEDPHOTOALBUM = 2;
+
+ /// <summary>
+ /// Take a picture of type JPEG
+ /// </summary>
+ private const int JPEG = 0;
+
+ /// <summary>
+ /// Take a picture of type PNG
+ /// </summary>
+ private const int PNG = 1;
+
+ /// <summary>
+ /// Folder to store captured images
+ /// </summary>
+ private const string isoFolder = "CapturedImagesCache";
+
+ /// <summary>
+ /// Represents captureImage action options.
+ /// </summary>
+ [DataContract]
+ public class CameraOptions
+ {
+ /// <summary>
+ /// Source to getPicture from.
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "sourceType")]
+ public int PictureSourceType { get; set; }
+
+ /// <summary>
+ /// Format of image that returned from getPicture.
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "destinationType")]
+ public int DestinationType { get; set; }
+
+ /// <summary>
+ /// Quality of saved image
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "quality")]
+ public int Quality { get; set; }
+
+ /// <summary>
+ /// Controls whether or not the image is also added to the device photo album.
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "saveToPhotoAlbum")]
+ public bool SaveToPhotoAlbum { get; set; }
+
+ /// <summary>
+ /// Ignored
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "correctOrientation")]
+ public bool CorrectOrientation { get; set; }
+
+
+
+ /// <summary>
+ /// Ignored
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "allowEdit")]
+ public bool AllowEdit { get; set; }
+
+ /// <summary>
+ /// Height in pixels to scale image
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "encodingType")]
+ public int EncodingType { get; set; }
+
+ /// <summary>
+ /// Height in pixels to scale image
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "mediaType")]
+ public int MediaType { get; set; }
+
+
+ /// <summary>
+ /// Height in pixels to scale image
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "targetHeight")]
+ public int TargetHeight { get; set; }
+
+
+ /// <summary>
+ /// Width in pixels to scale image
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "targetWidth")]
+ public int TargetWidth { get; set; }
+
+ /// <summary>
+ /// Creates options object with default parameters
+ /// </summary>
+ public CameraOptions()
+ {
+ this.SetDefaultValues(new StreamingContext());
+ }
+
+ /// <summary>
+ /// Initializes default values for class fields.
+ /// Implemented in separate method because default constructor is not invoked during deserialization.
+ /// </summary>
+ /// <param name="context"></param>
+ [OnDeserializing()]
+ public void SetDefaultValues(StreamingContext context)
+ {
+ PictureSourceType = CAMERA;
+ DestinationType = FILE_URI;
+ Quality = 80;
+ TargetHeight = -1;
+ TargetWidth = -1;
+ SaveToPhotoAlbum = false;
+ CorrectOrientation = true;
+ AllowEdit = false;
+ MediaType = -1;
+ EncodingType = -1;
+ }
+ }
+
+ /// <summary>
+ /// Used to open photo library
+ /// </summary>
+ PhotoChooserTask photoChooserTask;
+
+ /// <summary>
+ /// Used to open camera application
+ /// </summary>
+ CameraCaptureTask cameraTask;
+
+ /// <summary>
+ /// Camera options
+ /// </summary>
+ CameraOptions cameraOptions;
+
+ public void takePicture(string options)
+ {
+ try
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+ // ["quality", "destinationType", "sourceType", "targetWidth", "targetHeight", "encodingType",
+ // "mediaType", "allowEdit", "correctOrientation", "saveToPhotoAlbum" ]
+ this.cameraOptions = new CameraOptions();
+ this.cameraOptions.Quality = int.Parse(args[0]);
+ this.cameraOptions.DestinationType = int.Parse(args[1]);
+ this.cameraOptions.PictureSourceType = int.Parse(args[2]);
+ this.cameraOptions.TargetWidth = int.Parse(args[3]);
+ this.cameraOptions.TargetHeight = int.Parse(args[4]);
+ this.cameraOptions.EncodingType = int.Parse(args[5]);
+ this.cameraOptions.MediaType = int.Parse(args[6]);
+ this.cameraOptions.AllowEdit = bool.Parse(args[7]);
+ this.cameraOptions.CorrectOrientation = bool.Parse(args[8]);
+ this.cameraOptions.SaveToPhotoAlbum = bool.Parse(args[9]);
+
+ //this.cameraOptions = String.IsNullOrEmpty(options) ?
+ // new CameraOptions() : JSON.JsonHelper.Deserialize<CameraOptions>(options);
+ }
+ catch (Exception ex)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, ex.Message));
+ return;
+ }
+
+ //TODO Check if all the options are acceptable
+
+
+ if (cameraOptions.PictureSourceType == CAMERA)
+ {
+ cameraTask = new CameraCaptureTask();
+ cameraTask.Completed += onCameraTaskCompleted;
+ cameraTask.Show();
+ }
+ else
+ {
+ if ((cameraOptions.PictureSourceType == PHOTOLIBRARY) || (cameraOptions.PictureSourceType == SAVEDPHOTOALBUM))
+ {
+ photoChooserTask = new PhotoChooserTask();
+ photoChooserTask.Completed += onPickerTaskCompleted;
+ photoChooserTask.Show();
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.NO_RESULT));
+ }
+ }
+
+ }
+
+ public void onCameraTaskCompleted(object sender, PhotoResult e)
+ {
+ if (e.Error != null)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR));
+ return;
+ }
+
+ switch (e.TaskResult)
+ {
+ case TaskResult.OK:
+ try
+ {
+ string imagePathOrContent = string.Empty;
+
+ if (cameraOptions.DestinationType == FILE_URI)
+ {
+ // Save image in media library
+ if (cameraOptions.SaveToPhotoAlbum)
+ {
+ MediaLibrary library = new MediaLibrary();
+ Picture pict = library.SavePicture(e.OriginalFileName, e.ChosenPhoto); // to save to photo-roll ...
+ }
+
+ int orient = ImageExifHelper.getImageOrientationFromStream(e.ChosenPhoto);
+ int newAngle = 0;
+ switch (orient)
+ {
+ case ImageExifOrientation.LandscapeLeft:
+ newAngle = 90;
+ break;
+ case ImageExifOrientation.PortraitUpsideDown:
+ newAngle = 180;
+ break;
+ case ImageExifOrientation.LandscapeRight:
+ newAngle = 270;
+ break;
+ case ImageExifOrientation.Portrait:
+ default: break; // 0 default already set
+ }
+
+ Stream rotImageStream = ImageExifHelper.RotateStream(e.ChosenPhoto, newAngle);
+
+ // we should return stream position back after saving stream to media library
+ rotImageStream.Seek(0, SeekOrigin.Begin);
+
+ WriteableBitmap image = PictureDecoder.DecodeJpeg(rotImageStream);
+
+ imagePathOrContent = this.SaveImageToLocalStorage(image, Path.GetFileName(e.OriginalFileName));
+
+
+ }
+ else if (cameraOptions.DestinationType == DATA_URL)
+ {
+ imagePathOrContent = this.GetImageContent(e.ChosenPhoto);
+ }
+ else
+ {
+ // TODO: shouldn't this happen before we launch the camera-picker?
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Incorrect option: destinationType"));
+ return;
+ }
+
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, imagePathOrContent));
+
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Error retrieving image."));
+ }
+ break;
+
+ case TaskResult.Cancel:
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Selection cancelled."));
+ break;
+
+ default:
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Selection did not complete!"));
+ break;
+ }
+
+ }
+
+ public void onPickerTaskCompleted(object sender, PhotoResult e)
+ {
+ if (e.Error != null)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR));
+ return;
+ }
+
+ switch (e.TaskResult)
+ {
+ case TaskResult.OK:
+ try
+ {
+ string imagePathOrContent = string.Empty;
+
+ if (cameraOptions.DestinationType == FILE_URI)
+ {
+ WriteableBitmap image = PictureDecoder.DecodeJpeg(e.ChosenPhoto);
+ imagePathOrContent = this.SaveImageToLocalStorage(image, Path.GetFileName(e.OriginalFileName));
+ }
+ else if (cameraOptions.DestinationType == DATA_URL)
+ {
+ imagePathOrContent = this.GetImageContent(e.ChosenPhoto);
+
+ }
+ else
+ {
+ // TODO: shouldn't this happen before we launch the camera-picker?
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Incorrect option: destinationType"));
+ return;
+ }
+
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, imagePathOrContent));
+
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Error retrieving image."));
+ }
+ break;
+
+ case TaskResult.Cancel:
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Selection cancelled."));
+ break;
+
+ default:
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Selection did not complete!"));
+ break;
+ }
+ }
+
+ /// <summary>
+ /// Returns image content in a form of base64 string
+ /// </summary>
+ /// <param name="stream">Image stream</param>
+ /// <returns>Base64 representation of the image</returns>
+ private string GetImageContent(Stream stream)
+ {
+ int streamLength = (int)stream.Length;
+ byte[] fileData = new byte[streamLength + 1];
+ stream.Read(fileData, 0, streamLength);
+
+ //use photo's actual width & height if user doesn't provide width & height
+ if (cameraOptions.TargetWidth < 0 && cameraOptions.TargetHeight < 0)
+ {
+ stream.Close();
+ return Convert.ToBase64String(fileData);
+ }
+ else
+ {
+ // resize photo
+ byte[] resizedFile = ResizePhoto(stream, fileData);
+ stream.Close();
+ return Convert.ToBase64String(resizedFile);
+ }
+ }
+
+ /// <summary>
+ /// Resize image
+ /// </summary>
+ /// <param name="stream">Image stream</param>
+ /// <param name="fileData">File data</param>
+ /// <returns>resized image</returns>
+ private byte[] ResizePhoto(Stream stream, byte[] fileData)
+ {
+ int streamLength = (int)stream.Length;
+ int intResult = 0;
+
+ byte[] resizedFile;
+
+ stream.Read(fileData, 0, streamLength);
+
+ BitmapImage objBitmap = new BitmapImage();
+ MemoryStream objBitmapStream = new MemoryStream(fileData);
+ MemoryStream objBitmapStreamResized = new MemoryStream();
+ WriteableBitmap objWB;
+ objBitmap.SetSource(stream);
+ objWB = new WriteableBitmap(objBitmap);
+
+ // resize the photo with user defined TargetWidth & TargetHeight
+ Extensions.SaveJpeg(objWB, objBitmapStreamResized, cameraOptions.TargetWidth, cameraOptions.TargetHeight, 0, cameraOptions.Quality);
+
+ //Convert the resized stream to a byte array.
+ streamLength = (int)objBitmapStreamResized.Length;
+ resizedFile = new Byte[streamLength]; //-1
+ objBitmapStreamResized.Position = 0;
+ //for some reason we have to set Position to zero, but we don't have to earlier when we get the bytes from the chosen photo...
+ intResult = objBitmapStreamResized.Read(resizedFile, 0, streamLength);
+
+ return resizedFile;
+ }
+
+ /// <summary>
+ /// Saves captured image in isolated storage
+ /// </summary>
+ /// <param name="imageFileName">image file name</param>
+ /// <returns>Image path</returns>
+ private string SaveImageToLocalStorage(WriteableBitmap image, string imageFileName)
+ {
+
+ if (image == null)
+ {
+ throw new ArgumentNullException("imageBytes");
+ }
+ try
+ {
+
+
+ var isoFile = IsolatedStorageFile.GetUserStoreForApplication();
+
+ if (!isoFile.DirectoryExists(isoFolder))
+ {
+ isoFile.CreateDirectory(isoFolder);
+ }
+
+ string filePath = System.IO.Path.Combine("///" + isoFolder + "/", imageFileName);
+
+ using (var stream = isoFile.CreateFile(filePath))
+ {
+ // resize image if Height and Width defined via options
+ if (cameraOptions.TargetHeight > 0 && cameraOptions.TargetWidth > 0)
+ {
+ image.SaveJpeg(stream, cameraOptions.TargetWidth, cameraOptions.TargetHeight, 0, cameraOptions.Quality);
+ }
+ else
+ {
+ image.SaveJpeg(stream, image.PixelWidth, image.PixelHeight, 0, cameraOptions.Quality);
+ }
+ }
+
+ return new Uri(filePath, UriKind.Relative).ToString();
+ }
+ catch (Exception)
+ {
+ //TODO: log or do something else
+ throw;
+ }
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/Capture.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/Capture.cs b/lib/cordova-wp8/templates/standalone/Plugins/Capture.cs
new file mode 100644
index 0000000..5e14a16
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/Capture.cs
@@ -0,0 +1,736 @@
+/*
+ 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.IO;
+using System.IO.IsolatedStorage;
+using System.Runtime.Serialization;
+using System.Windows.Media.Imaging;
+using Microsoft.Phone;
+using Microsoft.Phone.Tasks;
+using Microsoft.Xna.Framework.Media;
+using WPCordovaClassLib.Cordova.UI;
+using AudioResult = WPCordovaClassLib.Cordova.UI.AudioCaptureTask.AudioResult;
+using VideoResult = WPCordovaClassLib.Cordova.UI.VideoCaptureTask.VideoResult;
+using System.Windows;
+using System.Diagnostics;
+using Microsoft.Phone.Controls;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ /// <summary>
+ /// Provides access to the audio, image, and video capture capabilities of the device
+ /// </summary>
+ public class Capture : BaseCommand
+ {
+ #region Internal classes (options and resultant objects)
+
+ /// <summary>
+ /// Represents captureImage action options.
+ /// </summary>
+ [DataContract]
+ public class CaptureImageOptions
+ {
+ /// <summary>
+ /// The maximum number of images the device user can capture in a single capture operation. The value must be greater than or equal to 1 (defaults to 1).
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "limit")]
+ public int Limit { get; set; }
+
+ public static CaptureImageOptions Default
+ {
+ get { return new CaptureImageOptions() { Limit = 1 }; }
+ }
+ }
+
+ /// <summary>
+ /// Represents captureAudio action options.
+ /// </summary>
+ [DataContract]
+ public class CaptureAudioOptions
+ {
+ /// <summary>
+ /// The maximum number of audio files the device user can capture in a single capture operation. The value must be greater than or equal to 1 (defaults to 1).
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "limit")]
+ public int Limit { get; set; }
+
+ public static CaptureAudioOptions Default
+ {
+ get { return new CaptureAudioOptions() { Limit = 1 }; }
+ }
+ }
+
+ /// <summary>
+ /// Represents captureVideo action options.
+ /// </summary>
+ [DataContract]
+ public class CaptureVideoOptions
+ {
+ /// <summary>
+ /// The maximum number of video files the device user can capture in a single capture operation. The value must be greater than or equal to 1 (defaults to 1).
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "limit")]
+ public int Limit { get; set; }
+
+ public static CaptureVideoOptions Default
+ {
+ get { return new CaptureVideoOptions() { Limit = 1 }; }
+ }
+ }
+
+ /// <summary>
+ /// Represents getFormatData action options.
+ /// </summary>
+ [DataContract]
+ public class MediaFormatOptions
+ {
+ /// <summary>
+ /// File path
+ /// </summary>
+ [DataMember(IsRequired = true, Name = "fullPath")]
+ public string FullPath { get; set; }
+
+ /// <summary>
+ /// File mime type
+ /// </summary>
+ [DataMember(Name = "type")]
+ public string Type { get; set; }
+
+ }
+
+ /// <summary>
+ /// Stores image info
+ /// </summary>
+ [DataContract]
+ public class MediaFile
+ {
+
+ [DataMember(Name = "name")]
+ public string FileName { get; set; }
+
+ [DataMember(Name = "fullPath")]
+ public string FilePath { get; set; }
+
+ [DataMember(Name = "type")]
+ public string Type { get; set; }
+
+ [DataMember(Name = "lastModifiedDate")]
+ public string LastModifiedDate { get; set; }
+
+ [DataMember(Name = "size")]
+ public long Size { get; set; }
+
+ public MediaFile(string filePath, Picture image)
+ {
+ this.FilePath = filePath;
+ this.FileName = System.IO.Path.GetFileName(this.FilePath);
+ this.Type = MimeTypeMapper.GetMimeType(FileName);
+ this.Size = image.GetImage().Length;
+
+ using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ this.LastModifiedDate = storage.GetLastWriteTime(filePath).DateTime.ToString();
+ }
+
+ }
+
+ public MediaFile(string filePath, Stream stream)
+ {
+ this.FilePath = filePath;
+ this.FileName = System.IO.Path.GetFileName(this.FilePath);
+ this.Type = MimeTypeMapper.GetMimeType(FileName);
+ this.Size = stream.Length;
+
+ using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ this.LastModifiedDate = storage.GetLastWriteTime(filePath).DateTime.ToString();
+ }
+ }
+ }
+
+ /// <summary>
+ /// Stores additional media file data
+ /// </summary>
+ [DataContract]
+ public class MediaFileData
+ {
+ [DataMember(Name = "height")]
+ public int Height { get; set; }
+
+ [DataMember(Name = "width")]
+ public int Width { get; set; }
+
+ [DataMember(Name = "bitrate")]
+ public int Bitrate { get; set; }
+
+ [DataMember(Name = "duration")]
+ public int Duration { get; set; }
+
+ [DataMember(Name = "codecs")]
+ public string Codecs { get; set; }
+
+ public MediaFileData(WriteableBitmap image)
+ {
+ this.Height = image.PixelHeight;
+ this.Width = image.PixelWidth;
+ this.Bitrate = 0;
+ this.Duration = 0;
+ this.Codecs = "";
+ }
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Folder to store captured images
+ /// </summary>
+ private string isoFolder = "CapturedImagesCache";
+
+ /// <summary>
+ /// Capture Image options
+ /// </summary>
+ protected CaptureImageOptions captureImageOptions;
+
+ /// <summary>
+ /// Capture Audio options
+ /// </summary>
+ protected CaptureAudioOptions captureAudioOptions;
+
+ /// <summary>
+ /// Capture Video options
+ /// </summary>
+ protected CaptureVideoOptions captureVideoOptions;
+
+ /// <summary>
+ /// Used to open camera application
+ /// </summary>
+ private CameraCaptureTask cameraTask;
+
+ /// <summary>
+ /// Used for audio recording
+ /// </summary>
+ private AudioCaptureTask audioCaptureTask;
+
+ /// <summary>
+ /// Used for video recording
+ /// </summary>
+ private VideoCaptureTask videoCaptureTask;
+
+ /// <summary>
+ /// Stores information about captured files
+ /// </summary>
+ List<MediaFile> files = new List<MediaFile>();
+
+ /// <summary>
+ /// Launches default camera application to capture image
+ /// </summary>
+ /// <param name="options">may contains limit or mode parameters</param>
+ public void captureImage(string options)
+ {
+ try
+ {
+ try
+ {
+
+ string args = JSON.JsonHelper.Deserialize<string[]>(options)[0];
+ this.captureImageOptions = String.IsNullOrEmpty(args) ? CaptureImageOptions.Default : JSON.JsonHelper.Deserialize<CaptureImageOptions>(args);
+
+ }
+ catch (Exception ex)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, ex.Message));
+ return;
+ }
+
+
+ cameraTask = new CameraCaptureTask();
+ cameraTask.Completed += this.cameraTask_Completed;
+ cameraTask.Show();
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ }
+
+ /// <summary>
+ /// Launches our own audio recording control to capture audio
+ /// </summary>
+ /// <param name="options">may contains additional parameters</param>
+ public void captureAudio(string options)
+ {
+ try
+ {
+ try
+ {
+ string args = JSON.JsonHelper.Deserialize<string[]>(options)[0];
+ this.captureAudioOptions = String.IsNullOrEmpty(args) ? CaptureAudioOptions.Default : JSON.JsonHelper.Deserialize<CaptureAudioOptions>(args);
+
+ }
+ catch (Exception ex)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, ex.Message));
+ return;
+ }
+
+ audioCaptureTask = new AudioCaptureTask();
+ audioCaptureTask.Completed += audioRecordingTask_Completed;
+ audioCaptureTask.Show();
+
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ }
+
+ /// <summary>
+ /// Launches our own video recording control to capture video
+ /// </summary>
+ /// <param name="options">may contains additional parameters</param>
+ public void captureVideo(string options)
+ {
+ try
+ {
+ try
+ {
+ string args = JSON.JsonHelper.Deserialize<string[]>(options)[0];
+ this.captureVideoOptions = String.IsNullOrEmpty(args) ? CaptureVideoOptions.Default : JSON.JsonHelper.Deserialize<CaptureVideoOptions>(args);
+
+ }
+ catch (Exception ex)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, ex.Message));
+ return;
+ }
+
+ videoCaptureTask = new VideoCaptureTask();
+ videoCaptureTask.Completed += videoRecordingTask_Completed;
+ videoCaptureTask.Show();
+
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ }
+
+ /// <summary>
+ /// Retrieves the format information of the media file.
+ /// </summary>
+ /// <param name="options"></param>
+ public void getFormatData(string options)
+ {
+ try
+ {
+ MediaFormatOptions mediaFormatOptions;
+ try
+ {
+ mediaFormatOptions = new MediaFormatOptions();
+ string[] optionStrings = JSON.JsonHelper.Deserialize<string[]>(options);
+ mediaFormatOptions.FullPath = optionStrings[0];
+ mediaFormatOptions.Type = optionStrings[1];
+ }
+ catch (Exception ex)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, ex.Message));
+ return;
+ }
+
+ if (string.IsNullOrEmpty(mediaFormatOptions.FullPath))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ }
+
+ string mimeType = mediaFormatOptions.Type;
+
+ if (string.IsNullOrEmpty(mimeType))
+ {
+ mimeType = MimeTypeMapper.GetMimeType(mediaFormatOptions.FullPath);
+ }
+
+ if (mimeType.Equals("image/jpeg"))
+ {
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ WriteableBitmap image = ExtractImageFromLocalStorage(mediaFormatOptions.FullPath);
+
+ if (image == null)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "File not found"));
+ return;
+ }
+
+ MediaFileData mediaData = new MediaFileData(image);
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, mediaData));
+ });
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR));
+ }
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR));
+ }
+ }
+
+ /// <summary>
+ /// Opens specified file in media player
+ /// </summary>
+ /// <param name="options">MediaFile to play</param>
+ public void play(string options)
+ {
+ try
+ {
+ MediaFile file;
+
+ try
+ {
+ file = String.IsNullOrEmpty(options) ? null : JSON.JsonHelper.Deserialize<MediaFile[]>(options)[0];
+
+ }
+ catch (Exception ex)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, ex.Message));
+ return;
+ }
+
+ if (file == null || String.IsNullOrEmpty(file.FilePath))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "File path is missing"));
+ return;
+ }
+
+ // if url starts with '/' media player throws FileNotFound exception
+ Uri fileUri = new Uri(file.FilePath.TrimStart(new char[] { '/', '\\' }), UriKind.Relative);
+
+ MediaPlayerLauncher player = new MediaPlayerLauncher();
+ player.Media = fileUri;
+ player.Location = MediaLocationType.Data;
+ player.Show();
+
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ }
+
+
+ /// <summary>
+ /// Handles result of capture to save image information
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="e">stores information about current captured image</param>
+ private void cameraTask_Completed(object sender, PhotoResult e)
+ {
+
+ if (e.Error != null)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR));
+ return;
+ }
+
+ switch (e.TaskResult)
+ {
+ case TaskResult.OK:
+ try
+ {
+ string fileName = System.IO.Path.GetFileName(e.OriginalFileName);
+
+ // Save image in media library
+ MediaLibrary library = new MediaLibrary();
+ Picture image = library.SavePicture(fileName, e.ChosenPhoto);
+
+ int orient = ImageExifHelper.getImageOrientationFromStream(e.ChosenPhoto);
+ int newAngle = 0;
+ switch (orient)
+ {
+ case ImageExifOrientation.LandscapeLeft:
+ newAngle = 90;
+ break;
+ case ImageExifOrientation.PortraitUpsideDown:
+ newAngle = 180;
+ break;
+ case ImageExifOrientation.LandscapeRight:
+ newAngle = 270;
+ break;
+ case ImageExifOrientation.Portrait:
+ default: break; // 0 default already set
+ }
+
+ Stream rotImageStream = ImageExifHelper.RotateStream(e.ChosenPhoto, newAngle);
+
+ // Save image in isolated storage
+
+ // we should return stream position back after saving stream to media library
+ rotImageStream.Seek(0, SeekOrigin.Begin);
+
+ byte[] imageBytes = new byte[rotImageStream.Length];
+ rotImageStream.Read(imageBytes, 0, imageBytes.Length);
+ rotImageStream.Dispose();
+ string pathLocalStorage = this.SaveImageToLocalStorage(fileName, isoFolder, imageBytes);
+ imageBytes = null;
+ // Get image data
+ MediaFile data = new MediaFile(pathLocalStorage, image);
+
+ this.files.Add(data);
+
+ if (files.Count < this.captureImageOptions.Limit)
+ {
+ cameraTask.Show();
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, files));
+ files.Clear();
+ }
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Error capturing image."));
+ }
+ break;
+
+ case TaskResult.Cancel:
+ if (files.Count > 0)
+ {
+ // User canceled operation, but some images were made
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, files));
+ files.Clear();
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Canceled."));
+ }
+ break;
+
+ default:
+ if (files.Count > 0)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, files));
+ files.Clear();
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Did not complete!"));
+ }
+ break;
+ }
+ }
+
+ /// <summary>
+ /// Handles result of audio recording tasks
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="e">stores information about current captured audio</param>
+ private void audioRecordingTask_Completed(object sender, AudioResult e)
+ {
+
+ if (e.Error != null)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR));
+ return;
+ }
+
+ switch (e.TaskResult)
+ {
+ case TaskResult.OK:
+ try
+ {
+ // Get image data
+ MediaFile data = new MediaFile(e.AudioFileName, e.AudioFile);
+
+ this.files.Add(data);
+
+ if (files.Count < this.captureAudioOptions.Limit)
+ {
+ audioCaptureTask.Show();
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, files));
+ files.Clear();
+ }
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Error capturing audio."));
+ }
+ break;
+
+ case TaskResult.Cancel:
+ if (files.Count > 0)
+ {
+ // User canceled operation, but some audio clips were made
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, files));
+ files.Clear();
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Canceled."));
+ }
+ break;
+
+ default:
+ if (files.Count > 0)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, files));
+ files.Clear();
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Did not complete!"));
+ }
+ break;
+ }
+ }
+
+ /// <summary>
+ /// Handles result of video recording tasks
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="e">stores information about current captured video</param>
+ private void videoRecordingTask_Completed(object sender, VideoResult e)
+ {
+
+ if (e.Error != null)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR));
+ return;
+ }
+
+ switch (e.TaskResult)
+ {
+ case TaskResult.OK:
+ try
+ {
+ // Get image data
+ MediaFile data = new MediaFile(e.VideoFileName, e.VideoFile);
+
+ this.files.Add(data);
+
+ if (files.Count < this.captureVideoOptions.Limit)
+ {
+ videoCaptureTask.Show();
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, files));
+ files.Clear();
+ }
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Error capturing video."));
+ }
+ break;
+
+ case TaskResult.Cancel:
+ if (files.Count > 0)
+ {
+ // User canceled operation, but some video clips were made
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, files));
+ files.Clear();
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Canceled."));
+ }
+ break;
+
+ default:
+ if (files.Count > 0)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, files));
+ files.Clear();
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Did not complete!"));
+ }
+ break;
+ }
+ }
+
+ /// <summary>
+ /// Extract file from Isolated Storage as WriteableBitmap object
+ /// </summary>
+ /// <param name="filePath"></param>
+ /// <returns></returns>
+ private WriteableBitmap ExtractImageFromLocalStorage(string filePath)
+ {
+ try
+ {
+
+ var isoFile = IsolatedStorageFile.GetUserStoreForApplication();
+
+ using (var imageStream = isoFile.OpenFile(filePath, FileMode.Open, FileAccess.Read))
+ {
+ var imageSource = PictureDecoder.DecodeJpeg(imageStream);
+ return imageSource;
+ }
+ }
+ catch (Exception)
+ {
+ return null;
+ }
+ }
+
+
+ /// <summary>
+ /// Saves captured image in isolated storage
+ /// </summary>
+ /// <param name="imageFileName">image file name</param>
+ /// <param name="imageFolder">folder to store images</param>
+ /// <returns>Image path</returns>
+ private string SaveImageToLocalStorage(string imageFileName, string imageFolder, byte[] imageBytes)
+ {
+ if (imageBytes == null)
+ {
+ throw new ArgumentNullException("imageBytes");
+ }
+ try
+ {
+ var isoFile = IsolatedStorageFile.GetUserStoreForApplication();
+
+ if (!isoFile.DirectoryExists(imageFolder))
+ {
+ isoFile.CreateDirectory(imageFolder);
+ }
+ string filePath = System.IO.Path.Combine("/" + imageFolder + "/", imageFileName);
+
+ using (IsolatedStorageFileStream stream = isoFile.CreateFile(filePath))
+ {
+ stream.Write(imageBytes, 0, imageBytes.Length);
+ }
+
+ return filePath;
+ }
+ catch (Exception)
+ {
+ //TODO: log or do something else
+ throw;
+ }
+ }
+
+
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/Compass.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/Compass.cs b/lib/cordova-wp8/templates/standalone/Plugins/Compass.cs
new file mode 100644
index 0000000..c9e1c4d
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/Compass.cs
@@ -0,0 +1,362 @@
+/*
+ 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 DeviceCompass = Microsoft.Devices.Sensors.Compass;
+using System.Windows.Threading;
+using System.Runtime.Serialization;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.Threading;
+using Microsoft.Devices.Sensors;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+
+ public class Compass : BaseCommand
+ {
+ #region Static members
+
+ /// <summary>
+ /// Status of listener
+ /// </summary>
+ private static int currentStatus;
+
+ /// <summary>
+ /// Id for get getCompass method
+ /// </summary>
+ private static string getCompassId = "getCompassId";
+
+ /// <summary>
+ /// Compass
+ /// </summary>
+ private static DeviceCompass compass = new DeviceCompass();
+
+ /// <summary>
+ /// Listeners for callbacks
+ /// </summary>
+ private static Dictionary<string, Compass> watchers = new Dictionary<string, Compass>();
+
+ #endregion
+
+ #region Status codes
+
+ public const int Stopped = 0;
+ public const int Starting = 1;
+ public const int Running = 2;
+ public const int ErrorFailedToStart = 4;
+ public const int Not_Supported = 20;
+
+ /*
+ * // Capture error codes
+ CompassError.COMPASS_INTERNAL_ERR = 0;
+ CompassError.COMPASS_NOT_SUPPORTED = 20;
+ * */
+
+ #endregion
+
+ #region CompassOptions class
+ /// <summary>
+ /// Represents Accelerometer options.
+ /// </summary>
+ [DataContract]
+ public class CompassOptions
+ {
+ /// <summary>
+ /// How often to retrieve the Acceleration in milliseconds
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "frequency")]
+ public int Frequency { get; set; }
+
+ /// <summary>
+ /// The change in degrees required to initiate a watchHeadingFilter success callback.
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "filter")]
+ public int Filter { get; set; }
+
+ /// <summary>
+ /// Watcher id
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "id")]
+ public string Id { get; set; }
+
+ }
+ #endregion
+
+
+ /// <summary>
+ /// Time the value was last changed
+ /// </summary>
+ //private DateTime lastValueChangedTime;
+
+ /// <summary>
+ /// Accelerometer options
+ /// </summary>
+ private CompassOptions compassOptions;
+
+ //bool isDataValid;
+
+ //bool calibrating = false;
+
+ public Compass()
+ {
+
+ }
+
+ /// <summary>
+ /// Formats current coordinates into JSON format
+ /// </summary>
+ /// <returns>Coordinates in JSON format</returns>
+ private string GetHeadingFormatted(CompassReading reading)
+ {
+ // NOTE: timestamp is generated on the JS side, to avoid issues with format conversions
+ string result = String.Format("\"magneticHeading\":{0},\"headingAccuracy\":{1},\"trueHeading\":{2}",
+ reading.MagneticHeading.ToString("0.0", CultureInfo.InvariantCulture),
+ reading.HeadingAccuracy.ToString("0.0", CultureInfo.InvariantCulture),
+ reading.TrueHeading.ToString("0.0", CultureInfo.InvariantCulture));
+ return "{" + result + "}";
+ }
+
+ public void getHeading(string options)
+ {
+ if (!DeviceCompass.IsSupported)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "{code:" + Not_Supported + "}"));
+ }
+ else
+ {
+ //if (compass == null)
+ //{
+ // // Instantiate the compass.
+ // compass = new DeviceCompass();
+ // compass.TimeBetweenUpdates = TimeSpan.FromMilliseconds(40);
+ // compass.CurrentValueChanged += new EventHandler<Microsoft.Devices.Sensors.SensorReadingEventArgs<Microsoft.Devices.Sensors.CompassReading>>(compass_CurrentValueChanged);
+ // compass.Calibrate += new EventHandler<Microsoft.Devices.Sensors.CalibrationEventArgs>(compass_Calibrate);
+ //}
+
+
+ //compass.Start();
+
+ }
+
+ try
+ {
+ if (currentStatus != Running)
+ {
+ lock (compass)
+ {
+ compass.CurrentValueChanged += compass_SingleHeadingValueChanged;
+ compass.Start();
+ this.SetStatus(Starting);
+ }
+
+ long timeout = 2000;
+ while ((currentStatus == Starting) && (timeout > 0))
+ {
+ timeout = timeout - 100;
+ Thread.Sleep(100);
+ }
+
+ if (currentStatus != Running)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, ErrorFailedToStart));
+ return;
+ }
+ }
+ lock (compass)
+ {
+ compass.CurrentValueChanged -= compass_SingleHeadingValueChanged;
+ if (watchers.Count < 1)
+ {
+ compass.Stop();
+ this.SetStatus(Stopped);
+ }
+ }
+ }
+ catch (UnauthorizedAccessException)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ILLEGAL_ACCESS_EXCEPTION, ErrorFailedToStart));
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, ErrorFailedToStart));
+ }
+ }
+
+ void compass_SingleHeadingValueChanged(object sender, Microsoft.Devices.Sensors.SensorReadingEventArgs<CompassReading> e)
+ {
+ this.SetStatus(Running);
+ if (compass.IsDataValid)
+ {
+ // trueHeading :: The heading in degrees from 0 - 359.99 at a single moment in time.
+ // magneticHeading:: The heading relative to the geographic North Pole in degrees 0 - 359.99 at a single moment in time.
+ // A negative value indicates that the true heading could not be determined.
+ // headingAccuracy :: The deviation in degrees between the reported heading and the true heading.
+ //rawMagnetometerReading = e.SensorReading.MagnetometerReading;
+
+ //Debug.WriteLine("Compass Result :: " + GetHeadingFormatted(e.SensorReading));
+
+ PluginResult result = new PluginResult(PluginResult.Status.OK, GetHeadingFormatted(e.SensorReading));
+
+ DispatchCommandResult(result);
+ }
+ }
+
+ /// <summary>
+ /// Starts listening for compass sensor
+ /// </summary>
+ /// <returns>status of listener</returns>
+ private int start()
+ {
+ if ((currentStatus == Running) || (currentStatus == Starting))
+ {
+ return currentStatus;
+ }
+ try
+ {
+ lock (compass)
+ {
+ watchers.Add(getCompassId, this);
+ compass.CurrentValueChanged += watchers[getCompassId].compass_CurrentValueChanged;
+ compass.Start();
+ this.SetStatus(Starting);
+ }
+ }
+ catch (Exception)
+ {
+ this.SetStatus(ErrorFailedToStart);
+ }
+ return currentStatus;
+ }
+
+ public void startWatch(string options)
+ {
+ if (!DeviceCompass.IsSupported)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, Not_Supported));
+ }
+
+ try
+ {
+ compassOptions = JSON.JsonHelper.Deserialize<CompassOptions>(options);
+ }
+ catch (Exception ex)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, ex.Message));
+ return;
+ }
+
+ if (string.IsNullOrEmpty(compassOptions.Id))
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ try
+ {
+ lock (compass)
+ {
+ watchers.Add(compassOptions.Id, this);
+ compass.CurrentValueChanged += watchers[compassOptions.Id].compass_CurrentValueChanged;
+ compass.Start();
+ this.SetStatus(Starting);
+ }
+ }
+ catch (Exception)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, ErrorFailedToStart));
+ return;
+ }
+ }
+
+ public void stopWatch(string options)
+ {
+ try
+ {
+ compassOptions = JSON.JsonHelper.Deserialize<CompassOptions>(options);
+ }
+ catch (Exception ex)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, ex.Message));
+ return;
+ }
+
+ if (string.IsNullOrEmpty(compassOptions.Id))
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ if (currentStatus != Stopped)
+ {
+ lock (compass)
+ {
+ Compass watcher = watchers[compassOptions.Id];
+ compass.CurrentValueChanged -= watcher.compass_CurrentValueChanged;
+ watchers.Remove(compassOptions.Id);
+ watcher.Dispose();
+ }
+ }
+ this.SetStatus(Stopped);
+
+ this.DispatchCommandResult();
+ }
+
+ void compass_Calibrate(object sender, Microsoft.Devices.Sensors.CalibrationEventArgs e)
+ {
+ //throw new NotImplementedException();
+ // TODO: pass calibration error to JS
+ }
+
+ void compass_CurrentValueChanged(object sender, Microsoft.Devices.Sensors.SensorReadingEventArgs<CompassReading> e)
+ {
+ this.SetStatus(Running);
+ if (compass.IsDataValid)
+ {
+ // trueHeading :: The heading in degrees from 0 - 359.99 at a single moment in time.
+ // magneticHeading:: The heading relative to the geographic North Pole in degrees 0 - 359.99 at a single moment in time.
+ // A negative value indicates that the true heading could not be determined.
+ // headingAccuracy :: The deviation in degrees between the reported heading and the true heading.
+ //rawMagnetometerReading = e.SensorReading.MagnetometerReading;
+
+ //Debug.WriteLine("Compass Result :: " + GetHeadingFormatted(e.SensorReading));
+
+ PluginResult result = new PluginResult(PluginResult.Status.OK, GetHeadingFormatted(e.SensorReading));
+ result.KeepCallback = true;
+
+ DispatchCommandResult(result);
+ }
+ }
+
+ /// <summary>
+ /// Sets current status
+ /// </summary>
+ /// <param name="status">current status</param>
+ private void SetStatus(int status)
+ {
+ currentStatus = status;
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/Contacts.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/Contacts.cs b/lib/cordova-wp8/templates/standalone/Plugins/Contacts.cs
new file mode 100644
index 0000000..af78942
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/Contacts.cs
@@ -0,0 +1,664 @@
+/*
+ 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 Microsoft.Phone.Tasks;
+using Microsoft.Phone.UserData;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Runtime.Serialization;
+using System.Windows;
+using DeviceContacts = Microsoft.Phone.UserData.Contacts;
+
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ [DataContract]
+ public class SearchOptions
+ {
+ [DataMember]
+ public string filter { get; set; }
+ [DataMember]
+ public bool multiple { get; set; }
+ }
+
+ [DataContract]
+ public class ContactSearchParams
+ {
+ [DataMember]
+ public string[] fields { get; set; }
+ [DataMember]
+ public SearchOptions options { get; set; }
+ }
+
+ [DataContract]
+ public class JSONContactAddress
+ {
+ [DataMember]
+ public string formatted { get; set; }
+ [DataMember]
+ public string type { get; set; }
+ [DataMember]
+ public string streetAddress { get; set; }
+ [DataMember]
+ public string locality { get; set; }
+ [DataMember]
+ public string region { get; set; }
+ [DataMember]
+ public string postalCode { get; set; }
+ [DataMember]
+ public string country { get; set; }
+ [DataMember]
+ public bool pref { get; set; }
+ }
+
+ [DataContract]
+ public class JSONContactName
+ {
+ [DataMember]
+ public string formatted { get; set; }
+ [DataMember]
+ public string familyName { get; set; }
+ [DataMember]
+ public string givenName { get; set; }
+ [DataMember]
+ public string middleName { get; set; }
+ [DataMember]
+ public string honorificPrefix { get; set; }
+ [DataMember]
+ public string honorificSuffix { get; set; }
+ }
+
+ [DataContract]
+ public class JSONContactField
+ {
+ [DataMember]
+ public string type { get; set; }
+ [DataMember]
+ public string value { get; set; }
+ [DataMember]
+ public bool pref { get; set; }
+ }
+
+ [DataContract]
+ public class JSONContactOrganization
+ {
+ [DataMember]
+ public string type { get; set; }
+ [DataMember]
+ public string name { get; set; }
+ [DataMember]
+ public bool pref { get; set; }
+ [DataMember]
+ public string department { get; set; }
+ [DataMember]
+ public string title { get; set; }
+ }
+
+ [DataContract]
+ public class JSONContact
+ {
+ [DataMember]
+ public string id { get; set; }
+ [DataMember]
+ public string rawId { get; set; }
+ [DataMember]
+ public string displayName { get; set; }
+ [DataMember]
+ public string nickname { get; set; }
+ [DataMember]
+ public string note { get; set; }
+
+ [DataMember]
+ public JSONContactName name { get; set; }
+
+ [DataMember]
+ public JSONContactField[] emails { get; set; }
+
+ [DataMember]
+ public JSONContactField[] phoneNumbers { get; set; }
+
+ [DataMember]
+ public JSONContactField[] ims { get; set; }
+
+ [DataMember]
+ public JSONContactField[] photos { get; set; }
+
+ [DataMember]
+ public JSONContactField[] categories { get; set; }
+
+ [DataMember]
+ public JSONContactField[] urls { get; set; }
+
+ [DataMember]
+ public JSONContactOrganization[] organizations { get; set; }
+
+ [DataMember]
+ public JSONContactAddress[] addresses { get; set; }
+ }
+
+
+ public class Contacts : BaseCommand
+ {
+
+ public const int UNKNOWN_ERROR = 0;
+ public const int INVALID_ARGUMENT_ERROR = 1;
+ public const int TIMEOUT_ERROR = 2;
+ public const int PENDING_OPERATION_ERROR = 3;
+ public const int IO_ERROR = 4;
+ public const int NOT_SUPPORTED_ERROR = 5;
+ public const int PERMISSION_DENIED_ERROR = 20;
+ public const int SYNTAX_ERR = 8;
+
+ public Contacts()
+ {
+
+ }
+
+ // refer here for contact properties we can access: http://msdn.microsoft.com/en-us/library/microsoft.phone.tasks.savecontacttask_members%28v=VS.92%29.aspx
+ public void save(string jsonContact)
+ {
+
+ // jsonContact is actually an array of 1 {contact}
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(jsonContact);
+
+
+ JSONContact contact = JSON.JsonHelper.Deserialize<JSONContact>(args[0]);
+
+ SaveContactTask contactTask = new SaveContactTask();
+
+ if (contact.nickname != null)
+ {
+ contactTask.Nickname = contact.nickname;
+ }
+ if (contact.urls != null && contact.urls.Length > 0)
+ {
+ contactTask.Website = contact.urls[0].value;
+ }
+ if (contact.note != null)
+ {
+ contactTask.Notes = contact.note;
+ }
+
+ #region contact.name
+ if (contact.name != null)
+ {
+ if (contact.name.givenName != null)
+ contactTask.FirstName = contact.name.givenName;
+ if (contact.name.familyName != null)
+ contactTask.LastName = contact.name.familyName;
+ if (contact.name.middleName != null)
+ contactTask.MiddleName = contact.name.middleName;
+ if (contact.name.honorificSuffix != null)
+ contactTask.Suffix = contact.name.honorificSuffix;
+ if (contact.name.honorificPrefix != null)
+ contactTask.Title = contact.name.honorificPrefix;
+ }
+ #endregion
+
+ #region contact.org
+ if (contact.organizations != null && contact.organizations.Count() > 0)
+ {
+ contactTask.Company = contact.organizations[0].name;
+ contactTask.JobTitle = contact.organizations[0].title;
+ }
+ #endregion
+
+ #region contact.phoneNumbers
+ if (contact.phoneNumbers != null && contact.phoneNumbers.Length > 0)
+ {
+ foreach (JSONContactField field in contact.phoneNumbers)
+ {
+ string fieldType = field.type.ToLower();
+ if (fieldType == "work")
+ {
+ contactTask.WorkPhone = field.value;
+ }
+ else if (fieldType == "home")
+ {
+ contactTask.HomePhone = field.value;
+ }
+ else if (fieldType == "mobile")
+ {
+ contactTask.MobilePhone = field.value;
+ }
+ }
+ }
+ #endregion
+
+ #region contact.emails
+
+ if (contact.emails != null && contact.emails.Length > 0)
+ {
+
+ // set up different email types if they are not explicitly defined
+ foreach (string type in new string[] { "personal", "work", "other" })
+ {
+ foreach (JSONContactField field in contact.emails)
+ {
+ if (field != null && String.IsNullOrEmpty(field.type))
+ {
+ field.type = type;
+ break;
+ }
+ }
+ }
+
+ foreach (JSONContactField field in contact.emails)
+ {
+ if (field != null)
+ {
+ if (field.type != null && field.type != "other")
+ {
+ string fieldType = field.type.ToLower();
+ if (fieldType == "work")
+ {
+ contactTask.WorkEmail = field.value;
+ }
+ else if (fieldType == "home" || fieldType == "personal")
+ {
+ contactTask.PersonalEmail = field.value;
+ }
+ }
+ else
+ {
+ contactTask.OtherEmail = field.value;
+ }
+ }
+
+ }
+ }
+ #endregion
+
+ if (contact.note != null && contact.note.Length > 0)
+ {
+ contactTask.Notes = contact.note;
+ }
+
+ #region contact.addresses
+ if (contact.addresses != null && contact.addresses.Length > 0)
+ {
+ foreach (JSONContactAddress address in contact.addresses)
+ {
+ if (address.type == null)
+ {
+ address.type = "home"; // set a default
+ }
+ string fieldType = address.type.ToLower();
+ if (fieldType == "work")
+ {
+ contactTask.WorkAddressCity = address.locality;
+ contactTask.WorkAddressCountry = address.country;
+ contactTask.WorkAddressState = address.region;
+ contactTask.WorkAddressStreet = address.streetAddress;
+ contactTask.WorkAddressZipCode = address.postalCode;
+ }
+ else if (fieldType == "home" || fieldType == "personal")
+ {
+ contactTask.HomeAddressCity = address.locality;
+ contactTask.HomeAddressCountry = address.country;
+ contactTask.HomeAddressState = address.region;
+ contactTask.HomeAddressStreet = address.streetAddress;
+ contactTask.HomeAddressZipCode = address.postalCode;
+ }
+ else
+ {
+ // no other address fields available ...
+ Debug.WriteLine("Creating contact with unsupported address type :: " + address.type);
+ }
+ }
+ }
+ #endregion
+
+
+ contactTask.Completed += new EventHandler<SaveContactResult>(ContactSaveTaskCompleted);
+ contactTask.Show();
+ }
+
+ void ContactSaveTaskCompleted(object sender, SaveContactResult e)
+ {
+ SaveContactTask task = sender as SaveContactTask;
+
+ if (e.TaskResult == TaskResult.OK)
+ {
+
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ DeviceContacts deviceContacts = new DeviceContacts();
+ deviceContacts.SearchCompleted += new EventHandler<ContactsSearchEventArgs>(postAdd_SearchCompleted);
+
+ string displayName = String.Format("{0}{2}{1}", task.FirstName, task.LastName, String.IsNullOrEmpty(task.FirstName) ? "" : " ");
+
+ deviceContacts.SearchAsync(displayName, FilterKind.DisplayName, task);
+ });
+
+
+ }
+ else if (e.TaskResult == TaskResult.Cancel)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Operation cancelled."));
+ }
+ }
+
+ void postAdd_SearchCompleted(object sender, ContactsSearchEventArgs e)
+ {
+ if (e.Results.Count() > 0)
+ {
+ List<Contact> foundContacts = new List<Contact>();
+
+ int n = (from Contact contact in e.Results select contact.GetHashCode()).Max();
+ Contact newContact = (from Contact contact in e.Results
+ where contact.GetHashCode() == n
+ select contact).First();
+
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, FormatJSONContact(newContact, null)));
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.NO_RESULT));
+ }
+ }
+
+
+
+ public void remove(string id)
+ {
+ // note id is wrapped in [] and always has exactly one string ...
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "{\"code\":" + NOT_SUPPORTED_ERROR + "}"));
+ }
+
+ public void search(string searchCriteria)
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(searchCriteria);
+
+ ContactSearchParams searchParams = new ContactSearchParams();
+ try
+ {
+ searchParams.fields = JSON.JsonHelper.Deserialize<string[]>(args[0]);
+ searchParams.options = JSON.JsonHelper.Deserialize<SearchOptions>(args[1]);
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, INVALID_ARGUMENT_ERROR));
+ return;
+ }
+
+ if (searchParams.options == null)
+ {
+ searchParams.options = new SearchOptions();
+ searchParams.options.filter = "";
+ searchParams.options.multiple = true;
+ }
+
+ DeviceContacts deviceContacts = new DeviceContacts();
+ deviceContacts.SearchCompleted += new EventHandler<ContactsSearchEventArgs>(contacts_SearchCompleted);
+
+ // default is to search all fields
+ FilterKind filterKind = FilterKind.None;
+ // if only one field is specified, we will try the 3 available DeviceContact search filters
+ if (searchParams.fields.Count() == 1)
+ {
+ if (searchParams.fields.Contains("name"))
+ {
+ filterKind = FilterKind.DisplayName;
+ }
+ else if (searchParams.fields.Contains("emails"))
+ {
+ filterKind = FilterKind.EmailAddress;
+ }
+ else if (searchParams.fields.Contains("phoneNumbers"))
+ {
+ filterKind = FilterKind.PhoneNumber;
+ }
+ }
+
+ try
+ {
+
+ deviceContacts.SearchAsync(searchParams.options.filter, filterKind, searchParams);
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine("search contacts exception :: " + ex.Message);
+ }
+ }
+
+ private void contacts_SearchCompleted(object sender, ContactsSearchEventArgs e)
+ {
+ ContactSearchParams searchParams = (ContactSearchParams)e.State;
+
+ List<Contact> foundContacts = null;
+
+ // if we have multiple search fields
+ if (searchParams.options.filter.Length > 0 && searchParams.fields.Count() > 1)
+ {
+ foundContacts = new List<Contact>();
+ if (searchParams.fields.Contains("emails"))
+ {
+ foundContacts.AddRange(from Contact con in e.Results
+ from ContactEmailAddress a in con.EmailAddresses
+ where a.EmailAddress.Contains(searchParams.options.filter)
+ select con);
+ }
+ if (searchParams.fields.Contains("displayName"))
+ {
+ foundContacts.AddRange(from Contact con in e.Results
+ where con.DisplayName.Contains(searchParams.options.filter)
+ select con);
+ }
+ if (searchParams.fields.Contains("name"))
+ {
+ foundContacts.AddRange(from Contact con in e.Results
+ where con.CompleteName != null && con.CompleteName.ToString().Contains(searchParams.options.filter)
+ select con);
+ }
+ if (searchParams.fields.Contains("phoneNumbers"))
+ {
+ foundContacts.AddRange(from Contact con in e.Results
+ from ContactPhoneNumber a in con.PhoneNumbers
+ where a.PhoneNumber.Contains(searchParams.options.filter)
+ select con);
+ }
+ if (searchParams.fields.Contains("urls"))
+ {
+ foundContacts.AddRange(from Contact con in e.Results
+ from string a in con.Websites
+ where a.Contains(searchParams.options.filter)
+ select con);
+ }
+ }
+ else
+ {
+ foundContacts = new List<Contact>(e.Results);
+ }
+
+ //List<string> contactList = new List<string>();
+
+ string strResult = "";
+
+ IEnumerable<Contact> distinctContacts = foundContacts.Distinct();
+
+ foreach (Contact contact in distinctContacts)
+ {
+ strResult += FormatJSONContact(contact, null) + ",";
+ //contactList.Add(FormatJSONContact(contact, null));
+ if (!searchParams.options.multiple)
+ {
+ break; // just return the first item
+ }
+ }
+ PluginResult result = new PluginResult(PluginResult.Status.OK);
+ result.Message = "[" + strResult.TrimEnd(',') + "]";
+ DispatchCommandResult(result);
+
+ }
+
+ private string FormatJSONPhoneNumbers(Contact con)
+ {
+ string retVal = "";
+ string contactFieldFormat = "\"type\":\"{0}\",\"value\":\"{1}\",\"pref\":\"false\"";
+ foreach (ContactPhoneNumber number in con.PhoneNumbers)
+ {
+
+ string contactField = string.Format(contactFieldFormat,
+ number.Kind.ToString(),
+ number.PhoneNumber);
+
+ retVal += "{" + contactField + "},";
+ }
+ return retVal.TrimEnd(',');
+ }
+
+ private string FormatJSONEmails(Contact con)
+ {
+ string retVal = "";
+ string contactFieldFormat = "\"type\":\"{0}\",\"value\":\"{1}\",\"pref\":\"false\"";
+ foreach (ContactEmailAddress address in con.EmailAddresses)
+ {
+ string contactField = string.Format(contactFieldFormat,
+ address.Kind.ToString(),
+ address.EmailAddress);
+
+ retVal += "{" + contactField + "},";
+ }
+ return retVal.TrimEnd(',');
+ }
+
+ private string getFormattedJSONAddress(ContactAddress address, bool isPrefered)
+ {
+
+ string addressFormatString = "\"pref\":{0}," + // bool
+ "\"type\":\"{1}\"," +
+ "\"formatted\":\"{2}\"," +
+ "\"streetAddress\":\"{3}\"," +
+ "\"locality\":\"{4}\"," +
+ "\"region\":\"{5}\"," +
+ "\"postalCode\":\"{6}\"," +
+ "\"country\":\"{7}\"";
+
+ string formattedAddress = address.PhysicalAddress.AddressLine1 + " "
+ + address.PhysicalAddress.AddressLine2 + " "
+ + address.PhysicalAddress.City + " "
+ + address.PhysicalAddress.StateProvince + " "
+ + address.PhysicalAddress.CountryRegion + " "
+ + address.PhysicalAddress.PostalCode;
+
+ string jsonAddress = string.Format(addressFormatString,
+ isPrefered ? "\"true\"" : "\"false\"",
+ address.Kind.ToString(),
+ formattedAddress,
+ address.PhysicalAddress.AddressLine1 + " " + address.PhysicalAddress.AddressLine2,
+ address.PhysicalAddress.City,
+ address.PhysicalAddress.StateProvince,
+ address.PhysicalAddress.PostalCode,
+ address.PhysicalAddress.CountryRegion);
+
+ //Debug.WriteLine("getFormattedJSONAddress returning :: " + jsonAddress);
+
+ return "{" + jsonAddress + "}";
+ }
+
+ private string FormatJSONAddresses(Contact con)
+ {
+ string retVal = "";
+ foreach (ContactAddress address in con.Addresses)
+ {
+ retVal += this.getFormattedJSONAddress(address, false) + ",";
+ }
+
+ //Debug.WriteLine("FormatJSONAddresses returning :: " + retVal);
+ return retVal.TrimEnd(',');
+ }
+
+ private string FormatJSONWebsites(Contact con)
+ {
+ string retVal = "";
+ foreach (string website in con.Websites)
+ {
+ retVal += "\"" + website + "\",";
+ }
+ return retVal.TrimEnd(',');
+ }
+
+ /*
+ * formatted: The complete name of the contact. (DOMString)
+ familyName: The contacts family name. (DOMString)
+ givenName: The contacts given name. (DOMString)
+ middleName: The contacts middle name. (DOMString)
+ honorificPrefix: The contacts prefix (example Mr. or Dr.) (DOMString)
+ honorificSuffix: The contacts suffix (example Esq.). (DOMString)
+ */
+ private string FormatJSONName(Contact con)
+ {
+ string retVal = "";
+ string formatStr = "\"formatted\":\"{0}\"," +
+ "\"familyName\":\"{1}\"," +
+ "\"givenName\":\"{2}\"," +
+ "\"middleName\":\"{3}\"," +
+ "\"honorificPrefix\":\"{4}\"," +
+ "\"honorificSuffix\":\"{5}\"";
+
+ if (con.CompleteName != null)
+ {
+ retVal = string.Format(formatStr,
+ con.CompleteName.FirstName + " " + con.CompleteName.LastName, // TODO: does this need suffix? middlename?
+ con.CompleteName.LastName,
+ con.CompleteName.FirstName,
+ con.CompleteName.MiddleName,
+ con.CompleteName.Title,
+ con.CompleteName.Suffix);
+ }
+ else
+ {
+ retVal = string.Format(formatStr,"","","","","","");
+ }
+
+ return "{" + retVal + "}";
+ }
+
+ private string FormatJSONContact(Contact con, string[] fields)
+ {
+
+ string contactFormatStr = "\"id\":\"{0}\"," +
+ "\"displayName\":\"{1}\"," +
+ "\"nickname\":\"{2}\"," +
+ "\"phoneNumbers\":[{3}]," +
+ "\"emails\":[{4}]," +
+ "\"addresses\":[{5}]," +
+ "\"urls\":[{6}]," +
+ "\"name\":{7}," +
+ "\"note\":\"{8}\"," +
+ "\"birthday\":\"{9}\"";
+
+
+ string jsonContact = String.Format(contactFormatStr,
+ con.GetHashCode(),
+ con.DisplayName,
+ con.CompleteName != null ? con.CompleteName.Nickname : "",
+ FormatJSONPhoneNumbers(con),
+ FormatJSONEmails(con),
+ FormatJSONAddresses(con),
+ FormatJSONWebsites(con),
+ FormatJSONName(con),
+ con.Notes.FirstOrDefault(),
+ con.Birthdays.FirstOrDefault());
+
+ //Debug.WriteLine("jsonContact = " + jsonContact);
+ // JSON requires new line characters be escaped
+ return "{" + jsonContact.Replace("\n", "\\n") + "}";
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/DebugConsole.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/DebugConsole.cs b/lib/cordova-wp8/templates/standalone/Plugins/DebugConsole.cs
new file mode 100644
index 0000000..fa9863a
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/DebugConsole.cs
@@ -0,0 +1,49 @@
+/*
+ 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.Diagnostics;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+
+ public class DebugConsole : BaseCommand
+ {
+ // warn, error
+ public void log(string msg)
+ {
+ Debug.WriteLine("Log:" + msg);
+ }
+
+ public void error(string msg)
+ {
+ Debug.WriteLine("Error:" + msg);
+ }
+
+ public void warn(string msg)
+ {
+ Debug.WriteLine("Warn:" + msg);
+ }
+
+ }
+}
[06/37] Add WP7 and WP8 platform files.
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/camera/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/camera/index.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/camera/index.html
new file mode 100644
index 0000000..bc3b554
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/camera/index.html
@@ -0,0 +1,96 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width,height=device-height,user-scalable=no,maximum-scale=1.0,initial-scale=1.0" />
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8"> <!-- ISO-8859-1 -->
+ <title>Cordova Mobile Spec</title>
+ <link rel="stylesheet" href="../master.css" type="text/css" media="screen" title="no title" charset="utf-8">
+ <script type="text/javascript" charset="utf-8" src="../cordova.js"></script>
+
+
+<script type="text/javascript" charset="utf-8">
+
+ var deviceReady = false;
+
+ //-------------------------------------------------------------------------
+ // Camera
+ //-------------------------------------------------------------------------
+
+ /**
+ * Capture picture
+ */
+ function getPicture() {
+
+ //navigator.camera.getPicture(onPhotoDataSuccess, onFail, { quality: 50,
+ // destinationType: Camera.DestinationType.FILE_URI, sourceType : Camera.PictureSourceType.CAMERA });
+
+ navigator.camera.getPicture(
+ function(data) {
+ var img = document.getElementById('camera_image');
+ img.style.visibility = "visible";
+ img.style.display = "block";
+ //img.src = "data:image/jpeg;base64," + data;
+ img.src = data;
+ document.getElementById('camera_status').innerHTML = "Success";
+ },
+ function(e) {
+ console.log("Error getting picture: " + e);
+ document.getElementById('camera_status').innerHTML = "Error getting picture.";
+ },
+ { quality: 50, destinationType:
+ Camera.DestinationType.FILE_URI, sourceType : Camera.PictureSourceType.CAMERA});
+ };
+
+ /**
+ * Select image from library
+ */
+ function getImage() {
+ navigator.camera.getPicture(
+ function(data) {
+ var img = document.getElementById('camera_image');
+ img.style.visibility = "visible";
+ img.style.display = "block";
+ //img.src = "data:image/jpeg;base64," + data;
+ img.src = data;
+ document.getElementById('camera_status').innerHTML = "Success";
+ },
+ function(e) {
+ console.log("Error getting picture: " + e);
+ document.getElementById('camera_status').innerHTML = "Error getting picture.";
+ },
+ { quality: 50, destinationType:
+ Camera.DestinationType.FILE_URI, sourceType: Camera.PictureSourceType.PHOTOLIBRARY});
+ };
+
+
+ /**
+ * Function called when page has finished loading.
+ */
+ function init() {
+ document.addEventListener("deviceready", function() {
+ deviceReady = true;
+ console.log("Device="+device.platform+" "+device.version);
+ }, false);
+ window.setTimeout(function() {
+ if (!deviceReady) {
+ alert("Error: PhoneGap did not initialize. Demo will not run correctly.");
+ }
+ },1000);
+ }
+
+</script>
+
+ </head>
+ <body onload="init();" id="stage" class="theme">
+
+ <h1>Camera</h1>
+ <div id="info">
+ <b>Status:</b> <span id="camera_status"></span><br>
+ <img style="width:120px;height:120px;visibility:hidden;display:none;" id="camera_image" src="" />
+ </div>
+ <h2>Action</h2>
+ <div class="btn large" onclick="getPicture();">Take Picture</div>
+ <div class="btn large" onclick="getImage();">Select Image from Library</div>
+ <h2> </h2><div class="backBtn" onclick="backHome();">Back</div>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/compass/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/compass/index.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/compass/index.html
new file mode 100644
index 0000000..8dbf99a
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/compass/index.html
@@ -0,0 +1,128 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width,height=device-height,user-scalable=no,maximum-scale=1.0,initial-scale=1.0" />
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8"> <!-- ISO-8859-1 -->
+ <title>Cordova Mobile Spec</title>
+ <link rel="stylesheet" href="../master.css" type="text/css" media="screen" title="no title" charset="utf-8">
+ <script type="text/javascript" charset="utf-8" src="../cordova.js"></script>
+
+
+<script type="text/javascript" charset="utf-8">
+
+ var deviceReady = false;
+
+ function roundNumber(num) {
+ var dec = 3;
+ var result = Math.round(num*Math.pow(10,dec))/Math.pow(10,dec);
+ return result;
+ }
+
+ //-------------------------------------------------------------------------
+ // Compass
+ //-------------------------------------------------------------------------
+ var watchCompassId = null;
+
+ /**
+ * Start watching compass
+ */
+ var watchCompass = function() {
+ console.log("watchCompass()");
+
+ // Success callback
+ var success = function(a){
+ document.getElementById('compassHeading').innerHTML = roundNumber(a.magneticHeading);
+ };
+
+ // Fail callback
+ var fail = function(e){
+ console.log("watchCompass fail callback with error code "+e);
+ stopCompass();
+ setCompassStatus(e);
+ };
+
+ // Update heading every 1 sec
+ var opt = {};
+ opt.frequency = 1000;
+ watchCompassId = navigator.compass.watchHeading(success, fail, opt);
+
+ setCompassStatus("Running");
+ };
+
+ /**
+ * Stop watching the acceleration
+ */
+ var stopCompass = function() {
+ setCompassStatus("Stopped");
+ if (watchCompassId) {
+ navigator.compass.clearWatch(watchCompassId);
+ watchCompassId = null;
+ }
+ };
+
+ /**
+ * Get current compass
+ */
+ var getCompass = function() {
+ console.log("getCompass()");
+
+ // Stop compass if running
+ stopCompass();
+
+ // Success callback
+ var success = function(a){
+ document.getElementById('compassHeading').innerHTML = roundNumber(a.magneticHeading);
+ };
+
+ // Fail callback
+ var fail = function(e){
+ console.log("getCompass fail callback with error code "+e);
+ setCompassStatus(e);
+ };
+
+ // Make call
+ var opt = {};
+ navigator.compass.getCurrentHeading(success, fail, opt);
+ };
+
+ /**
+ * Set compass status
+ */
+ var setCompassStatus = function(status) {
+ document.getElementById('compass_status').innerHTML = status;
+ };
+
+ /**
+ * Function called when page has finished loading.
+ */
+ function init() {
+ document.addEventListener("deviceready", function() {
+ deviceReady = true;
+ console.log("Device="+device.platform+" "+device.version);
+ }, false);
+ window.setTimeout(function() {
+ if (!deviceReady) {
+ alert("Error: PhoneGap did not initialize. Demo will not run correctly.");
+ }
+ },1000);
+ }
+
+</script>
+
+ </head>
+ <body onload="init();" id="stage" class="theme">
+
+ <h1>Compass</h1>
+ <div id="info">
+ <b>Status:</b> <span id="compass_status">Stopped</span>
+ <table width="100%"><tr>
+ <td width="33%">Heading: <span id="compassHeading"> </span></td>
+ </tr></table>
+ </div>
+ <h2>Action</h2>
+ <div class="btn large" onclick="getCompass();">Get Compass</div>
+ <div class="btn large" onclick="watchCompass();">Start Watching Compass</div>
+ <div class="btn large" onclick="stopCompass();">Stop Watching Compass</div>
+ <h2> </h2><div class="backBtn" onclick="backHome();">Back</div>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/contacts/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/contacts/index.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/contacts/index.html
new file mode 100644
index 0000000..950e1cc
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/contacts/index.html
@@ -0,0 +1,112 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width,height=device-height,user-scalable=no,maximum-scale=1.0,initial-scale=1.0" />
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8"> <!-- ISO-8859-1 -->
+ <title>Cordova Mobile Spec</title>
+ <link rel="stylesheet" href="../master.css" type="text/css" media="screen" title="no title" charset="utf-8">
+ <script type="text/javascript" charset="utf-8" src="../cordova.js"></script>
+
+
+<script type="text/javascript" charset="utf-8">
+
+ var deviceReady = false;
+
+ //-------------------------------------------------------------------------
+ // Contacts
+ //-------------------------------------------------------------------------
+ function getContacts() {
+ obj = new ContactFindOptions();
+ obj.filter = "D"; //Brooks";
+ obj.multiple = true;
+ navigator.contacts.find(
+ ["displayName", "name", "phoneNumbers", "emails", "urls", "note"],
+ function(contacts) {
+ var s = "";
+ if (contacts.length == 0) {
+ s = "No contacts found";
+ }
+ else {
+ s = "Number of contacts: "+contacts.length+"<br><table width='100%'><tr><th>Name</th><td>Phone</td><td>Email</td></tr>";
+ for (var i=0; i<contacts.length; i++) {
+ var contact = contacts[i];
+ s = s + "<tr><td>" + contact.name.formatted + "</td><td>";
+ if (contact.phoneNumbers && contact.phoneNumbers.length > 0) {
+ s = s + contact.phoneNumbers[0].value;
+ }
+ s = s + "</td><td>"
+ if (contact.emails && contact.emails.length > 0) {
+ s = s + contact.emails[0].value;
+ }
+ s = s + "</td></tr>";
+ }
+ s = s + "</table>";
+ }
+ document.getElementById('contacts_results').innerHTML = s;
+ },
+ function(e) {
+ document.getElementById('contacts_results').innerHTML = "Error: "+e.code;
+ },
+ obj);
+ };
+
+ function addContact(){
+ console.log("addContact()");
+ try{
+ var contact = navigator.contacts.create({"displayName": "Dooney Evans"});
+ var contactName = {
+ formatted: "Dooney Evans",
+ familyName: "Evans",
+ givenName: "Dooney",
+ middleName: ""
+ };
+
+ contact.name = contactName;
+
+ var phoneNumbers = [1];
+ phoneNumbers[0] = new ContactField('work', '512-555-1234', true);
+ contact.phoneNumbers = phoneNumbers;
+
+ contact.save(
+ function() { alert("Contact saved.");},
+ function(e) { alert("Contact save failed: " + e.code); }
+ );
+ console.log("you have saved the contact");
+ }
+ catch (e){
+ alert(e);
+ }
+
+ };
+
+ /**
+ * Function called when page has finished loading.
+ */
+ function init() {
+ document.addEventListener("deviceready", function() {
+ deviceReady = true;
+ console.log("Device="+device.platform+" "+device.version);
+ }, false);
+ window.setTimeout(function() {
+ if (!deviceReady) {
+ alert("Error: PhoneGap did not initialize. Demo will not run correctly.");
+ }
+ },1000);
+ }
+
+</script>
+
+ </head>
+ <body onload="init();" id="stage" class="theme">
+
+ <h1>Contacts</h1>
+ <div id="info">
+ <b>Results:</b><br>
+ <span id="contacts_results"> </span>
+ </div>
+ <h2>Action</h2>
+ <div class="btn large" onclick="getContacts();">Get phone's contacts</div>
+ <div class="btn large" onclick="addContact();">Add a new contact 'Dooney Evans'</div>
+ <h2> </h2><div class="backBtn" onclick="backHome();">Back</div>
+ </body>
+</html>
[03/37] git commit: Reorganize specs into cordova-cli/ and
platform-script/
Posted by mw...@apache.org.
Reorganize specs into cordova-cli/ and platform-script/
Project: http://git-wip-us.apache.org/repos/asf/cordova-cli/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-cli/commit/b50b5284
Tree: http://git-wip-us.apache.org/repos/asf/cordova-cli/tree/b50b5284
Diff: http://git-wip-us.apache.org/repos/asf/cordova-cli/diff/b50b5284
Branch: refs/heads/master
Commit: b50b52841fe5016888a298ac0a48d9f5d7fbf410
Parents: 2293706
Author: Benn Mapes <be...@gmail.com>
Authored: Tue May 14 15:18:41 2013 -0700
Committer: Michael Brooks <mi...@michaelbrooks.ca>
Committed: Wed May 15 10:20:34 2013 -0700
----------------------------------------------------------------------
package.json | 2 +-
spec/compile.spec.js | 179 --------
spec/config_parser.spec.js | 167 -------
spec/cordova-cli/compile.spec.js | 179 ++++++++
spec/cordova-cli/config_parser.spec.js | 167 +++++++
spec/cordova-cli/create.spec.js | 68 +++
spec/cordova-cli/emulate.spec.js | 191 ++++++++
spec/cordova-cli/helper.js | 20 +
spec/cordova-cli/hooker.spec.js | 137 ++++++
spec/cordova-cli/platform.spec.js | 339 +++++++++++++++
spec/cordova-cli/plugin.spec.js | 164 +++++++
spec/cordova-cli/plugin_parser.spec.js | 42 ++
spec/cordova-cli/prepare.spec.js | 133 ++++++
spec/cordova-cli/serve.spec.js | 132 ++++++
spec/create.spec.js | 68 ---
spec/emulate.spec.js | 191 --------
spec/helper.js | 20 -
spec/hooker.spec.js | 137 ------
spec/metadata/android_parser.spec.js | 220 ----------
spec/metadata/blackberry_parser.spec.js | 249 -----------
spec/metadata/ios_parser.spec.js | 218 ---------
.../platform-script/android/android_parser.spec.js | 220 ++++++++++
.../blackberry/blackberry_parser.spec.js | 249 +++++++++++
spec/platform-script/ios/ios_parser.spec.js | 218 +++++++++
spec/platform.spec.js | 339 ---------------
spec/plugin.spec.js | 164 -------
spec/plugin_parser.spec.js | 42 --
spec/prepare.spec.js | 133 ------
spec/serve.spec.js | 132 ------
29 files changed, 2260 insertions(+), 2260 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/package.json
----------------------------------------------------------------------
diff --git a/package.json b/package.json
index 3a41515..96e53bd 100644
--- a/package.json
+++ b/package.json
@@ -8,7 +8,7 @@
"cordova": "./bin/cordova"
},
"scripts": {
- "test": "./node_modules/jasmine-node/bin/jasmine-node --color spec",
+ "test": "./node_modules/jasmine-node/bin/jasmine-node --color spec/cordova-cli",
"install": "node bootstrap.js"
},
"repository": {
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/compile.spec.js
----------------------------------------------------------------------
diff --git a/spec/compile.spec.js b/spec/compile.spec.js
deleted file mode 100644
index f13792a..0000000
--- a/spec/compile.spec.js
+++ /dev/null
@@ -1,179 +0,0 @@
-/**
- 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.
-*/
-var cordova = require('../cordova'),
- et = require('elementtree'),
- shell = require('shelljs'),
- path = require('path'),
- fs = require('fs'),
- config_parser = require('../src/config_parser'),
- android_parser = require('../src/metadata/android_parser'),
- ios_parser = require('../src/metadata/ios_parser'),
- blackberry_parser = require('../src/metadata/blackberry_parser'),
- hooker = require('../src/hooker'),
- fixtures = path.join(__dirname, 'fixtures'),
- hooks = path.join(fixtures, 'hooks'),
- tempDir = path.join(__dirname, '..', 'temp'),
- cordova_project = path.join(fixtures, 'projects', 'cordova');
-
-var cwd = process.cwd();
-describe('compile command', function() {
- beforeEach(function() {
- shell.rm('-rf', tempDir);
- shell.mkdir('-p', tempDir);
- });
-
- it('should not run inside a Cordova-based project with no added platforms', function() {
- this.after(function() {
- process.chdir(cwd);
- });
-
- cordova.create(tempDir);
- process.chdir(tempDir);
- expect(function() {
- cordova.compile();
- }).toThrow();
- });
-
- it('should run inside a Cordova-based project with at least one added platform', function() {
- // move platform project fixtures over to fake cordova into thinking platforms were added
- // TODO: possibly add this to helper?
- shell.mv('-f', path.join(cordova_project, 'platforms', 'blackberry'), path.join(tempDir));
- shell.mv('-f', path.join(cordova_project, 'platforms', 'ios'), path.join(tempDir));
- this.after(function() {
- process.chdir(cwd);
- shell.mv('-f', path.join(tempDir, 'blackberry'), path.join(cordova_project, 'platforms', 'blackberry'));
- shell.mv('-f', path.join(tempDir, 'ios'), path.join(cordova_project, 'platforms', 'ios'));
- });
-
- process.chdir(cordova_project);
-
- var sh_spy = spyOn(shell, 'exec');
-
- expect(function() {
- cordova.compile();
- expect(sh_spy).toHaveBeenCalled();
- }).not.toThrow();
- });
- it('should not run outside of a Cordova-based project', function() {
- this.after(function() {
- process.chdir(cwd);
- });
-
- shell.mkdir('-p', tempDir);
- process.chdir(tempDir);
-
- expect(function() {
- cordova.compile();
- }).toThrow();
- });
-
- describe('hooks', function() {
- var s;
- beforeEach(function() {
- s = spyOn(hooker.prototype, 'fire').andReturn(true);
- });
-
- describe('when platforms are added', function() {
- beforeEach(function() {
- shell.mv('-f', path.join(cordova_project, 'platforms', 'blackberry'), path.join(tempDir));
- shell.mv('-f', path.join(cordova_project, 'platforms', 'ios'), path.join(tempDir));
- process.chdir(cordova_project);
- });
- afterEach(function() {
- shell.mv('-f', path.join(tempDir, 'blackberry'), path.join(cordova_project, 'platforms', 'blackberry'));
- shell.mv('-f', path.join(tempDir, 'ios'), path.join(cordova_project, 'platforms', 'ios'));
- process.chdir(cwd);
- });
-
- it('should fire before hooks through the hooker module', function() {
- spyOn(shell, 'exec');
- cordova.compile();
- expect(s).toHaveBeenCalledWith('before_compile');
- });
- it('should fire after hooks through the hooker module', function() {
- var sh_spy = spyOn(shell, 'exec');
- cordova.compile();
- sh_spy.mostRecentCall.args[2](0); // shell cb
- expect(s).toHaveBeenCalledWith('after_compile');
- });
- });
-
- describe('with no platforms added', function() {
- beforeEach(function() {
- cordova.create(tempDir);
- process.chdir(tempDir);
- });
- afterEach(function() {
- process.chdir(cwd);
- });
- it('should not fire the hooker', function() {
- expect(function() {
- cordova.compile();
- }).toThrow();
- expect(s).not.toHaveBeenCalledWith('before_compile');
- expect(s).not.toHaveBeenCalledWith('after_compile');
- });
- });
- });
- describe('per platform', function() {
- beforeEach(function() {
- process.chdir(cordova_project);
- });
-
- afterEach(function() {
- process.chdir(cwd);
- });
-
- describe('Android', function() {
- it('should shell out to build command on Android', function() {
- var s = spyOn(require('shelljs'), 'exec').andReturn({code:0});
- cordova.compile('android');
- expect(s.mostRecentCall.args[0].match(/\/cordova\/build/)).not.toBeNull();
- });
- });
- describe('iOS', function() {
- it('should shell out to build command on iOS', function() {
- var s = spyOn(require('shelljs'), 'exec');
- cordova.compile('ios');
- expect(s).toHaveBeenCalled();
- expect(s.mostRecentCall.args[0].match(/\/cordova\/build/)).not.toBeNull();
- });
- });
- describe('BlackBerry', function() {
- it('should shell out to ant command on blackberry', function() {
- var s = spyOn(shell, 'exec');
- cordova.compile('blackberry');
- expect(s).toHaveBeenCalled();
- expect(s.mostRecentCall.args[0]).toMatch(/ant -f .*build\.xml" qnx load-device/);
- });
- });
- it('should not treat a .gitignore file as a platform', function() {
- var gitignore = path.join(cordova_project, 'platforms', '.gitignore');
- fs.writeFileSync(gitignore, 'somethinghere', 'utf-8');
- this.after(function() {
- shell.rm('-f', gitignore);
- });
- var s = spyOn(shell, 'exec');
- cordova.compile();
- expect(s.calls[0].args[0]).not.toMatch(/\.gitignore/);
- expect(s.calls[1].args[0]).not.toMatch(/\.gitignore/);
- expect(s.calls[1].args[0]).not.toMatch(/\.gitignore/);
- });
- });
-});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/config_parser.spec.js
----------------------------------------------------------------------
diff --git a/spec/config_parser.spec.js b/spec/config_parser.spec.js
deleted file mode 100644
index 99bc717..0000000
--- a/spec/config_parser.spec.js
+++ /dev/null
@@ -1,167 +0,0 @@
-
-/**
- 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.
-*/
-var cordova = require('../cordova'),
- path = require('path'),
- fs = require('fs'),
- shell = require('shelljs'),
- config_parser = require('../src/config_parser'),
- tempDir = path.join(__dirname, '..', 'temp'),
- et = require('elementtree'),
- xml = path.join(tempDir, 'www', 'config.xml');
-
-
-describe('config.xml parser', function () {
- beforeEach(function() {
- shell.rm('-rf', tempDir);
- cordova.create(tempDir);
- });
-
- it('should create an instance based on an xml file', function() {
- var cfg;
- expect(function () {
- cfg = new config_parser(xml);
- }).not.toThrow();
- expect(cfg).toBeDefined();
- expect(cfg.doc).toBeDefined();
- });
-
- describe('package name / id', function() {
- var cfg;
-
- beforeEach(function() {
- cfg = new config_parser(xml);
- });
-
- it('should get the (default) packagename', function() {
- expect(cfg.packageName()).toEqual('io.cordova.hellocordova');
- });
- it('should allow setting the packagename', function() {
- cfg.packageName('this.is.bat.country');
- expect(cfg.packageName()).toEqual('this.is.bat.country');
- });
- it('should write to disk after setting the packagename', function() {
- cfg.packageName('this.is.bat.country');
- expect(fs.readFileSync(xml, 'utf-8')).toMatch(/id="this\.is\.bat\.country"/);
- });
- });
-
- describe('app name', function() {
- var cfg;
-
- beforeEach(function() {
- cfg = new config_parser(xml);
- });
-
- it('should get the (default) app name', function() {
- expect(cfg.name()).toEqual('HelloCordova');
- });
- it('should allow setting the app name', function() {
- cfg.name('this.is.bat.country');
- expect(cfg.name()).toEqual('this.is.bat.country');
- });
- it('should write to disk after setting the name', function() {
- cfg.name('one toke over the line');
- expect(fs.readFileSync(xml, 'utf-8')).toMatch(/<name>one toke over the line<\/name>/);
- });
- });
-
- describe('access elements (whitelist)', function() {
- var cfg;
-
- beforeEach(function() {
- cfg = new config_parser(xml);
- });
-
- describe('getter', function() {
- it('should get the (default) access element', function() {
- expect(cfg.access.get()[0]).toEqual('*');
- });
- it('should return an array of all access origin uris via access()', function() {
- expect(cfg.access.get() instanceof Array).toBe(true);
- });
- });
- describe('setters', function() {
- it('should allow removing a uri from the access list', function() {
- cfg.access.remove('*');
- expect(cfg.access.get().length).toEqual(0);
- });
- it('should write to disk after removing a uri', function() {
- cfg.access.remove('*');
- expect(fs.readFileSync(xml, 'utf-8')).not.toMatch(/<access.*\/>/);
- });
- it('should allow adding a new uri to the access list', function() {
- cfg.access.add('http://canucks.com');
- expect(cfg.access.get().length).toEqual(2);
- expect(cfg.access.get().indexOf('http://canucks.com') > -1).toBe(true);
- });
- it('should write to disk after adding a uri', function() {
- cfg.access.add('http://cordova.io');
- expect(fs.readFileSync(xml, 'utf-8')).toMatch(/<access origin="http:\/\/cordova\.io/);
- });
- it('should allow removing all access elements when no parameter is specified', function() {
- cfg.access.add('http://cordova.io');
- cfg.access.remove();
-
- expect(fs.readFileSync(xml, 'utf-8')).not.toMatch(/<access.*\/>/);
- });
- });
- });
-
- describe('preference elements', function() {
- var cfg;
-
- beforeEach(function() {
- cfg = new config_parser(xml);
- });
-
- describe('getter', function() {
- it('should get all preference elements', function() {
- expect(cfg.preference.get()[0].name).toEqual('phonegap-version');
- expect(cfg.preference.get()[0].value).toEqual('1.9.0');
- });
- it('should return an array of all preference name/value pairs', function() {
- expect(cfg.preference.get() instanceof Array).toBe(true);
- });
- });
- describe('setters', function() {
- it('should allow removing a preference by name', function() {
- cfg.preference.remove('phonegap-version');
- expect(cfg.preference.get().length).toEqual(3);
- });
- it('should write to disk after removing a preference', function() {
- cfg.preference.remove('phonegap-version');
- expect(fs.readFileSync(xml, 'utf-8')).not.toMatch(/<preference\sname="phonegap-version"/);
- });
- it('should allow adding a new preference', function() {
- cfg.preference.add({name:'UIWebViewBounce',value:'false'});
- expect(cfg.preference.get().length).toEqual(5);
- expect(cfg.preference.get()[4].value).toEqual('false');
- });
- it('should write to disk after adding a preference', function() {
- cfg.preference.add({name:'UIWebViewBounce',value:'false'});
- expect(fs.readFileSync(xml, 'utf-8')).toMatch(/<preference name="UIWebViewBounce" value="false"/);
- });
- it('should allow removing all preference elements when no parameter is specified', function() {
- cfg.preference.remove();
- expect(fs.readFileSync(xml, 'utf-8')).not.toMatch(/<preference.*\/>/);
- });
- });
- });
-});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/cordova-cli/compile.spec.js
----------------------------------------------------------------------
diff --git a/spec/cordova-cli/compile.spec.js b/spec/cordova-cli/compile.spec.js
new file mode 100644
index 0000000..f13792a
--- /dev/null
+++ b/spec/cordova-cli/compile.spec.js
@@ -0,0 +1,179 @@
+/**
+ 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.
+*/
+var cordova = require('../cordova'),
+ et = require('elementtree'),
+ shell = require('shelljs'),
+ path = require('path'),
+ fs = require('fs'),
+ config_parser = require('../src/config_parser'),
+ android_parser = require('../src/metadata/android_parser'),
+ ios_parser = require('../src/metadata/ios_parser'),
+ blackberry_parser = require('../src/metadata/blackberry_parser'),
+ hooker = require('../src/hooker'),
+ fixtures = path.join(__dirname, 'fixtures'),
+ hooks = path.join(fixtures, 'hooks'),
+ tempDir = path.join(__dirname, '..', 'temp'),
+ cordova_project = path.join(fixtures, 'projects', 'cordova');
+
+var cwd = process.cwd();
+describe('compile command', function() {
+ beforeEach(function() {
+ shell.rm('-rf', tempDir);
+ shell.mkdir('-p', tempDir);
+ });
+
+ it('should not run inside a Cordova-based project with no added platforms', function() {
+ this.after(function() {
+ process.chdir(cwd);
+ });
+
+ cordova.create(tempDir);
+ process.chdir(tempDir);
+ expect(function() {
+ cordova.compile();
+ }).toThrow();
+ });
+
+ it('should run inside a Cordova-based project with at least one added platform', function() {
+ // move platform project fixtures over to fake cordova into thinking platforms were added
+ // TODO: possibly add this to helper?
+ shell.mv('-f', path.join(cordova_project, 'platforms', 'blackberry'), path.join(tempDir));
+ shell.mv('-f', path.join(cordova_project, 'platforms', 'ios'), path.join(tempDir));
+ this.after(function() {
+ process.chdir(cwd);
+ shell.mv('-f', path.join(tempDir, 'blackberry'), path.join(cordova_project, 'platforms', 'blackberry'));
+ shell.mv('-f', path.join(tempDir, 'ios'), path.join(cordova_project, 'platforms', 'ios'));
+ });
+
+ process.chdir(cordova_project);
+
+ var sh_spy = spyOn(shell, 'exec');
+
+ expect(function() {
+ cordova.compile();
+ expect(sh_spy).toHaveBeenCalled();
+ }).not.toThrow();
+ });
+ it('should not run outside of a Cordova-based project', function() {
+ this.after(function() {
+ process.chdir(cwd);
+ });
+
+ shell.mkdir('-p', tempDir);
+ process.chdir(tempDir);
+
+ expect(function() {
+ cordova.compile();
+ }).toThrow();
+ });
+
+ describe('hooks', function() {
+ var s;
+ beforeEach(function() {
+ s = spyOn(hooker.prototype, 'fire').andReturn(true);
+ });
+
+ describe('when platforms are added', function() {
+ beforeEach(function() {
+ shell.mv('-f', path.join(cordova_project, 'platforms', 'blackberry'), path.join(tempDir));
+ shell.mv('-f', path.join(cordova_project, 'platforms', 'ios'), path.join(tempDir));
+ process.chdir(cordova_project);
+ });
+ afterEach(function() {
+ shell.mv('-f', path.join(tempDir, 'blackberry'), path.join(cordova_project, 'platforms', 'blackberry'));
+ shell.mv('-f', path.join(tempDir, 'ios'), path.join(cordova_project, 'platforms', 'ios'));
+ process.chdir(cwd);
+ });
+
+ it('should fire before hooks through the hooker module', function() {
+ spyOn(shell, 'exec');
+ cordova.compile();
+ expect(s).toHaveBeenCalledWith('before_compile');
+ });
+ it('should fire after hooks through the hooker module', function() {
+ var sh_spy = spyOn(shell, 'exec');
+ cordova.compile();
+ sh_spy.mostRecentCall.args[2](0); // shell cb
+ expect(s).toHaveBeenCalledWith('after_compile');
+ });
+ });
+
+ describe('with no platforms added', function() {
+ beforeEach(function() {
+ cordova.create(tempDir);
+ process.chdir(tempDir);
+ });
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+ it('should not fire the hooker', function() {
+ expect(function() {
+ cordova.compile();
+ }).toThrow();
+ expect(s).not.toHaveBeenCalledWith('before_compile');
+ expect(s).not.toHaveBeenCalledWith('after_compile');
+ });
+ });
+ });
+ describe('per platform', function() {
+ beforeEach(function() {
+ process.chdir(cordova_project);
+ });
+
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+
+ describe('Android', function() {
+ it('should shell out to build command on Android', function() {
+ var s = spyOn(require('shelljs'), 'exec').andReturn({code:0});
+ cordova.compile('android');
+ expect(s.mostRecentCall.args[0].match(/\/cordova\/build/)).not.toBeNull();
+ });
+ });
+ describe('iOS', function() {
+ it('should shell out to build command on iOS', function() {
+ var s = spyOn(require('shelljs'), 'exec');
+ cordova.compile('ios');
+ expect(s).toHaveBeenCalled();
+ expect(s.mostRecentCall.args[0].match(/\/cordova\/build/)).not.toBeNull();
+ });
+ });
+ describe('BlackBerry', function() {
+ it('should shell out to ant command on blackberry', function() {
+ var s = spyOn(shell, 'exec');
+ cordova.compile('blackberry');
+ expect(s).toHaveBeenCalled();
+ expect(s.mostRecentCall.args[0]).toMatch(/ant -f .*build\.xml" qnx load-device/);
+ });
+ });
+ it('should not treat a .gitignore file as a platform', function() {
+ var gitignore = path.join(cordova_project, 'platforms', '.gitignore');
+ fs.writeFileSync(gitignore, 'somethinghere', 'utf-8');
+ this.after(function() {
+ shell.rm('-f', gitignore);
+ });
+ var s = spyOn(shell, 'exec');
+ cordova.compile();
+ expect(s.calls[0].args[0]).not.toMatch(/\.gitignore/);
+ expect(s.calls[1].args[0]).not.toMatch(/\.gitignore/);
+ expect(s.calls[1].args[0]).not.toMatch(/\.gitignore/);
+ });
+ });
+});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/cordova-cli/config_parser.spec.js
----------------------------------------------------------------------
diff --git a/spec/cordova-cli/config_parser.spec.js b/spec/cordova-cli/config_parser.spec.js
new file mode 100644
index 0000000..99bc717
--- /dev/null
+++ b/spec/cordova-cli/config_parser.spec.js
@@ -0,0 +1,167 @@
+
+/**
+ 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.
+*/
+var cordova = require('../cordova'),
+ path = require('path'),
+ fs = require('fs'),
+ shell = require('shelljs'),
+ config_parser = require('../src/config_parser'),
+ tempDir = path.join(__dirname, '..', 'temp'),
+ et = require('elementtree'),
+ xml = path.join(tempDir, 'www', 'config.xml');
+
+
+describe('config.xml parser', function () {
+ beforeEach(function() {
+ shell.rm('-rf', tempDir);
+ cordova.create(tempDir);
+ });
+
+ it('should create an instance based on an xml file', function() {
+ var cfg;
+ expect(function () {
+ cfg = new config_parser(xml);
+ }).not.toThrow();
+ expect(cfg).toBeDefined();
+ expect(cfg.doc).toBeDefined();
+ });
+
+ describe('package name / id', function() {
+ var cfg;
+
+ beforeEach(function() {
+ cfg = new config_parser(xml);
+ });
+
+ it('should get the (default) packagename', function() {
+ expect(cfg.packageName()).toEqual('io.cordova.hellocordova');
+ });
+ it('should allow setting the packagename', function() {
+ cfg.packageName('this.is.bat.country');
+ expect(cfg.packageName()).toEqual('this.is.bat.country');
+ });
+ it('should write to disk after setting the packagename', function() {
+ cfg.packageName('this.is.bat.country');
+ expect(fs.readFileSync(xml, 'utf-8')).toMatch(/id="this\.is\.bat\.country"/);
+ });
+ });
+
+ describe('app name', function() {
+ var cfg;
+
+ beforeEach(function() {
+ cfg = new config_parser(xml);
+ });
+
+ it('should get the (default) app name', function() {
+ expect(cfg.name()).toEqual('HelloCordova');
+ });
+ it('should allow setting the app name', function() {
+ cfg.name('this.is.bat.country');
+ expect(cfg.name()).toEqual('this.is.bat.country');
+ });
+ it('should write to disk after setting the name', function() {
+ cfg.name('one toke over the line');
+ expect(fs.readFileSync(xml, 'utf-8')).toMatch(/<name>one toke over the line<\/name>/);
+ });
+ });
+
+ describe('access elements (whitelist)', function() {
+ var cfg;
+
+ beforeEach(function() {
+ cfg = new config_parser(xml);
+ });
+
+ describe('getter', function() {
+ it('should get the (default) access element', function() {
+ expect(cfg.access.get()[0]).toEqual('*');
+ });
+ it('should return an array of all access origin uris via access()', function() {
+ expect(cfg.access.get() instanceof Array).toBe(true);
+ });
+ });
+ describe('setters', function() {
+ it('should allow removing a uri from the access list', function() {
+ cfg.access.remove('*');
+ expect(cfg.access.get().length).toEqual(0);
+ });
+ it('should write to disk after removing a uri', function() {
+ cfg.access.remove('*');
+ expect(fs.readFileSync(xml, 'utf-8')).not.toMatch(/<access.*\/>/);
+ });
+ it('should allow adding a new uri to the access list', function() {
+ cfg.access.add('http://canucks.com');
+ expect(cfg.access.get().length).toEqual(2);
+ expect(cfg.access.get().indexOf('http://canucks.com') > -1).toBe(true);
+ });
+ it('should write to disk after adding a uri', function() {
+ cfg.access.add('http://cordova.io');
+ expect(fs.readFileSync(xml, 'utf-8')).toMatch(/<access origin="http:\/\/cordova\.io/);
+ });
+ it('should allow removing all access elements when no parameter is specified', function() {
+ cfg.access.add('http://cordova.io');
+ cfg.access.remove();
+
+ expect(fs.readFileSync(xml, 'utf-8')).not.toMatch(/<access.*\/>/);
+ });
+ });
+ });
+
+ describe('preference elements', function() {
+ var cfg;
+
+ beforeEach(function() {
+ cfg = new config_parser(xml);
+ });
+
+ describe('getter', function() {
+ it('should get all preference elements', function() {
+ expect(cfg.preference.get()[0].name).toEqual('phonegap-version');
+ expect(cfg.preference.get()[0].value).toEqual('1.9.0');
+ });
+ it('should return an array of all preference name/value pairs', function() {
+ expect(cfg.preference.get() instanceof Array).toBe(true);
+ });
+ });
+ describe('setters', function() {
+ it('should allow removing a preference by name', function() {
+ cfg.preference.remove('phonegap-version');
+ expect(cfg.preference.get().length).toEqual(3);
+ });
+ it('should write to disk after removing a preference', function() {
+ cfg.preference.remove('phonegap-version');
+ expect(fs.readFileSync(xml, 'utf-8')).not.toMatch(/<preference\sname="phonegap-version"/);
+ });
+ it('should allow adding a new preference', function() {
+ cfg.preference.add({name:'UIWebViewBounce',value:'false'});
+ expect(cfg.preference.get().length).toEqual(5);
+ expect(cfg.preference.get()[4].value).toEqual('false');
+ });
+ it('should write to disk after adding a preference', function() {
+ cfg.preference.add({name:'UIWebViewBounce',value:'false'});
+ expect(fs.readFileSync(xml, 'utf-8')).toMatch(/<preference name="UIWebViewBounce" value="false"/);
+ });
+ it('should allow removing all preference elements when no parameter is specified', function() {
+ cfg.preference.remove();
+ expect(fs.readFileSync(xml, 'utf-8')).not.toMatch(/<preference.*\/>/);
+ });
+ });
+ });
+});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/cordova-cli/create.spec.js
----------------------------------------------------------------------
diff --git a/spec/cordova-cli/create.spec.js b/spec/cordova-cli/create.spec.js
new file mode 100644
index 0000000..fcb3e76
--- /dev/null
+++ b/spec/cordova-cli/create.spec.js
@@ -0,0 +1,68 @@
+var cordova = require('../cordova'),
+ path = require('path'),
+ shell = require('shelljs'),
+ fs = require('fs'),
+ tempDir = path.join(__dirname, '..', 'temp');
+
+describe('create command', function () {
+ beforeEach(function() {
+ shell.rm('-rf', tempDir);
+ });
+
+ it('should print out help txt if no directory is provided', function() {
+ expect(cordova.create()).toMatch(/synopsis/i);
+ });
+ it('should create a cordova project in the specified directory if parameter is provided', function() {
+ cordova.create(tempDir);
+ var dotc = path.join(tempDir, '.cordova', 'config.json');
+ expect(fs.lstatSync(dotc).isFile()).toBe(true);
+ expect(JSON.parse(fs.readFileSync(dotc, 'utf8')).name).toBe("HelloCordova");
+ var hooks = path.join(tempDir, '.cordova', 'hooks');
+ expect(fs.existsSync(hooks)).toBe(true);
+ expect(fs.existsSync(path.join(hooks, 'before_platform_add'))).toBe(true);
+ expect(fs.existsSync(path.join(hooks, 'before_prepare'))).toBe(true);
+ expect(fs.existsSync(path.join(hooks, 'before_compile'))).toBe(true);
+ expect(fs.existsSync(path.join(hooks, 'after_platform_add'))).toBe(true);
+ expect(fs.existsSync(path.join(hooks, 'before_platform_rm'))).toBe(true);
+ expect(fs.existsSync(path.join(hooks, 'after_platform_rm'))).toBe(true);
+ expect(fs.existsSync(path.join(hooks, 'before_platform_ls'))).toBe(true);
+ expect(fs.existsSync(path.join(hooks, 'after_platform_ls'))).toBe(true);
+ expect(fs.existsSync(path.join(hooks, 'before_plugin_add'))).toBe(true);
+ expect(fs.existsSync(path.join(hooks, 'after_plugin_add'))).toBe(true);
+ expect(fs.existsSync(path.join(hooks, 'before_plugin_rm'))).toBe(true);
+ expect(fs.existsSync(path.join(hooks, 'after_plugin_rm'))).toBe(true);
+ expect(fs.existsSync(path.join(hooks, 'before_plugin_ls'))).toBe(true);
+ expect(fs.existsSync(path.join(hooks, 'after_plugin_ls'))).toBe(true);
+ expect(fs.existsSync(path.join(hooks, 'after_prepare'))).toBe(true);
+ expect(fs.existsSync(path.join(hooks, 'after_compile'))).toBe(true);
+ expect(fs.existsSync(path.join(hooks, 'before_build'))).toBe(true);
+ expect(fs.existsSync(path.join(hooks, 'after_build'))).toBe(true);
+ expect(fs.existsSync(path.join(hooks, 'before_emulate'))).toBe(true);
+ expect(fs.existsSync(path.join(hooks, 'after_emulate'))).toBe(true);
+ expect(fs.existsSync(path.join(hooks, 'before_docs'))).toBe(true);
+ expect(fs.existsSync(path.join(hooks, 'after_docs'))).toBe(true);
+ });
+ it('should throw if the directory is already a cordova project', function() {
+ shell.mkdir('-p', path.join(tempDir, '.cordova'));
+
+ expect(function() {
+ cordova.create(tempDir);
+ }).toThrow();
+ });
+ it('should create a cordova project in the specified dir with specified name if provided', function() {
+ cordova.create(tempDir, "balls");
+
+ expect(fs.lstatSync(path.join(tempDir, '.cordova', 'config.json')).isFile()).toBe(true);
+
+ expect(fs.readFileSync(path.join(tempDir, 'www', 'config.xml')).toString('utf8')).toMatch(/<name>balls<\/name>/);
+ });
+ it('should create a cordova project in the specified dir with specified name and id if provided', function() {
+ cordova.create(tempDir, "birdy.nam.nam", "numnum");
+
+ expect(fs.lstatSync(path.join(tempDir, '.cordova', 'config.json')).isFile()).toBe(true);
+
+ var config = fs.readFileSync(path.join(tempDir, 'www', 'config.xml')).toString('utf8');
+ expect(config).toMatch(/<name>numnum<\/name>/);
+ expect(config).toMatch(/id="birdy\.nam\.nam"/);
+ });
+});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/cordova-cli/emulate.spec.js
----------------------------------------------------------------------
diff --git a/spec/cordova-cli/emulate.spec.js b/spec/cordova-cli/emulate.spec.js
new file mode 100644
index 0000000..3a4d1a4
--- /dev/null
+++ b/spec/cordova-cli/emulate.spec.js
@@ -0,0 +1,191 @@
+/**
+ 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.
+*/
+var cordova = require('../cordova'),
+ et = require('elementtree'),
+ shell = require('shelljs'),
+ path = require('path'),
+ fs = require('fs'),
+ config_parser = require('../src/config_parser'),
+ android_parser = require('../src/metadata/android_parser'),
+ ios_parser = require('../src/metadata/ios_parser'),
+ blackberry_parser = require('../src/metadata/blackberry_parser'),
+ hooker = require('../src/hooker'),
+ fixtures = path.join(__dirname, 'fixtures'),
+ hooks = path.join(fixtures, 'hooks'),
+ tempDir = path.join(__dirname, '..', 'temp'),
+ cordova_project = path.join(fixtures, 'projects', 'cordova');
+
+var cwd = process.cwd();
+
+describe('emulate command', function() {
+ beforeEach(function() {
+ shell.rm('-rf', tempDir);
+ shell.mkdir('-p', tempDir);
+ });
+
+ it('should not run inside a Cordova-based project with no added platforms', function() {
+ this.after(function() {
+ process.chdir(cwd);
+ });
+
+ cordova.create(tempDir);
+ process.chdir(tempDir);
+ expect(function() {
+ cordova.emulate();
+ }).toThrow();
+ });
+
+ it('should run inside a Cordova-based project with at least one added platform', function() {
+ shell.mv('-f', path.join(cordova_project, 'platforms', 'blackberry'), path.join(tempDir));
+ shell.mv('-f', path.join(cordova_project, 'platforms', 'ios'), path.join(tempDir));
+ this.after(function() {
+ process.chdir(cwd);
+ shell.mv('-f', path.join(tempDir, 'blackberry'), path.join(cordova_project, 'platforms', 'blackberry'));
+ shell.mv('-f', path.join(tempDir, 'ios'), path.join(cordova_project, 'platforms', 'ios'));
+ });
+
+ process.chdir(cordova_project);
+
+ var s = spyOn(shell, 'exec');
+ var a_spy = spyOn(android_parser.prototype, 'update_project');
+ expect(function() {
+ cordova.emulate();
+ a_spy.mostRecentCall.args[1](); // fake out android parser
+ expect(s).toHaveBeenCalled();
+ }).not.toThrow();
+ });
+ it('should not run outside of a Cordova-based project', function() {
+ this.after(function() {
+ process.chdir(cwd);
+ });
+
+ shell.mkdir('-p', tempDir);
+ process.chdir(tempDir);
+
+ expect(function() {
+ cordova.emulate();
+ }).toThrow();
+ });
+ describe('per platform', function() {
+ beforeEach(function() {
+ process.chdir(cordova_project);
+ });
+
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+
+ describe('Android', function() {
+ var s;
+ beforeEach(function() {
+ s = spyOn(require('shelljs'), 'exec');
+ });
+ it('should shell out to run command on Android', function() {
+ cordova.emulate('android');
+ expect(s.mostRecentCall.args[0].match(/\/cordova\/run/)).not.toBeNull();
+ });
+ it('should call android_parser\'s update_project', function() {
+ var spy = spyOn(android_parser.prototype, 'update_project');
+ cordova.emulate('android');
+ expect(spy).toHaveBeenCalled();
+ });
+ });
+ describe('iOS', function() {
+ it('should shell out to emulate command on iOS', function() {
+ var s = spyOn(require('shelljs'), 'exec');
+ var proj_spy = spyOn(ios_parser.prototype, 'update_project');
+ cordova.emulate('ios');
+ proj_spy.mostRecentCall.args[1]();
+ expect(s).toHaveBeenCalled();
+ expect(s.mostRecentCall.args[0].match(/\/cordova\/emulate/)).not.toBeNull();
+ });
+ it('should call ios_parser\'s update_project', function() {
+ var s = spyOn(ios_parser.prototype, 'update_project');
+ cordova.emulate('ios');
+ expect(s).toHaveBeenCalled();
+ });
+ });
+ describe('BlackBerry', function() {
+ it('should shell out to ant command on blackberry', function() {
+ var proj_spy = spyOn(blackberry_parser.prototype, 'update_project');
+ var s = spyOn(require('shelljs'), 'exec');
+ cordova.emulate('blackberry');
+ proj_spy.mostRecentCall.args[1](); // update_project fake
+ expect(s).toHaveBeenCalled();
+ expect(s.mostRecentCall.args[0]).toMatch(/ant -f .*build\.xml" qnx load-simulator/);
+ });
+ it('should call blackberry_parser\'s update_project', function() {
+ var s = spyOn(blackberry_parser.prototype, 'update_project');
+ cordova.emulate('blackberry');
+ expect(s).toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('hooks', function() {
+ var s, sh, ap;
+ beforeEach(function() {
+ s = spyOn(hooker.prototype, 'fire').andReturn(true);
+ });
+
+ describe('when platforms are added', function() {
+ beforeEach(function() {
+ shell.mv('-f', path.join(cordova_project, 'platforms', 'blackberry'), path.join(tempDir));
+ shell.mv('-f', path.join(cordova_project, 'platforms', 'ios'), path.join(tempDir));
+ sh = spyOn(shell, 'exec');
+ ap = spyOn(android_parser.prototype, 'update_project');
+ process.chdir(cordova_project);
+ });
+ afterEach(function() {
+ shell.mv('-f', path.join(tempDir, 'blackberry'), path.join(cordova_project, 'platforms', 'blackberry'));
+ shell.mv('-f', path.join(tempDir, 'ios'), path.join(cordova_project, 'platforms', 'ios'));
+ process.chdir(cwd);
+ });
+
+ it('should fire before hooks through the hooker module', function() {
+ cordova.emulate();
+ expect(s).toHaveBeenCalledWith('before_emulate');
+ });
+ it('should fire after hooks through the hooker module', function() {
+ cordova.emulate();
+ ap.mostRecentCall.args[1](); // fake parser call
+ sh.mostRecentCall.args[2](0); //fake shell call
+ expect(s).toHaveBeenCalledWith('after_emulate');
+ });
+ });
+
+ describe('with no platforms added', function() {
+ beforeEach(function() {
+ cordova.create(tempDir);
+ process.chdir(tempDir);
+ });
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+ it('should not fire the hooker', function() {
+ spyOn(shell, 'exec');
+ expect(function() {
+ cordova.emulate();
+ }).toThrow();
+ expect(s).not.toHaveBeenCalledWith('before_emulate');
+ expect(s).not.toHaveBeenCalledWith('after_emulate');
+ });
+ });
+ });
+});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/cordova-cli/helper.js
----------------------------------------------------------------------
diff --git a/spec/cordova-cli/helper.js b/spec/cordova-cli/helper.js
new file mode 100644
index 0000000..2c4f331
--- /dev/null
+++ b/spec/cordova-cli/helper.js
@@ -0,0 +1,20 @@
+
+/**
+ 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.
+*/
+jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/cordova-cli/hooker.spec.js
----------------------------------------------------------------------
diff --git a/spec/cordova-cli/hooker.spec.js b/spec/cordova-cli/hooker.spec.js
new file mode 100644
index 0000000..4a0ca7d
--- /dev/null
+++ b/spec/cordova-cli/hooker.spec.js
@@ -0,0 +1,137 @@
+/**
+ 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.
+*/
+var hooker = require('../src/hooker'),
+ shell = require('shelljs'),
+ path = require('path'),
+ fs = require('fs'),
+ tempDir= path.join(__dirname, '..', 'temp'),
+ hooks = path.join(__dirname, 'fixtures', 'hooks'),
+ cordova= require('../cordova');
+
+var cwd = process.cwd();
+
+describe('hooker', function() {
+ it('should throw if provided directory is not a cordova project', function() {
+ shell.rm('-rf', tempDir);
+ shell.mkdir('-p', tempDir);
+ this.after(function() {
+ shell.rm('-rf', tempDir);
+ });
+
+ expect(function() {
+ var h = new hooker(tempDir);
+ }).toThrow();
+ });
+ it('should not throw if provided directory is a cordova project', function() {
+ cordova.create(tempDir);
+ this.after(function() {
+ shell.rm('-rf', tempDir);
+ });
+
+ expect(function() {
+ var h = new hooker(tempDir);
+ }).not.toThrow();
+ });
+
+ describe('fire method', function() {
+ var h;
+
+ beforeEach(function() {
+ cordova.create(tempDir);
+ h = new hooker(tempDir);
+ });
+ afterEach(function() {
+ shell.rm('-rf', tempDir);
+ });
+
+ describe('failure', function() {
+ it('should not throw if the hook is unrecognized', function() {
+ expect(function() {
+ h.fire('CLEAN YOUR SHORTS GODDAMNIT LIKE A BIG BOY!');
+ }).not.toThrow();
+ });
+ it('should throw if any script exits with non-zero code', function() {
+ var script = path.join(tempDir, '.cordova', 'hooks', 'before_build', 'fail.sh');
+ shell.cp(path.join(hooks, 'fail', 'fail.sh'), script);
+ fs.chmodSync(script, '754');
+ expect(function() {
+ h.fire('before_build');
+ }).toThrow();
+ });
+ });
+
+ describe('success', function() {
+ it('should execute all scripts in order and return true', function() {
+ var hook = path.join(tempDir, '.cordova', 'hooks', 'before_build');
+ shell.cp(path.join(hooks, 'test', '*'), path.join(hook, '.'));
+ fs.readdirSync(hook).forEach(function(script) {
+ fs.chmodSync(path.join(hook, script), '754');
+ });
+ var returnValue;
+ var s = spyOn(shell, 'exec').andReturn({code:0});
+ expect(function() {
+ returnValue = h.fire('before_build');
+ }).not.toThrow();
+ expect(returnValue).toBe(true);
+ expect(s.calls[0].args[0]).toMatch(/0.sh/);
+ expect(s.calls[1].args[0]).toMatch(/1.sh/);
+ });
+ it('should pass the project root folder as parameter into the project-level hooks', function() {
+ var hook = path.join(tempDir, '.cordova', 'hooks', 'before_build');
+ shell.cp(path.join(hooks, 'test', '0.sh'), path.join(hook, '.'));
+ fs.readdirSync(hook).forEach(function(script) {
+ fs.chmodSync(path.join(hook, script), '754');
+ });
+ var returnValue;
+ var s = spyOn(shell, 'exec').andReturn({code:0});
+ expect(function() {
+ returnValue = h.fire('before_build');
+ }).not.toThrow();
+ expect(returnValue).toBe(true);
+ var paramRegex = new RegExp('0.sh "'+tempDir+'"$');
+ expect(s.calls[0].args[0]).toMatch(paramRegex);
+ });
+ describe('module-level hooks', function() {
+ var handler = jasmine.createSpy();
+ var test_event = 'before_build';
+ afterEach(function() {
+ cordova.off(test_event, handler);
+ handler.reset();
+ });
+
+ it('should fire handlers using cordova.on', function() {
+ cordova.on(test_event, handler);
+ h.fire(test_event);
+ expect(handler).toHaveBeenCalled();
+ });
+ it('should pass the project root folder as parameter into the module-level handlers', function() {
+ cordova.on(test_event, handler);
+ h.fire('before_build');
+ expect(handler).toHaveBeenCalledWith(tempDir);
+ });
+ it('should be able to stop listening to events using cordova.off', function() {
+ cordova.on(test_event, handler);
+ cordova.off(test_event, handler);
+ h.fire('before_build');
+ expect(handler).not.toHaveBeenCalled();
+ });
+ });
+ });
+ });
+});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/cordova-cli/platform.spec.js
----------------------------------------------------------------------
diff --git a/spec/cordova-cli/platform.spec.js b/spec/cordova-cli/platform.spec.js
new file mode 100644
index 0000000..7138c7e
--- /dev/null
+++ b/spec/cordova-cli/platform.spec.js
@@ -0,0 +1,339 @@
+/**
+ 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.
+*/
+var cordova = require('../cordova'),
+ path = require('path'),
+ shell = require('shelljs'),
+ request = require('request'),
+ fs = require('fs'),
+ et = require('elementtree'),
+ config_parser = require('../src/config_parser'),
+ helper = require('./helper'),
+ util = require('../src/util'),
+ hooker = require('../src/hooker'),
+ platforms = require('../platforms'),
+ tempDir = path.join(__dirname, '..', 'temp');
+ android_parser = require('../src/metadata/android_parser'),
+ ios_parser = require('../src/metadata/ios_parser'),
+ cordova_project = path.join(__dirname, 'fixtures', 'projects', 'cordova'),
+ blackberry_parser = require('../src/metadata/blackberry_parser');
+
+var cwd = process.cwd();
+
+describe('platform command', function() {
+ beforeEach(function() {
+ // Make a temp directory
+ shell.rm('-rf', tempDir);
+ shell.mkdir('-p', tempDir);
+ });
+ it('should run inside a Cordova-based project', function() {
+ this.after(function() {
+ process.chdir(cwd);
+ });
+
+ cordova.create(tempDir);
+
+ process.chdir(tempDir);
+
+ expect(function() {
+ cordova.platform();
+ }).not.toThrow();
+ });
+ it('should not run outside of a Cordova-based project', function() {
+ this.after(function() {
+ process.chdir(cwd);
+ });
+
+ process.chdir(tempDir);
+
+ expect(function() {
+ cordova.platform();
+ }).toThrow();
+ });
+
+ describe('`ls`', function() {
+ beforeEach(function() {
+ process.chdir(cordova_project);
+ });
+
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+
+ it('should list out no platforms for a fresh project', function() {
+ shell.mv('-f', path.join(cordova_project, 'platforms', '*'), tempDir);
+ this.after(function() {
+ shell.mv('-f', path.join(tempDir, '*'), path.join(cordova_project, 'platforms'));
+ });
+ expect(cordova.platform('list').length).toEqual(0);
+ });
+
+ it('should list out added platforms in a project', function() {
+ expect(cordova.platform('list').length).toEqual(3);
+ });
+ });
+
+ describe('`add`', function() {
+ beforeEach(function() {
+ cordova.create(tempDir);
+ process.chdir(tempDir);
+ });
+
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+
+ describe('android', function() {
+ var sh, cr;
+ var fake_reqs_check = function() {
+ cr.mostRecentCall.args[0](false);
+ };
+ var fake_create = function(a_path) {
+ shell.mkdir('-p', a_path);
+ fs.writeFileSync(path.join(a_path, 'AndroidManifest.xml'), 'hi', 'utf-8');
+ sh.mostRecentCall.args[2](0, '');
+ };
+ beforeEach(function() {
+ sh = spyOn(shell, 'exec');
+ cr = spyOn(android_parser, 'check_requirements');
+ });
+
+ it('should shell out to android ./bin/create', function() {
+ cordova.platform('add', 'android');
+ fake_reqs_check();
+ var shell_cmd = sh.mostRecentCall.args[0];
+ expect(shell_cmd).toMatch(/android\/bin\/create/);
+ });
+ it('should call android_parser\'s update_project', function() {
+ var s = spyOn(android_parser.prototype, 'update_project');
+ cordova.platform('add', 'android');
+ fake_reqs_check();
+ fake_create(path.join(tempDir, 'platforms', 'android'));
+ expect(s).toHaveBeenCalled();
+ });
+ });
+ describe('ios', function() {
+ var sh, cr;
+ var fake_reqs_check = function() {
+ cr.mostRecentCall.args[0](false);
+ };
+ var fake_create = function(a_path) {
+ shell.mkdir('-p', a_path);
+ fs.writeFileSync(path.join(a_path, 'poo.xcodeproj'), 'hi', 'utf-8');
+ shell.mkdir('-p', path.join(a_path, 'poo'));
+ shell.cp(path.join(cordova_project, 'www', 'config.xml'), path.join(a_path, 'poo', 'config.xml'));
+ sh.mostRecentCall.args[2](0, '');
+ };
+ beforeEach(function() {
+ sh = spyOn(shell, 'exec');
+ cr = spyOn(ios_parser, 'check_requirements');
+ });
+ it('should shell out to ios ./bin/create', function() {
+ cordova.platform('add', 'ios');
+ fake_reqs_check();
+ var shell_cmd = sh.mostRecentCall.args[0];
+ expect(shell_cmd).toMatch(/ios\/bin\/create/);
+ });
+ it('should call ios_parser\'s update_project', function() {
+ var s = spyOn(ios_parser.prototype, 'update_project');
+ cordova.platform('add', 'ios');
+ fake_reqs_check();
+ fake_create(path.join(tempDir, 'platforms', 'ios'));
+ expect(s).toHaveBeenCalled();
+ });
+ });
+ describe('blackberry', function() {
+ var sh, cr;
+ var fake_reqs_check = function() {
+ cr.mostRecentCall.args[0](false);
+ };
+ var fake_create = function(a_path) {
+ shell.mkdir('-p', path.join(a_path, 'www'));
+ fs.writeFileSync(path.join(a_path, 'project.properties'), 'hi', 'utf-8');
+ fs.writeFileSync(path.join(a_path, 'build.xml'), 'hi', 'utf-8');
+ shell.cp(path.join(cordova_project, 'www', 'config.xml'), path.join(a_path, 'www', 'config.xml'));
+ sh.mostRecentCall.args[2](0, '');
+ };
+ beforeEach(function() {
+ sh = spyOn(shell, 'exec');
+ cr = spyOn(blackberry_parser, 'check_requirements');
+ });
+ it('should shell out to blackberry bin/create', function() {
+ cordova.platform('add', 'blackberry');
+ fake_reqs_check();
+ var shell_cmd = sh.mostRecentCall.args[0];
+ expect(shell_cmd).toMatch(/blackberry\/bin\/create/);
+ });
+ it('should call blackberry_parser\'s update_project', function() {
+ var s = spyOn(blackberry_parser.prototype, 'update_project');
+ cordova.platform('add', 'blackberry');
+ fake_reqs_check();
+ fake_create(path.join(tempDir, 'platforms', 'blackberry'));
+ expect(s).toHaveBeenCalled();
+ });
+ });
+ it('should handle multiple platforms', function() {
+ var arc = spyOn(android_parser, 'check_requirements');
+ var irc = spyOn(ios_parser, 'check_requirements');
+ var sh = spyOn(shell, 'exec');
+ cordova.platform('add', ['android', 'ios']);
+ arc.mostRecentCall.args[0](false);
+ irc.mostRecentCall.args[0](false);
+ expect(sh.argsForCall[0][0]).toMatch(/android\/bin\/create/);
+ expect(sh.argsForCall[1][0]).toMatch(/ios\/bin\/create/);
+ });
+ });
+
+ describe('`remove`',function() {
+ beforeEach(function() {
+ process.chdir(cordova_project);
+ shell.cp('-rf', path.join(cordova_project, 'platforms' ,'*'), tempDir);
+ });
+
+ afterEach(function() {
+ process.chdir(cwd);
+ shell.cp('-rf', path.join(tempDir, '*'), path.join(cordova_project, 'platforms'));
+ });
+
+ it('should remove a supported and added platform', function() {
+ cordova.platform('remove', 'android');
+ expect(cordova.platform('ls').length).toEqual(2);
+ });
+ it('should be able to remove multiple platforms', function() {
+ cordova.platform('remove', ['android','ios']);
+ expect(cordova.platform('ls').length).toEqual(1);
+ });
+ });
+
+ describe('hooks', function() {
+ var s;
+ beforeEach(function() {
+ cordova.create(tempDir);
+ process.chdir(tempDir);
+ s = spyOn(hooker.prototype, 'fire').andReturn(true);
+ });
+ afterEach(function() {
+ process.chdir(cwd);
+ shell.rm('-rf', tempDir);
+ });
+
+ describe('list (ls) hooks', function() {
+ it('should fire before hooks through the hooker module', function() {
+ cordova.platform();
+ expect(s).toHaveBeenCalledWith('before_platform_ls');
+ });
+ it('should fire after hooks through the hooker module', function() {
+ cordova.platform();
+ expect(s).toHaveBeenCalledWith('after_platform_ls');
+ });
+ });
+ describe('remove (rm) hooks', function() {
+ it('should fire before hooks through the hooker module', function() {
+ cordova.platform('rm', 'android');
+ expect(s).toHaveBeenCalledWith('before_platform_rm');
+ });
+ it('should fire after hooks through the hooker module', function() {
+ cordova.platform('rm', 'android');
+ expect(s).toHaveBeenCalledWith('after_platform_rm');
+ });
+ });
+ describe('add hooks', function() {
+ var sh, cr;
+ var fake_reqs_check = function() {
+ cr.mostRecentCall.args[0](false);
+ };
+ var fake_create = function(a_path) {
+ shell.mkdir('-p', a_path);
+ fs.writeFileSync(path.join(a_path, 'AndroidManifest.xml'), 'hi', 'utf-8');
+ sh.mostRecentCall.args[2](0, '');
+ };
+ beforeEach(function() {
+ sh = spyOn(shell, 'exec');
+ cr = spyOn(android_parser, 'check_requirements');
+ });
+ it('should fire before and after hooks through the hooker module', function() {
+ var ap = spyOn(android_parser.prototype, 'update_project');
+ cordova.platform('add', 'android');
+ fake_reqs_check();
+ fake_create(path.join(tempDir, 'platforms', 'android'));
+ ap.mostRecentCall.args[1](); // fake out update_project
+ expect(s).toHaveBeenCalledWith('before_platform_add');
+ expect(s).toHaveBeenCalledWith('after_platform_add');
+ });
+ });
+ });
+});
+
+describe('platform.supports(name, callback)', function() {
+ var androidParser = require('../src/metadata/android_parser');
+
+ beforeEach(function() {
+ spyOn(androidParser, 'check_requirements');
+ });
+
+ it('should require a platform name', function() {
+ expect(function() {
+ cordova.platform.supports(undefined, function(e){});
+ }).toThrow();
+ });
+
+ it('should require a callback function', function() {
+ expect(function() {
+ cordova.platform.supports('android', undefined);
+ }).toThrow();
+ });
+
+ describe('when platform is unknown', function() {
+ it('should trigger callback with false', function(done) {
+ cordova.platform.supports('windows-3.1', function(e) {
+ expect(e).toEqual(jasmine.any(Error));
+ done();
+ });
+ });
+ });
+
+ describe('when platform is supported', function() {
+ beforeEach(function() {
+ androidParser.check_requirements.andCallFake(function(callback) {
+ callback(null);
+ });
+ });
+
+ it('should trigger callback without error', function(done) {
+ cordova.platform.supports('android', function(e) {
+ expect(e).toBeNull();
+ done();
+ });
+ });
+ });
+
+ describe('when platform is unsupported', function() {
+ beforeEach(function() {
+ androidParser.check_requirements.andCallFake(function(callback) {
+ callback(new Error('could not find the android sdk'));
+ });
+ });
+
+ it('should trigger callback with error', function(done) {
+ cordova.platform.supports('android', function(e) {
+ expect(e).toEqual(jasmine.any(Error));
+ done();
+ });
+ });
+ });
+});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/cordova-cli/plugin.spec.js
----------------------------------------------------------------------
diff --git a/spec/cordova-cli/plugin.spec.js b/spec/cordova-cli/plugin.spec.js
new file mode 100644
index 0000000..3d370e7
--- /dev/null
+++ b/spec/cordova-cli/plugin.spec.js
@@ -0,0 +1,164 @@
+/**
+ 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.
+*/
+var cordova = require('../cordova'),
+ path = require('path'),
+ shell = require('shelljs'),
+ fs = require('fs'),
+ hooker = require('../src/hooker'),
+ tempDir = path.join(__dirname, '..', 'temp'),
+ fixturesDir = path.join(__dirname, 'fixtures'),
+ testPlugin = path.join(fixturesDir, 'plugins', 'test'),
+ cordova_project = path.join(fixturesDir, 'projects', 'cordova'),
+ androidPlugin = path.join(fixturesDir, 'plugins', 'android');
+
+var cwd = process.cwd();
+
+describe('plugin command', function() {
+ beforeEach(function() {
+ // Make a temp directory
+ shell.rm('-rf', tempDir);
+ shell.mkdir('-p', tempDir);
+ });
+
+ it('should run inside a Cordova-based project', function() {
+ this.after(function() {
+ process.chdir(cwd);
+ });
+
+ cordova.create(tempDir);
+
+ process.chdir(tempDir);
+
+ expect(function() {
+ cordova.plugin();
+ }).not.toThrow();
+ });
+ it('should not run outside of a Cordova-based project', function() {
+ this.after(function() {
+ process.chdir(cwd);
+ });
+
+ process.chdir(tempDir);
+
+ expect(function() {
+ cordova.plugin();
+ }).toThrow();
+ });
+
+ describe('edge cases', function() {
+ beforeEach(function() {
+ cordova.create(tempDir);
+ process.chdir(tempDir);
+ });
+
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+
+ it('should not fail when the plugins directory is missing', function() {
+ fs.rmdirSync('plugins');
+
+ expect(function() {
+ cordova.plugin();
+ }).not.toThrow();
+ });
+
+ it('should ignore files, like .gitignore, in the plugins directory', function() {
+ var someFile = path.join(tempDir, 'plugins', '.gitignore');
+ fs.writeFileSync(someFile, 'not a plugin');
+
+ expect(cordova.plugin('list')).toEqual('No plugins added. Use `cordova plugin add <plugin>`.');
+ });
+ });
+
+ describe('`ls`', function() {
+ beforeEach(function() {
+ cordova.create(tempDir);
+ });
+
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+
+ it('should list out no plugins for a fresh project', function() {
+ process.chdir(tempDir);
+
+ expect(cordova.plugin('list')).toEqual('No plugins added. Use `cordova plugin add <plugin>`.');
+ });
+ });
+
+ describe('`add`', function() {
+ beforeEach(function() {
+ cordova.create(tempDir);
+ process.chdir(tempDir);
+ });
+
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+ describe('failure', function() {
+ it('should throw if your app has no platforms added', function() {
+ expect(function() {
+ cordova.plugin('add', testPlugin);
+ }).toThrow('You need at least one platform added to your app. Use `cordova platform add <platform>`.');
+ });
+ it('should throw if plugin does not support any app platforms', function() {
+ process.chdir(cordova_project);
+ shell.mv('-f', path.join(cordova_project, 'platforms', 'android'), tempDir);
+ shell.mv('-f', path.join(cordova_project, 'platforms', 'blackberry'), tempDir);
+ this.after(function() {
+ process.chdir(cwd);
+ shell.mv('-f', path.join(tempDir, 'android'), path.join(cordova_project, 'platforms'));
+ shell.mv('-f', path.join(tempDir, 'blackberry'), path.join(cordova_project, 'platforms'));
+ });
+ expect(function() {
+ cordova.plugin('add', androidPlugin);
+ }).toThrow('Plugin "android" does not support any of your application\'s platforms. Plugin platforms: android; your application\'s platforms: ios');
+ });
+ it('should throw if plugin is already added to project', function() {
+ process.chdir(cordova_project);
+ var cb = jasmine.createSpy();
+ this.after(function() {
+ process.chdir(cordova_project);
+ cordova.plugin('rm', "test");
+ process.chdir(cwd);
+ });
+ runs(function() {
+ cordova.plugin('add', testPlugin, cb);
+ });
+ waitsFor(function() { return cb.wasCalled; }, 'frst add plugin');
+ runs(function(){
+ expect(function() {
+ cordova.plugin('add', testPlugin);
+ }).toThrow('Plugin "test" already added to project.');
+ });
+ });
+ it('should throw if plugin does not have a plugin.xml', function() {
+ process.chdir(cordova_project);
+ this.after(function() {
+ process.chdir(cwd);
+ });
+ expect(function() {
+ cordova.plugin('add', fixturesDir);
+ }).toThrow('Plugin "fixtures" does not have a plugin.xml in the root. Plugin must support the Cordova Plugin Specification: https://github.com/alunny/cordova-plugin-spec');
+ });
+ });
+ });
+});
+
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/cordova-cli/plugin_parser.spec.js
----------------------------------------------------------------------
diff --git a/spec/cordova-cli/plugin_parser.spec.js b/spec/cordova-cli/plugin_parser.spec.js
new file mode 100644
index 0000000..4391003
--- /dev/null
+++ b/spec/cordova-cli/plugin_parser.spec.js
@@ -0,0 +1,42 @@
+
+/**
+ 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.
+*/
+var cordova = require('../cordova'),
+ path = require('path'),
+ fs = require('fs'),
+ plugin_parser = require('../src/plugin_parser'),
+ et = require('elementtree'),
+ xml = path.join(__dirname, '..', 'fixtures', 'plugins', 'test', 'plugin.xml');
+
+describe('plugin.xml parser', function () {
+ it('should read a proper plugin.xml file', function() {
+ var cfg;
+ expect(function () {
+ cfg = new plugin_parser(xml);
+ }).not.toThrow();
+ expect(cfg).toBeDefined();
+ expect(cfg.doc).toBeDefined();
+ });
+ it('should be able to figure out which platforms the plugin supports', function() {
+ var cfg = new plugin_parser(xml);
+ expect(cfg.platforms.length).toBe(1);
+ expect(cfg.platforms.indexOf('ios') > -1).toBe(true);
+ });
+});
+
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/cordova-cli/prepare.spec.js
----------------------------------------------------------------------
diff --git a/spec/cordova-cli/prepare.spec.js b/spec/cordova-cli/prepare.spec.js
new file mode 100644
index 0000000..f232b3e
--- /dev/null
+++ b/spec/cordova-cli/prepare.spec.js
@@ -0,0 +1,133 @@
+/**
+ 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.
+*/
+var cordova = require('../cordova'),
+ et = require('elementtree'),
+ shell = require('shelljs'),
+ path = require('path'),
+ fs = require('fs'),
+ config_parser = require('../src/config_parser'),
+ android_parser = require('../src/metadata/android_parser'),
+ ios_parser = require('../src/metadata/ios_parser'),
+ blackberry_parser = require('../src/metadata/blackberry_parser'),
+ hooker = require('../src/hooker'),
+ fixtures = path.join(__dirname, 'fixtures'),
+ hooks = path.join(fixtures, 'hooks'),
+ tempDir = path.join(__dirname, '..', 'temp'),
+ cordova_project = path.join(fixtures, 'projects', 'cordova');
+
+var cwd = process.cwd();
+
+describe('prepare command', function() {
+ beforeEach(function() {
+ shell.rm('-rf', tempDir);
+ shell.mkdir('-p', tempDir);
+ });
+
+ it('should not run inside a Cordova-based project with no added platforms', function() {
+ this.after(function() {
+ process.chdir(cwd);
+ });
+
+ cordova.create(tempDir);
+ process.chdir(tempDir);
+ expect(function() {
+ cordova.prepare();
+ }).toThrow();
+ });
+
+ it('should run inside a Cordova-based project with at least one added platform', function() {
+ // move platform project fixtures over to fake cordova into thinking platforms were added
+ // TODO: possibly add this to helper?
+ shell.mv('-f', path.join(cordova_project, 'platforms', 'blackberry'), path.join(tempDir));
+ this.after(function() {
+ process.chdir(cwd);
+ shell.mv('-f', path.join(tempDir, 'blackberry'), path.join(cordova_project, 'platforms', 'blackberry'));
+ });
+
+ process.chdir(cordova_project);
+
+ var a_parser_spy = spyOn(android_parser.prototype, 'update_project');
+ var i_parser_spy = spyOn(ios_parser.prototype, 'update_project');
+ expect(function() {
+ cordova.prepare();
+ expect(a_parser_spy).toHaveBeenCalled();
+ expect(i_parser_spy).toHaveBeenCalled();
+ }).not.toThrow();
+ });
+ it('should not run outside of a Cordova-based project', function() {
+ this.after(function() {
+ process.chdir(cwd);
+ });
+
+ shell.mkdir('-p', tempDir);
+ process.chdir(tempDir);
+
+ expect(function() {
+ cordova.prepare();
+ }).toThrow();
+ });
+
+ describe('hooks', function() {
+ var s;
+ beforeEach(function() {
+ s = spyOn(hooker.prototype, 'fire').andReturn(true);
+ });
+
+ describe('when platforms are added', function() {
+ beforeEach(function() {
+ shell.mv('-f', path.join(cordova_project, 'platforms', 'blackberry'), path.join(tempDir));
+ shell.mv('-f', path.join(cordova_project, 'platforms', 'ios'), path.join(tempDir));
+ process.chdir(cordova_project);
+ });
+ afterEach(function() {
+ shell.mv('-f', path.join(tempDir, 'blackberry'), path.join(cordova_project, 'platforms', 'blackberry'));
+ shell.mv('-f', path.join(tempDir, 'ios'), path.join(cordova_project, 'platforms', 'ios'));
+ process.chdir(cwd);
+ });
+
+ it('should fire before hooks through the hooker module', function() {
+ cordova.prepare();
+ expect(s).toHaveBeenCalledWith('before_prepare');
+ });
+ it('should fire after hooks through the hooker module', function() {
+ var parser_spy = spyOn(android_parser.prototype, 'update_project');
+ cordova.prepare();
+ parser_spy.mostRecentCall.args[1](); // parser cb
+ expect(s).toHaveBeenCalledWith('after_prepare');
+ });
+ });
+
+ describe('with no platforms added', function() {
+ beforeEach(function() {
+ cordova.create(tempDir);
+ process.chdir(tempDir);
+ });
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+ it('should not fire the hooker', function() {
+ expect(function() {
+ cordova.prepare();
+ }).toThrow();
+ expect(s).not.toHaveBeenCalledWith('before_prepare');
+ expect(s).not.toHaveBeenCalledWith('after_prepare');
+ });
+ });
+ });
+});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/cordova-cli/serve.spec.js
----------------------------------------------------------------------
diff --git a/spec/cordova-cli/serve.spec.js b/spec/cordova-cli/serve.spec.js
new file mode 100644
index 0000000..8d00cab
--- /dev/null
+++ b/spec/cordova-cli/serve.spec.js
@@ -0,0 +1,132 @@
+
+/**
+ 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.
+*/
+var cordova = require('../cordova'),
+ path = require('path'),
+ shell = require('shelljs'),
+ request = require('request'),
+ fs = require('fs'),
+ util = require('../src/util'),
+ hooker = require('../src/hooker'),
+ tempDir = path.join(__dirname, '..', 'temp'),
+ http = require('http'),
+ android_parser = require('../src/metadata/android_parser'),
+ ios_parser = require('../src/metadata/ios_parser'),
+ blackberry_parser = require('../src/metadata/blackberry_parser');
+
+var cwd = process.cwd();
+
+xdescribe('serve command', function() {
+ beforeEach(function() {
+ // Make a temp directory
+ shell.rm('-rf', tempDir);
+ shell.mkdir('-p', tempDir);
+ });
+ it('should not run outside of a Cordova-based project', function() {
+ this.after(function() {
+ process.chdir(cwd);
+ });
+
+ process.chdir(tempDir);
+
+ expect(function() {
+ cordova.serve('android');
+ }).toThrow();
+ });
+
+
+ describe('`serve`', function() {
+ var payloads = {
+ android: 'This is the Android test file.',
+ ios: 'This is the iOS test file.'
+ };
+
+ beforeEach(function() {
+ cordova.create(tempDir);
+ process.chdir(tempDir);
+ cordova.platform('add', 'android');
+ cordova.platform('add', 'ios');
+
+ // Write testing HTML files into the directory.
+ fs.writeFileSync(path.join(tempDir, 'platforms', 'android', 'assets', 'www', 'test.html'), payloads.android);
+ fs.writeFileSync(path.join(tempDir, 'platforms', 'ios', 'www', 'test.html'), payloads.ios);
+ });
+
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+
+ function test_serve(platform, path, expectedContents, port) {
+ return function() {
+ var ret;
+ runs(function() {
+ ret = port ? cordova.serve(platform, port) : cordova.serve(platform);
+ });
+
+ waitsFor(function() {
+ return ret.server;
+ }, 'the server should start', 1000);
+
+ var done, errorCB;
+ runs(function() {
+ expect(ret.server).toBeDefined();
+ errorCB = jasmine.createSpy();
+ http.get({
+ host: 'localhost',
+ port: port || 8000,
+ path: path
+ }).on('response', function(res) {
+ var response = '';
+ res.on('data', function(data) {
+ response += data;
+ });
+ res.on('end', function() {
+ expect(res.statusCode).toEqual(200);
+ expect(response).toEqual(expectedContents);
+ done = true;
+ });
+ }).on('error', errorCB);
+ });
+
+ waitsFor(function() {
+ return done;
+ }, 'the HTTP request should complete', 1000);
+
+ runs(function() {
+ expect(done).toBeTruthy();
+ expect(errorCB).not.toHaveBeenCalled();
+
+ ret.server.close();
+ });
+ };
+ };
+
+ it('should serve from top-level www if the file exists there', function() {
+ var payload = 'This is test file.';
+ fs.writeFileSync(path.join(tempDir, 'www', 'test.html'), payload);
+ test_serve('android', '/test.html', payload)();
+ });
+
+ it('should fall back to assets/www on Android', test_serve('android', '/test.html', payloads.android));
+ it('should fall back to www on iOS', test_serve('ios', '/test.html', payloads.ios));
+
+ it('should honour a custom port setting', test_serve('android', '/test.html', payloads.android, 9001));
+ });
+});
+
[27/37] Add WP7 and WP8 platform files.
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/File.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/File.cs b/lib/cordova-wp7/templates/standalone/Plugins/File.cs
new file mode 100644
index 0000000..cde7a1c
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/File.cs
@@ -0,0 +1,1676 @@
+/*
+ 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.Diagnostics;
+using System.IO;
+using System.IO.IsolatedStorage;
+using System.Runtime.Serialization;
+using System.Security;
+using System.Text;
+using System.Windows;
+using System.Windows.Resources;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ /// <summary>
+ /// Provides access to isolated storage
+ /// </summary>
+ public class File : BaseCommand
+ {
+ // Error codes
+ public const int NOT_FOUND_ERR = 1;
+ public const int SECURITY_ERR = 2;
+ public const int ABORT_ERR = 3;
+ public const int NOT_READABLE_ERR = 4;
+ public const int ENCODING_ERR = 5;
+ public const int NO_MODIFICATION_ALLOWED_ERR = 6;
+ public const int INVALID_STATE_ERR = 7;
+ public const int SYNTAX_ERR = 8;
+ public const int INVALID_MODIFICATION_ERR = 9;
+ public const int QUOTA_EXCEEDED_ERR = 10;
+ public const int TYPE_MISMATCH_ERR = 11;
+ public const int PATH_EXISTS_ERR = 12;
+
+ // File system options
+ public const int TEMPORARY = 0;
+ public const int PERSISTENT = 1;
+ public const int RESOURCE = 2;
+ public const int APPLICATION = 3;
+
+ /// <summary>
+ /// Temporary directory name
+ /// </summary>
+ private readonly string TMP_DIRECTORY_NAME = "tmp";
+
+ /// <summary>
+ /// Represents error code for callback
+ /// </summary>
+ [DataContract]
+ public class ErrorCode
+ {
+ /// <summary>
+ /// Error code
+ /// </summary>
+ [DataMember(IsRequired = true, Name = "code")]
+ public int Code { get; set; }
+
+ /// <summary>
+ /// Creates ErrorCode object
+ /// </summary>
+ public ErrorCode(int code)
+ {
+ this.Code = code;
+ }
+ }
+
+ /// <summary>
+ /// Represents File action options.
+ /// </summary>
+ [DataContract]
+ public class FileOptions
+ {
+ /// <summary>
+ /// File path
+ /// </summary>
+ ///
+ private string _fileName;
+ [DataMember(Name = "fileName")]
+ public string FilePath
+ {
+ get
+ {
+ return this._fileName;
+ }
+
+ set
+ {
+ int index = value.IndexOfAny(new char[] { '#', '?' });
+ this._fileName = index > -1 ? value.Substring(0, index) : value;
+ }
+ }
+
+ /// <summary>
+ /// Full entryPath
+ /// </summary>
+ [DataMember(Name = "fullPath")]
+ public string FullPath { get; set; }
+
+ /// <summary>
+ /// Directory name
+ /// </summary>
+ [DataMember(Name = "dirName")]
+ public string DirectoryName { get; set; }
+
+ /// <summary>
+ /// Path to create file/directory
+ /// </summary>
+ [DataMember(Name = "path")]
+ public string Path { get; set; }
+
+ /// <summary>
+ /// The encoding to use to encode the file's content. Default is UTF8.
+ /// </summary>
+ [DataMember(Name = "encoding")]
+ public string Encoding { get; set; }
+
+ /// <summary>
+ /// Uri to get file
+ /// </summary>
+ ///
+ private string _uri;
+ [DataMember(Name = "uri")]
+ public string Uri
+ {
+ get
+ {
+ return this._uri;
+ }
+
+ set
+ {
+ int index = value.IndexOfAny(new char[] { '#', '?' });
+ this._uri = index > -1 ? value.Substring(0, index) : value;
+ }
+ }
+
+ /// <summary>
+ /// Size to truncate file
+ /// </summary>
+ [DataMember(Name = "size")]
+ public long Size { get; set; }
+
+ /// <summary>
+ /// Data to write in file
+ /// </summary>
+ [DataMember(Name = "data")]
+ public string Data { get; set; }
+
+ /// <summary>
+ /// Position the writing starts with
+ /// </summary>
+ [DataMember(Name = "position")]
+ public int Position { get; set; }
+
+ /// <summary>
+ /// Type of file system requested
+ /// </summary>
+ [DataMember(Name = "type")]
+ public int FileSystemType { get; set; }
+
+ /// <summary>
+ /// New file/directory name
+ /// </summary>
+ [DataMember(Name = "newName")]
+ public string NewName { get; set; }
+
+ /// <summary>
+ /// Destination directory to copy/move file/directory
+ /// </summary>
+ [DataMember(Name = "parent")]
+ public string Parent { get; set; }
+
+ /// <summary>
+ /// Options for getFile/getDirectory methods
+ /// </summary>
+ [DataMember(Name = "options")]
+ public CreatingOptions CreatingOpt { get; set; }
+
+ /// <summary>
+ /// Creates options object with default parameters
+ /// </summary>
+ public FileOptions()
+ {
+ this.SetDefaultValues(new StreamingContext());
+ }
+
+ /// <summary>
+ /// Initializes default values for class fields.
+ /// Implemented in separate method because default constructor is not invoked during deserialization.
+ /// </summary>
+ /// <param name="context"></param>
+ [OnDeserializing()]
+ public void SetDefaultValues(StreamingContext context)
+ {
+ this.Encoding = "UTF-8";
+ this.FilePath = "";
+ this.FileSystemType = -1;
+ }
+ }
+
+ /// <summary>
+ /// Stores image info
+ /// </summary>
+ [DataContract]
+ public class FileMetadata
+ {
+ [DataMember(Name = "fileName")]
+ public string FileName { get; set; }
+
+ [DataMember(Name = "fullPath")]
+ public string FullPath { get; set; }
+
+ [DataMember(Name = "type")]
+ public string Type { get; set; }
+
+ [DataMember(Name = "lastModifiedDate")]
+ public string LastModifiedDate { get; set; }
+
+ [DataMember(Name = "size")]
+ public long Size { get; set; }
+
+ public FileMetadata(string filePath)
+ {
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ if (string.IsNullOrEmpty(filePath))
+ {
+ throw new FileNotFoundException("File doesn't exist");
+ }
+ else if (!isoFile.FileExists(filePath))
+ {
+ // attempt to get it from the resources
+ if (filePath.IndexOf("www") == 0)
+ {
+ Uri fileUri = new Uri(filePath, UriKind.Relative);
+ StreamResourceInfo streamInfo = Application.GetResourceStream(fileUri);
+ if (streamInfo != null)
+ {
+ this.Size = streamInfo.Stream.Length;
+ this.FileName = filePath.Substring(filePath.LastIndexOf("/") + 1);
+ this.FullPath = filePath;
+ }
+ }
+ else
+ {
+ throw new FileNotFoundException("File doesn't exist");
+ }
+ }
+ else
+ {
+ //TODO get file size the other way if possible
+ using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(filePath, FileMode.Open, FileAccess.Read, isoFile))
+ {
+ this.Size = stream.Length;
+ }
+ this.FullPath = filePath;
+ this.FileName = System.IO.Path.GetFileName(filePath);
+ this.LastModifiedDate = isoFile.GetLastWriteTime(filePath).DateTime.ToString();
+ }
+ this.Type = MimeTypeMapper.GetMimeType(this.FileName);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Represents file or directory modification metadata
+ /// </summary>
+ [DataContract]
+ public class ModificationMetadata
+ {
+ /// <summary>
+ /// Modification time
+ /// </summary>
+ [DataMember]
+ public string modificationTime { get; set; }
+ }
+
+ /// <summary>
+ /// Represents file or directory entry
+ /// </summary>
+ [DataContract]
+ public class FileEntry
+ {
+
+ /// <summary>
+ /// File type
+ /// </summary>
+ [DataMember(Name = "isFile")]
+ public bool IsFile { get; set; }
+
+ /// <summary>
+ /// Directory type
+ /// </summary>
+ [DataMember(Name = "isDirectory")]
+ public bool IsDirectory { get; set; }
+
+ /// <summary>
+ /// File/directory name
+ /// </summary>
+ [DataMember(Name = "name")]
+ public string Name { get; set; }
+
+ /// <summary>
+ /// Full path to file/directory
+ /// </summary>
+ [DataMember(Name = "fullPath")]
+ public string FullPath { get; set; }
+
+ public bool IsResource { get; set; }
+
+ public static FileEntry GetEntry(string filePath, bool bIsRes=false)
+ {
+ FileEntry entry = null;
+ try
+ {
+ entry = new FileEntry(filePath, bIsRes);
+
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine("Exception in GetEntry for filePath :: " + filePath + " " + ex.Message);
+ }
+ return entry;
+ }
+
+ /// <summary>
+ /// Creates object and sets necessary properties
+ /// </summary>
+ /// <param name="filePath"></param>
+ public FileEntry(string filePath, bool bIsRes = false)
+ {
+ if (string.IsNullOrEmpty(filePath))
+ {
+ throw new ArgumentException();
+ }
+
+ if(filePath.Contains(" "))
+ {
+ Debug.WriteLine("FilePath with spaces :: " + filePath);
+ }
+
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ IsResource = bIsRes;
+ IsFile = isoFile.FileExists(filePath);
+ IsDirectory = isoFile.DirectoryExists(filePath);
+ if (IsFile)
+ {
+ this.Name = Path.GetFileName(filePath);
+ }
+ else if (IsDirectory)
+ {
+ this.Name = this.GetDirectoryName(filePath);
+ if (string.IsNullOrEmpty(Name))
+ {
+ this.Name = "/";
+ }
+ }
+ else
+ {
+ if (IsResource)
+ {
+ this.Name = Path.GetFileName(filePath);
+ }
+ else
+ {
+ throw new FileNotFoundException();
+ }
+ }
+
+ try
+ {
+ this.FullPath = filePath.Replace('\\', '/'); // new Uri(filePath).LocalPath;
+ }
+ catch (Exception)
+ {
+ this.FullPath = filePath;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Extracts directory name from path string
+ /// Path should refer to a directory, for example \foo\ or /foo.
+ /// </summary>
+ /// <param name="path"></param>
+ /// <returns></returns>
+ private string GetDirectoryName(string path)
+ {
+ if (String.IsNullOrEmpty(path))
+ {
+ return path;
+ }
+
+ string[] split = path.Split(new char[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries);
+ if (split.Length < 1)
+ {
+ return null;
+ }
+ else
+ {
+ return split[split.Length - 1];
+ }
+ }
+ }
+
+
+ /// <summary>
+ /// Represents info about requested file system
+ /// </summary>
+ [DataContract]
+ public class FileSystemInfo
+ {
+ /// <summary>
+ /// file system type
+ /// </summary>
+ [DataMember(Name = "name", IsRequired = true)]
+ public string Name { get; set; }
+
+ /// <summary>
+ /// Root directory entry
+ /// </summary>
+ [DataMember(Name = "root", EmitDefaultValue = false)]
+ public FileEntry Root { get; set; }
+
+ /// <summary>
+ /// Creates class instance
+ /// </summary>
+ /// <param name="name"></param>
+ /// <param name="rootEntry"> Root directory</param>
+ public FileSystemInfo(string name, FileEntry rootEntry = null)
+ {
+ Name = name;
+ Root = rootEntry;
+ }
+ }
+
+ [DataContract]
+ public class CreatingOptions
+ {
+ /// <summary>
+ /// Create file/directory if is doesn't exist
+ /// </summary>
+ [DataMember(Name = "create")]
+ public bool Create { get; set; }
+
+ /// <summary>
+ /// Generate an exception if create=true and file/directory already exists
+ /// </summary>
+ [DataMember(Name = "exclusive")]
+ public bool Exclusive { get; set; }
+
+
+ }
+
+ // returns null value if it fails.
+ private string[] getOptionStrings(string options)
+ {
+ string[] optStings = null;
+ try
+ {
+ optStings = JSON.JsonHelper.Deserialize<string[]>(options);
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION), CurrentCommandCallbackId);
+ }
+ return optStings;
+ }
+
+ /// <summary>
+ /// Gets amount of free space available for Isolated Storage
+ /// </summary>
+ /// <param name="options">No options is needed for this method</param>
+ public void getFreeDiskSpace(string options)
+ {
+ string callbackId = getOptionStrings(options)[0];
+
+ try
+ {
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, isoFile.AvailableFreeSpace), callbackId);
+ }
+ }
+ catch (IsolatedStorageException)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId);
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Check if file exists
+ /// </summary>
+ /// <param name="options">File path</param>
+ public void testFileExists(string options)
+ {
+ IsDirectoryOrFileExist(options, false);
+ }
+
+ /// <summary>
+ /// Check if directory exists
+ /// </summary>
+ /// <param name="options">directory name</param>
+ public void testDirectoryExists(string options)
+ {
+ IsDirectoryOrFileExist(options, true);
+ }
+
+ /// <summary>
+ /// Check if file or directory exist
+ /// </summary>
+ /// <param name="options">File path/Directory name</param>
+ /// <param name="isDirectory">Flag to recognize what we should check</param>
+ public void IsDirectoryOrFileExist(string options, bool isDirectory)
+ {
+ string[] args = getOptionStrings(options);
+ string callbackId = args[1];
+ FileOptions fileOptions = JSON.JsonHelper.Deserialize<FileOptions>(args[0]);
+ string filePath = args[0];
+
+ if (fileOptions == null)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION), callbackId);
+ }
+
+ try
+ {
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ bool isExist;
+ if (isDirectory)
+ {
+ isExist = isoFile.DirectoryExists(fileOptions.DirectoryName);
+ }
+ else
+ {
+ isExist = isoFile.FileExists(fileOptions.FilePath);
+ }
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, isExist), callbackId);
+ }
+ }
+ catch (IsolatedStorageException) // default handler throws INVALID_MODIFICATION_ERR
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId);
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ }
+ }
+
+ }
+
+ public void readAsDataURL(string options)
+ {
+ string[] optStrings = getOptionStrings(options);
+ string filePath = optStrings[0];
+ int startPos = int.Parse(optStrings[1]);
+ int endPos = int.Parse(optStrings[2]);
+ string callbackId = optStrings[3];
+
+ if (filePath != null)
+ {
+ try
+ {
+ string base64URL = null;
+
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ if (!isoFile.FileExists(filePath))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ return;
+ }
+ string mimeType = MimeTypeMapper.GetMimeType(filePath);
+
+ using (IsolatedStorageFileStream stream = isoFile.OpenFile(filePath, FileMode.Open, FileAccess.Read))
+ {
+ string base64String = GetFileContent(stream);
+ base64URL = "data:" + mimeType + ";base64," + base64String;
+ }
+ }
+
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, base64URL), callbackId);
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId);
+ }
+ }
+ }
+ }
+
+ public void readAsArrayBuffer(string options)
+ {
+ string[] optStrings = getOptionStrings(options);
+ string filePath = optStrings[0];
+ int startPos = int.Parse(optStrings[1]);
+ int endPos = int.Parse(optStrings[2]);
+ string callbackId = optStrings[3];
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR), callbackId);
+ }
+
+ public void readAsBinaryString(string options)
+ {
+ string[] optStrings = getOptionStrings(options);
+ string filePath = optStrings[0];
+ int startPos = int.Parse(optStrings[1]);
+ int endPos = int.Parse(optStrings[2]);
+ string callbackId = optStrings[3];
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR), callbackId);
+ }
+
+ public void readAsText(string options)
+ {
+ string[] optStrings = getOptionStrings(options);
+ string filePath = optStrings[0];
+ string encStr = optStrings[1];
+ int startPos = int.Parse(optStrings[2]);
+ int endPos = int.Parse(optStrings[3]);
+ string callbackId = optStrings[4];
+
+ try
+ {
+ string text = "";
+
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ if (!isoFile.FileExists(filePath))
+ {
+ readResourceAsText(options);
+ return;
+ }
+ Encoding encoding = Encoding.GetEncoding(encStr);
+
+ using (TextReader reader = new StreamReader(isoFile.OpenFile(filePath, FileMode.Open, FileAccess.Read), encoding))
+ {
+ text = reader.ReadToEnd();
+ if (startPos < 0)
+ {
+ startPos = Math.Max(text.Length + startPos, 0);
+ }
+ else if (startPos > 0)
+ {
+ startPos = Math.Min(text.Length, startPos);
+ }
+
+ if (endPos > 0)
+ {
+ endPos = Math.Min(text.Length, endPos);
+ }
+ else if (endPos < 0)
+ {
+ endPos = Math.Max(endPos + text.Length, 0);
+ }
+
+
+ text = text.Substring(startPos, endPos - startPos);
+
+ }
+ }
+
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, text), callbackId);
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex, callbackId))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Reads application resource as a text
+ /// </summary>
+ /// <param name="options">Path to a resource</param>
+ public void readResourceAsText(string options)
+ {
+ string[] optStrings = getOptionStrings(options);
+ string pathToResource = optStrings[0];
+ string encStr = optStrings[1];
+ int start = int.Parse(optStrings[2]);
+ int endMarker = int.Parse(optStrings[3]);
+ string callbackId = optStrings[4];
+
+ try
+ {
+ if (pathToResource.StartsWith("/"))
+ {
+ pathToResource = pathToResource.Remove(0, 1);
+ }
+
+ var resource = Application.GetResourceStream(new Uri(pathToResource, UriKind.Relative));
+
+ if (resource == null)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ return;
+ }
+
+ string text;
+ StreamReader streamReader = new StreamReader(resource.Stream);
+ text = streamReader.ReadToEnd();
+
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, text), callbackId);
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex, callbackId))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId);
+ }
+ }
+ }
+
+ public void truncate(string options)
+ {
+ string[] optStrings = getOptionStrings(options);
+
+ string filePath = optStrings[0];
+ int size = int.Parse(optStrings[1]);
+ string callbackId = optStrings[2];
+
+ try
+ {
+ long streamLength = 0;
+
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ if (!isoFile.FileExists(filePath))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ return;
+ }
+
+ using (FileStream stream = new IsolatedStorageFileStream(filePath, FileMode.Open, FileAccess.ReadWrite, isoFile))
+ {
+ if (0 <= size && size <= stream.Length)
+ {
+ stream.SetLength(size);
+ }
+ streamLength = stream.Length;
+ }
+ }
+
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, streamLength), callbackId);
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex, callbackId))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId);
+ }
+ }
+ }
+
+ //write:["filePath","data","position"],
+ public void write(string options)
+ {
+ // TODO: try/catch
+ string[] optStrings = getOptionStrings(options);
+
+ string filePath = optStrings[0];
+ string data = optStrings[1];
+ int position = int.Parse(optStrings[2]);
+ string callbackId = optStrings[3];
+
+ try
+ {
+ if (string.IsNullOrEmpty(data))
+ {
+ Debug.WriteLine("Expected some data to be send in the write command to {0}", filePath);
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION), callbackId);
+ return;
+ }
+
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ // create the file if not exists
+ if (!isoFile.FileExists(filePath))
+ {
+ var file = isoFile.CreateFile(filePath);
+ file.Close();
+ }
+
+ using (FileStream stream = new IsolatedStorageFileStream(filePath, FileMode.Open, FileAccess.ReadWrite, isoFile))
+ {
+ if (0 <= position && position <= stream.Length)
+ {
+ stream.SetLength(position);
+ }
+ using (BinaryWriter writer = new BinaryWriter(stream))
+ {
+ writer.Seek(0, SeekOrigin.End);
+ writer.Write(data.ToCharArray());
+ }
+ }
+ }
+
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, data.Length), callbackId);
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex, callbackId))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Look up metadata about this entry.
+ /// </summary>
+ /// <param name="options">filePath to entry</param>
+ public void getMetadata(string options)
+ {
+ string[] optStings = getOptionStrings(options);
+ string filePath = optStings[0];
+ string callbackId = optStings[1];
+
+ if (filePath != null)
+ {
+ try
+ {
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ if (isoFile.FileExists(filePath))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK,
+ new ModificationMetadata() { modificationTime = isoFile.GetLastWriteTime(filePath).DateTime.ToString() }), callbackId);
+ }
+ else if (isoFile.DirectoryExists(filePath))
+ {
+ string modTime = isoFile.GetLastWriteTime(filePath).DateTime.ToString();
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, new ModificationMetadata() { modificationTime = modTime }), callbackId);
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ }
+
+ }
+ }
+ catch (IsolatedStorageException)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId);
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId);
+ }
+ }
+ }
+
+ }
+
+
+ /// <summary>
+ /// Returns a File that represents the current state of the file that this FileEntry represents.
+ /// </summary>
+ /// <param name="filePath">filePath to entry</param>
+ /// <returns></returns>
+ public void getFileMetadata(string options)
+ {
+ string[] optStings = getOptionStrings(options);
+ string filePath = optStings[0];
+ string callbackId = optStings[1];
+
+ if (filePath != null)
+ {
+ try
+ {
+ FileMetadata metaData = new FileMetadata(filePath);
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, metaData), callbackId);
+ }
+ catch (IsolatedStorageException)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId);
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId);
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Look up the parent DirectoryEntry containing this Entry.
+ /// If this Entry is the root of IsolatedStorage, its parent is itself.
+ /// </summary>
+ /// <param name="options"></param>
+ public void getParent(string options)
+ {
+ string[] optStings = getOptionStrings(options);
+ string filePath = optStings[0];
+ string callbackId = optStings[1];
+
+ if (filePath != null)
+ {
+ try
+ {
+ if (string.IsNullOrEmpty(filePath))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION),callbackId);
+ return;
+ }
+
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ FileEntry entry;
+
+ if (isoFile.FileExists(filePath) || isoFile.DirectoryExists(filePath))
+ {
+
+
+ string path = this.GetParentDirectory(filePath);
+ entry = FileEntry.GetEntry(path);
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, entry),callbackId);
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR),callbackId);
+ }
+
+ }
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR),callbackId);
+ }
+ }
+ }
+ }
+
+ public void remove(string options)
+ {
+ string[] args = getOptionStrings(options);
+ string filePath = args[0];
+ string callbackId = args[1];
+
+ if (filePath != null)
+ {
+ try
+ {
+ if (filePath == "/" || filePath == "" || filePath == @"\")
+ {
+ throw new Exception("Cannot delete root file system") ;
+ }
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ if (isoFile.FileExists(filePath))
+ {
+ isoFile.DeleteFile(filePath);
+ }
+ else
+ {
+ if (isoFile.DirectoryExists(filePath))
+ {
+ isoFile.DeleteDirectory(filePath);
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR),callbackId);
+ return;
+ }
+ }
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK),callbackId);
+ }
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NO_MODIFICATION_ALLOWED_ERR),callbackId);
+ }
+ }
+ }
+ }
+
+ public void removeRecursively(string options)
+ {
+ string[] args = getOptionStrings(options);
+ string filePath = args[0];
+ string callbackId = args[1];
+
+ if (filePath != null)
+ {
+ if (string.IsNullOrEmpty(filePath))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION),callbackId);
+ }
+ else
+ {
+ if (removeDirRecursively(filePath, callbackId))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK), callbackId);
+ }
+ }
+ }
+ }
+
+ public void readEntries(string options)
+ {
+ string[] args = getOptionStrings(options);
+ string filePath = args[0];
+ string callbackId = args[1];
+
+ if (filePath != null)
+ {
+ try
+ {
+ if (string.IsNullOrEmpty(filePath))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION),callbackId);
+ return;
+ }
+
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ if (isoFile.DirectoryExists(filePath))
+ {
+ string path = File.AddSlashToDirectory(filePath);
+ List<FileEntry> entries = new List<FileEntry>();
+ string[] files = isoFile.GetFileNames(path + "*");
+ string[] dirs = isoFile.GetDirectoryNames(path + "*");
+ foreach (string file in files)
+ {
+ entries.Add(FileEntry.GetEntry(path + file));
+ }
+ foreach (string dir in dirs)
+ {
+ entries.Add(FileEntry.GetEntry(path + dir + "/"));
+ }
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, entries),callbackId);
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR),callbackId);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NO_MODIFICATION_ALLOWED_ERR),callbackId);
+ }
+ }
+ }
+ }
+
+ public void requestFileSystem(string options)
+ {
+ // TODO: try/catch
+ string[] optVals = getOptionStrings(options);
+ //FileOptions fileOptions = new FileOptions();
+ int fileSystemType = int.Parse(optVals[0]);
+ double size = double.Parse(optVals[1]);
+ string callbackId = optVals[2];
+
+
+ IsolatedStorageFile.GetUserStoreForApplication();
+
+ if (size > (10 * 1024 * 1024)) // 10 MB, compier will clean this up!
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, QUOTA_EXCEEDED_ERR), callbackId);
+ return;
+ }
+
+ try
+ {
+ if (size != 0)
+ {
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ long availableSize = isoFile.AvailableFreeSpace;
+ if (size > availableSize)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, QUOTA_EXCEEDED_ERR), callbackId);
+ return;
+ }
+ }
+ }
+
+ if (fileSystemType == PERSISTENT)
+ {
+ // TODO: this should be in it's own folder to prevent overwriting of the app assets, which are also in ISO
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, new FileSystemInfo("persistent", FileEntry.GetEntry("/"))), callbackId);
+ }
+ else if (fileSystemType == TEMPORARY)
+ {
+ using (IsolatedStorageFile isoStorage = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ if (!isoStorage.FileExists(TMP_DIRECTORY_NAME))
+ {
+ isoStorage.CreateDirectory(TMP_DIRECTORY_NAME);
+ }
+ }
+
+ string tmpFolder = "/" + TMP_DIRECTORY_NAME + "/";
+
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, new FileSystemInfo("temporary", FileEntry.GetEntry(tmpFolder))), callbackId);
+ }
+ else if (fileSystemType == RESOURCE)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, new FileSystemInfo("resource")), callbackId);
+ }
+ else if (fileSystemType == APPLICATION)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, new FileSystemInfo("application")), callbackId);
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NO_MODIFICATION_ALLOWED_ERR), callbackId);
+ }
+
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NO_MODIFICATION_ALLOWED_ERR), callbackId);
+ }
+ }
+ }
+
+ public void resolveLocalFileSystemURI(string options)
+ {
+
+ string[] optVals = getOptionStrings(options);
+ string uri = optVals[0].Split('?')[0];
+ string callbackId = optVals[1];
+
+ if (uri != null)
+ {
+ // a single '/' is valid, however, '/someDir' is not, but '/tmp//somedir' and '///someDir' are valid
+ if (uri.StartsWith("/") && uri.IndexOf("//") < 0 && uri != "/")
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, ENCODING_ERR), callbackId);
+ return;
+ }
+ try
+ {
+ // fix encoded spaces
+ string path = Uri.UnescapeDataString(uri);
+
+ FileEntry uriEntry = FileEntry.GetEntry(path);
+ if (uriEntry != null)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, uriEntry), callbackId);
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ }
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex, callbackId))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NO_MODIFICATION_ALLOWED_ERR), callbackId);
+ }
+ }
+ }
+ }
+
+ public void copyTo(string options)
+ {
+ TransferTo(options, false);
+ }
+
+ public void moveTo(string options)
+ {
+ TransferTo(options, true);
+ }
+
+ public void getFile(string options)
+ {
+ GetFileOrDirectory(options, false);
+ }
+
+ public void getDirectory(string options)
+ {
+ GetFileOrDirectory(options, true);
+ }
+
+ #region internal functionality
+
+ /// <summary>
+ /// Retrieves the parent directory name of the specified path,
+ /// </summary>
+ /// <param name="path">Path</param>
+ /// <returns>Parent directory name</returns>
+ private string GetParentDirectory(string path)
+ {
+ if (String.IsNullOrEmpty(path) || path == "/")
+ {
+ return "/";
+ }
+
+ if (path.EndsWith(@"/") || path.EndsWith(@"\"))
+ {
+ return this.GetParentDirectory(Path.GetDirectoryName(path));
+ }
+
+ string result = Path.GetDirectoryName(path);
+ if (result == null)
+ {
+ result = "/";
+ }
+
+ return result;
+ }
+
+ private bool removeDirRecursively(string fullPath,string callbackId)
+ {
+ try
+ {
+ if (fullPath == "/")
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NO_MODIFICATION_ALLOWED_ERR),callbackId);
+ return false;
+ }
+
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ if (isoFile.DirectoryExists(fullPath))
+ {
+ string tempPath = File.AddSlashToDirectory(fullPath);
+ string[] files = isoFile.GetFileNames(tempPath + "*");
+ if (files.Length > 0)
+ {
+ foreach (string file in files)
+ {
+ isoFile.DeleteFile(tempPath + file);
+ }
+ }
+ string[] dirs = isoFile.GetDirectoryNames(tempPath + "*");
+ if (dirs.Length > 0)
+ {
+ foreach (string dir in dirs)
+ {
+ if (!removeDirRecursively(tempPath + dir, callbackId))
+ {
+ return false;
+ }
+ }
+ }
+ isoFile.DeleteDirectory(fullPath);
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR),callbackId);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NO_MODIFICATION_ALLOWED_ERR),callbackId);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private bool CanonicalCompare(string pathA, string pathB)
+ {
+ string a = pathA.Replace("//", "/");
+ string b = pathB.Replace("//", "/");
+
+ return a.Equals(b, StringComparison.OrdinalIgnoreCase);
+ }
+
+ /*
+ * copyTo:["fullPath","parent", "newName"],
+ * moveTo:["fullPath","parent", "newName"],
+ */
+ private void TransferTo(string options, bool move)
+ {
+ // TODO: try/catch
+ string[] optStrings = getOptionStrings(options);
+ string fullPath = optStrings[0];
+ string parent = optStrings[1];
+ string newFileName = optStrings[2];
+ string callbackId = optStrings[3];
+
+ char[] invalids = Path.GetInvalidPathChars();
+
+ if (newFileName.IndexOfAny(invalids) > -1 || newFileName.IndexOf(":") > -1 )
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, ENCODING_ERR), callbackId);
+ return;
+ }
+
+ try
+ {
+ if ((parent == null) || (string.IsNullOrEmpty(parent)) || (string.IsNullOrEmpty(fullPath)))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ return;
+ }
+
+ string parentPath = File.AddSlashToDirectory(parent);
+ string currentPath = fullPath;
+
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ bool isFileExist = isoFile.FileExists(currentPath);
+ bool isDirectoryExist = isoFile.DirectoryExists(currentPath);
+ bool isParentExist = isoFile.DirectoryExists(parentPath);
+
+ if ( ( !isFileExist && !isDirectoryExist ) || !isParentExist )
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ return;
+ }
+ string newName;
+ string newPath;
+ if (isFileExist)
+ {
+ newName = (string.IsNullOrEmpty(newFileName))
+ ? Path.GetFileName(currentPath)
+ : newFileName;
+
+ newPath = Path.Combine(parentPath, newName);
+
+ // sanity check ..
+ // cannot copy file onto itself
+ if (CanonicalCompare(newPath,currentPath)) //(parent + newFileName))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, INVALID_MODIFICATION_ERR), callbackId);
+ return;
+ }
+ else if (isoFile.DirectoryExists(newPath))
+ {
+ // there is already a folder with the same name, operation is not allowed
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, INVALID_MODIFICATION_ERR), callbackId);
+ return;
+ }
+ else if (isoFile.FileExists(newPath))
+ { // remove destination file if exists, in other case there will be exception
+ isoFile.DeleteFile(newPath);
+ }
+
+ if (move)
+ {
+ isoFile.MoveFile(currentPath, newPath);
+ }
+ else
+ {
+ isoFile.CopyFile(currentPath, newPath, true);
+ }
+ }
+ else
+ {
+ newName = (string.IsNullOrEmpty(newFileName))
+ ? currentPath
+ : newFileName;
+
+ newPath = Path.Combine(parentPath, newName);
+
+ if (move)
+ {
+ // remove destination directory if exists, in other case there will be exception
+ // target directory should be empty
+ if (!newPath.Equals(currentPath) && isoFile.DirectoryExists(newPath))
+ {
+ isoFile.DeleteDirectory(newPath);
+ }
+
+ isoFile.MoveDirectory(currentPath, newPath);
+ }
+ else
+ {
+ CopyDirectory(currentPath, newPath, isoFile);
+ }
+ }
+ FileEntry entry = FileEntry.GetEntry(newPath);
+ if (entry != null)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, entry), callbackId);
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ }
+ }
+
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex, callbackId))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NO_MODIFICATION_ALLOWED_ERR), callbackId);
+ }
+ }
+ }
+
+ private bool HandleException(Exception ex, string cbId="")
+ {
+ bool handled = false;
+ string callbackId = String.IsNullOrEmpty(cbId) ? this.CurrentCommandCallbackId : cbId;
+ if (ex is SecurityException)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, SECURITY_ERR), callbackId);
+ handled = true;
+ }
+ else if (ex is FileNotFoundException)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ handled = true;
+ }
+ else if (ex is ArgumentException)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, ENCODING_ERR), callbackId);
+ handled = true;
+ }
+ else if (ex is IsolatedStorageException)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, INVALID_MODIFICATION_ERR), callbackId);
+ handled = true;
+ }
+ else if (ex is DirectoryNotFoundException)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ handled = true;
+ }
+ return handled;
+ }
+
+ private void CopyDirectory(string sourceDir, string destDir, IsolatedStorageFile isoFile)
+ {
+ string path = File.AddSlashToDirectory(sourceDir);
+
+ bool bExists = isoFile.DirectoryExists(destDir);
+
+ if (!bExists)
+ {
+ isoFile.CreateDirectory(destDir);
+ }
+
+ destDir = File.AddSlashToDirectory(destDir);
+
+ string[] files = isoFile.GetFileNames(path + "*");
+
+ if (files.Length > 0)
+ {
+ foreach (string file in files)
+ {
+ isoFile.CopyFile(path + file, destDir + file,true);
+ }
+ }
+ string[] dirs = isoFile.GetDirectoryNames(path + "*");
+ if (dirs.Length > 0)
+ {
+ foreach (string dir in dirs)
+ {
+ CopyDirectory(path + dir, destDir + dir, isoFile);
+ }
+ }
+ }
+
+ private void GetFileOrDirectory(string options, bool getDirectory)
+ {
+ FileOptions fOptions = new FileOptions();
+ string[] args = getOptionStrings(options);
+
+ fOptions.FullPath = args[0];
+ fOptions.Path = args[1];
+
+ string callbackId = args[3];
+
+ try
+ {
+ fOptions.CreatingOpt = JSON.JsonHelper.Deserialize<CreatingOptions>(args[2]);
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION), callbackId);
+ return;
+ }
+
+ try
+ {
+ if ((string.IsNullOrEmpty(fOptions.Path)) || (string.IsNullOrEmpty(fOptions.FullPath)))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ return;
+ }
+
+ string path;
+
+ if (fOptions.Path.Split(':').Length > 2)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, ENCODING_ERR), callbackId);
+ return;
+ }
+
+ try
+ {
+ path = Path.Combine(fOptions.FullPath + "/", fOptions.Path);
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, ENCODING_ERR), callbackId);
+ return;
+ }
+
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ bool isFile = isoFile.FileExists(path);
+ bool isDirectory = isoFile.DirectoryExists(path);
+ bool create = (fOptions.CreatingOpt == null) ? false : fOptions.CreatingOpt.Create;
+ bool exclusive = (fOptions.CreatingOpt == null) ? false : fOptions.CreatingOpt.Exclusive;
+ if (create)
+ {
+ if (exclusive && (isoFile.FileExists(path) || isoFile.DirectoryExists(path)))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, PATH_EXISTS_ERR), callbackId);
+ return;
+ }
+
+ // need to make sure the parent exists
+ // it is an error to create a directory whose immediate parent does not yet exist
+ // see issue: https://issues.apache.org/jira/browse/CB-339
+ string[] pathParts = path.Split('/');
+ string builtPath = pathParts[0];
+ for (int n = 1; n < pathParts.Length - 1; n++)
+ {
+ builtPath += "/" + pathParts[n];
+ if (!isoFile.DirectoryExists(builtPath))
+ {
+ Debug.WriteLine(String.Format("Error :: Parent folder \"{0}\" does not exist, when attempting to create \"{1}\"",builtPath,path));
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ return;
+ }
+ }
+
+ if ((getDirectory) && (!isDirectory))
+ {
+ isoFile.CreateDirectory(path);
+ }
+ else
+ {
+ if ((!getDirectory) && (!isFile))
+ {
+
+ IsolatedStorageFileStream fileStream = isoFile.CreateFile(path);
+ fileStream.Close();
+ }
+ }
+ }
+ else // (not create)
+ {
+ if ((!isFile) && (!isDirectory))
+ {
+ if (path.IndexOf("//www") == 0)
+ {
+ Uri fileUri = new Uri(path.Remove(0,2), UriKind.Relative);
+ StreamResourceInfo streamInfo = Application.GetResourceStream(fileUri);
+ if (streamInfo != null)
+ {
+ FileEntry _entry = FileEntry.GetEntry(fileUri.OriginalString,true);
+
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, _entry), callbackId);
+
+ //using (BinaryReader br = new BinaryReader(streamInfo.Stream))
+ //{
+ // byte[] data = br.ReadBytes((int)streamInfo.Stream.Length);
+
+ //}
+
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ }
+
+
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ }
+ return;
+ }
+ if (((getDirectory) && (!isDirectory)) || ((!getDirectory) && (!isFile)))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, TYPE_MISMATCH_ERR), callbackId);
+ return;
+ }
+ }
+ FileEntry entry = FileEntry.GetEntry(path);
+ if (entry != null)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, entry), callbackId);
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NO_MODIFICATION_ALLOWED_ERR), callbackId);
+ }
+ }
+ }
+
+ private static string AddSlashToDirectory(string dirPath)
+ {
+ if (dirPath.EndsWith("/"))
+ {
+ return dirPath;
+ }
+ else
+ {
+ return dirPath + "/";
+ }
+ }
+
+ /// <summary>
+ /// Returns file content in a form of base64 string
+ /// </summary>
+ /// <param name="stream">File stream</param>
+ /// <returns>Base64 representation of the file</returns>
+ private string GetFileContent(Stream stream)
+ {
+ int streamLength = (int)stream.Length;
+ byte[] fileData = new byte[streamLength + 1];
+ stream.Read(fileData, 0, streamLength);
+ stream.Close();
+ return Convert.ToBase64String(fileData);
+ }
+
+ #endregion
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/FileTransfer.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/FileTransfer.cs b/lib/cordova-wp7/templates/standalone/Plugins/FileTransfer.cs
new file mode 100644
index 0000000..e585895
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/FileTransfer.cs
@@ -0,0 +1,526 @@
+/*
+ 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.IO;
+using System.IO.IsolatedStorage;
+using System.Net;
+using System.Runtime.Serialization;
+using System.Windows;
+using System.Security;
+using System.Diagnostics;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ public class FileTransfer : BaseCommand
+ {
+ public class DownloadRequestState
+ {
+ // This class stores the State of the request.
+ public HttpWebRequest request;
+ public DownloadOptions options;
+
+ public DownloadRequestState()
+ {
+ request = null;
+ options = null;
+ }
+ }
+
+ /// <summary>
+ /// Boundary symbol
+ /// </summary>
+ private string Boundary = "----------------------------" + DateTime.Now.Ticks.ToString("x");
+
+ // Error codes
+ public const int FileNotFoundError = 1;
+ public const int InvalidUrlError = 2;
+ public const int ConnectionError = 3;
+
+ /// <summary>
+ /// Options for downloading file
+ /// </summary>
+ [DataContract]
+ public class DownloadOptions
+ {
+ /// <summary>
+ /// File path to download to
+ /// </summary>
+ [DataMember(Name = "filePath", IsRequired = true)]
+ public string FilePath { get; set; }
+
+ /// <summary>
+ /// Server address to the file to download
+ /// </summary>
+ [DataMember(Name = "url", IsRequired = true)]
+ public string Url { get; set; }
+ }
+
+ /// <summary>
+ /// Options for uploading file
+ /// </summary>
+ [DataContract]
+ public class UploadOptions
+ {
+ /// <summary>
+ /// File path to upload
+ /// </summary>
+ [DataMember(Name = "filePath", IsRequired = true)]
+ public string FilePath { get; set; }
+
+ /// <summary>
+ /// Server address
+ /// </summary>
+ [DataMember(Name = "server", IsRequired = true)]
+ public string Server { get; set; }
+
+ /// <summary>
+ /// File key
+ /// </summary>
+ [DataMember(Name = "fileKey")]
+ public string FileKey { get; set; }
+
+ /// <summary>
+ /// File name on the server
+ /// </summary>
+ [DataMember(Name = "fileName")]
+ public string FileName { get; set; }
+
+ /// <summary>
+ /// File Mime type
+ /// </summary>
+ [DataMember(Name = "mimeType")]
+ public string MimeType { get; set; }
+
+
+ /// <summary>
+ /// Additional options
+ /// </summary>
+ [DataMember(Name = "params")]
+ public string Params { get; set; }
+
+ /// <summary>
+ /// Flag to recognize if we should trust every host (only in debug environments)
+ /// </summary>
+ [DataMember(Name = "debug")]
+ public bool Debug { get; set; }
+
+ /// <summary>
+ /// Creates options object with default parameters
+ /// </summary>
+ public UploadOptions()
+ {
+ this.SetDefaultValues(new StreamingContext());
+ }
+
+ /// <summary>
+ /// Initializes default values for class fields.
+ /// Implemented in separate method because default constructor is not invoked during deserialization.
+ /// </summary>
+ /// <param name="context"></param>
+ [OnDeserializing()]
+ public void SetDefaultValues(StreamingContext context)
+ {
+ this.FileKey = "file";
+ this.FileName = "image.jpg";
+ this.MimeType = "image/jpeg";
+ }
+
+ }
+
+ /// <summary>
+ /// Uploading response info
+ /// </summary>
+ [DataContract]
+ public class FileUploadResult
+ {
+ /// <summary>
+ /// Amount of sent bytes
+ /// </summary>
+ [DataMember(Name = "bytesSent")]
+ public long BytesSent { get; set; }
+
+ /// <summary>
+ /// Server response code
+ /// </summary>
+ [DataMember(Name = "responseCode")]
+ public long ResponseCode { get; set; }
+
+ /// <summary>
+ /// Server response
+ /// </summary>
+ [DataMember(Name = "response", EmitDefaultValue = false)]
+ public string Response { get; set; }
+
+ /// <summary>
+ /// Creates FileUploadResult object with response values
+ /// </summary>
+ /// <param name="bytesSent">Amount of sent bytes</param>
+ /// <param name="responseCode">Server response code</param>
+ /// <param name="response">Server response</param>
+ public FileUploadResult(long bytesSent, long responseCode, string response)
+ {
+ this.BytesSent = bytesSent;
+ this.ResponseCode = responseCode;
+ this.Response = response;
+ }
+ }
+
+ /// <summary>
+ /// Represents transfer error codes for callback
+ /// </summary>
+ [DataContract]
+ public class FileTransferError
+ {
+ /// <summary>
+ /// Error code
+ /// </summary>
+ [DataMember(Name = "code", IsRequired = true)]
+ public int Code { get; set; }
+
+ /// <summary>
+ /// The source URI
+ /// </summary>
+ [DataMember(Name = "source", IsRequired = true)]
+ public string Source { get; set; }
+
+ /// <summary>
+ /// The target URI
+ /// </summary>
+ [DataMember(Name = "target", IsRequired = true)]
+ public string Target { get; set; }
+
+ /// <summary>
+ /// The http status code response from the remote URI
+ /// </summary>
+ [DataMember(Name = "http_status", IsRequired = true)]
+ public int HttpStatus { get; set; }
+
+ /// <summary>
+ /// Creates FileTransferError object
+ /// </summary>
+ /// <param name="errorCode">Error code</param>
+ public FileTransferError(int errorCode)
+ {
+ this.Code = errorCode;
+ this.Source = null;
+ this.Target = null;
+ this.HttpStatus = 0;
+ }
+ public FileTransferError(int errorCode, string source, string target, int status)
+ {
+ this.Code = errorCode;
+ this.Source = source;
+ this.Target = target;
+ this.HttpStatus = status;
+ }
+ }
+
+ /// <summary>
+ /// Upload options
+ /// </summary>
+ private UploadOptions uploadOptions;
+
+ /// <summary>
+ /// Bytes sent
+ /// </summary>
+ private long bytesSent;
+
+ /// <summary>
+ /// sends a file to a server
+ /// </summary>
+ /// <param name="options">Upload options</param>
+ public void upload(string options)
+ {
+ Debug.WriteLine("options = " + options);
+ options = options.Replace("{}", "null");
+
+ try
+ {
+ try
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+ uploadOptions = JSON.JsonHelper.Deserialize<UploadOptions>(args[0]);
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ Uri serverUri;
+ try
+ {
+ serverUri = new Uri(uploadOptions.Server);
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(InvalidUrlError, uploadOptions.Server, null, 0)));
+ return;
+ }
+ HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(serverUri);
+ webRequest.ContentType = "multipart/form-data;boundary=" + Boundary;
+ webRequest.Method = "POST";
+ webRequest.BeginGetRequestStream(WriteCallback, webRequest);
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(ConnectionError)));
+ }
+ }
+
+ public void download(string options)
+ {
+ DownloadOptions downloadOptions = null;
+ HttpWebRequest webRequest = null;
+
+ try
+ {
+ string[] optionStrings = JSON.JsonHelper.Deserialize<string[]>(options);
+
+ downloadOptions = new DownloadOptions();// JSON.JsonHelper.Deserialize<DownloadOptions>(options);
+ downloadOptions.Url = optionStrings[0];
+ downloadOptions.FilePath = optionStrings[1];
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ try
+ {
+ webRequest = (HttpWebRequest)WebRequest.Create(downloadOptions.Url);
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(InvalidUrlError, downloadOptions.Url, null, 0)));
+ return;
+ }
+
+ if (downloadOptions != null && webRequest != null)
+ {
+ DownloadRequestState state = new DownloadRequestState();
+ state.options = downloadOptions;
+ state.request = webRequest;
+ webRequest.BeginGetResponse(new AsyncCallback(downloadCallback), state);
+ }
+
+
+
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="asynchronousResult"></param>
+ private void downloadCallback(IAsyncResult asynchronousResult)
+ {
+ DownloadRequestState reqState = (DownloadRequestState)asynchronousResult.AsyncState;
+ HttpWebRequest request = reqState.request;
+
+ try
+ {
+ HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
+
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ // create the file if not exists
+ if (!isoFile.FileExists(reqState.options.FilePath))
+ {
+ var file = isoFile.CreateFile(reqState.options.FilePath);
+ file.Close();
+ }
+
+ using (FileStream fileStream = new IsolatedStorageFileStream(reqState.options.FilePath, FileMode.Open, FileAccess.Write, isoFile))
+ {
+ long totalBytes = response.ContentLength;
+ int bytesRead = 0;
+ using (BinaryReader reader = new BinaryReader(response.GetResponseStream()))
+ {
+
+ using (BinaryWriter writer = new BinaryWriter(fileStream))
+ {
+ int BUFFER_SIZE = 1024;
+ byte[] buffer;
+
+ while (true)
+ {
+ buffer = reader.ReadBytes(BUFFER_SIZE);
+ // fire a progress event ?
+ bytesRead += buffer.Length;
+ if (buffer.Length > 0)
+ {
+ writer.Write(buffer);
+ }
+ else
+ {
+ writer.Close();
+ reader.Close();
+ fileStream.Close();
+ break;
+ }
+ }
+ }
+
+ }
+
+
+ }
+ }
+ WPCordovaClassLib.Cordova.Commands.File.FileEntry entry = new WPCordovaClassLib.Cordova.Commands.File.FileEntry(reqState.options.FilePath);
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, entry));
+ }
+ catch (IsolatedStorageException)
+ {
+ // Trying to write the file somewhere within the IsoStorage.
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(FileNotFoundError)));
+ }
+ catch (SecurityException)
+ {
+ // Trying to write the file somewhere not allowed.
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(FileNotFoundError)));
+ }
+ catch (WebException webex)
+ {
+ // TODO: probably need better work here to properly respond with all http status codes back to JS
+ // Right now am jumping through hoops just to detect 404.
+ if ((webex.Status == WebExceptionStatus.ProtocolError && ((HttpWebResponse)webex.Response).StatusCode == HttpStatusCode.NotFound) || webex.Status == WebExceptionStatus.UnknownError)
+ {
+ // Weird MSFT detection of 404... seriously... just give us the f(*&#$@ status code as a number ffs!!!
+ // "Numbers for HTTP status codes? Nah.... let's create our own set of enums/structs to abstract that stuff away."
+ // FACEPALM
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(ConnectionError, null, null, 404)));
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(ConnectionError)));
+ }
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(FileNotFoundError)));
+ }
+ }
+
+
+
+ /// <summary>
+ /// Read file from Isolated Storage and sends it to server
+ /// </summary>
+ /// <param name="asynchronousResult"></param>
+ private void WriteCallback(IAsyncResult asynchronousResult)
+ {
+ try
+ {
+ HttpWebRequest webRequest = (HttpWebRequest)asynchronousResult.AsyncState;
+ using (Stream requestStream = (webRequest.EndGetRequestStream(asynchronousResult)))
+ {
+ string lineStart = "--";
+ string lineEnd = Environment.NewLine;
+ byte[] boundaryBytes = System.Text.Encoding.UTF8.GetBytes(lineStart + Boundary + lineEnd);
+ string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"" + lineEnd + lineEnd + "{1}" + lineEnd;
+
+ if (uploadOptions.Params != null)
+ {
+
+ string[] arrParams = uploadOptions.Params.Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries);
+
+ foreach (string param in arrParams)
+ {
+ string[] split = param.Split('=');
+ string key = split[0];
+ string val = split[1];
+ requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
+ string formItem = string.Format(formdataTemplate, key, val);
+ byte[] formItemBytes = System.Text.Encoding.UTF8.GetBytes(formItem);
+ requestStream.Write(formItemBytes, 0, formItemBytes.Length);
+ }
+ requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
+ }
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ if (!isoFile.FileExists(uploadOptions.FilePath))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(FileNotFoundError, uploadOptions.Server, uploadOptions.FilePath, 0)));
+ return;
+ }
+
+ using (FileStream fileStream = new IsolatedStorageFileStream(uploadOptions.FilePath, FileMode.Open, isoFile))
+ {
+ string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"" + lineEnd + "Content-Type: {2}" + lineEnd + lineEnd;
+ string header = string.Format(headerTemplate, uploadOptions.FileKey, uploadOptions.FileName, uploadOptions.MimeType);
+ byte[] headerBytes = System.Text.Encoding.UTF8.GetBytes(header);
+ requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
+ requestStream.Write(headerBytes, 0, headerBytes.Length);
+ byte[] buffer = new byte[4096];
+ int bytesRead = 0;
+
+ while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
+ {
+ requestStream.Write(buffer, 0, bytesRead);
+ bytesSent += bytesRead;
+ }
+ }
+ byte[] endRequest = System.Text.Encoding.UTF8.GetBytes(lineEnd + lineStart + Boundary + lineStart + lineEnd);
+ requestStream.Write(endRequest, 0, endRequest.Length);
+ }
+ }
+ webRequest.BeginGetResponse(ReadCallback, webRequest);
+ }
+ catch (Exception)
+ {
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(ConnectionError)));
+ });
+ }
+ }
+
+ /// <summary>
+ /// Reads response into FileUploadResult
+ /// </summary>
+ /// <param name="asynchronousResult"></param>
+ private void ReadCallback(IAsyncResult asynchronousResult)
+ {
+ try
+ {
+ HttpWebRequest webRequest = (HttpWebRequest)asynchronousResult.AsyncState;
+ using (HttpWebResponse response = (HttpWebResponse)webRequest.EndGetResponse(asynchronousResult))
+ {
+ using (Stream streamResponse = response.GetResponseStream())
+ {
+ using (StreamReader streamReader = new StreamReader(streamResponse))
+ {
+ string responseString = streamReader.ReadToEnd();
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, new FileUploadResult(bytesSent, (long)response.StatusCode, responseString)));
+ });
+ }
+ }
+ }
+ }
+ catch (Exception)
+ {
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ FileTransferError transferError = new FileTransferError(ConnectionError, uploadOptions.Server, uploadOptions.FilePath, 403);
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, transferError));
+ });
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/GeoLocation.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/GeoLocation.cs b/lib/cordova-wp7/templates/standalone/Plugins/GeoLocation.cs
new file mode 100644
index 0000000..c53cb29
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/GeoLocation.cs
@@ -0,0 +1,34 @@
+/*
+ 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.Runtime.Serialization;
+using System.Threading;
+using System.Device.Location;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ /// <summary>
+ /// This is a command stub, the browser provides the correct implementation. We use this to trigger the static analyzer that we require this permission
+ /// </summary>
+ public class GeoLocation
+ {
+ /* Unreachable code, by design -jm */
+ private void triggerGeoInclusion()
+ {
+ new GeoCoordinateWatcher();
+ }
+ }
+}
[25/37] Add WP7 and WP8 platform files.
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/MimeTypeMapper.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/MimeTypeMapper.cs b/lib/cordova-wp7/templates/standalone/Plugins/MimeTypeMapper.cs
new file mode 100644
index 0000000..01ba4cb
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/MimeTypeMapper.cs
@@ -0,0 +1,99 @@
+/*
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+using System.Collections.Generic;
+using System.IO;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ /// <summary>
+ /// Represents file extension to mime type mapper.
+ /// </summary>
+ public static class MimeTypeMapper
+ {
+ /// <summary>
+ /// For unknown type it is recommended to use 'application/octet-stream'
+ /// http://stackoverflow.com/questions/1176022/unknown-file-type-mime
+ /// </summary>
+ private static string DefaultMimeType = "application/octet-stream";
+
+ /// <summary>
+ /// Stores mime type for all necessary extension
+ /// </summary>
+ private static readonly Dictionary<string, string> MIMETypesDictionary = new Dictionary<string, string>
+ {
+ {"avi", "video/x-msvideo"},
+ {"bmp", "image/bmp"},
+ {"gif", "image/gif"},
+ {"jpe", "image/jpeg"},
+ {"jpeg", "image/jpeg"},
+ {"jpg", "image/jpeg"},
+ {"mov", "video/quicktime"},
+ {"mp2", "audio/mpeg"},
+ {"mp3", "audio/mpeg"},
+ {"mp4", "video/mp4"},
+ {"mpe", "video/mpeg"},
+ {"mpeg", "video/mpeg"},
+ {"mpg", "video/mpeg"},
+ {"mpga", "audio/mpeg"},
+ {"pbm", "image/x-portable-bitmap"},
+ {"pcm", "audio/x-pcm"},
+ {"pct", "image/pict"},
+ {"pgm", "image/x-portable-graymap"},
+ {"pic", "image/pict"},
+ {"pict", "image/pict"},
+ {"png", "image/png"},
+ {"pnm", "image/x-portable-anymap"},
+ {"pnt", "image/x-macpaint"},
+ {"pntg", "image/x-macpaint"},
+ {"ppm", "image/x-portable-pixmap"},
+ {"qt", "video/quicktime"},
+ {"ra", "audio/x-pn-realaudio"},
+ {"ram", "audio/x-pn-realaudio"},
+ {"ras", "image/x-cmu-raster"},
+ {"rgb", "image/x-rgb"},
+ {"snd", "audio/basic"},
+ {"txt", "text/plain"},
+ {"tif", "image/tiff"},
+ {"tiff", "image/tiff"},
+ {"wav", "audio/x-wav"},
+ {"wbmp", "image/vnd.wap.wbmp"},
+
+ };
+ /// <summary>
+ /// Gets mime type by file extension
+ /// </summary>
+ /// <param name="fileName">file name to extract extension</param>
+ /// <returns>mime type</returns>
+ public static string GetMimeType(string fileName)
+ {
+ string ext = Path.GetExtension(fileName);
+
+ // invalid extension
+ if (string.IsNullOrEmpty(ext) || !ext.StartsWith("."))
+ {
+ return DefaultMimeType;
+ }
+
+ ext = ext.Remove(0, 1);
+
+ if (MIMETypesDictionary.ContainsKey(ext))
+ {
+ return MIMETypesDictionary[ext];
+ }
+
+ return DefaultMimeType;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/NetworkStatus.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/NetworkStatus.cs b/lib/cordova-wp7/templates/standalone/Plugins/NetworkStatus.cs
new file mode 100644
index 0000000..12eb061
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/NetworkStatus.cs
@@ -0,0 +1,129 @@
+/*
+ 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.Net;
+using System.Net.NetworkInformation;
+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.Net.NetworkInformation;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+
+ // http://msdn.microsoft.com/en-us/library/microsoft.phone.net.networkinformation(v=VS.92).aspx
+ // http://msdn.microsoft.com/en-us/library/microsoft.phone.net.networkinformation.devicenetworkinformation(v=VS.92).aspx
+
+ public class NetworkStatus : BaseCommand
+ {
+ const string UNKNOWN = "unknown";
+ const string ETHERNET = "ethernet";
+ const string WIFI = "wifi";
+ const string CELL_2G = "2g";
+ const string CELL_3G = "3g";
+ const string CELL_4G = "4g";
+ const string NONE = "none";
+ const string CELL = "cellular";
+
+ private bool HasCallback = false;
+
+ public NetworkStatus()
+ {
+ DeviceNetworkInformation.NetworkAvailabilityChanged += new EventHandler<NetworkNotificationEventArgs>(ChangeDetected);
+ }
+
+ public override void OnResume(object sender, Microsoft.Phone.Shell.ActivatedEventArgs e)
+ {
+ this.getConnectionInfo("");
+ }
+
+ public void getConnectionInfo(string empty)
+ {
+ HasCallback = true;
+ updateConnectionType(checkConnectionType());
+ }
+
+ private string checkConnectionType()
+ {
+ if (DeviceNetworkInformation.IsNetworkAvailable)
+ {
+ if (DeviceNetworkInformation.IsWiFiEnabled)
+ {
+ return WIFI;
+ }
+ else
+ {
+ return DeviceNetworkInformation.IsCellularDataEnabled ? CELL : UNKNOWN;
+ }
+ }
+ return NONE;
+ }
+
+ private string checkConnectionType(NetworkInterfaceSubType type)
+ {
+ switch (type)
+ {
+ case NetworkInterfaceSubType.Cellular_1XRTT: //cell
+ case NetworkInterfaceSubType.Cellular_GPRS: //cell
+ return CELL;
+ case NetworkInterfaceSubType.Cellular_EDGE: //2
+ return CELL_2G;
+ case NetworkInterfaceSubType.Cellular_3G:
+ case NetworkInterfaceSubType.Cellular_EVDO: //3
+ case NetworkInterfaceSubType.Cellular_EVDV: //3
+ case NetworkInterfaceSubType.Cellular_HSPA: //3
+ return CELL_3G;
+ case NetworkInterfaceSubType.WiFi:
+ return WIFI;
+ case NetworkInterfaceSubType.Unknown:
+ case NetworkInterfaceSubType.Desktop_PassThru:
+ default:
+ return UNKNOWN;
+ }
+ }
+
+ void ChangeDetected(object sender, NetworkNotificationEventArgs e)
+ {
+ switch (e.NotificationType)
+ {
+ case NetworkNotificationType.InterfaceConnected:
+ updateConnectionType(checkConnectionType(e.NetworkInterface.InterfaceSubtype));
+ break;
+ case NetworkNotificationType.InterfaceDisconnected:
+ updateConnectionType(NONE);
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void updateConnectionType(string type)
+ {
+ // This should also implicitly fire offline/online events as that is handled on the JS side
+ if (this.HasCallback)
+ {
+ PluginResult result = new PluginResult(PluginResult.Status.OK, type);
+ result.KeepCallback = true;
+ DispatchCommandResult(result);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/Notification.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/Notification.cs b/lib/cordova-wp7/templates/standalone/Plugins/Notification.cs
new file mode 100644
index 0000000..11f14bd
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/Notification.cs
@@ -0,0 +1,367 @@
+/*
+ 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.Windows;
+using System.Windows.Controls;
+using Microsoft.Devices;
+using System.Runtime.Serialization;
+using System.Threading;
+using System.Windows.Resources;
+using Microsoft.Phone.Controls;
+using Microsoft.Xna.Framework.Audio;
+using WPCordovaClassLib.Cordova.UI;
+using System.Diagnostics;
+
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ public class Notification : BaseCommand
+ {
+ static ProgressBar progressBar = null;
+ const int DEFAULT_DURATION = 5;
+
+ private NotificationBox notifyBox;
+
+ private class NotifBoxData
+ {
+ public NotificationBox previous;
+ public string callbackId;
+ }
+
+ private PhoneApplicationPage Page
+ {
+ get
+ {
+ PhoneApplicationPage page = null;
+ PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
+ if (frame != null)
+ {
+ page = frame.Content as PhoneApplicationPage;
+ }
+ return page;
+ }
+ }
+
+ // blink api - doesn't look like there is an equivalent api we can use...
+
+ [DataContract]
+ public class AlertOptions
+ {
+ [OnDeserializing]
+ public void OnDeserializing(StreamingContext context)
+ {
+ // set defaults
+ this.message = "message";
+ this.title = "Alert";
+ this.buttonLabel = "ok";
+ }
+
+ /// <summary>
+ /// message to display in the alert box
+ /// </summary>
+ [DataMember]
+ public string message;
+
+ /// <summary>
+ /// title displayed on the alert window
+ /// </summary>
+ [DataMember]
+ public string title;
+
+ /// <summary>
+ /// text to display on the button
+ /// </summary>
+ [DataMember]
+ public string buttonLabel;
+ }
+
+ public void alert(string options)
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+ AlertOptions alertOpts = new AlertOptions();
+ alertOpts.message = args[0];
+ alertOpts.title = args[1];
+ alertOpts.buttonLabel = args[2];
+ string aliasCurrentCommandCallbackId = args[3];
+
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ PhoneApplicationPage page = Page;
+ if (page != null)
+ {
+ Grid grid = page.FindName("LayoutRoot") as Grid;
+ if (grid != null)
+ {
+ var previous = notifyBox;
+ notifyBox = new NotificationBox();
+ notifyBox.Tag = new NotifBoxData{ previous = previous, callbackId = aliasCurrentCommandCallbackId };
+ notifyBox.PageTitle.Text = alertOpts.title;
+ notifyBox.SubTitle.Text = alertOpts.message;
+ Button btnOK = new Button();
+ btnOK.Content = alertOpts.buttonLabel;
+ btnOK.Click += new RoutedEventHandler(btnOK_Click);
+ btnOK.Tag = 1;
+ notifyBox.ButtonPanel.Children.Add(btnOK);
+ grid.Children.Add(notifyBox);
+
+ if (previous == null)
+ {
+ page.BackKeyPress += page_BackKeyPress;
+ }
+ }
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.INSTANTIATION_EXCEPTION));
+ }
+ });
+ }
+
+ public void confirm(string options)
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+ AlertOptions alertOpts = new AlertOptions();
+ alertOpts.message = args[0];
+ alertOpts.title = args[1];
+ alertOpts.buttonLabel = args[2];
+ string aliasCurrentCommandCallbackId = args[3];
+
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ PhoneApplicationPage page = Page;
+ if (page != null)
+ {
+ Grid grid = page.FindName("LayoutRoot") as Grid;
+ if (grid != null)
+ {
+ var previous = notifyBox;
+ notifyBox = new NotificationBox();
+ notifyBox.Tag = new NotifBoxData{ previous = previous, callbackId = aliasCurrentCommandCallbackId };
+ notifyBox.PageTitle.Text = alertOpts.title;
+ notifyBox.SubTitle.Text = alertOpts.message;
+
+ string[] labels = JSON.JsonHelper.Deserialize<string[]>(alertOpts.buttonLabel);
+
+ if (labels == null)
+ {
+ labels = alertOpts.buttonLabel.Split(',');
+ }
+
+ for (int n = 0; n < labels.Length; n++)
+ {
+ Button btn = new Button();
+ btn.Content = labels[n];
+ btn.Tag = n;
+ btn.Click += new RoutedEventHandler(btnOK_Click);
+ notifyBox.ButtonPanel.Children.Add(btn);
+ }
+
+ grid.Children.Add(notifyBox);
+ if (previous == null)
+ {
+ page.BackKeyPress += page_BackKeyPress;
+ }
+ }
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.INSTANTIATION_EXCEPTION));
+ }
+ });
+ }
+
+ void page_BackKeyPress(object sender, System.ComponentModel.CancelEventArgs e)
+ {
+ PhoneApplicationPage page = sender as PhoneApplicationPage;
+ string callbackId = "";
+ if (page != null && notifyBox != null)
+ {
+ Grid grid = page.FindName("LayoutRoot") as Grid;
+ if (grid != null)
+ {
+ grid.Children.Remove(notifyBox);
+ NotifBoxData notifBoxData = notifyBox.Tag as NotifBoxData;
+ notifyBox = notifBoxData.previous;
+ callbackId = notifBoxData.callbackId;
+ }
+ if (notifyBox == null)
+ {
+ page.BackKeyPress -= page_BackKeyPress;
+ }
+ e.Cancel = true;
+ }
+
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, 0), callbackId);
+ }
+
+ void btnOK_Click(object sender, RoutedEventArgs e)
+ {
+ Button btn = sender as Button;
+ FrameworkElement notifBoxParent = null;
+ int retVal = 0;
+ string callbackId = "";
+ if (btn != null)
+ {
+ retVal = (int)btn.Tag + 1;
+
+ notifBoxParent = btn.Parent as FrameworkElement;
+ while ((notifBoxParent = notifBoxParent.Parent as FrameworkElement) != null &&
+ !(notifBoxParent is NotificationBox)) ;
+ }
+ if (notifBoxParent != null)
+ {
+ PhoneApplicationPage page = Page;
+ if (page != null)
+ {
+ Grid grid = page.FindName("LayoutRoot") as Grid;
+ if (grid != null)
+ {
+ grid.Children.Remove(notifBoxParent);
+ }
+
+ NotifBoxData notifBoxData = notifBoxParent.Tag as NotifBoxData;
+ notifyBox = notifBoxData.previous;
+ callbackId = notifBoxData.callbackId;
+
+ if (notifyBox == null)
+ {
+ page.BackKeyPress -= page_BackKeyPress;
+ }
+ }
+
+ }
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, retVal),callbackId);
+ }
+
+
+
+ public void beep(string options)
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+ int times = int.Parse(args[0]);
+
+ string resourcePath = BaseCommand.GetBaseURL() + "resources/notification-beep.wav";
+
+ StreamResourceInfo sri = Application.GetResourceStream(new Uri(resourcePath, UriKind.Relative));
+
+ if (sri != null)
+ {
+ SoundEffect effect = SoundEffect.FromStream(sri.Stream);
+ SoundEffectInstance inst = effect.CreateInstance();
+ ThreadPool.QueueUserWorkItem((o) =>
+ {
+ // cannot interact with UI !!
+ do
+ {
+ inst.Play();
+ Thread.Sleep(effect.Duration + TimeSpan.FromMilliseconds(100));
+ }
+ while (--times > 0);
+
+ });
+
+ }
+
+ // TODO: may need a listener to trigger DispatchCommandResult after the alarm has finished executing...
+ DispatchCommandResult();
+ }
+
+ // Display an indeterminate progress indicator
+ public void activityStart(string unused)
+ {
+
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
+
+ if (frame != null)
+ {
+ PhoneApplicationPage page = frame.Content as PhoneApplicationPage;
+
+ if (page != null)
+ {
+ var temp = page.FindName("LayoutRoot");
+ Grid grid = temp as Grid;
+ if (grid != null)
+ {
+ if (progressBar != null)
+ {
+ grid.Children.Remove(progressBar);
+ }
+ progressBar = new ProgressBar();
+ progressBar.IsIndeterminate = true;
+ progressBar.IsEnabled = true;
+
+ grid.Children.Add(progressBar);
+ }
+ }
+ }
+ });
+ }
+
+
+ // Remove our indeterminate progress indicator
+ public void activityStop(string unused)
+ {
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ if (progressBar != null)
+ {
+ progressBar.IsEnabled = false;
+ PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
+ if (frame != null)
+ {
+ PhoneApplicationPage page = frame.Content as PhoneApplicationPage;
+ if (page != null)
+ {
+ Grid grid = page.FindName("LayoutRoot") as Grid;
+ if (grid != null)
+ {
+ grid.Children.Remove(progressBar);
+ }
+ }
+ }
+ progressBar = null;
+ }
+ });
+ }
+
+ public void vibrate(string vibrateDuration)
+ {
+
+ int msecs = 200; // set default
+
+ try
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(vibrateDuration);
+
+ msecs = int.Parse(args[0]);
+ if (msecs < 1)
+ {
+ msecs = 1;
+ }
+ }
+ catch (FormatException)
+ {
+
+ }
+
+ VibrateController.Default.Start(TimeSpan.FromMilliseconds(msecs));
+
+ // TODO: may need to add listener to trigger DispatchCommandResult when the vibration ends...
+ DispatchCommandResult();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/UI/AudioCaptureTask.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/UI/AudioCaptureTask.cs b/lib/cordova-wp7/templates/standalone/Plugins/UI/AudioCaptureTask.cs
new file mode 100644
index 0000000..9f43d23
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/UI/AudioCaptureTask.cs
@@ -0,0 +1,107 @@
+/*
+ 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.IO;
+using System.Windows;
+using Microsoft.Phone.Controls;
+using Microsoft.Phone.Tasks;
+
+namespace WPCordovaClassLib.Cordova.UI
+{
+ /// <summary>
+ /// Allows an application to launch the Audio Recording application.
+ /// Use this to allow users to record audio from your application.
+ /// </summary>
+ public class AudioCaptureTask
+ {
+ /// <summary>
+ /// Represents recorded audio returned from a call to the Show method of
+ /// a WPCordovaClassLib.Cordova.Controls.AudioCaptureTask object
+ /// </summary>
+ public class AudioResult : TaskEventArgs
+ {
+ /// <summary>
+ /// Initializes a new instance of the AudioResult class.
+ /// </summary>
+ public AudioResult()
+ { }
+
+ /// <summary>
+ /// Initializes a new instance of the AudioResult class
+ /// with the specified Microsoft.Phone.Tasks.TaskResult.
+ /// </summary>
+ /// <param name="taskResult">Associated Microsoft.Phone.Tasks.TaskResult</param>
+ public AudioResult(TaskResult taskResult)
+ : base(taskResult)
+ { }
+
+ /// <summary>
+ /// Gets the file name of the recorded audio.
+ /// </summary>
+ public Stream AudioFile { get; internal set; }
+
+ /// <summary>
+ /// Gets the stream containing the data for the recorded audio.
+ /// </summary>
+ public string AudioFileName { get; internal set; }
+ }
+
+ /// <summary>
+ /// Occurs when a audio recording task is completed.
+ /// </summary>
+ public event EventHandler<AudioResult> Completed;
+
+ /// <summary>
+ /// Shows Audio Recording application
+ /// </summary>
+ public void Show()
+ {
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ var root = Application.Current.RootVisual as PhoneApplicationFrame;
+
+ root.Navigated += new System.Windows.Navigation.NavigatedEventHandler(NavigationService_Navigated);
+
+ string baseUrl = WPCordovaClassLib.Cordova.Commands.BaseCommand.GetBaseURL();
+ // dummy parameter is used to always open a fresh version
+ root.Navigate(new System.Uri(baseUrl + "CordovaLib/UI/AudioRecorder.xaml?dummy=" + Guid.NewGuid().ToString(), UriKind.Relative));
+
+ });
+ }
+
+ /// <summary>
+ /// Performs additional configuration of the recording application.
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="e"></param>
+ private void NavigationService_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
+ {
+ if (!(e.Content is AudioRecorder)) return;
+
+ (Application.Current.RootVisual as PhoneApplicationFrame).Navigated -= NavigationService_Navigated;
+
+ AudioRecorder audioRecorder = (AudioRecorder)e.Content;
+
+ if (audioRecorder != null)
+ {
+ audioRecorder.Completed += this.Completed;
+ }
+ else if (this.Completed != null)
+ {
+ this.Completed(this, new AudioResult(TaskResult.Cancel));
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/UI/AudioRecorder.xaml
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/UI/AudioRecorder.xaml b/lib/cordova-wp7/templates/standalone/Plugins/UI/AudioRecorder.xaml
new file mode 100644
index 0000000..0fd26ab
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/UI/AudioRecorder.xaml
@@ -0,0 +1,66 @@
+<!--
+ 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.
+-->
+<phone:PhoneApplicationPage
+ x:Class="WPCordovaClassLib.Cordova.UI.AudioRecorder"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
+ xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ FontFamily="{StaticResource PhoneFontFamilyNormal}"
+ FontSize="{StaticResource PhoneFontSizeNormal}"
+ Foreground="{StaticResource PhoneForegroundBrush}"
+ SupportedOrientations="Portrait" Orientation="Portrait"
+ mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
+ shell:SystemTray.IsVisible="True">
+
+ <!--LayoutRoot is the root grid where all page content is placed-->
+ <Grid x:Name="LayoutRoot" Background="Transparent">
+ <Grid.RowDefinitions>
+ <RowDefinition Height="Auto"/>
+ <RowDefinition Height="*"/>
+ </Grid.RowDefinitions>
+
+ <!--TitlePanel contains the name of the application and page title-->
+ <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="0,17,0,28">
+ <TextBlock x:Name="PageTitle" Text="Audio recorder" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
+ </StackPanel>
+
+ <!--ContentPanel - place additional content here-->
+ <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
+ <Button Name="btnStartStop" Content="Start" Height="72" HorizontalAlignment="Left" Margin="156,96,0,0" VerticalAlignment="Top" Width="160" Click="btnStartStop_Click" />
+ <Button Name="btnTake" Content="Take" IsEnabled="False" Height="72" HorizontalAlignment="Left" Margin="155,182,0,0" VerticalAlignment="Top" Width="160" Click="btnTake_Click" />
+ <TextBlock Height="30" HorizontalAlignment="Left" Margin="168,60,0,0" Name="txtDuration" Text="Duration: 00:00" VerticalAlignment="Top" />
+ </Grid>
+ </Grid>
+
+ <!--Sample code showing usage of ApplicationBar-->
+ <!--<phone:PhoneApplicationPage.ApplicationBar>
+ <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
+ <shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="Button 1"/>
+ <shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="Button 2"/>
+ <shell:ApplicationBar.MenuItems>
+ <shell:ApplicationBarMenuItem Text="MenuItem 1"/>
+ <shell:ApplicationBarMenuItem Text="MenuItem 2"/>
+ </shell:ApplicationBar.MenuItems>
+ </shell:ApplicationBar>
+ </phone:PhoneApplicationPage.ApplicationBar>-->
+
+</phone:PhoneApplicationPage>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/UI/AudioRecorder.xaml.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/UI/AudioRecorder.xaml.cs b/lib/cordova-wp7/templates/standalone/Plugins/UI/AudioRecorder.xaml.cs
new file mode 100644
index 0000000..bc8ba6f
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/UI/AudioRecorder.xaml.cs
@@ -0,0 +1,306 @@
+/*
+ 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 Microsoft.Phone.Controls;
+using Microsoft.Phone.Tasks;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Audio;
+using System;
+using System.IO;
+using System.IO.IsolatedStorage;
+using System.Windows;
+using System.Windows.Threading;
+using WPCordovaClassLib.Cordova.Commands;
+using AudioResult = WPCordovaClassLib.Cordova.UI.AudioCaptureTask.AudioResult;
+
+namespace WPCordovaClassLib.Cordova.UI
+{
+ /// <summary>
+ /// Implements Audio Recording application
+ /// </summary>
+ public partial class AudioRecorder : PhoneApplicationPage
+ {
+
+ #region Constants
+
+ private const string RecordingStartCaption = "Start";
+ private const string RecordingStopCaption = "Stop";
+
+ private const string LocalFolderName = "AudioCache";
+ private const string FileNameFormat = "Audio-{0}.wav";
+
+ #endregion
+
+ #region Callbacks
+
+ /// <summary>
+ /// Occurs when a audio recording task is completed.
+ /// </summary>
+ public event EventHandler<AudioResult> Completed;
+
+ #endregion
+
+ #region Fields
+
+ /// <summary>
+ /// Audio source
+ /// </summary>
+ private Microphone microphone;
+
+ /// <summary>
+ /// Temporary buffer to store audio chunk
+ /// </summary>
+ private byte[] buffer;
+
+ /// <summary>
+ /// Recording duration
+ /// </summary>
+ private TimeSpan duration;
+
+ /// <summary>
+ /// Output buffer
+ /// </summary>
+ private MemoryStream memoryStream;
+
+ /// <summary>
+ /// Xna game loop dispatcher
+ /// </summary>
+ DispatcherTimer dtXna;
+
+ /// <summary>
+ /// Recording result, dispatched back when recording page is closed
+ /// </summary>
+ private AudioResult result = new AudioResult(TaskResult.Cancel);
+
+ /// <summary>
+ /// Whether we are recording audio now
+ /// </summary>
+ private bool IsRecording
+ {
+ get
+ {
+ return (this.microphone != null && this.microphone.State == MicrophoneState.Started);
+ }
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Creates new instance of the AudioRecorder class.
+ /// </summary>
+ public AudioRecorder()
+ {
+
+ this.InitializeXnaGameLoop();
+
+ // microphone requires special XNA initialization to work
+ InitializeComponent();
+ }
+
+ /// <summary>
+ /// Starts recording, data is stored in memory
+ /// </summary>
+ private void StartRecording()
+ {
+ this.microphone = Microphone.Default;
+ this.microphone.BufferDuration = TimeSpan.FromMilliseconds(500);
+
+ this.btnTake.IsEnabled = false;
+ this.btnStartStop.Content = RecordingStopCaption;
+
+ this.buffer = new byte[microphone.GetSampleSizeInBytes(this.microphone.BufferDuration)];
+ this.microphone.BufferReady += new EventHandler<EventArgs>(MicrophoneBufferReady);
+
+ this.memoryStream = new MemoryStream();
+ this.memoryStream.InitializeWavStream(this.microphone.SampleRate);
+
+ this.duration = new TimeSpan(0);
+
+ this.microphone.Start();
+ }
+
+ /// <summary>
+ /// Stops recording
+ /// </summary>
+ private void StopRecording()
+ {
+ this.microphone.Stop();
+
+ this.microphone.BufferReady -= MicrophoneBufferReady;
+
+ this.microphone = null;
+
+ btnStartStop.Content = RecordingStartCaption;
+
+ // check there is some data
+ this.btnTake.IsEnabled = true;
+ }
+
+ /// <summary>
+ /// Handles Start/Stop events
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="e"></param>
+ private void btnStartStop_Click(object sender, RoutedEventArgs e)
+ {
+
+ if (this.IsRecording)
+ {
+ this.StopRecording();
+ }
+ else
+ {
+ this.StartRecording();
+ }
+ }
+
+ /// <summary>
+ /// Handles Take button click
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="e"></param>
+ private void btnTake_Click(object sender, RoutedEventArgs e)
+ {
+ this.result = this.SaveAudioClipToLocalStorage();
+
+ if (Completed != null)
+ {
+ Completed(this, result);
+ }
+
+ if (this.NavigationService.CanGoBack)
+ {
+ this.NavigationService.GoBack();
+ }
+ }
+
+ /// <summary>
+ /// Handles page closing event, stops recording if needed and dispatches results.
+ /// </summary>
+ /// <param name="e"></param>
+ protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
+ {
+ if (IsRecording)
+ {
+ StopRecording();
+ }
+
+ this.FinalizeXnaGameLoop();
+
+ base.OnNavigatedFrom(e);
+ }
+
+ /// <summary>
+ /// Copies data from microphone to memory storages and updates recording state
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="e"></param>
+ private void MicrophoneBufferReady(object sender, EventArgs e)
+ {
+ this.microphone.GetData(this.buffer);
+ this.memoryStream.Write(this.buffer, 0, this.buffer.Length);
+ TimeSpan bufferDuration = this.microphone.BufferDuration;
+
+ this.Dispatcher.BeginInvoke(() =>
+ {
+ this.duration += bufferDuration;
+
+ this.txtDuration.Text = "Duration: " +
+ this.duration.Minutes.ToString().PadLeft(2, '0') + ":" +
+ this.duration.Seconds.ToString().PadLeft(2, '0');
+ });
+
+ }
+
+ /// <summary>
+ /// Writes audio data from memory to isolated storage
+ /// </summary>
+ /// <returns></returns>
+ private AudioResult SaveAudioClipToLocalStorage()
+ {
+ if (this.memoryStream == null || this.memoryStream.Length <= 0)
+ {
+ return new AudioResult(TaskResult.Cancel);
+ }
+
+ this.memoryStream.UpdateWavStream();
+
+ // save audio data to local isolated storage
+
+ string filename = String.Format(FileNameFormat, Guid.NewGuid().ToString());
+
+ try
+ {
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+
+ if (!isoFile.DirectoryExists(LocalFolderName))
+ {
+ isoFile.CreateDirectory(LocalFolderName);
+ }
+
+ string filePath = System.IO.Path.Combine("/" + LocalFolderName + "/", filename);
+
+ this.memoryStream.Seek(0, SeekOrigin.Begin);
+
+ using (IsolatedStorageFileStream fileStream = isoFile.CreateFile(filePath))
+ {
+
+ this.memoryStream.CopyTo(fileStream);
+ }
+
+ AudioResult result = new AudioResult(TaskResult.OK);
+ result.AudioFileName = filePath;
+
+ result.AudioFile = this.memoryStream;
+ result.AudioFile.Seek(0, SeekOrigin.Begin);
+
+ return result;
+ }
+
+
+
+ }
+ catch (Exception)
+ {
+ //TODO: log or do something else
+ throw;
+ }
+ }
+
+ /// <summary>
+ /// Special initialization required for the microphone: XNA game loop
+ /// </summary>
+ private void InitializeXnaGameLoop()
+ {
+ // Timer to simulate the XNA game loop (Microphone is from XNA)
+ this.dtXna = new DispatcherTimer();
+ this.dtXna.Interval = TimeSpan.FromMilliseconds(33);
+ this.dtXna.Tick += delegate { try { FrameworkDispatcher.Update(); } catch { } };
+ this.dtXna.Start();
+ }
+ /// <summary>
+ /// Finalizes XNA game loop for microphone
+ /// </summary>
+ private void FinalizeXnaGameLoop()
+ {
+ // Timer to simulate the XNA game loop (Microphone is from XNA)
+ if (dtXna != null)
+ {
+ dtXna.Stop();
+ dtXna = null;
+ }
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/UI/ImageCapture.xaml
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/UI/ImageCapture.xaml b/lib/cordova-wp7/templates/standalone/Plugins/UI/ImageCapture.xaml
new file mode 100644
index 0000000..a7eee21
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/UI/ImageCapture.xaml
@@ -0,0 +1,26 @@
+<phone:PhoneApplicationPage
+ x:Class="WPCordovaClassLib.Cordova.UI.ImageCapture"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
+ xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ FontFamily="{StaticResource PhoneFontFamilyNormal}"
+ FontSize="{StaticResource PhoneFontSizeNormal}"
+ Foreground="{StaticResource PhoneForegroundBrush}"
+ SupportedOrientations="PortraitOrLandscape" Orientation="Portrait"
+ mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
+ shell:SystemTray.IsVisible="True">
+
+ <!--LayoutRoot is the root grid where all page content is placed-->
+ <Grid x:Name="LayoutRoot" Background="Yellow">
+ <Grid.RowDefinitions>
+ <RowDefinition Height="Auto"/>
+ <RowDefinition Height="*"/>
+ </Grid.RowDefinitions>
+
+ </Grid>
+
+
+</phone:PhoneApplicationPage>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/UI/ImageCapture.xaml.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/UI/ImageCapture.xaml.cs b/lib/cordova-wp7/templates/standalone/Plugins/UI/ImageCapture.xaml.cs
new file mode 100644
index 0000000..234b444
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/UI/ImageCapture.xaml.cs
@@ -0,0 +1,109 @@
+/*
+ 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.IO;
+using System.Windows;
+using Microsoft.Phone.Controls;
+using Microsoft.Phone.Tasks;
+
+namespace WPCordovaClassLib.Cordova.UI
+{
+ public partial class ImageCapture : PhoneApplicationPage
+ {
+ public ImageCapture()
+ {
+ InitializeComponent();
+ }
+ }
+
+ public class ImageCaptureTask
+ {
+ /// <summary>
+ /// Represents an image returned from a call to the Show method of
+ /// a WPCordovaClassLib.Cordova.Controls.ImageCaptureTask object
+ /// </summary>
+ //public class AudioResult : TaskEventArgs
+ //{
+ // /// <summary>
+ // /// Initializes a new instance of the AudioResult class.
+ // /// </summary>
+ // public AudioResult()
+ // { }
+
+ // /// <summary>
+ // /// Initializes a new instance of the AudioResult class
+ // /// with the specified Microsoft.Phone.Tasks.TaskResult.
+ // /// </summary>
+ // /// <param name="taskResult">Associated Microsoft.Phone.Tasks.TaskResult</param>
+ // public AudioResult(TaskResult taskResult)
+ // : base(taskResult)
+ // { }
+
+ // /// <summary>
+ // /// Gets the file name of the recorded audio.
+ // /// </summary>
+ // public Stream AudioFile { get; internal set; }
+
+ // /// <summary>
+ // /// Gets the stream containing the data for the recorded audio.
+ // /// </summary>
+ // public string AudioFileName { get; internal set; }
+ //}
+
+ ///// <summary>
+ ///// Occurs when a audio recording task is completed.
+ ///// </summary>
+ //public event EventHandler<AudioResult> Completed;
+
+ /// <summary>
+ /// Shows Audio Recording application
+ /// </summary>
+ public void Show()
+ {
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ var root = Application.Current.RootVisual as PhoneApplicationFrame;
+
+ root.Navigated += new System.Windows.Navigation.NavigatedEventHandler(NavigationService_Navigated);
+
+ string baseUrl = WPCordovaClassLib.Cordova.Commands.BaseCommand.GetBaseURL();
+
+ // dummy parameter is used to always open a fresh version
+ root.Navigate(new System.Uri(baseUrl + "Cordova/UI/ImageCapture.xaml?dummy=" + Guid.NewGuid().ToString(), UriKind.Relative));
+ });
+ }
+
+ /// <summary>
+ /// Performs additional configuration of the recording application.
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="e"></param>
+ private void NavigationService_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
+ {
+ ImageCapture imageCapture = e.Content as ImageCapture;
+ if (imageCapture != null)
+ {
+ (Application.Current.RootVisual as PhoneApplicationFrame).Navigated -= NavigationService_Navigated;
+
+ //imageCapture.Completed += this.Completed;
+ //else if (this.Completed != null)
+ //{
+ // this.Completed(this, new AudioResult(TaskResult.Cancel));
+ //}
+ }
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/UI/NotificationBox.xaml
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/UI/NotificationBox.xaml b/lib/cordova-wp7/templates/standalone/Plugins/UI/NotificationBox.xaml
new file mode 100644
index 0000000..1ca5d5f
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/UI/NotificationBox.xaml
@@ -0,0 +1,62 @@
+<!--
+ 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.Cordova.UI.NotificationBox"
+ 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="800" d:DesignWidth="480" VerticalAlignment="Stretch">
+
+ <Grid x:Name="LayoutRoot"
+ Background="{StaticResource PhoneSemitransparentBrush}" VerticalAlignment="Stretch">
+
+ <Grid.RowDefinitions>
+ <RowDefinition Height="Auto"/>
+ <RowDefinition Height="*"/>
+ </Grid.RowDefinitions>
+
+
+ <!--TitlePanel contains the name of the application and page title-->
+ <StackPanel x:Name="TitlePanel"
+ Grid.Row="0"
+ Background="{StaticResource PhoneSemitransparentBrush}">
+ <TextBlock x:Name="PageTitle"
+ Text="Title"
+ Margin="10,10"
+ Style="{StaticResource PhoneTextTitle2Style}"/>
+
+ <TextBlock x:Name="SubTitle"
+ Text="Subtitle"
+ TextWrapping="Wrap"
+ Margin="10,10"
+ Style="{StaticResource PhoneTextTitle3Style}"/>
+
+ <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled">
+ <StackPanel x:Name="ButtonPanel"
+ Margin="10,10"
+ Orientation="Horizontal"/>
+ </ScrollViewer>
+
+ </StackPanel>
+ </Grid>
+</UserControl>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/UI/NotificationBox.xaml.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/UI/NotificationBox.xaml.cs b/lib/cordova-wp7/templates/standalone/Plugins/UI/NotificationBox.xaml.cs
new file mode 100644
index 0000000..50b2f2a
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/UI/NotificationBox.xaml.cs
@@ -0,0 +1,41 @@
+/*
+ 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.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;
+
+namespace WPCordovaClassLib.Cordova.UI
+{
+ public partial class NotificationBox : UserControl
+ {
+ public NotificationBox()
+ {
+ InitializeComponent();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/UI/VideoCaptureTask.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/UI/VideoCaptureTask.cs b/lib/cordova-wp7/templates/standalone/Plugins/UI/VideoCaptureTask.cs
new file mode 100644
index 0000000..def2a88
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/UI/VideoCaptureTask.cs
@@ -0,0 +1,105 @@
+/*
+ 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.IO;
+using System.Windows;
+using Microsoft.Phone.Controls;
+using Microsoft.Phone.Tasks;
+
+namespace WPCordovaClassLib.Cordova.UI
+{
+ /// <summary>
+ /// Allows an application to launch the Video Recording application.
+ /// Use this to allow users to record video from your application.
+ /// </summary>
+ public class VideoCaptureTask
+ {
+ /// <summary>
+ /// Represents recorded video returned from a call to the Show method of
+ /// a WPCordovaClassLib.Cordova.Controls.VideoCaptureTask object
+ /// </summary>
+ public class VideoResult : TaskEventArgs
+ {
+ /// <summary>
+ /// Initializes a new instance of the VideoResult class.
+ /// </summary>
+ public VideoResult()
+ { }
+
+ /// <summary>
+ /// Initializes a new instance of the VideoResult class
+ /// with the specified Microsoft.Phone.Tasks.TaskResult.
+ /// </summary>
+ /// <param name="taskResult">Associated Microsoft.Phone.Tasks.TaskResult</param>
+ public VideoResult(TaskResult taskResult)
+ : base(taskResult)
+ { }
+
+ /// <summary>
+ /// Gets the file name of the recorded Video.
+ /// </summary>
+ public Stream VideoFile { get; internal set; }
+
+ /// <summary>
+ /// Gets the stream containing the data for the recorded Video.
+ /// </summary>
+ public string VideoFileName { get; internal set; }
+ }
+
+ /// <summary>
+ /// Occurs when a Video recording task is completed.
+ /// </summary>
+ public event EventHandler<VideoResult> Completed;
+
+ /// <summary>
+ /// Shows Video Recording application
+ /// </summary>
+ public void Show()
+ {
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ var root = Application.Current.RootVisual as PhoneApplicationFrame;
+
+ root.Navigated += new System.Windows.Navigation.NavigatedEventHandler(NavigationService_Navigated);
+
+ string baseUrl = WPCordovaClassLib.Cordova.Commands.BaseCommand.GetBaseURL();
+ // dummy parameter is used to always open a fresh version
+ root.Navigate(new System.Uri(baseUrl + "CordovaLib/UI/VideoRecorder.xaml?dummy=" + Guid.NewGuid().ToString(), UriKind.Relative));
+ });
+ }
+
+ /// <summary>
+ /// Performs additional configuration of the recording application.
+ /// </summary>
+ private void NavigationService_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
+ {
+ if (!(e.Content is VideoRecorder)) return;
+
+ (Application.Current.RootVisual as PhoneApplicationFrame).Navigated -= NavigationService_Navigated;
+
+ VideoRecorder VideoRecorder = (VideoRecorder)e.Content;
+
+ if (VideoRecorder != null)
+ {
+ VideoRecorder.Completed += this.Completed;
+ }
+ else if (this.Completed != null)
+ {
+ this.Completed(this, new VideoResult(TaskResult.Cancel));
+ }
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/UI/VideoRecorder.xaml
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/UI/VideoRecorder.xaml b/lib/cordova-wp7/templates/standalone/Plugins/UI/VideoRecorder.xaml
new file mode 100644
index 0000000..c78fdb0
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/UI/VideoRecorder.xaml
@@ -0,0 +1,52 @@
+<!--
+ 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.
+-->
+<phone:PhoneApplicationPage
+ x:Class="WPCordovaClassLib.Cordova.UI.VideoRecorder"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
+ xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="480"
+ FontFamily="{StaticResource PhoneFontFamilyNormal}"
+ FontSize="{StaticResource PhoneFontSizeNormal}"
+ Foreground="{StaticResource PhoneForegroundBrush}"
+ SupportedOrientations="Landscape" Orientation="LandscapeLeft"
+ shell:SystemTray.IsVisible="False">
+
+ <Canvas x:Name="LayoutRoot" Background="Transparent" Grid.ColumnSpan="1" Grid.Column="0">
+
+ <Rectangle
+ x:Name="viewfinderRectangle"
+ Width="640"
+ Height="480"
+ HorizontalAlignment="Left"
+ Canvas.Left="80"/>
+
+ </Canvas>
+
+ <phone:PhoneApplicationPage.ApplicationBar>
+ <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True" x:Name="PhoneAppBar" Opacity="0.0">
+ <shell:ApplicationBarIconButton IconUri="/Images/appbar.feature.video.rest.png" Text="Record" x:Name="btnStartRecording" Click="StartRecording_Click" />
+ <shell:ApplicationBarIconButton IconUri="/Images/appbar.save.rest.png" Text="Take" x:Name="btnTakeVideo" Click="TakeVideo_Click"/>
+ </shell:ApplicationBar>
+ </phone:PhoneApplicationPage.ApplicationBar>
+
+</phone:PhoneApplicationPage>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/UI/VideoRecorder.xaml.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/UI/VideoRecorder.xaml.cs b/lib/cordova-wp7/templates/standalone/Plugins/UI/VideoRecorder.xaml.cs
new file mode 100644
index 0000000..6ab1cc3
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/UI/VideoRecorder.xaml.cs
@@ -0,0 +1,405 @@
+/*
+ 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.IO;
+using System.IO.IsolatedStorage;
+using System.Windows.Media;
+using System.Windows.Navigation;
+using Microsoft.Phone.Controls;
+using Microsoft.Phone.Shell;
+using Microsoft.Phone.Tasks;
+using VideoResult = WPCordovaClassLib.Cordova.UI.VideoCaptureTask.VideoResult;
+
+namespace WPCordovaClassLib.Cordova.UI
+{
+ public partial class VideoRecorder : PhoneApplicationPage
+ {
+
+ #region Constants
+
+ /// <summary>
+ /// Caption for record button in ready state
+ /// </summary>
+ private const string RecordingStartCaption = "Record";
+
+ /// <summary>
+ /// Caption for record button in recording state
+ /// </summary>
+ private const string RecordingStopCaption = "Stop";
+
+ /// <summary>
+ /// Start record icon URI
+ /// </summary>
+ private const string StartIconUri = "/Images/appbar.feature.video.rest.png";
+
+ /// <summary>
+ /// Stop record icon URI
+ /// </summary>
+ private const string StopIconUri = "/Images/appbar.stop.rest.png";
+
+ /// <summary>
+ /// Folder to save video clips
+ /// </summary>
+ private const string LocalFolderName = "VideoCache";
+
+ /// <summary>
+ /// File name format
+ /// </summary>
+ private const string FileNameFormat = "Video-{0}.mp4";
+
+ /// <summary>
+ /// Temporary file name
+ /// </summary>
+ private const string defaultFileName = "NewVideoFile.mp4";
+
+ #endregion
+
+ #region Callbacks
+ /// <summary>
+ /// Occurs when a video recording task is completed.
+ /// </summary>
+ public event EventHandler<VideoResult> Completed;
+
+ #endregion
+
+ #region Fields
+
+ /// <summary>
+ /// Viewfinder for capturing video
+ /// </summary>
+ private VideoBrush videoRecorderBrush;
+
+ /// <summary>
+ /// Path to save video clip
+ /// </summary>
+ private string filePath;
+
+ /// <summary>
+ /// Source for capturing video.
+ /// </summary>
+ private CaptureSource captureSource;
+
+ /// <summary>
+ /// Video device
+ /// </summary>
+ private VideoCaptureDevice videoCaptureDevice;
+
+ /// <summary>
+ /// File sink so save recording video in Isolated Storage
+ /// </summary>
+ private FileSink fileSink;
+
+ /// <summary>
+ /// For managing button and application state
+ /// </summary>
+ private enum VideoState { Initialized, Ready, Recording, CameraNotSupported };
+
+ /// <summary>
+ /// Current video state
+ /// </summary>
+ private VideoState currentVideoState;
+
+ /// <summary>
+ /// Stream to return result
+ /// </summary>
+ private MemoryStream memoryStream;
+
+ /// <summary>
+ /// Recording result, dispatched back when recording page is closed
+ /// </summary>
+ private VideoResult result = new VideoResult(TaskResult.Cancel);
+
+ #endregion
+
+ /// <summary>
+ /// Initializes components
+ /// </summary>
+ public VideoRecorder()
+ {
+ InitializeComponent();
+
+ PhoneAppBar = (ApplicationBar)ApplicationBar;
+ PhoneAppBar.IsVisible = true;
+ btnStartRecording = ((ApplicationBarIconButton)ApplicationBar.Buttons[0]);
+ btnTakeVideo = ((ApplicationBarIconButton)ApplicationBar.Buttons[1]);
+ }
+
+ /// <summary>
+ /// Initializes the video recorder then page is loading
+ /// </summary>
+ protected override void OnNavigatedTo(NavigationEventArgs e)
+ {
+ base.OnNavigatedTo(e);
+ this.InitializeVideoRecorder();
+ }
+
+ /// <summary>
+ /// Disposes camera and media objects then leave the page
+ /// </summary>
+ protected override void OnNavigatedFrom(NavigationEventArgs e)
+ {
+ this.DisposeVideoRecorder();
+
+ if (this.Completed != null)
+ {
+ this.Completed(this, result);
+ }
+ base.OnNavigatedFrom(e);
+ }
+
+ /// <summary>
+ /// Handles TakeVideo button click
+ /// </summary>
+ private void TakeVideo_Click(object sender, EventArgs e)
+ {
+ this.result = this.SaveVideoClip();
+ this.NavigateBack();
+ }
+
+ private void NavigateBack()
+ {
+ if (this.NavigationService.CanGoBack)
+ {
+ this.NavigationService.GoBack();
+ }
+ }
+
+ /// <summary>
+ /// Resaves video clip from temporary directory to persistent
+ /// </summary>
+ private VideoResult SaveVideoClip()
+ {
+ try
+ {
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ if (string.IsNullOrEmpty(filePath) || (!isoFile.FileExists(filePath)))
+ {
+ return new VideoResult(TaskResult.Cancel);
+ }
+
+ string fileName = String.Format(FileNameFormat, Guid.NewGuid().ToString());
+ string newPath = Path.Combine("/" + LocalFolderName + "/", fileName);
+ isoFile.CopyFile(filePath, newPath);
+ isoFile.DeleteFile(filePath);
+
+ memoryStream = new MemoryStream();
+ using (IsolatedStorageFileStream fileStream = new IsolatedStorageFileStream(newPath, FileMode.Open, isoFile))
+ {
+ fileStream.CopyTo(memoryStream);
+ }
+
+ VideoResult result = new VideoResult(TaskResult.OK);
+ result.VideoFileName = newPath;
+ result.VideoFile = this.memoryStream;
+ result.VideoFile.Seek(0, SeekOrigin.Begin);
+ return result;
+ }
+
+ }
+ catch (Exception)
+ {
+ return new VideoResult(TaskResult.None);
+ }
+ }
+
+ /// <summary>
+ /// Updates the buttons on the UI thread based on current state.
+ /// </summary>
+ /// <param name="currentState">current UI state</param>
+ private void UpdateUI(VideoState currentState)
+ {
+ Dispatcher.BeginInvoke(delegate
+ {
+ switch (currentState)
+ {
+ case VideoState.CameraNotSupported:
+ btnStartRecording.IsEnabled = false;
+ btnTakeVideo.IsEnabled = false;
+ break;
+
+ case VideoState.Initialized:
+ btnStartRecording.Text = RecordingStartCaption;
+ btnStartRecording.IconUri = new Uri(StartIconUri, UriKind.Relative);
+ btnTakeVideo.IsEnabled = false;
+ break;
+
+ case VideoState.Ready:
+ btnStartRecording.Text = RecordingStartCaption;
+ btnStartRecording.IconUri = new Uri(StartIconUri, UriKind.Relative);
+ btnTakeVideo.IsEnabled = true;
+ break;
+
+ case VideoState.Recording:
+ btnStartRecording.Text = RecordingStopCaption;
+ btnStartRecording.IconUri = new Uri(StopIconUri, UriKind.Relative);
+ btnTakeVideo.IsEnabled = false;
+ break;
+
+ default:
+ break;
+ }
+ currentVideoState = currentState;
+ });
+ }
+
+ /// <summary>
+ /// Initializes VideoRecorder
+ /// </summary>
+ public void InitializeVideoRecorder()
+ {
+ if (captureSource == null)
+ {
+ captureSource = new CaptureSource();
+ fileSink = new FileSink();
+ videoCaptureDevice = CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice();
+
+ if (videoCaptureDevice != null)
+ {
+ videoRecorderBrush = new VideoBrush();
+ videoRecorderBrush.SetSource(captureSource);
+ viewfinderRectangle.Fill = videoRecorderBrush;
+ captureSource.Start();
+ this.UpdateUI(VideoState.Initialized);
+ }
+ else
+ {
+ this.UpdateUI(VideoState.CameraNotSupported);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Sets recording state: start recording
+ /// </summary>
+ private void StartVideoRecording()
+ {
+ try
+ {
+ if ((captureSource.VideoCaptureDevice != null) && (captureSource.State == CaptureState.Started))
+ {
+ captureSource.Stop();
+ fileSink.CaptureSource = captureSource;
+ filePath = System.IO.Path.Combine("/" + LocalFolderName + "/", defaultFileName);
+
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ if (!isoFile.DirectoryExists(LocalFolderName))
+ {
+ isoFile.CreateDirectory(LocalFolderName);
+ }
+
+ if (isoFile.FileExists(filePath))
+ {
+ isoFile.DeleteFile(filePath);
+ }
+ }
+
+ fileSink.IsolatedStorageFileName = filePath;
+ }
+
+ if (captureSource.VideoCaptureDevice != null
+ && captureSource.State == CaptureState.Stopped)
+ {
+ captureSource.Start();
+ }
+ this.UpdateUI(VideoState.Recording);
+ }
+ catch (Exception)
+ {
+ this.result = new VideoResult(TaskResult.None);
+ this.NavigateBack();
+ }
+ }
+
+ /// <summary>
+ /// Sets the recording state: stop recording
+ /// </summary>
+ private void StopVideoRecording()
+ {
+ try
+ {
+ if ((captureSource.VideoCaptureDevice != null) && (captureSource.State == CaptureState.Started))
+ {
+ captureSource.Stop();
+ fileSink.CaptureSource = null;
+ fileSink.IsolatedStorageFileName = null;
+ this.StartVideoPreview();
+ }
+ }
+ catch (Exception)
+ {
+ this.result = new VideoResult(TaskResult.None);
+ this.NavigateBack();
+ }
+ }
+
+ /// <summary>
+ /// Sets the recording state: display the video on the viewfinder.
+ /// </summary>
+ private void StartVideoPreview()
+ {
+ try
+ {
+ if ((captureSource.VideoCaptureDevice != null) && (captureSource.State == CaptureState.Stopped))
+ {
+ videoRecorderBrush.SetSource(captureSource);
+ viewfinderRectangle.Fill = videoRecorderBrush;
+ captureSource.Start();
+ this.UpdateUI(VideoState.Ready);
+ }
+ }
+ catch (Exception)
+ {
+ this.result = new VideoResult(TaskResult.None);
+ this.NavigateBack();
+ }
+ }
+
+ /// <summary>
+ /// Starts video recording
+ /// </summary>
+ private void StartRecording_Click(object sender, EventArgs e)
+ {
+ if (currentVideoState == VideoState.Recording)
+ {
+ this.StopVideoRecording();
+ }
+ else
+ {
+ this.StartVideoRecording();
+ }
+ }
+
+ /// <summary>
+ /// Releases resources
+ /// </summary>
+ private void DisposeVideoRecorder()
+ {
+ if (captureSource != null)
+ {
+ if ((captureSource.VideoCaptureDevice != null) && (captureSource.State == CaptureState.Started))
+ {
+ captureSource.Stop();
+ }
+ captureSource = null;
+ videoCaptureDevice = null;
+ fileSink = null;
+ videoRecorderBrush = null;
+ }
+ }
+
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Properties/AppManifest.xml
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Properties/AppManifest.xml b/lib/cordova-wp7/templates/standalone/Properties/AppManifest.xml
new file mode 100644
index 0000000..877ea4b
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Properties/AppManifest.xml
@@ -0,0 +1,6 @@
+<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+>
+ <Deployment.Parts>
+ </Deployment.Parts>
+</Deployment>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Properties/AssemblyInfo.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Properties/AssemblyInfo.cs b/lib/cordova-wp7/templates/standalone/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..3f5dc5a
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Properties/AssemblyInfo.cs
@@ -0,0 +1,38 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Resources;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("CordovaAppProj")]
+[assembly: AssemblyDescription("2.0.0.0")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Cordova")]
+[assembly: AssemblyProduct("CordovaAppProj")]
+[assembly: AssemblyCopyright("Copyright © Apache Cordova 2013")]
+[assembly: AssemblyTrademark("Apache Cordova")]
+[assembly: AssemblyCulture("")]
+
+[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("9e27b972-0825-4386-ba17-63c695262c3d")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Properties/WMAppManifest.xml
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Properties/WMAppManifest.xml b/lib/cordova-wp7/templates/standalone/Properties/WMAppManifest.xml
new file mode 100644
index 0000000..96332e1
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Properties/WMAppManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Deployment xmlns="http://schemas.microsoft.com/windowsphone/2009/deployment" AppPlatformVersion="7.1">
+ <App xmlns="" ProductID="{$guid1$}" Title="$safeprojectname$"
+ RuntimeType="Silverlight" Version="1.0.0.0" Genre="apps.normal"
+ Author="$safeprojectname$ author"
+ BitsPerPixel="32"
+ Description="Apache Cordova for Windows Phone 7"
+ Publisher="$safeprojectname$">
+
+ <IconPath IsRelative="true" IsResource="false">ApplicationIcon.png</IconPath>
+ <Capabilities>
+ <Capability Name="ID_CAP_IDENTITY_DEVICE" />
+ <Capability Name="ID_CAP_IDENTITY_USER" />
+ <Capability Name="ID_CAP_LOCATION" />
+ <Capability Name="ID_CAP_NETWORKING" />
+ <Capability Name="ID_CAP_WEBBROWSERCOMPONENT" />
+ <Capability Name="ID_CAP_APPOINTMENTS"/>
+ <Capability Name="ID_CAP_CONTACTS"/>
+ <Capability Name="ID_CAP_ISV_CAMERA"/>
+ <Capability Name="ID_CAP_MEDIALIB"/>
+ <Capability Name="ID_CAP_MICROPHONE"/>
+ <Capability Name="ID_CAP_PHONEDIALER"/>
+ <Capability Name="ID_CAP_PUSH_NOTIFICATION"/>
+ <Capability Name="ID_CAP_SENSORS"/>
+ <Capability Name="ID_HW_FRONTCAMERA"/>
+ </Capabilities>
+
+ <Tasks>
+ <DefaultTask Name="_default" NavigationPage="MainPage.xaml" />
+ </Tasks>
+ <Tokens>
+ <PrimaryToken TokenID="$safeprojectname$Token" TaskName="_default">
+ <TemplateType5>
+ <BackgroundImageURI IsRelative="true" IsResource="false">Background.png</BackgroundImageURI>
+ <Count>0</Count>
+ <Title>$safeprojectname$</Title>
+ </TemplateType5>
+ </PrimaryToken>
+ </Tokens>
+ </App>
+</Deployment>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/README.md
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/README.md b/lib/cordova-wp7/templates/standalone/README.md
new file mode 100644
index 0000000..6374253
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/README.md
@@ -0,0 +1,13 @@
+Project Template
+===
+
+This project template needs to be built to be installed.
+
+
+This template includes the full source code for Windows Phone 7
+
+
+In order to build this template in Visual Studio Express for Windows Phone 7 :
+
+1. Open the solution file in Visual Studio
+2. Choose File->Export Template and follow the directions.
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/SplashScreenImage.jpg
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/SplashScreenImage.jpg b/lib/cordova-wp7/templates/standalone/SplashScreenImage.jpg
new file mode 100644
index 0000000..d35501d
Binary files /dev/null and b/lib/cordova-wp7/templates/standalone/SplashScreenImage.jpg differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/VERSION
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/VERSION b/lib/cordova-wp7/templates/standalone/VERSION
new file mode 100644
index 0000000..9aa3464
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/VERSION
@@ -0,0 +1 @@
+2.7.0
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/config.xml
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/config.xml b/lib/cordova-wp7/templates/standalone/config.xml
new file mode 100644
index 0000000..170f9fe
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/config.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+#
+# 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.
+#
+-->
+<widget>
+
+ <plugins>
+ <plugin name="Device"/>
+ <plugin name="Logger"/>
+ <plugin name="Compass"/>
+ <plugin name="Accelerometer"/>
+ <plugin name="Camera"/>
+ <plugin name="NetworkStatus"/>
+ <plugin name="Contacts"/>
+ <plugin name="DebugConsole" />
+ <plugin name="Echo"/>
+ <plugin name="File"/>
+ <plugin name="FileTransfer"/>
+ <plugin name="Geolocation"/>
+ <plugin name="Notification"/>
+ <plugin name="Media"/>
+ <plugin name="Capture"/>
+ <plugin name="SplashScreen"/>
+ <plugin name="Battery"/>
+ <plugin name="Globalization"/>
+ <plugin name="InAppBrowser"/>
+ </plugins>
+
+
+ <access origin="*"/>
+
+</widget>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/cordova/build.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordova/build.bat b/lib/cordova-wp7/templates/standalone/cordova/build.bat
new file mode 100644
index 0000000..b48598a
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/cordova/build.bat
@@ -0,0 +1,9 @@
+@ECHO OFF
+SET full_path=%~dp0
+IF EXIST %full_path%lib\build.js (
+ cscript "%full_path%lib\build.js" %* //nologo
+) ELSE (
+ ECHO.
+ ECHO ERROR: Could not find 'build.js' in cordova/lib, aborting...>&2
+ EXIT /B 1
+)
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/cordova/clean.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordova/clean.bat b/lib/cordova-wp7/templates/standalone/cordova/clean.bat
new file mode 100644
index 0000000..1bafe1b
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/cordova/clean.bat
@@ -0,0 +1,9 @@
+@ECHO OFF
+SET full_path=%~dp0
+IF EXIST %full_path%lib\clean.js (
+ cscript "%full_path%lib\clean.js" %* //nologo
+) ELSE (
+ ECHO.
+ ECHO ERROR: Could not find 'clean.js' in cordova/lib, aborting...>&2
+ EXIT /B 1
+)
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy.sln
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy.sln b/lib/cordova-wp7/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy.sln
new file mode 100644
index 0000000..3305276
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CordovaDeploy", "CordovaDeploy\CordovaDeploy.csproj", "{E752165B-AF59-4FF0-8601-A2A69FE09E0E}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x86 = Debug|x86
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {E752165B-AF59-4FF0-8601-A2A69FE09E0E}.Debug|x86.ActiveCfg = Debug|x86
+ {E752165B-AF59-4FF0-8601-A2A69FE09E0E}.Debug|x86.Build.0 = Debug|x86
+ {E752165B-AF59-4FF0-8601-A2A69FE09E0E}.Release|x86.ActiveCfg = Release|x86
+ {E752165B-AF59-4FF0-8601-A2A69FE09E0E}.Release|x86.Build.0 = Release|x86
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
[13/37] Add WP7 and WP8 platform files.
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/www/cordova-2.7.0.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/www/cordova-2.7.0.js b/lib/cordova-wp8/templates/standalone/www/cordova-2.7.0.js
new file mode 100644
index 0000000..199ba93
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/www/cordova-2.7.0.js
@@ -0,0 +1,6700 @@
+// Platform: windowsphone
+
+// commit cd29cf0f224ccf25e9d422a33fd02ef67d3a78f4
+
+// File generated at :: Fri Apr 26 2013 14:56:24 GMT-0700 (Pacific Daylight Time)
+
+/*
+ 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.
+*/
+
+;(function() {
+
+// file: lib\scripts\require.js
+
+var require,
+ define;
+
+(function () {
+ var modules = {};
+ // Stack of moduleIds currently being built.
+ var requireStack = [];
+ // Map of module ID -> index into requireStack of modules currently being built.
+ var inProgressModules = {};
+
+ function build(module) {
+ var factory = module.factory;
+ module.exports = {};
+ delete module.factory;
+ factory(require, module.exports, module);
+ return module.exports;
+ }
+
+ require = function (id) {
+ if (!modules[id]) {
+ throw "module " + id + " not found";
+ } else if (id in inProgressModules) {
+ var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id;
+ throw "Cycle in require graph: " + cycle;
+ }
+ if (modules[id].factory) {
+ try {
+ inProgressModules[id] = requireStack.length;
+ requireStack.push(id);
+ return build(modules[id]);
+ } finally {
+ delete inProgressModules[id];
+ requireStack.pop();
+ }
+ }
+ return modules[id].exports;
+ };
+
+ define = function (id, factory) {
+ if (modules[id]) {
+ throw "module " + id + " already defined";
+ }
+
+ modules[id] = {
+ id: id,
+ factory: factory
+ };
+ };
+
+ define.remove = function (id) {
+ delete modules[id];
+ };
+
+ define.moduleMap = modules;
+})();
+
+//Export for use in node
+if (typeof module === "object" && typeof require === "function") {
+ module.exports.require = require;
+ module.exports.define = define;
+}
+
+// file: lib/cordova.js
+define("cordova", function(require, exports, module) {
+
+
+var channel = require('cordova/channel');
+
+/**
+ * Listen for DOMContentLoaded and notify our channel subscribers.
+ */
+document.addEventListener('DOMContentLoaded', function() {
+ channel.onDOMContentLoaded.fire();
+}, false);
+if (document.readyState == 'complete' || document.readyState == 'interactive') {
+ channel.onDOMContentLoaded.fire();
+}
+
+/**
+ * Intercept calls to addEventListener + removeEventListener and handle deviceready,
+ * resume, and pause events.
+ */
+var m_document_addEventListener = document.addEventListener;
+var m_document_removeEventListener = document.removeEventListener;
+var m_window_addEventListener = window.addEventListener;
+var m_window_removeEventListener = window.removeEventListener;
+
+/**
+ * Houses custom event handlers to intercept on document + window event listeners.
+ */
+var documentEventHandlers = {},
+ windowEventHandlers = {};
+
+document.addEventListener = function(evt, handler, capture) {
+ var e = evt.toLowerCase();
+ if (typeof documentEventHandlers[e] != 'undefined') {
+ documentEventHandlers[e].subscribe(handler);
+ } else {
+ m_document_addEventListener.call(document, evt, handler, capture);
+ }
+};
+
+window.addEventListener = function(evt, handler, capture) {
+ var e = evt.toLowerCase();
+ if (typeof windowEventHandlers[e] != 'undefined') {
+ windowEventHandlers[e].subscribe(handler);
+ } else {
+ m_window_addEventListener.call(window, evt, handler, capture);
+ }
+};
+
+document.removeEventListener = function(evt, handler, capture) {
+ var e = evt.toLowerCase();
+ // If unsubscribing from an event that is handled by a plugin
+ if (typeof documentEventHandlers[e] != "undefined") {
+ documentEventHandlers[e].unsubscribe(handler);
+ } else {
+ m_document_removeEventListener.call(document, evt, handler, capture);
+ }
+};
+
+window.removeEventListener = function(evt, handler, capture) {
+ var e = evt.toLowerCase();
+ // If unsubscribing from an event that is handled by a plugin
+ if (typeof windowEventHandlers[e] != "undefined") {
+ windowEventHandlers[e].unsubscribe(handler);
+ } else {
+ m_window_removeEventListener.call(window, evt, handler, capture);
+ }
+};
+
+function createEvent(type, data) {
+ var event = document.createEvent('Events');
+ event.initEvent(type, false, false);
+ if (data) {
+ for (var i in data) {
+ if (data.hasOwnProperty(i)) {
+ event[i] = data[i];
+ }
+ }
+ }
+ return event;
+}
+
+if(typeof window.console === "undefined") {
+ window.console = {
+ log:function(){}
+ };
+}
+
+var cordova = {
+ define:define,
+ require:require,
+ /**
+ * Methods to add/remove your own addEventListener hijacking on document + window.
+ */
+ addWindowEventHandler:function(event) {
+ return (windowEventHandlers[event] = channel.create(event));
+ },
+ addStickyDocumentEventHandler:function(event) {
+ return (documentEventHandlers[event] = channel.createSticky(event));
+ },
+ addDocumentEventHandler:function(event) {
+ return (documentEventHandlers[event] = channel.create(event));
+ },
+ removeWindowEventHandler:function(event) {
+ delete windowEventHandlers[event];
+ },
+ removeDocumentEventHandler:function(event) {
+ delete documentEventHandlers[event];
+ },
+ /**
+ * Retrieve original event handlers that were replaced by Cordova
+ *
+ * @return object
+ */
+ getOriginalHandlers: function() {
+ return {'document': {'addEventListener': m_document_addEventListener, 'removeEventListener': m_document_removeEventListener},
+ 'window': {'addEventListener': m_window_addEventListener, 'removeEventListener': m_window_removeEventListener}};
+ },
+ /**
+ * Method to fire event from native code
+ * bNoDetach is required for events which cause an exception which needs to be caught in native code
+ */
+ fireDocumentEvent: function(type, data, bNoDetach) {
+ var evt = createEvent(type, data);
+ if (typeof documentEventHandlers[type] != 'undefined') {
+ if( bNoDetach ) {
+ documentEventHandlers[type].fire(evt);
+ }
+ else {
+ setTimeout(function() {
+ // Fire deviceready on listeners that were registered before cordova.js was loaded.
+ if (type == 'deviceready') {
+ document.dispatchEvent(evt);
+ }
+ documentEventHandlers[type].fire(evt);
+ }, 0);
+ }
+ } else {
+ document.dispatchEvent(evt);
+ }
+ },
+ fireWindowEvent: function(type, data) {
+ var evt = createEvent(type,data);
+ if (typeof windowEventHandlers[type] != 'undefined') {
+ setTimeout(function() {
+ windowEventHandlers[type].fire(evt);
+ }, 0);
+ } else {
+ window.dispatchEvent(evt);
+ }
+ },
+
+ /**
+ * Plugin callback mechanism.
+ */
+ // Randomize the starting callbackId to avoid collisions after refreshing or navigating.
+ // This way, it's very unlikely that any new callback would get the same callbackId as an old callback.
+ callbackId: Math.floor(Math.random() * 2000000000),
+ callbacks: {},
+ callbackStatus: {
+ NO_RESULT: 0,
+ OK: 1,
+ CLASS_NOT_FOUND_EXCEPTION: 2,
+ ILLEGAL_ACCESS_EXCEPTION: 3,
+ INSTANTIATION_EXCEPTION: 4,
+ MALFORMED_URL_EXCEPTION: 5,
+ IO_EXCEPTION: 6,
+ INVALID_ACTION: 7,
+ JSON_EXCEPTION: 8,
+ ERROR: 9
+ },
+
+ /**
+ * Called by native code when returning successful result from an action.
+ */
+ callbackSuccess: function(callbackId, args) {
+ try {
+ cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback);
+ } catch (e) {
+ console.log("Error in error callback: " + callbackId + " = "+e);
+ }
+ },
+
+ /**
+ * Called by native code when returning error result from an action.
+ */
+ callbackError: function(callbackId, args) {
+ // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative.
+ // Derive success from status.
+ try {
+ cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback);
+ } catch (e) {
+ console.log("Error in error callback: " + callbackId + " = "+e);
+ }
+ },
+
+ /**
+ * Called by native code when returning the result from an action.
+ */
+ callbackFromNative: function(callbackId, success, status, args, keepCallback) {
+ var callback = cordova.callbacks[callbackId];
+ if (callback) {
+ if (success && status == cordova.callbackStatus.OK) {
+ callback.success && callback.success.apply(null, args);
+ } else if (!success) {
+ callback.fail && callback.fail.apply(null, args);
+ }
+
+ // Clear callback if not expecting any more results
+ if (!keepCallback) {
+ delete cordova.callbacks[callbackId];
+ }
+ }
+ },
+ addConstructor: function(func) {
+ channel.onCordovaReady.subscribe(function() {
+ try {
+ func();
+ } catch(e) {
+ console.log("Failed to run constructor: " + e);
+ }
+ });
+ }
+};
+
+// Register pause, resume and deviceready channels as events on document.
+channel.onPause = cordova.addDocumentEventHandler('pause');
+channel.onResume = cordova.addDocumentEventHandler('resume');
+channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready');
+
+module.exports = cordova;
+
+});
+
+// file: lib\common\argscheck.js
+define("cordova/argscheck", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+var utils = require('cordova/utils');
+
+var moduleExports = module.exports;
+
+var typeMap = {
+ 'A': 'Array',
+ 'D': 'Date',
+ 'N': 'Number',
+ 'S': 'String',
+ 'F': 'Function',
+ 'O': 'Object'
+};
+
+function extractParamName(callee, argIndex) {
+ return (/.*?\((.*?)\)/).exec(callee)[1].split(', ')[argIndex];
+}
+
+function checkArgs(spec, functionName, args, opt_callee) {
+ if (!moduleExports.enableChecks) {
+ return;
+ }
+ var errMsg = null;
+ var typeName;
+ for (var i = 0; i < spec.length; ++i) {
+ var c = spec.charAt(i),
+ cUpper = c.toUpperCase(),
+ arg = args[i];
+ // Asterix means allow anything.
+ if (c == '*') {
+ continue;
+ }
+ typeName = utils.typeName(arg);
+ if ((arg === null || arg === undefined) && c == cUpper) {
+ continue;
+ }
+ if (typeName != typeMap[cUpper]) {
+ errMsg = 'Expected ' + typeMap[cUpper];
+ break;
+ }
+ }
+ if (errMsg) {
+ errMsg += ', but got ' + typeName + '.';
+ errMsg = 'Wrong type for parameter "' + extractParamName(opt_callee || args.callee, i) + '" of ' + functionName + ': ' + errMsg;
+ // Don't log when running jake test.
+ if (typeof jasmine == 'undefined') {
+ console.error(errMsg);
+ }
+ throw TypeError(errMsg);
+ }
+}
+
+function getValue(value, defaultValue) {
+ return value === undefined ? defaultValue : value;
+}
+
+moduleExports.checkArgs = checkArgs;
+moduleExports.getValue = getValue;
+moduleExports.enableChecks = true;
+
+
+});
+
+// file: lib\common\builder.js
+define("cordova/builder", function(require, exports, module) {
+
+var utils = require('cordova/utils');
+
+function each(objects, func, context) {
+ for (var prop in objects) {
+ if (objects.hasOwnProperty(prop)) {
+ func.apply(context, [objects[prop], prop]);
+ }
+ }
+}
+
+function clobber(obj, key, value) {
+ exports.replaceHookForTesting(obj, key);
+ obj[key] = value;
+ // Getters can only be overridden by getters.
+ if (obj[key] !== value) {
+ utils.defineGetter(obj, key, function() {
+ return value;
+ });
+ }
+}
+
+function assignOrWrapInDeprecateGetter(obj, key, value, message) {
+ if (message) {
+ utils.defineGetter(obj, key, function() {
+ console.log(message);
+ delete obj[key];
+ clobber(obj, key, value);
+ return value;
+ });
+ } else {
+ clobber(obj, key, value);
+ }
+}
+
+function include(parent, objects, clobber, merge) {
+ each(objects, function (obj, key) {
+ try {
+ var result = obj.path ? require(obj.path) : {};
+
+ if (clobber) {
+ // Clobber if it doesn't exist.
+ if (typeof parent[key] === 'undefined') {
+ assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+ } else if (typeof obj.path !== 'undefined') {
+ // If merging, merge properties onto parent, otherwise, clobber.
+ if (merge) {
+ recursiveMerge(parent[key], result);
+ } else {
+ assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+ }
+ }
+ result = parent[key];
+ } else {
+ // Overwrite if not currently defined.
+ if (typeof parent[key] == 'undefined') {
+ assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+ } else {
+ // Set result to what already exists, so we can build children into it if they exist.
+ result = parent[key];
+ }
+ }
+
+ if (obj.children) {
+ include(result, obj.children, clobber, merge);
+ }
+ } catch(e) {
+ utils.alert('Exception building cordova JS globals: ' + e + ' for key "' + key + '"');
+ }
+ });
+}
+
+/**
+ * Merge properties from one object onto another recursively. Properties from
+ * the src object will overwrite existing target property.
+ *
+ * @param target Object to merge properties into.
+ * @param src Object to merge properties from.
+ */
+function recursiveMerge(target, src) {
+ for (var prop in src) {
+ if (src.hasOwnProperty(prop)) {
+ if (target.prototype && target.prototype.constructor === target) {
+ // If the target object is a constructor override off prototype.
+ clobber(target.prototype, prop, src[prop]);
+ } else {
+ if (typeof src[prop] === 'object' && typeof target[prop] === 'object') {
+ recursiveMerge(target[prop], src[prop]);
+ } else {
+ clobber(target, prop, src[prop]);
+ }
+ }
+ }
+ }
+}
+
+exports.buildIntoButDoNotClobber = function(objects, target) {
+ include(target, objects, false, false);
+};
+exports.buildIntoAndClobber = function(objects, target) {
+ include(target, objects, true, false);
+};
+exports.buildIntoAndMerge = function(objects, target) {
+ include(target, objects, true, true);
+};
+exports.recursiveMerge = recursiveMerge;
+exports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter;
+exports.replaceHookForTesting = function() {};
+
+});
+
+// file: lib\common\channel.js
+define("cordova/channel", function(require, exports, module) {
+
+var utils = require('cordova/utils'),
+ nextGuid = 1;
+
+/**
+ * Custom pub-sub "channel" that can have functions subscribed to it
+ * This object is used to define and control firing of events for
+ * cordova initialization, as well as for custom events thereafter.
+ *
+ * The order of events during page load and Cordova startup is as follows:
+ *
+ * onDOMContentLoaded* Internal event that is received when the web page is loaded and parsed.
+ * onNativeReady* Internal event that indicates the Cordova native side is ready.
+ * onCordovaReady* Internal event fired when all Cordova JavaScript objects have been created.
+ * onCordovaInfoReady* Internal event fired when device properties are available.
+ * onCordovaConnectionReady* Internal event fired when the connection property has been set.
+ * onDeviceReady* User event fired to indicate that Cordova is ready
+ * onResume User event fired to indicate a start/resume lifecycle event
+ * onPause User event fired to indicate a pause lifecycle event
+ * onDestroy* Internal event fired when app is being destroyed (User should use window.onunload event, not this one).
+ *
+ * The events marked with an * are sticky. Once they have fired, they will stay in the fired state.
+ * All listeners that subscribe after the event is fired will be executed right away.
+ *
+ * The only Cordova events that user code should register for are:
+ * deviceready Cordova native code is initialized and Cordova APIs can be called from JavaScript
+ * pause App has moved to background
+ * resume App has returned to foreground
+ *
+ * Listeners can be registered as:
+ * document.addEventListener("deviceready", myDeviceReadyListener, false);
+ * document.addEventListener("resume", myResumeListener, false);
+ * document.addEventListener("pause", myPauseListener, false);
+ *
+ * The DOM lifecycle events should be used for saving and restoring state
+ * window.onload
+ * window.onunload
+ *
+ */
+
+/**
+ * Channel
+ * @constructor
+ * @param type String the channel name
+ */
+var Channel = function(type, sticky) {
+ this.type = type;
+ // Map of guid -> function.
+ this.handlers = {};
+ // 0 = Non-sticky, 1 = Sticky non-fired, 2 = Sticky fired.
+ this.state = sticky ? 1 : 0;
+ // Used in sticky mode to remember args passed to fire().
+ this.fireArgs = null;
+ // Used by onHasSubscribersChange to know if there are any listeners.
+ this.numHandlers = 0;
+ // Function that is called when the first listener is subscribed, or when
+ // the last listener is unsubscribed.
+ this.onHasSubscribersChange = null;
+},
+ channel = {
+ /**
+ * Calls the provided function only after all of the channels specified
+ * have been fired. All channels must be sticky channels.
+ */
+ join: function(h, c) {
+ var len = c.length,
+ i = len,
+ f = function() {
+ if (!(--i)) h();
+ };
+ for (var j=0; j<len; j++) {
+ if (c[j].state === 0) {
+ throw Error('Can only use join with sticky channels.');
+ }
+ c[j].subscribe(f);
+ }
+ if (!len) h();
+ },
+ create: function(type) {
+ return channel[type] = new Channel(type, false);
+ },
+ createSticky: function(type) {
+ return channel[type] = new Channel(type, true);
+ },
+
+ /**
+ * cordova Channels that must fire before "deviceready" is fired.
+ */
+ deviceReadyChannelsArray: [],
+ deviceReadyChannelsMap: {},
+
+ /**
+ * Indicate that a feature needs to be initialized before it is ready to be used.
+ * This holds up Cordova's "deviceready" event until the feature has been initialized
+ * and Cordova.initComplete(feature) is called.
+ *
+ * @param feature {String} The unique feature name
+ */
+ waitForInitialization: function(feature) {
+ if (feature) {
+ var c = channel[feature] || this.createSticky(feature);
+ this.deviceReadyChannelsMap[feature] = c;
+ this.deviceReadyChannelsArray.push(c);
+ }
+ },
+
+ /**
+ * Indicate that initialization code has completed and the feature is ready to be used.
+ *
+ * @param feature {String} The unique feature name
+ */
+ initializationComplete: function(feature) {
+ var c = this.deviceReadyChannelsMap[feature];
+ if (c) {
+ c.fire();
+ }
+ }
+ };
+
+function forceFunction(f) {
+ if (typeof f != 'function') throw "Function required as first argument!";
+}
+
+/**
+ * Subscribes the given function to the channel. Any time that
+ * Channel.fire is called so too will the function.
+ * Optionally specify an execution context for the function
+ * and a guid that can be used to stop subscribing to the channel.
+ * Returns the guid.
+ */
+Channel.prototype.subscribe = function(f, c) {
+ // need a function to call
+ forceFunction(f);
+ if (this.state == 2) {
+ f.apply(c || this, this.fireArgs);
+ return;
+ }
+
+ var func = f,
+ guid = f.observer_guid;
+ if (typeof c == "object") { func = utils.close(c, f); }
+
+ if (!guid) {
+ // first time any channel has seen this subscriber
+ guid = '' + nextGuid++;
+ }
+ func.observer_guid = guid;
+ f.observer_guid = guid;
+
+ // Don't add the same handler more than once.
+ if (!this.handlers[guid]) {
+ this.handlers[guid] = func;
+ this.numHandlers++;
+ if (this.numHandlers == 1) {
+ this.onHasSubscribersChange && this.onHasSubscribersChange();
+ }
+ }
+};
+
+/**
+ * Unsubscribes the function with the given guid from the channel.
+ */
+Channel.prototype.unsubscribe = function(f) {
+ // need a function to unsubscribe
+ forceFunction(f);
+
+ var guid = f.observer_guid,
+ handler = this.handlers[guid];
+ if (handler) {
+ delete this.handlers[guid];
+ this.numHandlers--;
+ if (this.numHandlers === 0) {
+ this.onHasSubscribersChange && this.onHasSubscribersChange();
+ }
+ }
+};
+
+/**
+ * Calls all functions subscribed to this channel.
+ */
+Channel.prototype.fire = function(e) {
+ var fail = false,
+ fireArgs = Array.prototype.slice.call(arguments);
+ // Apply stickiness.
+ if (this.state == 1) {
+ this.state = 2;
+ this.fireArgs = fireArgs;
+ }
+ if (this.numHandlers) {
+ // Copy the values first so that it is safe to modify it from within
+ // callbacks.
+ var toCall = [];
+ for (var item in this.handlers) {
+ toCall.push(this.handlers[item]);
+ }
+ for (var i = 0; i < toCall.length; ++i) {
+ toCall[i].apply(this, fireArgs);
+ }
+ if (this.state == 2 && this.numHandlers) {
+ this.numHandlers = 0;
+ this.handlers = {};
+ this.onHasSubscribersChange && this.onHasSubscribersChange();
+ }
+ }
+};
+
+
+// defining them here so they are ready super fast!
+// DOM event that is received when the web page is loaded and parsed.
+channel.createSticky('onDOMContentLoaded');
+
+// Event to indicate the Cordova native side is ready.
+channel.createSticky('onNativeReady');
+
+// Event to indicate that all Cordova JavaScript objects have been created
+// and it's time to run plugin constructors.
+channel.createSticky('onCordovaReady');
+
+// Event to indicate that device properties are available
+channel.createSticky('onCordovaInfoReady');
+
+// Event to indicate that the connection property has been set.
+channel.createSticky('onCordovaConnectionReady');
+
+// Event to indicate that all automatically loaded JS plugins are loaded and ready.
+channel.createSticky('onPluginsReady');
+
+// Event to indicate that Cordova is ready
+channel.createSticky('onDeviceReady');
+
+// Event to indicate a resume lifecycle event
+channel.create('onResume');
+
+// Event to indicate a pause lifecycle event
+channel.create('onPause');
+
+// Event to indicate a destroy lifecycle event
+channel.createSticky('onDestroy');
+
+// Channels that must fire before "deviceready" is fired.
+channel.waitForInitialization('onCordovaReady');
+channel.waitForInitialization('onCordovaConnectionReady');
+channel.waitForInitialization('onDOMContentLoaded');
+
+module.exports = channel;
+
+});
+
+// file: lib\common\commandProxy.js
+define("cordova/commandProxy", function(require, exports, module) {
+
+
+// internal map of proxy function
+var CommandProxyMap = {};
+
+module.exports = {
+
+ // example: cordova.commandProxy.add("Accelerometer",{getCurrentAcceleration: function(successCallback, errorCallback, options) {...},...);
+ add:function(id,proxyObj) {
+ console.log("adding proxy for " + id);
+ CommandProxyMap[id] = proxyObj;
+ return proxyObj;
+ },
+
+ // cordova.commandProxy.remove("Accelerometer");
+ remove:function(id) {
+ var proxy = CommandProxyMap[id];
+ delete CommandProxyMap[id];
+ CommandProxyMap[id] = null;
+ return proxy;
+ },
+
+ get:function(service,action) {
+ return ( CommandProxyMap[service] ? CommandProxyMap[service][action] : null );
+ }
+};
+});
+
+// file: lib\windowsphone\exec.js
+define("cordova/exec", function(require, exports, module) {
+
+var cordova = require('cordova');
+
+/**
+ * Execute a cordova command. It is up to the native side whether this action
+ * is synchronous or asynchronous. The native side can return:
+ * Synchronous: PluginResult object as a JSON string
+ * Asynchronous: Empty string ""
+ * If async, the native side will cordova.callbackSuccess or cordova.callbackError,
+ * depending upon the result of the action.
+ *
+ * @param {Function} success The success callback
+ * @param {Function} fail The fail callback
+ * @param {String} service The name of the service to use
+ * @param {String} action Action to be run in cordova
+ * @param {String[]} [args] Zero or more arguments to pass to the method
+
+ */
+
+module.exports = function(success, fail, service, action, args) {
+
+ var callbackId = service + cordova.callbackId++;
+ if (typeof success == "function" || typeof fail == "function") {
+ cordova.callbacks[callbackId] = {success:success, fail:fail};
+ }
+ // generate a new command string, ex. DebugConsole/log/DebugConsole23/["wtf dude?"]
+ for(var n = 0; n < args.length; n++)
+ {
+ if(typeof args[n] !== "string")
+ {
+ args[n] = JSON.stringify(args[n]);
+ }
+ }
+ var command = service + "/" + action + "/" + callbackId + "/" + JSON.stringify(args);
+ // pass it on to Notify
+ try {
+ if(window.external) {
+ window.external.Notify(command);
+ }
+ else {
+ console.log("window.external not available :: command=" + command);
+ }
+ }
+ catch(e) {
+ console.log("Exception calling native with command :: " + command + " :: exception=" + e);
+ }
+};
+
+
+});
+
+// file: lib\common\modulemapper.js
+define("cordova/modulemapper", function(require, exports, module) {
+
+var builder = require('cordova/builder'),
+ moduleMap = define.moduleMap,
+ symbolList,
+ deprecationMap;
+
+exports.reset = function() {
+ symbolList = [];
+ deprecationMap = {};
+};
+
+function addEntry(strategy, moduleName, symbolPath, opt_deprecationMessage) {
+ if (!(moduleName in moduleMap)) {
+ throw new Error('Module ' + moduleName + ' does not exist.');
+ }
+ symbolList.push(strategy, moduleName, symbolPath);
+ if (opt_deprecationMessage) {
+ deprecationMap[symbolPath] = opt_deprecationMessage;
+ }
+}
+
+// Note: Android 2.3 does have Function.bind().
+exports.clobbers = function(moduleName, symbolPath, opt_deprecationMessage) {
+ addEntry('c', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+exports.merges = function(moduleName, symbolPath, opt_deprecationMessage) {
+ addEntry('m', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+exports.defaults = function(moduleName, symbolPath, opt_deprecationMessage) {
+ addEntry('d', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+function prepareNamespace(symbolPath, context) {
+ if (!symbolPath) {
+ return context;
+ }
+ var parts = symbolPath.split('.');
+ var cur = context;
+ for (var i = 0, part; part = parts[i]; ++i) {
+ cur = cur[part] = cur[part] || {};
+ }
+ return cur;
+}
+
+exports.mapModules = function(context) {
+ var origSymbols = {};
+ context.CDV_origSymbols = origSymbols;
+ for (var i = 0, len = symbolList.length; i < len; i += 3) {
+ var strategy = symbolList[i];
+ var moduleName = symbolList[i + 1];
+ var symbolPath = symbolList[i + 2];
+ var lastDot = symbolPath.lastIndexOf('.');
+ var namespace = symbolPath.substr(0, lastDot);
+ var lastName = symbolPath.substr(lastDot + 1);
+
+ var module = require(moduleName);
+ var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null;
+ var parentObj = prepareNamespace(namespace, context);
+ var target = parentObj[lastName];
+
+ if (strategy == 'm' && target) {
+ builder.recursiveMerge(target, module);
+ } else if ((strategy == 'd' && !target) || (strategy != 'd')) {
+ if (!(symbolPath in origSymbols)) {
+ origSymbols[symbolPath] = target;
+ }
+ builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg);
+ }
+ }
+};
+
+exports.getOriginalSymbol = function(context, symbolPath) {
+ var origSymbols = context.CDV_origSymbols;
+ if (origSymbols && (symbolPath in origSymbols)) {
+ return origSymbols[symbolPath];
+ }
+ var parts = symbolPath.split('.');
+ var obj = context;
+ for (var i = 0; i < parts.length; ++i) {
+ obj = obj && obj[parts[i]];
+ }
+ return obj;
+};
+
+exports.loadMatchingModules = function(matchingRegExp) {
+ for (var k in moduleMap) {
+ if (matchingRegExp.exec(k)) {
+ require(k);
+ }
+ }
+};
+
+exports.reset();
+
+
+});
+
+// file: lib\windowsphone\platform.js
+define("cordova/platform", function(require, exports, module) {
+
+var cordova = require('cordova'),
+ exec = require('cordova/exec');
+
+module.exports = {
+ id: "windowsphone",
+ initialize:function() {
+ var modulemapper = require('cordova/modulemapper');
+
+ modulemapper.loadMatchingModules(/cordova.*\/plugininit$/);
+
+ modulemapper.loadMatchingModules(/cordova.*\/symbols$/);
+
+ modulemapper.mapModules(window);
+
+ // Inject a listener for the backbutton, and tell native to override the flag (true/false) when we have 1 or more, or 0, listeners
+ var backButtonChannel = cordova.addDocumentEventHandler('backbutton');
+ backButtonChannel.onHasSubscribersChange = function() {
+ exec(null, null, "CoreEvents", "overridebackbutton", [this.numHandlers == 1]);
+ };
+ }
+};
+
+});
+
+// file: lib\common\plugin\Acceleration.js
+define("cordova/plugin/Acceleration", function(require, exports, module) {
+
+var Acceleration = function(x, y, z, timestamp) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.timestamp = timestamp || (new Date()).getTime();
+};
+
+module.exports = Acceleration;
+
+});
+
+// file: lib\common\plugin\Camera.js
+define("cordova/plugin/Camera", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ exec = require('cordova/exec'),
+ Camera = require('cordova/plugin/CameraConstants'),
+ CameraPopoverHandle = require('cordova/plugin/CameraPopoverHandle');
+
+var cameraExport = {};
+
+// Tack on the Camera Constants to the base camera plugin.
+for (var key in Camera) {
+ cameraExport[key] = Camera[key];
+}
+
+/**
+ * Gets a picture from source defined by "options.sourceType", and returns the
+ * image as defined by the "options.destinationType" option.
+
+ * The defaults are sourceType=CAMERA and destinationType=FILE_URI.
+ *
+ * @param {Function} successCallback
+ * @param {Function} errorCallback
+ * @param {Object} options
+ */
+cameraExport.getPicture = function(successCallback, errorCallback, options) {
+ argscheck.checkArgs('fFO', 'Camera.getPicture', arguments);
+ options = options || {};
+ var getValue = argscheck.getValue;
+
+ var quality = getValue(options.quality, 50);
+ var destinationType = getValue(options.destinationType, Camera.DestinationType.FILE_URI);
+ var sourceType = getValue(options.sourceType, Camera.PictureSourceType.CAMERA);
+ var targetWidth = getValue(options.targetWidth, -1);
+ var targetHeight = getValue(options.targetHeight, -1);
+ var encodingType = getValue(options.encodingType, Camera.EncodingType.JPEG);
+ var mediaType = getValue(options.mediaType, Camera.MediaType.PICTURE);
+ var allowEdit = !!options.allowEdit;
+ var correctOrientation = !!options.correctOrientation;
+ var saveToPhotoAlbum = !!options.saveToPhotoAlbum;
+ var popoverOptions = getValue(options.popoverOptions, null);
+ var cameraDirection = getValue(options.cameraDirection, Camera.Direction.BACK);
+
+ var args = [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType,
+ mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions, cameraDirection];
+
+ exec(successCallback, errorCallback, "Camera", "takePicture", args);
+ return new CameraPopoverHandle();
+};
+
+cameraExport.cleanup = function(successCallback, errorCallback) {
+ exec(successCallback, errorCallback, "Camera", "cleanup", []);
+};
+
+module.exports = cameraExport;
+
+});
+
+// file: lib\common\plugin\CameraConstants.js
+define("cordova/plugin/CameraConstants", function(require, exports, module) {
+
+module.exports = {
+ DestinationType:{
+ DATA_URL: 0, // Return base64 encoded string
+ FILE_URI: 1, // Return file uri (content://media/external/images/media/2 for Android)
+ NATIVE_URI: 2 // Return native uri (eg. asset-library://... for iOS)
+ },
+ EncodingType:{
+ JPEG: 0, // Return JPEG encoded image
+ PNG: 1 // Return PNG encoded image
+ },
+ MediaType:{
+ PICTURE: 0, // allow selection of still pictures only. DEFAULT. Will return format specified via DestinationType
+ VIDEO: 1, // allow selection of video only, ONLY RETURNS URL
+ ALLMEDIA : 2 // allow selection from all media types
+ },
+ PictureSourceType:{
+ PHOTOLIBRARY : 0, // Choose image from picture library (same as SAVEDPHOTOALBUM for Android)
+ CAMERA : 1, // Take picture from camera
+ SAVEDPHOTOALBUM : 2 // Choose image from picture library (same as PHOTOLIBRARY for Android)
+ },
+ PopoverArrowDirection:{
+ ARROW_UP : 1, // matches iOS UIPopoverArrowDirection constants to specify arrow location on popover
+ ARROW_DOWN : 2,
+ ARROW_LEFT : 4,
+ ARROW_RIGHT : 8,
+ ARROW_ANY : 15
+ },
+ Direction:{
+ BACK: 0,
+ FRONT: 1
+ }
+};
+
+});
+
+// file: lib\common\plugin\CameraPopoverHandle.js
+define("cordova/plugin/CameraPopoverHandle", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+
+/**
+ * A handle to an image picker popover.
+ */
+var CameraPopoverHandle = function() {
+ this.setPosition = function(popoverOptions) {
+ console.log('CameraPopoverHandle.setPosition is only supported on iOS.');
+ };
+};
+
+module.exports = CameraPopoverHandle;
+
+});
+
+// file: lib\common\plugin\CameraPopoverOptions.js
+define("cordova/plugin/CameraPopoverOptions", function(require, exports, module) {
+
+var Camera = require('cordova/plugin/CameraConstants');
+
+/**
+ * Encapsulates options for iOS Popover image picker
+ */
+var CameraPopoverOptions = function(x,y,width,height,arrowDir){
+ // information of rectangle that popover should be anchored to
+ this.x = x || 0;
+ this.y = y || 32;
+ this.width = width || 320;
+ this.height = height || 480;
+ // The direction of the popover arrow
+ this.arrowDir = arrowDir || Camera.PopoverArrowDirection.ARROW_ANY;
+};
+
+module.exports = CameraPopoverOptions;
+
+});
+
+// file: lib\common\plugin\CaptureAudioOptions.js
+define("cordova/plugin/CaptureAudioOptions", function(require, exports, module) {
+
+/**
+ * Encapsulates all audio capture operation configuration options.
+ */
+var CaptureAudioOptions = function(){
+ // Upper limit of sound clips user can record. Value must be equal or greater than 1.
+ this.limit = 1;
+ // Maximum duration of a single sound clip in seconds.
+ this.duration = 0;
+ // The selected audio mode. Must match with one of the elements in supportedAudioModes array.
+ this.mode = null;
+};
+
+module.exports = CaptureAudioOptions;
+
+});
+
+// file: lib\common\plugin\CaptureError.js
+define("cordova/plugin/CaptureError", function(require, exports, module) {
+
+/**
+ * The CaptureError interface encapsulates all errors in the Capture API.
+ */
+var CaptureError = function(c) {
+ this.code = c || null;
+};
+
+// Camera or microphone failed to capture image or sound.
+CaptureError.CAPTURE_INTERNAL_ERR = 0;
+// Camera application or audio capture application is currently serving other capture request.
+CaptureError.CAPTURE_APPLICATION_BUSY = 1;
+// Invalid use of the API (e.g. limit parameter has value less than one).
+CaptureError.CAPTURE_INVALID_ARGUMENT = 2;
+// User exited camera application or audio capture application before capturing anything.
+CaptureError.CAPTURE_NO_MEDIA_FILES = 3;
+// The requested capture operation is not supported.
+CaptureError.CAPTURE_NOT_SUPPORTED = 20;
+
+module.exports = CaptureError;
+
+});
+
+// file: lib\common\plugin\CaptureImageOptions.js
+define("cordova/plugin/CaptureImageOptions", function(require, exports, module) {
+
+/**
+ * Encapsulates all image capture operation configuration options.
+ */
+var CaptureImageOptions = function(){
+ // Upper limit of images user can take. Value must be equal or greater than 1.
+ this.limit = 1;
+ // The selected image mode. Must match with one of the elements in supportedImageModes array.
+ this.mode = null;
+};
+
+module.exports = CaptureImageOptions;
+
+});
+
+// file: lib\common\plugin\CaptureVideoOptions.js
+define("cordova/plugin/CaptureVideoOptions", function(require, exports, module) {
+
+/**
+ * Encapsulates all video capture operation configuration options.
+ */
+var CaptureVideoOptions = function(){
+ // Upper limit of videos user can record. Value must be equal or greater than 1.
+ this.limit = 1;
+ // Maximum duration of a single video clip in seconds.
+ this.duration = 0;
+ // The selected video mode. Must match with one of the elements in supportedVideoModes array.
+ this.mode = null;
+};
+
+module.exports = CaptureVideoOptions;
+
+});
+
+// file: lib\common\plugin\CompassError.js
+define("cordova/plugin/CompassError", function(require, exports, module) {
+
+/**
+ * CompassError.
+ * An error code assigned by an implementation when an error has occurred
+ * @constructor
+ */
+var CompassError = function(err) {
+ this.code = (err !== undefined ? err : null);
+};
+
+CompassError.COMPASS_INTERNAL_ERR = 0;
+CompassError.COMPASS_NOT_SUPPORTED = 20;
+
+module.exports = CompassError;
+
+});
+
+// file: lib\common\plugin\CompassHeading.js
+define("cordova/plugin/CompassHeading", function(require, exports, module) {
+
+var CompassHeading = function(magneticHeading, trueHeading, headingAccuracy, timestamp) {
+ this.magneticHeading = magneticHeading;
+ this.trueHeading = trueHeading;
+ this.headingAccuracy = headingAccuracy;
+ this.timestamp = timestamp || new Date().getTime();
+};
+
+module.exports = CompassHeading;
+
+});
+
+// file: lib\common\plugin\ConfigurationData.js
+define("cordova/plugin/ConfigurationData", function(require, exports, module) {
+
+/**
+ * Encapsulates a set of parameters that the capture device supports.
+ */
+function ConfigurationData() {
+ // The ASCII-encoded string in lower case representing the media type.
+ this.type = null;
+ // The height attribute represents height of the image or video in pixels.
+ // In the case of a sound clip this attribute has value 0.
+ this.height = 0;
+ // The width attribute represents width of the image or video in pixels.
+ // In the case of a sound clip this attribute has value 0
+ this.width = 0;
+}
+
+module.exports = ConfigurationData;
+
+});
+
+// file: lib\common\plugin\Connection.js
+define("cordova/plugin/Connection", function(require, exports, module) {
+
+/**
+ * Network status
+ */
+module.exports = {
+ UNKNOWN: "unknown",
+ ETHERNET: "ethernet",
+ WIFI: "wifi",
+ CELL_2G: "2g",
+ CELL_3G: "3g",
+ CELL_4G: "4g",
+ CELL:"cellular",
+ NONE: "none"
+};
+
+});
+
+// file: lib\common\plugin\Contact.js
+define("cordova/plugin/Contact", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ exec = require('cordova/exec'),
+ ContactError = require('cordova/plugin/ContactError'),
+ utils = require('cordova/utils');
+
+/**
+* Converts primitives into Complex Object
+* Currently only used for Date fields
+*/
+function convertIn(contact) {
+ var value = contact.birthday;
+ try {
+ contact.birthday = new Date(parseFloat(value));
+ } catch (exception){
+ console.log("Cordova Contact convertIn error: exception creating date.");
+ }
+ return contact;
+}
+
+/**
+* Converts Complex objects into primitives
+* Only conversion at present is for Dates.
+**/
+
+function convertOut(contact) {
+ var value = contact.birthday;
+ if (value !== null) {
+ // try to make it a Date object if it is not already
+ if (!utils.isDate(value)){
+ try {
+ value = new Date(value);
+ } catch(exception){
+ value = null;
+ }
+ }
+ if (utils.isDate(value)){
+ value = value.valueOf(); // convert to milliseconds
+ }
+ contact.birthday = value;
+ }
+ return contact;
+}
+
+/**
+* Contains information about a single contact.
+* @constructor
+* @param {DOMString} id unique identifier
+* @param {DOMString} displayName
+* @param {ContactName} name
+* @param {DOMString} nickname
+* @param {Array.<ContactField>} phoneNumbers array of phone numbers
+* @param {Array.<ContactField>} emails array of email addresses
+* @param {Array.<ContactAddress>} addresses array of addresses
+* @param {Array.<ContactField>} ims instant messaging user ids
+* @param {Array.<ContactOrganization>} organizations
+* @param {DOMString} birthday contact's birthday
+* @param {DOMString} note user notes about contact
+* @param {Array.<ContactField>} photos
+* @param {Array.<ContactField>} categories
+* @param {Array.<ContactField>} urls contact's web sites
+*/
+var Contact = function (id, displayName, name, nickname, phoneNumbers, emails, addresses,
+ ims, organizations, birthday, note, photos, categories, urls) {
+ this.id = id || null;
+ this.rawId = null;
+ this.displayName = displayName || null;
+ this.name = name || null; // ContactName
+ this.nickname = nickname || null;
+ this.phoneNumbers = phoneNumbers || null; // ContactField[]
+ this.emails = emails || null; // ContactField[]
+ this.addresses = addresses || null; // ContactAddress[]
+ this.ims = ims || null; // ContactField[]
+ this.organizations = organizations || null; // ContactOrganization[]
+ this.birthday = birthday || null;
+ this.note = note || null;
+ this.photos = photos || null; // ContactField[]
+ this.categories = categories || null; // ContactField[]
+ this.urls = urls || null; // ContactField[]
+};
+
+/**
+* Removes contact from device storage.
+* @param successCB success callback
+* @param errorCB error callback
+*/
+Contact.prototype.remove = function(successCB, errorCB) {
+ argscheck.checkArgs('FF', 'Contact.remove', arguments);
+ var fail = errorCB && function(code) {
+ errorCB(new ContactError(code));
+ };
+ if (this.id === null) {
+ fail(ContactError.UNKNOWN_ERROR);
+ }
+ else {
+ exec(successCB, fail, "Contacts", "remove", [this.id]);
+ }
+};
+
+/**
+* Creates a deep copy of this Contact.
+* With the contact ID set to null.
+* @return copy of this Contact
+*/
+Contact.prototype.clone = function() {
+ var clonedContact = utils.clone(this);
+ clonedContact.id = null;
+ clonedContact.rawId = null;
+
+ function nullIds(arr) {
+ if (arr) {
+ for (var i = 0; i < arr.length; ++i) {
+ arr[i].id = null;
+ }
+ }
+ }
+
+ // Loop through and clear out any id's in phones, emails, etc.
+ nullIds(clonedContact.phoneNumbers);
+ nullIds(clonedContact.emails);
+ nullIds(clonedContact.addresses);
+ nullIds(clonedContact.ims);
+ nullIds(clonedContact.organizations);
+ nullIds(clonedContact.categories);
+ nullIds(clonedContact.photos);
+ nullIds(clonedContact.urls);
+ return clonedContact;
+};
+
+/**
+* Persists contact to device storage.
+* @param successCB success callback
+* @param errorCB error callback
+*/
+Contact.prototype.save = function(successCB, errorCB) {
+ argscheck.checkArgs('FFO', 'Contact.save', arguments);
+ var fail = errorCB && function(code) {
+ errorCB(new ContactError(code));
+ };
+ var success = function(result) {
+ if (result) {
+ if (successCB) {
+ var fullContact = require('cordova/plugin/contacts').create(result);
+ successCB(convertIn(fullContact));
+ }
+ }
+ else {
+ // no Entry object returned
+ fail(ContactError.UNKNOWN_ERROR);
+ }
+ };
+ var dupContact = convertOut(utils.clone(this));
+ exec(success, fail, "Contacts", "save", [dupContact]);
+};
+
+
+module.exports = Contact;
+
+});
+
+// file: lib\common\plugin\ContactAddress.js
+define("cordova/plugin/ContactAddress", function(require, exports, module) {
+
+/**
+* Contact address.
+* @constructor
+* @param {DOMString} id unique identifier, should only be set by native code
+* @param formatted // NOTE: not a W3C standard
+* @param streetAddress
+* @param locality
+* @param region
+* @param postalCode
+* @param country
+*/
+
+var ContactAddress = function(pref, type, formatted, streetAddress, locality, region, postalCode, country) {
+ this.id = null;
+ this.pref = (typeof pref != 'undefined' ? pref : false);
+ this.type = type || null;
+ this.formatted = formatted || null;
+ this.streetAddress = streetAddress || null;
+ this.locality = locality || null;
+ this.region = region || null;
+ this.postalCode = postalCode || null;
+ this.country = country || null;
+};
+
+module.exports = ContactAddress;
+
+});
+
+// file: lib\common\plugin\ContactError.js
+define("cordova/plugin/ContactError", function(require, exports, module) {
+
+/**
+ * ContactError.
+ * An error code assigned by an implementation when an error has occurred
+ * @constructor
+ */
+var ContactError = function(err) {
+ this.code = (typeof err != 'undefined' ? err : null);
+};
+
+/**
+ * Error codes
+ */
+ContactError.UNKNOWN_ERROR = 0;
+ContactError.INVALID_ARGUMENT_ERROR = 1;
+ContactError.TIMEOUT_ERROR = 2;
+ContactError.PENDING_OPERATION_ERROR = 3;
+ContactError.IO_ERROR = 4;
+ContactError.NOT_SUPPORTED_ERROR = 5;
+ContactError.PERMISSION_DENIED_ERROR = 20;
+
+module.exports = ContactError;
+
+});
+
+// file: lib\common\plugin\ContactField.js
+define("cordova/plugin/ContactField", function(require, exports, module) {
+
+/**
+* Generic contact field.
+* @constructor
+* @param {DOMString} id unique identifier, should only be set by native code // NOTE: not a W3C standard
+* @param type
+* @param value
+* @param pref
+*/
+var ContactField = function(type, value, pref) {
+ this.id = null;
+ this.type = (type && type.toString()) || null;
+ this.value = (value && value.toString()) || null;
+ this.pref = (typeof pref != 'undefined' ? pref : false);
+};
+
+module.exports = ContactField;
+
+});
+
+// file: lib\common\plugin\ContactFindOptions.js
+define("cordova/plugin/ContactFindOptions", function(require, exports, module) {
+
+/**
+ * ContactFindOptions.
+ * @constructor
+ * @param filter used to match contacts against
+ * @param multiple boolean used to determine if more than one contact should be returned
+ */
+
+var ContactFindOptions = function(filter, multiple) {
+ this.filter = filter || '';
+ this.multiple = (typeof multiple != 'undefined' ? multiple : false);
+};
+
+module.exports = ContactFindOptions;
+
+});
+
+// file: lib\common\plugin\ContactName.js
+define("cordova/plugin/ContactName", function(require, exports, module) {
+
+/**
+* Contact name.
+* @constructor
+* @param formatted // NOTE: not part of W3C standard
+* @param familyName
+* @param givenName
+* @param middle
+* @param prefix
+* @param suffix
+*/
+var ContactName = function(formatted, familyName, givenName, middle, prefix, suffix) {
+ this.formatted = formatted || null;
+ this.familyName = familyName || null;
+ this.givenName = givenName || null;
+ this.middleName = middle || null;
+ this.honorificPrefix = prefix || null;
+ this.honorificSuffix = suffix || null;
+};
+
+module.exports = ContactName;
+
+});
+
+// file: lib\common\plugin\ContactOrganization.js
+define("cordova/plugin/ContactOrganization", function(require, exports, module) {
+
+/**
+* Contact organization.
+* @constructor
+* @param {DOMString} id unique identifier, should only be set by native code // NOTE: not a W3C standard
+* @param name
+* @param dept
+* @param title
+* @param startDate
+* @param endDate
+* @param location
+* @param desc
+*/
+
+var ContactOrganization = function(pref, type, name, dept, title) {
+ this.id = null;
+ this.pref = (typeof pref != 'undefined' ? pref : false);
+ this.type = type || null;
+ this.name = name || null;
+ this.department = dept || null;
+ this.title = title || null;
+};
+
+module.exports = ContactOrganization;
+
+});
+
+// file: lib\common\plugin\Coordinates.js
+define("cordova/plugin/Coordinates", function(require, exports, module) {
+
+/**
+ * This class contains position information.
+ * @param {Object} lat
+ * @param {Object} lng
+ * @param {Object} alt
+ * @param {Object} acc
+ * @param {Object} head
+ * @param {Object} vel
+ * @param {Object} altacc
+ * @constructor
+ */
+var Coordinates = function(lat, lng, alt, acc, head, vel, altacc) {
+ /**
+ * The latitude of the position.
+ */
+ this.latitude = lat;
+ /**
+ * The longitude of the position,
+ */
+ this.longitude = lng;
+ /**
+ * The accuracy of the position.
+ */
+ this.accuracy = acc;
+ /**
+ * The altitude of the position.
+ */
+ this.altitude = (alt !== undefined ? alt : null);
+ /**
+ * The direction the device is moving at the position.
+ */
+ this.heading = (head !== undefined ? head : null);
+ /**
+ * The velocity with which the device is moving at the position.
+ */
+ this.speed = (vel !== undefined ? vel : null);
+
+ if (this.speed === 0 || this.speed === null) {
+ this.heading = NaN;
+ }
+
+ /**
+ * The altitude accuracy of the position.
+ */
+ this.altitudeAccuracy = (altacc !== undefined) ? altacc : null;
+};
+
+module.exports = Coordinates;
+
+});
+
+// file: lib\common\plugin\DirectoryEntry.js
+define("cordova/plugin/DirectoryEntry", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ utils = require('cordova/utils'),
+ exec = require('cordova/exec'),
+ Entry = require('cordova/plugin/Entry'),
+ FileError = require('cordova/plugin/FileError'),
+ DirectoryReader = require('cordova/plugin/DirectoryReader');
+
+/**
+ * An interface representing a directory on the file system.
+ *
+ * {boolean} isFile always false (readonly)
+ * {boolean} isDirectory always true (readonly)
+ * {DOMString} name of the directory, excluding the path leading to it (readonly)
+ * {DOMString} fullPath the absolute full path to the directory (readonly)
+ * TODO: implement this!!! {FileSystem} filesystem on which the directory resides (readonly)
+ */
+var DirectoryEntry = function(name, fullPath) {
+ DirectoryEntry.__super__.constructor.call(this, false, true, name, fullPath);
+};
+
+utils.extend(DirectoryEntry, Entry);
+
+/**
+ * Creates a new DirectoryReader to read entries from this directory
+ */
+DirectoryEntry.prototype.createReader = function() {
+ return new DirectoryReader(this.fullPath);
+};
+
+/**
+ * Creates or looks up a directory
+ *
+ * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a directory
+ * @param {Flags} options to create or exclusively create the directory
+ * @param {Function} successCallback is called with the new entry
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryEntry.prototype.getDirectory = function(path, options, successCallback, errorCallback) {
+ argscheck.checkArgs('sOFF', 'DirectoryEntry.getDirectory', arguments);
+ var win = successCallback && function(result) {
+ var entry = new DirectoryEntry(result.name, result.fullPath);
+ successCallback(entry);
+ };
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(win, fail, "File", "getDirectory", [this.fullPath, path, options]);
+};
+
+/**
+ * Deletes a directory and all of it's contents
+ *
+ * @param {Function} successCallback is called with no parameters
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryEntry.prototype.removeRecursively = function(successCallback, errorCallback) {
+ argscheck.checkArgs('FF', 'DirectoryEntry.removeRecursively', arguments);
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(successCallback, fail, "File", "removeRecursively", [this.fullPath]);
+};
+
+/**
+ * Creates or looks up a file
+ *
+ * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a file
+ * @param {Flags} options to create or exclusively create the file
+ * @param {Function} successCallback is called with the new entry
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryEntry.prototype.getFile = function(path, options, successCallback, errorCallback) {
+ argscheck.checkArgs('sOFF', 'DirectoryEntry.getFile', arguments);
+ var win = successCallback && function(result) {
+ var FileEntry = require('cordova/plugin/FileEntry');
+ var entry = new FileEntry(result.name, result.fullPath);
+ successCallback(entry);
+ };
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(win, fail, "File", "getFile", [this.fullPath, path, options]);
+};
+
+module.exports = DirectoryEntry;
+
+});
+
+// file: lib\common\plugin\DirectoryReader.js
+define("cordova/plugin/DirectoryReader", function(require, exports, module) {
+
+var exec = require('cordova/exec'),
+ FileError = require('cordova/plugin/FileError') ;
+
+/**
+ * An interface that lists the files and directories in a directory.
+ */
+function DirectoryReader(path) {
+ this.path = path || null;
+}
+
+/**
+ * Returns a list of entries from a directory.
+ *
+ * @param {Function} successCallback is called with a list of entries
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryReader.prototype.readEntries = function(successCallback, errorCallback) {
+ var win = typeof successCallback !== 'function' ? null : function(result) {
+ var retVal = [];
+ for (var i=0; i<result.length; i++) {
+ var entry = null;
+ if (result[i].isDirectory) {
+ entry = new (require('cordova/plugin/DirectoryEntry'))();
+ }
+ else if (result[i].isFile) {
+ entry = new (require('cordova/plugin/FileEntry'))();
+ }
+ entry.isDirectory = result[i].isDirectory;
+ entry.isFile = result[i].isFile;
+ entry.name = result[i].name;
+ entry.fullPath = result[i].fullPath;
+ retVal.push(entry);
+ }
+ successCallback(retVal);
+ };
+ var fail = typeof errorCallback !== 'function' ? null : function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(win, fail, "File", "readEntries", [this.path]);
+};
+
+module.exports = DirectoryReader;
+
+});
+
+// file: lib\common\plugin\Entry.js
+define("cordova/plugin/Entry", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ exec = require('cordova/exec'),
+ FileError = require('cordova/plugin/FileError'),
+ Metadata = require('cordova/plugin/Metadata');
+
+/**
+ * Represents a file or directory on the local file system.
+ *
+ * @param isFile
+ * {boolean} true if Entry is a file (readonly)
+ * @param isDirectory
+ * {boolean} true if Entry is a directory (readonly)
+ * @param name
+ * {DOMString} name of the file or directory, excluding the path
+ * leading to it (readonly)
+ * @param fullPath
+ * {DOMString} the absolute full path to the file or directory
+ * (readonly)
+ */
+function Entry(isFile, isDirectory, name, fullPath, fileSystem) {
+ this.isFile = !!isFile;
+ this.isDirectory = !!isDirectory;
+ this.name = name || '';
+ this.fullPath = fullPath || '';
+ this.filesystem = fileSystem || null;
+}
+
+/**
+ * Look up the metadata of the entry.
+ *
+ * @param successCallback
+ * {Function} is called with a Metadata object
+ * @param errorCallback
+ * {Function} is called with a FileError
+ */
+Entry.prototype.getMetadata = function(successCallback, errorCallback) {
+ argscheck.checkArgs('FF', 'Entry.getMetadata', arguments);
+ var success = successCallback && function(lastModified) {
+ var metadata = new Metadata(lastModified);
+ successCallback(metadata);
+ };
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+
+ exec(success, fail, "File", "getMetadata", [this.fullPath]);
+};
+
+/**
+ * Set the metadata of the entry.
+ *
+ * @param successCallback
+ * {Function} is called with a Metadata object
+ * @param errorCallback
+ * {Function} is called with a FileError
+ * @param metadataObject
+ * {Object} keys and values to set
+ */
+Entry.prototype.setMetadata = function(successCallback, errorCallback, metadataObject) {
+ argscheck.checkArgs('FFO', 'Entry.setMetadata', arguments);
+ exec(successCallback, errorCallback, "File", "setMetadata", [this.fullPath, metadataObject]);
+};
+
+/**
+ * Move a file or directory to a new location.
+ *
+ * @param parent
+ * {DirectoryEntry} the directory to which to move this entry
+ * @param newName
+ * {DOMString} new name of the entry, defaults to the current name
+ * @param successCallback
+ * {Function} called with the new DirectoryEntry object
+ * @param errorCallback
+ * {Function} called with a FileError
+ */
+Entry.prototype.moveTo = function(parent, newName, successCallback, errorCallback) {
+ argscheck.checkArgs('oSFF', 'Entry.moveTo', arguments);
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ // source path
+ var srcPath = this.fullPath,
+ // entry name
+ name = newName || this.name,
+ success = function(entry) {
+ if (entry) {
+ if (successCallback) {
+ // create appropriate Entry object
+ var result = (entry.isDirectory) ? new (require('cordova/plugin/DirectoryEntry'))(entry.name, entry.fullPath) : new (require('cordova/plugin/FileEntry'))(entry.name, entry.fullPath);
+ successCallback(result);
+ }
+ }
+ else {
+ // no Entry object returned
+ fail && fail(FileError.NOT_FOUND_ERR);
+ }
+ };
+
+ // copy
+ exec(success, fail, "File", "moveTo", [srcPath, parent.fullPath, name]);
+};
+
+/**
+ * Copy a directory to a different location.
+ *
+ * @param parent
+ * {DirectoryEntry} the directory to which to copy the entry
+ * @param newName
+ * {DOMString} new name of the entry, defaults to the current name
+ * @param successCallback
+ * {Function} called with the new Entry object
+ * @param errorCallback
+ * {Function} called with a FileError
+ */
+Entry.prototype.copyTo = function(parent, newName, successCallback, errorCallback) {
+ argscheck.checkArgs('oSFF', 'Entry.copyTo', arguments);
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+
+ // source path
+ var srcPath = this.fullPath,
+ // entry name
+ name = newName || this.name,
+ // success callback
+ success = function(entry) {
+ if (entry) {
+ if (successCallback) {
+ // create appropriate Entry object
+ var result = (entry.isDirectory) ? new (require('cordova/plugin/DirectoryEntry'))(entry.name, entry.fullPath) : new (require('cordova/plugin/FileEntry'))(entry.name, entry.fullPath);
+ successCallback(result);
+ }
+ }
+ else {
+ // no Entry object returned
+ fail && fail(FileError.NOT_FOUND_ERR);
+ }
+ };
+
+ // copy
+ exec(success, fail, "File", "copyTo", [srcPath, parent.fullPath, name]);
+};
+
+/**
+ * Return a URL that can be used to identify this entry.
+ */
+Entry.prototype.toURL = function() {
+ // fullPath attribute contains the full URL
+ return this.fullPath;
+};
+
+/**
+ * Returns a URI that can be used to identify this entry.
+ *
+ * @param {DOMString} mimeType for a FileEntry, the mime type to be used to interpret the file, when loaded through this URI.
+ * @return uri
+ */
+Entry.prototype.toURI = function(mimeType) {
+ console.log("DEPRECATED: Update your code to use 'toURL'");
+ // fullPath attribute contains the full URI
+ return this.toURL();
+};
+
+/**
+ * Remove a file or directory. It is an error to attempt to delete a
+ * directory that is not empty. It is an error to attempt to delete a
+ * root directory of a file system.
+ *
+ * @param successCallback {Function} called with no parameters
+ * @param errorCallback {Function} called with a FileError
+ */
+Entry.prototype.remove = function(successCallback, errorCallback) {
+ argscheck.checkArgs('FF', 'Entry.remove', arguments);
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(successCallback, fail, "File", "remove", [this.fullPath]);
+};
+
+/**
+ * Look up the parent DirectoryEntry of this entry.
+ *
+ * @param successCallback {Function} called with the parent DirectoryEntry object
+ * @param errorCallback {Function} called with a FileError
+ */
+Entry.prototype.getParent = function(successCallback, errorCallback) {
+ argscheck.checkArgs('FF', 'Entry.getParent', arguments);
+ var win = successCallback && function(result) {
+ var DirectoryEntry = require('cordova/plugin/DirectoryEntry');
+ var entry = new DirectoryEntry(result.name, result.fullPath);
+ successCallback(entry);
+ };
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(win, fail, "File", "getParent", [this.fullPath]);
+};
+
+module.exports = Entry;
+
+});
+
+// file: lib\common\plugin\File.js
+define("cordova/plugin/File", function(require, exports, module) {
+
+/**
+ * Constructor.
+ * name {DOMString} name of the file, without path information
+ * fullPath {DOMString} the full path of the file, including the name
+ * type {DOMString} mime type
+ * lastModifiedDate {Date} last modified date
+ * size {Number} size of the file in bytes
+ */
+
+var File = function(name, fullPath, type, lastModifiedDate, size){
+ this.name = name || '';
+ this.fullPath = fullPath || null;
+ this.type = type || null;
+ this.lastModifiedDate = lastModifiedDate || null;
+ this.size = size || 0;
+
+ // These store the absolute start and end for slicing the file.
+ this.start = 0;
+ this.end = this.size;
+};
+
+/**
+ * Returns a "slice" of the file. Since Cordova Files don't contain the actual
+ * content, this really returns a File with adjusted start and end.
+ * Slices of slices are supported.
+ * start {Number} The index at which to start the slice (inclusive).
+ * end {Number} The index at which to end the slice (exclusive).
+ */
+File.prototype.slice = function(start, end) {
+ var size = this.end - this.start;
+ var newStart = 0;
+ var newEnd = size;
+ if (arguments.length) {
+ if (start < 0) {
+ newStart = Math.max(size + start, 0);
+ } else {
+ newStart = Math.min(size, start);
+ }
+ }
+
+ if (arguments.length >= 2) {
+ if (end < 0) {
+ newEnd = Math.max(size + end, 0);
+ } else {
+ newEnd = Math.min(end, size);
+ }
+ }
+
+ var newFile = new File(this.name, this.fullPath, this.type, this.lastModifiedData, this.size);
+ newFile.start = this.start + newStart;
+ newFile.end = this.start + newEnd;
+ return newFile;
+};
+
+
+module.exports = File;
+
+});
+
+// file: lib\common\plugin\FileEntry.js
+define("cordova/plugin/FileEntry", function(require, exports, module) {
+
+var utils = require('cordova/utils'),
+ exec = require('cordova/exec'),
+ Entry = require('cordova/plugin/Entry'),
+ FileWriter = require('cordova/plugin/FileWriter'),
+ File = require('cordova/plugin/File'),
+ FileError = require('cordova/plugin/FileError');
+
+/**
+ * An interface representing a file on the file system.
+ *
+ * {boolean} isFile always true (readonly)
+ * {boolean} isDirectory always false (readonly)
+ * {DOMString} name of the file, excluding the path leading to it (readonly)
+ * {DOMString} fullPath the absolute full path to the file (readonly)
+ * {FileSystem} filesystem on which the file resides (readonly)
+ */
+var FileEntry = function(name, fullPath) {
+ FileEntry.__super__.constructor.apply(this, [true, false, name, fullPath]);
+};
+
+utils.extend(FileEntry, Entry);
+
+/**
+ * Creates a new FileWriter associated with the file that this FileEntry represents.
+ *
+ * @param {Function} successCallback is called with the new FileWriter
+ * @param {Function} errorCallback is called with a FileError
+ */
+FileEntry.prototype.createWriter = function(successCallback, errorCallback) {
+ this.file(function(filePointer) {
+ var writer = new FileWriter(filePointer);
+
+ if (writer.fileName === null || writer.fileName === "") {
+ errorCallback && errorCallback(new FileError(FileError.INVALID_STATE_ERR));
+ } else {
+ successCallback && successCallback(writer);
+ }
+ }, errorCallback);
+};
+
+/**
+ * Returns a File that represents the current state of the file that this FileEntry represents.
+ *
+ * @param {Function} successCallback is called with the new File object
+ * @param {Function} errorCallback is called with a FileError
+ */
+FileEntry.prototype.file = function(successCallback, errorCallback) {
+ var win = successCallback && function(f) {
+ var file = new File(f.name, f.fullPath, f.type, f.lastModifiedDate, f.size);
+ successCallback(file);
+ };
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(win, fail, "File", "getFileMetadata", [this.fullPath]);
+};
+
+
+module.exports = FileEntry;
+
+});
+
+// file: lib\common\plugin\FileError.js
+define("cordova/plugin/FileError", function(require, exports, module) {
+
+/**
+ * FileError
+ */
+function FileError(error) {
+ this.code = error || null;
+}
+
+// File error codes
+// Found in DOMException
+FileError.NOT_FOUND_ERR = 1;
+FileError.SECURITY_ERR = 2;
+FileError.ABORT_ERR = 3;
+
+// Added by File API specification
+FileError.NOT_READABLE_ERR = 4;
+FileError.ENCODING_ERR = 5;
+FileError.NO_MODIFICATION_ALLOWED_ERR = 6;
+FileError.INVALID_STATE_ERR = 7;
+FileError.SYNTAX_ERR = 8;
+FileError.INVALID_MODIFICATION_ERR = 9;
+FileError.QUOTA_EXCEEDED_ERR = 10;
+FileError.TYPE_MISMATCH_ERR = 11;
+FileError.PATH_EXISTS_ERR = 12;
+
+module.exports = FileError;
+
+});
+
+// file: lib\common\plugin\FileReader.js
+define("cordova/plugin/FileReader", function(require, exports, module) {
+
+var exec = require('cordova/exec'),
+ modulemapper = require('cordova/modulemapper'),
+ utils = require('cordova/utils'),
+ File = require('cordova/plugin/File'),
+ FileError = require('cordova/plugin/FileError'),
+ ProgressEvent = require('cordova/plugin/ProgressEvent'),
+ origFileReader = modulemapper.getOriginalSymbol(this, 'FileReader');
+
+/**
+ * This class reads the mobile device file system.
+ *
+ * For Android:
+ * The root directory is the root of the file system.
+ * To read from the SD card, the file name is "sdcard/my_file.txt"
+ * @constructor
+ */
+var FileReader = function() {
+ this._readyState = 0;
+ this._error = null;
+ this._result = null;
+ this._fileName = '';
+ this._realReader = origFileReader ? new origFileReader() : {};
+};
+
+// States
+FileReader.EMPTY = 0;
+FileReader.LOADING = 1;
+FileReader.DONE = 2;
+
+utils.defineGetter(FileReader.prototype, 'readyState', function() {
+ return this._fileName ? this._readyState : this._realReader.readyState;
+});
+
+utils.defineGetter(FileReader.prototype, 'error', function() {
+ return this._fileName ? this._error: this._realReader.error;
+});
+
+utils.defineGetter(FileReader.prototype, 'result', function() {
+ return this._fileName ? this._result: this._realReader.result;
+});
+
+function defineEvent(eventName) {
+ utils.defineGetterSetter(FileReader.prototype, eventName, function() {
+ return this._realReader[eventName] || null;
+ }, function(value) {
+ this._realReader[eventName] = value;
+ });
+}
+defineEvent('onloadstart'); // When the read starts.
+defineEvent('onprogress'); // While reading (and decoding) file or fileBlob data, and reporting partial file data (progress.loaded/progress.total)
+defineEvent('onload'); // When the read has successfully completed.
+defineEvent('onerror'); // When the read has failed (see errors).
+defineEvent('onloadend'); // When the request has completed (either in success or failure).
+defineEvent('onabort'); // When the read has been aborted. For instance, by invoking the abort() method.
+
+function initRead(reader, file) {
+ // Already loading something
+ if (reader.readyState == FileReader.LOADING) {
+ throw new FileError(FileError.INVALID_STATE_ERR);
+ }
+
+ reader._result = null;
+ reader._error = null;
+ reader._readyState = FileReader.LOADING;
+
+ if (typeof file == 'string') {
+ // Deprecated in Cordova 2.4.
+ console.warn('Using a string argument with FileReader.readAs functions is deprecated.');
+ reader._fileName = file;
+ } else if (typeof file.fullPath == 'string') {
+ reader._fileName = file.fullPath;
+ } else {
+ reader._fileName = '';
+ return true;
+ }
+
+ reader.onloadstart && reader.onloadstart(new ProgressEvent("loadstart", {target:reader}));
+}
+
+/**
+ * Abort reading file.
+ */
+FileReader.prototype.abort = function() {
+ if (origFileReader && !this._fileName) {
+ return this._realReader.abort();
+ }
+ this._result = null;
+
+ if (this._readyState == FileReader.DONE || this._readyState == FileReader.EMPTY) {
+ return;
+ }
+
+ this._readyState = FileReader.DONE;
+
+ // If abort callback
+ if (typeof this.onabort === 'function') {
+ this.onabort(new ProgressEvent('abort', {target:this}));
+ }
+ // If load end callback
+ if (typeof this.onloadend === 'function') {
+ this.onloadend(new ProgressEvent('loadend', {target:this}));
+ }
+};
+
+/**
+ * Read text file.
+ *
+ * @param file {File} File object containing file properties
+ * @param encoding [Optional] (see http://www.iana.org/assignments/character-sets)
+ */
+FileReader.prototype.readAsText = function(file, encoding) {
+ if (initRead(this, file)) {
+ return this._realReader.readAsText(file, encoding);
+ }
+
+ // Default encoding is UTF-8
+ var enc = encoding ? encoding : "UTF-8";
+ var me = this;
+ var execArgs = [this._fileName, enc, file.start, file.end];
+
+ // Read file
+ exec(
+ // Success callback
+ function(r) {
+ // If DONE (cancelled), then don't do anything
+ if (me._readyState === FileReader.DONE) {
+ return;
+ }
+
+ // Save result
+ me._result = r;
+
+ // If onload callback
+ if (typeof me.onload === "function") {
+ me.onload(new ProgressEvent("load", {target:me}));
+ }
+
+ // DONE state
+ me._readyState = FileReader.DONE;
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ me.onloadend(new ProgressEvent("loadend", {target:me}));
+ }
+ },
+ // Error callback
+ function(e) {
+ // If DONE (cancelled), then don't do anything
+ if (me._readyState === FileReader.DONE) {
+ return;
+ }
+
+ // DONE state
+ me._readyState = FileReader.DONE;
+
+ // null result
+ me._result = null;
+
+ // Save error
+ me._error = new FileError(e);
+
+ // If onerror callback
+ if (typeof me.onerror === "function") {
+ me.onerror(new ProgressEvent("error", {target:me}));
+ }
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ me.onloadend(new ProgressEvent("loadend", {target:me}));
+ }
+ }, "File", "readAsText", execArgs);
+};
+
+
+/**
+ * Read file and return data as a base64 encoded data url.
+ * A data url is of the form:
+ * data:[<mediatype>][;base64],<data>
+ *
+ * @param file {File} File object containing file properties
+ */
+FileReader.prototype.readAsDataURL = function(file) {
+ if (initRead(this, file)) {
+ return this._realReader.readAsDataURL(file);
+ }
+
+ var me = this;
+ var execArgs = [this._fileName, file.start, file.end];
+
+ // Read file
+ exec(
+ // Success callback
+ function(r) {
+ // If DONE (cancelled), then don't do anything
+ if (me._readyState === FileReader.DONE) {
+ return;
+ }
+
+ // DONE state
+ me._readyState = FileReader.DONE;
+
+ // Save result
+ me._result = r;
+
+ // If onload callback
+ if (typeof me.onload === "function") {
+ me.onload(new ProgressEvent("load", {target:me}));
+ }
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ me.onloadend(new ProgressEvent("loadend", {target:me}));
+ }
+ },
+ // Error callback
+ function(e) {
+ // If DONE (cancelled), then don't do anything
+ if (me._readyState === FileReader.DONE) {
+ return;
+ }
+
+ // DONE state
+ me._readyState = FileReader.DONE;
+
+ me._result = null;
+
+ // Save error
+ me._error = new FileError(e);
+
+ // If onerror callback
+ if (typeof me.onerror === "function") {
+ me.onerror(new ProgressEvent("error", {target:me}));
+ }
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ me.onloadend(new ProgressEvent("loadend", {target:me}));
+ }
+ }, "File", "readAsDataURL", execArgs);
+};
+
+/**
+ * Read file and return data as a binary data.
+ *
+ * @param file {File} File object containing file properties
+ */
+FileReader.prototype.readAsBinaryString = function(file) {
+ if (initRead(this, file)) {
+ return this._realReader.readAsBinaryString(file);
+ }
+
+ var me = this;
+ var execArgs = [this._fileName, file.start, file.end];
+
+ // Read file
+ exec(
+ // Success callback
+ function(r) {
+ // If DONE (cancelled), then don't do anything
+ if (me._readyState === FileReader.DONE) {
+ return;
+ }
+
+ // DONE state
+ me._readyState = FileReader.DONE;
+
+ me._result = r;
+
+ // If onload callback
+ if (typeof me.onload === "function") {
+ me.onload(new ProgressEvent("load", {target:me}));
+ }
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ me.onloadend(new ProgressEvent("loadend", {target:me}));
+ }
+ },
+ // Error callback
+ function(e) {
+ // If DONE (cancelled), then don't do anything
+ if (me._readyState === FileReader.DONE) {
+ return;
+ }
+
+ // DONE state
+ me._readyState = FileReader.DONE;
+
+ me._result = null;
+
+ // Save error
+ me._error = new FileError(e);
+
+ // If onerror callback
+ if (typeof me.onerror === "function") {
+ me.onerror(new ProgressEvent("error", {target:me}));
+ }
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ me.onloadend(new ProgressEvent("loadend", {target:me}));
+ }
+ }, "File", "readAsBinaryString", execArgs);
+};
+
+/**
+ * Read file and return data as a binary data.
+ *
+ * @param file {File} File object containing file properties
+ */
+FileReader.prototype.readAsArrayBuffer = function(file) {
+ if (initRead(this, file)) {
+ return this._realReader.readAsArrayBuffer(file);
+ }
+
+ var me = this;
+ var execArgs = [this._fileName, file.start, file.end];
+
+ // Read file
+ exec(
+ // Success callback
+ function(r) {
+ // If DONE (cancelled), then don't do anything
+ if (me._readyState === FileReader.DONE) {
+ return;
+ }
+
+ // DONE state
+ me._readyState = FileReader.DONE;
+
+ me._result = r;
+
+ // If onload callback
+ if (typeof me.onload === "function") {
+ me.onload(new ProgressEvent("load", {target:me}));
+ }
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ me.onloadend(new ProgressEvent("loadend", {target:me}));
+ }
+ },
+ // Error callback
+ function(e) {
+ // If DONE (cancelled), then don't do anything
+ if (me._readyState === FileReader.DONE) {
+ return;
+ }
+
+ // DONE state
+ me._readyState = FileReader.DONE;
+
+ me._result = null;
+
+ // Save error
+ me._error = new FileError(e);
+
+ // If onerror callback
+ if (typeof me.onerror === "function") {
+ me.onerror(new ProgressEvent("error", {target:me}));
+ }
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ me.onloadend(new ProgressEvent("loadend", {target:me}));
+ }
+ }, "File", "readAsArrayBuffer", execArgs);
+};
+
+module.exports = FileReader;
+
+});
+
+// file: lib\common\plugin\FileSystem.js
+define("cordova/plugin/FileSystem", function(require, exports, module) {
+
+var DirectoryEntry = require('cordova/plugin/DirectoryEntry');
+
+/**
+ * An interface representing a file system
+ *
+ * @constructor
+ * {DOMString} name the unique name of the file system (readonly)
+ * {DirectoryEntry} root directory of the file system (readonly)
+ */
+var FileSystem = function(name, root) {
+ this.name = name || null;
+ if (root) {
+ this.root = new DirectoryEntry(root.name, root.fullPath);
+ }
+};
+
+module.exports = FileSystem;
+
+});
+
+// file: lib\common\plugin\FileTransfer.js
+define("cordova/plugin/FileTransfer", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ exec = require('cordova/exec'),
+ FileTransferError = require('cordova/plugin/FileTransferError'),
+ ProgressEvent = require('cordova/plugin/ProgressEvent');
+
+function newProgressEvent(result) {
+ var pe = new ProgressEvent();
+ pe.lengthComputable = result.lengthComputable;
+ pe.loaded = result.loaded;
+ pe.total = result.total;
+ return pe;
+}
+
+function getBasicAuthHeader(urlString) {
+ var header = null;
+
+ if (window.btoa) {
+ // parse the url using the Location object
+ var url = document.createElement('a');
+ url.href = urlString;
+
+ var credentials = null;
+ var protocol = url.protocol + "//";
+ var origin = protocol + url.host;
+
+ // check whether there are the username:password credentials in the url
+ if (url.href.indexOf(origin) !== 0) { // credentials found
+ var atIndex = url.href.indexOf("@");
+ credentials = url.href.substring(protocol.length, atIndex);
+ }
+
+ if (credentials) {
+ var authHeader = "Authorization";
+ var authHeaderValue = "Basic " + window.btoa(credentials);
+
+ header = {
+ name : authHeader,
+ value : authHeaderValue
+ };
+ }
+ }
+
+ return header;
+}
+
+var idCounter = 0;
+
+/**
+ * FileTransfer uploads a file to a remote server.
+ * @constructor
+ */
+var FileTransfer = function() {
+ this._id = ++idCounter;
+ this.onprogress = null; // optional callback
+};
+
+/**
+* Given an absolute file path, uploads a file on the device to a remote server
+* using a multipart HTTP request.
+* @param filePath {String} Full path of the file on the device
+* @param server {String} URL of the server to receive the file
+* @param successCallback (Function} Callback to be invoked when upload has completed
+* @param errorCallback {Function} Callback to be invoked upon error
+* @param options {FileUploadOptions} Optional parameters such as file name and mimetype
+* @param trustAllHosts {Boolean} Optional trust all hosts (e.g. for self-signed certs), defaults to false
+*/
+FileTransfer.prototype.upload = function(filePath, server, successCallback, errorCallback, options, trustAllHosts) {
+ argscheck.checkArgs('ssFFO*', 'FileTransfer.upload', arguments);
+ // check for options
+ var fileKey = null;
+ var fileName = null;
+ var mimeType = null;
+ var params = null;
+ var chunkedMode = true;
+ var headers = null;
+ var httpMethod = null;
+ var basicAuthHeader = getBasicAuthHeader(server);
+ if (basicAuthHeader) {
+ options = options || {};
+ options.headers = options.headers || {};
+ options.headers[basicAuthHeader.name] = basicAuthHeader.value;
+ }
+
+ if (options) {
+ fileKey = options.fileKey;
+ fileName = options.fileName;
+ mimeType = options.mimeType;
+ headers = options.headers;
+ httpMethod = options.httpMethod || "POST";
+ if (httpMethod.toUpperCase() == "PUT"){
+ httpMethod = "PUT";
+ } else {
+ httpMethod = "POST";
+ }
+ if (options.chunkedMode !== null || typeof options.chunkedMode != "undefined") {
+ chunkedMode = options.chunkedMode;
+ }
+ if (options.params) {
+ params = options.params;
+ }
+ else {
+ params = {};
+ }
+ }
+
+ var fail = errorCallback && function(e) {
+ var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body);
+ errorCallback(error);
+ };
+
+ var self = this;
+ var win = function(result) {
+ if (typeof result.lengthComputable != "undefined") {
+ if (self.onprogress) {
+ self.onprogress(newProgressEvent(result));
+ }
+ } else {
+ successCallback && successCallback(result);
+ }
+ };
+ exec(win, fail, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode, headers, this._id, httpMethod]);
+};
+
+/**
+ * Downloads a file form a given URL and saves it to the specified directory.
+ * @param source {String} URL of the server to receive the file
+ * @param target {String} Full path of the file on the device
+ * @param successCallback (Function} Callback to be invoked when upload has completed
+ * @param errorCallback {Function} Callback to be invoked upon error
+ * @param trustAllHosts {Boolean} Optional trust all hosts (e.g. for self-signed certs), defaults to false
+ * @param options {FileDownloadOptions} Optional parameters such as headers
+ */
+FileTransfer.prototype.download = function(source, target, successCallback, errorCallback, trustAllHosts, options) {
+ argscheck.checkArgs('ssFF*', 'FileTransfer.download', arguments);
+ var self = this;
+
+ var basicAuthHeader = getBasicAuthHeader(source);
+ if (basicAuthHeader) {
+ options = options || {};
+ options.headers = options.headers || {};
+ options.headers[basicAuthHeader.name] = basicAuthHeader.value;
+ }
+
+ var headers = null;
+ if (options) {
+ headers = options.headers || null;
+ }
+
+ var win = function(result) {
+ if (typeof result.lengthComputable != "undefined") {
+ if (self.onprogress) {
+ return self.onprogress(newProgressEvent(result));
+ }
+ } else if (successCallback) {
+ var entry = null;
+ if (result.isDirectory) {
+ entry = new (require('cordova/plugin/DirectoryEntry'))();
+ }
+ else if (result.isFile) {
+ entry = new (require('cordova/plugin/FileEntry'))();
+ }
+ entry.isDirectory = result.isDirectory;
+ entry.isFile = result.isFile;
+ entry.name = result.name;
+ entry.fullPath = result.fullPath;
+ successCallback(entry);
+ }
+ };
+
+ var fail = errorCallback && function(e) {
+ var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body);
+ errorCallback(error);
+ };
+
+ exec(win, fail, 'FileTransfer', 'download', [source, target, trustAllHosts, this._id, headers]);
+};
+
+/**
+ * Aborts the ongoing file transfer on this object. The original error
+ * callback for the file trans
<TRUNCATED>
[02/37] Reorganize specs into cordova-cli/ and platform-script/
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/create.spec.js
----------------------------------------------------------------------
diff --git a/spec/create.spec.js b/spec/create.spec.js
deleted file mode 100644
index fcb3e76..0000000
--- a/spec/create.spec.js
+++ /dev/null
@@ -1,68 +0,0 @@
-var cordova = require('../cordova'),
- path = require('path'),
- shell = require('shelljs'),
- fs = require('fs'),
- tempDir = path.join(__dirname, '..', 'temp');
-
-describe('create command', function () {
- beforeEach(function() {
- shell.rm('-rf', tempDir);
- });
-
- it('should print out help txt if no directory is provided', function() {
- expect(cordova.create()).toMatch(/synopsis/i);
- });
- it('should create a cordova project in the specified directory if parameter is provided', function() {
- cordova.create(tempDir);
- var dotc = path.join(tempDir, '.cordova', 'config.json');
- expect(fs.lstatSync(dotc).isFile()).toBe(true);
- expect(JSON.parse(fs.readFileSync(dotc, 'utf8')).name).toBe("HelloCordova");
- var hooks = path.join(tempDir, '.cordova', 'hooks');
- expect(fs.existsSync(hooks)).toBe(true);
- expect(fs.existsSync(path.join(hooks, 'before_platform_add'))).toBe(true);
- expect(fs.existsSync(path.join(hooks, 'before_prepare'))).toBe(true);
- expect(fs.existsSync(path.join(hooks, 'before_compile'))).toBe(true);
- expect(fs.existsSync(path.join(hooks, 'after_platform_add'))).toBe(true);
- expect(fs.existsSync(path.join(hooks, 'before_platform_rm'))).toBe(true);
- expect(fs.existsSync(path.join(hooks, 'after_platform_rm'))).toBe(true);
- expect(fs.existsSync(path.join(hooks, 'before_platform_ls'))).toBe(true);
- expect(fs.existsSync(path.join(hooks, 'after_platform_ls'))).toBe(true);
- expect(fs.existsSync(path.join(hooks, 'before_plugin_add'))).toBe(true);
- expect(fs.existsSync(path.join(hooks, 'after_plugin_add'))).toBe(true);
- expect(fs.existsSync(path.join(hooks, 'before_plugin_rm'))).toBe(true);
- expect(fs.existsSync(path.join(hooks, 'after_plugin_rm'))).toBe(true);
- expect(fs.existsSync(path.join(hooks, 'before_plugin_ls'))).toBe(true);
- expect(fs.existsSync(path.join(hooks, 'after_plugin_ls'))).toBe(true);
- expect(fs.existsSync(path.join(hooks, 'after_prepare'))).toBe(true);
- expect(fs.existsSync(path.join(hooks, 'after_compile'))).toBe(true);
- expect(fs.existsSync(path.join(hooks, 'before_build'))).toBe(true);
- expect(fs.existsSync(path.join(hooks, 'after_build'))).toBe(true);
- expect(fs.existsSync(path.join(hooks, 'before_emulate'))).toBe(true);
- expect(fs.existsSync(path.join(hooks, 'after_emulate'))).toBe(true);
- expect(fs.existsSync(path.join(hooks, 'before_docs'))).toBe(true);
- expect(fs.existsSync(path.join(hooks, 'after_docs'))).toBe(true);
- });
- it('should throw if the directory is already a cordova project', function() {
- shell.mkdir('-p', path.join(tempDir, '.cordova'));
-
- expect(function() {
- cordova.create(tempDir);
- }).toThrow();
- });
- it('should create a cordova project in the specified dir with specified name if provided', function() {
- cordova.create(tempDir, "balls");
-
- expect(fs.lstatSync(path.join(tempDir, '.cordova', 'config.json')).isFile()).toBe(true);
-
- expect(fs.readFileSync(path.join(tempDir, 'www', 'config.xml')).toString('utf8')).toMatch(/<name>balls<\/name>/);
- });
- it('should create a cordova project in the specified dir with specified name and id if provided', function() {
- cordova.create(tempDir, "birdy.nam.nam", "numnum");
-
- expect(fs.lstatSync(path.join(tempDir, '.cordova', 'config.json')).isFile()).toBe(true);
-
- var config = fs.readFileSync(path.join(tempDir, 'www', 'config.xml')).toString('utf8');
- expect(config).toMatch(/<name>numnum<\/name>/);
- expect(config).toMatch(/id="birdy\.nam\.nam"/);
- });
-});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/emulate.spec.js
----------------------------------------------------------------------
diff --git a/spec/emulate.spec.js b/spec/emulate.spec.js
deleted file mode 100644
index 3a4d1a4..0000000
--- a/spec/emulate.spec.js
+++ /dev/null
@@ -1,191 +0,0 @@
-/**
- 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.
-*/
-var cordova = require('../cordova'),
- et = require('elementtree'),
- shell = require('shelljs'),
- path = require('path'),
- fs = require('fs'),
- config_parser = require('../src/config_parser'),
- android_parser = require('../src/metadata/android_parser'),
- ios_parser = require('../src/metadata/ios_parser'),
- blackberry_parser = require('../src/metadata/blackberry_parser'),
- hooker = require('../src/hooker'),
- fixtures = path.join(__dirname, 'fixtures'),
- hooks = path.join(fixtures, 'hooks'),
- tempDir = path.join(__dirname, '..', 'temp'),
- cordova_project = path.join(fixtures, 'projects', 'cordova');
-
-var cwd = process.cwd();
-
-describe('emulate command', function() {
- beforeEach(function() {
- shell.rm('-rf', tempDir);
- shell.mkdir('-p', tempDir);
- });
-
- it('should not run inside a Cordova-based project with no added platforms', function() {
- this.after(function() {
- process.chdir(cwd);
- });
-
- cordova.create(tempDir);
- process.chdir(tempDir);
- expect(function() {
- cordova.emulate();
- }).toThrow();
- });
-
- it('should run inside a Cordova-based project with at least one added platform', function() {
- shell.mv('-f', path.join(cordova_project, 'platforms', 'blackberry'), path.join(tempDir));
- shell.mv('-f', path.join(cordova_project, 'platforms', 'ios'), path.join(tempDir));
- this.after(function() {
- process.chdir(cwd);
- shell.mv('-f', path.join(tempDir, 'blackberry'), path.join(cordova_project, 'platforms', 'blackberry'));
- shell.mv('-f', path.join(tempDir, 'ios'), path.join(cordova_project, 'platforms', 'ios'));
- });
-
- process.chdir(cordova_project);
-
- var s = spyOn(shell, 'exec');
- var a_spy = spyOn(android_parser.prototype, 'update_project');
- expect(function() {
- cordova.emulate();
- a_spy.mostRecentCall.args[1](); // fake out android parser
- expect(s).toHaveBeenCalled();
- }).not.toThrow();
- });
- it('should not run outside of a Cordova-based project', function() {
- this.after(function() {
- process.chdir(cwd);
- });
-
- shell.mkdir('-p', tempDir);
- process.chdir(tempDir);
-
- expect(function() {
- cordova.emulate();
- }).toThrow();
- });
- describe('per platform', function() {
- beforeEach(function() {
- process.chdir(cordova_project);
- });
-
- afterEach(function() {
- process.chdir(cwd);
- });
-
- describe('Android', function() {
- var s;
- beforeEach(function() {
- s = spyOn(require('shelljs'), 'exec');
- });
- it('should shell out to run command on Android', function() {
- cordova.emulate('android');
- expect(s.mostRecentCall.args[0].match(/\/cordova\/run/)).not.toBeNull();
- });
- it('should call android_parser\'s update_project', function() {
- var spy = spyOn(android_parser.prototype, 'update_project');
- cordova.emulate('android');
- expect(spy).toHaveBeenCalled();
- });
- });
- describe('iOS', function() {
- it('should shell out to emulate command on iOS', function() {
- var s = spyOn(require('shelljs'), 'exec');
- var proj_spy = spyOn(ios_parser.prototype, 'update_project');
- cordova.emulate('ios');
- proj_spy.mostRecentCall.args[1]();
- expect(s).toHaveBeenCalled();
- expect(s.mostRecentCall.args[0].match(/\/cordova\/emulate/)).not.toBeNull();
- });
- it('should call ios_parser\'s update_project', function() {
- var s = spyOn(ios_parser.prototype, 'update_project');
- cordova.emulate('ios');
- expect(s).toHaveBeenCalled();
- });
- });
- describe('BlackBerry', function() {
- it('should shell out to ant command on blackberry', function() {
- var proj_spy = spyOn(blackberry_parser.prototype, 'update_project');
- var s = spyOn(require('shelljs'), 'exec');
- cordova.emulate('blackberry');
- proj_spy.mostRecentCall.args[1](); // update_project fake
- expect(s).toHaveBeenCalled();
- expect(s.mostRecentCall.args[0]).toMatch(/ant -f .*build\.xml" qnx load-simulator/);
- });
- it('should call blackberry_parser\'s update_project', function() {
- var s = spyOn(blackberry_parser.prototype, 'update_project');
- cordova.emulate('blackberry');
- expect(s).toHaveBeenCalled();
- });
- });
- });
-
- describe('hooks', function() {
- var s, sh, ap;
- beforeEach(function() {
- s = spyOn(hooker.prototype, 'fire').andReturn(true);
- });
-
- describe('when platforms are added', function() {
- beforeEach(function() {
- shell.mv('-f', path.join(cordova_project, 'platforms', 'blackberry'), path.join(tempDir));
- shell.mv('-f', path.join(cordova_project, 'platforms', 'ios'), path.join(tempDir));
- sh = spyOn(shell, 'exec');
- ap = spyOn(android_parser.prototype, 'update_project');
- process.chdir(cordova_project);
- });
- afterEach(function() {
- shell.mv('-f', path.join(tempDir, 'blackberry'), path.join(cordova_project, 'platforms', 'blackberry'));
- shell.mv('-f', path.join(tempDir, 'ios'), path.join(cordova_project, 'platforms', 'ios'));
- process.chdir(cwd);
- });
-
- it('should fire before hooks through the hooker module', function() {
- cordova.emulate();
- expect(s).toHaveBeenCalledWith('before_emulate');
- });
- it('should fire after hooks through the hooker module', function() {
- cordova.emulate();
- ap.mostRecentCall.args[1](); // fake parser call
- sh.mostRecentCall.args[2](0); //fake shell call
- expect(s).toHaveBeenCalledWith('after_emulate');
- });
- });
-
- describe('with no platforms added', function() {
- beforeEach(function() {
- cordova.create(tempDir);
- process.chdir(tempDir);
- });
- afterEach(function() {
- process.chdir(cwd);
- });
- it('should not fire the hooker', function() {
- spyOn(shell, 'exec');
- expect(function() {
- cordova.emulate();
- }).toThrow();
- expect(s).not.toHaveBeenCalledWith('before_emulate');
- expect(s).not.toHaveBeenCalledWith('after_emulate');
- });
- });
- });
-});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/helper.js
----------------------------------------------------------------------
diff --git a/spec/helper.js b/spec/helper.js
deleted file mode 100644
index 2c4f331..0000000
--- a/spec/helper.js
+++ /dev/null
@@ -1,20 +0,0 @@
-
-/**
- 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.
-*/
-jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/hooker.spec.js
----------------------------------------------------------------------
diff --git a/spec/hooker.spec.js b/spec/hooker.spec.js
deleted file mode 100644
index 4a0ca7d..0000000
--- a/spec/hooker.spec.js
+++ /dev/null
@@ -1,137 +0,0 @@
-/**
- 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.
-*/
-var hooker = require('../src/hooker'),
- shell = require('shelljs'),
- path = require('path'),
- fs = require('fs'),
- tempDir= path.join(__dirname, '..', 'temp'),
- hooks = path.join(__dirname, 'fixtures', 'hooks'),
- cordova= require('../cordova');
-
-var cwd = process.cwd();
-
-describe('hooker', function() {
- it('should throw if provided directory is not a cordova project', function() {
- shell.rm('-rf', tempDir);
- shell.mkdir('-p', tempDir);
- this.after(function() {
- shell.rm('-rf', tempDir);
- });
-
- expect(function() {
- var h = new hooker(tempDir);
- }).toThrow();
- });
- it('should not throw if provided directory is a cordova project', function() {
- cordova.create(tempDir);
- this.after(function() {
- shell.rm('-rf', tempDir);
- });
-
- expect(function() {
- var h = new hooker(tempDir);
- }).not.toThrow();
- });
-
- describe('fire method', function() {
- var h;
-
- beforeEach(function() {
- cordova.create(tempDir);
- h = new hooker(tempDir);
- });
- afterEach(function() {
- shell.rm('-rf', tempDir);
- });
-
- describe('failure', function() {
- it('should not throw if the hook is unrecognized', function() {
- expect(function() {
- h.fire('CLEAN YOUR SHORTS GODDAMNIT LIKE A BIG BOY!');
- }).not.toThrow();
- });
- it('should throw if any script exits with non-zero code', function() {
- var script = path.join(tempDir, '.cordova', 'hooks', 'before_build', 'fail.sh');
- shell.cp(path.join(hooks, 'fail', 'fail.sh'), script);
- fs.chmodSync(script, '754');
- expect(function() {
- h.fire('before_build');
- }).toThrow();
- });
- });
-
- describe('success', function() {
- it('should execute all scripts in order and return true', function() {
- var hook = path.join(tempDir, '.cordova', 'hooks', 'before_build');
- shell.cp(path.join(hooks, 'test', '*'), path.join(hook, '.'));
- fs.readdirSync(hook).forEach(function(script) {
- fs.chmodSync(path.join(hook, script), '754');
- });
- var returnValue;
- var s = spyOn(shell, 'exec').andReturn({code:0});
- expect(function() {
- returnValue = h.fire('before_build');
- }).not.toThrow();
- expect(returnValue).toBe(true);
- expect(s.calls[0].args[0]).toMatch(/0.sh/);
- expect(s.calls[1].args[0]).toMatch(/1.sh/);
- });
- it('should pass the project root folder as parameter into the project-level hooks', function() {
- var hook = path.join(tempDir, '.cordova', 'hooks', 'before_build');
- shell.cp(path.join(hooks, 'test', '0.sh'), path.join(hook, '.'));
- fs.readdirSync(hook).forEach(function(script) {
- fs.chmodSync(path.join(hook, script), '754');
- });
- var returnValue;
- var s = spyOn(shell, 'exec').andReturn({code:0});
- expect(function() {
- returnValue = h.fire('before_build');
- }).not.toThrow();
- expect(returnValue).toBe(true);
- var paramRegex = new RegExp('0.sh "'+tempDir+'"$');
- expect(s.calls[0].args[0]).toMatch(paramRegex);
- });
- describe('module-level hooks', function() {
- var handler = jasmine.createSpy();
- var test_event = 'before_build';
- afterEach(function() {
- cordova.off(test_event, handler);
- handler.reset();
- });
-
- it('should fire handlers using cordova.on', function() {
- cordova.on(test_event, handler);
- h.fire(test_event);
- expect(handler).toHaveBeenCalled();
- });
- it('should pass the project root folder as parameter into the module-level handlers', function() {
- cordova.on(test_event, handler);
- h.fire('before_build');
- expect(handler).toHaveBeenCalledWith(tempDir);
- });
- it('should be able to stop listening to events using cordova.off', function() {
- cordova.on(test_event, handler);
- cordova.off(test_event, handler);
- h.fire('before_build');
- expect(handler).not.toHaveBeenCalled();
- });
- });
- });
- });
-});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/metadata/android_parser.spec.js
----------------------------------------------------------------------
diff --git a/spec/metadata/android_parser.spec.js b/spec/metadata/android_parser.spec.js
deleted file mode 100644
index d051c6f..0000000
--- a/spec/metadata/android_parser.spec.js
+++ /dev/null
@@ -1,220 +0,0 @@
-
-/**
- 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.
-*/
-var android_parser = require('../../src/metadata/android_parser'),
- config_parser = require('../../src/config_parser'),
- util = require('../../src/util'),
- path = require('path'),
- shell = require('shelljs'),
- fs = require('fs'),
- et = require('elementtree'),
- cordova = require('../../cordova'),
- projects_path = path.join(__dirname, '..', 'fixtures', 'projects'),
- android_path = path.join(projects_path, 'native', 'android_fixture'),
- project_path = path.join(projects_path, 'cordova'),
- android_project_path = path.join(project_path, 'platforms', 'android');
-
-var www_config = path.join(project_path, 'www', 'config.xml');
-var original_www_config = fs.readFileSync(www_config, 'utf-8');
-
-describe('android project parser', function() {
- it('should throw an exception with a path that is not a native android project', function() {
- expect(function() {
- var project = new android_parser(process.cwd());
- }).toThrow();
- });
- it('should accept a proper native android project path as construction parameter', function() {
- expect(function() {
- var project = new android_parser(android_path);
- expect(project).toBeDefined();
- }).not.toThrow();
- });
-
- describe('update_from_config method', function() {
- var project, config;
-
- var android_strings = path.join(android_path, 'res', 'values', 'strings.xml');
- var android_manifest = path.join(android_path, 'AndroidManifest.xml');
- var android_config = path.join(android_path, 'res', 'xml', 'config.xml');
-
- var original_strings = fs.readFileSync(android_strings, 'utf-8');
- var original_manifest = fs.readFileSync(android_manifest, 'utf-8');
- var original_android_config = fs.readFileSync(android_config, 'utf-8');
-
- beforeEach(function() {
- project = new android_parser(android_path);
- config = new config_parser(www_config);
- });
- afterEach(function() {
- fs.writeFileSync(android_strings, original_strings, 'utf-8');
- fs.writeFileSync(android_manifest, original_manifest, 'utf-8');
- fs.writeFileSync(www_config, original_www_config, 'utf-8');
- fs.writeFileSync(android_config, original_android_config, 'utf-8');
- });
- it('should throw an exception if a non config_parser object is passed into it', function() {
- expect(function() {
- project.update_from_config({});
- }).toThrow();
- });
- it('should update the application name properly', function() {
- config.name('bond. james bond.');
- project.update_from_config(config);
-
- var strings = new et.ElementTree(et.XML(fs.readFileSync(android_strings, 'utf-8')));
- var app_name = strings.find('string[@name="app_name"]').text;
-
- expect(app_name).toBe('bond. james bond.');
- });
- it('should update the application package name properly', function() {
- var javs = path.join(android_path, 'src', 'ca', 'filmaj', 'dewd', 'cordovaExample.java');
- var orig_javs = path.join(android_path, 'src', 'org', 'apache', 'cordova', 'cordovaExample', 'cordovaExample.java');
- var orig_contents = fs.readFileSync(orig_javs, 'utf-8');
- this.after(function() {
- fs.writeFileSync(orig_javs, orig_contents, 'utf-8');
- shell.rm('-rf', path.join(android_path, 'src', 'ca'));
- });
- config.packageName('ca.filmaj.dewd');
- project.update_from_config(config);
-
- var manifest = new et.ElementTree(et.XML(fs.readFileSync(android_manifest, 'utf-8')));
- expect(manifest.getroot().attrib.package).toEqual('ca.filmaj.dewd');
-
- expect(fs.existsSync(javs)).toBe(true);
- expect(fs.readFileSync(javs, 'utf-8')).toMatch(/package ca.filmaj.dewd/i);
- });
- it('should update the whitelist properly', function() {
- config.access.remove('*');
- config.access.add('http://apache.org');
- config.access.add('http://github.com');
- project.update_from_config(config);
-
- var native_config = new et.ElementTree(et.XML(fs.readFileSync(android_config, 'utf-8')));
- var as = native_config.findall('access');
- expect(as.length).toEqual(2);
- expect(as[0].attrib.origin).toEqual('http://apache.org');
- expect(as[1].attrib.origin).toEqual('http://github.com');
- });
- describe('preferences', function() {
- it('should not change default project preferences and copy over additional project preferences to platform-level config.xml', function() {
- config.preference.add({name:'henrik',value:'sedin'});
- project.update_from_config(config);
-
- var native_config = new et.ElementTree(et.XML(fs.readFileSync(android_config, 'utf-8')));
- var ps = native_config.findall('preference');
- expect(ps.length).toEqual(7);
- expect(ps[0].attrib.name).toEqual('useBrowserHistory');
- expect(ps[0].attrib.value).toEqual('true');
- expect(ps[6].attrib.name).toEqual('henrik');
- expect(ps[6].attrib.value).toEqual('sedin');
- });
- it('should override a default project preference if applicable', function() {
- config.preference.add({name:'useBrowserHistory',value:'false'});
- project.update_from_config(config);
-
- var native_config = new et.ElementTree(et.XML(fs.readFileSync(android_config, 'utf-8')));
- var ps = native_config.findall('preference');
- expect(ps.length).toEqual(6);
- expect(ps[0].attrib.name).toEqual('useBrowserHistory');
- expect(ps[0].attrib.value).toEqual('false');
- });
- });
- });
-
- describe('cross-platform project level methods', function() {
- var parser, config;
- var android_strings = path.join(android_project_path, 'res', 'values', 'strings.xml');
- var android_manifest = path.join(android_project_path, 'AndroidManifest.xml');
- var android_config = path.join(android_project_path, 'res', 'xml', 'config.xml');
-
- var original_strings = fs.readFileSync(android_strings, 'utf-8');
- var original_manifest = fs.readFileSync(android_manifest, 'utf-8');
- var original_android_config = fs.readFileSync(android_config, 'utf-8');
-
- beforeEach(function() {
- parser = new android_parser(android_project_path);
- config = new config_parser(www_config);
- });
- afterEach(function() {
- fs.writeFileSync(android_strings, original_strings, 'utf-8');
- fs.writeFileSync(android_manifest, original_manifest, 'utf-8');
- fs.writeFileSync(www_config, original_www_config, 'utf-8');
- fs.writeFileSync(android_config, original_android_config, 'utf-8');
- });
- describe('update_www method', function() {
- it('should update all www assets', function() {
- var newFile = path.join(project_path, 'www', 'somescript.js');
- this.after(function() {
- shell.rm('-f', newFile);
- });
- fs.writeFileSync(newFile, 'alert("sup");', 'utf-8');
- parser.update_www();
- expect(fs.existsSync(path.join(android_project_path, 'assets', 'www', 'somescript.js'))).toBe(true);
- });
- it('should write out android js to cordova.js', function() {
- parser.update_www();
- expect(fs.readFileSync(path.join(android_project_path, 'assets', 'www', 'cordova.js'),'utf-8')).toBe(fs.readFileSync(path.join(util.libDirectory, 'cordova-android', 'framework', 'assets', 'js', 'cordova.android.js'), 'utf-8'));
- });
- });
-
- describe('update_overrides method',function() {
- var mergesPath = path.join(project_path, 'merges', 'android');
- var newFile = path.join(mergesPath, 'merge.js');
- beforeEach(function() {
- shell.mkdir('-p', mergesPath);
- fs.writeFileSync(newFile, 'alert("sup");', 'utf-8');
- });
- afterEach(function() {
- shell.rm('-rf', mergesPath);
- });
- it('should copy a new file from merges into www', function() {
- parser.update_overrides();
- expect(fs.existsSync(path.join(android_project_path, 'assets', 'www', 'merge.js'))).toBe(true);
- });
-
- it('should copy a file from merges over a file in www', function() {
- var newFileWWW = path.join(project_path, 'www','merge.js');
- fs.writeFileSync(newFileWWW, 'var foo=1;', 'utf-8');
- this.after(function() {
- shell.rm('-rf', newFileWWW);
- });
- parser.update_overrides();
- expect(fs.existsSync(path.join(android_project_path, 'assets', 'www', 'merge.js'))).toBe(true);
- expect(fs.readFileSync(path.join(android_project_path, 'assets', 'www', 'merge.js'),'utf-8')).toEqual('alert("sup");');
- });
- });
-
- describe('update_project method', function() {
- it('should invoke update_www', function() {
- var spyWww = spyOn(parser, 'update_www');
- parser.update_project(config);
- expect(spyWww).toHaveBeenCalled();
- });
- it('should invoke update_from_config', function() {
- var spyConfig = spyOn(parser, 'update_from_config');
- parser.update_project(config);
- expect(spyConfig).toHaveBeenCalled();
- });
- it('should call out to util.deleteSvnFolders', function() {
- var spy = spyOn(util, 'deleteSvnFolders');
- parser.update_project(config);
- expect(spy).toHaveBeenCalled();
- });
- });
- });
-});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/metadata/blackberry_parser.spec.js
----------------------------------------------------------------------
diff --git a/spec/metadata/blackberry_parser.spec.js b/spec/metadata/blackberry_parser.spec.js
deleted file mode 100644
index 12d5294..0000000
--- a/spec/metadata/blackberry_parser.spec.js
+++ /dev/null
@@ -1,249 +0,0 @@
-
-/**
- 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.
-*/
-var blackberry_parser = require('../../src/metadata/blackberry_parser'),
- config_parser = require('../../src/config_parser'),
- path = require('path'),
- util = require('../../src/util'),
- et = require('elementtree'),
- shell = require('shelljs'),
- cordova = require('../../cordova'),
- fs = require('fs'),
- projects_path = path.join(__dirname, '..', 'fixtures', 'projects'),
- blackberry_path = path.join(projects_path, 'native', 'blackberry_fixture'),
- project_path = path.join(projects_path, 'cordova'),
- blackberry_project_path = path.join(project_path, 'platforms', 'blackberry');
-
-var www_config = path.join(project_path, 'www', 'config.xml');
-var original_www_config = fs.readFileSync(www_config, 'utf-8');
-
-describe('blackberry project parser', function() {
- beforeEach(function() {
- spyOn(process.stdout, 'write'); // silence console output
- });
-
- it('should throw an exception with a path that is not a native blackberry project', function() {
- expect(function() {
- var project = new blackberry_parser(process.cwd());
- }).toThrow();
- });
- it('should accept a proper native blackberry project path as construction parameter', function() {
- var project;
- expect(function() {
- project = new blackberry_parser(blackberry_path);
- }).not.toThrow();
- expect(project).toBeDefined();
- });
-
- describe('update_from_config method', function() {
- var project, config;
-
- var blackberry_config = path.join(blackberry_path, 'www', 'config.xml');
- var original_blackberry_config = fs.readFileSync(blackberry_config, 'utf-8');
-
- beforeEach(function() {
- project = new blackberry_parser(blackberry_path);
- config = new config_parser(www_config);
- });
- afterEach(function() {
- fs.writeFileSync(blackberry_config, original_blackberry_config, 'utf-8');
- fs.writeFileSync(www_config, original_www_config, 'utf-8');
- });
- it('should throw an exception if a non config_parser object is passed into it', function() {
- expect(function() {
- project.update_from_config({});
- }).toThrow();
- });
- it('should update the application name properly', function() {
- config.name('bond. james bond.');
- project.update_from_config(config);
-
- var bb_cfg = new config_parser(blackberry_config);
-
- expect(bb_cfg.name()).toBe('bond. james bond.');
- });
- it('should update the application package name properly', function() {
- config.packageName('sofa.king.awesome');
- project.update_from_config(config);
-
- var bb_cfg = new config_parser(blackberry_config);
- expect(bb_cfg.packageName()).toBe('sofa.king.awesome');
- });
- describe('whitelist', function() {
- it('should update the whitelist when using access elements with origin attribute', function() {
- config.access.remove('*');
- config.access.add('http://blackberry.com');
- config.access.add('http://rim.com');
- project.update_from_config(config);
-
- var bb_cfg = new et.ElementTree(et.XML(fs.readFileSync(blackberry_config, 'utf-8')));
- var as = bb_cfg.getroot().findall('access');
- expect(as.length).toEqual(2);
- expect(as[0].attrib.uri).toEqual('http://blackberry.com');
- expect(as[1].attrib.uri).toEqual('http://rim.com');
- });
- it('should update the whitelist when using access elements with uri attributes', function() {
- fs.writeFileSync(www_config, fs.readFileSync(www_config, 'utf-8').replace(/origin="\*/,'uri="http://rim.com'), 'utf-8');
- config = new config_parser(www_config);
- project.update_from_config(config);
-
- var bb_cfg = new et.ElementTree(et.XML(fs.readFileSync(blackberry_config, 'utf-8')));
- var as = bb_cfg.getroot().findall('access');
- expect(as.length).toEqual(1);
- expect(as[0].attrib.uri).toEqual('http://rim.com');
- });
- });
- });
-
- describe('cross-platform project level methods', function() {
- var parser, config;
-
- var blackberry_config = path.join(blackberry_project_path, 'www', 'config.xml');
- var original_blackberry_config = fs.readFileSync(blackberry_config, 'utf-8');
-
- beforeEach(function() {
- parser = new blackberry_parser(blackberry_project_path);
- config = new config_parser(www_config);
- });
- afterEach(function() {
- fs.writeFileSync(blackberry_config, original_blackberry_config, 'utf-8');
- fs.writeFileSync(www_config, original_www_config, 'utf-8');
- });
-
- describe('update_www method', function() {
- it('should update all www assets', function() {
- var newFile = path.join(project_path, 'www', 'somescript.js');
- this.after(function() {
- shell.rm('-f', newFile);
- });
- fs.writeFileSync(newFile, 'alert("sup");', 'utf-8');
- parser.update_www();
- expect(fs.existsSync(path.join(blackberry_project_path, 'www', 'somescript.js'))).toBe(true);
- });
- it('should not overwrite the blackberry-specific config.xml', function() {
- var www_cfg = fs.readFileSync(path.join(project_path, 'www', 'config.xml'), 'utf-8');
- parser.update_www();
- var bb_cfg = fs.readFileSync(blackberry_config, 'utf-8');
- expect(bb_cfg).not.toBe(www_cfg);
- });
- });
-
- describe('update_overrides method',function() {
- var mergesPath = path.join(project_path, 'merges', 'blackberry');
- var newFile = path.join(mergesPath, 'merge.js');
- beforeEach(function() {
- shell.mkdir('-p', mergesPath);
- fs.writeFileSync(newFile, 'alert("sup");', 'utf-8');
- });
- afterEach(function() {
- shell.rm('-rf', mergesPath);
- });
-
- it('should copy a new file from merges into www', function() {
- parser.update_overrides();
- expect(fs.existsSync(path.join(blackberry_project_path, 'www', 'merge.js'))).toBe(true);
- });
-
- it('should copy a file from merges over a file in www', function() {
- var newFileWWW = path.join(project_path, 'www','merge.js');
- fs.writeFileSync(newFileWWW, 'var foo=1;', 'utf-8');
- this.after(function() {
- shell.rm('-rf', newFileWWW);
- });
- parser.update_overrides();
- expect(fs.existsSync(path.join(blackberry_project_path, 'www', 'merge.js'))).toBe(true);
- expect(fs.readFileSync(path.join(blackberry_project_path, 'www', 'merge.js'),'utf-8')).toEqual('alert("sup");');
- });
- });
-
- describe('update_project method', function() {
- var cordova_config_path = path.join(project_path, '.cordova', 'config.json');
- var original_config_json = fs.readFileSync(cordova_config_path, 'utf-8');
-
- describe('with stubbed out config for BlackBerry SDKs', function() {
- beforeEach(function() {
- fs.writeFileSync(cordova_config_path, JSON.stringify({
- blackberry:{
- qnx:{
- }
- }
- }), 'utf-8');
- });
- afterEach(function() {
- fs.writeFileSync(cordova_config_path, original_config_json, 'utf-8');
- });
- it('should invoke update_www', function() {
- var spyWww = spyOn(parser, 'update_www');
- parser.update_project(config);
- expect(spyWww).toHaveBeenCalled();
- });
- it('should invoke update_from_config', function() {
- var spyConfig = spyOn(parser, 'update_from_config');
- parser.update_project(config);
- expect(spyConfig).toHaveBeenCalled();
- });
- it('should not invoke get_blackberry_environment', function() {
- var spyEnv = spyOn(parser, 'get_blackberry_environment');
- parser.update_project(config);
- expect(spyEnv).not.toHaveBeenCalled();
- });
- it('should write out project properties', function(done) {
- var spyProps = spyOn(parser, 'write_project_properties');
- parser.update_project(config, function() {
- expect(spyProps).toHaveBeenCalled();
- done();
- });
- });
- it('should call out to util.deleteSvnFolders', function(done) {
- var spy = spyOn(util, 'deleteSvnFolders');
- parser.update_project(config, function() {
- expect(spy).toHaveBeenCalled();
- done();
- });
- });
- });
- describe('with empty BlackBerry SDKs in config', function() {
- afterEach(function() {
- fs.writeFileSync(cordova_config_path, original_config_json, 'utf-8');
- });
- it('should invoke get_blackberry_environment', function() {
- var spyEnv = spyOn(parser, 'get_blackberry_environment');
- var promptSpy = spyOn(require('prompt'), 'get');
- parser.update_project(config);
- expect(spyEnv).toHaveBeenCalled();
- });
- it('should write out project properties', function(done) {
- var spyProps = spyOn(parser, 'write_project_properties');
- var promptSpy = spyOn(require('prompt'), 'get');
- parser.update_project(config, function() {
- expect(spyProps).toHaveBeenCalled();
- done();
- });
- promptSpy.mostRecentCall.args[1](null, {});
- });
- });
- });
- });
-
- describe('write_project_properties method', function() {
- });
-
- describe('get_blackberry_environment method', function() {
- });
-});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/metadata/ios_parser.spec.js
----------------------------------------------------------------------
diff --git a/spec/metadata/ios_parser.spec.js b/spec/metadata/ios_parser.spec.js
deleted file mode 100644
index dbd4816..0000000
--- a/spec/metadata/ios_parser.spec.js
+++ /dev/null
@@ -1,218 +0,0 @@
-/**
- 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.
- */
-
-var ios_parser = require('../../src/metadata/ios_parser'),
- config_parser = require('../../src/config_parser'),
- cordova = require('../../cordova'),
- util = require('../../src/util'),
- path = require('path'),
- shell = require('shelljs'),
- fs = require('fs'),
- et = require('elementtree'),
- projects_path = path.join(__dirname, '..', 'fixtures', 'projects')
-ios_path = path.join(projects_path, 'native', 'ios_fixture'),
- project_path = path.join(projects_path, 'cordova'),
- ios_project_path = path.join(project_path, 'platforms', 'ios');
-
-var www_config = path.join(project_path, 'www', 'config.xml');
-var original_www_config = fs.readFileSync(www_config, 'utf-8');
-
-describe('ios project parser', function () {
- it('should throw an exception with a path that is not a native ios project', function () {
- expect(function () {
- var project = new ios_parser(process.cwd());
- }).toThrow();
- });
- it('should accept a proper native ios project path as construction parameter', function () {
- var project;
- expect(function () {
- project = new ios_parser(ios_path);
- }).not.toThrow();
- expect(project).toBeDefined();
- });
-
- describe('update_from_config method', function () {
- var project, config;
-
- var ios_plist = path.join(ios_path, 'cordovaExample', 'cordovaExample-Info.plist'),
- ios_pbx = path.join(ios_path, 'cordovaExample.xcodeproj', 'project.pbxproj'),
- ios_config_xml = path.join(ios_path, 'cordovaExample', 'config.xml');
-
- var original_pbx = fs.readFileSync(ios_pbx, 'utf-8');
- var original_plist = fs.readFileSync(ios_plist, 'utf-8');
- var original_ios_config = fs.readFileSync(ios_config_xml, 'utf-8');
-
- beforeEach(function () {
- project = new ios_parser(ios_path);
- config = new config_parser(www_config);
- });
- afterEach(function () {
- fs.writeFileSync(ios_pbx, original_pbx, 'utf-8');
- fs.writeFileSync(ios_config_xml, original_ios_config, 'utf-8');
- fs.writeFileSync(ios_plist, original_plist, 'utf-8');
- fs.writeFileSync(www_config, original_www_config, 'utf-8');
- });
- it('should throw an exception if a non config_parser object is passed into it', function () {
- expect(function () {
- project.update_from_config({});
- }).toThrow();
- });
- it('should update the application name properly', function (done) {
- config.name('bond. james bond.');
- project.update_from_config(config, function () {
- var pbx_contents = fs.readFileSync(ios_pbx, 'utf-8');
- expect(pbx_contents.match(/PRODUCT_NAME\s*=\s*"bond. james bond."/)[0]).toBe('PRODUCT_NAME = "bond. james bond."');
- done();
- });
- });
- it('should update the application package name (bundle identifier) properly', function (done) {
- config.packageName('ca.filmaj.dewd');
- project.update_from_config(config, function () {
- var plist_contents = fs.readFileSync(ios_plist, 'utf-8');
- expect(plist_contents).toMatch(/<string>ca.filmaj.dewd/);
- done();
- });
- });
- it('should update the whitelist in the project config.xml', function (done) {
- project.update_from_config(config, function () {
- var config_contents = fs.readFileSync(ios_config_xml, 'utf-8');
- expect(config_contents).toMatch(/<access origin="\*" \/>/);
- done();
- });
- });
- describe('preferences', function () {
- it('should not change default project preferences and copy over additional project preferences to platform-level config.xml', function (done) {
- config.preference.add({name:'henrik', value:'sedin'});
- project.update_from_config(config, function () {
- var native_config = new et.ElementTree(et.XML(fs.readFileSync(ios_config_xml, 'utf-8')));
- var ps = native_config.findall('preference');
- expect(ps.length).toEqual(17);
- expect(ps[0].attrib.name).toEqual('KeyboardDisplayRequiresUserAction');
- expect(ps[0].attrib.value).toEqual('true');
- expect(ps[16].attrib.name).toEqual('henrik');
- expect(ps[16].attrib.value).toEqual('sedin');
- done();
- });
- });
- it('should override a default project preference if applicable', function (done) {
- config.preference.add({name:'UIWebViewBounce', value:'false'});
- project.update_from_config(config, function () {
- var native_config = new et.ElementTree(et.XML(fs.readFileSync(ios_config_xml, 'utf-8')));
- var ps = native_config.findall('preference');
- expect(ps.length).toEqual(16);
- expect(ps[2].attrib.name).toEqual('UIWebViewBounce');
- expect(ps[2].attrib.value).toEqual('false');
- done();
- });
- });
- });
- });
-
- describe('cross-platform project level methods', function () {
- var parser, config;
- var ios_plist = path.join(ios_project_path, 'cordovaExample', 'cordovaExample-Info.plist'),
- ios_pbx = path.join(ios_project_path, 'cordovaExample.xcodeproj', 'project.pbxproj'),
- ios_config_xml = path.join(ios_project_path, 'cordovaExample', 'config.xml');
-
- var original_pbx = fs.readFileSync(ios_pbx, 'utf-8');
- var original_plist = fs.readFileSync(ios_plist, 'utf-8');
- var original_ios_config = fs.readFileSync(ios_config_xml, 'utf-8');
-
- beforeEach(function () {
- parser = new ios_parser(ios_project_path);
- config = new config_parser(www_config);
- });
- afterEach(function () {
- fs.writeFileSync(ios_pbx, original_pbx, 'utf-8');
- fs.writeFileSync(ios_config_xml, original_ios_config, 'utf-8');
- fs.writeFileSync(ios_plist, original_plist, 'utf-8');
- fs.writeFileSync(www_config, original_www_config, 'utf-8');
- });
-
- describe('update_www method', function () {
- it('should update all www assets', function () {
- var newFile = path.join(project_path, 'www', 'somescript.js');
- this.after(function () {
- shell.rm('-f', newFile);
- });
- fs.writeFileSync(newFile, 'alert("sup");', 'utf-8');
- parser.update_www();
- expect(fs.existsSync(path.join(ios_project_path, 'www', 'somescript.js'))).toBe(true);
- });
- it('should write out ios js to cordova.js', function () {
- parser.update_www();
- expect(fs.readFileSync(path.join(ios_project_path, 'www', 'cordova.js'), 'utf-8')).toBe(fs.readFileSync(path.join(util.libDirectory, 'cordova-ios', 'CordovaLib', 'cordova.ios.js'), 'utf-8'));
- });
- });
-
- describe('update_overrides method', function () {
- var mergesPath = path.join(project_path, 'merges', 'ios');
- var newFile = path.join(mergesPath, 'merge.js');
- beforeEach(function() {
- shell.mkdir('-p', mergesPath);
- fs.writeFileSync(newFile, 'alert("sup");', 'utf-8');
- });
- afterEach(function() {
- shell.rm('-rf', mergesPath);
- });
-
- it('should copy a new file from merges into www', function () {
- parser.update_overrides();
- expect(fs.existsSync(path.join(ios_project_path, 'www', 'merge.js'))).toBe(true);
- });
-
- it('should copy a file from merges over a file in www', function () {
- var newFileWWW = path.join(project_path, 'www', 'merge.js');
- fs.writeFileSync(newFileWWW, 'var foo=1;', 'utf-8');
- this.after(function () {
- shell.rm('-rf', newFileWWW);
- });
-
- parser.update_overrides();
- expect(fs.existsSync(path.join(ios_project_path, 'www', 'merge.js'))).toBe(true);
- expect(fs.readFileSync(path.join(ios_project_path, 'www', 'merge.js'), 'utf-8')).toEqual('alert("sup");');
- });
- });
-
- describe('update_project method', function () {
- it('should invoke update_www', function (done) {
- var spyWww = spyOn(parser, 'update_www');
- parser.update_project(config, function () {
- expect(spyWww).toHaveBeenCalled();
- done();
- });
- });
- it('should invoke update_from_config', function (done) {
- var spyConfig = spyOn(parser, 'update_from_config').andCallThrough();
- parser.update_project(config, function () {
- expect(spyConfig).toHaveBeenCalled();
- done();
- });
- });
- it('should call out to util.deleteSvnFolders', function(done) {
- var spy = spyOn(util, 'deleteSvnFolders');
- var spyConfig = spyOn(parser, 'update_from_config').andCallThrough();
- parser.update_project(config, function () {
- expect(spy).toHaveBeenCalled();
- done();
- });
- });
- });
- });
-});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/platform-script/android/android_parser.spec.js
----------------------------------------------------------------------
diff --git a/spec/platform-script/android/android_parser.spec.js b/spec/platform-script/android/android_parser.spec.js
new file mode 100644
index 0000000..d051c6f
--- /dev/null
+++ b/spec/platform-script/android/android_parser.spec.js
@@ -0,0 +1,220 @@
+
+/**
+ 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.
+*/
+var android_parser = require('../../src/metadata/android_parser'),
+ config_parser = require('../../src/config_parser'),
+ util = require('../../src/util'),
+ path = require('path'),
+ shell = require('shelljs'),
+ fs = require('fs'),
+ et = require('elementtree'),
+ cordova = require('../../cordova'),
+ projects_path = path.join(__dirname, '..', 'fixtures', 'projects'),
+ android_path = path.join(projects_path, 'native', 'android_fixture'),
+ project_path = path.join(projects_path, 'cordova'),
+ android_project_path = path.join(project_path, 'platforms', 'android');
+
+var www_config = path.join(project_path, 'www', 'config.xml');
+var original_www_config = fs.readFileSync(www_config, 'utf-8');
+
+describe('android project parser', function() {
+ it('should throw an exception with a path that is not a native android project', function() {
+ expect(function() {
+ var project = new android_parser(process.cwd());
+ }).toThrow();
+ });
+ it('should accept a proper native android project path as construction parameter', function() {
+ expect(function() {
+ var project = new android_parser(android_path);
+ expect(project).toBeDefined();
+ }).not.toThrow();
+ });
+
+ describe('update_from_config method', function() {
+ var project, config;
+
+ var android_strings = path.join(android_path, 'res', 'values', 'strings.xml');
+ var android_manifest = path.join(android_path, 'AndroidManifest.xml');
+ var android_config = path.join(android_path, 'res', 'xml', 'config.xml');
+
+ var original_strings = fs.readFileSync(android_strings, 'utf-8');
+ var original_manifest = fs.readFileSync(android_manifest, 'utf-8');
+ var original_android_config = fs.readFileSync(android_config, 'utf-8');
+
+ beforeEach(function() {
+ project = new android_parser(android_path);
+ config = new config_parser(www_config);
+ });
+ afterEach(function() {
+ fs.writeFileSync(android_strings, original_strings, 'utf-8');
+ fs.writeFileSync(android_manifest, original_manifest, 'utf-8');
+ fs.writeFileSync(www_config, original_www_config, 'utf-8');
+ fs.writeFileSync(android_config, original_android_config, 'utf-8');
+ });
+ it('should throw an exception if a non config_parser object is passed into it', function() {
+ expect(function() {
+ project.update_from_config({});
+ }).toThrow();
+ });
+ it('should update the application name properly', function() {
+ config.name('bond. james bond.');
+ project.update_from_config(config);
+
+ var strings = new et.ElementTree(et.XML(fs.readFileSync(android_strings, 'utf-8')));
+ var app_name = strings.find('string[@name="app_name"]').text;
+
+ expect(app_name).toBe('bond. james bond.');
+ });
+ it('should update the application package name properly', function() {
+ var javs = path.join(android_path, 'src', 'ca', 'filmaj', 'dewd', 'cordovaExample.java');
+ var orig_javs = path.join(android_path, 'src', 'org', 'apache', 'cordova', 'cordovaExample', 'cordovaExample.java');
+ var orig_contents = fs.readFileSync(orig_javs, 'utf-8');
+ this.after(function() {
+ fs.writeFileSync(orig_javs, orig_contents, 'utf-8');
+ shell.rm('-rf', path.join(android_path, 'src', 'ca'));
+ });
+ config.packageName('ca.filmaj.dewd');
+ project.update_from_config(config);
+
+ var manifest = new et.ElementTree(et.XML(fs.readFileSync(android_manifest, 'utf-8')));
+ expect(manifest.getroot().attrib.package).toEqual('ca.filmaj.dewd');
+
+ expect(fs.existsSync(javs)).toBe(true);
+ expect(fs.readFileSync(javs, 'utf-8')).toMatch(/package ca.filmaj.dewd/i);
+ });
+ it('should update the whitelist properly', function() {
+ config.access.remove('*');
+ config.access.add('http://apache.org');
+ config.access.add('http://github.com');
+ project.update_from_config(config);
+
+ var native_config = new et.ElementTree(et.XML(fs.readFileSync(android_config, 'utf-8')));
+ var as = native_config.findall('access');
+ expect(as.length).toEqual(2);
+ expect(as[0].attrib.origin).toEqual('http://apache.org');
+ expect(as[1].attrib.origin).toEqual('http://github.com');
+ });
+ describe('preferences', function() {
+ it('should not change default project preferences and copy over additional project preferences to platform-level config.xml', function() {
+ config.preference.add({name:'henrik',value:'sedin'});
+ project.update_from_config(config);
+
+ var native_config = new et.ElementTree(et.XML(fs.readFileSync(android_config, 'utf-8')));
+ var ps = native_config.findall('preference');
+ expect(ps.length).toEqual(7);
+ expect(ps[0].attrib.name).toEqual('useBrowserHistory');
+ expect(ps[0].attrib.value).toEqual('true');
+ expect(ps[6].attrib.name).toEqual('henrik');
+ expect(ps[6].attrib.value).toEqual('sedin');
+ });
+ it('should override a default project preference if applicable', function() {
+ config.preference.add({name:'useBrowserHistory',value:'false'});
+ project.update_from_config(config);
+
+ var native_config = new et.ElementTree(et.XML(fs.readFileSync(android_config, 'utf-8')));
+ var ps = native_config.findall('preference');
+ expect(ps.length).toEqual(6);
+ expect(ps[0].attrib.name).toEqual('useBrowserHistory');
+ expect(ps[0].attrib.value).toEqual('false');
+ });
+ });
+ });
+
+ describe('cross-platform project level methods', function() {
+ var parser, config;
+ var android_strings = path.join(android_project_path, 'res', 'values', 'strings.xml');
+ var android_manifest = path.join(android_project_path, 'AndroidManifest.xml');
+ var android_config = path.join(android_project_path, 'res', 'xml', 'config.xml');
+
+ var original_strings = fs.readFileSync(android_strings, 'utf-8');
+ var original_manifest = fs.readFileSync(android_manifest, 'utf-8');
+ var original_android_config = fs.readFileSync(android_config, 'utf-8');
+
+ beforeEach(function() {
+ parser = new android_parser(android_project_path);
+ config = new config_parser(www_config);
+ });
+ afterEach(function() {
+ fs.writeFileSync(android_strings, original_strings, 'utf-8');
+ fs.writeFileSync(android_manifest, original_manifest, 'utf-8');
+ fs.writeFileSync(www_config, original_www_config, 'utf-8');
+ fs.writeFileSync(android_config, original_android_config, 'utf-8');
+ });
+ describe('update_www method', function() {
+ it('should update all www assets', function() {
+ var newFile = path.join(project_path, 'www', 'somescript.js');
+ this.after(function() {
+ shell.rm('-f', newFile);
+ });
+ fs.writeFileSync(newFile, 'alert("sup");', 'utf-8');
+ parser.update_www();
+ expect(fs.existsSync(path.join(android_project_path, 'assets', 'www', 'somescript.js'))).toBe(true);
+ });
+ it('should write out android js to cordova.js', function() {
+ parser.update_www();
+ expect(fs.readFileSync(path.join(android_project_path, 'assets', 'www', 'cordova.js'),'utf-8')).toBe(fs.readFileSync(path.join(util.libDirectory, 'cordova-android', 'framework', 'assets', 'js', 'cordova.android.js'), 'utf-8'));
+ });
+ });
+
+ describe('update_overrides method',function() {
+ var mergesPath = path.join(project_path, 'merges', 'android');
+ var newFile = path.join(mergesPath, 'merge.js');
+ beforeEach(function() {
+ shell.mkdir('-p', mergesPath);
+ fs.writeFileSync(newFile, 'alert("sup");', 'utf-8');
+ });
+ afterEach(function() {
+ shell.rm('-rf', mergesPath);
+ });
+ it('should copy a new file from merges into www', function() {
+ parser.update_overrides();
+ expect(fs.existsSync(path.join(android_project_path, 'assets', 'www', 'merge.js'))).toBe(true);
+ });
+
+ it('should copy a file from merges over a file in www', function() {
+ var newFileWWW = path.join(project_path, 'www','merge.js');
+ fs.writeFileSync(newFileWWW, 'var foo=1;', 'utf-8');
+ this.after(function() {
+ shell.rm('-rf', newFileWWW);
+ });
+ parser.update_overrides();
+ expect(fs.existsSync(path.join(android_project_path, 'assets', 'www', 'merge.js'))).toBe(true);
+ expect(fs.readFileSync(path.join(android_project_path, 'assets', 'www', 'merge.js'),'utf-8')).toEqual('alert("sup");');
+ });
+ });
+
+ describe('update_project method', function() {
+ it('should invoke update_www', function() {
+ var spyWww = spyOn(parser, 'update_www');
+ parser.update_project(config);
+ expect(spyWww).toHaveBeenCalled();
+ });
+ it('should invoke update_from_config', function() {
+ var spyConfig = spyOn(parser, 'update_from_config');
+ parser.update_project(config);
+ expect(spyConfig).toHaveBeenCalled();
+ });
+ it('should call out to util.deleteSvnFolders', function() {
+ var spy = spyOn(util, 'deleteSvnFolders');
+ parser.update_project(config);
+ expect(spy).toHaveBeenCalled();
+ });
+ });
+ });
+});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/platform-script/blackberry/blackberry_parser.spec.js
----------------------------------------------------------------------
diff --git a/spec/platform-script/blackberry/blackberry_parser.spec.js b/spec/platform-script/blackberry/blackberry_parser.spec.js
new file mode 100644
index 0000000..12d5294
--- /dev/null
+++ b/spec/platform-script/blackberry/blackberry_parser.spec.js
@@ -0,0 +1,249 @@
+
+/**
+ 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.
+*/
+var blackberry_parser = require('../../src/metadata/blackberry_parser'),
+ config_parser = require('../../src/config_parser'),
+ path = require('path'),
+ util = require('../../src/util'),
+ et = require('elementtree'),
+ shell = require('shelljs'),
+ cordova = require('../../cordova'),
+ fs = require('fs'),
+ projects_path = path.join(__dirname, '..', 'fixtures', 'projects'),
+ blackberry_path = path.join(projects_path, 'native', 'blackberry_fixture'),
+ project_path = path.join(projects_path, 'cordova'),
+ blackberry_project_path = path.join(project_path, 'platforms', 'blackberry');
+
+var www_config = path.join(project_path, 'www', 'config.xml');
+var original_www_config = fs.readFileSync(www_config, 'utf-8');
+
+describe('blackberry project parser', function() {
+ beforeEach(function() {
+ spyOn(process.stdout, 'write'); // silence console output
+ });
+
+ it('should throw an exception with a path that is not a native blackberry project', function() {
+ expect(function() {
+ var project = new blackberry_parser(process.cwd());
+ }).toThrow();
+ });
+ it('should accept a proper native blackberry project path as construction parameter', function() {
+ var project;
+ expect(function() {
+ project = new blackberry_parser(blackberry_path);
+ }).not.toThrow();
+ expect(project).toBeDefined();
+ });
+
+ describe('update_from_config method', function() {
+ var project, config;
+
+ var blackberry_config = path.join(blackberry_path, 'www', 'config.xml');
+ var original_blackberry_config = fs.readFileSync(blackberry_config, 'utf-8');
+
+ beforeEach(function() {
+ project = new blackberry_parser(blackberry_path);
+ config = new config_parser(www_config);
+ });
+ afterEach(function() {
+ fs.writeFileSync(blackberry_config, original_blackberry_config, 'utf-8');
+ fs.writeFileSync(www_config, original_www_config, 'utf-8');
+ });
+ it('should throw an exception if a non config_parser object is passed into it', function() {
+ expect(function() {
+ project.update_from_config({});
+ }).toThrow();
+ });
+ it('should update the application name properly', function() {
+ config.name('bond. james bond.');
+ project.update_from_config(config);
+
+ var bb_cfg = new config_parser(blackberry_config);
+
+ expect(bb_cfg.name()).toBe('bond. james bond.');
+ });
+ it('should update the application package name properly', function() {
+ config.packageName('sofa.king.awesome');
+ project.update_from_config(config);
+
+ var bb_cfg = new config_parser(blackberry_config);
+ expect(bb_cfg.packageName()).toBe('sofa.king.awesome');
+ });
+ describe('whitelist', function() {
+ it('should update the whitelist when using access elements with origin attribute', function() {
+ config.access.remove('*');
+ config.access.add('http://blackberry.com');
+ config.access.add('http://rim.com');
+ project.update_from_config(config);
+
+ var bb_cfg = new et.ElementTree(et.XML(fs.readFileSync(blackberry_config, 'utf-8')));
+ var as = bb_cfg.getroot().findall('access');
+ expect(as.length).toEqual(2);
+ expect(as[0].attrib.uri).toEqual('http://blackberry.com');
+ expect(as[1].attrib.uri).toEqual('http://rim.com');
+ });
+ it('should update the whitelist when using access elements with uri attributes', function() {
+ fs.writeFileSync(www_config, fs.readFileSync(www_config, 'utf-8').replace(/origin="\*/,'uri="http://rim.com'), 'utf-8');
+ config = new config_parser(www_config);
+ project.update_from_config(config);
+
+ var bb_cfg = new et.ElementTree(et.XML(fs.readFileSync(blackberry_config, 'utf-8')));
+ var as = bb_cfg.getroot().findall('access');
+ expect(as.length).toEqual(1);
+ expect(as[0].attrib.uri).toEqual('http://rim.com');
+ });
+ });
+ });
+
+ describe('cross-platform project level methods', function() {
+ var parser, config;
+
+ var blackberry_config = path.join(blackberry_project_path, 'www', 'config.xml');
+ var original_blackberry_config = fs.readFileSync(blackberry_config, 'utf-8');
+
+ beforeEach(function() {
+ parser = new blackberry_parser(blackberry_project_path);
+ config = new config_parser(www_config);
+ });
+ afterEach(function() {
+ fs.writeFileSync(blackberry_config, original_blackberry_config, 'utf-8');
+ fs.writeFileSync(www_config, original_www_config, 'utf-8');
+ });
+
+ describe('update_www method', function() {
+ it('should update all www assets', function() {
+ var newFile = path.join(project_path, 'www', 'somescript.js');
+ this.after(function() {
+ shell.rm('-f', newFile);
+ });
+ fs.writeFileSync(newFile, 'alert("sup");', 'utf-8');
+ parser.update_www();
+ expect(fs.existsSync(path.join(blackberry_project_path, 'www', 'somescript.js'))).toBe(true);
+ });
+ it('should not overwrite the blackberry-specific config.xml', function() {
+ var www_cfg = fs.readFileSync(path.join(project_path, 'www', 'config.xml'), 'utf-8');
+ parser.update_www();
+ var bb_cfg = fs.readFileSync(blackberry_config, 'utf-8');
+ expect(bb_cfg).not.toBe(www_cfg);
+ });
+ });
+
+ describe('update_overrides method',function() {
+ var mergesPath = path.join(project_path, 'merges', 'blackberry');
+ var newFile = path.join(mergesPath, 'merge.js');
+ beforeEach(function() {
+ shell.mkdir('-p', mergesPath);
+ fs.writeFileSync(newFile, 'alert("sup");', 'utf-8');
+ });
+ afterEach(function() {
+ shell.rm('-rf', mergesPath);
+ });
+
+ it('should copy a new file from merges into www', function() {
+ parser.update_overrides();
+ expect(fs.existsSync(path.join(blackberry_project_path, 'www', 'merge.js'))).toBe(true);
+ });
+
+ it('should copy a file from merges over a file in www', function() {
+ var newFileWWW = path.join(project_path, 'www','merge.js');
+ fs.writeFileSync(newFileWWW, 'var foo=1;', 'utf-8');
+ this.after(function() {
+ shell.rm('-rf', newFileWWW);
+ });
+ parser.update_overrides();
+ expect(fs.existsSync(path.join(blackberry_project_path, 'www', 'merge.js'))).toBe(true);
+ expect(fs.readFileSync(path.join(blackberry_project_path, 'www', 'merge.js'),'utf-8')).toEqual('alert("sup");');
+ });
+ });
+
+ describe('update_project method', function() {
+ var cordova_config_path = path.join(project_path, '.cordova', 'config.json');
+ var original_config_json = fs.readFileSync(cordova_config_path, 'utf-8');
+
+ describe('with stubbed out config for BlackBerry SDKs', function() {
+ beforeEach(function() {
+ fs.writeFileSync(cordova_config_path, JSON.stringify({
+ blackberry:{
+ qnx:{
+ }
+ }
+ }), 'utf-8');
+ });
+ afterEach(function() {
+ fs.writeFileSync(cordova_config_path, original_config_json, 'utf-8');
+ });
+ it('should invoke update_www', function() {
+ var spyWww = spyOn(parser, 'update_www');
+ parser.update_project(config);
+ expect(spyWww).toHaveBeenCalled();
+ });
+ it('should invoke update_from_config', function() {
+ var spyConfig = spyOn(parser, 'update_from_config');
+ parser.update_project(config);
+ expect(spyConfig).toHaveBeenCalled();
+ });
+ it('should not invoke get_blackberry_environment', function() {
+ var spyEnv = spyOn(parser, 'get_blackberry_environment');
+ parser.update_project(config);
+ expect(spyEnv).not.toHaveBeenCalled();
+ });
+ it('should write out project properties', function(done) {
+ var spyProps = spyOn(parser, 'write_project_properties');
+ parser.update_project(config, function() {
+ expect(spyProps).toHaveBeenCalled();
+ done();
+ });
+ });
+ it('should call out to util.deleteSvnFolders', function(done) {
+ var spy = spyOn(util, 'deleteSvnFolders');
+ parser.update_project(config, function() {
+ expect(spy).toHaveBeenCalled();
+ done();
+ });
+ });
+ });
+ describe('with empty BlackBerry SDKs in config', function() {
+ afterEach(function() {
+ fs.writeFileSync(cordova_config_path, original_config_json, 'utf-8');
+ });
+ it('should invoke get_blackberry_environment', function() {
+ var spyEnv = spyOn(parser, 'get_blackberry_environment');
+ var promptSpy = spyOn(require('prompt'), 'get');
+ parser.update_project(config);
+ expect(spyEnv).toHaveBeenCalled();
+ });
+ it('should write out project properties', function(done) {
+ var spyProps = spyOn(parser, 'write_project_properties');
+ var promptSpy = spyOn(require('prompt'), 'get');
+ parser.update_project(config, function() {
+ expect(spyProps).toHaveBeenCalled();
+ done();
+ });
+ promptSpy.mostRecentCall.args[1](null, {});
+ });
+ });
+ });
+ });
+
+ describe('write_project_properties method', function() {
+ });
+
+ describe('get_blackberry_environment method', function() {
+ });
+});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b50b5284/spec/platform-script/ios/ios_parser.spec.js
----------------------------------------------------------------------
diff --git a/spec/platform-script/ios/ios_parser.spec.js b/spec/platform-script/ios/ios_parser.spec.js
new file mode 100644
index 0000000..dbd4816
--- /dev/null
+++ b/spec/platform-script/ios/ios_parser.spec.js
@@ -0,0 +1,218 @@
+/**
+ 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.
+ */
+
+var ios_parser = require('../../src/metadata/ios_parser'),
+ config_parser = require('../../src/config_parser'),
+ cordova = require('../../cordova'),
+ util = require('../../src/util'),
+ path = require('path'),
+ shell = require('shelljs'),
+ fs = require('fs'),
+ et = require('elementtree'),
+ projects_path = path.join(__dirname, '..', 'fixtures', 'projects')
+ios_path = path.join(projects_path, 'native', 'ios_fixture'),
+ project_path = path.join(projects_path, 'cordova'),
+ ios_project_path = path.join(project_path, 'platforms', 'ios');
+
+var www_config = path.join(project_path, 'www', 'config.xml');
+var original_www_config = fs.readFileSync(www_config, 'utf-8');
+
+describe('ios project parser', function () {
+ it('should throw an exception with a path that is not a native ios project', function () {
+ expect(function () {
+ var project = new ios_parser(process.cwd());
+ }).toThrow();
+ });
+ it('should accept a proper native ios project path as construction parameter', function () {
+ var project;
+ expect(function () {
+ project = new ios_parser(ios_path);
+ }).not.toThrow();
+ expect(project).toBeDefined();
+ });
+
+ describe('update_from_config method', function () {
+ var project, config;
+
+ var ios_plist = path.join(ios_path, 'cordovaExample', 'cordovaExample-Info.plist'),
+ ios_pbx = path.join(ios_path, 'cordovaExample.xcodeproj', 'project.pbxproj'),
+ ios_config_xml = path.join(ios_path, 'cordovaExample', 'config.xml');
+
+ var original_pbx = fs.readFileSync(ios_pbx, 'utf-8');
+ var original_plist = fs.readFileSync(ios_plist, 'utf-8');
+ var original_ios_config = fs.readFileSync(ios_config_xml, 'utf-8');
+
+ beforeEach(function () {
+ project = new ios_parser(ios_path);
+ config = new config_parser(www_config);
+ });
+ afterEach(function () {
+ fs.writeFileSync(ios_pbx, original_pbx, 'utf-8');
+ fs.writeFileSync(ios_config_xml, original_ios_config, 'utf-8');
+ fs.writeFileSync(ios_plist, original_plist, 'utf-8');
+ fs.writeFileSync(www_config, original_www_config, 'utf-8');
+ });
+ it('should throw an exception if a non config_parser object is passed into it', function () {
+ expect(function () {
+ project.update_from_config({});
+ }).toThrow();
+ });
+ it('should update the application name properly', function (done) {
+ config.name('bond. james bond.');
+ project.update_from_config(config, function () {
+ var pbx_contents = fs.readFileSync(ios_pbx, 'utf-8');
+ expect(pbx_contents.match(/PRODUCT_NAME\s*=\s*"bond. james bond."/)[0]).toBe('PRODUCT_NAME = "bond. james bond."');
+ done();
+ });
+ });
+ it('should update the application package name (bundle identifier) properly', function (done) {
+ config.packageName('ca.filmaj.dewd');
+ project.update_from_config(config, function () {
+ var plist_contents = fs.readFileSync(ios_plist, 'utf-8');
+ expect(plist_contents).toMatch(/<string>ca.filmaj.dewd/);
+ done();
+ });
+ });
+ it('should update the whitelist in the project config.xml', function (done) {
+ project.update_from_config(config, function () {
+ var config_contents = fs.readFileSync(ios_config_xml, 'utf-8');
+ expect(config_contents).toMatch(/<access origin="\*" \/>/);
+ done();
+ });
+ });
+ describe('preferences', function () {
+ it('should not change default project preferences and copy over additional project preferences to platform-level config.xml', function (done) {
+ config.preference.add({name:'henrik', value:'sedin'});
+ project.update_from_config(config, function () {
+ var native_config = new et.ElementTree(et.XML(fs.readFileSync(ios_config_xml, 'utf-8')));
+ var ps = native_config.findall('preference');
+ expect(ps.length).toEqual(17);
+ expect(ps[0].attrib.name).toEqual('KeyboardDisplayRequiresUserAction');
+ expect(ps[0].attrib.value).toEqual('true');
+ expect(ps[16].attrib.name).toEqual('henrik');
+ expect(ps[16].attrib.value).toEqual('sedin');
+ done();
+ });
+ });
+ it('should override a default project preference if applicable', function (done) {
+ config.preference.add({name:'UIWebViewBounce', value:'false'});
+ project.update_from_config(config, function () {
+ var native_config = new et.ElementTree(et.XML(fs.readFileSync(ios_config_xml, 'utf-8')));
+ var ps = native_config.findall('preference');
+ expect(ps.length).toEqual(16);
+ expect(ps[2].attrib.name).toEqual('UIWebViewBounce');
+ expect(ps[2].attrib.value).toEqual('false');
+ done();
+ });
+ });
+ });
+ });
+
+ describe('cross-platform project level methods', function () {
+ var parser, config;
+ var ios_plist = path.join(ios_project_path, 'cordovaExample', 'cordovaExample-Info.plist'),
+ ios_pbx = path.join(ios_project_path, 'cordovaExample.xcodeproj', 'project.pbxproj'),
+ ios_config_xml = path.join(ios_project_path, 'cordovaExample', 'config.xml');
+
+ var original_pbx = fs.readFileSync(ios_pbx, 'utf-8');
+ var original_plist = fs.readFileSync(ios_plist, 'utf-8');
+ var original_ios_config = fs.readFileSync(ios_config_xml, 'utf-8');
+
+ beforeEach(function () {
+ parser = new ios_parser(ios_project_path);
+ config = new config_parser(www_config);
+ });
+ afterEach(function () {
+ fs.writeFileSync(ios_pbx, original_pbx, 'utf-8');
+ fs.writeFileSync(ios_config_xml, original_ios_config, 'utf-8');
+ fs.writeFileSync(ios_plist, original_plist, 'utf-8');
+ fs.writeFileSync(www_config, original_www_config, 'utf-8');
+ });
+
+ describe('update_www method', function () {
+ it('should update all www assets', function () {
+ var newFile = path.join(project_path, 'www', 'somescript.js');
+ this.after(function () {
+ shell.rm('-f', newFile);
+ });
+ fs.writeFileSync(newFile, 'alert("sup");', 'utf-8');
+ parser.update_www();
+ expect(fs.existsSync(path.join(ios_project_path, 'www', 'somescript.js'))).toBe(true);
+ });
+ it('should write out ios js to cordova.js', function () {
+ parser.update_www();
+ expect(fs.readFileSync(path.join(ios_project_path, 'www', 'cordova.js'), 'utf-8')).toBe(fs.readFileSync(path.join(util.libDirectory, 'cordova-ios', 'CordovaLib', 'cordova.ios.js'), 'utf-8'));
+ });
+ });
+
+ describe('update_overrides method', function () {
+ var mergesPath = path.join(project_path, 'merges', 'ios');
+ var newFile = path.join(mergesPath, 'merge.js');
+ beforeEach(function() {
+ shell.mkdir('-p', mergesPath);
+ fs.writeFileSync(newFile, 'alert("sup");', 'utf-8');
+ });
+ afterEach(function() {
+ shell.rm('-rf', mergesPath);
+ });
+
+ it('should copy a new file from merges into www', function () {
+ parser.update_overrides();
+ expect(fs.existsSync(path.join(ios_project_path, 'www', 'merge.js'))).toBe(true);
+ });
+
+ it('should copy a file from merges over a file in www', function () {
+ var newFileWWW = path.join(project_path, 'www', 'merge.js');
+ fs.writeFileSync(newFileWWW, 'var foo=1;', 'utf-8');
+ this.after(function () {
+ shell.rm('-rf', newFileWWW);
+ });
+
+ parser.update_overrides();
+ expect(fs.existsSync(path.join(ios_project_path, 'www', 'merge.js'))).toBe(true);
+ expect(fs.readFileSync(path.join(ios_project_path, 'www', 'merge.js'), 'utf-8')).toEqual('alert("sup");');
+ });
+ });
+
+ describe('update_project method', function () {
+ it('should invoke update_www', function (done) {
+ var spyWww = spyOn(parser, 'update_www');
+ parser.update_project(config, function () {
+ expect(spyWww).toHaveBeenCalled();
+ done();
+ });
+ });
+ it('should invoke update_from_config', function (done) {
+ var spyConfig = spyOn(parser, 'update_from_config').andCallThrough();
+ parser.update_project(config, function () {
+ expect(spyConfig).toHaveBeenCalled();
+ done();
+ });
+ });
+ it('should call out to util.deleteSvnFolders', function(done) {
+ var spy = spyOn(util, 'deleteSvnFolders');
+ var spyConfig = spyOn(parser, 'update_from_config').andCallThrough();
+ parser.update_project(config, function () {
+ expect(spy).toHaveBeenCalled();
+ done();
+ });
+ });
+ });
+ });
+});
[22/37] Add WP7 and WP8 platform files.
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/www/cordova-2.7.0.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/www/cordova-2.7.0.js b/lib/cordova-wp7/templates/standalone/www/cordova-2.7.0.js
new file mode 100644
index 0000000..f930212
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/www/cordova-2.7.0.js
@@ -0,0 +1,6700 @@
+// Platform: windowsphone
+
+// commit cd29cf0f224ccf25e9d422a33fd02ef67d3a78f4
+
+// File generated at :: Thu Apr 25 2013 15:58:48 GMT-0700 (Pacific Daylight Time)
+
+/*
+ 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.
+*/
+
+;(function() {
+
+// file: lib\scripts\require.js
+
+var require,
+ define;
+
+(function () {
+ var modules = {};
+ // Stack of moduleIds currently being built.
+ var requireStack = [];
+ // Map of module ID -> index into requireStack of modules currently being built.
+ var inProgressModules = {};
+
+ function build(module) {
+ var factory = module.factory;
+ module.exports = {};
+ delete module.factory;
+ factory(require, module.exports, module);
+ return module.exports;
+ }
+
+ require = function (id) {
+ if (!modules[id]) {
+ throw "module " + id + " not found";
+ } else if (id in inProgressModules) {
+ var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id;
+ throw "Cycle in require graph: " + cycle;
+ }
+ if (modules[id].factory) {
+ try {
+ inProgressModules[id] = requireStack.length;
+ requireStack.push(id);
+ return build(modules[id]);
+ } finally {
+ delete inProgressModules[id];
+ requireStack.pop();
+ }
+ }
+ return modules[id].exports;
+ };
+
+ define = function (id, factory) {
+ if (modules[id]) {
+ throw "module " + id + " already defined";
+ }
+
+ modules[id] = {
+ id: id,
+ factory: factory
+ };
+ };
+
+ define.remove = function (id) {
+ delete modules[id];
+ };
+
+ define.moduleMap = modules;
+})();
+
+//Export for use in node
+if (typeof module === "object" && typeof require === "function") {
+ module.exports.require = require;
+ module.exports.define = define;
+}
+
+// file: lib/cordova.js
+define("cordova", function(require, exports, module) {
+
+
+var channel = require('cordova/channel');
+
+/**
+ * Listen for DOMContentLoaded and notify our channel subscribers.
+ */
+document.addEventListener('DOMContentLoaded', function() {
+ channel.onDOMContentLoaded.fire();
+}, false);
+if (document.readyState == 'complete' || document.readyState == 'interactive') {
+ channel.onDOMContentLoaded.fire();
+}
+
+/**
+ * Intercept calls to addEventListener + removeEventListener and handle deviceready,
+ * resume, and pause events.
+ */
+var m_document_addEventListener = document.addEventListener;
+var m_document_removeEventListener = document.removeEventListener;
+var m_window_addEventListener = window.addEventListener;
+var m_window_removeEventListener = window.removeEventListener;
+
+/**
+ * Houses custom event handlers to intercept on document + window event listeners.
+ */
+var documentEventHandlers = {},
+ windowEventHandlers = {};
+
+document.addEventListener = function(evt, handler, capture) {
+ var e = evt.toLowerCase();
+ if (typeof documentEventHandlers[e] != 'undefined') {
+ documentEventHandlers[e].subscribe(handler);
+ } else {
+ m_document_addEventListener.call(document, evt, handler, capture);
+ }
+};
+
+window.addEventListener = function(evt, handler, capture) {
+ var e = evt.toLowerCase();
+ if (typeof windowEventHandlers[e] != 'undefined') {
+ windowEventHandlers[e].subscribe(handler);
+ } else {
+ m_window_addEventListener.call(window, evt, handler, capture);
+ }
+};
+
+document.removeEventListener = function(evt, handler, capture) {
+ var e = evt.toLowerCase();
+ // If unsubscribing from an event that is handled by a plugin
+ if (typeof documentEventHandlers[e] != "undefined") {
+ documentEventHandlers[e].unsubscribe(handler);
+ } else {
+ m_document_removeEventListener.call(document, evt, handler, capture);
+ }
+};
+
+window.removeEventListener = function(evt, handler, capture) {
+ var e = evt.toLowerCase();
+ // If unsubscribing from an event that is handled by a plugin
+ if (typeof windowEventHandlers[e] != "undefined") {
+ windowEventHandlers[e].unsubscribe(handler);
+ } else {
+ m_window_removeEventListener.call(window, evt, handler, capture);
+ }
+};
+
+function createEvent(type, data) {
+ var event = document.createEvent('Events');
+ event.initEvent(type, false, false);
+ if (data) {
+ for (var i in data) {
+ if (data.hasOwnProperty(i)) {
+ event[i] = data[i];
+ }
+ }
+ }
+ return event;
+}
+
+if(typeof window.console === "undefined") {
+ window.console = {
+ log:function(){}
+ };
+}
+
+var cordova = {
+ define:define,
+ require:require,
+ /**
+ * Methods to add/remove your own addEventListener hijacking on document + window.
+ */
+ addWindowEventHandler:function(event) {
+ return (windowEventHandlers[event] = channel.create(event));
+ },
+ addStickyDocumentEventHandler:function(event) {
+ return (documentEventHandlers[event] = channel.createSticky(event));
+ },
+ addDocumentEventHandler:function(event) {
+ return (documentEventHandlers[event] = channel.create(event));
+ },
+ removeWindowEventHandler:function(event) {
+ delete windowEventHandlers[event];
+ },
+ removeDocumentEventHandler:function(event) {
+ delete documentEventHandlers[event];
+ },
+ /**
+ * Retrieve original event handlers that were replaced by Cordova
+ *
+ * @return object
+ */
+ getOriginalHandlers: function() {
+ return {'document': {'addEventListener': m_document_addEventListener, 'removeEventListener': m_document_removeEventListener},
+ 'window': {'addEventListener': m_window_addEventListener, 'removeEventListener': m_window_removeEventListener}};
+ },
+ /**
+ * Method to fire event from native code
+ * bNoDetach is required for events which cause an exception which needs to be caught in native code
+ */
+ fireDocumentEvent: function(type, data, bNoDetach) {
+ var evt = createEvent(type, data);
+ if (typeof documentEventHandlers[type] != 'undefined') {
+ if( bNoDetach ) {
+ documentEventHandlers[type].fire(evt);
+ }
+ else {
+ setTimeout(function() {
+ // Fire deviceready on listeners that were registered before cordova.js was loaded.
+ if (type == 'deviceready') {
+ document.dispatchEvent(evt);
+ }
+ documentEventHandlers[type].fire(evt);
+ }, 0);
+ }
+ } else {
+ document.dispatchEvent(evt);
+ }
+ },
+ fireWindowEvent: function(type, data) {
+ var evt = createEvent(type,data);
+ if (typeof windowEventHandlers[type] != 'undefined') {
+ setTimeout(function() {
+ windowEventHandlers[type].fire(evt);
+ }, 0);
+ } else {
+ window.dispatchEvent(evt);
+ }
+ },
+
+ /**
+ * Plugin callback mechanism.
+ */
+ // Randomize the starting callbackId to avoid collisions after refreshing or navigating.
+ // This way, it's very unlikely that any new callback would get the same callbackId as an old callback.
+ callbackId: Math.floor(Math.random() * 2000000000),
+ callbacks: {},
+ callbackStatus: {
+ NO_RESULT: 0,
+ OK: 1,
+ CLASS_NOT_FOUND_EXCEPTION: 2,
+ ILLEGAL_ACCESS_EXCEPTION: 3,
+ INSTANTIATION_EXCEPTION: 4,
+ MALFORMED_URL_EXCEPTION: 5,
+ IO_EXCEPTION: 6,
+ INVALID_ACTION: 7,
+ JSON_EXCEPTION: 8,
+ ERROR: 9
+ },
+
+ /**
+ * Called by native code when returning successful result from an action.
+ */
+ callbackSuccess: function(callbackId, args) {
+ try {
+ cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback);
+ } catch (e) {
+ console.log("Error in error callback: " + callbackId + " = "+e);
+ }
+ },
+
+ /**
+ * Called by native code when returning error result from an action.
+ */
+ callbackError: function(callbackId, args) {
+ // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative.
+ // Derive success from status.
+ try {
+ cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback);
+ } catch (e) {
+ console.log("Error in error callback: " + callbackId + " = "+e);
+ }
+ },
+
+ /**
+ * Called by native code when returning the result from an action.
+ */
+ callbackFromNative: function(callbackId, success, status, args, keepCallback) {
+ var callback = cordova.callbacks[callbackId];
+ if (callback) {
+ if (success && status == cordova.callbackStatus.OK) {
+ callback.success && callback.success.apply(null, args);
+ } else if (!success) {
+ callback.fail && callback.fail.apply(null, args);
+ }
+
+ // Clear callback if not expecting any more results
+ if (!keepCallback) {
+ delete cordova.callbacks[callbackId];
+ }
+ }
+ },
+ addConstructor: function(func) {
+ channel.onCordovaReady.subscribe(function() {
+ try {
+ func();
+ } catch(e) {
+ console.log("Failed to run constructor: " + e);
+ }
+ });
+ }
+};
+
+// Register pause, resume and deviceready channels as events on document.
+channel.onPause = cordova.addDocumentEventHandler('pause');
+channel.onResume = cordova.addDocumentEventHandler('resume');
+channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready');
+
+module.exports = cordova;
+
+});
+
+// file: lib\common\argscheck.js
+define("cordova/argscheck", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+var utils = require('cordova/utils');
+
+var moduleExports = module.exports;
+
+var typeMap = {
+ 'A': 'Array',
+ 'D': 'Date',
+ 'N': 'Number',
+ 'S': 'String',
+ 'F': 'Function',
+ 'O': 'Object'
+};
+
+function extractParamName(callee, argIndex) {
+ return (/.*?\((.*?)\)/).exec(callee)[1].split(', ')[argIndex];
+}
+
+function checkArgs(spec, functionName, args, opt_callee) {
+ if (!moduleExports.enableChecks) {
+ return;
+ }
+ var errMsg = null;
+ var typeName;
+ for (var i = 0; i < spec.length; ++i) {
+ var c = spec.charAt(i),
+ cUpper = c.toUpperCase(),
+ arg = args[i];
+ // Asterix means allow anything.
+ if (c == '*') {
+ continue;
+ }
+ typeName = utils.typeName(arg);
+ if ((arg === null || arg === undefined) && c == cUpper) {
+ continue;
+ }
+ if (typeName != typeMap[cUpper]) {
+ errMsg = 'Expected ' + typeMap[cUpper];
+ break;
+ }
+ }
+ if (errMsg) {
+ errMsg += ', but got ' + typeName + '.';
+ errMsg = 'Wrong type for parameter "' + extractParamName(opt_callee || args.callee, i) + '" of ' + functionName + ': ' + errMsg;
+ // Don't log when running jake test.
+ if (typeof jasmine == 'undefined') {
+ console.error(errMsg);
+ }
+ throw TypeError(errMsg);
+ }
+}
+
+function getValue(value, defaultValue) {
+ return value === undefined ? defaultValue : value;
+}
+
+moduleExports.checkArgs = checkArgs;
+moduleExports.getValue = getValue;
+moduleExports.enableChecks = true;
+
+
+});
+
+// file: lib\common\builder.js
+define("cordova/builder", function(require, exports, module) {
+
+var utils = require('cordova/utils');
+
+function each(objects, func, context) {
+ for (var prop in objects) {
+ if (objects.hasOwnProperty(prop)) {
+ func.apply(context, [objects[prop], prop]);
+ }
+ }
+}
+
+function clobber(obj, key, value) {
+ exports.replaceHookForTesting(obj, key);
+ obj[key] = value;
+ // Getters can only be overridden by getters.
+ if (obj[key] !== value) {
+ utils.defineGetter(obj, key, function() {
+ return value;
+ });
+ }
+}
+
+function assignOrWrapInDeprecateGetter(obj, key, value, message) {
+ if (message) {
+ utils.defineGetter(obj, key, function() {
+ console.log(message);
+ delete obj[key];
+ clobber(obj, key, value);
+ return value;
+ });
+ } else {
+ clobber(obj, key, value);
+ }
+}
+
+function include(parent, objects, clobber, merge) {
+ each(objects, function (obj, key) {
+ try {
+ var result = obj.path ? require(obj.path) : {};
+
+ if (clobber) {
+ // Clobber if it doesn't exist.
+ if (typeof parent[key] === 'undefined') {
+ assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+ } else if (typeof obj.path !== 'undefined') {
+ // If merging, merge properties onto parent, otherwise, clobber.
+ if (merge) {
+ recursiveMerge(parent[key], result);
+ } else {
+ assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+ }
+ }
+ result = parent[key];
+ } else {
+ // Overwrite if not currently defined.
+ if (typeof parent[key] == 'undefined') {
+ assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+ } else {
+ // Set result to what already exists, so we can build children into it if they exist.
+ result = parent[key];
+ }
+ }
+
+ if (obj.children) {
+ include(result, obj.children, clobber, merge);
+ }
+ } catch(e) {
+ utils.alert('Exception building cordova JS globals: ' + e + ' for key "' + key + '"');
+ }
+ });
+}
+
+/**
+ * Merge properties from one object onto another recursively. Properties from
+ * the src object will overwrite existing target property.
+ *
+ * @param target Object to merge properties into.
+ * @param src Object to merge properties from.
+ */
+function recursiveMerge(target, src) {
+ for (var prop in src) {
+ if (src.hasOwnProperty(prop)) {
+ if (target.prototype && target.prototype.constructor === target) {
+ // If the target object is a constructor override off prototype.
+ clobber(target.prototype, prop, src[prop]);
+ } else {
+ if (typeof src[prop] === 'object' && typeof target[prop] === 'object') {
+ recursiveMerge(target[prop], src[prop]);
+ } else {
+ clobber(target, prop, src[prop]);
+ }
+ }
+ }
+ }
+}
+
+exports.buildIntoButDoNotClobber = function(objects, target) {
+ include(target, objects, false, false);
+};
+exports.buildIntoAndClobber = function(objects, target) {
+ include(target, objects, true, false);
+};
+exports.buildIntoAndMerge = function(objects, target) {
+ include(target, objects, true, true);
+};
+exports.recursiveMerge = recursiveMerge;
+exports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter;
+exports.replaceHookForTesting = function() {};
+
+});
+
+// file: lib\common\channel.js
+define("cordova/channel", function(require, exports, module) {
+
+var utils = require('cordova/utils'),
+ nextGuid = 1;
+
+/**
+ * Custom pub-sub "channel" that can have functions subscribed to it
+ * This object is used to define and control firing of events for
+ * cordova initialization, as well as for custom events thereafter.
+ *
+ * The order of events during page load and Cordova startup is as follows:
+ *
+ * onDOMContentLoaded* Internal event that is received when the web page is loaded and parsed.
+ * onNativeReady* Internal event that indicates the Cordova native side is ready.
+ * onCordovaReady* Internal event fired when all Cordova JavaScript objects have been created.
+ * onCordovaInfoReady* Internal event fired when device properties are available.
+ * onCordovaConnectionReady* Internal event fired when the connection property has been set.
+ * onDeviceReady* User event fired to indicate that Cordova is ready
+ * onResume User event fired to indicate a start/resume lifecycle event
+ * onPause User event fired to indicate a pause lifecycle event
+ * onDestroy* Internal event fired when app is being destroyed (User should use window.onunload event, not this one).
+ *
+ * The events marked with an * are sticky. Once they have fired, they will stay in the fired state.
+ * All listeners that subscribe after the event is fired will be executed right away.
+ *
+ * The only Cordova events that user code should register for are:
+ * deviceready Cordova native code is initialized and Cordova APIs can be called from JavaScript
+ * pause App has moved to background
+ * resume App has returned to foreground
+ *
+ * Listeners can be registered as:
+ * document.addEventListener("deviceready", myDeviceReadyListener, false);
+ * document.addEventListener("resume", myResumeListener, false);
+ * document.addEventListener("pause", myPauseListener, false);
+ *
+ * The DOM lifecycle events should be used for saving and restoring state
+ * window.onload
+ * window.onunload
+ *
+ */
+
+/**
+ * Channel
+ * @constructor
+ * @param type String the channel name
+ */
+var Channel = function(type, sticky) {
+ this.type = type;
+ // Map of guid -> function.
+ this.handlers = {};
+ // 0 = Non-sticky, 1 = Sticky non-fired, 2 = Sticky fired.
+ this.state = sticky ? 1 : 0;
+ // Used in sticky mode to remember args passed to fire().
+ this.fireArgs = null;
+ // Used by onHasSubscribersChange to know if there are any listeners.
+ this.numHandlers = 0;
+ // Function that is called when the first listener is subscribed, or when
+ // the last listener is unsubscribed.
+ this.onHasSubscribersChange = null;
+},
+ channel = {
+ /**
+ * Calls the provided function only after all of the channels specified
+ * have been fired. All channels must be sticky channels.
+ */
+ join: function(h, c) {
+ var len = c.length,
+ i = len,
+ f = function() {
+ if (!(--i)) h();
+ };
+ for (var j=0; j<len; j++) {
+ if (c[j].state === 0) {
+ throw Error('Can only use join with sticky channels.');
+ }
+ c[j].subscribe(f);
+ }
+ if (!len) h();
+ },
+ create: function(type) {
+ return channel[type] = new Channel(type, false);
+ },
+ createSticky: function(type) {
+ return channel[type] = new Channel(type, true);
+ },
+
+ /**
+ * cordova Channels that must fire before "deviceready" is fired.
+ */
+ deviceReadyChannelsArray: [],
+ deviceReadyChannelsMap: {},
+
+ /**
+ * Indicate that a feature needs to be initialized before it is ready to be used.
+ * This holds up Cordova's "deviceready" event until the feature has been initialized
+ * and Cordova.initComplete(feature) is called.
+ *
+ * @param feature {String} The unique feature name
+ */
+ waitForInitialization: function(feature) {
+ if (feature) {
+ var c = channel[feature] || this.createSticky(feature);
+ this.deviceReadyChannelsMap[feature] = c;
+ this.deviceReadyChannelsArray.push(c);
+ }
+ },
+
+ /**
+ * Indicate that initialization code has completed and the feature is ready to be used.
+ *
+ * @param feature {String} The unique feature name
+ */
+ initializationComplete: function(feature) {
+ var c = this.deviceReadyChannelsMap[feature];
+ if (c) {
+ c.fire();
+ }
+ }
+ };
+
+function forceFunction(f) {
+ if (typeof f != 'function') throw "Function required as first argument!";
+}
+
+/**
+ * Subscribes the given function to the channel. Any time that
+ * Channel.fire is called so too will the function.
+ * Optionally specify an execution context for the function
+ * and a guid that can be used to stop subscribing to the channel.
+ * Returns the guid.
+ */
+Channel.prototype.subscribe = function(f, c) {
+ // need a function to call
+ forceFunction(f);
+ if (this.state == 2) {
+ f.apply(c || this, this.fireArgs);
+ return;
+ }
+
+ var func = f,
+ guid = f.observer_guid;
+ if (typeof c == "object") { func = utils.close(c, f); }
+
+ if (!guid) {
+ // first time any channel has seen this subscriber
+ guid = '' + nextGuid++;
+ }
+ func.observer_guid = guid;
+ f.observer_guid = guid;
+
+ // Don't add the same handler more than once.
+ if (!this.handlers[guid]) {
+ this.handlers[guid] = func;
+ this.numHandlers++;
+ if (this.numHandlers == 1) {
+ this.onHasSubscribersChange && this.onHasSubscribersChange();
+ }
+ }
+};
+
+/**
+ * Unsubscribes the function with the given guid from the channel.
+ */
+Channel.prototype.unsubscribe = function(f) {
+ // need a function to unsubscribe
+ forceFunction(f);
+
+ var guid = f.observer_guid,
+ handler = this.handlers[guid];
+ if (handler) {
+ delete this.handlers[guid];
+ this.numHandlers--;
+ if (this.numHandlers === 0) {
+ this.onHasSubscribersChange && this.onHasSubscribersChange();
+ }
+ }
+};
+
+/**
+ * Calls all functions subscribed to this channel.
+ */
+Channel.prototype.fire = function(e) {
+ var fail = false,
+ fireArgs = Array.prototype.slice.call(arguments);
+ // Apply stickiness.
+ if (this.state == 1) {
+ this.state = 2;
+ this.fireArgs = fireArgs;
+ }
+ if (this.numHandlers) {
+ // Copy the values first so that it is safe to modify it from within
+ // callbacks.
+ var toCall = [];
+ for (var item in this.handlers) {
+ toCall.push(this.handlers[item]);
+ }
+ for (var i = 0; i < toCall.length; ++i) {
+ toCall[i].apply(this, fireArgs);
+ }
+ if (this.state == 2 && this.numHandlers) {
+ this.numHandlers = 0;
+ this.handlers = {};
+ this.onHasSubscribersChange && this.onHasSubscribersChange();
+ }
+ }
+};
+
+
+// defining them here so they are ready super fast!
+// DOM event that is received when the web page is loaded and parsed.
+channel.createSticky('onDOMContentLoaded');
+
+// Event to indicate the Cordova native side is ready.
+channel.createSticky('onNativeReady');
+
+// Event to indicate that all Cordova JavaScript objects have been created
+// and it's time to run plugin constructors.
+channel.createSticky('onCordovaReady');
+
+// Event to indicate that device properties are available
+channel.createSticky('onCordovaInfoReady');
+
+// Event to indicate that the connection property has been set.
+channel.createSticky('onCordovaConnectionReady');
+
+// Event to indicate that all automatically loaded JS plugins are loaded and ready.
+channel.createSticky('onPluginsReady');
+
+// Event to indicate that Cordova is ready
+channel.createSticky('onDeviceReady');
+
+// Event to indicate a resume lifecycle event
+channel.create('onResume');
+
+// Event to indicate a pause lifecycle event
+channel.create('onPause');
+
+// Event to indicate a destroy lifecycle event
+channel.createSticky('onDestroy');
+
+// Channels that must fire before "deviceready" is fired.
+channel.waitForInitialization('onCordovaReady');
+channel.waitForInitialization('onCordovaConnectionReady');
+channel.waitForInitialization('onDOMContentLoaded');
+
+module.exports = channel;
+
+});
+
+// file: lib\common\commandProxy.js
+define("cordova/commandProxy", function(require, exports, module) {
+
+
+// internal map of proxy function
+var CommandProxyMap = {};
+
+module.exports = {
+
+ // example: cordova.commandProxy.add("Accelerometer",{getCurrentAcceleration: function(successCallback, errorCallback, options) {...},...);
+ add:function(id,proxyObj) {
+ console.log("adding proxy for " + id);
+ CommandProxyMap[id] = proxyObj;
+ return proxyObj;
+ },
+
+ // cordova.commandProxy.remove("Accelerometer");
+ remove:function(id) {
+ var proxy = CommandProxyMap[id];
+ delete CommandProxyMap[id];
+ CommandProxyMap[id] = null;
+ return proxy;
+ },
+
+ get:function(service,action) {
+ return ( CommandProxyMap[service] ? CommandProxyMap[service][action] : null );
+ }
+};
+});
+
+// file: lib\windowsphone\exec.js
+define("cordova/exec", function(require, exports, module) {
+
+var cordova = require('cordova');
+
+/**
+ * Execute a cordova command. It is up to the native side whether this action
+ * is synchronous or asynchronous. The native side can return:
+ * Synchronous: PluginResult object as a JSON string
+ * Asynchronous: Empty string ""
+ * If async, the native side will cordova.callbackSuccess or cordova.callbackError,
+ * depending upon the result of the action.
+ *
+ * @param {Function} success The success callback
+ * @param {Function} fail The fail callback
+ * @param {String} service The name of the service to use
+ * @param {String} action Action to be run in cordova
+ * @param {String[]} [args] Zero or more arguments to pass to the method
+
+ */
+
+module.exports = function(success, fail, service, action, args) {
+
+ var callbackId = service + cordova.callbackId++;
+ if (typeof success == "function" || typeof fail == "function") {
+ cordova.callbacks[callbackId] = {success:success, fail:fail};
+ }
+ // generate a new command string, ex. DebugConsole/log/DebugConsole23/["wtf dude?"]
+ for(var n = 0; n < args.length; n++)
+ {
+ if(typeof args[n] !== "string")
+ {
+ args[n] = JSON.stringify(args[n]);
+ }
+ }
+ var command = service + "/" + action + "/" + callbackId + "/" + JSON.stringify(args);
+ // pass it on to Notify
+ try {
+ if(window.external) {
+ window.external.Notify(command);
+ }
+ else {
+ console.log("window.external not available :: command=" + command);
+ }
+ }
+ catch(e) {
+ console.log("Exception calling native with command :: " + command + " :: exception=" + e);
+ }
+};
+
+
+});
+
+// file: lib\common\modulemapper.js
+define("cordova/modulemapper", function(require, exports, module) {
+
+var builder = require('cordova/builder'),
+ moduleMap = define.moduleMap,
+ symbolList,
+ deprecationMap;
+
+exports.reset = function() {
+ symbolList = [];
+ deprecationMap = {};
+};
+
+function addEntry(strategy, moduleName, symbolPath, opt_deprecationMessage) {
+ if (!(moduleName in moduleMap)) {
+ throw new Error('Module ' + moduleName + ' does not exist.');
+ }
+ symbolList.push(strategy, moduleName, symbolPath);
+ if (opt_deprecationMessage) {
+ deprecationMap[symbolPath] = opt_deprecationMessage;
+ }
+}
+
+// Note: Android 2.3 does have Function.bind().
+exports.clobbers = function(moduleName, symbolPath, opt_deprecationMessage) {
+ addEntry('c', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+exports.merges = function(moduleName, symbolPath, opt_deprecationMessage) {
+ addEntry('m', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+exports.defaults = function(moduleName, symbolPath, opt_deprecationMessage) {
+ addEntry('d', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+function prepareNamespace(symbolPath, context) {
+ if (!symbolPath) {
+ return context;
+ }
+ var parts = symbolPath.split('.');
+ var cur = context;
+ for (var i = 0, part; part = parts[i]; ++i) {
+ cur = cur[part] = cur[part] || {};
+ }
+ return cur;
+}
+
+exports.mapModules = function(context) {
+ var origSymbols = {};
+ context.CDV_origSymbols = origSymbols;
+ for (var i = 0, len = symbolList.length; i < len; i += 3) {
+ var strategy = symbolList[i];
+ var moduleName = symbolList[i + 1];
+ var symbolPath = symbolList[i + 2];
+ var lastDot = symbolPath.lastIndexOf('.');
+ var namespace = symbolPath.substr(0, lastDot);
+ var lastName = symbolPath.substr(lastDot + 1);
+
+ var module = require(moduleName);
+ var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null;
+ var parentObj = prepareNamespace(namespace, context);
+ var target = parentObj[lastName];
+
+ if (strategy == 'm' && target) {
+ builder.recursiveMerge(target, module);
+ } else if ((strategy == 'd' && !target) || (strategy != 'd')) {
+ if (!(symbolPath in origSymbols)) {
+ origSymbols[symbolPath] = target;
+ }
+ builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg);
+ }
+ }
+};
+
+exports.getOriginalSymbol = function(context, symbolPath) {
+ var origSymbols = context.CDV_origSymbols;
+ if (origSymbols && (symbolPath in origSymbols)) {
+ return origSymbols[symbolPath];
+ }
+ var parts = symbolPath.split('.');
+ var obj = context;
+ for (var i = 0; i < parts.length; ++i) {
+ obj = obj && obj[parts[i]];
+ }
+ return obj;
+};
+
+exports.loadMatchingModules = function(matchingRegExp) {
+ for (var k in moduleMap) {
+ if (matchingRegExp.exec(k)) {
+ require(k);
+ }
+ }
+};
+
+exports.reset();
+
+
+});
+
+// file: lib\windowsphone\platform.js
+define("cordova/platform", function(require, exports, module) {
+
+var cordova = require('cordova'),
+ exec = require('cordova/exec');
+
+module.exports = {
+ id: "windowsphone",
+ initialize:function() {
+ var modulemapper = require('cordova/modulemapper');
+
+ modulemapper.loadMatchingModules(/cordova.*\/plugininit$/);
+
+ modulemapper.loadMatchingModules(/cordova.*\/symbols$/);
+
+ modulemapper.mapModules(window);
+
+ // Inject a listener for the backbutton, and tell native to override the flag (true/false) when we have 1 or more, or 0, listeners
+ var backButtonChannel = cordova.addDocumentEventHandler('backbutton');
+ backButtonChannel.onHasSubscribersChange = function() {
+ exec(null, null, "CoreEvents", "overridebackbutton", [this.numHandlers == 1]);
+ };
+ }
+};
+
+});
+
+// file: lib\common\plugin\Acceleration.js
+define("cordova/plugin/Acceleration", function(require, exports, module) {
+
+var Acceleration = function(x, y, z, timestamp) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.timestamp = timestamp || (new Date()).getTime();
+};
+
+module.exports = Acceleration;
+
+});
+
+// file: lib\common\plugin\Camera.js
+define("cordova/plugin/Camera", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ exec = require('cordova/exec'),
+ Camera = require('cordova/plugin/CameraConstants'),
+ CameraPopoverHandle = require('cordova/plugin/CameraPopoverHandle');
+
+var cameraExport = {};
+
+// Tack on the Camera Constants to the base camera plugin.
+for (var key in Camera) {
+ cameraExport[key] = Camera[key];
+}
+
+/**
+ * Gets a picture from source defined by "options.sourceType", and returns the
+ * image as defined by the "options.destinationType" option.
+
+ * The defaults are sourceType=CAMERA and destinationType=FILE_URI.
+ *
+ * @param {Function} successCallback
+ * @param {Function} errorCallback
+ * @param {Object} options
+ */
+cameraExport.getPicture = function(successCallback, errorCallback, options) {
+ argscheck.checkArgs('fFO', 'Camera.getPicture', arguments);
+ options = options || {};
+ var getValue = argscheck.getValue;
+
+ var quality = getValue(options.quality, 50);
+ var destinationType = getValue(options.destinationType, Camera.DestinationType.FILE_URI);
+ var sourceType = getValue(options.sourceType, Camera.PictureSourceType.CAMERA);
+ var targetWidth = getValue(options.targetWidth, -1);
+ var targetHeight = getValue(options.targetHeight, -1);
+ var encodingType = getValue(options.encodingType, Camera.EncodingType.JPEG);
+ var mediaType = getValue(options.mediaType, Camera.MediaType.PICTURE);
+ var allowEdit = !!options.allowEdit;
+ var correctOrientation = !!options.correctOrientation;
+ var saveToPhotoAlbum = !!options.saveToPhotoAlbum;
+ var popoverOptions = getValue(options.popoverOptions, null);
+ var cameraDirection = getValue(options.cameraDirection, Camera.Direction.BACK);
+
+ var args = [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType,
+ mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions, cameraDirection];
+
+ exec(successCallback, errorCallback, "Camera", "takePicture", args);
+ return new CameraPopoverHandle();
+};
+
+cameraExport.cleanup = function(successCallback, errorCallback) {
+ exec(successCallback, errorCallback, "Camera", "cleanup", []);
+};
+
+module.exports = cameraExport;
+
+});
+
+// file: lib\common\plugin\CameraConstants.js
+define("cordova/plugin/CameraConstants", function(require, exports, module) {
+
+module.exports = {
+ DestinationType:{
+ DATA_URL: 0, // Return base64 encoded string
+ FILE_URI: 1, // Return file uri (content://media/external/images/media/2 for Android)
+ NATIVE_URI: 2 // Return native uri (eg. asset-library://... for iOS)
+ },
+ EncodingType:{
+ JPEG: 0, // Return JPEG encoded image
+ PNG: 1 // Return PNG encoded image
+ },
+ MediaType:{
+ PICTURE: 0, // allow selection of still pictures only. DEFAULT. Will return format specified via DestinationType
+ VIDEO: 1, // allow selection of video only, ONLY RETURNS URL
+ ALLMEDIA : 2 // allow selection from all media types
+ },
+ PictureSourceType:{
+ PHOTOLIBRARY : 0, // Choose image from picture library (same as SAVEDPHOTOALBUM for Android)
+ CAMERA : 1, // Take picture from camera
+ SAVEDPHOTOALBUM : 2 // Choose image from picture library (same as PHOTOLIBRARY for Android)
+ },
+ PopoverArrowDirection:{
+ ARROW_UP : 1, // matches iOS UIPopoverArrowDirection constants to specify arrow location on popover
+ ARROW_DOWN : 2,
+ ARROW_LEFT : 4,
+ ARROW_RIGHT : 8,
+ ARROW_ANY : 15
+ },
+ Direction:{
+ BACK: 0,
+ FRONT: 1
+ }
+};
+
+});
+
+// file: lib\common\plugin\CameraPopoverHandle.js
+define("cordova/plugin/CameraPopoverHandle", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+
+/**
+ * A handle to an image picker popover.
+ */
+var CameraPopoverHandle = function() {
+ this.setPosition = function(popoverOptions) {
+ console.log('CameraPopoverHandle.setPosition is only supported on iOS.');
+ };
+};
+
+module.exports = CameraPopoverHandle;
+
+});
+
+// file: lib\common\plugin\CameraPopoverOptions.js
+define("cordova/plugin/CameraPopoverOptions", function(require, exports, module) {
+
+var Camera = require('cordova/plugin/CameraConstants');
+
+/**
+ * Encapsulates options for iOS Popover image picker
+ */
+var CameraPopoverOptions = function(x,y,width,height,arrowDir){
+ // information of rectangle that popover should be anchored to
+ this.x = x || 0;
+ this.y = y || 32;
+ this.width = width || 320;
+ this.height = height || 480;
+ // The direction of the popover arrow
+ this.arrowDir = arrowDir || Camera.PopoverArrowDirection.ARROW_ANY;
+};
+
+module.exports = CameraPopoverOptions;
+
+});
+
+// file: lib\common\plugin\CaptureAudioOptions.js
+define("cordova/plugin/CaptureAudioOptions", function(require, exports, module) {
+
+/**
+ * Encapsulates all audio capture operation configuration options.
+ */
+var CaptureAudioOptions = function(){
+ // Upper limit of sound clips user can record. Value must be equal or greater than 1.
+ this.limit = 1;
+ // Maximum duration of a single sound clip in seconds.
+ this.duration = 0;
+ // The selected audio mode. Must match with one of the elements in supportedAudioModes array.
+ this.mode = null;
+};
+
+module.exports = CaptureAudioOptions;
+
+});
+
+// file: lib\common\plugin\CaptureError.js
+define("cordova/plugin/CaptureError", function(require, exports, module) {
+
+/**
+ * The CaptureError interface encapsulates all errors in the Capture API.
+ */
+var CaptureError = function(c) {
+ this.code = c || null;
+};
+
+// Camera or microphone failed to capture image or sound.
+CaptureError.CAPTURE_INTERNAL_ERR = 0;
+// Camera application or audio capture application is currently serving other capture request.
+CaptureError.CAPTURE_APPLICATION_BUSY = 1;
+// Invalid use of the API (e.g. limit parameter has value less than one).
+CaptureError.CAPTURE_INVALID_ARGUMENT = 2;
+// User exited camera application or audio capture application before capturing anything.
+CaptureError.CAPTURE_NO_MEDIA_FILES = 3;
+// The requested capture operation is not supported.
+CaptureError.CAPTURE_NOT_SUPPORTED = 20;
+
+module.exports = CaptureError;
+
+});
+
+// file: lib\common\plugin\CaptureImageOptions.js
+define("cordova/plugin/CaptureImageOptions", function(require, exports, module) {
+
+/**
+ * Encapsulates all image capture operation configuration options.
+ */
+var CaptureImageOptions = function(){
+ // Upper limit of images user can take. Value must be equal or greater than 1.
+ this.limit = 1;
+ // The selected image mode. Must match with one of the elements in supportedImageModes array.
+ this.mode = null;
+};
+
+module.exports = CaptureImageOptions;
+
+});
+
+// file: lib\common\plugin\CaptureVideoOptions.js
+define("cordova/plugin/CaptureVideoOptions", function(require, exports, module) {
+
+/**
+ * Encapsulates all video capture operation configuration options.
+ */
+var CaptureVideoOptions = function(){
+ // Upper limit of videos user can record. Value must be equal or greater than 1.
+ this.limit = 1;
+ // Maximum duration of a single video clip in seconds.
+ this.duration = 0;
+ // The selected video mode. Must match with one of the elements in supportedVideoModes array.
+ this.mode = null;
+};
+
+module.exports = CaptureVideoOptions;
+
+});
+
+// file: lib\common\plugin\CompassError.js
+define("cordova/plugin/CompassError", function(require, exports, module) {
+
+/**
+ * CompassError.
+ * An error code assigned by an implementation when an error has occurred
+ * @constructor
+ */
+var CompassError = function(err) {
+ this.code = (err !== undefined ? err : null);
+};
+
+CompassError.COMPASS_INTERNAL_ERR = 0;
+CompassError.COMPASS_NOT_SUPPORTED = 20;
+
+module.exports = CompassError;
+
+});
+
+// file: lib\common\plugin\CompassHeading.js
+define("cordova/plugin/CompassHeading", function(require, exports, module) {
+
+var CompassHeading = function(magneticHeading, trueHeading, headingAccuracy, timestamp) {
+ this.magneticHeading = magneticHeading;
+ this.trueHeading = trueHeading;
+ this.headingAccuracy = headingAccuracy;
+ this.timestamp = timestamp || new Date().getTime();
+};
+
+module.exports = CompassHeading;
+
+});
+
+// file: lib\common\plugin\ConfigurationData.js
+define("cordova/plugin/ConfigurationData", function(require, exports, module) {
+
+/**
+ * Encapsulates a set of parameters that the capture device supports.
+ */
+function ConfigurationData() {
+ // The ASCII-encoded string in lower case representing the media type.
+ this.type = null;
+ // The height attribute represents height of the image or video in pixels.
+ // In the case of a sound clip this attribute has value 0.
+ this.height = 0;
+ // The width attribute represents width of the image or video in pixels.
+ // In the case of a sound clip this attribute has value 0
+ this.width = 0;
+}
+
+module.exports = ConfigurationData;
+
+});
+
+// file: lib\common\plugin\Connection.js
+define("cordova/plugin/Connection", function(require, exports, module) {
+
+/**
+ * Network status
+ */
+module.exports = {
+ UNKNOWN: "unknown",
+ ETHERNET: "ethernet",
+ WIFI: "wifi",
+ CELL_2G: "2g",
+ CELL_3G: "3g",
+ CELL_4G: "4g",
+ CELL:"cellular",
+ NONE: "none"
+};
+
+});
+
+// file: lib\common\plugin\Contact.js
+define("cordova/plugin/Contact", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ exec = require('cordova/exec'),
+ ContactError = require('cordova/plugin/ContactError'),
+ utils = require('cordova/utils');
+
+/**
+* Converts primitives into Complex Object
+* Currently only used for Date fields
+*/
+function convertIn(contact) {
+ var value = contact.birthday;
+ try {
+ contact.birthday = new Date(parseFloat(value));
+ } catch (exception){
+ console.log("Cordova Contact convertIn error: exception creating date.");
+ }
+ return contact;
+}
+
+/**
+* Converts Complex objects into primitives
+* Only conversion at present is for Dates.
+**/
+
+function convertOut(contact) {
+ var value = contact.birthday;
+ if (value !== null) {
+ // try to make it a Date object if it is not already
+ if (!utils.isDate(value)){
+ try {
+ value = new Date(value);
+ } catch(exception){
+ value = null;
+ }
+ }
+ if (utils.isDate(value)){
+ value = value.valueOf(); // convert to milliseconds
+ }
+ contact.birthday = value;
+ }
+ return contact;
+}
+
+/**
+* Contains information about a single contact.
+* @constructor
+* @param {DOMString} id unique identifier
+* @param {DOMString} displayName
+* @param {ContactName} name
+* @param {DOMString} nickname
+* @param {Array.<ContactField>} phoneNumbers array of phone numbers
+* @param {Array.<ContactField>} emails array of email addresses
+* @param {Array.<ContactAddress>} addresses array of addresses
+* @param {Array.<ContactField>} ims instant messaging user ids
+* @param {Array.<ContactOrganization>} organizations
+* @param {DOMString} birthday contact's birthday
+* @param {DOMString} note user notes about contact
+* @param {Array.<ContactField>} photos
+* @param {Array.<ContactField>} categories
+* @param {Array.<ContactField>} urls contact's web sites
+*/
+var Contact = function (id, displayName, name, nickname, phoneNumbers, emails, addresses,
+ ims, organizations, birthday, note, photos, categories, urls) {
+ this.id = id || null;
+ this.rawId = null;
+ this.displayName = displayName || null;
+ this.name = name || null; // ContactName
+ this.nickname = nickname || null;
+ this.phoneNumbers = phoneNumbers || null; // ContactField[]
+ this.emails = emails || null; // ContactField[]
+ this.addresses = addresses || null; // ContactAddress[]
+ this.ims = ims || null; // ContactField[]
+ this.organizations = organizations || null; // ContactOrganization[]
+ this.birthday = birthday || null;
+ this.note = note || null;
+ this.photos = photos || null; // ContactField[]
+ this.categories = categories || null; // ContactField[]
+ this.urls = urls || null; // ContactField[]
+};
+
+/**
+* Removes contact from device storage.
+* @param successCB success callback
+* @param errorCB error callback
+*/
+Contact.prototype.remove = function(successCB, errorCB) {
+ argscheck.checkArgs('FF', 'Contact.remove', arguments);
+ var fail = errorCB && function(code) {
+ errorCB(new ContactError(code));
+ };
+ if (this.id === null) {
+ fail(ContactError.UNKNOWN_ERROR);
+ }
+ else {
+ exec(successCB, fail, "Contacts", "remove", [this.id]);
+ }
+};
+
+/**
+* Creates a deep copy of this Contact.
+* With the contact ID set to null.
+* @return copy of this Contact
+*/
+Contact.prototype.clone = function() {
+ var clonedContact = utils.clone(this);
+ clonedContact.id = null;
+ clonedContact.rawId = null;
+
+ function nullIds(arr) {
+ if (arr) {
+ for (var i = 0; i < arr.length; ++i) {
+ arr[i].id = null;
+ }
+ }
+ }
+
+ // Loop through and clear out any id's in phones, emails, etc.
+ nullIds(clonedContact.phoneNumbers);
+ nullIds(clonedContact.emails);
+ nullIds(clonedContact.addresses);
+ nullIds(clonedContact.ims);
+ nullIds(clonedContact.organizations);
+ nullIds(clonedContact.categories);
+ nullIds(clonedContact.photos);
+ nullIds(clonedContact.urls);
+ return clonedContact;
+};
+
+/**
+* Persists contact to device storage.
+* @param successCB success callback
+* @param errorCB error callback
+*/
+Contact.prototype.save = function(successCB, errorCB) {
+ argscheck.checkArgs('FFO', 'Contact.save', arguments);
+ var fail = errorCB && function(code) {
+ errorCB(new ContactError(code));
+ };
+ var success = function(result) {
+ if (result) {
+ if (successCB) {
+ var fullContact = require('cordova/plugin/contacts').create(result);
+ successCB(convertIn(fullContact));
+ }
+ }
+ else {
+ // no Entry object returned
+ fail(ContactError.UNKNOWN_ERROR);
+ }
+ };
+ var dupContact = convertOut(utils.clone(this));
+ exec(success, fail, "Contacts", "save", [dupContact]);
+};
+
+
+module.exports = Contact;
+
+});
+
+// file: lib\common\plugin\ContactAddress.js
+define("cordova/plugin/ContactAddress", function(require, exports, module) {
+
+/**
+* Contact address.
+* @constructor
+* @param {DOMString} id unique identifier, should only be set by native code
+* @param formatted // NOTE: not a W3C standard
+* @param streetAddress
+* @param locality
+* @param region
+* @param postalCode
+* @param country
+*/
+
+var ContactAddress = function(pref, type, formatted, streetAddress, locality, region, postalCode, country) {
+ this.id = null;
+ this.pref = (typeof pref != 'undefined' ? pref : false);
+ this.type = type || null;
+ this.formatted = formatted || null;
+ this.streetAddress = streetAddress || null;
+ this.locality = locality || null;
+ this.region = region || null;
+ this.postalCode = postalCode || null;
+ this.country = country || null;
+};
+
+module.exports = ContactAddress;
+
+});
+
+// file: lib\common\plugin\ContactError.js
+define("cordova/plugin/ContactError", function(require, exports, module) {
+
+/**
+ * ContactError.
+ * An error code assigned by an implementation when an error has occurred
+ * @constructor
+ */
+var ContactError = function(err) {
+ this.code = (typeof err != 'undefined' ? err : null);
+};
+
+/**
+ * Error codes
+ */
+ContactError.UNKNOWN_ERROR = 0;
+ContactError.INVALID_ARGUMENT_ERROR = 1;
+ContactError.TIMEOUT_ERROR = 2;
+ContactError.PENDING_OPERATION_ERROR = 3;
+ContactError.IO_ERROR = 4;
+ContactError.NOT_SUPPORTED_ERROR = 5;
+ContactError.PERMISSION_DENIED_ERROR = 20;
+
+module.exports = ContactError;
+
+});
+
+// file: lib\common\plugin\ContactField.js
+define("cordova/plugin/ContactField", function(require, exports, module) {
+
+/**
+* Generic contact field.
+* @constructor
+* @param {DOMString} id unique identifier, should only be set by native code // NOTE: not a W3C standard
+* @param type
+* @param value
+* @param pref
+*/
+var ContactField = function(type, value, pref) {
+ this.id = null;
+ this.type = (type && type.toString()) || null;
+ this.value = (value && value.toString()) || null;
+ this.pref = (typeof pref != 'undefined' ? pref : false);
+};
+
+module.exports = ContactField;
+
+});
+
+// file: lib\common\plugin\ContactFindOptions.js
+define("cordova/plugin/ContactFindOptions", function(require, exports, module) {
+
+/**
+ * ContactFindOptions.
+ * @constructor
+ * @param filter used to match contacts against
+ * @param multiple boolean used to determine if more than one contact should be returned
+ */
+
+var ContactFindOptions = function(filter, multiple) {
+ this.filter = filter || '';
+ this.multiple = (typeof multiple != 'undefined' ? multiple : false);
+};
+
+module.exports = ContactFindOptions;
+
+});
+
+// file: lib\common\plugin\ContactName.js
+define("cordova/plugin/ContactName", function(require, exports, module) {
+
+/**
+* Contact name.
+* @constructor
+* @param formatted // NOTE: not part of W3C standard
+* @param familyName
+* @param givenName
+* @param middle
+* @param prefix
+* @param suffix
+*/
+var ContactName = function(formatted, familyName, givenName, middle, prefix, suffix) {
+ this.formatted = formatted || null;
+ this.familyName = familyName || null;
+ this.givenName = givenName || null;
+ this.middleName = middle || null;
+ this.honorificPrefix = prefix || null;
+ this.honorificSuffix = suffix || null;
+};
+
+module.exports = ContactName;
+
+});
+
+// file: lib\common\plugin\ContactOrganization.js
+define("cordova/plugin/ContactOrganization", function(require, exports, module) {
+
+/**
+* Contact organization.
+* @constructor
+* @param {DOMString} id unique identifier, should only be set by native code // NOTE: not a W3C standard
+* @param name
+* @param dept
+* @param title
+* @param startDate
+* @param endDate
+* @param location
+* @param desc
+*/
+
+var ContactOrganization = function(pref, type, name, dept, title) {
+ this.id = null;
+ this.pref = (typeof pref != 'undefined' ? pref : false);
+ this.type = type || null;
+ this.name = name || null;
+ this.department = dept || null;
+ this.title = title || null;
+};
+
+module.exports = ContactOrganization;
+
+});
+
+// file: lib\common\plugin\Coordinates.js
+define("cordova/plugin/Coordinates", function(require, exports, module) {
+
+/**
+ * This class contains position information.
+ * @param {Object} lat
+ * @param {Object} lng
+ * @param {Object} alt
+ * @param {Object} acc
+ * @param {Object} head
+ * @param {Object} vel
+ * @param {Object} altacc
+ * @constructor
+ */
+var Coordinates = function(lat, lng, alt, acc, head, vel, altacc) {
+ /**
+ * The latitude of the position.
+ */
+ this.latitude = lat;
+ /**
+ * The longitude of the position,
+ */
+ this.longitude = lng;
+ /**
+ * The accuracy of the position.
+ */
+ this.accuracy = acc;
+ /**
+ * The altitude of the position.
+ */
+ this.altitude = (alt !== undefined ? alt : null);
+ /**
+ * The direction the device is moving at the position.
+ */
+ this.heading = (head !== undefined ? head : null);
+ /**
+ * The velocity with which the device is moving at the position.
+ */
+ this.speed = (vel !== undefined ? vel : null);
+
+ if (this.speed === 0 || this.speed === null) {
+ this.heading = NaN;
+ }
+
+ /**
+ * The altitude accuracy of the position.
+ */
+ this.altitudeAccuracy = (altacc !== undefined) ? altacc : null;
+};
+
+module.exports = Coordinates;
+
+});
+
+// file: lib\common\plugin\DirectoryEntry.js
+define("cordova/plugin/DirectoryEntry", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ utils = require('cordova/utils'),
+ exec = require('cordova/exec'),
+ Entry = require('cordova/plugin/Entry'),
+ FileError = require('cordova/plugin/FileError'),
+ DirectoryReader = require('cordova/plugin/DirectoryReader');
+
+/**
+ * An interface representing a directory on the file system.
+ *
+ * {boolean} isFile always false (readonly)
+ * {boolean} isDirectory always true (readonly)
+ * {DOMString} name of the directory, excluding the path leading to it (readonly)
+ * {DOMString} fullPath the absolute full path to the directory (readonly)
+ * TODO: implement this!!! {FileSystem} filesystem on which the directory resides (readonly)
+ */
+var DirectoryEntry = function(name, fullPath) {
+ DirectoryEntry.__super__.constructor.call(this, false, true, name, fullPath);
+};
+
+utils.extend(DirectoryEntry, Entry);
+
+/**
+ * Creates a new DirectoryReader to read entries from this directory
+ */
+DirectoryEntry.prototype.createReader = function() {
+ return new DirectoryReader(this.fullPath);
+};
+
+/**
+ * Creates or looks up a directory
+ *
+ * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a directory
+ * @param {Flags} options to create or exclusively create the directory
+ * @param {Function} successCallback is called with the new entry
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryEntry.prototype.getDirectory = function(path, options, successCallback, errorCallback) {
+ argscheck.checkArgs('sOFF', 'DirectoryEntry.getDirectory', arguments);
+ var win = successCallback && function(result) {
+ var entry = new DirectoryEntry(result.name, result.fullPath);
+ successCallback(entry);
+ };
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(win, fail, "File", "getDirectory", [this.fullPath, path, options]);
+};
+
+/**
+ * Deletes a directory and all of it's contents
+ *
+ * @param {Function} successCallback is called with no parameters
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryEntry.prototype.removeRecursively = function(successCallback, errorCallback) {
+ argscheck.checkArgs('FF', 'DirectoryEntry.removeRecursively', arguments);
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(successCallback, fail, "File", "removeRecursively", [this.fullPath]);
+};
+
+/**
+ * Creates or looks up a file
+ *
+ * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a file
+ * @param {Flags} options to create or exclusively create the file
+ * @param {Function} successCallback is called with the new entry
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryEntry.prototype.getFile = function(path, options, successCallback, errorCallback) {
+ argscheck.checkArgs('sOFF', 'DirectoryEntry.getFile', arguments);
+ var win = successCallback && function(result) {
+ var FileEntry = require('cordova/plugin/FileEntry');
+ var entry = new FileEntry(result.name, result.fullPath);
+ successCallback(entry);
+ };
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(win, fail, "File", "getFile", [this.fullPath, path, options]);
+};
+
+module.exports = DirectoryEntry;
+
+});
+
+// file: lib\common\plugin\DirectoryReader.js
+define("cordova/plugin/DirectoryReader", function(require, exports, module) {
+
+var exec = require('cordova/exec'),
+ FileError = require('cordova/plugin/FileError') ;
+
+/**
+ * An interface that lists the files and directories in a directory.
+ */
+function DirectoryReader(path) {
+ this.path = path || null;
+}
+
+/**
+ * Returns a list of entries from a directory.
+ *
+ * @param {Function} successCallback is called with a list of entries
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryReader.prototype.readEntries = function(successCallback, errorCallback) {
+ var win = typeof successCallback !== 'function' ? null : function(result) {
+ var retVal = [];
+ for (var i=0; i<result.length; i++) {
+ var entry = null;
+ if (result[i].isDirectory) {
+ entry = new (require('cordova/plugin/DirectoryEntry'))();
+ }
+ else if (result[i].isFile) {
+ entry = new (require('cordova/plugin/FileEntry'))();
+ }
+ entry.isDirectory = result[i].isDirectory;
+ entry.isFile = result[i].isFile;
+ entry.name = result[i].name;
+ entry.fullPath = result[i].fullPath;
+ retVal.push(entry);
+ }
+ successCallback(retVal);
+ };
+ var fail = typeof errorCallback !== 'function' ? null : function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(win, fail, "File", "readEntries", [this.path]);
+};
+
+module.exports = DirectoryReader;
+
+});
+
+// file: lib\common\plugin\Entry.js
+define("cordova/plugin/Entry", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ exec = require('cordova/exec'),
+ FileError = require('cordova/plugin/FileError'),
+ Metadata = require('cordova/plugin/Metadata');
+
+/**
+ * Represents a file or directory on the local file system.
+ *
+ * @param isFile
+ * {boolean} true if Entry is a file (readonly)
+ * @param isDirectory
+ * {boolean} true if Entry is a directory (readonly)
+ * @param name
+ * {DOMString} name of the file or directory, excluding the path
+ * leading to it (readonly)
+ * @param fullPath
+ * {DOMString} the absolute full path to the file or directory
+ * (readonly)
+ */
+function Entry(isFile, isDirectory, name, fullPath, fileSystem) {
+ this.isFile = !!isFile;
+ this.isDirectory = !!isDirectory;
+ this.name = name || '';
+ this.fullPath = fullPath || '';
+ this.filesystem = fileSystem || null;
+}
+
+/**
+ * Look up the metadata of the entry.
+ *
+ * @param successCallback
+ * {Function} is called with a Metadata object
+ * @param errorCallback
+ * {Function} is called with a FileError
+ */
+Entry.prototype.getMetadata = function(successCallback, errorCallback) {
+ argscheck.checkArgs('FF', 'Entry.getMetadata', arguments);
+ var success = successCallback && function(lastModified) {
+ var metadata = new Metadata(lastModified);
+ successCallback(metadata);
+ };
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+
+ exec(success, fail, "File", "getMetadata", [this.fullPath]);
+};
+
+/**
+ * Set the metadata of the entry.
+ *
+ * @param successCallback
+ * {Function} is called with a Metadata object
+ * @param errorCallback
+ * {Function} is called with a FileError
+ * @param metadataObject
+ * {Object} keys and values to set
+ */
+Entry.prototype.setMetadata = function(successCallback, errorCallback, metadataObject) {
+ argscheck.checkArgs('FFO', 'Entry.setMetadata', arguments);
+ exec(successCallback, errorCallback, "File", "setMetadata", [this.fullPath, metadataObject]);
+};
+
+/**
+ * Move a file or directory to a new location.
+ *
+ * @param parent
+ * {DirectoryEntry} the directory to which to move this entry
+ * @param newName
+ * {DOMString} new name of the entry, defaults to the current name
+ * @param successCallback
+ * {Function} called with the new DirectoryEntry object
+ * @param errorCallback
+ * {Function} called with a FileError
+ */
+Entry.prototype.moveTo = function(parent, newName, successCallback, errorCallback) {
+ argscheck.checkArgs('oSFF', 'Entry.moveTo', arguments);
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ // source path
+ var srcPath = this.fullPath,
+ // entry name
+ name = newName || this.name,
+ success = function(entry) {
+ if (entry) {
+ if (successCallback) {
+ // create appropriate Entry object
+ var result = (entry.isDirectory) ? new (require('cordova/plugin/DirectoryEntry'))(entry.name, entry.fullPath) : new (require('cordova/plugin/FileEntry'))(entry.name, entry.fullPath);
+ successCallback(result);
+ }
+ }
+ else {
+ // no Entry object returned
+ fail && fail(FileError.NOT_FOUND_ERR);
+ }
+ };
+
+ // copy
+ exec(success, fail, "File", "moveTo", [srcPath, parent.fullPath, name]);
+};
+
+/**
+ * Copy a directory to a different location.
+ *
+ * @param parent
+ * {DirectoryEntry} the directory to which to copy the entry
+ * @param newName
+ * {DOMString} new name of the entry, defaults to the current name
+ * @param successCallback
+ * {Function} called with the new Entry object
+ * @param errorCallback
+ * {Function} called with a FileError
+ */
+Entry.prototype.copyTo = function(parent, newName, successCallback, errorCallback) {
+ argscheck.checkArgs('oSFF', 'Entry.copyTo', arguments);
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+
+ // source path
+ var srcPath = this.fullPath,
+ // entry name
+ name = newName || this.name,
+ // success callback
+ success = function(entry) {
+ if (entry) {
+ if (successCallback) {
+ // create appropriate Entry object
+ var result = (entry.isDirectory) ? new (require('cordova/plugin/DirectoryEntry'))(entry.name, entry.fullPath) : new (require('cordova/plugin/FileEntry'))(entry.name, entry.fullPath);
+ successCallback(result);
+ }
+ }
+ else {
+ // no Entry object returned
+ fail && fail(FileError.NOT_FOUND_ERR);
+ }
+ };
+
+ // copy
+ exec(success, fail, "File", "copyTo", [srcPath, parent.fullPath, name]);
+};
+
+/**
+ * Return a URL that can be used to identify this entry.
+ */
+Entry.prototype.toURL = function() {
+ // fullPath attribute contains the full URL
+ return this.fullPath;
+};
+
+/**
+ * Returns a URI that can be used to identify this entry.
+ *
+ * @param {DOMString} mimeType for a FileEntry, the mime type to be used to interpret the file, when loaded through this URI.
+ * @return uri
+ */
+Entry.prototype.toURI = function(mimeType) {
+ console.log("DEPRECATED: Update your code to use 'toURL'");
+ // fullPath attribute contains the full URI
+ return this.toURL();
+};
+
+/**
+ * Remove a file or directory. It is an error to attempt to delete a
+ * directory that is not empty. It is an error to attempt to delete a
+ * root directory of a file system.
+ *
+ * @param successCallback {Function} called with no parameters
+ * @param errorCallback {Function} called with a FileError
+ */
+Entry.prototype.remove = function(successCallback, errorCallback) {
+ argscheck.checkArgs('FF', 'Entry.remove', arguments);
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(successCallback, fail, "File", "remove", [this.fullPath]);
+};
+
+/**
+ * Look up the parent DirectoryEntry of this entry.
+ *
+ * @param successCallback {Function} called with the parent DirectoryEntry object
+ * @param errorCallback {Function} called with a FileError
+ */
+Entry.prototype.getParent = function(successCallback, errorCallback) {
+ argscheck.checkArgs('FF', 'Entry.getParent', arguments);
+ var win = successCallback && function(result) {
+ var DirectoryEntry = require('cordova/plugin/DirectoryEntry');
+ var entry = new DirectoryEntry(result.name, result.fullPath);
+ successCallback(entry);
+ };
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(win, fail, "File", "getParent", [this.fullPath]);
+};
+
+module.exports = Entry;
+
+});
+
+// file: lib\common\plugin\File.js
+define("cordova/plugin/File", function(require, exports, module) {
+
+/**
+ * Constructor.
+ * name {DOMString} name of the file, without path information
+ * fullPath {DOMString} the full path of the file, including the name
+ * type {DOMString} mime type
+ * lastModifiedDate {Date} last modified date
+ * size {Number} size of the file in bytes
+ */
+
+var File = function(name, fullPath, type, lastModifiedDate, size){
+ this.name = name || '';
+ this.fullPath = fullPath || null;
+ this.type = type || null;
+ this.lastModifiedDate = lastModifiedDate || null;
+ this.size = size || 0;
+
+ // These store the absolute start and end for slicing the file.
+ this.start = 0;
+ this.end = this.size;
+};
+
+/**
+ * Returns a "slice" of the file. Since Cordova Files don't contain the actual
+ * content, this really returns a File with adjusted start and end.
+ * Slices of slices are supported.
+ * start {Number} The index at which to start the slice (inclusive).
+ * end {Number} The index at which to end the slice (exclusive).
+ */
+File.prototype.slice = function(start, end) {
+ var size = this.end - this.start;
+ var newStart = 0;
+ var newEnd = size;
+ if (arguments.length) {
+ if (start < 0) {
+ newStart = Math.max(size + start, 0);
+ } else {
+ newStart = Math.min(size, start);
+ }
+ }
+
+ if (arguments.length >= 2) {
+ if (end < 0) {
+ newEnd = Math.max(size + end, 0);
+ } else {
+ newEnd = Math.min(end, size);
+ }
+ }
+
+ var newFile = new File(this.name, this.fullPath, this.type, this.lastModifiedData, this.size);
+ newFile.start = this.start + newStart;
+ newFile.end = this.start + newEnd;
+ return newFile;
+};
+
+
+module.exports = File;
+
+});
+
+// file: lib\common\plugin\FileEntry.js
+define("cordova/plugin/FileEntry", function(require, exports, module) {
+
+var utils = require('cordova/utils'),
+ exec = require('cordova/exec'),
+ Entry = require('cordova/plugin/Entry'),
+ FileWriter = require('cordova/plugin/FileWriter'),
+ File = require('cordova/plugin/File'),
+ FileError = require('cordova/plugin/FileError');
+
+/**
+ * An interface representing a file on the file system.
+ *
+ * {boolean} isFile always true (readonly)
+ * {boolean} isDirectory always false (readonly)
+ * {DOMString} name of the file, excluding the path leading to it (readonly)
+ * {DOMString} fullPath the absolute full path to the file (readonly)
+ * {FileSystem} filesystem on which the file resides (readonly)
+ */
+var FileEntry = function(name, fullPath) {
+ FileEntry.__super__.constructor.apply(this, [true, false, name, fullPath]);
+};
+
+utils.extend(FileEntry, Entry);
+
+/**
+ * Creates a new FileWriter associated with the file that this FileEntry represents.
+ *
+ * @param {Function} successCallback is called with the new FileWriter
+ * @param {Function} errorCallback is called with a FileError
+ */
+FileEntry.prototype.createWriter = function(successCallback, errorCallback) {
+ this.file(function(filePointer) {
+ var writer = new FileWriter(filePointer);
+
+ if (writer.fileName === null || writer.fileName === "") {
+ errorCallback && errorCallback(new FileError(FileError.INVALID_STATE_ERR));
+ } else {
+ successCallback && successCallback(writer);
+ }
+ }, errorCallback);
+};
+
+/**
+ * Returns a File that represents the current state of the file that this FileEntry represents.
+ *
+ * @param {Function} successCallback is called with the new File object
+ * @param {Function} errorCallback is called with a FileError
+ */
+FileEntry.prototype.file = function(successCallback, errorCallback) {
+ var win = successCallback && function(f) {
+ var file = new File(f.name, f.fullPath, f.type, f.lastModifiedDate, f.size);
+ successCallback(file);
+ };
+ var fail = errorCallback && function(code) {
+ errorCallback(new FileError(code));
+ };
+ exec(win, fail, "File", "getFileMetadata", [this.fullPath]);
+};
+
+
+module.exports = FileEntry;
+
+});
+
+// file: lib\common\plugin\FileError.js
+define("cordova/plugin/FileError", function(require, exports, module) {
+
+/**
+ * FileError
+ */
+function FileError(error) {
+ this.code = error || null;
+}
+
+// File error codes
+// Found in DOMException
+FileError.NOT_FOUND_ERR = 1;
+FileError.SECURITY_ERR = 2;
+FileError.ABORT_ERR = 3;
+
+// Added by File API specification
+FileError.NOT_READABLE_ERR = 4;
+FileError.ENCODING_ERR = 5;
+FileError.NO_MODIFICATION_ALLOWED_ERR = 6;
+FileError.INVALID_STATE_ERR = 7;
+FileError.SYNTAX_ERR = 8;
+FileError.INVALID_MODIFICATION_ERR = 9;
+FileError.QUOTA_EXCEEDED_ERR = 10;
+FileError.TYPE_MISMATCH_ERR = 11;
+FileError.PATH_EXISTS_ERR = 12;
+
+module.exports = FileError;
+
+});
+
+// file: lib\common\plugin\FileReader.js
+define("cordova/plugin/FileReader", function(require, exports, module) {
+
+var exec = require('cordova/exec'),
+ modulemapper = require('cordova/modulemapper'),
+ utils = require('cordova/utils'),
+ File = require('cordova/plugin/File'),
+ FileError = require('cordova/plugin/FileError'),
+ ProgressEvent = require('cordova/plugin/ProgressEvent'),
+ origFileReader = modulemapper.getOriginalSymbol(this, 'FileReader');
+
+/**
+ * This class reads the mobile device file system.
+ *
+ * For Android:
+ * The root directory is the root of the file system.
+ * To read from the SD card, the file name is "sdcard/my_file.txt"
+ * @constructor
+ */
+var FileReader = function() {
+ this._readyState = 0;
+ this._error = null;
+ this._result = null;
+ this._fileName = '';
+ this._realReader = origFileReader ? new origFileReader() : {};
+};
+
+// States
+FileReader.EMPTY = 0;
+FileReader.LOADING = 1;
+FileReader.DONE = 2;
+
+utils.defineGetter(FileReader.prototype, 'readyState', function() {
+ return this._fileName ? this._readyState : this._realReader.readyState;
+});
+
+utils.defineGetter(FileReader.prototype, 'error', function() {
+ return this._fileName ? this._error: this._realReader.error;
+});
+
+utils.defineGetter(FileReader.prototype, 'result', function() {
+ return this._fileName ? this._result: this._realReader.result;
+});
+
+function defineEvent(eventName) {
+ utils.defineGetterSetter(FileReader.prototype, eventName, function() {
+ return this._realReader[eventName] || null;
+ }, function(value) {
+ this._realReader[eventName] = value;
+ });
+}
+defineEvent('onloadstart'); // When the read starts.
+defineEvent('onprogress'); // While reading (and decoding) file or fileBlob data, and reporting partial file data (progress.loaded/progress.total)
+defineEvent('onload'); // When the read has successfully completed.
+defineEvent('onerror'); // When the read has failed (see errors).
+defineEvent('onloadend'); // When the request has completed (either in success or failure).
+defineEvent('onabort'); // When the read has been aborted. For instance, by invoking the abort() method.
+
+function initRead(reader, file) {
+ // Already loading something
+ if (reader.readyState == FileReader.LOADING) {
+ throw new FileError(FileError.INVALID_STATE_ERR);
+ }
+
+ reader._result = null;
+ reader._error = null;
+ reader._readyState = FileReader.LOADING;
+
+ if (typeof file == 'string') {
+ // Deprecated in Cordova 2.4.
+ console.warn('Using a string argument with FileReader.readAs functions is deprecated.');
+ reader._fileName = file;
+ } else if (typeof file.fullPath == 'string') {
+ reader._fileName = file.fullPath;
+ } else {
+ reader._fileName = '';
+ return true;
+ }
+
+ reader.onloadstart && reader.onloadstart(new ProgressEvent("loadstart", {target:reader}));
+}
+
+/**
+ * Abort reading file.
+ */
+FileReader.prototype.abort = function() {
+ if (origFileReader && !this._fileName) {
+ return this._realReader.abort();
+ }
+ this._result = null;
+
+ if (this._readyState == FileReader.DONE || this._readyState == FileReader.EMPTY) {
+ return;
+ }
+
+ this._readyState = FileReader.DONE;
+
+ // If abort callback
+ if (typeof this.onabort === 'function') {
+ this.onabort(new ProgressEvent('abort', {target:this}));
+ }
+ // If load end callback
+ if (typeof this.onloadend === 'function') {
+ this.onloadend(new ProgressEvent('loadend', {target:this}));
+ }
+};
+
+/**
+ * Read text file.
+ *
+ * @param file {File} File object containing file properties
+ * @param encoding [Optional] (see http://www.iana.org/assignments/character-sets)
+ */
+FileReader.prototype.readAsText = function(file, encoding) {
+ if (initRead(this, file)) {
+ return this._realReader.readAsText(file, encoding);
+ }
+
+ // Default encoding is UTF-8
+ var enc = encoding ? encoding : "UTF-8";
+ var me = this;
+ var execArgs = [this._fileName, enc, file.start, file.end];
+
+ // Read file
+ exec(
+ // Success callback
+ function(r) {
+ // If DONE (cancelled), then don't do anything
+ if (me._readyState === FileReader.DONE) {
+ return;
+ }
+
+ // Save result
+ me._result = r;
+
+ // If onload callback
+ if (typeof me.onload === "function") {
+ me.onload(new ProgressEvent("load", {target:me}));
+ }
+
+ // DONE state
+ me._readyState = FileReader.DONE;
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ me.onloadend(new ProgressEvent("loadend", {target:me}));
+ }
+ },
+ // Error callback
+ function(e) {
+ // If DONE (cancelled), then don't do anything
+ if (me._readyState === FileReader.DONE) {
+ return;
+ }
+
+ // DONE state
+ me._readyState = FileReader.DONE;
+
+ // null result
+ me._result = null;
+
+ // Save error
+ me._error = new FileError(e);
+
+ // If onerror callback
+ if (typeof me.onerror === "function") {
+ me.onerror(new ProgressEvent("error", {target:me}));
+ }
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ me.onloadend(new ProgressEvent("loadend", {target:me}));
+ }
+ }, "File", "readAsText", execArgs);
+};
+
+
+/**
+ * Read file and return data as a base64 encoded data url.
+ * A data url is of the form:
+ * data:[<mediatype>][;base64],<data>
+ *
+ * @param file {File} File object containing file properties
+ */
+FileReader.prototype.readAsDataURL = function(file) {
+ if (initRead(this, file)) {
+ return this._realReader.readAsDataURL(file);
+ }
+
+ var me = this;
+ var execArgs = [this._fileName, file.start, file.end];
+
+ // Read file
+ exec(
+ // Success callback
+ function(r) {
+ // If DONE (cancelled), then don't do anything
+ if (me._readyState === FileReader.DONE) {
+ return;
+ }
+
+ // DONE state
+ me._readyState = FileReader.DONE;
+
+ // Save result
+ me._result = r;
+
+ // If onload callback
+ if (typeof me.onload === "function") {
+ me.onload(new ProgressEvent("load", {target:me}));
+ }
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ me.onloadend(new ProgressEvent("loadend", {target:me}));
+ }
+ },
+ // Error callback
+ function(e) {
+ // If DONE (cancelled), then don't do anything
+ if (me._readyState === FileReader.DONE) {
+ return;
+ }
+
+ // DONE state
+ me._readyState = FileReader.DONE;
+
+ me._result = null;
+
+ // Save error
+ me._error = new FileError(e);
+
+ // If onerror callback
+ if (typeof me.onerror === "function") {
+ me.onerror(new ProgressEvent("error", {target:me}));
+ }
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ me.onloadend(new ProgressEvent("loadend", {target:me}));
+ }
+ }, "File", "readAsDataURL", execArgs);
+};
+
+/**
+ * Read file and return data as a binary data.
+ *
+ * @param file {File} File object containing file properties
+ */
+FileReader.prototype.readAsBinaryString = function(file) {
+ if (initRead(this, file)) {
+ return this._realReader.readAsBinaryString(file);
+ }
+
+ var me = this;
+ var execArgs = [this._fileName, file.start, file.end];
+
+ // Read file
+ exec(
+ // Success callback
+ function(r) {
+ // If DONE (cancelled), then don't do anything
+ if (me._readyState === FileReader.DONE) {
+ return;
+ }
+
+ // DONE state
+ me._readyState = FileReader.DONE;
+
+ me._result = r;
+
+ // If onload callback
+ if (typeof me.onload === "function") {
+ me.onload(new ProgressEvent("load", {target:me}));
+ }
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ me.onloadend(new ProgressEvent("loadend", {target:me}));
+ }
+ },
+ // Error callback
+ function(e) {
+ // If DONE (cancelled), then don't do anything
+ if (me._readyState === FileReader.DONE) {
+ return;
+ }
+
+ // DONE state
+ me._readyState = FileReader.DONE;
+
+ me._result = null;
+
+ // Save error
+ me._error = new FileError(e);
+
+ // If onerror callback
+ if (typeof me.onerror === "function") {
+ me.onerror(new ProgressEvent("error", {target:me}));
+ }
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ me.onloadend(new ProgressEvent("loadend", {target:me}));
+ }
+ }, "File", "readAsBinaryString", execArgs);
+};
+
+/**
+ * Read file and return data as a binary data.
+ *
+ * @param file {File} File object containing file properties
+ */
+FileReader.prototype.readAsArrayBuffer = function(file) {
+ if (initRead(this, file)) {
+ return this._realReader.readAsArrayBuffer(file);
+ }
+
+ var me = this;
+ var execArgs = [this._fileName, file.start, file.end];
+
+ // Read file
+ exec(
+ // Success callback
+ function(r) {
+ // If DONE (cancelled), then don't do anything
+ if (me._readyState === FileReader.DONE) {
+ return;
+ }
+
+ // DONE state
+ me._readyState = FileReader.DONE;
+
+ me._result = r;
+
+ // If onload callback
+ if (typeof me.onload === "function") {
+ me.onload(new ProgressEvent("load", {target:me}));
+ }
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ me.onloadend(new ProgressEvent("loadend", {target:me}));
+ }
+ },
+ // Error callback
+ function(e) {
+ // If DONE (cancelled), then don't do anything
+ if (me._readyState === FileReader.DONE) {
+ return;
+ }
+
+ // DONE state
+ me._readyState = FileReader.DONE;
+
+ me._result = null;
+
+ // Save error
+ me._error = new FileError(e);
+
+ // If onerror callback
+ if (typeof me.onerror === "function") {
+ me.onerror(new ProgressEvent("error", {target:me}));
+ }
+
+ // If onloadend callback
+ if (typeof me.onloadend === "function") {
+ me.onloadend(new ProgressEvent("loadend", {target:me}));
+ }
+ }, "File", "readAsArrayBuffer", execArgs);
+};
+
+module.exports = FileReader;
+
+});
+
+// file: lib\common\plugin\FileSystem.js
+define("cordova/plugin/FileSystem", function(require, exports, module) {
+
+var DirectoryEntry = require('cordova/plugin/DirectoryEntry');
+
+/**
+ * An interface representing a file system
+ *
+ * @constructor
+ * {DOMString} name the unique name of the file system (readonly)
+ * {DirectoryEntry} root directory of the file system (readonly)
+ */
+var FileSystem = function(name, root) {
+ this.name = name || null;
+ if (root) {
+ this.root = new DirectoryEntry(root.name, root.fullPath);
+ }
+};
+
+module.exports = FileSystem;
+
+});
+
+// file: lib\common\plugin\FileTransfer.js
+define("cordova/plugin/FileTransfer", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+ exec = require('cordova/exec'),
+ FileTransferError = require('cordova/plugin/FileTransferError'),
+ ProgressEvent = require('cordova/plugin/ProgressEvent');
+
+function newProgressEvent(result) {
+ var pe = new ProgressEvent();
+ pe.lengthComputable = result.lengthComputable;
+ pe.loaded = result.loaded;
+ pe.total = result.total;
+ return pe;
+}
+
+function getBasicAuthHeader(urlString) {
+ var header = null;
+
+ if (window.btoa) {
+ // parse the url using the Location object
+ var url = document.createElement('a');
+ url.href = urlString;
+
+ var credentials = null;
+ var protocol = url.protocol + "//";
+ var origin = protocol + url.host;
+
+ // check whether there are the username:password credentials in the url
+ if (url.href.indexOf(origin) !== 0) { // credentials found
+ var atIndex = url.href.indexOf("@");
+ credentials = url.href.substring(protocol.length, atIndex);
+ }
+
+ if (credentials) {
+ var authHeader = "Authorization";
+ var authHeaderValue = "Basic " + window.btoa(credentials);
+
+ header = {
+ name : authHeader,
+ value : authHeaderValue
+ };
+ }
+ }
+
+ return header;
+}
+
+var idCounter = 0;
+
+/**
+ * FileTransfer uploads a file to a remote server.
+ * @constructor
+ */
+var FileTransfer = function() {
+ this._id = ++idCounter;
+ this.onprogress = null; // optional callback
+};
+
+/**
+* Given an absolute file path, uploads a file on the device to a remote server
+* using a multipart HTTP request.
+* @param filePath {String} Full path of the file on the device
+* @param server {String} URL of the server to receive the file
+* @param successCallback (Function} Callback to be invoked when upload has completed
+* @param errorCallback {Function} Callback to be invoked upon error
+* @param options {FileUploadOptions} Optional parameters such as file name and mimetype
+* @param trustAllHosts {Boolean} Optional trust all hosts (e.g. for self-signed certs), defaults to false
+*/
+FileTransfer.prototype.upload = function(filePath, server, successCallback, errorCallback, options, trustAllHosts) {
+ argscheck.checkArgs('ssFFO*', 'FileTransfer.upload', arguments);
+ // check for options
+ var fileKey = null;
+ var fileName = null;
+ var mimeType = null;
+ var params = null;
+ var chunkedMode = true;
+ var headers = null;
+ var httpMethod = null;
+ var basicAuthHeader = getBasicAuthHeader(server);
+ if (basicAuthHeader) {
+ options = options || {};
+ options.headers = options.headers || {};
+ options.headers[basicAuthHeader.name] = basicAuthHeader.value;
+ }
+
+ if (options) {
+ fileKey = options.fileKey;
+ fileName = options.fileName;
+ mimeType = options.mimeType;
+ headers = options.headers;
+ httpMethod = options.httpMethod || "POST";
+ if (httpMethod.toUpperCase() == "PUT"){
+ httpMethod = "PUT";
+ } else {
+ httpMethod = "POST";
+ }
+ if (options.chunkedMode !== null || typeof options.chunkedMode != "undefined") {
+ chunkedMode = options.chunkedMode;
+ }
+ if (options.params) {
+ params = options.params;
+ }
+ else {
+ params = {};
+ }
+ }
+
+ var fail = errorCallback && function(e) {
+ var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body);
+ errorCallback(error);
+ };
+
+ var self = this;
+ var win = function(result) {
+ if (typeof result.lengthComputable != "undefined") {
+ if (self.onprogress) {
+ self.onprogress(newProgressEvent(result));
+ }
+ } else {
+ successCallback && successCallback(result);
+ }
+ };
+ exec(win, fail, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode, headers, this._id, httpMethod]);
+};
+
+/**
+ * Downloads a file form a given URL and saves it to the specified directory.
+ * @param source {String} URL of the server to receive the file
+ * @param target {String} Full path of the file on the device
+ * @param successCallback (Function} Callback to be invoked when upload has completed
+ * @param errorCallback {Function} Callback to be invoked upon error
+ * @param trustAllHosts {Boolean} Optional trust all hosts (e.g. for self-signed certs), defaults to false
+ * @param options {FileDownloadOptions} Optional parameters such as headers
+ */
+FileTransfer.prototype.download = function(source, target, successCallback, errorCallback, trustAllHosts, options) {
+ argscheck.checkArgs('ssFF*', 'FileTransfer.download', arguments);
+ var self = this;
+
+ var basicAuthHeader = getBasicAuthHeader(source);
+ if (basicAuthHeader) {
+ options = options || {};
+ options.headers = options.headers || {};
+ options.headers[basicAuthHeader.name] = basicAuthHeader.value;
+ }
+
+ var headers = null;
+ if (options) {
+ headers = options.headers || null;
+ }
+
+ var win = function(result) {
+ if (typeof result.lengthComputable != "undefined") {
+ if (self.onprogress) {
+ return self.onprogress(newProgressEvent(result));
+ }
+ } else if (successCallback) {
+ var entry = null;
+ if (result.isDirectory) {
+ entry = new (require('cordova/plugin/DirectoryEntry'))();
+ }
+ else if (result.isFile) {
+ entry = new (require('cordova/plugin/FileEntry'))();
+ }
+ entry.isDirectory = result.isDirectory;
+ entry.isFile = result.isFile;
+ entry.name = result.name;
+ entry.fullPath = result.fullPath;
+ successCallback(entry);
+ }
+ };
+
+ var fail = errorCallback && function(e) {
+ var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body);
+ errorCallback(error);
+ };
+
+ exec(win, fail, 'FileTransfer', 'download', [source, target, trustAllHosts, this._id, headers]);
+};
+
+/**
+ * Aborts the ongoing file transfer on this object. The original error
+ * callback for the file trans
<TRUNCATED>
[20/37] Add WP7 and WP8 platform files.
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/framework/WPCordovaClassLib.sln
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/framework/WPCordovaClassLib.sln b/lib/cordova-wp8/framework/WPCordovaClassLib.sln
new file mode 100644
index 0000000..c34cba1
--- /dev/null
+++ b/lib/cordova-wp8/framework/WPCordovaClassLib.sln
@@ -0,0 +1,32 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Express 2012 for Windows Phone
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WPCordovaClassLib", "WPCordovaClassLib.csproj", "{FC6A1A70-892D-46AD-9E4A-9793F72AF780}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM = Debug|ARM
+ Debug|Any CPU = Debug|Any CPU
+ Debug|x86 = Debug|x86
+ Release|ARM = Release|ARM
+ Release|Any CPU = Release|Any CPU
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {FC6A1A70-892D-46AD-9E4A-9793F72AF780}.Debug|ARM.ActiveCfg = Debug|ARM
+ {FC6A1A70-892D-46AD-9E4A-9793F72AF780}.Debug|ARM.Build.0 = Debug|ARM
+ {FC6A1A70-892D-46AD-9E4A-9793F72AF780}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FC6A1A70-892D-46AD-9E4A-9793F72AF780}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FC6A1A70-892D-46AD-9E4A-9793F72AF780}.Debug|x86.ActiveCfg = Debug|x86
+ {FC6A1A70-892D-46AD-9E4A-9793F72AF780}.Debug|x86.Build.0 = Debug|x86
+ {FC6A1A70-892D-46AD-9E4A-9793F72AF780}.Release|ARM.ActiveCfg = Release|ARM
+ {FC6A1A70-892D-46AD-9E4A-9793F72AF780}.Release|ARM.Build.0 = Release|ARM
+ {FC6A1A70-892D-46AD-9E4A-9793F72AF780}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FC6A1A70-892D-46AD-9E4A-9793F72AF780}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FC6A1A70-892D-46AD-9E4A-9793F72AF780}.Release|x86.ActiveCfg = Release|x86
+ {FC6A1A70-892D-46AD-9E4A-9793F72AF780}.Release|x86.Build.0 = Release|x86
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/framework/resources/notification-beep.wav
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/framework/resources/notification-beep.wav b/lib/cordova-wp8/framework/resources/notification-beep.wav
new file mode 100644
index 0000000..d0ad085
Binary files /dev/null and b/lib/cordova-wp8/framework/resources/notification-beep.wav differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/App.xaml
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/App.xaml b/lib/cordova-wp8/templates/standalone/App.xaml
new file mode 100644
index 0000000..18072fe
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/App.xaml
@@ -0,0 +1,37 @@
+<!--
+ 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.
+-->
+<Application
+ x:Class="$safeprojectname$.App"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
+ xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone">
+
+ <!--Application Resources-->
+ <Application.Resources>
+ </Application.Resources>
+
+ <Application.ApplicationLifetimeObjects>
+ <!--Required object that handles lifetime events for the application-->
+ <shell:PhoneApplicationService
+ Launching="Application_Launching" Closing="Application_Closing"
+ Activated="Application_Activated" Deactivated="Application_Deactivated"/>
+ </Application.ApplicationLifetimeObjects>
+
+</Application>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/App.xaml.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/App.xaml.cs b/lib/cordova-wp8/templates/standalone/App.xaml.cs
new file mode 100644
index 0000000..2b7306d
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/App.xaml.cs
@@ -0,0 +1,154 @@
+/*
+ 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.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.Navigation;
+using System.Windows.Shapes;
+using Microsoft.Phone.Controls;
+using Microsoft.Phone.Shell;
+
+namespace $safeprojectname$
+{
+ public partial class App : Application
+ {
+ /// <summary>
+ /// Provides easy access to the root frame of the Phone Application.
+ /// </summary>
+ /// <returns>The root frame of the Phone Application.</returns>
+ public PhoneApplicationFrame RootFrame { get; private set; }
+
+ /// <summary>
+ /// Constructor for the Application object.
+ /// </summary>
+ public App()
+ {
+ // Global handler for uncaught exceptions.
+ UnhandledException += Application_UnhandledException;
+
+ // Show graphics profiling information while debugging.
+ if (System.Diagnostics.Debugger.IsAttached)
+ {
+ // Display the current frame rate counters.
+ //Application.Current.Host.Settings.EnableFrameRateCounter = true;
+
+ // Show the areas of the app that are being redrawn in each frame.
+ //Application.Current.Host.Settings.EnableRedrawRegions = true;
+
+ // Enable non-production analysis visualization mode,
+ // which shows areas of a page that are being GPU accelerated with a colored overlay.
+ //Application.Current.Host.Settings.EnableCacheVisualization = true;
+ }
+
+ // Standard Silverlight initialization
+ InitializeComponent();
+
+ // Phone-specific initialization
+ InitializePhoneApplication();
+ }
+
+ // Code to execute when the application is launching (eg, from Start)
+ // This code will not execute when the application is reactivated
+ private void Application_Launching(object sender, LaunchingEventArgs e)
+ {
+ }
+
+ // Code to execute when the application is activated (brought to foreground)
+ // This code will not execute when the application is first launched
+ private void Application_Activated(object sender, ActivatedEventArgs e)
+ {
+ }
+
+ // Code to execute when the application is deactivated (sent to background)
+ // This code will not execute when the application is closing
+ private void Application_Deactivated(object sender, DeactivatedEventArgs e)
+ {
+ }
+
+ // Code to execute when the application is closing (eg, user hit Back)
+ // This code will not execute when the application is deactivated
+ private void Application_Closing(object sender, ClosingEventArgs e)
+ {
+ }
+
+ // Code to execute if a navigation fails
+ private void RootFrame_NavigationFailed(object sender, NavigationFailedEventArgs e)
+ {
+ if (System.Diagnostics.Debugger.IsAttached)
+ {
+ // A navigation has failed; break into the debugger
+ System.Diagnostics.Debugger.Break();
+ }
+ }
+
+ // Code to execute on Unhandled Exceptions
+ private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
+ {
+ if (System.Diagnostics.Debugger.IsAttached)
+ {
+ // An unhandled exception has occurred; break into the debugger
+ System.Diagnostics.Debugger.Break();
+ }
+ }
+
+ #region Phone application initialization
+
+ // Avoid double-initialization
+ private bool phoneApplicationInitialized = false;
+
+ // Do not add any additional code to this method
+ private void InitializePhoneApplication()
+ {
+ if (phoneApplicationInitialized)
+ return;
+
+ // Create the frame but don't set it as RootVisual yet; this allows the splash
+ // screen to remain active until the application is ready to render.
+ RootFrame = new PhoneApplicationFrame();
+ RootFrame.Navigated += CompleteInitializePhoneApplication;
+
+ // Handle navigation failures
+ RootFrame.NavigationFailed += RootFrame_NavigationFailed;
+
+ // Ensure we don't initialize again
+ phoneApplicationInitialized = true;
+ }
+
+ // Do not add any additional code to this method
+ private void CompleteInitializePhoneApplication(object sender, NavigationEventArgs e)
+ {
+ // Set the root visual to allow the application to render
+ if (RootVisual != RootFrame)
+ RootVisual = RootFrame;
+
+ // Remove this handler since it is no longer needed
+ RootFrame.Navigated -= CompleteInitializePhoneApplication;
+ }
+
+ #endregion
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/ApplicationIcon.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/ApplicationIcon.png b/lib/cordova-wp8/templates/standalone/ApplicationIcon.png
new file mode 100644
index 0000000..6b69046
Binary files /dev/null and b/lib/cordova-wp8/templates/standalone/ApplicationIcon.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Background.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Background.png b/lib/cordova-wp8/templates/standalone/Background.png
new file mode 100644
index 0000000..2667df4
Binary files /dev/null and b/lib/cordova-wp8/templates/standalone/Background.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/CordovaAppProj.csproj
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/CordovaAppProj.csproj b/lib/cordova-wp8/templates/standalone/CordovaAppProj.csproj
new file mode 100644
index 0000000..23e4eef
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/CordovaAppProj.csproj
@@ -0,0 +1,228 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>10.0.20506</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{3677C1B7-D68B-4CF9-BF8A-E869D437A6DF}</ProjectGuid>
+ <ProjectTypeGuids>{C089C8C0-30E0-4E22-80C0-CE093F111A43};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>$safeprojectname$</RootNamespace>
+ <AssemblyName>$safeprojectname$</AssemblyName>
+ <TargetFrameworkVersion>v8.0</TargetFrameworkVersion>
+ <SilverlightVersion>
+ </SilverlightVersion>
+ <TargetFrameworkProfile>
+ </TargetFrameworkProfile>
+ <TargetFrameworkIdentifier>WindowsPhone</TargetFrameworkIdentifier>
+ <SilverlightApplication>true</SilverlightApplication>
+ <SupportedCultures>en-US</SupportedCultures>
+ <XapOutputs>true</XapOutputs>
+ <GenerateSilverlightManifest>true</GenerateSilverlightManifest>
+ <XapFilename>CordovaAppProj_$(Configuration)_$(Platform).xap</XapFilename>
+ <SilverlightManifestTemplate>Properties\AppManifest.xml</SilverlightManifestTemplate>
+ <SilverlightAppEntry>$safeprojectname$.App</SilverlightAppEntry>
+ <ValidateXaml>true</ValidateXaml>
+ <ThrowErrorsInValidation>true</ThrowErrorsInValidation>
+ <MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
+ <BackgroundAgentType />
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>Bin\Debug</OutputPath>
+ <DefineConstants>DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <Prefer32Bit>false</Prefer32Bit>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>Bin\Release</OutputPath>
+ <DefineConstants>TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <Prefer32Bit>false</Prefer32Bit>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
+ <DebugSymbols>true</DebugSymbols>
+ <OutputPath>Bin\x86\Debug</OutputPath>
+ <DefineConstants>DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <DebugType>full</DebugType>
+ <PlatformTarget>
+ </PlatformTarget>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>ManagedMinimumRules.ruleset</CodeAnalysisRuleSet>
+ <Optimize>false</Optimize>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
+ <OutputPath>Bin\x86\Release</OutputPath>
+ <DefineConstants>TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
+ <Optimize>true</Optimize>
+ <NoStdLib>true</NoStdLib>
+ <DebugType>pdbonly</DebugType>
+ <PlatformTarget>
+ </PlatformTarget>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>ManagedMinimumRules.ruleset</CodeAnalysisRuleSet>
+ <Prefer32Bit>false</Prefer32Bit>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
+ <DebugSymbols>true</DebugSymbols>
+ <OutputPath>Bin\ARM\Debug</OutputPath>
+ <DefineConstants>DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <DebugType>full</DebugType>
+ <PlatformTarget>
+ </PlatformTarget>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>ManagedMinimumRules.ruleset</CodeAnalysisRuleSet>
+ <Prefer32Bit>false</Prefer32Bit>
+ <Optimize>false</Optimize>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
+ <OutputPath>Bin\ARM\Release</OutputPath>
+ <DefineConstants>TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
+ <Optimize>true</Optimize>
+ <NoStdLib>true</NoStdLib>
+ <DebugType>pdbonly</DebugType>
+ <PlatformTarget>
+ </PlatformTarget>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>ManagedMinimumRules.ruleset</CodeAnalysisRuleSet>
+ <Prefer32Bit>false</Prefer32Bit>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="App.xaml.cs">
+ <DependentUpon>App.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="cordovalib\BrowserMouseHelper.cs" />
+ <Compile Include="cordovalib\CommandFactory.cs" />
+ <Compile Include="cordovalib\Commands\BaseCommand.cs" />
+ <Compile Include="cordovalib\ConfigHandler.cs" />
+ <Compile Include="cordovalib\CordovaCommandCall.cs" />
+ <Compile Include="cordovalib\CordovaView.xaml.cs">
+ <DependentUpon>CordovaView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="cordovalib\DOMStorageHelper.cs" />
+ <Compile Include="cordovalib\JSON\JsonHelper.cs" />
+ <Compile Include="cordovalib\NativeExecution.cs" />
+ <Compile Include="cordovalib\OrientationHelper.cs" />
+ <Compile Include="cordovalib\PluginResult.cs" />
+ <Compile Include="cordovalib\ScriptCallback.cs" />
+
+ <Compile Include="MainPage.xaml.cs">
+ <DependentUpon>MainPage.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ApplicationDefinition Include="App.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </ApplicationDefinition>
+ <Page Include="cordovalib\CordovaView.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+
+ <Page Include="Plugins\UI\AudioRecorder.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="Plugins\UI\ImageCapture.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="Plugins\UI\NotificationBox.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="Plugins\UI\VideoRecorder.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="MainPage.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
+ </ItemGroup>
+
+ <ItemGroup>
+ <Content Include="www\**" />
+ <Content Include="config.xml" />
+ <Content Include="Images\**" />
+
+ <Content Include="resources\notification-beep.wav" />
+ <None Include="VERSION" />
+
+ <None Include="Properties\AppManifest.xml">
+ <SubType>Designer</SubType>
+ </None>
+ <None Include="Properties\WMAppManifest.xml">
+ <SubType>Designer</SubType>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <Content Include="ApplicationIcon.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="Background.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="SplashScreenImage.jpg" />
+ </ItemGroup>
+ <ItemGroup>
+ <WCFMetadata Include="Service References\" />
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Plugins\*" />
+ <Compile Include="Plugins\UI\*.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildExtensionsPath)\Microsoft\$(TargetFrameworkIdentifier)\$(TargetFrameworkVersion)\Microsoft.$(TargetFrameworkIdentifier).$(TargetFrameworkVersion).Overrides.targets" />
+ <Import Project="$(MSBuildExtensionsPath)\Microsoft\$(TargetFrameworkIdentifier)\$(TargetFrameworkVersion)\Microsoft.$(TargetFrameworkIdentifier).CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+ <ProjectExtensions />
+ <PropertyGroup>
+ </PropertyGroup>
+ <PropertyGroup>
+ <PostBuildEvent>
+ </PostBuildEvent>
+ </PropertyGroup>
+</Project>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/CordovaSolution.sln
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/CordovaSolution.sln b/lib/cordova-wp8/templates/standalone/CordovaSolution.sln
new file mode 100644
index 0000000..58c0e62
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/CordovaSolution.sln
@@ -0,0 +1,30 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Express 2012 for Windows Phone
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CordovaAppProj", "CordovaAppProj.csproj", "{3677C1B7-D68B-4CF9-BF8A-E869D437A6DF}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|ARM = Debug|ARM
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|ARM = Release|ARM
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {3677C1B7-D68B-4CF9-BF8A-E869D437A6DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3677C1B7-D68B-4CF9-BF8A-E869D437A6DF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3677C1B7-D68B-4CF9-BF8A-E869D437A6DF}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {3677C1B7-D68B-4CF9-BF8A-E869D437A6DF}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {3677C1B7-D68B-4CF9-BF8A-E869D437A6DF}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {3677C1B7-D68B-4CF9-BF8A-E869D437A6DF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3677C1B7-D68B-4CF9-BF8A-E869D437A6DF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3677C1B7-D68B-4CF9-BF8A-E869D437A6DF}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {3677C1B7-D68B-4CF9-BF8A-E869D437A6DF}.Release|ARM.ActiveCfg = Release|Any CPU
+ {3677C1B7-D68B-4CF9-BF8A-E869D437A6DF}.Release|x86.ActiveCfg = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Images/appbar.back.rest.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Images/appbar.back.rest.png b/lib/cordova-wp8/templates/standalone/Images/appbar.back.rest.png
new file mode 100644
index 0000000..4bc2b92
Binary files /dev/null and b/lib/cordova-wp8/templates/standalone/Images/appbar.back.rest.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Images/appbar.close.rest.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Images/appbar.close.rest.png b/lib/cordova-wp8/templates/standalone/Images/appbar.close.rest.png
new file mode 100644
index 0000000..8166a1c
Binary files /dev/null and b/lib/cordova-wp8/templates/standalone/Images/appbar.close.rest.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Images/appbar.feature.video.rest.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Images/appbar.feature.video.rest.png b/lib/cordova-wp8/templates/standalone/Images/appbar.feature.video.rest.png
new file mode 100644
index 0000000..baff565
Binary files /dev/null and b/lib/cordova-wp8/templates/standalone/Images/appbar.feature.video.rest.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Images/appbar.next.rest.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Images/appbar.next.rest.png b/lib/cordova-wp8/templates/standalone/Images/appbar.next.rest.png
new file mode 100644
index 0000000..ed577d7
Binary files /dev/null and b/lib/cordova-wp8/templates/standalone/Images/appbar.next.rest.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Images/appbar.save.rest.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Images/appbar.save.rest.png b/lib/cordova-wp8/templates/standalone/Images/appbar.save.rest.png
new file mode 100644
index 0000000..d49940e
Binary files /dev/null and b/lib/cordova-wp8/templates/standalone/Images/appbar.save.rest.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Images/appbar.stop.rest.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Images/appbar.stop.rest.png b/lib/cordova-wp8/templates/standalone/Images/appbar.stop.rest.png
new file mode 100644
index 0000000..4dd724f
Binary files /dev/null and b/lib/cordova-wp8/templates/standalone/Images/appbar.stop.rest.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/MainPage.xaml
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/MainPage.xaml b/lib/cordova-wp8/templates/standalone/MainPage.xaml
new file mode 100644
index 0000000..db0d8e6
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/MainPage.xaml
@@ -0,0 +1,53 @@
+<!--
+ 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.
+-->
+<phone:PhoneApplicationPage
+ x:Class="$safeprojectname$.MainPage"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
+ xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
+ 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}"
+ Background="Black"
+ SupportedOrientations="PortraitOrLandscape" Orientation="Portrait"
+ shell:SystemTray.IsVisible="True" d:DesignHeight="768" d:DesignWidth="480"
+ xmlns:my="clr-namespace:WPCordovaClassLib">
+ <Grid x:Name="LayoutRoot" Background="Transparent" HorizontalAlignment="Stretch">
+ <Grid.RowDefinitions>
+ <RowDefinition Height="*"/>
+ </Grid.RowDefinitions>
+ <my:CordovaView HorizontalAlignment="Stretch"
+ Margin="0,0,0,0"
+ x:Name="CordovaView"
+ VerticalAlignment="Stretch" />
+ <Image Source="SplashScreenImage.jpg"
+ x:Name="SplashImage"
+ VerticalAlignment="Center"
+ HorizontalAlignment="Stretch">
+ <Image.Projection>
+ <PlaneProjection x:Name="SplashProjector" CenterOfRotationX="0"/>
+ </Image.Projection>
+ </Image>
+ </Grid>
+
+</phone:PhoneApplicationPage>
+
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/MainPage.xaml.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/MainPage.xaml.cs b/lib/cordova-wp8/templates/standalone/MainPage.xaml.cs
new file mode 100644
index 0000000..b9ec7e1
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/MainPage.xaml.cs
@@ -0,0 +1,72 @@
+/*
+ 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.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;
+using System.Windows.Media.Imaging;
+using System.Windows.Resources;
+
+
+namespace $safeprojectname$
+{
+ public partial class MainPage : PhoneApplicationPage
+ {
+ // Constructor
+ public MainPage()
+ {
+ InitializeComponent();
+ this.CordovaView.Loaded += CordovaView_Loaded;
+ }
+
+ private void CordovaView_Loaded(object sender, RoutedEventArgs e)
+ {
+ this.CordovaView.Loaded -= CordovaView_Loaded;
+ // first time load will have an animation
+ Storyboard _storyBoard = new Storyboard();
+ DoubleAnimation animation = new DoubleAnimation()
+ {
+ From = 0,
+ Duration = TimeSpan.FromSeconds(0.6),
+ To = 90
+ };
+ Storyboard.SetTarget(animation, SplashProjector);
+ Storyboard.SetTargetProperty(animation, new PropertyPath("RotationY"));
+ _storyBoard.Children.Add(animation);
+ _storyBoard.Begin();
+ _storyBoard.Completed += Splash_Completed;
+ }
+
+ void Splash_Completed(object sender, EventArgs e)
+ {
+ (sender as Storyboard).Completed -= Splash_Completed;
+ LayoutRoot.Children.Remove(SplashImage);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/Accelerometer.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/Accelerometer.cs b/lib/cordova-wp8/templates/standalone/Plugins/Accelerometer.cs
new file mode 100644
index 0000000..cba911c
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/Accelerometer.cs
@@ -0,0 +1,196 @@
+/*
+ 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.Runtime.Serialization;
+using System.Threading;
+using Microsoft.Devices.Sensors;
+using System.Globalization;
+using System.Diagnostics;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ /// <summary>
+ /// Captures device motion in the x, y, and z direction.
+ /// </summary>
+ public class Accelerometer : BaseCommand
+ {
+ #region AccelerometerOptions class
+ /// <summary>
+ /// Represents Accelerometer options.
+ /// </summary>
+ [DataContract]
+ public class AccelerometerOptions
+ {
+ /// <summary>
+ /// How often to retrieve the Acceleration in milliseconds
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "frequency")]
+ public int Frequency { get; set; }
+
+ /// <summary>
+ /// Watcher id
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "id")]
+ public string Id { get; set; }
+
+ /// <summary>
+ /// Creates options object with default parameters
+ /// </summary>
+ public AccelerometerOptions()
+ {
+ this.SetDefaultValues(new StreamingContext());
+ }
+
+ /// <summary>
+ /// Initializes default values for class fields.
+ /// Implemented in separate method because default constructor is not invoked during deserialization.
+ /// </summary>
+ /// <param name="context"></param>
+ [OnDeserializing()]
+ public void SetDefaultValues(StreamingContext context)
+ {
+ this.Frequency = 10000;
+ }
+ }
+
+ #endregion
+
+ #region Status codes and Constants
+
+ public const int Stopped = 0;
+ public const int Starting = 1;
+ public const int Running = 2;
+ public const int ErrorFailedToStart = 3;
+
+ public const double gConstant = -9.81;
+
+ #endregion
+
+ #region Static members
+
+ /// <summary>
+ /// Status of listener
+ /// </summary>
+ private static int currentStatus;
+
+ /// <summary>
+ /// Accelerometer
+ /// </summary>
+ private static Microsoft.Devices.Sensors.Accelerometer accelerometer = new Microsoft.Devices.Sensors.Accelerometer();
+
+ private static DateTime StartOfEpoch = new DateTime(1970, 1, 1, 0, 0, 0);
+
+ #endregion
+
+ /// <summary>
+ /// Sensor listener event
+ /// </summary>
+ private void accelerometer_CurrentValueChanged(object sender, SensorReadingEventArgs<AccelerometerReading> e)
+ {
+ this.SetStatus(Running);
+
+ PluginResult result = new PluginResult(PluginResult.Status.OK, GetCurrentAccelerationFormatted());
+ result.KeepCallback = true;
+ DispatchCommandResult(result);
+ }
+
+ /// <summary>
+ /// Starts listening for acceleration sensor
+ /// </summary>
+ /// <returns>status of listener</returns>
+ public void start(string options)
+ {
+ if ((currentStatus == Running) || (currentStatus == Starting))
+ {
+ return;
+ }
+ try
+ {
+ lock (accelerometer)
+ {
+ accelerometer.CurrentValueChanged += accelerometer_CurrentValueChanged;
+ accelerometer.Start();
+ this.SetStatus(Starting);
+ }
+
+ long timeout = 2000;
+ while ((currentStatus == Starting) && (timeout > 0))
+ {
+ timeout = timeout - 100;
+ Thread.Sleep(100);
+ }
+
+ if (currentStatus != Running)
+ {
+ this.SetStatus(ErrorFailedToStart);
+ DispatchCommandResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, ErrorFailedToStart));
+ return;
+ }
+ }
+ catch (Exception)
+ {
+ this.SetStatus(ErrorFailedToStart);
+ DispatchCommandResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, ErrorFailedToStart));
+ return;
+ }
+ PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT);
+ result.KeepCallback = true;
+ DispatchCommandResult(result);
+ }
+
+ public void stop(string options)
+ {
+ if (currentStatus == Running)
+ {
+ lock (accelerometer)
+ {
+ accelerometer.CurrentValueChanged -= accelerometer_CurrentValueChanged;
+ accelerometer.Stop();
+ this.SetStatus(Stopped);
+ }
+ }
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+ }
+
+ /// <summary>
+ /// Formats current coordinates into JSON format
+ /// </summary>
+ /// <returns>Coordinates in JSON format</returns>
+ private string GetCurrentAccelerationFormatted()
+ {
+ // convert to unix timestamp
+ // long timestamp = ((accelerometer.CurrentValue.Timestamp.DateTime - StartOfEpoch).Ticks) / 10000;
+ // Note: Removed timestamp, to let the JS side create it using (new Date().getTime()) -jm
+ // this resolves an issue with inconsistencies between JS dates and Native DateTime
+ string resultCoordinates = String.Format("\"x\":{0},\"y\":{1},\"z\":{2}",
+ (accelerometer.CurrentValue.Acceleration.X * gConstant).ToString("0.00000", CultureInfo.InvariantCulture),
+ (accelerometer.CurrentValue.Acceleration.Y * gConstant).ToString("0.00000", CultureInfo.InvariantCulture),
+ (accelerometer.CurrentValue.Acceleration.Z * gConstant).ToString("0.00000", CultureInfo.InvariantCulture));
+ return "{" + resultCoordinates + "}";
+ }
+
+ /// <summary>
+ /// Sets current status
+ /// </summary>
+ /// <param name="status">current status</param>
+ private void SetStatus(int status)
+ {
+ currentStatus = status;
+ }
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/AudioFormatsHelper.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/AudioFormatsHelper.cs b/lib/cordova-wp8/templates/standalone/Plugins/AudioFormatsHelper.cs
new file mode 100644
index 0000000..dca7ee6
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/AudioFormatsHelper.cs
@@ -0,0 +1,89 @@
+/*
+ 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.IO;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ /// <summary>
+ /// Provides extra functionality to support different audio formats.
+ /// </summary>
+ public static class AudioFormatsHelper
+ {
+ #region Wav
+ /// <summary>
+ /// Adds wav file format header to the stream
+ /// https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
+ /// </summary>
+ /// <param name="stream">The stream</param>
+ /// <param name="sampleRate">Sample Rate</param>
+ public static void InitializeWavStream(this Stream stream, int sampleRate)
+ {
+ #region args checking
+
+ if (stream == null)
+ {
+ throw new ArgumentNullException("stream can't be null or empty");
+ }
+
+ #endregion
+
+ int numBits = 16;
+ int numBytes = numBits / 8;
+
+ stream.Write(System.Text.Encoding.UTF8.GetBytes("RIFF"), 0, 4);
+ stream.Write(BitConverter.GetBytes(0), 0, 4);
+ stream.Write(System.Text.Encoding.UTF8.GetBytes("WAVE"), 0, 4);
+ stream.Write(System.Text.Encoding.UTF8.GetBytes("fmt "), 0, 4);
+ stream.Write(BitConverter.GetBytes(16), 0, 4);
+ stream.Write(BitConverter.GetBytes((short)1), 0, 2);
+ stream.Write(BitConverter.GetBytes((short)1), 0, 2);
+ stream.Write(BitConverter.GetBytes(sampleRate), 0, 4);
+ stream.Write(BitConverter.GetBytes(sampleRate * numBytes), 0, 4);
+ stream.Write(BitConverter.GetBytes((short)(numBytes)), 0, 2);
+ stream.Write(BitConverter.GetBytes((short)(numBits)), 0, 2);
+ stream.Write(System.Text.Encoding.UTF8.GetBytes("data"), 0, 4);
+ stream.Write(BitConverter.GetBytes(0), 0, 4);
+ }
+
+ /// <summary>
+ /// Updates wav file format header
+ /// https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
+ /// </summary>
+ /// <param name="stream">Wav stream</param>
+ public static void UpdateWavStream(this Stream stream)
+ {
+ #region args checking
+
+ if (stream == null)
+ {
+ throw new ArgumentNullException("stream can't be null or empty");
+ }
+
+ #endregion
+
+ var position = stream.Position;
+
+ stream.Seek(4, SeekOrigin.Begin);
+ stream.Write(BitConverter.GetBytes((int)stream.Length - 8), 0, 4);
+ stream.Seek(40, SeekOrigin.Begin);
+ stream.Write(BitConverter.GetBytes((int)stream.Length - 44), 0, 4);
+ stream.Seek(position, SeekOrigin.Begin);
+ }
+
+ #endregion
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/AudioPlayer.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/AudioPlayer.cs b/lib/cordova-wp8/templates/standalone/Plugins/AudioPlayer.cs
new file mode 100644
index 0000000..a83be5b
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/AudioPlayer.cs
@@ -0,0 +1,620 @@
+/*
+ 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.IO;
+using System.IO.IsolatedStorage;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Threading;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Audio;
+using Microsoft.Xna.Framework.Media;
+using Microsoft.Phone.Controls;
+using System.Diagnostics;
+using System.Windows.Resources;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ /// <summary>
+ /// Implements audio record and play back functionality.
+ /// </summary>
+ internal class AudioPlayer : IDisposable
+ {
+ #region Constants
+
+ // AudioPlayer states
+ private const int PlayerState_None = 0;
+ private const int PlayerState_Starting = 1;
+ private const int PlayerState_Running = 2;
+ private const int PlayerState_Paused = 3;
+ private const int PlayerState_Stopped = 4;
+
+ // AudioPlayer messages
+ private const int MediaState = 1;
+ private const int MediaDuration = 2;
+ private const int MediaPosition = 3;
+ private const int MediaError = 9;
+
+ // AudioPlayer errors
+ private const int MediaErrorPlayModeSet = 1;
+ private const int MediaErrorAlreadyRecording = 2;
+ private const int MediaErrorStartingRecording = 3;
+ private const int MediaErrorRecordModeSet = 4;
+ private const int MediaErrorStartingPlayback = 5;
+ private const int MediaErrorResumeState = 6;
+ private const int MediaErrorPauseState = 7;
+ private const int MediaErrorStopState = 8;
+
+ //TODO: get rid of this callback, it should be universal
+ //private const string CallbackFunction = "CordovaMediaonStatus";
+
+ #endregion
+
+ /// <summary>
+ /// The AudioHandler object
+ /// </summary>
+ private Media handler;
+
+ /// <summary>
+ /// Temporary buffer to store audio chunk
+ /// </summary>
+ private byte[] buffer;
+
+ /// <summary>
+ /// Xna game loop dispatcher
+ /// </summary>
+ DispatcherTimer dtXna;
+
+ /// <summary>
+ /// Output buffer
+ /// </summary>
+ private MemoryStream memoryStream;
+
+ /// <summary>
+ /// The id of this player (used to identify Media object in JavaScript)
+ /// </summary>
+ private String id;
+
+ /// <summary>
+ /// State of recording or playback
+ /// </summary>
+ private int state = PlayerState_None;
+
+ /// <summary>
+ /// File name to play or record to
+ /// </summary>
+ private String audioFile = null;
+
+ /// <summary>
+ /// Duration of audio
+ /// </summary>
+ private double duration = -1;
+
+ /// <summary>
+ /// Audio player object
+ /// </summary>
+ private MediaElement player = null;
+
+ /// <summary>
+ /// Audio source
+ /// </summary>
+ private Microphone recorder;
+
+ /// <summary>
+ /// Internal flag specified that we should only open audio w/o playing it
+ /// </summary>
+ private bool prepareOnly = false;
+
+ /// <summary>
+ /// Creates AudioPlayer instance
+ /// </summary>
+ /// <param name="handler">Media object</param>
+ /// <param name="id">player id</param>
+ public AudioPlayer(Media handler, String id)
+ {
+ this.handler = handler;
+ this.id = id;
+ }
+
+ /// <summary>
+ /// Destroys player and stop audio playing or recording
+ /// </summary>
+ public void Dispose()
+ {
+ if (this.player != null)
+ {
+ this.stopPlaying();
+ this.player = null;
+ }
+ if (this.recorder != null)
+ {
+ this.stopRecording();
+ this.recorder = null;
+ }
+
+ this.FinalizeXnaGameLoop();
+ }
+
+ private void InvokeCallback(int message, string value, bool removeHandler)
+ {
+ string args = string.Format("('{0}',{1},{2});", this.id, message, value);
+ string callback = @"(function(id,msg,value){
+ try {
+ if (msg == Media.MEDIA_ERROR) {
+ value = {'code':value};
+ }
+ Media.onStatus(id,msg,value);
+ }
+ catch(e) {
+ console.log('Error calling Media.onStatus :: ' + e);
+ }
+ })" + args;
+ this.handler.InvokeCustomScript(new ScriptCallback("eval", new string[] { callback }), false);
+ }
+
+ private void InvokeCallback(int message, int value, bool removeHandler)
+ {
+ InvokeCallback(message, value.ToString(), removeHandler);
+ }
+
+ private void InvokeCallback(int message, double value, bool removeHandler)
+ {
+ InvokeCallback(message, value.ToString(), removeHandler);
+ }
+
+ /// <summary>
+ /// Starts recording, data is stored in memory
+ /// </summary>
+ /// <param name="filePath"></param>
+ public void startRecording(string filePath)
+ {
+ if (this.player != null)
+ {
+ InvokeCallback(MediaError, MediaErrorPlayModeSet, false);
+ }
+ else if (this.recorder == null)
+ {
+ try
+ {
+ this.audioFile = filePath;
+ this.InitializeXnaGameLoop();
+ this.recorder = Microphone.Default;
+ this.recorder.BufferDuration = TimeSpan.FromMilliseconds(500);
+ this.buffer = new byte[recorder.GetSampleSizeInBytes(this.recorder.BufferDuration)];
+ this.recorder.BufferReady += new EventHandler<EventArgs>(recorderBufferReady);
+ this.memoryStream = new MemoryStream();
+ this.memoryStream.InitializeWavStream(this.recorder.SampleRate);
+ this.recorder.Start();
+ FrameworkDispatcher.Update();
+ this.SetState(PlayerState_Running);
+ }
+ catch (Exception)
+ {
+ InvokeCallback(MediaError, MediaErrorStartingRecording, false);
+ //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaError, MediaErrorStartingRecording),false);
+ }
+ }
+ else
+ {
+ InvokeCallback(MediaError, MediaErrorAlreadyRecording, false);
+ //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaError, MediaErrorAlreadyRecording),false);
+ }
+ }
+
+ /// <summary>
+ /// Stops recording
+ /// </summary>
+ public void stopRecording()
+ {
+ if (this.recorder != null)
+ {
+ if (this.state == PlayerState_Running)
+ {
+ try
+ {
+ this.recorder.Stop();
+ this.recorder.BufferReady -= recorderBufferReady;
+ this.recorder = null;
+ SaveAudioClipToLocalStorage();
+ this.FinalizeXnaGameLoop();
+ this.SetState(PlayerState_Stopped);
+ }
+ catch (Exception)
+ {
+ //TODO
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Starts or resume playing audio file
+ /// </summary>
+ /// <param name="filePath">The name of the audio file</param>
+ /// <summary>
+ /// Starts or resume playing audio file
+ /// </summary>
+ /// <param name="filePath">The name of the audio file</param>
+ public void startPlaying(string filePath)
+ {
+ if (this.recorder != null)
+ {
+ InvokeCallback(MediaError, MediaErrorRecordModeSet, false);
+ //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaError, MediaErrorRecordModeSet),false);
+ return;
+ }
+
+
+ if (this.player == null || this.player.Source.AbsolutePath.LastIndexOf(filePath) < 0)
+ {
+ try
+ {
+ // this.player is a MediaElement, it must be added to the visual tree in order to play
+ PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
+ if (frame != null)
+ {
+ PhoneApplicationPage page = frame.Content as PhoneApplicationPage;
+ if (page != null)
+ {
+ Grid grid = page.FindName("LayoutRoot") as Grid;
+ if (grid != null)
+ {
+
+ this.player = grid.FindName("playerMediaElement") as MediaElement;
+ if (this.player == null) // still null ?
+ {
+ this.player = new MediaElement();
+ this.player.Name = "playerMediaElement";
+ grid.Children.Add(this.player);
+ this.player.Visibility = Visibility.Visible;
+ }
+ if (this.player.CurrentState == System.Windows.Media.MediaElementState.Playing)
+ {
+ this.player.Stop(); // stop it!
+ }
+
+ this.player.Source = null; // Garbage collect it.
+ this.player.MediaOpened += MediaOpened;
+ this.player.MediaEnded += MediaEnded;
+ this.player.MediaFailed += MediaFailed;
+ }
+ }
+ }
+
+ this.audioFile = filePath;
+
+ Uri uri = new Uri(filePath, UriKind.RelativeOrAbsolute);
+ if (uri.IsAbsoluteUri)
+ {
+ this.player.Source = uri;
+ }
+ else
+ {
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ if (!isoFile.FileExists(filePath))
+ {
+ // try to unpack it from the dll into isolated storage
+ StreamResourceInfo fileResourceStreamInfo = Application.GetResourceStream(new Uri(filePath, UriKind.Relative));
+ if (fileResourceStreamInfo != null)
+ {
+ using (BinaryReader br = new BinaryReader(fileResourceStreamInfo.Stream))
+ {
+ byte[] data = br.ReadBytes((int)fileResourceStreamInfo.Stream.Length);
+
+ string[] dirParts = filePath.Split('/');
+ string dirName = "";
+ for (int n = 0; n < dirParts.Length - 1; n++)
+ {
+ dirName += dirParts[n] + "/";
+ }
+ if (!isoFile.DirectoryExists(dirName))
+ {
+ isoFile.CreateDirectory(dirName);
+ }
+
+ using (IsolatedStorageFileStream outFile = isoFile.OpenFile(filePath, FileMode.Create))
+ {
+ using (BinaryWriter writer = new BinaryWriter(outFile))
+ {
+ writer.Write(data);
+ }
+ }
+ }
+ }
+ }
+ if (isoFile.FileExists(filePath))
+ {
+ using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(filePath, FileMode.Open, isoFile))
+ {
+ this.player.SetSource(stream);
+ }
+ }
+ else
+ {
+ InvokeCallback(MediaError, MediaErrorPlayModeSet, false);
+ //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaError, 1), false);
+ return;
+ }
+ }
+ }
+ this.SetState(PlayerState_Starting);
+ }
+ catch (Exception e)
+ {
+ Debug.WriteLine("Error in AudioPlayer::startPlaying : " + e.Message);
+ InvokeCallback(MediaError, MediaErrorStartingPlayback, false);
+ //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaError, MediaErrorStartingPlayback),false);
+ }
+ }
+ else
+ {
+ if (this.state != PlayerState_Running)
+ {
+ this.player.Play();
+ this.SetState(PlayerState_Running);
+ }
+ else
+ {
+ InvokeCallback(MediaError, MediaErrorResumeState, false);
+ //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaError, MediaErrorResumeState),false);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Callback to be invoked when the media source is ready for playback
+ /// </summary>
+ private void MediaOpened(object sender, RoutedEventArgs arg)
+ {
+ if (this.player != null)
+ {
+ this.duration = this.player.NaturalDuration.TimeSpan.TotalSeconds;
+ InvokeCallback(MediaDuration, this.duration, false);
+ //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaDuration, this.duration),false);
+ if (!this.prepareOnly)
+ {
+ this.player.Play();
+ this.SetState(PlayerState_Running);
+ }
+ this.prepareOnly = false;
+ }
+ else
+ {
+ // TODO: occasionally MediaOpened is signalled, but player is null
+ }
+ }
+
+ /// <summary>
+ /// Callback to be invoked when playback of a media source has completed
+ /// </summary>
+ private void MediaEnded(object sender, RoutedEventArgs arg)
+ {
+ this.SetState(PlayerState_Stopped);
+ }
+
+ /// <summary>
+ /// Callback to be invoked when playback of a media source has failed
+ /// </summary>
+ private void MediaFailed(object sender, RoutedEventArgs arg)
+ {
+ player.Stop();
+ InvokeCallback(MediaError, MediaErrorStartingPlayback, false);
+ //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaError.ToString(), "Media failed"),false);
+ }
+
+ /// <summary>
+ /// Seek or jump to a new time in the track
+ /// </summary>
+ /// <param name="milliseconds">The new track position</param>
+ public void seekToPlaying(int milliseconds)
+ {
+ if (this.player != null)
+ {
+ TimeSpan tsPos = new TimeSpan(0, 0, 0, 0, milliseconds);
+ this.player.Position = tsPos;
+ InvokeCallback(MediaPosition, milliseconds / 1000.0f, false);
+ //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaPosition, milliseconds / 1000.0f),false);
+ }
+ }
+
+ /// <summary>
+ /// Set the volume of the player
+ /// </summary>
+ /// <param name="vol">volume 0.0-1.0, default value is 0.5</param>
+ public void setVolume(double vol)
+ {
+ if (this.player != null)
+ {
+ this.player.Volume = vol;
+ }
+ }
+
+ /// <summary>
+ /// Pauses playing
+ /// </summary>
+ public void pausePlaying()
+ {
+ if (this.state == PlayerState_Running)
+ {
+ this.player.Pause();
+ this.SetState(PlayerState_Paused);
+ }
+ else
+ {
+ InvokeCallback(MediaError, MediaErrorPauseState, false);
+ //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaError, MediaErrorPauseState),false);
+ }
+ }
+
+
+ /// <summary>
+ /// Stops playing the audio file
+ /// </summary>
+ public void stopPlaying()
+ {
+ if ((this.state == PlayerState_Running) || (this.state == PlayerState_Paused))
+ {
+ this.player.Stop();
+
+ this.player.Position = new TimeSpan(0L);
+ this.SetState(PlayerState_Stopped);
+ }
+ //else // Why is it an error to call stop on a stopped media?
+ //{
+ // this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaError, MediaErrorStopState), false);
+ //}
+ }
+
+ /// <summary>
+ /// Gets current position of playback
+ /// </summary>
+ /// <returns>current position</returns>
+ public double getCurrentPosition()
+ {
+ if ((this.state == PlayerState_Running) || (this.state == PlayerState_Paused))
+ {
+ double currentPosition = this.player.Position.TotalSeconds;
+ //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaPosition, currentPosition),false);
+ return currentPosition;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ /// <summary>
+ /// Gets the duration of the audio file
+ /// </summary>
+ /// <param name="filePath">The name of the audio file</param>
+ /// <returns>track duration</returns>
+ public double getDuration(string filePath)
+ {
+ if (this.recorder != null)
+ {
+ return (-2);
+ }
+
+ if (this.player != null)
+ {
+ return this.duration;
+
+ }
+ else
+ {
+ this.prepareOnly = true;
+ this.startPlaying(filePath);
+ return this.duration;
+ }
+ }
+
+ /// <summary>
+ /// Sets the state and send it to JavaScript
+ /// </summary>
+ /// <param name="state">state</param>
+ private void SetState(int state)
+ {
+ if (this.state != state)
+ {
+ InvokeCallback(MediaState, state, false);
+ //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaState, state),false);
+ }
+
+ this.state = state;
+ }
+
+ #region record methods
+
+ /// <summary>
+ /// Copies data from recorder to memory storages and updates recording state
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="e"></param>
+ private void recorderBufferReady(object sender, EventArgs e)
+ {
+ this.recorder.GetData(this.buffer);
+ this.memoryStream.Write(this.buffer, 0, this.buffer.Length);
+ }
+
+ /// <summary>
+ /// Writes audio data from memory to isolated storage
+ /// </summary>
+ /// <returns></returns>
+ private void SaveAudioClipToLocalStorage()
+ {
+ if (this.memoryStream == null || this.memoryStream.Length <= 0)
+ {
+ return;
+ }
+
+ this.memoryStream.UpdateWavStream();
+
+ try
+ {
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ string directory = Path.GetDirectoryName(audioFile);
+
+ if (!isoFile.DirectoryExists(directory))
+ {
+ isoFile.CreateDirectory(directory);
+ }
+
+ this.memoryStream.Seek(0, SeekOrigin.Begin);
+
+ using (IsolatedStorageFileStream fileStream = isoFile.CreateFile(audioFile))
+ {
+ this.memoryStream.CopyTo(fileStream);
+ }
+ }
+ }
+ catch (Exception)
+ {
+ //TODO: log or do something else
+ throw;
+ }
+ }
+
+ #region Xna loop
+ /// <summary>
+ /// Special initialization required for the microphone: XNA game loop
+ /// </summary>
+ private void InitializeXnaGameLoop()
+ {
+ // Timer to simulate the XNA game loop (Microphone is from XNA)
+ this.dtXna = new DispatcherTimer();
+ this.dtXna.Interval = TimeSpan.FromMilliseconds(33);
+ this.dtXna.Tick += delegate { try { FrameworkDispatcher.Update(); } catch { } };
+ this.dtXna.Start();
+ }
+ /// <summary>
+ /// Finalizes XNA game loop for microphone
+ /// </summary>
+ private void FinalizeXnaGameLoop()
+ {
+ // Timer to simulate the XNA game loop (Microphone is from XNA)
+ if (this.dtXna != null)
+ {
+ this.dtXna.Stop();
+ this.dtXna = null;
+ }
+ }
+
+ #endregion
+
+ #endregion
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/Battery.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/Battery.cs b/lib/cordova-wp8/templates/standalone/Plugins/Battery.cs
new file mode 100644
index 0000000..962959e
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/Battery.cs
@@ -0,0 +1,79 @@
+/*
+ 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.Info;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ /// <summary>
+ /// Listens for changes to the state of the battery on the device.
+ /// Currently only the "isPlugged" parameter available via native APIs.
+ /// </summary>
+ public class Battery : BaseCommand
+ {
+ private bool isPlugged = false;
+ private EventHandler powerChanged;
+
+ public Battery()
+ {
+ powerChanged = new EventHandler(DeviceStatus_PowerSourceChanged);
+ isPlugged = DeviceStatus.PowerSource.ToString().CompareTo("External") == 0;
+ }
+
+ public void start(string options)
+ {
+ // Register power changed event handler
+ DeviceStatus.PowerSourceChanged += powerChanged;
+
+ PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT);
+ result.KeepCallback = true;
+ DispatchCommandResult(result);
+ }
+ public void stop(string options)
+ {
+ // Unregister power changed event handler
+ DeviceStatus.PowerSourceChanged -= powerChanged;
+ }
+
+ private void DeviceStatus_PowerSourceChanged(object sender, EventArgs e)
+ {
+ isPlugged = DeviceStatus.PowerSource.ToString().CompareTo("External") == 0;
+ PluginResult result = new PluginResult(PluginResult.Status.OK, GetCurrentBatteryStateFormatted());
+ result.KeepCallback = true;
+ DispatchCommandResult(result);
+ }
+
+ private string GetCurrentBatteryStateFormatted()
+ {
+ string batteryState = String.Format("\"level\":{0},\"isPlugged\":{1}",
+ "null",
+ isPlugged ? "true" : "false"
+ );
+ batteryState = "{" + batteryState + "}";
+ return batteryState;
+ }
+
+ }
+}
[18/37] Add WP7 and WP8 platform files.
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/Device.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/Device.cs b/lib/cordova-wp8/templates/standalone/Plugins/Device.cs
new file mode 100644
index 0000000..07100ae
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/Device.cs
@@ -0,0 +1,135 @@
+/*
+ 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.Info;
+using System.IO.IsolatedStorage;
+using System.Windows.Resources;
+using System.IO;
+using System.Diagnostics;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ public class Device : BaseCommand
+ {
+ public void getDeviceInfo(string notused)
+ {
+
+ string res = String.Format("\"name\":\"{0}\",\"cordova\":\"{1}\",\"platform\":\"{2}\",\"uuid\":\"{3}\",\"version\":\"{4}\",\"model\":\"{5}\"",
+ this.name,
+ this.cordova,
+ this.platform,
+ this.uuid,
+ this.version,
+ this.model);
+
+
+
+ res = "{" + res + "}";
+ //Debug.WriteLine("Result::" + res);
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, res));
+ }
+
+ public string model
+ {
+ get
+ {
+ return DeviceStatus.DeviceName;
+ //return String.Format("{0},{1},{2}", DeviceStatus.DeviceManufacturer, DeviceStatus.DeviceHardwareVersion, DeviceStatus.DeviceFirmwareVersion);
+ }
+ }
+
+ public string name
+ {
+ get
+ {
+ return DeviceStatus.DeviceName;
+
+ }
+ }
+
+ public string cordova
+ {
+ get
+ {
+ // TODO: should be able to dynamically read the Cordova version from somewhere...
+ return "2.7.0";
+ }
+ }
+
+ public string platform
+ {
+ get
+ {
+ return Environment.OSVersion.Platform.ToString();
+ }
+ }
+
+ public string uuid
+ {
+ get
+ {
+ string returnVal = "";
+ object id;
+ UserExtendedProperties.TryGetValue("ANID", out id);
+
+ if (id != null)
+ {
+ returnVal = id.ToString().Substring(2, 32);
+ }
+ else
+ {
+ returnVal = "???unknown???";
+
+ using (IsolatedStorageFile appStorage = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ try
+ {
+ IsolatedStorageFileStream fileStream = new IsolatedStorageFileStream("DeviceID.txt", FileMode.Open, FileAccess.Read, appStorage);
+
+ using (StreamReader reader = new StreamReader(fileStream))
+ {
+ returnVal = reader.ReadLine();
+ }
+ }
+ catch (Exception /*ex*/)
+ {
+
+ }
+ }
+ }
+
+ return returnVal;
+ }
+ }
+
+ public string version
+ {
+ get
+ {
+ return Environment.OSVersion.Version.ToString();
+ }
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/File.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/File.cs b/lib/cordova-wp8/templates/standalone/Plugins/File.cs
new file mode 100644
index 0000000..cde7a1c
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/File.cs
@@ -0,0 +1,1676 @@
+/*
+ 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.Diagnostics;
+using System.IO;
+using System.IO.IsolatedStorage;
+using System.Runtime.Serialization;
+using System.Security;
+using System.Text;
+using System.Windows;
+using System.Windows.Resources;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ /// <summary>
+ /// Provides access to isolated storage
+ /// </summary>
+ public class File : BaseCommand
+ {
+ // Error codes
+ public const int NOT_FOUND_ERR = 1;
+ public const int SECURITY_ERR = 2;
+ public const int ABORT_ERR = 3;
+ public const int NOT_READABLE_ERR = 4;
+ public const int ENCODING_ERR = 5;
+ public const int NO_MODIFICATION_ALLOWED_ERR = 6;
+ public const int INVALID_STATE_ERR = 7;
+ public const int SYNTAX_ERR = 8;
+ public const int INVALID_MODIFICATION_ERR = 9;
+ public const int QUOTA_EXCEEDED_ERR = 10;
+ public const int TYPE_MISMATCH_ERR = 11;
+ public const int PATH_EXISTS_ERR = 12;
+
+ // File system options
+ public const int TEMPORARY = 0;
+ public const int PERSISTENT = 1;
+ public const int RESOURCE = 2;
+ public const int APPLICATION = 3;
+
+ /// <summary>
+ /// Temporary directory name
+ /// </summary>
+ private readonly string TMP_DIRECTORY_NAME = "tmp";
+
+ /// <summary>
+ /// Represents error code for callback
+ /// </summary>
+ [DataContract]
+ public class ErrorCode
+ {
+ /// <summary>
+ /// Error code
+ /// </summary>
+ [DataMember(IsRequired = true, Name = "code")]
+ public int Code { get; set; }
+
+ /// <summary>
+ /// Creates ErrorCode object
+ /// </summary>
+ public ErrorCode(int code)
+ {
+ this.Code = code;
+ }
+ }
+
+ /// <summary>
+ /// Represents File action options.
+ /// </summary>
+ [DataContract]
+ public class FileOptions
+ {
+ /// <summary>
+ /// File path
+ /// </summary>
+ ///
+ private string _fileName;
+ [DataMember(Name = "fileName")]
+ public string FilePath
+ {
+ get
+ {
+ return this._fileName;
+ }
+
+ set
+ {
+ int index = value.IndexOfAny(new char[] { '#', '?' });
+ this._fileName = index > -1 ? value.Substring(0, index) : value;
+ }
+ }
+
+ /// <summary>
+ /// Full entryPath
+ /// </summary>
+ [DataMember(Name = "fullPath")]
+ public string FullPath { get; set; }
+
+ /// <summary>
+ /// Directory name
+ /// </summary>
+ [DataMember(Name = "dirName")]
+ public string DirectoryName { get; set; }
+
+ /// <summary>
+ /// Path to create file/directory
+ /// </summary>
+ [DataMember(Name = "path")]
+ public string Path { get; set; }
+
+ /// <summary>
+ /// The encoding to use to encode the file's content. Default is UTF8.
+ /// </summary>
+ [DataMember(Name = "encoding")]
+ public string Encoding { get; set; }
+
+ /// <summary>
+ /// Uri to get file
+ /// </summary>
+ ///
+ private string _uri;
+ [DataMember(Name = "uri")]
+ public string Uri
+ {
+ get
+ {
+ return this._uri;
+ }
+
+ set
+ {
+ int index = value.IndexOfAny(new char[] { '#', '?' });
+ this._uri = index > -1 ? value.Substring(0, index) : value;
+ }
+ }
+
+ /// <summary>
+ /// Size to truncate file
+ /// </summary>
+ [DataMember(Name = "size")]
+ public long Size { get; set; }
+
+ /// <summary>
+ /// Data to write in file
+ /// </summary>
+ [DataMember(Name = "data")]
+ public string Data { get; set; }
+
+ /// <summary>
+ /// Position the writing starts with
+ /// </summary>
+ [DataMember(Name = "position")]
+ public int Position { get; set; }
+
+ /// <summary>
+ /// Type of file system requested
+ /// </summary>
+ [DataMember(Name = "type")]
+ public int FileSystemType { get; set; }
+
+ /// <summary>
+ /// New file/directory name
+ /// </summary>
+ [DataMember(Name = "newName")]
+ public string NewName { get; set; }
+
+ /// <summary>
+ /// Destination directory to copy/move file/directory
+ /// </summary>
+ [DataMember(Name = "parent")]
+ public string Parent { get; set; }
+
+ /// <summary>
+ /// Options for getFile/getDirectory methods
+ /// </summary>
+ [DataMember(Name = "options")]
+ public CreatingOptions CreatingOpt { get; set; }
+
+ /// <summary>
+ /// Creates options object with default parameters
+ /// </summary>
+ public FileOptions()
+ {
+ this.SetDefaultValues(new StreamingContext());
+ }
+
+ /// <summary>
+ /// Initializes default values for class fields.
+ /// Implemented in separate method because default constructor is not invoked during deserialization.
+ /// </summary>
+ /// <param name="context"></param>
+ [OnDeserializing()]
+ public void SetDefaultValues(StreamingContext context)
+ {
+ this.Encoding = "UTF-8";
+ this.FilePath = "";
+ this.FileSystemType = -1;
+ }
+ }
+
+ /// <summary>
+ /// Stores image info
+ /// </summary>
+ [DataContract]
+ public class FileMetadata
+ {
+ [DataMember(Name = "fileName")]
+ public string FileName { get; set; }
+
+ [DataMember(Name = "fullPath")]
+ public string FullPath { get; set; }
+
+ [DataMember(Name = "type")]
+ public string Type { get; set; }
+
+ [DataMember(Name = "lastModifiedDate")]
+ public string LastModifiedDate { get; set; }
+
+ [DataMember(Name = "size")]
+ public long Size { get; set; }
+
+ public FileMetadata(string filePath)
+ {
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ if (string.IsNullOrEmpty(filePath))
+ {
+ throw new FileNotFoundException("File doesn't exist");
+ }
+ else if (!isoFile.FileExists(filePath))
+ {
+ // attempt to get it from the resources
+ if (filePath.IndexOf("www") == 0)
+ {
+ Uri fileUri = new Uri(filePath, UriKind.Relative);
+ StreamResourceInfo streamInfo = Application.GetResourceStream(fileUri);
+ if (streamInfo != null)
+ {
+ this.Size = streamInfo.Stream.Length;
+ this.FileName = filePath.Substring(filePath.LastIndexOf("/") + 1);
+ this.FullPath = filePath;
+ }
+ }
+ else
+ {
+ throw new FileNotFoundException("File doesn't exist");
+ }
+ }
+ else
+ {
+ //TODO get file size the other way if possible
+ using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(filePath, FileMode.Open, FileAccess.Read, isoFile))
+ {
+ this.Size = stream.Length;
+ }
+ this.FullPath = filePath;
+ this.FileName = System.IO.Path.GetFileName(filePath);
+ this.LastModifiedDate = isoFile.GetLastWriteTime(filePath).DateTime.ToString();
+ }
+ this.Type = MimeTypeMapper.GetMimeType(this.FileName);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Represents file or directory modification metadata
+ /// </summary>
+ [DataContract]
+ public class ModificationMetadata
+ {
+ /// <summary>
+ /// Modification time
+ /// </summary>
+ [DataMember]
+ public string modificationTime { get; set; }
+ }
+
+ /// <summary>
+ /// Represents file or directory entry
+ /// </summary>
+ [DataContract]
+ public class FileEntry
+ {
+
+ /// <summary>
+ /// File type
+ /// </summary>
+ [DataMember(Name = "isFile")]
+ public bool IsFile { get; set; }
+
+ /// <summary>
+ /// Directory type
+ /// </summary>
+ [DataMember(Name = "isDirectory")]
+ public bool IsDirectory { get; set; }
+
+ /// <summary>
+ /// File/directory name
+ /// </summary>
+ [DataMember(Name = "name")]
+ public string Name { get; set; }
+
+ /// <summary>
+ /// Full path to file/directory
+ /// </summary>
+ [DataMember(Name = "fullPath")]
+ public string FullPath { get; set; }
+
+ public bool IsResource { get; set; }
+
+ public static FileEntry GetEntry(string filePath, bool bIsRes=false)
+ {
+ FileEntry entry = null;
+ try
+ {
+ entry = new FileEntry(filePath, bIsRes);
+
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine("Exception in GetEntry for filePath :: " + filePath + " " + ex.Message);
+ }
+ return entry;
+ }
+
+ /// <summary>
+ /// Creates object and sets necessary properties
+ /// </summary>
+ /// <param name="filePath"></param>
+ public FileEntry(string filePath, bool bIsRes = false)
+ {
+ if (string.IsNullOrEmpty(filePath))
+ {
+ throw new ArgumentException();
+ }
+
+ if(filePath.Contains(" "))
+ {
+ Debug.WriteLine("FilePath with spaces :: " + filePath);
+ }
+
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ IsResource = bIsRes;
+ IsFile = isoFile.FileExists(filePath);
+ IsDirectory = isoFile.DirectoryExists(filePath);
+ if (IsFile)
+ {
+ this.Name = Path.GetFileName(filePath);
+ }
+ else if (IsDirectory)
+ {
+ this.Name = this.GetDirectoryName(filePath);
+ if (string.IsNullOrEmpty(Name))
+ {
+ this.Name = "/";
+ }
+ }
+ else
+ {
+ if (IsResource)
+ {
+ this.Name = Path.GetFileName(filePath);
+ }
+ else
+ {
+ throw new FileNotFoundException();
+ }
+ }
+
+ try
+ {
+ this.FullPath = filePath.Replace('\\', '/'); // new Uri(filePath).LocalPath;
+ }
+ catch (Exception)
+ {
+ this.FullPath = filePath;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Extracts directory name from path string
+ /// Path should refer to a directory, for example \foo\ or /foo.
+ /// </summary>
+ /// <param name="path"></param>
+ /// <returns></returns>
+ private string GetDirectoryName(string path)
+ {
+ if (String.IsNullOrEmpty(path))
+ {
+ return path;
+ }
+
+ string[] split = path.Split(new char[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries);
+ if (split.Length < 1)
+ {
+ return null;
+ }
+ else
+ {
+ return split[split.Length - 1];
+ }
+ }
+ }
+
+
+ /// <summary>
+ /// Represents info about requested file system
+ /// </summary>
+ [DataContract]
+ public class FileSystemInfo
+ {
+ /// <summary>
+ /// file system type
+ /// </summary>
+ [DataMember(Name = "name", IsRequired = true)]
+ public string Name { get; set; }
+
+ /// <summary>
+ /// Root directory entry
+ /// </summary>
+ [DataMember(Name = "root", EmitDefaultValue = false)]
+ public FileEntry Root { get; set; }
+
+ /// <summary>
+ /// Creates class instance
+ /// </summary>
+ /// <param name="name"></param>
+ /// <param name="rootEntry"> Root directory</param>
+ public FileSystemInfo(string name, FileEntry rootEntry = null)
+ {
+ Name = name;
+ Root = rootEntry;
+ }
+ }
+
+ [DataContract]
+ public class CreatingOptions
+ {
+ /// <summary>
+ /// Create file/directory if is doesn't exist
+ /// </summary>
+ [DataMember(Name = "create")]
+ public bool Create { get; set; }
+
+ /// <summary>
+ /// Generate an exception if create=true and file/directory already exists
+ /// </summary>
+ [DataMember(Name = "exclusive")]
+ public bool Exclusive { get; set; }
+
+
+ }
+
+ // returns null value if it fails.
+ private string[] getOptionStrings(string options)
+ {
+ string[] optStings = null;
+ try
+ {
+ optStings = JSON.JsonHelper.Deserialize<string[]>(options);
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION), CurrentCommandCallbackId);
+ }
+ return optStings;
+ }
+
+ /// <summary>
+ /// Gets amount of free space available for Isolated Storage
+ /// </summary>
+ /// <param name="options">No options is needed for this method</param>
+ public void getFreeDiskSpace(string options)
+ {
+ string callbackId = getOptionStrings(options)[0];
+
+ try
+ {
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, isoFile.AvailableFreeSpace), callbackId);
+ }
+ }
+ catch (IsolatedStorageException)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId);
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Check if file exists
+ /// </summary>
+ /// <param name="options">File path</param>
+ public void testFileExists(string options)
+ {
+ IsDirectoryOrFileExist(options, false);
+ }
+
+ /// <summary>
+ /// Check if directory exists
+ /// </summary>
+ /// <param name="options">directory name</param>
+ public void testDirectoryExists(string options)
+ {
+ IsDirectoryOrFileExist(options, true);
+ }
+
+ /// <summary>
+ /// Check if file or directory exist
+ /// </summary>
+ /// <param name="options">File path/Directory name</param>
+ /// <param name="isDirectory">Flag to recognize what we should check</param>
+ public void IsDirectoryOrFileExist(string options, bool isDirectory)
+ {
+ string[] args = getOptionStrings(options);
+ string callbackId = args[1];
+ FileOptions fileOptions = JSON.JsonHelper.Deserialize<FileOptions>(args[0]);
+ string filePath = args[0];
+
+ if (fileOptions == null)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION), callbackId);
+ }
+
+ try
+ {
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ bool isExist;
+ if (isDirectory)
+ {
+ isExist = isoFile.DirectoryExists(fileOptions.DirectoryName);
+ }
+ else
+ {
+ isExist = isoFile.FileExists(fileOptions.FilePath);
+ }
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, isExist), callbackId);
+ }
+ }
+ catch (IsolatedStorageException) // default handler throws INVALID_MODIFICATION_ERR
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId);
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ }
+ }
+
+ }
+
+ public void readAsDataURL(string options)
+ {
+ string[] optStrings = getOptionStrings(options);
+ string filePath = optStrings[0];
+ int startPos = int.Parse(optStrings[1]);
+ int endPos = int.Parse(optStrings[2]);
+ string callbackId = optStrings[3];
+
+ if (filePath != null)
+ {
+ try
+ {
+ string base64URL = null;
+
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ if (!isoFile.FileExists(filePath))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ return;
+ }
+ string mimeType = MimeTypeMapper.GetMimeType(filePath);
+
+ using (IsolatedStorageFileStream stream = isoFile.OpenFile(filePath, FileMode.Open, FileAccess.Read))
+ {
+ string base64String = GetFileContent(stream);
+ base64URL = "data:" + mimeType + ";base64," + base64String;
+ }
+ }
+
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, base64URL), callbackId);
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId);
+ }
+ }
+ }
+ }
+
+ public void readAsArrayBuffer(string options)
+ {
+ string[] optStrings = getOptionStrings(options);
+ string filePath = optStrings[0];
+ int startPos = int.Parse(optStrings[1]);
+ int endPos = int.Parse(optStrings[2]);
+ string callbackId = optStrings[3];
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR), callbackId);
+ }
+
+ public void readAsBinaryString(string options)
+ {
+ string[] optStrings = getOptionStrings(options);
+ string filePath = optStrings[0];
+ int startPos = int.Parse(optStrings[1]);
+ int endPos = int.Parse(optStrings[2]);
+ string callbackId = optStrings[3];
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR), callbackId);
+ }
+
+ public void readAsText(string options)
+ {
+ string[] optStrings = getOptionStrings(options);
+ string filePath = optStrings[0];
+ string encStr = optStrings[1];
+ int startPos = int.Parse(optStrings[2]);
+ int endPos = int.Parse(optStrings[3]);
+ string callbackId = optStrings[4];
+
+ try
+ {
+ string text = "";
+
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ if (!isoFile.FileExists(filePath))
+ {
+ readResourceAsText(options);
+ return;
+ }
+ Encoding encoding = Encoding.GetEncoding(encStr);
+
+ using (TextReader reader = new StreamReader(isoFile.OpenFile(filePath, FileMode.Open, FileAccess.Read), encoding))
+ {
+ text = reader.ReadToEnd();
+ if (startPos < 0)
+ {
+ startPos = Math.Max(text.Length + startPos, 0);
+ }
+ else if (startPos > 0)
+ {
+ startPos = Math.Min(text.Length, startPos);
+ }
+
+ if (endPos > 0)
+ {
+ endPos = Math.Min(text.Length, endPos);
+ }
+ else if (endPos < 0)
+ {
+ endPos = Math.Max(endPos + text.Length, 0);
+ }
+
+
+ text = text.Substring(startPos, endPos - startPos);
+
+ }
+ }
+
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, text), callbackId);
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex, callbackId))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Reads application resource as a text
+ /// </summary>
+ /// <param name="options">Path to a resource</param>
+ public void readResourceAsText(string options)
+ {
+ string[] optStrings = getOptionStrings(options);
+ string pathToResource = optStrings[0];
+ string encStr = optStrings[1];
+ int start = int.Parse(optStrings[2]);
+ int endMarker = int.Parse(optStrings[3]);
+ string callbackId = optStrings[4];
+
+ try
+ {
+ if (pathToResource.StartsWith("/"))
+ {
+ pathToResource = pathToResource.Remove(0, 1);
+ }
+
+ var resource = Application.GetResourceStream(new Uri(pathToResource, UriKind.Relative));
+
+ if (resource == null)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ return;
+ }
+
+ string text;
+ StreamReader streamReader = new StreamReader(resource.Stream);
+ text = streamReader.ReadToEnd();
+
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, text), callbackId);
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex, callbackId))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId);
+ }
+ }
+ }
+
+ public void truncate(string options)
+ {
+ string[] optStrings = getOptionStrings(options);
+
+ string filePath = optStrings[0];
+ int size = int.Parse(optStrings[1]);
+ string callbackId = optStrings[2];
+
+ try
+ {
+ long streamLength = 0;
+
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ if (!isoFile.FileExists(filePath))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ return;
+ }
+
+ using (FileStream stream = new IsolatedStorageFileStream(filePath, FileMode.Open, FileAccess.ReadWrite, isoFile))
+ {
+ if (0 <= size && size <= stream.Length)
+ {
+ stream.SetLength(size);
+ }
+ streamLength = stream.Length;
+ }
+ }
+
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, streamLength), callbackId);
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex, callbackId))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId);
+ }
+ }
+ }
+
+ //write:["filePath","data","position"],
+ public void write(string options)
+ {
+ // TODO: try/catch
+ string[] optStrings = getOptionStrings(options);
+
+ string filePath = optStrings[0];
+ string data = optStrings[1];
+ int position = int.Parse(optStrings[2]);
+ string callbackId = optStrings[3];
+
+ try
+ {
+ if (string.IsNullOrEmpty(data))
+ {
+ Debug.WriteLine("Expected some data to be send in the write command to {0}", filePath);
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION), callbackId);
+ return;
+ }
+
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ // create the file if not exists
+ if (!isoFile.FileExists(filePath))
+ {
+ var file = isoFile.CreateFile(filePath);
+ file.Close();
+ }
+
+ using (FileStream stream = new IsolatedStorageFileStream(filePath, FileMode.Open, FileAccess.ReadWrite, isoFile))
+ {
+ if (0 <= position && position <= stream.Length)
+ {
+ stream.SetLength(position);
+ }
+ using (BinaryWriter writer = new BinaryWriter(stream))
+ {
+ writer.Seek(0, SeekOrigin.End);
+ writer.Write(data.ToCharArray());
+ }
+ }
+ }
+
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, data.Length), callbackId);
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex, callbackId))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Look up metadata about this entry.
+ /// </summary>
+ /// <param name="options">filePath to entry</param>
+ public void getMetadata(string options)
+ {
+ string[] optStings = getOptionStrings(options);
+ string filePath = optStings[0];
+ string callbackId = optStings[1];
+
+ if (filePath != null)
+ {
+ try
+ {
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ if (isoFile.FileExists(filePath))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK,
+ new ModificationMetadata() { modificationTime = isoFile.GetLastWriteTime(filePath).DateTime.ToString() }), callbackId);
+ }
+ else if (isoFile.DirectoryExists(filePath))
+ {
+ string modTime = isoFile.GetLastWriteTime(filePath).DateTime.ToString();
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, new ModificationMetadata() { modificationTime = modTime }), callbackId);
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ }
+
+ }
+ }
+ catch (IsolatedStorageException)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId);
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId);
+ }
+ }
+ }
+
+ }
+
+
+ /// <summary>
+ /// Returns a File that represents the current state of the file that this FileEntry represents.
+ /// </summary>
+ /// <param name="filePath">filePath to entry</param>
+ /// <returns></returns>
+ public void getFileMetadata(string options)
+ {
+ string[] optStings = getOptionStrings(options);
+ string filePath = optStings[0];
+ string callbackId = optStings[1];
+
+ if (filePath != null)
+ {
+ try
+ {
+ FileMetadata metaData = new FileMetadata(filePath);
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, metaData), callbackId);
+ }
+ catch (IsolatedStorageException)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId);
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_READABLE_ERR), callbackId);
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Look up the parent DirectoryEntry containing this Entry.
+ /// If this Entry is the root of IsolatedStorage, its parent is itself.
+ /// </summary>
+ /// <param name="options"></param>
+ public void getParent(string options)
+ {
+ string[] optStings = getOptionStrings(options);
+ string filePath = optStings[0];
+ string callbackId = optStings[1];
+
+ if (filePath != null)
+ {
+ try
+ {
+ if (string.IsNullOrEmpty(filePath))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION),callbackId);
+ return;
+ }
+
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ FileEntry entry;
+
+ if (isoFile.FileExists(filePath) || isoFile.DirectoryExists(filePath))
+ {
+
+
+ string path = this.GetParentDirectory(filePath);
+ entry = FileEntry.GetEntry(path);
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, entry),callbackId);
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR),callbackId);
+ }
+
+ }
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR),callbackId);
+ }
+ }
+ }
+ }
+
+ public void remove(string options)
+ {
+ string[] args = getOptionStrings(options);
+ string filePath = args[0];
+ string callbackId = args[1];
+
+ if (filePath != null)
+ {
+ try
+ {
+ if (filePath == "/" || filePath == "" || filePath == @"\")
+ {
+ throw new Exception("Cannot delete root file system") ;
+ }
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ if (isoFile.FileExists(filePath))
+ {
+ isoFile.DeleteFile(filePath);
+ }
+ else
+ {
+ if (isoFile.DirectoryExists(filePath))
+ {
+ isoFile.DeleteDirectory(filePath);
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR),callbackId);
+ return;
+ }
+ }
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK),callbackId);
+ }
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NO_MODIFICATION_ALLOWED_ERR),callbackId);
+ }
+ }
+ }
+ }
+
+ public void removeRecursively(string options)
+ {
+ string[] args = getOptionStrings(options);
+ string filePath = args[0];
+ string callbackId = args[1];
+
+ if (filePath != null)
+ {
+ if (string.IsNullOrEmpty(filePath))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION),callbackId);
+ }
+ else
+ {
+ if (removeDirRecursively(filePath, callbackId))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK), callbackId);
+ }
+ }
+ }
+ }
+
+ public void readEntries(string options)
+ {
+ string[] args = getOptionStrings(options);
+ string filePath = args[0];
+ string callbackId = args[1];
+
+ if (filePath != null)
+ {
+ try
+ {
+ if (string.IsNullOrEmpty(filePath))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION),callbackId);
+ return;
+ }
+
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ if (isoFile.DirectoryExists(filePath))
+ {
+ string path = File.AddSlashToDirectory(filePath);
+ List<FileEntry> entries = new List<FileEntry>();
+ string[] files = isoFile.GetFileNames(path + "*");
+ string[] dirs = isoFile.GetDirectoryNames(path + "*");
+ foreach (string file in files)
+ {
+ entries.Add(FileEntry.GetEntry(path + file));
+ }
+ foreach (string dir in dirs)
+ {
+ entries.Add(FileEntry.GetEntry(path + dir + "/"));
+ }
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, entries),callbackId);
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR),callbackId);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NO_MODIFICATION_ALLOWED_ERR),callbackId);
+ }
+ }
+ }
+ }
+
+ public void requestFileSystem(string options)
+ {
+ // TODO: try/catch
+ string[] optVals = getOptionStrings(options);
+ //FileOptions fileOptions = new FileOptions();
+ int fileSystemType = int.Parse(optVals[0]);
+ double size = double.Parse(optVals[1]);
+ string callbackId = optVals[2];
+
+
+ IsolatedStorageFile.GetUserStoreForApplication();
+
+ if (size > (10 * 1024 * 1024)) // 10 MB, compier will clean this up!
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, QUOTA_EXCEEDED_ERR), callbackId);
+ return;
+ }
+
+ try
+ {
+ if (size != 0)
+ {
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ long availableSize = isoFile.AvailableFreeSpace;
+ if (size > availableSize)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, QUOTA_EXCEEDED_ERR), callbackId);
+ return;
+ }
+ }
+ }
+
+ if (fileSystemType == PERSISTENT)
+ {
+ // TODO: this should be in it's own folder to prevent overwriting of the app assets, which are also in ISO
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, new FileSystemInfo("persistent", FileEntry.GetEntry("/"))), callbackId);
+ }
+ else if (fileSystemType == TEMPORARY)
+ {
+ using (IsolatedStorageFile isoStorage = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ if (!isoStorage.FileExists(TMP_DIRECTORY_NAME))
+ {
+ isoStorage.CreateDirectory(TMP_DIRECTORY_NAME);
+ }
+ }
+
+ string tmpFolder = "/" + TMP_DIRECTORY_NAME + "/";
+
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, new FileSystemInfo("temporary", FileEntry.GetEntry(tmpFolder))), callbackId);
+ }
+ else if (fileSystemType == RESOURCE)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, new FileSystemInfo("resource")), callbackId);
+ }
+ else if (fileSystemType == APPLICATION)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, new FileSystemInfo("application")), callbackId);
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NO_MODIFICATION_ALLOWED_ERR), callbackId);
+ }
+
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NO_MODIFICATION_ALLOWED_ERR), callbackId);
+ }
+ }
+ }
+
+ public void resolveLocalFileSystemURI(string options)
+ {
+
+ string[] optVals = getOptionStrings(options);
+ string uri = optVals[0].Split('?')[0];
+ string callbackId = optVals[1];
+
+ if (uri != null)
+ {
+ // a single '/' is valid, however, '/someDir' is not, but '/tmp//somedir' and '///someDir' are valid
+ if (uri.StartsWith("/") && uri.IndexOf("//") < 0 && uri != "/")
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, ENCODING_ERR), callbackId);
+ return;
+ }
+ try
+ {
+ // fix encoded spaces
+ string path = Uri.UnescapeDataString(uri);
+
+ FileEntry uriEntry = FileEntry.GetEntry(path);
+ if (uriEntry != null)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, uriEntry), callbackId);
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ }
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex, callbackId))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NO_MODIFICATION_ALLOWED_ERR), callbackId);
+ }
+ }
+ }
+ }
+
+ public void copyTo(string options)
+ {
+ TransferTo(options, false);
+ }
+
+ public void moveTo(string options)
+ {
+ TransferTo(options, true);
+ }
+
+ public void getFile(string options)
+ {
+ GetFileOrDirectory(options, false);
+ }
+
+ public void getDirectory(string options)
+ {
+ GetFileOrDirectory(options, true);
+ }
+
+ #region internal functionality
+
+ /// <summary>
+ /// Retrieves the parent directory name of the specified path,
+ /// </summary>
+ /// <param name="path">Path</param>
+ /// <returns>Parent directory name</returns>
+ private string GetParentDirectory(string path)
+ {
+ if (String.IsNullOrEmpty(path) || path == "/")
+ {
+ return "/";
+ }
+
+ if (path.EndsWith(@"/") || path.EndsWith(@"\"))
+ {
+ return this.GetParentDirectory(Path.GetDirectoryName(path));
+ }
+
+ string result = Path.GetDirectoryName(path);
+ if (result == null)
+ {
+ result = "/";
+ }
+
+ return result;
+ }
+
+ private bool removeDirRecursively(string fullPath,string callbackId)
+ {
+ try
+ {
+ if (fullPath == "/")
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NO_MODIFICATION_ALLOWED_ERR),callbackId);
+ return false;
+ }
+
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ if (isoFile.DirectoryExists(fullPath))
+ {
+ string tempPath = File.AddSlashToDirectory(fullPath);
+ string[] files = isoFile.GetFileNames(tempPath + "*");
+ if (files.Length > 0)
+ {
+ foreach (string file in files)
+ {
+ isoFile.DeleteFile(tempPath + file);
+ }
+ }
+ string[] dirs = isoFile.GetDirectoryNames(tempPath + "*");
+ if (dirs.Length > 0)
+ {
+ foreach (string dir in dirs)
+ {
+ if (!removeDirRecursively(tempPath + dir, callbackId))
+ {
+ return false;
+ }
+ }
+ }
+ isoFile.DeleteDirectory(fullPath);
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR),callbackId);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NO_MODIFICATION_ALLOWED_ERR),callbackId);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private bool CanonicalCompare(string pathA, string pathB)
+ {
+ string a = pathA.Replace("//", "/");
+ string b = pathB.Replace("//", "/");
+
+ return a.Equals(b, StringComparison.OrdinalIgnoreCase);
+ }
+
+ /*
+ * copyTo:["fullPath","parent", "newName"],
+ * moveTo:["fullPath","parent", "newName"],
+ */
+ private void TransferTo(string options, bool move)
+ {
+ // TODO: try/catch
+ string[] optStrings = getOptionStrings(options);
+ string fullPath = optStrings[0];
+ string parent = optStrings[1];
+ string newFileName = optStrings[2];
+ string callbackId = optStrings[3];
+
+ char[] invalids = Path.GetInvalidPathChars();
+
+ if (newFileName.IndexOfAny(invalids) > -1 || newFileName.IndexOf(":") > -1 )
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, ENCODING_ERR), callbackId);
+ return;
+ }
+
+ try
+ {
+ if ((parent == null) || (string.IsNullOrEmpty(parent)) || (string.IsNullOrEmpty(fullPath)))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ return;
+ }
+
+ string parentPath = File.AddSlashToDirectory(parent);
+ string currentPath = fullPath;
+
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ bool isFileExist = isoFile.FileExists(currentPath);
+ bool isDirectoryExist = isoFile.DirectoryExists(currentPath);
+ bool isParentExist = isoFile.DirectoryExists(parentPath);
+
+ if ( ( !isFileExist && !isDirectoryExist ) || !isParentExist )
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ return;
+ }
+ string newName;
+ string newPath;
+ if (isFileExist)
+ {
+ newName = (string.IsNullOrEmpty(newFileName))
+ ? Path.GetFileName(currentPath)
+ : newFileName;
+
+ newPath = Path.Combine(parentPath, newName);
+
+ // sanity check ..
+ // cannot copy file onto itself
+ if (CanonicalCompare(newPath,currentPath)) //(parent + newFileName))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, INVALID_MODIFICATION_ERR), callbackId);
+ return;
+ }
+ else if (isoFile.DirectoryExists(newPath))
+ {
+ // there is already a folder with the same name, operation is not allowed
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, INVALID_MODIFICATION_ERR), callbackId);
+ return;
+ }
+ else if (isoFile.FileExists(newPath))
+ { // remove destination file if exists, in other case there will be exception
+ isoFile.DeleteFile(newPath);
+ }
+
+ if (move)
+ {
+ isoFile.MoveFile(currentPath, newPath);
+ }
+ else
+ {
+ isoFile.CopyFile(currentPath, newPath, true);
+ }
+ }
+ else
+ {
+ newName = (string.IsNullOrEmpty(newFileName))
+ ? currentPath
+ : newFileName;
+
+ newPath = Path.Combine(parentPath, newName);
+
+ if (move)
+ {
+ // remove destination directory if exists, in other case there will be exception
+ // target directory should be empty
+ if (!newPath.Equals(currentPath) && isoFile.DirectoryExists(newPath))
+ {
+ isoFile.DeleteDirectory(newPath);
+ }
+
+ isoFile.MoveDirectory(currentPath, newPath);
+ }
+ else
+ {
+ CopyDirectory(currentPath, newPath, isoFile);
+ }
+ }
+ FileEntry entry = FileEntry.GetEntry(newPath);
+ if (entry != null)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, entry), callbackId);
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ }
+ }
+
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex, callbackId))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NO_MODIFICATION_ALLOWED_ERR), callbackId);
+ }
+ }
+ }
+
+ private bool HandleException(Exception ex, string cbId="")
+ {
+ bool handled = false;
+ string callbackId = String.IsNullOrEmpty(cbId) ? this.CurrentCommandCallbackId : cbId;
+ if (ex is SecurityException)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, SECURITY_ERR), callbackId);
+ handled = true;
+ }
+ else if (ex is FileNotFoundException)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ handled = true;
+ }
+ else if (ex is ArgumentException)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, ENCODING_ERR), callbackId);
+ handled = true;
+ }
+ else if (ex is IsolatedStorageException)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, INVALID_MODIFICATION_ERR), callbackId);
+ handled = true;
+ }
+ else if (ex is DirectoryNotFoundException)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ handled = true;
+ }
+ return handled;
+ }
+
+ private void CopyDirectory(string sourceDir, string destDir, IsolatedStorageFile isoFile)
+ {
+ string path = File.AddSlashToDirectory(sourceDir);
+
+ bool bExists = isoFile.DirectoryExists(destDir);
+
+ if (!bExists)
+ {
+ isoFile.CreateDirectory(destDir);
+ }
+
+ destDir = File.AddSlashToDirectory(destDir);
+
+ string[] files = isoFile.GetFileNames(path + "*");
+
+ if (files.Length > 0)
+ {
+ foreach (string file in files)
+ {
+ isoFile.CopyFile(path + file, destDir + file,true);
+ }
+ }
+ string[] dirs = isoFile.GetDirectoryNames(path + "*");
+ if (dirs.Length > 0)
+ {
+ foreach (string dir in dirs)
+ {
+ CopyDirectory(path + dir, destDir + dir, isoFile);
+ }
+ }
+ }
+
+ private void GetFileOrDirectory(string options, bool getDirectory)
+ {
+ FileOptions fOptions = new FileOptions();
+ string[] args = getOptionStrings(options);
+
+ fOptions.FullPath = args[0];
+ fOptions.Path = args[1];
+
+ string callbackId = args[3];
+
+ try
+ {
+ fOptions.CreatingOpt = JSON.JsonHelper.Deserialize<CreatingOptions>(args[2]);
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION), callbackId);
+ return;
+ }
+
+ try
+ {
+ if ((string.IsNullOrEmpty(fOptions.Path)) || (string.IsNullOrEmpty(fOptions.FullPath)))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ return;
+ }
+
+ string path;
+
+ if (fOptions.Path.Split(':').Length > 2)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, ENCODING_ERR), callbackId);
+ return;
+ }
+
+ try
+ {
+ path = Path.Combine(fOptions.FullPath + "/", fOptions.Path);
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, ENCODING_ERR), callbackId);
+ return;
+ }
+
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ bool isFile = isoFile.FileExists(path);
+ bool isDirectory = isoFile.DirectoryExists(path);
+ bool create = (fOptions.CreatingOpt == null) ? false : fOptions.CreatingOpt.Create;
+ bool exclusive = (fOptions.CreatingOpt == null) ? false : fOptions.CreatingOpt.Exclusive;
+ if (create)
+ {
+ if (exclusive && (isoFile.FileExists(path) || isoFile.DirectoryExists(path)))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, PATH_EXISTS_ERR), callbackId);
+ return;
+ }
+
+ // need to make sure the parent exists
+ // it is an error to create a directory whose immediate parent does not yet exist
+ // see issue: https://issues.apache.org/jira/browse/CB-339
+ string[] pathParts = path.Split('/');
+ string builtPath = pathParts[0];
+ for (int n = 1; n < pathParts.Length - 1; n++)
+ {
+ builtPath += "/" + pathParts[n];
+ if (!isoFile.DirectoryExists(builtPath))
+ {
+ Debug.WriteLine(String.Format("Error :: Parent folder \"{0}\" does not exist, when attempting to create \"{1}\"",builtPath,path));
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ return;
+ }
+ }
+
+ if ((getDirectory) && (!isDirectory))
+ {
+ isoFile.CreateDirectory(path);
+ }
+ else
+ {
+ if ((!getDirectory) && (!isFile))
+ {
+
+ IsolatedStorageFileStream fileStream = isoFile.CreateFile(path);
+ fileStream.Close();
+ }
+ }
+ }
+ else // (not create)
+ {
+ if ((!isFile) && (!isDirectory))
+ {
+ if (path.IndexOf("//www") == 0)
+ {
+ Uri fileUri = new Uri(path.Remove(0,2), UriKind.Relative);
+ StreamResourceInfo streamInfo = Application.GetResourceStream(fileUri);
+ if (streamInfo != null)
+ {
+ FileEntry _entry = FileEntry.GetEntry(fileUri.OriginalString,true);
+
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, _entry), callbackId);
+
+ //using (BinaryReader br = new BinaryReader(streamInfo.Stream))
+ //{
+ // byte[] data = br.ReadBytes((int)streamInfo.Stream.Length);
+
+ //}
+
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ }
+
+
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ }
+ return;
+ }
+ if (((getDirectory) && (!isDirectory)) || ((!getDirectory) && (!isFile)))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, TYPE_MISMATCH_ERR), callbackId);
+ return;
+ }
+ }
+ FileEntry entry = FileEntry.GetEntry(path);
+ if (entry != null)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, entry), callbackId);
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NOT_FOUND_ERR), callbackId);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ if (!this.HandleException(ex))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, NO_MODIFICATION_ALLOWED_ERR), callbackId);
+ }
+ }
+ }
+
+ private static string AddSlashToDirectory(string dirPath)
+ {
+ if (dirPath.EndsWith("/"))
+ {
+ return dirPath;
+ }
+ else
+ {
+ return dirPath + "/";
+ }
+ }
+
+ /// <summary>
+ /// Returns file content in a form of base64 string
+ /// </summary>
+ /// <param name="stream">File stream</param>
+ /// <returns>Base64 representation of the file</returns>
+ private string GetFileContent(Stream stream)
+ {
+ int streamLength = (int)stream.Length;
+ byte[] fileData = new byte[streamLength + 1];
+ stream.Read(fileData, 0, streamLength);
+ stream.Close();
+ return Convert.ToBase64String(fileData);
+ }
+
+ #endregion
+
+ }
+}
[04/37] Add WP7 and WP8 platform files.
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/cordova.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/cordova.js b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/cordova.js
new file mode 100644
index 0000000..6778e2b
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/cordova.js
@@ -0,0 +1,14 @@
+var VERSION='2.5.0';
+var scripts = document.getElementsByTagName('script');
+var cordovaPath = scripts[scripts.length - 1].src.replace('cordova.js', 'cordova-'+VERSION+'.js');
+
+document.write('<script type="text/javascript" charset="utf-8" src="' + cordovaPath + '"></script>');
+
+function backHome() {
+ if (window.device && device.platform && device.platform.toLowerCase() == 'android') {
+ navigator.app.backHistory();
+ }
+ else {
+ window.history.go(-1);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/events/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/events/index.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/events/index.html
new file mode 100644
index 0000000..2c7e8ba
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/events/index.html
@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width,height=device-height,user-scalable=no,maximum-scale=1.0,initial-scale=1.0" />
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8"> <!-- ISO-8859-1 -->
+ <title>Cordova Mobile Spec</title>
+ <link rel="stylesheet" href="../master.css" type="text/css" media="screen" title="no title" charset="utf-8">
+ <script type="text/javascript" charset="utf-8" src="../cordova.js"></script>
+
+
+<script type="text/javascript" charset="utf-8">
+
+ var deviceReady = false;
+
+ function interceptBackbutton() {
+ eventOutput("Back button intercepted");
+ }
+ function interceptMenubutton() {
+ eventOutput("Menu button intercepted");
+ }
+ function interceptSearchbutton() {
+ eventOutput("Search button intercepted");
+ }
+ function interceptResume() {
+ eventOutput("Resume event intercepted");
+ }
+ function interceptPause() {
+ eventOutput("Pause event intercepted");
+ }
+ function interceptOnline() {
+ eventOutput("Online event intercepted");
+ }
+ function interceptOffline() {
+ eventOutput("Offline event intercepted");
+ }
+
+ var eventOutput = function(s) {
+ var el = document.getElementById("results");
+ el.innerHTML = el.innerHTML + s + "<br>";
+ };
+
+
+ /**
+ * Function called when page has finished loading.
+ */
+ function init() {
+ document.addEventListener("deviceready", function() {
+ deviceReady = true;
+ console.log("Device="+device.platform+" "+device.version);
+ eventOutput("deviceready event: "+device.platform+" "+device.version);
+ }, false);
+ window.setTimeout(function() {
+ if (!deviceReady) {
+ alert("Error: PhoneGap did not initialize. Demo will not run correctly.");
+ }
+ },1000);
+ }
+
+</script>
+
+ </head>
+ <body onload="init();" id="stage" class="theme">
+
+ <h1>Events</h1>
+ <div id="info">
+ <b>Results:</b><br>
+ <span id="results"></span>
+ </div>
+
+ <h2>Action</h2>
+ <div class="btn large" onclick="document.addEventListener('backbutton', interceptBackbutton, false);">Intercept backbutton</div>
+ <div class="btn large" onclick="document.removeEventListener('backbutton', interceptBackbutton, false);">Stop intercept of backbutton</div>
+ <div class="btn large" onclick="document.addEventListener('menubutton', interceptMenubutton, false);">Intercept menubutton</div>
+ <div class="btn large" onclick="document.removeEventListener('menubutton', interceptMenubutton, false);">Stop intercept of menubutton</div>
+ <div class="btn large" onclick="document.addEventListener('searchbutton', interceptSearchbutton, false);">Intercept searchbutton</div>
+ <div class="btn large" onclick="document.removeEventListener('searchbutton', interceptSearchbutton, false);">Stop intercept of searchbutton</div>
+ <div class="btn large" onclick="document.addEventListener('resume', interceptResume, false);">Intercept resume</div>
+ <div class="btn large" onclick="document.removeEventListener('resume', interceptResume, false);">Stop intercept of resume</div>
+ <div class="btn large" onclick="document.addEventListener('pause', interceptPause, false);">Intercept pause</div>
+ <div class="btn large" onclick="document.removeEventListener('pause', interceptPause, false);">Stop intercept of pause</div>
+ <div class="btn large" onclick="document.addEventListener('online', interceptOnline, false);">Intercept online</div>
+ <div class="btn large" onclick="document.removeEventListener('online', interceptOnline, false);">Stop intercept of online</div>
+ <div class="btn large" onclick="document.addEventListener('offline', interceptOffline, false);">Intercept offline</div>
+ <div class="btn large" onclick="document.removeEventListener('offline', interceptOffline, false);">Stop intercept of offline</div>
+
+ <h2> </h2><div class="backBtn" onclick="backHome();">Back</div>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/index.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/index.html
new file mode 100644
index 0000000..e7a77e0
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/index.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width,height=device-height,user-scalable=no,initial-scale=1.0" />
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8">
+ <title>Cordova Mobile Spec</title>
+ <link rel="stylesheet" href="master.css" type="text/css" media="screen" title="no title" charset="utf-8">
+ <script type="text/javascript" charset="utf-8" src="cordova.js"></script>
+ <script type="text/javascript" charset="utf-8" src="main.js"></script>
+
+ </head>
+ <body onload="init();" id="stage" class="theme">
+ <h1>Apache Cordova Tests</h1>
+ <div id="info">
+ <h4>Platform: <span id="platform"> </span></h4>
+ <h4>Version: <span id="version"> </span></h4>
+ <h4>UUID: <span id="uuid"> </span></h4>
+ <h4>Name: <span id="name"> </span></h4>
+ <h4>Width: <span id="width"> </span>, Height: <span id="height">
+ </span>, Color Depth: <span id="colorDepth"></span></h4>
+ </div>
+ <a href="autotest/index.html" class="btn large">Automatic Test</a>
+ <a href="accelerometer/index.html" class="btn large">Accelerometer</a>
+ <a href="audio/index.html" class="btn large">Audio Play/Record</a>
+ <a href="battery/index.html" class="btn large">Battery</a>
+ <a href="camera/index.html" class="btn large">Camera</a>
+ <a href="compass/index.html" class="btn large">Compass</a>
+ <a href="contacts/index.html" class="btn large">Contacts</a>
+ <a href="events/index.html" class="btn large">Events</a>
+ <a href="location/index.html" class="btn large">Location</a>
+ <a href="misc/index.html" class="btn large">Misc Content</a>
+ <a href="network/index.html" class="btn large">Network</a>
+ <a href="notification/index.html" class="btn large">Notification</a>
+ <a href="sql/index.html" class="btn large">Web SQL</a>
+ <a href="storage/index.html" class="btn large">Local Storage</a>
+ <a href="execbenchmark/index.html" class="btn large">Benchmark exec()</a>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/location/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/location/index.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/location/index.html
new file mode 100644
index 0000000..8b1e681
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/location/index.html
@@ -0,0 +1,147 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width,height=device-height,user-scalable=no,maximum-scale=1.0,initial-scale=1.0" />
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8"> <!-- ISO-8859-1 -->
+ <title>Cordova Mobile Spec</title>
+ <link rel="stylesheet" href="../master.css" type="text/css" media="screen" title="no title" charset="utf-8">
+ <script type="text/javascript" charset="utf-8" src="../cordova.js"></script>
+
+
+<script type="text/javascript" charset="utf-8">
+
+ var deviceReady = false;
+
+ //-------------------------------------------------------------------------
+ // Location
+ //-------------------------------------------------------------------------
+ var watchLocationId = null;
+
+ /**
+ * Start watching location
+ */
+ var watchLocation = function(geo) {
+ console.log("watchLocation()");
+
+ // Success callback
+ var success = function(p){
+ console.log('watch location success');
+ setLocationDetails(p);
+ };
+
+ // Fail callback
+ var fail = function(e){
+ console.log("watchLocation fail callback with error code "+e);
+ stopLocation(geo);
+ };
+
+ // Get location
+ watchLocationId = geo.watchPosition(success, fail, {enableHighAccuracy: true});
+ setLocationStatus("Running");
+ };
+
+ /**
+ * Stop watching the location
+ */
+ var stopLocation = function(geo) {
+ setLocationStatus("Stopped");
+ if (watchLocationId) {
+ geo.clearWatch(watchLocationId);
+ watchLocationId = null;
+ }
+ };
+
+ /**
+ * Get current location
+ */
+ var getLocation = function(geo, opts) {
+ console.log("getLocation()");
+
+ // Stop location if running
+ stopLocation(geo);
+
+ // Success callback
+ var success = function(p){
+ console.log('get location success');
+ setLocationDetails(p);
+ setLocationStatus("Done");
+ };
+
+ // Fail callback
+ var fail = function(e){
+ console.log("getLocation fail callback with error code "+e.code);
+ setLocationStatus("Error: "+e.code);
+ };
+
+ // Get location
+ geo.getCurrentPosition(success, fail, opts || {enableHighAccuracy: true}); //, {timeout: 10000});
+ setLocationStatus("Retrieving location...");
+
+ };
+
+ /**
+ * Set location status
+ */
+ var setLocationStatus = function(status) {
+ document.getElementById('location_status').innerHTML = status;
+ };
+var setLocationDetails = function(p) {
+var date = (new Date(p.timestamp));
+ document.getElementById('latitude').innerHTML = p.coords.latitude;
+ document.getElementById('longitude').innerHTML = p.coords.longitude;
+ document.getElementById('altitude').innerHTML = p.coords.altitude;
+ document.getElementById('accuracy').innerHTML = p.coords.accuracy;
+ document.getElementById('heading').innerHTML = p.coords.heading;
+ document.getElementById('speed').innerHTML = p.coords.speed;
+ document.getElementById('altitude_accuracy').innerHTML = p.coords.altitudeAccuracy;
+ document.getElementById('timestamp').innerHTML = date.toDateString() + " " + date.toTimeString();
+ }
+
+ /**
+ * Function called when page has finished loading.
+ */
+ function init() {
+ document.addEventListener("deviceready", function() {
+ deviceReady = true;
+ console.log("Device="+device.platform+" "+device.version);
+ }, false);
+ window.setTimeout(function() {
+ if (!deviceReady) {
+ alert("Error: PhoneGap did not initialize. Demo will not run correctly.");
+ }
+ },1000);
+ }
+
+</script>
+
+ </head>
+ <body onload="init();" id="stage" class="theme">
+
+ <h1>Location</h1>
+ <div id="info">
+ <b>Status:</b> <span id="location_status">Stopped</span>
+ <table width="100%">
+ <tr><td><b>Latitude:</b></td><td id="latitude"> </td></tr>
+ <tr><td><b>Longitude:</b></td><td id="longitude"> </td></tr>
+ <tr><td><b>Altitude:</b></td><td id="altitude"> </td></tr>
+ <tr><td><b>Accuracy:</b></td><td id="accuracy"> </td></tr>
+ <tr><td><b>Heading:</b></td><td id="heading"> </td></tr>
+ <tr><td><b>Speed:</b></td><td id="speed"> </td></tr>
+ <tr><td><b>Altitude Accuracy:</b></td><td id="altitude_accuracy"> </td></tr>
+ <tr><td><b>Time:</b></td><td id="timestamp"> </td></tr>
+ </table>
+ </div>
+ <h2>Action</h2>
+ <h3>Use Built-in WebView navigator.geolocation</h3>
+ <a href="javascript:" class="btn large" onclick="getLocation(navigator.geolocation);">Get Location</a>
+ <a href="javascript:" class="btn large" onclick="watchLocation(navigator.geolocation);">Start Watching Location</a>
+ <a href="javascript:" class="btn large" onclick="stopLocation(navigator.geolocation);">Stop Watching Location</a>
+ <a href="javascript:" class="btn large" onclick="getLocation(navigator.geolocation, {maximumAge:30000});">Get Location Up to 30 Seconds Old</a>
+ <h3>USe Cordova Geolocation Plugin</h3>
+ <a href="javascript:" class="btn large" onclick="getLocation(cordova.require('cordova/plugin/geolocation'));">Get Location</a>
+ <a href="javascript:" class="btn large" onclick="watchLocation(cordova.require('cordova/plugin/geolocation'));">Start Watching Location</a>
+ <a href="javascript:" class="btn large" onclick="stopLocation(cordova.require('cordova/plugin/geolocation'));">Stop Watching Location</a>
+ <a href="javascript:" class="btn large" onclick="getLocation(cordova.require('cordova/plugin/geolocation'), {maximumAge:30000});">Get Location Up to 30 Seconds Old</a>
+ <h2> </h2><a href="javascript:" class="backBtn" onclick="backHome();">Back</a>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/main.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/main.js b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/main.js
new file mode 100644
index 0000000..ae447aa
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/main.js
@@ -0,0 +1,140 @@
+var deviceInfo = function() {
+ document.getElementById("platform").innerHTML = device.platform;
+ document.getElementById("version").innerHTML = device.version;
+ document.getElementById("uuid").innerHTML = device.uuid;
+ document.getElementById("name").innerHTML = device.name;
+ document.getElementById("width").innerHTML = screen.width;
+ document.getElementById("height").innerHTML = screen.height;
+ document.getElementById("colorDepth").innerHTML = screen.colorDepth;
+};
+
+var getLocation = function() {
+ var suc = function(p) {
+ alert(p.coords.latitude + " " + p.coords.longitude);
+ };
+ var locFail = function() {
+ };
+ navigator.geolocation.getCurrentPosition(suc, locFail);
+};
+
+var beep = function() {
+ navigator.notification.beep(2);
+};
+
+var vibrate = function() {
+ navigator.notification.vibrate(0);
+};
+
+function roundNumber(num) {
+ var dec = 3;
+ var result = Math.round(num * Math.pow(10, dec)) / Math.pow(10, dec);
+ return result;
+}
+
+var accelerationWatch = null;
+
+function updateAcceleration(a) {
+ document.getElementById('x').innerHTML = roundNumber(a.x);
+ document.getElementById('y').innerHTML = roundNumber(a.y);
+ document.getElementById('z').innerHTML = roundNumber(a.z);
+}
+
+var toggleAccel = function() {
+ if (accelerationWatch !== null) {
+ navigator.accelerometer.clearWatch(accelerationWatch);
+ updateAcceleration({
+ x : "",
+ y : "",
+ z : ""
+ });
+ accelerationWatch = null;
+ } else {
+ var options = {};
+ options.frequency = 1000;
+ accelerationWatch = navigator.accelerometer.watchAcceleration(
+ updateAcceleration, function(ex) {
+ alert("accel fail (" + ex.name + ": " + ex.message + ")");
+ }, options);
+ }
+};
+
+var preventBehavior = function(e) {
+ e.preventDefault();
+};
+
+function dump_pic(data) {
+ var viewport = document.getElementById('viewport');
+ console.log(data);
+ viewport.style.display = "";
+ viewport.style.position = "absolute";
+ viewport.style.top = "10px";
+ viewport.style.left = "10px";
+ document.getElementById("test_img").src = "data:image/jpeg;base64," + data;
+}
+
+function fail(msg) {
+ alert(msg);
+}
+
+function show_pic() {
+ navigator.camera.getPicture(dump_pic, fail, {
+ quality : 50
+ });
+}
+
+function close() {
+ var viewport = document.getElementById('viewport');
+ viewport.style.position = "relative";
+ viewport.style.display = "none";
+}
+
+// This is just to do this.
+function readFile() {
+ navigator.file.read('/sdcard/phonegap.txt', fail, fail);
+}
+
+function writeFile() {
+ navigator.file.write('foo.txt', "This is a test of writing to a file",
+ fail, fail);
+}
+
+function contacts_success(contacts) {
+ alert(contacts.length
+ + ' contacts returned.'
+ + (contacts[2] && contacts[2].name ? (' Third contact is ' + contacts[2].name.formatted)
+ : ''));
+}
+
+function get_contacts() {
+ var obj = new ContactFindOptions();
+ obj.filter = "";
+ obj.multiple = true;
+ obj.limit = 5;
+ navigator.service.contacts.find(
+ [ "displayName", "name" ], contacts_success,
+ fail, obj);
+}
+
+var networkReachableCallback = function(reachability) {
+ // There is no consistency on the format of reachability
+ var networkState = reachability.code || reachability;
+
+ var currentState = {};
+ currentState[NetworkStatus.NOT_REACHABLE] = 'No network connection';
+ currentState[NetworkStatus.REACHABLE_VIA_CARRIER_DATA_NETWORK] = 'Carrier data connection';
+ currentState[NetworkStatus.REACHABLE_VIA_WIFI_NETWORK] = 'WiFi connection';
+
+ confirm("Connection type:\n" + currentState[networkState]);
+};
+
+function check_network() {
+ navigator.network.isReachable("www.mobiledevelopersolutions.com",
+ networkReachableCallback, {});
+}
+
+function init() {
+ // the next line makes it impossible to see Contacts on the HTC Evo since it
+ // doesn't have a scroll button
+ // document.addEventListener("touchmove", preventBehavior, false);
+ document.addEventListener("deviceready", deviceInfo, true);
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/master.css
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/master.css b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/master.css
new file mode 100644
index 0000000..2408052
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/master.css
@@ -0,0 +1,136 @@
+ body {
+ background:#222 none repeat scroll 0 0;
+ color:#666;
+ font-family:Helvetica;
+ font-size:72%;
+ line-height:1.5em;
+ margin:0;
+ border-top:1px solid #393939;
+ }
+
+ #info{
+ background:#ffa;
+ border: 1px solid #ffd324;
+ -webkit-border-radius: 5px;
+ border-radius: 5px;
+ clear:both;
+ margin:15px 6px 0;
+ width:295px;
+ padding:4px 0px 2px 10px;
+ }
+
+ #info > h4{
+ font-size:.95em;
+ margin:5px 0;
+ }
+
+ #stage.theme{
+ padding-top:3px;
+ }
+
+ /* Definition List */
+ #stage.theme > dl{
+ padding-top:10px;
+ clear:both;
+ margin:0;
+ list-style-type:none;
+ padding-left:10px;
+ overflow:auto;
+ }
+
+ #stage.theme > dl > dt{
+ font-weight:bold;
+ float:left;
+ margin-left:5px;
+ }
+
+ #stage.theme > dl > dd{
+ width:45px;
+ float:left;
+ color:#a87;
+ font-weight:bold;
+ }
+
+ /* Content Styling */
+ #stage.theme > h1, #stage.theme > h2, #stage.theme > p{
+ margin:1em 0 .5em 13px;
+ }
+
+ #stage.theme > h1{
+ color:#eee;
+ font-size:1.6em;
+ text-align:center;
+ margin:0;
+ margin-top:15px;
+ padding:0;
+ }
+
+ #stage.theme > h2{
+ clear:both;
+ margin:0;
+ padding:3px;
+ font-size:1em;
+ text-align:center;
+ }
+
+ /* Stage Buttons */
+ #stage.theme .btn{
+ border: 1px solid #555;
+ -webkit-border-radius: 5px;
+ border-radius: 5px;
+ text-align:center;
+ display:block;
+ float:left;
+ background:#444;
+ width:150px;
+ color:#9ab;
+ font-size:1.1em;
+ text-decoration:none;
+ padding:1.2em 0;
+ margin:3px 0px 3px 5px;
+ }
+
+ #stage.theme .large{
+ width:308px;
+ padding:1.2em 0;
+ }
+
+ #stage.theme .wide{
+ width:100%;
+ padding:1.2em 0;
+ }
+
+ #stage.theme .backBtn{
+ border: 1px solid #555;
+ -webkit-border-radius: 5px;
+ border-radius: 5px;
+ text-align:center;
+ display:block;
+ float:right;
+ background:#666;
+ width:75px;
+ color:#9ab;
+ font-size:1.1em;
+ text-decoration:none;
+ padding:1.2em 0;
+ margin:3px 5px 3px 5px;
+ }
+
+ #stage.theme .input{
+ border: 1px solid #555;
+ -webkit-border-radius: 5px;
+ border-radius: 5px;
+ text-align:center;
+ display:block;
+ float:light;
+ background:#888;
+ color:#9cd;
+ font-size:1.1em;
+ text-decoration:none;
+ padding:1.2em 0;
+ margin:3px 0px 3px 5px;
+ }
+
+ #stage.theme .numeric{
+ width:100%;
+ }
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/misc/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/misc/index.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/misc/index.html
new file mode 100644
index 0000000..697cb10
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/misc/index.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width,height=device-height,user-scalable=no,maximum-scale=1.0,initial-scale=1.0" />
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8"> <!-- ISO-8859-1 -->
+ <title>Cordova Mobile Spec</title>
+ <link rel="stylesheet" href="../master.css" type="text/css" media="screen" title="no title" charset="utf-8">
+ <script type="text/javascript" charset="utf-8" src="../cordova.js"></script>
+
+
+<script type="text/javascript" charset="utf-8">
+
+ var deviceReady = false;
+
+ function roundNumber(num) {
+ var dec = 3;
+ var result = Math.round(num*Math.pow(10,dec))/Math.pow(10,dec);
+ return result;
+ }
+
+ /**
+ * Function called when page has finished loading.
+ */
+ function init() {
+ document.addEventListener("deviceready", function() {
+ deviceReady = true;
+ console.log("Device="+device.platform+" "+device.version);
+ }, false);
+ window.setTimeout(function() {
+ if (!deviceReady) {
+ alert("Error: PhoneGap did not initialize. Demo will not run correctly.");
+ }
+ },1000);
+ }
+
+</script>
+
+ </head>
+ <body onload="init();" id="stage" class="theme">
+
+ <h1>Display Other Content</h1>
+ <div id="info">
+ </div>
+ <h2>Action</h2>
+ <div class="btn large" onclick="document.location='tel:5551212';" >Call 411</div>
+ <a href="mailto:bob@abc.org?subject=My Subject&body=This is the body.%0D%0ANew line." class="btn large">Send Mail</a>
+ <a href="sms:5125551234?body=The SMS message." class="btn large">Send SMS</a>
+ <a href="http://www.google.com" class="btn large">Load Web Site</a>
+ <!-- Need new URL -->
+ <!-- a href="http://handle.library.cornell.edu/control/authBasic/authTest/" class="btn large">Basic Auth: test/this</a -->
+ <a href="page2.html" hrefbad="page2.html?me=test" class="btn large">Load another PhoneGap page</a>
+ <h2>Android Only</h2>
+ <a href="geo:0,0?q=11400 Burnet Rd, Austin, TX" class="btn large">Map IBM</a>
+ <a href="market://search?q=google" class="btn large">Search Android market</a>
+ <a href="content://media/external/images/media" class="btn large">View image app</a>
+
+ <h2> </h2><div class="backBtn" onclick="backHome();">Back</div>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/misc/page2.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/misc/page2.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/misc/page2.html
new file mode 100644
index 0000000..22026fc
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/misc/page2.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width,height=device-height,user-scalable=no,maximum-scale=1.0,initial-scale=1.0" />
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8">
+ <title>Cordova Mobile Spec</title>
+ <link rel="stylesheet" href="../master.css" type="text/css" media="screen" title="no title" charset="utf-8">
+ <script type="text/javascript" charset="utf-8" src="../cordova.js"></script>
+ <script type="text/javascript" charset="utf-8" src="../main.js"></script>
+
+ </head>
+ <body onload="init();" id="stage" class="theme">
+ <h1>Page2 App</h1>
+ <h2>This is page 2 of a PhoneGap app</h2>
+ <div id="info">
+ <h4>Platform: <span id="platform"> </span></h4>
+ <h4>Version: <span id="version"> </span></h4>
+ <h4>UUID: <span id="uuid"> </span></h4>
+ <h4>Name: <span id="name"> </span></h4>
+ <h4>Width: <span id="width"> </span>, Height: <span id="height">
+ </span>, Color Depth: <span id="colorDepth"></span></h4>
+ </div>
+ <div ><button class="backBtn" onclick="backHome();">Back</button></div>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/network/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/network/index.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/network/index.html
new file mode 100644
index 0000000..0b2204b
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/network/index.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width,height=device-height,user-scalable=no,maximum-scale=1.0,initial-scale=1.0" />
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8"> <!-- ISO-8859-1 -->
+ <title>Cordova Mobile Spec</title>
+ <link rel="stylesheet" href="../master.css" type="text/css" media="screen" title="no title" charset="utf-8">
+ <script type="text/javascript" charset="utf-8" src="../cordova.js"></script>
+
+
+<script type="text/javascript" charset="utf-8">
+
+ var deviceReady = false;
+
+ var eventOutput = function(s) {
+ var el = document.getElementById("results");
+ el.innerHTML = el.innerHTML + s + "<br>";
+ };
+
+ function printNetwork() {
+ eventOutput("Current network connection type is: " + navigator.network.connection.type);
+ }
+
+ /**
+ * Function called when page has finished loading.
+ */
+ function init() {
+ document.addEventListener("deviceready", function() {
+ deviceReady = true;
+ console.log("Device="+device.platform+" "+device.version);
+ eventOutput("Network Connection is: " + navigator.network.connection.type);
+ document.addEventListener('online', function() { eventOutput('Online event, connection is: ' + navigator.network.connection.type); }, false);
+ document.addEventListener('offline', function() { eventOutput('Offline event, connection is: ' + navigator.network.connection.type); }, false);
+
+ }, false);
+ window.setTimeout(function() {
+ if (!deviceReady) {
+ alert("Error: Cordova did not initialize. Demo will not run correctly.");
+ }
+ },1000);
+ }
+
+</script>
+
+ </head>
+ <body onload="init();" id="stage" class="theme">
+
+ <h1>Network Events and State</h1>
+ <div id="info">
+ <b>Results:</b><br>
+ <span id="results"></span>
+ </div>
+
+ <h2>Action</h2>
+ <div class="btn large" onclick="printNetwork();">Show Network Connection</div>
+ <h2> </h2><div class="backBtn" onclick="backHome();">Back</div>
+ </body>
+</html>
+
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/notification/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/notification/index.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/notification/index.html
new file mode 100644
index 0000000..e5c0d17
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/notification/index.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width,height=device-height,user-scalable=no,maximum-scale=1.0,initial-scale=1.0" />
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8"> <!-- ISO-8859-1 -->
+ <title>Cordova Mobile Spec</title>
+ <link rel="stylesheet" href="../master.css" type="text/css" media="screen" title="no title" charset="utf-8">
+ <script type="text/javascript" charset="utf-8" src="../cordova.js"></script>
+
+
+<script type="text/javascript" charset="utf-8">
+
+ var deviceReady = false;
+
+ //-------------------------------------------------------------------------
+ // Notifications
+ //-------------------------------------------------------------------------
+
+ var beep = function(){
+ navigator.notification.beep(3);
+ };
+
+ var vibrate = function(){
+ navigator.notification.vibrate(1000);
+ };
+
+ var alertDialog = function(message, title, button) {
+ console.log("alertDialog()");
+ navigator.notification.alert(message,
+ function(){
+ console.log("Alert dismissed.");
+ },
+ title, button);
+ console.log("After alert");
+ };
+
+ var confirmDialog = function(message, title, buttons) {
+ navigator.notification.confirm(message,
+ function(r) {
+ console.log("You selected " + r);
+ alert("You selected " + (buttons.split(","))[r-1]);
+ },
+ title,
+ buttons);
+ };
+
+ /**
+ * Function called when page has finished loading.
+ */
+ function init() {
+ document.addEventListener("deviceready", function() {
+ deviceReady = true;
+ console.log("Device="+device.platform+" "+device.version);
+ }, false);
+ window.setTimeout(function() {
+ if (!deviceReady) {
+ alert("Error: PhoneGap did not initialize. Demo will not run correctly.");
+ }
+ },1000);
+ }
+
+</script>
+
+ </head>
+ <body onload="init();" id="stage" class="theme">
+
+ <h1>Notifications and Dialogs</h1>
+ <div id="info">
+ </div>
+
+ <h2>Action</h2>
+ <div class="btn large" onclick="beep();">Beep</div>
+ <div class="btn large" onclick="vibrate();">Vibrate</div>
+ <div class="btn large" onclick="alertDialog('You pressed alert.', 'Alert Dialog', 'Continue');">Alert Dialog</div>
+ <div class="btn large" onclick="confirmDialog('You pressed confirm.', 'Confirm Dialog', 'Yes,No,Maybe');">Confirm Dialog</div>
+ <div class="btn large" onclick="alert('You pressed alert.');">Built-in Alert Dialog</div>
+ <div class="btn large" onclick="confirm('You selected confirm');">Built-in Confirm Dialog</div>
+ <div class="btn large" onclick="prompt('This is a prompt.', 'Default value');">Built-in Prompt Dialog</div>
+ <h2> </h2><div class="backBtn" onclick="backHome();">Back</div>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/sql/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/sql/index.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/sql/index.html
new file mode 100644
index 0000000..116f8d1
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/sql/index.html
@@ -0,0 +1,132 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width,height=device-height,user-scalable=no,maximum-scale=1.0,initial-scale=1.0" />
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8"> <!-- ISO-8859-1 -->
+ <title>Cordova Mobile Spec</title>
+ <link rel="stylesheet" href="../master.css" type="text/css" media="screen" title="no title" charset="utf-8">
+ <script type="text/javascript" charset="utf-8" src="../cordova.js"></script>
+
+
+<script type="text/javascript" charset="utf-8">
+
+ var deviceReady = false;
+
+ //-------------------------------------------------------------------------
+ // HTML5 Database
+ //-------------------------------------------------------------------------
+ var db;
+ var callDatabase = function() {
+ db = openDatabase("mydb", "1.0", "PhoneGap Demo", 20000);
+ if (db === null) {
+ databaseOutput("Database could not be opened.");
+ return;
+ }
+ databaseOutput("Database opened.");
+ db.transaction(function (tx) {
+ tx.executeSql('DROP TABLE IF EXISTS DEMO');
+ tx.executeSql('CREATE TABLE IF NOT EXISTS DEMO (id unique, data)', [],
+ function(tx,results) { console.log("Created table"); },
+ function(tx,err) { alert("Error creating table: "+err.message); });
+ tx.executeSql('INSERT INTO DEMO (id, data) VALUES (1, "First row")', [],
+ function(tx,results) { console.log("Insert row1 success"); },
+ function(tx,err) { alert("Error adding 1st row: "+err.message); });
+ tx.executeSql('INSERT INTO DEMO (id, data) VALUES (2, "Second row")', [],
+ function(tx,results) { console.log("Insert row2 success"); },
+ function(tx,err) { alert("Error adding 2nd row: "+err.message); });
+ databaseOutput("Data written to DEMO table.");
+ console.log("Data written to DEMO table.");
+
+ tx.executeSql('SELECT * FROM DEMO', [], function (tx, results) {
+ var len = results.rows.length;
+ var text = "DEMO table: " + len + " rows found.<br>";
+ text = text + "<table border='1'><tr><td>Row</td><td>Data</td></tr>";
+ for (var i=0; i<len; i++){
+ text = text + "<tr><td>" + i + "</td><td>" + results.rows.item(i).id + ", " + results.rows.item(i).data + "</td></tr>";
+ }
+ text = text + "</table>";
+ databaseOutput(text);
+ }, function(tx, err) {
+ alert("Error processing SELECT * SQL: "+err.message);
+ });
+ tx.executeSql('SELECT ID FROM DEMO', [], function (tx, results) {
+ var len = results.rows.length;
+ var text = "DEMO table: " + len + " rows found.<br>";
+ text = text + "<table border='1'><tr><td>Row</td><td>Data</td></tr>";
+ for (var i=0; i<len; i++){
+ text = text + "<tr><td>" + i + "</td><td>" + results.rows.item(i).id + "</td></tr>";
+ }
+ text = text + "</table>";
+ databaseOutput(text);
+ }, function(tx, err) {
+ alert("Error processing SELECT ID SQL: "+err.message);
+ });
+
+ },
+ function(err) {
+ console.log("Transaction failed: " + err.message);
+ });
+
+
+ };
+
+ var readDatabase = function() {
+ if (!db) {
+ db = openDatabase("mydb", "1.0", "PhoneGap Demo", 20000);
+ if (db === null) {
+ databaseOutput("Database could not be opened.");
+ return;
+ }
+ }
+ db.transaction(function (tx) {
+ tx.executeSql('SELECT * FROM DEMO WHERE id=2', [], function (tx, results) {
+ var len = results.rows.length;
+ var text = "DEMO table: " + len + " rows found.<br>";
+ text = text + "<table border='1'><tr><td>Row</td><td>Data</td></tr>";
+ for (var i=0; i<len; i++){
+ text = text + "<tr><td>" + i + "</td><td>" + results.rows.item(i).id + ", " + results.rows.item(i).data + "</td></tr>";
+ }
+ text = text + "</table>";
+ databaseOutput(text);
+ }, function(tx, err) {
+ alert("Error processing SELECT * WHERE id=2 SQL: "+err.message);
+ });
+ });
+ }
+
+ var databaseOutput = function(s) {
+ var el = document.getElementById("database_results");
+ el.innerHTML = el.innerHTML + s + "<br>";
+ };
+
+ /**
+ * Function called when page has finished loading.
+ */
+ function init() {
+ document.addEventListener("deviceready", function() {
+ deviceReady = true;
+ console.log("Device="+device.platform+" "+device.version);
+ }, false);
+ window.setTimeout(function() {
+ if (!deviceReady) {
+ alert("Error: PhoneGap did not initialize. Demo will not run correctly.");
+ }
+ },1000);
+ }
+
+</script>
+
+ </head>
+ <body onload="init();" id="stage" class="theme">
+
+ <h1>HTML5 Database</h1>
+ <div id="info">
+ <b>Results:</b><br>
+ <span id="database_results"></span>
+ </div>
+ <h2>Action</h2>
+ <div class="btn large" onclick="callDatabase();">Create, Add, Read Database</div>
+ <div class="btn large" onclick="readDatabase();">Read Database</div>
+ <h2> </h2><div class="backBtn" onclick="backHome();">Back</div>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/storage/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/storage/index.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/storage/index.html
new file mode 100644
index 0000000..85a0dbd
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/storage/index.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width,height=device-height,user-scalable=no,maximum-scale=1.0,initial-scale=1.0" />
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8"> <!-- ISO-8859-1 -->
+ <title>Cordova Mobile Spec</title>
+ <link rel="stylesheet" href="../master.css" type="text/css" media="screen" title="no title" charset="utf-8">
+ <script type="text/javascript" charset="utf-8" src="../cordova.js"></script>
+
+
+<script type="text/javascript" charset="utf-8">
+
+ var deviceReady = false;
+
+ /**
+ * Function called when page has finished loading.
+ */
+ function init() {
+ document.addEventListener("deviceready", function() {
+ deviceReady = true;
+ console.log("Device="+device.platform+" "+device.version);
+ }, false);
+ window.setTimeout(function() {
+ if (!deviceReady) {
+ alert("Error: PhoneGap did not initialize. Demo will not run correctly.");
+ }
+ },1000);
+ }
+
+</script>
+
+ </head>
+ <body onload="init();" id="stage" class="theme">
+
+ <h1>Local Storage</h1>
+ <div id="info">
+ You have run this app <span id="count">an untold number of</span> time(s).
+ </div>
+
+ <script>
+ if (!localStorage.pageLoadCount) {
+ localStorage.pageLoadCount = 0;
+ }
+ localStorage.pageLoadCount = parseInt(localStorage.pageLoadCount) + 1;
+ document.getElementById('count').textContent = localStorage.pageLoadCount;
+ </script>
+
+ <h2> </h2><div class="backBtn" onclick="backHome();">Back</div>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/README.md
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/README.md b/lib/cordova-wp8/tests/README.md
new file mode 100644
index 0000000..d095927
--- /dev/null
+++ b/lib/cordova-wp8/tests/README.md
@@ -0,0 +1,7 @@
+Tests Have Moved
+===
+
+Tests now live in the MobileSpec repo at:
+https://github.com/apache/cordova-mobile-spec
+
+You will need to create a new project, and add the mobile-spec files to it to run the tests.
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tooling/scripts/buildjs.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tooling/scripts/buildjs.bat b/lib/cordova-wp8/tooling/scripts/buildjs.bat
new file mode 100644
index 0000000..28d2423
--- /dev/null
+++ b/lib/cordova-wp8/tooling/scripts/buildjs.bat
@@ -0,0 +1,2 @@
+@echo off
+cscript "%~dp0\buildjs.js" %* //nologo
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tooling/scripts/buildjs.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tooling/scripts/buildjs.js b/lib/cordova-wp8/tooling/scripts/buildjs.js
new file mode 100644
index 0000000..78e213c
--- /dev/null
+++ b/lib/cordova-wp8/tooling/scripts/buildjs.js
@@ -0,0 +1,214 @@
+/*
+ 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.
+*/
+
+var fso = WScript.CreateObject('Scripting.FileSystemObject'),
+ shell = WScript.CreateObject("shell.application"),
+ wscript_shell = WScript.CreateObject("WScript.Shell");
+
+var args = WScript.Arguments,
+ //Root folder of cordova-wp8 (i.e C:\Cordova\cordova-wp8)
+ ROOT = WScript.ScriptFullName.split('\\tooling\\', 1),
+ //Sub folder containing templates
+ TEMPLATES_PATH = '\\templates',
+ //Sub folder for standalone project
+ STANDALONE_PATH = TEMPLATES_PATH + '\\standalone',
+ //Sub folder for full project
+ FULL_PATH = TEMPLATES_PATH + '\\full',
+ CUSTOM_PATH = TEMPLATES_PATH + '\\custom',
+ //Sub folder containing framework
+ FRAMEWORK_PATH = '\\framework',
+ //Subfolder containing example project
+ EXAMPLE_PATH = '\\example',
+ //Git Repositories
+ CORDOVA_JS = "https://git-wip-us.apache.org/repos/asf/cordova-js.git",
+ // get version
+ VERSION = read(ROOT+'\\VERSION').replace(/\r\n/,'').replace(/\n/,''),
+ BUILD_DESTINATION;
+
+function Log(msg) {
+ WScript.StdOut.WriteLine(msg);
+}
+
+// help function
+function Usage()
+{
+ Log("");
+ Log("This Script builds the given virsion of cordova.js and injects it into this or the given cordova-wp8 ");
+ Log("");
+ Log("Usage: buildjs [ Version PathTOCordovaWP8 ]");
+ Log(" Version : The version of cordova.js to build (must already be tagged)");
+ Log(" PathTOCordovaWP8 : The path to the cordova directory where the new cordova.js will go.");
+ Log("examples:");
+ Log(" buildjs 2.5.0rc1 //Puts cordova-2.5.0rc1 as the cordova.js in the current working directory");
+ Log(" buildjs 2.4.0 C:\\Users\\anonymous\\Desktop\\cordova-wp8 //Puts cordova-2.4.0.js in the given directory");
+ Log(" buildjs //Builds the version of cordova.js from the root folder and adds it to the working directory repo");
+ Log("");
+}
+
+// returns the contents of a file
+function read(filename) {
+ //Log('Reading in ' + filename);
+ if(fso.FileExists(filename))
+ {
+ var f=fso.OpenTextFile(filename, 1,2);
+ var s=f.ReadAll();
+ f.Close();
+ return s;
+ }
+ else
+ {
+ Log('Cannot read non-existant file : ' + filename);
+ WScript.Quit(1);
+ }
+ return null;
+}
+
+// executes a commmand in the shell
+function exec(command) {
+ var oShell=wscript_shell.Exec(command);
+ while (oShell.Status === 0) {
+ WScript.sleep(100);
+ }
+}
+
+// executes a commmand in the shell
+function exec_verbose(command) {
+ //Log("Command: " + command);
+ var oShell=wscript_shell.Exec(command);
+ while (oShell.Status === 0) {
+ //Wait a little bit so we're not super looping
+ WScript.sleep(100);
+ //Print any stdout output from the script
+ if(!oShell.StdOut.AtEndOfStream) {
+ var line = oShell.StdOut.ReadLine();
+ Log(line);
+ }
+ }
+ //Check to make sure our scripts did not encounter an error
+ if(!oShell.StdErr.AtEndOfStream)
+ {
+ var err_line = oShell.StdErr.ReadAll();
+ WScript.StdErr.WriteLine(err_line);
+ WScript.Quit(1);
+ }
+}
+
+function build_js(path)
+{
+ if(fso.FolderExists(path + '\\temp'))
+ {
+ fso.DeleteFolder(path + '\\temp', true);
+ }
+ fso.CreateFolder(path + '\\temp');
+ wscript_shell.CurrentDirectory = path + '\\temp';
+
+ Log('\tCloning js tagged with ' + VERSION + '...');
+ exec('%comspec% /c git clone ' + CORDOVA_JS + ' && cd cordova-js && git fetch && git checkout ' + VERSION );
+ if(!fso.FolderExists(path + '\\temp\\cordova-js'))
+ {
+ WScript.StdErr.WriteLine("ERROR: Failed to clone cordova-js. Aborting...");
+ WScript.Quit(1);
+ }
+ wscript_shell.CurrentDirectory = path + '\\temp\\cordova-js';
+ Log("Building Cordova.js...");
+
+ exec_verbose('%comspec% /c jake build');
+ if(!fso.FolderExists(path + '\\temp\\cordova-js\\pkg'))
+ {
+ WScript.StdErr.WriteLine("ERROR: Failed to build cordova-js. Aborting...");
+ WScript.Quit(1);
+ }
+
+ //copy the javascript wherever it needs to go.
+ wscript_shell.CurrentDirectory = path + '\\temp\\cordova-js\\pkg';
+ exec('%comspec% /c copy /Y cordova.windowsphone.js ' + path + STANDALONE_PATH + '\\www\\cordova-' + VERSION + '.js');
+ exec('%comspec% /c copy /Y cordova.windowsphone.js ' + path + FULL_PATH + '\\www\\cordova-' + VERSION + '.js');
+ exec('%comspec% /c copy /Y cordova.windowsphone.js ' + path + CUSTOM_PATH + '\\www\\cordova-' + VERSION + '.js');
+ exec('%comspec% /c copy /Y cordova.windowsphone.js ' + path + EXAMPLE_PATH + '\\www\\cordova-' + VERSION + '.js');
+
+ //TODO: Delete old cordova.js (done in reversion.js)
+
+ Log("SUCESS");
+}
+
+function set_path(some_arg)
+{
+ if(some_arg.indexOf('-p:')!= -1)
+ {
+ var path = some_arg.split('-p:')[1];
+ if(fso.FolderExists(path) && fso.FolderExists(path + '\\tooling'))
+ {
+ BUILD_DESTINATION = path;
+ return true;
+ }
+ else
+ {
+ Log("ERROR: The given path is not a cordova-wp8 repo, or");
+ Log(" does not exist. If your trying to reversion a");
+ Log(" cordova repo other then this one, please provide");
+ Log(" it's path in the form: -p:C:\\Path\\to\\repo");
+ WScript.Quit(1);
+ }
+
+ }
+ return false;
+}
+
+Log("");
+
+if(args.Count() > 1)
+{
+ set_path(args(1));
+}
+
+if(args.Count() > 0)
+{
+ //Support help flags
+ if(args(0).indexOf("--help") > -1 ||
+ args(0).indexOf("/?") > -1 )
+ {
+ Usage();
+ WScript.Quit(1);
+ }
+
+ if(args(0).match(/(\d+)[.](\d+)[.](\d+)(rc\d)?/))
+ {
+ VERSION = args(0);
+ if(args.Count() == 1)
+ {
+ BUILD_DESTINATION = ROOT;
+ }
+ }
+ else if(set_path(arg(0))) {} //do nothing
+ else
+ {
+ Log("The provided version number is invalid, please provide");
+ Log(" a version number in the format Major.Minor.Fix[rc#]");
+ Usage();
+ WScript.Quit(1);
+ }
+}
+else
+{
+ BUILD_DESTINATION = ROOT;
+}
+
+//If we haven't quit by here, build the damn javascript!
+Log("Creating js for " + BUILD_DESTINATION);
+build_js(BUILD_DESTINATION);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tooling/scripts/dist.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tooling/scripts/dist.bat b/lib/cordova-wp8/tooling/scripts/dist.bat
new file mode 100644
index 0000000..a1c0e1d
--- /dev/null
+++ b/lib/cordova-wp8/tooling/scripts/dist.bat
@@ -0,0 +1,2 @@
+@echo off
+cscript "%~dp0\dist.js" %* //nologo
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tooling/scripts/dist.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tooling/scripts/dist.js b/lib/cordova-wp8/tooling/scripts/dist.js
new file mode 100644
index 0000000..9dd93e6
--- /dev/null
+++ b/lib/cordova-wp8/tooling/scripts/dist.js
@@ -0,0 +1,202 @@
+/*
+ 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.
+*/
+
+
+/*************************************************/
+/**************** REQUIREMENTS *****************/
+/*************************************************/
+/*
+Paths:
+ - path to git.exe -> C:\msysgit\bin
+ - path to msbuild -> C:\Windows\Microsoft.NET\Framework\v4.0.30319
+Famework
+ - .NET 4.0
+ - Windows phone SDKs
+
+
+/************ Globals ********/
+
+var fso = WScript.CreateObject('Scripting.FileSystemObject'),
+ wscript_shell = WScript.CreateObject("WScript.Shell");
+
+//Replace root directory or create new directory?
+var REPLACE = false;
+
+//Set up directory structure of current release
+ //arguments passed in
+var args = WScript.Arguments,
+ //Root folder of cordova-wp8 (i.e C:\Cordova\cordova-wp8)
+ ROOT = WScript.ScriptFullName.split('\\tooling\\', 1),
+ // tooling scripts
+ SCRIPTS = '\\tooling\\scripts';
+ //Get version number
+ VERSION=read(ROOT+'\\VERSION').replace(/\r\n/,'').replace(/\n/,'');
+
+//Destination to build to
+var BUILD_DESTINATION;
+//current script that is running
+var current_script = "dist";
+
+
+/*************************************************/
+/**************** FUNCTIONS ********************/
+/*************************************************/
+
+function Log(msg) {
+ WScript.StdOut.WriteLine(msg);
+}
+
+// help function
+function Usage()
+{
+ Log("");
+ Log("This is a command line tool for building new releases. It will package a new release");
+ Log(" of a cordova-wp8 project, reversioning it to match the VERSION file in the root directory.");
+ Log("Usage: dist [ <NEW_PATH_FOR_BUILD> | -f ] ");
+ Log(" -f : force tool to reversion the current repositoy.");
+ Log(" <NEW_PATH_FOR_BUILD> : path to create the new reversioned repositoy in.");
+ Log("");
+}
+
+
+// returns the contents of a file
+function read(filename) {
+ //WScript.Echo('Reading in ' + filename);
+ if(fso.FileExists(filename))
+ {
+ var f=fso.OpenTextFile(filename, 1,2);
+ var s=f.ReadAll();
+ f.Close();
+ return s;
+ }
+ else
+ {
+ Log('Cannot read non-existant file : ' + filename);
+ WScript.Quit(1);
+ }
+ return null;
+}
+
+// executes a commmand in the shell
+function exec(command) {
+ Log("Command: " + command);
+ var oShell=wscript_shell.Exec(command);
+ while (oShell.Status === 0) {
+ //Wait a little bit so we're not super looping
+ WScript.sleep(100);
+ //Print any stdout output from the script
+ if(!oShell.StdOut.AtEndOfStream) {
+ var line = oShell.StdOut.ReadLine();
+ Log(line);
+ }
+ }
+ //Check to make sure our scripts did not encounter an error
+ if(!oShell.StdErr.AtEndOfStream)
+ {
+ var err_line = oShell.StdErr.ReadAll();
+ WScript.StdErr.WriteLine(err_line);
+ WScript.StdErr.WriteLine("ERROR: Could not complete distribution, failed while running: " + current_script);
+ WScript.Quit(1);
+ }
+}
+
+function space()
+{
+ Log("");
+ Log("*****************************************************");
+ Log("");
+}
+
+
+/*************************************************/
+/************** MAIN SCRIPT ********************/
+/*************************************************/
+
+if(REPLACE)
+{
+ BUILD_DESTINATION = ROOT;
+}
+else if(args.Count() > 0)
+{
+ if(args(0) == '-f') {
+ REPLACE = true;
+ BUILD_DESTINATION = ROOT;
+ } else {
+ BUILD_DESTINATION = args(0);
+ //Support help flags
+ if(BUILD_DESTINATION.indexOf("--help") > -1 ||
+ BUILD_DESTINATION.indexOf("/?") > -1 )
+ {
+ Usage();
+ WScript.Quit(1);
+ }
+ }
+
+}
+else
+{
+ Usage();
+ WScript.Quit(1);
+}
+
+
+/*************************************************/
+/****************** Step 1 *********************/
+/*************************************************/
+/** - Copy source code to new directory **/
+/*************************************************/
+if (!REPLACE) {
+ current_script = "new.js";
+ exec('cscript ' + ROOT + SCRIPTS + '\\new.js ' + BUILD_DESTINATION + ' //nologo');
+ space();
+}
+
+/*************************************************/
+/****************** Step 2 *********************/
+/*************************************************/
+/** - Retag everything with new version numbers **/
+/** - Delete any generated files and cordova.js **/
+/** - Rebuild dll **/
+/*************************************************/
+current_script = "reversion.js";
+exec('cscript ' + BUILD_DESTINATION + SCRIPTS + '\\reversion.js ' + VERSION + ' //nologo');
+space();
+
+/*************************************************/
+/****************** Step 3 *********************/
+/*************************************************/
+/** - Download tagged version of cordova.js **/
+/** - build cordova.js **/
+/** - windows.cordova.js -> templates + example **/
+/*************************************************/
+current_script = "buildjs.js";
+exec('cscript ' + BUILD_DESTINATION + SCRIPTS + '\\buildjs.js //nologo');
+space();
+
+/*************************************************/
+/****************** Step 5 *********************/
+/*************************************************/
+/** - Build templates **/
+/** - Zip templates **/
+/** - inject into Visual Studio **/
+/*************************************************/
+current_script = "package.js";
+exec('cscript ' + BUILD_DESTINATION + SCRIPTS + '\\package.js //nologo');
+space();
+Log("Distribution Complete.");
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tooling/scripts/new.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tooling/scripts/new.bat b/lib/cordova-wp8/tooling/scripts/new.bat
new file mode 100644
index 0000000..cb08e2e
--- /dev/null
+++ b/lib/cordova-wp8/tooling/scripts/new.bat
@@ -0,0 +1,2 @@
+@echo off
+cscript "%~dp0\new.js" %* //nologo
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tooling/scripts/new.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tooling/scripts/new.js b/lib/cordova-wp8/tooling/scripts/new.js
new file mode 100644
index 0000000..7462965
--- /dev/null
+++ b/lib/cordova-wp8/tooling/scripts/new.js
@@ -0,0 +1,151 @@
+/*
+ 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.
+*/
+
+var fso = WScript.CreateObject('Scripting.FileSystemObject'),
+ shell = WScript.CreateObject("shell.application"),
+ wscript_shell = WScript.CreateObject("WScript.Shell");
+
+var args = WScript.Arguments,
+ //Root folder of cordova-wp8 (i.e C:\Cordova\cordova-wp8)
+ ROOT = WScript.ScriptFullName.split('\\tooling\\', 1),
+ //Sub folder containing templates
+ TEMPLATES_PATH = '\\templates',
+ //Sub folder containing framework
+ FRAMEWORK_PATH = '\\framework',
+ //Subfolder containing example project
+ EXAMPLE_PATH = '\\example';
+// git repo for cordova-wp8
+var CORDOVA_WP8 = 'https://git-wip-us.apache.org/repos/asf/cordova-wp8.git';
+//Destination to build to
+var BUILD_DESTINATION;
+// pull the project down from github?
+var GET_NEW = false;
+
+// help function
+function Usage()
+{
+ WScript.StdOut.WriteLine("");
+ WScript.StdOut.WriteLine("Usage: new [ PathToDestinationFolder ]");
+ WScript.StdOut.WriteLine(" PathToDestinationFolder : Folder you wish to be created for a new cordova-wp8 repo");
+ WScript.StdOut.WriteLine("examples:");
+ WScript.StdOut.WriteLine(" new C:\\Users\\anonymous\\Desktop\\cordova-wp8");
+ WScript.StdOut.WriteLine("");
+}
+
+// returns the contents of a file
+function read(filename) {
+ //WScript.StdOut.WriteLine('Reading in ' + filename);
+ if(fso.FileExists(filename))
+ {
+ var f=fso.OpenTextFile(filename, 1,2);
+ var s=f.ReadAll();
+ f.Close();
+ return s;
+ }
+ else
+ {
+ WScript.StdErr.WriteLine('Cannot read non-existant file : ' + filename);
+ WScript.Quit(1);
+ }
+ return null;
+}
+
+// executes a commmand in the shell
+function exec(command) {
+ var oShell=wscript_shell.Exec(command);
+ while (oShell.Status === 0) {
+ WScript.sleep(100);
+ }
+}
+
+function copy_to(path)
+{
+ //Copy everything over to BUILD_DESTINATION
+ var dest = shell.NameSpace(path);
+ WScript.StdOut.WriteLine("Copying files to build directory...");
+
+ /** copy by file instead? (just what we need)**/
+ dest.CopyHere(ROOT + "\\bin", 4|20);
+ dest.CopyHere(ROOT + EXAMPLE_PATH, 4|20); //Should mostly be copied from standalone
+ dest.CopyHere(ROOT + FRAMEWORK_PATH, 4|20);
+ dest.CopyHere(ROOT + TEMPLATES_PATH, 4|20);
+ dest.CopyHere(ROOT + "\\tests", 4|20);
+ dest.CopyHere(ROOT + "\\tooling", 4|20);
+ dest.CopyHere(ROOT + "\\.gitignore", 4|20);
+ dest.CopyHere(ROOT + "\\LICENSE", 4|20);
+ dest.CopyHere(ROOT + "\\NOTICE", 4|20);
+ dest.CopyHere(ROOT + "\\README.md", 4|20);
+ dest.CopyHere(ROOT + "\\VERSION", 4|20);
+}
+
+WScript.StdOut.WriteLine("");
+
+if(args.Count() > 0)
+{
+ if(fso.FolderExists(args(0)))
+ {
+ WScript.StdErr.WriteLine("The given directory already exists!");
+ Usage();
+ WScript.Quit(1);
+ }
+ else
+ {
+ BUILD_DESTINATION = args(0);
+
+ }
+
+ if(!GET_NEW) {
+
+ if(fso.FolderExists(BUILD_DESTINATION))
+ {
+ WScript.StdErr.WriteLine("The given directory already exists!");
+ Usage();
+ WScript.Quit(1);
+ }
+ else
+ {
+ BUILD_DESTINATION = args(0);
+ }
+
+ // set up file structure
+ fso.CreateFolder(BUILD_DESTINATION);
+ // copy nessisary files
+ copy_to(BUILD_DESTINATION);
+ }
+ else
+ {
+ wscript_shell.CurrentDirectory = arg(0) + '\\..';
+ BUILD_DESTINATION = wscript_shell.CurrentDirectory + '\\cordova-wp8';
+
+ WScript.StdOut.WriteLine('Cloning cordova-wp8 from git, build destination now ' + BUILD_DESTINATION);
+ if(fso.FolderExists(BUILD_DESTINATION))
+ {
+ WScript.StdErr.WriteLine("Could not clone cordova-wp8 from git because it's directory already exists!");
+ WScript.Quit(1);
+ }
+
+ exec('git clone ' + CORDOVA_WP8); //git fetch --tags && git checkout?
+
+ }
+}
+else
+{
+ Usage();
+ WScript.Quit(1);
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tooling/scripts/package.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tooling/scripts/package.bat b/lib/cordova-wp8/tooling/scripts/package.bat
new file mode 100644
index 0000000..c00551e
--- /dev/null
+++ b/lib/cordova-wp8/tooling/scripts/package.bat
@@ -0,0 +1,2 @@
+@echo off
+cscript "%~dp0\package.js" %* //nologo
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tooling/scripts/package.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tooling/scripts/package.js b/lib/cordova-wp8/tooling/scripts/package.js
new file mode 100644
index 0000000..57a7340
--- /dev/null
+++ b/lib/cordova-wp8/tooling/scripts/package.js
@@ -0,0 +1,213 @@
+/*
+ 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.
+*/
+
+var fso = WScript.CreateObject('Scripting.FileSystemObject'),
+ shell = WScript.CreateObject("shell.application"),
+ wscript_shell = WScript.CreateObject("WScript.Shell");
+
+var args = WScript.Arguments,
+ // root folder of cordova-wp8 (i.e C:\Cordova\cordova-wp8)
+ ROOT = WScript.ScriptFullName.split('\\tooling\\', 1),
+ // sub folder containing templates
+ TEMPLATES_PATH = '\\templates',
+ // sub folder for standalone project
+ STANDALONE_PATH = TEMPLATES_PATH + '\\standalone',
+ // sub folder containing framework
+ FRAMEWORK_PATH = '\\framework',
+ // subfolder containing example project
+ EXAMPLE_PATH = '\\example',
+ // get version number
+ VERSION=read(ROOT+'\\VERSION').replace(/\r\n/,'').replace(/\n/,''),
+ BASE_VERSION = VERSION.split('rc', 1) + ".0";
+
+// destination directory to package
+var BUILD_DESTINATION;
+// add templates to visual studio?
+var ADD_TO_VS = false;
+// build the dll?
+var BUILD_DLL = false;
+
+function Log(msg) { WScript.StdOut.WriteLine(msg); }
+
+// help function
+function Usage()
+{
+ Log("");
+ Log("Usage: package [ PathToCordovaWP8 ]");
+ Log(" PathToCordovaWP8 : Cordova-wp8 repo you wish to package for release");
+ Log("examples:");
+ Log(" package C:\\Users\\anonymous\\Desktop\\cordova-wp8");
+ Log(" package // packages current cordova directory");
+ Log("");
+}
+
+// returns the contents of a file
+function read(filename) {
+ //Log('Reading in ' + filename);
+ if(fso.FileExists(filename))
+ {
+ var f=fso.OpenTextFile(filename, 1,2);
+ var s=f.ReadAll();
+ f.Close();
+ return s;
+ }
+ else
+ {
+ Log('ERROR: Cannot read non-existant file : ' + filename);
+ WScript.Quit(1);
+ }
+ return null;
+}
+
+// executes a commmand in the shell
+function exec(command) {
+ var oShell=wscript_shell.Exec(command);
+ while (oShell.Status === 0) {
+ WScript.sleep(100);
+ }
+}
+
+// executes a commmand in the shell
+function exec_verbose(command) {
+ Log("Command: " + command);
+ var oShell=wscript_shell.Exec(command);
+ while (oShell.Status === 0) {
+ //Wait a little bit so we're not super looping
+ WScript.sleep(100);
+ //Print any stdout output from the script
+ if(!oShell.StdOut.AtEndOfStream) {
+ var line = oShell.StdOut.ReadLine();
+ Log(line);
+ }
+ }
+ //Check to make sure our scripts did not encounter an error
+ if(!oShell.StdErr.AtEndOfStream)
+ {
+ var err_line = oShell.StdErr.ReadAll();
+ WScript.StdErr.WriteLine(err_line);
+ WScript.Quit(1);
+ }
+}
+
+// packages templates into .zip
+function package_templates()
+{
+ Log("Creating template .zip files ...");
+
+ var template_path = BUILD_DESTINATION + '\\CordovaWP8_' + VERSION.replace(/\./g, '_') + '.zip';
+ if(fso.FileExists(template_path))
+ {
+ fso.DeleteFile(template_path);
+ }
+
+ exec('%comspec% /c copy /Y ' + BUILD_DESTINATION + TEMPLATES_PATH + '\\vs\\MyTemplateStandAlone.vstemplate ' + BUILD_DESTINATION + STANDALONE_PATH + '\\MyTemplate.vstemplate');
+ exec('%comspec% /c copy /Y ' + BUILD_DESTINATION + TEMPLATES_PATH + '\\vs\\pg_templateIcon.png ' + BUILD_DESTINATION + STANDALONE_PATH + '\\__TemplateIcon.png');
+ exec('%comspec% /c copy /Y ' + BUILD_DESTINATION + TEMPLATES_PATH + '\\vs\\pg_templatePreview.jpg ' + BUILD_DESTINATION + STANDALONE_PATH + '\\__PreviewImage.jpg');
+ exec('%comspec% /c copy /Y ' + BUILD_DESTINATION + '\\VERSION ' + BUILD_DESTINATION + STANDALONE_PATH);
+
+ exec_verbose('cscript ' + BUILD_DESTINATION + '\\tooling\\scripts\\win-zip.js ' + template_path + ' ' + BUILD_DESTINATION + STANDALONE_PATH + '\\');
+
+
+ if(ADD_TO_VS)
+ {
+ var template_dir = wscript_shell.ExpandEnvironmentStrings("%USERPROFILE%") + '\\Documents\\Visual Studio 2012\\Templates\\ProjectTemplates';
+ if(fso.FolderExists(template_dir ))
+ {
+ dest = shell.NameSpace(template_dir);
+ dest.CopyHere(template_path, 4|20);
+ }
+ else
+ {
+ Log("WARNING: Could not find template directory in Visual Studio,\n you can manually copy over the template .zip files.");
+ }
+ }
+}
+
+// builds the new cordova dll and copys it to the full template (only done because of the version referance in Device.cs)
+function build_dll()
+{
+ Log("Packaging .dll ...");
+ // move to framework directory
+ wscript_shell.CurrentDirectory = BUILD_DESTINATION + FRAMEWORK_PATH;
+ // build .dll in Release
+ exec_verbose('msbuild /p:Configuration=Release;VersionNumber=' + VERSION + ';BaseVersionNumber=' + BASE_VERSION);
+ //Check if file dll was created
+ if(!fso.FileExists(BUILD_DESTINATION + FRAMEWORK_PATH + '\\Bin\\Release\\WPCordovaClassLib.dll'))
+ {
+ WScript.StdErr.WriteLine('ERROR: MSBuild failed to create .dll.');
+ WScript.Quit(1);
+ }
+
+ Log("SUCESS");
+}
+
+// delete any unnessisary files when finished
+function cleanUp() {
+
+ if(fso.FileExists(BUILD_DESTINATION + STANDALONE_PATH + '\\MyTemplate.vstemplate')) {
+ fso.DeleteFile(BUILD_DESTINATION + STANDALONE_PATH + '\\MyTemplate.vstemplate');
+ }
+ if(fso.FileExists(BUILD_DESTINATION + STANDALONE_PATH + '\\__PreviewImage.jpg')) {
+ fso.DeleteFile(BUILD_DESTINATION + STANDALONE_PATH + '\\__PreviewImage.jpg');
+ }
+ if(fso.FileExists(BUILD_DESTINATION + STANDALONE_PATH + '\\__TemplateIcon.png')) {
+ fso.DeleteFile(BUILD_DESTINATION + STANDALONE_PATH + '\\__TemplateIcon.png');
+ }
+ //Add any other cleanup here
+}
+
+
+Log("");
+
+if(args.Count() > 0)
+{
+ //Support help flags
+ if(args(0).indexOf("--help") > -1 ||
+ args(0).indexOf("/?") > -1 )
+ {
+ Usage();
+ WScript.Quit(1);
+ }
+
+ if(fso.FolderExists(args(0)) && fso.FolderExists(args(0) + '\\tooling'))
+ {
+ BUILD_DESTINATION = args(0);
+ }
+ else
+ {
+ Log("ERROR: The given directory is not a cordova-wp8 repo.");
+ Usage();
+ WScript.Quit(1);
+
+ }
+}
+else
+{
+ BUILD_DESTINATION = ROOT;
+}
+
+// build dll for full template
+if (BUILD_DLL) {
+ build_dll();
+}
+
+// build/package the templates
+package_templates(BUILD_DESTINATION);
+
+cleanUp();
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tooling/scripts/reversion.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tooling/scripts/reversion.bat b/lib/cordova-wp8/tooling/scripts/reversion.bat
new file mode 100644
index 0000000..b35ab08
--- /dev/null
+++ b/lib/cordova-wp8/tooling/scripts/reversion.bat
@@ -0,0 +1,2 @@
+@echo off
+cscript "%~dp0\reversion.js" %* //nologo
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tooling/scripts/reversion.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tooling/scripts/reversion.js b/lib/cordova-wp8/tooling/scripts/reversion.js
new file mode 100644
index 0000000..a726817
--- /dev/null
+++ b/lib/cordova-wp8/tooling/scripts/reversion.js
@@ -0,0 +1,280 @@
+/*
+ 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.
+*/
+
+
+/************ Globals ********/
+
+var fso = WScript.CreateObject('Scripting.FileSystemObject'),
+ shell = WScript.CreateObject("shell.application"),
+ wscript_shell = WScript.CreateObject("WScript.Shell");
+
+//Get new version from git or build off this version?
+var GET_NEW = false;
+
+//Set up directory structure of current release
+ //arguments passed in
+var args = WScript.Arguments,
+ //Root folder of cordova-wp8 (i.e C:\Cordova\cordova-wp8)
+ ROOT = WScript.ScriptFullName.split('\\tooling\\', 1),
+ //Sub folder containing templates
+ TEMPLATES_PATH = '\\templates',
+ //Sub folder for standalone project
+ STANDALONE_PATH = TEMPLATES_PATH + '\\standalone',
+ //Sub folder containing framework
+ FRAMEWORK_PATH = '\\framework',
+ //Subfolder containing example project
+ EXAMPLE_PATH = '\\example',
+ //Path to cordovalib folder, containing source for .dll
+ CORDOVA_LIB = STANDALONE_PATH + '\\cordovalib',
+ //Get version number
+ VERSION='',
+ BASE_VERSION = '';
+
+//Destination to build to
+var BUILD_DESTINATION;
+
+// help function
+function Usage()
+{
+ WScript.StdOut.WriteLine("");
+ WScript.StdOut.WriteLine("Usage: reversion [ Version PathTOCordovaWP8 ]");
+ WScript.StdOut.WriteLine(" Version : The new version for codova-wp8");
+ WScript.StdOut.WriteLine(" PathTOCordovaWP8 : The path to the cordova directory being reversioned.");
+ WScript.StdOut.WriteLine("examples:");
+ WScript.StdOut.WriteLine(" reversion 2.5.0rc1 //Reversions the current working directory");
+ WScript.StdOut.WriteLine(" reversion 2.5.0 C :\\Users\\anonymous\\Desktop\\cordova-wp8");
+ WScript.StdOut.WriteLine("");
+}
+
+var ForReading = 1, ForWriting = 2, ForAppending = 8;
+var TristateUseDefault = -2, TristateTrue = -1, TristateFalse = 0;
+
+// returns the contents of a file
+function read(filename) {
+ //WScript.Echo('Reading in ' + filename);
+ if(fso.FileExists(filename))
+ {
+ var f=fso.OpenTextFile(filename, 1,2);
+ var s=f.ReadAll();
+ f.Close();
+ return s;
+ }
+ else
+ {
+ WScript.StdErr.WriteLine('Cannot read non-existant file : ' + filename);
+ WScript.Quit(1);
+ }
+ return null;
+}
+
+// writes the contents to the specified file
+function write(filename, contents) {
+ var f=fso.OpenTextFile(filename, ForWriting, TristateTrue);
+ f.Write(contents);
+ f.Close();
+}
+
+// replaces the matches of regexp with replacement
+function replaceInFile(filename, regexp, replacement) {
+ //WScript.Echo("Replaceing with "+replacement+ " in:");
+ var text = read(filename).replace(regexp,replacement);
+ //WScript.Echo(text);
+ write(filename,text);
+}
+
+// executes a commmand in the shell
+function exec(command) {
+ var oShell=wscript_shell.Exec(command);
+ while (oShell.Status === 0) {
+ WScript.sleep(100);
+ }
+}
+
+// executes a commmand in the shell
+function exec_verbose(command) {
+ //WScript.StdOut.WriteLine("Command: " + command);
+ var oShell=wscript_shell.Exec(command);
+ while (oShell.Status === 0) {
+ //Wait a little bit so we're not super looping
+ WScript.sleep(100);
+ //Print any stdout output from the script
+ if(!oShell.StdOut.AtEndOfStream) {
+ var line = oShell.StdOut.ReadLine();
+ WScript.StdOut.WriteLine(line);
+ }
+ }
+ //Check to make sure our scripts did not encounter an error
+ if(!oShell.StdErr.AtEndOfStream)
+ {
+ var err_line = oShell.StdErr.ReadAll();
+ WScript.StdErr.WriteLine(err_line);
+ WScript.Quit(1);
+ }
+}
+
+function updateVersionNumbers() {
+ WScript.StdOut.WriteLine("Updating version numbers....");
+ var version_regex = /(\d+)[.](\d+)[.](\d+)(rc\d)?/;
+ replaceInFile(BUILD_DESTINATION + '\\VERSION', version_regex, VERSION);
+ // replace assembaly versions in framework
+ var framework_regex = /Description\(\"(\d+)[.](\d+)[.](\d+)(rc\d)?\"\)\]/; //Will match ("x.x.x[rcx]")]
+ replaceInFile(BUILD_DESTINATION + FRAMEWORK_PATH + "\\Properties\\AssemblyInfo.cs", framework_regex, "Description(\"" + VERSION + "\")]");
+ framework_regex = /Version\(\"(\d+)[.](\d+)[.](\d+)[.](\d+)\"\)\]/g;
+ replaceInFile(BUILD_DESTINATION + FRAMEWORK_PATH + "\\Properties\\AssemblyInfo.cs", framework_regex, "Version(\"" + BASE_VERSION + "\")]");
+
+ // update standalone project
+ exec('%comspec% /c copy /Y /V ' + BUILD_DESTINATION + "\\VERSION " + BUILD_DESTINATION + STANDALONE_PATH + "\\VERSION");
+ var cordova_regex = /cordova-(\d+)[.](\d+)[.](\d+)(rc\d)?/g; //Matches *first* cordova-x.x.x[rcx] (just ad g at end to make global)
+ replaceInFile(BUILD_DESTINATION + STANDALONE_PATH + '\\CordovaAppProj.csproj', cordova_regex, "cordova-" + VERSION);
+ replaceInFile(BUILD_DESTINATION + STANDALONE_PATH + '\\www\\index.html', cordova_regex, "cordova-" + VERSION);
+ version_regex = /return\s*\"(\d+)[.](\d+)[.](\d+)(rc\d)?/; //Matches return "x.x.x[rcx]
+
+ WScript.StdOut.WriteLine("path = " + BUILD_DESTINATION + CORDOVA_LIB + '\\Plugins\\Device.cs');
+ replaceInFile(BUILD_DESTINATION + CORDOVA_LIB + '\\..\\Plugins\\Device.cs', version_regex, "return \"" + VERSION);
+
+ // update example proj
+ replaceInFile(BUILD_DESTINATION + EXAMPLE_PATH + '\\CordovaExample.csproj', cordova_regex, "cordova-" + VERSION);
+ version_regex = /VERSION\s*\=\s*\'(\d+)[.](\d+)[.](\d+)(rc\d)?/; //Matches VERSION = x.x.x[rcx]
+ replaceInFile(BUILD_DESTINATION + EXAMPLE_PATH + '\\www\\cordova-current.js', version_regex, "VERSION = \'" + VERSION);
+
+ // update template discription
+ version_regex = /Cordova\s*(\d+)[.](\d+)[.](\d+)(rc\d)?\s*Windows/g; //Matches version: x.x.x[rcx]
+ replaceInFile(BUILD_DESTINATION + TEMPLATES_PATH + '\\vs\\description.txt', version_regex, "Cordova " + VERSION + " Windows");
+
+ // update .vstemplate files for the template zips.
+ var name_regex = /CordovaWP8[_](\d+)[_](\d+)[_](\d+)(rc\d)?/g;
+ var discript_regex = /Cordova\s*(\d+)[.](\d+)[.](\d+)(rc\d)?/;
+
+ replaceInFile(BUILD_DESTINATION + TEMPLATES_PATH + '\\vs\\MyTemplateStandAlone.vstemplate', name_regex, 'CordovaWP8_' + VERSION.replace(/\./g, '_'));
+ replaceInFile(BUILD_DESTINATION + TEMPLATES_PATH + '\\vs\\MyTemplateStandAlone.vstemplate', discript_regex, "Cordova " + VERSION);
+ replaceInFile(BUILD_DESTINATION + TEMPLATES_PATH + '\\vs\\MyTemplateStandAlone.vstemplate', cordova_regex, "cordova-" + VERSION);
+}
+
+// delete all cordova.js and generated files (templates) from old version numbers
+function cleanup()
+{
+ WScript.StdOut.WriteLine("Cleanup");
+ // remove old template .zip files
+ if(fso.FileExists(BUILD_DESTINATION + '\\*.zip'))
+ {
+ fso.DeleteFile(BUILD_DESTINATION + '\\*.zip');
+ }
+ // remove any generated framework files
+ if(fso.FolderExists(BUILD_DESTINATION + FRAMEWORK_PATH + '\\Bin'))
+ {
+ fso.DeleteFolder(BUILD_DESTINATION + FRAMEWORK_PATH + '\\Bin');
+ }
+ if(fso.FolderExists(BUILD_DESTINATION + FRAMEWORK_PATH + '\\obj'))
+ {
+ fso.DeleteFolder(BUILD_DESTINATION + FRAMEWORK_PATH + '\\obj');
+ }
+ // remove any generated CordovaDeploy
+ if(fso.FolderExists(BUILD_DESTINATION + '\\tooling\\CordovaDeploy\\CordovaDeploy\\bin'))
+ {
+ fso.DeleteFolder(BUILD_DESTINATION + '\\tooling\\CordovaDeploy\\CordovaDeploy\\bin');
+ }
+ if(fso.FolderExists(BUILD_DESTINATION + '\\tooling\\CordovaDeploy\\CordovaDeploy\\obj'))
+ {
+ fso.DeleteFolder(BUILD_DESTINATION + '\\tooling\\CordovaDeploy\\CordovaDeploy\\obj');
+ }
+ //remove old template .zip files
+ WScript.Echo(BUILD_DESTINATION);
+ var root_folder = shell.NameSpace(BUILD_DESTINATION + '\\').Items();
+ for(var i = 0; i < root_folder.Count; i++)
+ {
+ if(root_folder.Item(i).Name.match(/CordovaWP8[_](\d+)[_](\d+)[_](\d+)(rc\d)?/))
+ {
+ fso.DeleteFile(BUILD_DESTINATION + '\\' + root_folder.Item(i).Name);
+ }
+ }
+ // remove old cordova.js
+ var example_www = shell.NameSpace(BUILD_DESTINATION + EXAMPLE_PATH + '\\www').Items();
+ for(i = 0; i < example_www.Count; i++)
+ {
+ if(example_www.Item(i).Name.match(/cordova\-(\d+)[.](\d+)[.](\d+)(rc\d)?[.]js/))
+ {
+ fso.DeleteFile(BUILD_DESTINATION + EXAMPLE_PATH + '\\www\\' + example_www.Item(i).Name);
+ }
+ }
+
+ var standalone_www = shell.NameSpace(BUILD_DESTINATION + STANDALONE_PATH + '\\www').Items();
+ for(i = 0; i < standalone_www.Count; i++)
+ {
+ if(standalone_www.Item(i).Name.match(/cordova\-(\d+)[.](\d+)[.](\d+)(rc\d)?[.]js/))
+ {
+ fso.DeleteFile(BUILD_DESTINATION + STANDALONE_PATH + '\\www\\' + standalone_www.Item(i).Name);
+ }
+ }
+}
+
+
+WScript.StdOut.WriteLine("");
+
+if(args.Count() > 1)
+{
+ if(fso.FolderExists(args(1)) && fso.FolderExists(args(1) + '\\tooling'))
+ {
+ BUILD_DESTINATION = args(1);
+ }
+ else
+ {
+ WScript.StdErr.WriteLine("The given path is not a cordova-wp8 repo, if");
+ WScript.StdErr.WriteLine(" your trying to reversion a cordova-wp8 repo");
+ WScript.StdErr.WriteLine(" other then this one, please provide its path.");
+ Usage();
+ WScript.Quit(1);
+ }
+}
+
+if(args.Count() > 0)
+{
+ //Support help flags
+ if(args(0).indexOf("--help") > -1 ||
+ args(0).indexOf("/?") > -1 )
+ {
+ Usage();
+ WScript.Quit(1);
+ }
+
+ if(args(0).match(/(\d+)[.](\d+)[.](\d+)(rc\d)?/))
+ {
+ VERSION = args(0);
+ BASE_VERSION = VERSION.split('rc', 1) + ".0";
+ if(args.Count() < 2)
+ {
+ BUILD_DESTINATION = ROOT;
+ }
+ // remove old cordova.js files and any generated files
+ cleanup();
+ // update version numbers
+ updateVersionNumbers();
+ }
+ else
+ {
+ WScript.StdOut.WriteLine("The version number is invalid, please provide");
+ WScript.StdOut.WriteLine(" a version number in the format Major.Minor.Fix[rc#]");
+ Usage();
+ WScript.Quit(1);
+ }
+}
+else
+{
+ Usage();
+ WScript.Quit(1);
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tooling/scripts/win-zip.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tooling/scripts/win-zip.js b/lib/cordova-wp8/tooling/scripts/win-zip.js
new file mode 100644
index 0000000..7a79f43
--- /dev/null
+++ b/lib/cordova-wp8/tooling/scripts/win-zip.js
@@ -0,0 +1,43 @@
+/*
+ * Script for zipping the contents of a directory.
+ */
+
+// get commman line arguments
+var objArgs = WScript.Arguments;
+var zipPath = objArgs(0);
+var sourcePath = objArgs(1);
+
+
+// create empty ZIP file and open for adding
+var fso = new ActiveXObject("Scripting.FileSystemObject");
+var file = fso.CreateTextFile(zipPath, true);
+
+// create twenty-two byte "fingerprint" for .zip
+file.write("PK");
+file.write(String.fromCharCode(5));
+file.write(String.fromCharCode(6));
+file.write('\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0');
+file.Close();
+
+// open .zip foder and copy contents of sourcePath
+var objShell = new ActiveXObject("shell.application");
+var zipFolder = objShell.NameSpace(zipPath);
+var sourceItems = objShell.NameSpace(sourcePath).items();
+if (zipFolder !== null) {
+ zipFolder.CopyHere(sourceItems, 4|20|16);
+ var maxTime = 5000;
+ while(zipFolder.items().Count < sourceItems.Count)
+ {
+ maxTime -= 100;
+ if(maxTime > 0 ) {
+ WScript.Sleep(100);
+ }
+ else {
+ WScript.StdErr.WriteLine('Failed to create .zip file.');
+ break;
+ }
+ }
+}
+else {
+ WScript.StdErr.WriteLine('Failed to create .zip file.');
+}
\ No newline at end of file
[29/37] Add WP7 and WP8 platform files.
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/Accelerometer.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/Accelerometer.cs b/lib/cordova-wp7/templates/standalone/Plugins/Accelerometer.cs
new file mode 100644
index 0000000..cba911c
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/Accelerometer.cs
@@ -0,0 +1,196 @@
+/*
+ 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.Runtime.Serialization;
+using System.Threading;
+using Microsoft.Devices.Sensors;
+using System.Globalization;
+using System.Diagnostics;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ /// <summary>
+ /// Captures device motion in the x, y, and z direction.
+ /// </summary>
+ public class Accelerometer : BaseCommand
+ {
+ #region AccelerometerOptions class
+ /// <summary>
+ /// Represents Accelerometer options.
+ /// </summary>
+ [DataContract]
+ public class AccelerometerOptions
+ {
+ /// <summary>
+ /// How often to retrieve the Acceleration in milliseconds
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "frequency")]
+ public int Frequency { get; set; }
+
+ /// <summary>
+ /// Watcher id
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "id")]
+ public string Id { get; set; }
+
+ /// <summary>
+ /// Creates options object with default parameters
+ /// </summary>
+ public AccelerometerOptions()
+ {
+ this.SetDefaultValues(new StreamingContext());
+ }
+
+ /// <summary>
+ /// Initializes default values for class fields.
+ /// Implemented in separate method because default constructor is not invoked during deserialization.
+ /// </summary>
+ /// <param name="context"></param>
+ [OnDeserializing()]
+ public void SetDefaultValues(StreamingContext context)
+ {
+ this.Frequency = 10000;
+ }
+ }
+
+ #endregion
+
+ #region Status codes and Constants
+
+ public const int Stopped = 0;
+ public const int Starting = 1;
+ public const int Running = 2;
+ public const int ErrorFailedToStart = 3;
+
+ public const double gConstant = -9.81;
+
+ #endregion
+
+ #region Static members
+
+ /// <summary>
+ /// Status of listener
+ /// </summary>
+ private static int currentStatus;
+
+ /// <summary>
+ /// Accelerometer
+ /// </summary>
+ private static Microsoft.Devices.Sensors.Accelerometer accelerometer = new Microsoft.Devices.Sensors.Accelerometer();
+
+ private static DateTime StartOfEpoch = new DateTime(1970, 1, 1, 0, 0, 0);
+
+ #endregion
+
+ /// <summary>
+ /// Sensor listener event
+ /// </summary>
+ private void accelerometer_CurrentValueChanged(object sender, SensorReadingEventArgs<AccelerometerReading> e)
+ {
+ this.SetStatus(Running);
+
+ PluginResult result = new PluginResult(PluginResult.Status.OK, GetCurrentAccelerationFormatted());
+ result.KeepCallback = true;
+ DispatchCommandResult(result);
+ }
+
+ /// <summary>
+ /// Starts listening for acceleration sensor
+ /// </summary>
+ /// <returns>status of listener</returns>
+ public void start(string options)
+ {
+ if ((currentStatus == Running) || (currentStatus == Starting))
+ {
+ return;
+ }
+ try
+ {
+ lock (accelerometer)
+ {
+ accelerometer.CurrentValueChanged += accelerometer_CurrentValueChanged;
+ accelerometer.Start();
+ this.SetStatus(Starting);
+ }
+
+ long timeout = 2000;
+ while ((currentStatus == Starting) && (timeout > 0))
+ {
+ timeout = timeout - 100;
+ Thread.Sleep(100);
+ }
+
+ if (currentStatus != Running)
+ {
+ this.SetStatus(ErrorFailedToStart);
+ DispatchCommandResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, ErrorFailedToStart));
+ return;
+ }
+ }
+ catch (Exception)
+ {
+ this.SetStatus(ErrorFailedToStart);
+ DispatchCommandResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, ErrorFailedToStart));
+ return;
+ }
+ PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT);
+ result.KeepCallback = true;
+ DispatchCommandResult(result);
+ }
+
+ public void stop(string options)
+ {
+ if (currentStatus == Running)
+ {
+ lock (accelerometer)
+ {
+ accelerometer.CurrentValueChanged -= accelerometer_CurrentValueChanged;
+ accelerometer.Stop();
+ this.SetStatus(Stopped);
+ }
+ }
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+ }
+
+ /// <summary>
+ /// Formats current coordinates into JSON format
+ /// </summary>
+ /// <returns>Coordinates in JSON format</returns>
+ private string GetCurrentAccelerationFormatted()
+ {
+ // convert to unix timestamp
+ // long timestamp = ((accelerometer.CurrentValue.Timestamp.DateTime - StartOfEpoch).Ticks) / 10000;
+ // Note: Removed timestamp, to let the JS side create it using (new Date().getTime()) -jm
+ // this resolves an issue with inconsistencies between JS dates and Native DateTime
+ string resultCoordinates = String.Format("\"x\":{0},\"y\":{1},\"z\":{2}",
+ (accelerometer.CurrentValue.Acceleration.X * gConstant).ToString("0.00000", CultureInfo.InvariantCulture),
+ (accelerometer.CurrentValue.Acceleration.Y * gConstant).ToString("0.00000", CultureInfo.InvariantCulture),
+ (accelerometer.CurrentValue.Acceleration.Z * gConstant).ToString("0.00000", CultureInfo.InvariantCulture));
+ return "{" + resultCoordinates + "}";
+ }
+
+ /// <summary>
+ /// Sets current status
+ /// </summary>
+ /// <param name="status">current status</param>
+ private void SetStatus(int status)
+ {
+ currentStatus = status;
+ }
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/AudioFormatsHelper.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/AudioFormatsHelper.cs b/lib/cordova-wp7/templates/standalone/Plugins/AudioFormatsHelper.cs
new file mode 100644
index 0000000..dca7ee6
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/AudioFormatsHelper.cs
@@ -0,0 +1,89 @@
+/*
+ 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.IO;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ /// <summary>
+ /// Provides extra functionality to support different audio formats.
+ /// </summary>
+ public static class AudioFormatsHelper
+ {
+ #region Wav
+ /// <summary>
+ /// Adds wav file format header to the stream
+ /// https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
+ /// </summary>
+ /// <param name="stream">The stream</param>
+ /// <param name="sampleRate">Sample Rate</param>
+ public static void InitializeWavStream(this Stream stream, int sampleRate)
+ {
+ #region args checking
+
+ if (stream == null)
+ {
+ throw new ArgumentNullException("stream can't be null or empty");
+ }
+
+ #endregion
+
+ int numBits = 16;
+ int numBytes = numBits / 8;
+
+ stream.Write(System.Text.Encoding.UTF8.GetBytes("RIFF"), 0, 4);
+ stream.Write(BitConverter.GetBytes(0), 0, 4);
+ stream.Write(System.Text.Encoding.UTF8.GetBytes("WAVE"), 0, 4);
+ stream.Write(System.Text.Encoding.UTF8.GetBytes("fmt "), 0, 4);
+ stream.Write(BitConverter.GetBytes(16), 0, 4);
+ stream.Write(BitConverter.GetBytes((short)1), 0, 2);
+ stream.Write(BitConverter.GetBytes((short)1), 0, 2);
+ stream.Write(BitConverter.GetBytes(sampleRate), 0, 4);
+ stream.Write(BitConverter.GetBytes(sampleRate * numBytes), 0, 4);
+ stream.Write(BitConverter.GetBytes((short)(numBytes)), 0, 2);
+ stream.Write(BitConverter.GetBytes((short)(numBits)), 0, 2);
+ stream.Write(System.Text.Encoding.UTF8.GetBytes("data"), 0, 4);
+ stream.Write(BitConverter.GetBytes(0), 0, 4);
+ }
+
+ /// <summary>
+ /// Updates wav file format header
+ /// https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
+ /// </summary>
+ /// <param name="stream">Wav stream</param>
+ public static void UpdateWavStream(this Stream stream)
+ {
+ #region args checking
+
+ if (stream == null)
+ {
+ throw new ArgumentNullException("stream can't be null or empty");
+ }
+
+ #endregion
+
+ var position = stream.Position;
+
+ stream.Seek(4, SeekOrigin.Begin);
+ stream.Write(BitConverter.GetBytes((int)stream.Length - 8), 0, 4);
+ stream.Seek(40, SeekOrigin.Begin);
+ stream.Write(BitConverter.GetBytes((int)stream.Length - 44), 0, 4);
+ stream.Seek(position, SeekOrigin.Begin);
+ }
+
+ #endregion
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/AudioPlayer.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/AudioPlayer.cs b/lib/cordova-wp7/templates/standalone/Plugins/AudioPlayer.cs
new file mode 100644
index 0000000..a83be5b
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/AudioPlayer.cs
@@ -0,0 +1,620 @@
+/*
+ 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.IO;
+using System.IO.IsolatedStorage;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Threading;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Audio;
+using Microsoft.Xna.Framework.Media;
+using Microsoft.Phone.Controls;
+using System.Diagnostics;
+using System.Windows.Resources;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ /// <summary>
+ /// Implements audio record and play back functionality.
+ /// </summary>
+ internal class AudioPlayer : IDisposable
+ {
+ #region Constants
+
+ // AudioPlayer states
+ private const int PlayerState_None = 0;
+ private const int PlayerState_Starting = 1;
+ private const int PlayerState_Running = 2;
+ private const int PlayerState_Paused = 3;
+ private const int PlayerState_Stopped = 4;
+
+ // AudioPlayer messages
+ private const int MediaState = 1;
+ private const int MediaDuration = 2;
+ private const int MediaPosition = 3;
+ private const int MediaError = 9;
+
+ // AudioPlayer errors
+ private const int MediaErrorPlayModeSet = 1;
+ private const int MediaErrorAlreadyRecording = 2;
+ private const int MediaErrorStartingRecording = 3;
+ private const int MediaErrorRecordModeSet = 4;
+ private const int MediaErrorStartingPlayback = 5;
+ private const int MediaErrorResumeState = 6;
+ private const int MediaErrorPauseState = 7;
+ private const int MediaErrorStopState = 8;
+
+ //TODO: get rid of this callback, it should be universal
+ //private const string CallbackFunction = "CordovaMediaonStatus";
+
+ #endregion
+
+ /// <summary>
+ /// The AudioHandler object
+ /// </summary>
+ private Media handler;
+
+ /// <summary>
+ /// Temporary buffer to store audio chunk
+ /// </summary>
+ private byte[] buffer;
+
+ /// <summary>
+ /// Xna game loop dispatcher
+ /// </summary>
+ DispatcherTimer dtXna;
+
+ /// <summary>
+ /// Output buffer
+ /// </summary>
+ private MemoryStream memoryStream;
+
+ /// <summary>
+ /// The id of this player (used to identify Media object in JavaScript)
+ /// </summary>
+ private String id;
+
+ /// <summary>
+ /// State of recording or playback
+ /// </summary>
+ private int state = PlayerState_None;
+
+ /// <summary>
+ /// File name to play or record to
+ /// </summary>
+ private String audioFile = null;
+
+ /// <summary>
+ /// Duration of audio
+ /// </summary>
+ private double duration = -1;
+
+ /// <summary>
+ /// Audio player object
+ /// </summary>
+ private MediaElement player = null;
+
+ /// <summary>
+ /// Audio source
+ /// </summary>
+ private Microphone recorder;
+
+ /// <summary>
+ /// Internal flag specified that we should only open audio w/o playing it
+ /// </summary>
+ private bool prepareOnly = false;
+
+ /// <summary>
+ /// Creates AudioPlayer instance
+ /// </summary>
+ /// <param name="handler">Media object</param>
+ /// <param name="id">player id</param>
+ public AudioPlayer(Media handler, String id)
+ {
+ this.handler = handler;
+ this.id = id;
+ }
+
+ /// <summary>
+ /// Destroys player and stop audio playing or recording
+ /// </summary>
+ public void Dispose()
+ {
+ if (this.player != null)
+ {
+ this.stopPlaying();
+ this.player = null;
+ }
+ if (this.recorder != null)
+ {
+ this.stopRecording();
+ this.recorder = null;
+ }
+
+ this.FinalizeXnaGameLoop();
+ }
+
+ private void InvokeCallback(int message, string value, bool removeHandler)
+ {
+ string args = string.Format("('{0}',{1},{2});", this.id, message, value);
+ string callback = @"(function(id,msg,value){
+ try {
+ if (msg == Media.MEDIA_ERROR) {
+ value = {'code':value};
+ }
+ Media.onStatus(id,msg,value);
+ }
+ catch(e) {
+ console.log('Error calling Media.onStatus :: ' + e);
+ }
+ })" + args;
+ this.handler.InvokeCustomScript(new ScriptCallback("eval", new string[] { callback }), false);
+ }
+
+ private void InvokeCallback(int message, int value, bool removeHandler)
+ {
+ InvokeCallback(message, value.ToString(), removeHandler);
+ }
+
+ private void InvokeCallback(int message, double value, bool removeHandler)
+ {
+ InvokeCallback(message, value.ToString(), removeHandler);
+ }
+
+ /// <summary>
+ /// Starts recording, data is stored in memory
+ /// </summary>
+ /// <param name="filePath"></param>
+ public void startRecording(string filePath)
+ {
+ if (this.player != null)
+ {
+ InvokeCallback(MediaError, MediaErrorPlayModeSet, false);
+ }
+ else if (this.recorder == null)
+ {
+ try
+ {
+ this.audioFile = filePath;
+ this.InitializeXnaGameLoop();
+ this.recorder = Microphone.Default;
+ this.recorder.BufferDuration = TimeSpan.FromMilliseconds(500);
+ this.buffer = new byte[recorder.GetSampleSizeInBytes(this.recorder.BufferDuration)];
+ this.recorder.BufferReady += new EventHandler<EventArgs>(recorderBufferReady);
+ this.memoryStream = new MemoryStream();
+ this.memoryStream.InitializeWavStream(this.recorder.SampleRate);
+ this.recorder.Start();
+ FrameworkDispatcher.Update();
+ this.SetState(PlayerState_Running);
+ }
+ catch (Exception)
+ {
+ InvokeCallback(MediaError, MediaErrorStartingRecording, false);
+ //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaError, MediaErrorStartingRecording),false);
+ }
+ }
+ else
+ {
+ InvokeCallback(MediaError, MediaErrorAlreadyRecording, false);
+ //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaError, MediaErrorAlreadyRecording),false);
+ }
+ }
+
+ /// <summary>
+ /// Stops recording
+ /// </summary>
+ public void stopRecording()
+ {
+ if (this.recorder != null)
+ {
+ if (this.state == PlayerState_Running)
+ {
+ try
+ {
+ this.recorder.Stop();
+ this.recorder.BufferReady -= recorderBufferReady;
+ this.recorder = null;
+ SaveAudioClipToLocalStorage();
+ this.FinalizeXnaGameLoop();
+ this.SetState(PlayerState_Stopped);
+ }
+ catch (Exception)
+ {
+ //TODO
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Starts or resume playing audio file
+ /// </summary>
+ /// <param name="filePath">The name of the audio file</param>
+ /// <summary>
+ /// Starts or resume playing audio file
+ /// </summary>
+ /// <param name="filePath">The name of the audio file</param>
+ public void startPlaying(string filePath)
+ {
+ if (this.recorder != null)
+ {
+ InvokeCallback(MediaError, MediaErrorRecordModeSet, false);
+ //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaError, MediaErrorRecordModeSet),false);
+ return;
+ }
+
+
+ if (this.player == null || this.player.Source.AbsolutePath.LastIndexOf(filePath) < 0)
+ {
+ try
+ {
+ // this.player is a MediaElement, it must be added to the visual tree in order to play
+ PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
+ if (frame != null)
+ {
+ PhoneApplicationPage page = frame.Content as PhoneApplicationPage;
+ if (page != null)
+ {
+ Grid grid = page.FindName("LayoutRoot") as Grid;
+ if (grid != null)
+ {
+
+ this.player = grid.FindName("playerMediaElement") as MediaElement;
+ if (this.player == null) // still null ?
+ {
+ this.player = new MediaElement();
+ this.player.Name = "playerMediaElement";
+ grid.Children.Add(this.player);
+ this.player.Visibility = Visibility.Visible;
+ }
+ if (this.player.CurrentState == System.Windows.Media.MediaElementState.Playing)
+ {
+ this.player.Stop(); // stop it!
+ }
+
+ this.player.Source = null; // Garbage collect it.
+ this.player.MediaOpened += MediaOpened;
+ this.player.MediaEnded += MediaEnded;
+ this.player.MediaFailed += MediaFailed;
+ }
+ }
+ }
+
+ this.audioFile = filePath;
+
+ Uri uri = new Uri(filePath, UriKind.RelativeOrAbsolute);
+ if (uri.IsAbsoluteUri)
+ {
+ this.player.Source = uri;
+ }
+ else
+ {
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ if (!isoFile.FileExists(filePath))
+ {
+ // try to unpack it from the dll into isolated storage
+ StreamResourceInfo fileResourceStreamInfo = Application.GetResourceStream(new Uri(filePath, UriKind.Relative));
+ if (fileResourceStreamInfo != null)
+ {
+ using (BinaryReader br = new BinaryReader(fileResourceStreamInfo.Stream))
+ {
+ byte[] data = br.ReadBytes((int)fileResourceStreamInfo.Stream.Length);
+
+ string[] dirParts = filePath.Split('/');
+ string dirName = "";
+ for (int n = 0; n < dirParts.Length - 1; n++)
+ {
+ dirName += dirParts[n] + "/";
+ }
+ if (!isoFile.DirectoryExists(dirName))
+ {
+ isoFile.CreateDirectory(dirName);
+ }
+
+ using (IsolatedStorageFileStream outFile = isoFile.OpenFile(filePath, FileMode.Create))
+ {
+ using (BinaryWriter writer = new BinaryWriter(outFile))
+ {
+ writer.Write(data);
+ }
+ }
+ }
+ }
+ }
+ if (isoFile.FileExists(filePath))
+ {
+ using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(filePath, FileMode.Open, isoFile))
+ {
+ this.player.SetSource(stream);
+ }
+ }
+ else
+ {
+ InvokeCallback(MediaError, MediaErrorPlayModeSet, false);
+ //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaError, 1), false);
+ return;
+ }
+ }
+ }
+ this.SetState(PlayerState_Starting);
+ }
+ catch (Exception e)
+ {
+ Debug.WriteLine("Error in AudioPlayer::startPlaying : " + e.Message);
+ InvokeCallback(MediaError, MediaErrorStartingPlayback, false);
+ //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaError, MediaErrorStartingPlayback),false);
+ }
+ }
+ else
+ {
+ if (this.state != PlayerState_Running)
+ {
+ this.player.Play();
+ this.SetState(PlayerState_Running);
+ }
+ else
+ {
+ InvokeCallback(MediaError, MediaErrorResumeState, false);
+ //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaError, MediaErrorResumeState),false);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Callback to be invoked when the media source is ready for playback
+ /// </summary>
+ private void MediaOpened(object sender, RoutedEventArgs arg)
+ {
+ if (this.player != null)
+ {
+ this.duration = this.player.NaturalDuration.TimeSpan.TotalSeconds;
+ InvokeCallback(MediaDuration, this.duration, false);
+ //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaDuration, this.duration),false);
+ if (!this.prepareOnly)
+ {
+ this.player.Play();
+ this.SetState(PlayerState_Running);
+ }
+ this.prepareOnly = false;
+ }
+ else
+ {
+ // TODO: occasionally MediaOpened is signalled, but player is null
+ }
+ }
+
+ /// <summary>
+ /// Callback to be invoked when playback of a media source has completed
+ /// </summary>
+ private void MediaEnded(object sender, RoutedEventArgs arg)
+ {
+ this.SetState(PlayerState_Stopped);
+ }
+
+ /// <summary>
+ /// Callback to be invoked when playback of a media source has failed
+ /// </summary>
+ private void MediaFailed(object sender, RoutedEventArgs arg)
+ {
+ player.Stop();
+ InvokeCallback(MediaError, MediaErrorStartingPlayback, false);
+ //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaError.ToString(), "Media failed"),false);
+ }
+
+ /// <summary>
+ /// Seek or jump to a new time in the track
+ /// </summary>
+ /// <param name="milliseconds">The new track position</param>
+ public void seekToPlaying(int milliseconds)
+ {
+ if (this.player != null)
+ {
+ TimeSpan tsPos = new TimeSpan(0, 0, 0, 0, milliseconds);
+ this.player.Position = tsPos;
+ InvokeCallback(MediaPosition, milliseconds / 1000.0f, false);
+ //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaPosition, milliseconds / 1000.0f),false);
+ }
+ }
+
+ /// <summary>
+ /// Set the volume of the player
+ /// </summary>
+ /// <param name="vol">volume 0.0-1.0, default value is 0.5</param>
+ public void setVolume(double vol)
+ {
+ if (this.player != null)
+ {
+ this.player.Volume = vol;
+ }
+ }
+
+ /// <summary>
+ /// Pauses playing
+ /// </summary>
+ public void pausePlaying()
+ {
+ if (this.state == PlayerState_Running)
+ {
+ this.player.Pause();
+ this.SetState(PlayerState_Paused);
+ }
+ else
+ {
+ InvokeCallback(MediaError, MediaErrorPauseState, false);
+ //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaError, MediaErrorPauseState),false);
+ }
+ }
+
+
+ /// <summary>
+ /// Stops playing the audio file
+ /// </summary>
+ public void stopPlaying()
+ {
+ if ((this.state == PlayerState_Running) || (this.state == PlayerState_Paused))
+ {
+ this.player.Stop();
+
+ this.player.Position = new TimeSpan(0L);
+ this.SetState(PlayerState_Stopped);
+ }
+ //else // Why is it an error to call stop on a stopped media?
+ //{
+ // this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaError, MediaErrorStopState), false);
+ //}
+ }
+
+ /// <summary>
+ /// Gets current position of playback
+ /// </summary>
+ /// <returns>current position</returns>
+ public double getCurrentPosition()
+ {
+ if ((this.state == PlayerState_Running) || (this.state == PlayerState_Paused))
+ {
+ double currentPosition = this.player.Position.TotalSeconds;
+ //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaPosition, currentPosition),false);
+ return currentPosition;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ /// <summary>
+ /// Gets the duration of the audio file
+ /// </summary>
+ /// <param name="filePath">The name of the audio file</param>
+ /// <returns>track duration</returns>
+ public double getDuration(string filePath)
+ {
+ if (this.recorder != null)
+ {
+ return (-2);
+ }
+
+ if (this.player != null)
+ {
+ return this.duration;
+
+ }
+ else
+ {
+ this.prepareOnly = true;
+ this.startPlaying(filePath);
+ return this.duration;
+ }
+ }
+
+ /// <summary>
+ /// Sets the state and send it to JavaScript
+ /// </summary>
+ /// <param name="state">state</param>
+ private void SetState(int state)
+ {
+ if (this.state != state)
+ {
+ InvokeCallback(MediaState, state, false);
+ //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaState, state),false);
+ }
+
+ this.state = state;
+ }
+
+ #region record methods
+
+ /// <summary>
+ /// Copies data from recorder to memory storages and updates recording state
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="e"></param>
+ private void recorderBufferReady(object sender, EventArgs e)
+ {
+ this.recorder.GetData(this.buffer);
+ this.memoryStream.Write(this.buffer, 0, this.buffer.Length);
+ }
+
+ /// <summary>
+ /// Writes audio data from memory to isolated storage
+ /// </summary>
+ /// <returns></returns>
+ private void SaveAudioClipToLocalStorage()
+ {
+ if (this.memoryStream == null || this.memoryStream.Length <= 0)
+ {
+ return;
+ }
+
+ this.memoryStream.UpdateWavStream();
+
+ try
+ {
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ string directory = Path.GetDirectoryName(audioFile);
+
+ if (!isoFile.DirectoryExists(directory))
+ {
+ isoFile.CreateDirectory(directory);
+ }
+
+ this.memoryStream.Seek(0, SeekOrigin.Begin);
+
+ using (IsolatedStorageFileStream fileStream = isoFile.CreateFile(audioFile))
+ {
+ this.memoryStream.CopyTo(fileStream);
+ }
+ }
+ }
+ catch (Exception)
+ {
+ //TODO: log or do something else
+ throw;
+ }
+ }
+
+ #region Xna loop
+ /// <summary>
+ /// Special initialization required for the microphone: XNA game loop
+ /// </summary>
+ private void InitializeXnaGameLoop()
+ {
+ // Timer to simulate the XNA game loop (Microphone is from XNA)
+ this.dtXna = new DispatcherTimer();
+ this.dtXna.Interval = TimeSpan.FromMilliseconds(33);
+ this.dtXna.Tick += delegate { try { FrameworkDispatcher.Update(); } catch { } };
+ this.dtXna.Start();
+ }
+ /// <summary>
+ /// Finalizes XNA game loop for microphone
+ /// </summary>
+ private void FinalizeXnaGameLoop()
+ {
+ // Timer to simulate the XNA game loop (Microphone is from XNA)
+ if (this.dtXna != null)
+ {
+ this.dtXna.Stop();
+ this.dtXna = null;
+ }
+ }
+
+ #endregion
+
+ #endregion
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/Battery.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/Battery.cs b/lib/cordova-wp7/templates/standalone/Plugins/Battery.cs
new file mode 100644
index 0000000..962959e
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/Battery.cs
@@ -0,0 +1,79 @@
+/*
+ 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.Info;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ /// <summary>
+ /// Listens for changes to the state of the battery on the device.
+ /// Currently only the "isPlugged" parameter available via native APIs.
+ /// </summary>
+ public class Battery : BaseCommand
+ {
+ private bool isPlugged = false;
+ private EventHandler powerChanged;
+
+ public Battery()
+ {
+ powerChanged = new EventHandler(DeviceStatus_PowerSourceChanged);
+ isPlugged = DeviceStatus.PowerSource.ToString().CompareTo("External") == 0;
+ }
+
+ public void start(string options)
+ {
+ // Register power changed event handler
+ DeviceStatus.PowerSourceChanged += powerChanged;
+
+ PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT);
+ result.KeepCallback = true;
+ DispatchCommandResult(result);
+ }
+ public void stop(string options)
+ {
+ // Unregister power changed event handler
+ DeviceStatus.PowerSourceChanged -= powerChanged;
+ }
+
+ private void DeviceStatus_PowerSourceChanged(object sender, EventArgs e)
+ {
+ isPlugged = DeviceStatus.PowerSource.ToString().CompareTo("External") == 0;
+ PluginResult result = new PluginResult(PluginResult.Status.OK, GetCurrentBatteryStateFormatted());
+ result.KeepCallback = true;
+ DispatchCommandResult(result);
+ }
+
+ private string GetCurrentBatteryStateFormatted()
+ {
+ string batteryState = String.Format("\"level\":{0},\"isPlugged\":{1}",
+ "null",
+ isPlugged ? "true" : "false"
+ );
+ batteryState = "{" + batteryState + "}";
+ return batteryState;
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/Camera.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/Camera.cs b/lib/cordova-wp7/templates/standalone/Plugins/Camera.cs
new file mode 100644
index 0000000..5ff8045
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/Camera.cs
@@ -0,0 +1,490 @@
+/*
+ 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.Collections.Generic;
+using Microsoft.Phone.Tasks;
+using System.Runtime.Serialization;
+using System.IO;
+using System.IO.IsolatedStorage;
+using System.Windows.Media.Imaging;
+using Microsoft.Phone;
+using Microsoft.Xna.Framework.Media;
+using System.Diagnostics;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ public class Camera : BaseCommand
+ {
+
+ /// <summary>
+ /// Return base64 encoded string
+ /// </summary>
+ private const int DATA_URL = 0;
+
+ /// <summary>
+ /// Return file uri
+ /// </summary>
+ private const int FILE_URI = 1;
+
+ /// <summary>
+ /// Choose image from picture library
+ /// </summary>
+ private const int PHOTOLIBRARY = 0;
+
+ /// <summary>
+ /// Take picture from camera
+ /// </summary>
+
+ private const int CAMERA = 1;
+
+ /// <summary>
+ /// Choose image from picture library
+ /// </summary>
+ private const int SAVEDPHOTOALBUM = 2;
+
+ /// <summary>
+ /// Take a picture of type JPEG
+ /// </summary>
+ private const int JPEG = 0;
+
+ /// <summary>
+ /// Take a picture of type PNG
+ /// </summary>
+ private const int PNG = 1;
+
+ /// <summary>
+ /// Folder to store captured images
+ /// </summary>
+ private const string isoFolder = "CapturedImagesCache";
+
+ /// <summary>
+ /// Represents captureImage action options.
+ /// </summary>
+ [DataContract]
+ public class CameraOptions
+ {
+ /// <summary>
+ /// Source to getPicture from.
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "sourceType")]
+ public int PictureSourceType { get; set; }
+
+ /// <summary>
+ /// Format of image that returned from getPicture.
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "destinationType")]
+ public int DestinationType { get; set; }
+
+ /// <summary>
+ /// Quality of saved image
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "quality")]
+ public int Quality { get; set; }
+
+ /// <summary>
+ /// Controls whether or not the image is also added to the device photo album.
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "saveToPhotoAlbum")]
+ public bool SaveToPhotoAlbum { get; set; }
+
+ /// <summary>
+ /// Ignored
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "correctOrientation")]
+ public bool CorrectOrientation { get; set; }
+
+
+
+ /// <summary>
+ /// Ignored
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "allowEdit")]
+ public bool AllowEdit { get; set; }
+
+ /// <summary>
+ /// Height in pixels to scale image
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "encodingType")]
+ public int EncodingType { get; set; }
+
+ /// <summary>
+ /// Height in pixels to scale image
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "mediaType")]
+ public int MediaType { get; set; }
+
+
+ /// <summary>
+ /// Height in pixels to scale image
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "targetHeight")]
+ public int TargetHeight { get; set; }
+
+
+ /// <summary>
+ /// Width in pixels to scale image
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "targetWidth")]
+ public int TargetWidth { get; set; }
+
+ /// <summary>
+ /// Creates options object with default parameters
+ /// </summary>
+ public CameraOptions()
+ {
+ this.SetDefaultValues(new StreamingContext());
+ }
+
+ /// <summary>
+ /// Initializes default values for class fields.
+ /// Implemented in separate method because default constructor is not invoked during deserialization.
+ /// </summary>
+ /// <param name="context"></param>
+ [OnDeserializing()]
+ public void SetDefaultValues(StreamingContext context)
+ {
+ PictureSourceType = CAMERA;
+ DestinationType = FILE_URI;
+ Quality = 80;
+ TargetHeight = -1;
+ TargetWidth = -1;
+ SaveToPhotoAlbum = false;
+ CorrectOrientation = true;
+ AllowEdit = false;
+ MediaType = -1;
+ EncodingType = -1;
+ }
+ }
+
+ /// <summary>
+ /// Used to open photo library
+ /// </summary>
+ PhotoChooserTask photoChooserTask;
+
+ /// <summary>
+ /// Used to open camera application
+ /// </summary>
+ CameraCaptureTask cameraTask;
+
+ /// <summary>
+ /// Camera options
+ /// </summary>
+ CameraOptions cameraOptions;
+
+ public void takePicture(string options)
+ {
+ try
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+ // ["quality", "destinationType", "sourceType", "targetWidth", "targetHeight", "encodingType",
+ // "mediaType", "allowEdit", "correctOrientation", "saveToPhotoAlbum" ]
+ this.cameraOptions = new CameraOptions();
+ this.cameraOptions.Quality = int.Parse(args[0]);
+ this.cameraOptions.DestinationType = int.Parse(args[1]);
+ this.cameraOptions.PictureSourceType = int.Parse(args[2]);
+ this.cameraOptions.TargetWidth = int.Parse(args[3]);
+ this.cameraOptions.TargetHeight = int.Parse(args[4]);
+ this.cameraOptions.EncodingType = int.Parse(args[5]);
+ this.cameraOptions.MediaType = int.Parse(args[6]);
+ this.cameraOptions.AllowEdit = bool.Parse(args[7]);
+ this.cameraOptions.CorrectOrientation = bool.Parse(args[8]);
+ this.cameraOptions.SaveToPhotoAlbum = bool.Parse(args[9]);
+
+ //this.cameraOptions = String.IsNullOrEmpty(options) ?
+ // new CameraOptions() : JSON.JsonHelper.Deserialize<CameraOptions>(options);
+ }
+ catch (Exception ex)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, ex.Message));
+ return;
+ }
+
+ //TODO Check if all the options are acceptable
+
+
+ if (cameraOptions.PictureSourceType == CAMERA)
+ {
+ cameraTask = new CameraCaptureTask();
+ cameraTask.Completed += onCameraTaskCompleted;
+ cameraTask.Show();
+ }
+ else
+ {
+ if ((cameraOptions.PictureSourceType == PHOTOLIBRARY) || (cameraOptions.PictureSourceType == SAVEDPHOTOALBUM))
+ {
+ photoChooserTask = new PhotoChooserTask();
+ photoChooserTask.Completed += onPickerTaskCompleted;
+ photoChooserTask.Show();
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.NO_RESULT));
+ }
+ }
+
+ }
+
+ public void onCameraTaskCompleted(object sender, PhotoResult e)
+ {
+ if (e.Error != null)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR));
+ return;
+ }
+
+ switch (e.TaskResult)
+ {
+ case TaskResult.OK:
+ try
+ {
+ string imagePathOrContent = string.Empty;
+
+ if (cameraOptions.DestinationType == FILE_URI)
+ {
+ // Save image in media library
+ if (cameraOptions.SaveToPhotoAlbum)
+ {
+ MediaLibrary library = new MediaLibrary();
+ Picture pict = library.SavePicture(e.OriginalFileName, e.ChosenPhoto); // to save to photo-roll ...
+ }
+
+ int orient = ImageExifHelper.getImageOrientationFromStream(e.ChosenPhoto);
+ int newAngle = 0;
+ switch (orient)
+ {
+ case ImageExifOrientation.LandscapeLeft:
+ newAngle = 90;
+ break;
+ case ImageExifOrientation.PortraitUpsideDown:
+ newAngle = 180;
+ break;
+ case ImageExifOrientation.LandscapeRight:
+ newAngle = 270;
+ break;
+ case ImageExifOrientation.Portrait:
+ default: break; // 0 default already set
+ }
+
+ Stream rotImageStream = ImageExifHelper.RotateStream(e.ChosenPhoto, newAngle);
+
+ // we should return stream position back after saving stream to media library
+ rotImageStream.Seek(0, SeekOrigin.Begin);
+
+ WriteableBitmap image = PictureDecoder.DecodeJpeg(rotImageStream);
+
+ imagePathOrContent = this.SaveImageToLocalStorage(image, Path.GetFileName(e.OriginalFileName));
+
+
+ }
+ else if (cameraOptions.DestinationType == DATA_URL)
+ {
+ imagePathOrContent = this.GetImageContent(e.ChosenPhoto);
+ }
+ else
+ {
+ // TODO: shouldn't this happen before we launch the camera-picker?
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Incorrect option: destinationType"));
+ return;
+ }
+
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, imagePathOrContent));
+
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Error retrieving image."));
+ }
+ break;
+
+ case TaskResult.Cancel:
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Selection cancelled."));
+ break;
+
+ default:
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Selection did not complete!"));
+ break;
+ }
+
+ }
+
+ public void onPickerTaskCompleted(object sender, PhotoResult e)
+ {
+ if (e.Error != null)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR));
+ return;
+ }
+
+ switch (e.TaskResult)
+ {
+ case TaskResult.OK:
+ try
+ {
+ string imagePathOrContent = string.Empty;
+
+ if (cameraOptions.DestinationType == FILE_URI)
+ {
+ WriteableBitmap image = PictureDecoder.DecodeJpeg(e.ChosenPhoto);
+ imagePathOrContent = this.SaveImageToLocalStorage(image, Path.GetFileName(e.OriginalFileName));
+ }
+ else if (cameraOptions.DestinationType == DATA_URL)
+ {
+ imagePathOrContent = this.GetImageContent(e.ChosenPhoto);
+
+ }
+ else
+ {
+ // TODO: shouldn't this happen before we launch the camera-picker?
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Incorrect option: destinationType"));
+ return;
+ }
+
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, imagePathOrContent));
+
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Error retrieving image."));
+ }
+ break;
+
+ case TaskResult.Cancel:
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Selection cancelled."));
+ break;
+
+ default:
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Selection did not complete!"));
+ break;
+ }
+ }
+
+ /// <summary>
+ /// Returns image content in a form of base64 string
+ /// </summary>
+ /// <param name="stream">Image stream</param>
+ /// <returns>Base64 representation of the image</returns>
+ private string GetImageContent(Stream stream)
+ {
+ int streamLength = (int)stream.Length;
+ byte[] fileData = new byte[streamLength + 1];
+ stream.Read(fileData, 0, streamLength);
+
+ //use photo's actual width & height if user doesn't provide width & height
+ if (cameraOptions.TargetWidth < 0 && cameraOptions.TargetHeight < 0)
+ {
+ stream.Close();
+ return Convert.ToBase64String(fileData);
+ }
+ else
+ {
+ // resize photo
+ byte[] resizedFile = ResizePhoto(stream, fileData);
+ stream.Close();
+ return Convert.ToBase64String(resizedFile);
+ }
+ }
+
+ /// <summary>
+ /// Resize image
+ /// </summary>
+ /// <param name="stream">Image stream</param>
+ /// <param name="fileData">File data</param>
+ /// <returns>resized image</returns>
+ private byte[] ResizePhoto(Stream stream, byte[] fileData)
+ {
+ int streamLength = (int)stream.Length;
+ int intResult = 0;
+
+ byte[] resizedFile;
+
+ stream.Read(fileData, 0, streamLength);
+
+ BitmapImage objBitmap = new BitmapImage();
+ MemoryStream objBitmapStream = new MemoryStream(fileData);
+ MemoryStream objBitmapStreamResized = new MemoryStream();
+ WriteableBitmap objWB;
+ objBitmap.SetSource(stream);
+ objWB = new WriteableBitmap(objBitmap);
+
+ // resize the photo with user defined TargetWidth & TargetHeight
+ Extensions.SaveJpeg(objWB, objBitmapStreamResized, cameraOptions.TargetWidth, cameraOptions.TargetHeight, 0, cameraOptions.Quality);
+
+ //Convert the resized stream to a byte array.
+ streamLength = (int)objBitmapStreamResized.Length;
+ resizedFile = new Byte[streamLength]; //-1
+ objBitmapStreamResized.Position = 0;
+ //for some reason we have to set Position to zero, but we don't have to earlier when we get the bytes from the chosen photo...
+ intResult = objBitmapStreamResized.Read(resizedFile, 0, streamLength);
+
+ return resizedFile;
+ }
+
+ /// <summary>
+ /// Saves captured image in isolated storage
+ /// </summary>
+ /// <param name="imageFileName">image file name</param>
+ /// <returns>Image path</returns>
+ private string SaveImageToLocalStorage(WriteableBitmap image, string imageFileName)
+ {
+
+ if (image == null)
+ {
+ throw new ArgumentNullException("imageBytes");
+ }
+ try
+ {
+
+
+ var isoFile = IsolatedStorageFile.GetUserStoreForApplication();
+
+ if (!isoFile.DirectoryExists(isoFolder))
+ {
+ isoFile.CreateDirectory(isoFolder);
+ }
+
+ string filePath = System.IO.Path.Combine("///" + isoFolder + "/", imageFileName);
+
+ using (var stream = isoFile.CreateFile(filePath))
+ {
+ // resize image if Height and Width defined via options
+ if (cameraOptions.TargetHeight > 0 && cameraOptions.TargetWidth > 0)
+ {
+ image.SaveJpeg(stream, cameraOptions.TargetWidth, cameraOptions.TargetHeight, 0, cameraOptions.Quality);
+ }
+ else
+ {
+ image.SaveJpeg(stream, image.PixelWidth, image.PixelHeight, 0, cameraOptions.Quality);
+ }
+ }
+
+ return new Uri(filePath, UriKind.Relative).ToString();
+ }
+ catch (Exception)
+ {
+ //TODO: log or do something else
+ throw;
+ }
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/Capture.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/Capture.cs b/lib/cordova-wp7/templates/standalone/Plugins/Capture.cs
new file mode 100644
index 0000000..5e14a16
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/Capture.cs
@@ -0,0 +1,736 @@
+/*
+ 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.IO;
+using System.IO.IsolatedStorage;
+using System.Runtime.Serialization;
+using System.Windows.Media.Imaging;
+using Microsoft.Phone;
+using Microsoft.Phone.Tasks;
+using Microsoft.Xna.Framework.Media;
+using WPCordovaClassLib.Cordova.UI;
+using AudioResult = WPCordovaClassLib.Cordova.UI.AudioCaptureTask.AudioResult;
+using VideoResult = WPCordovaClassLib.Cordova.UI.VideoCaptureTask.VideoResult;
+using System.Windows;
+using System.Diagnostics;
+using Microsoft.Phone.Controls;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ /// <summary>
+ /// Provides access to the audio, image, and video capture capabilities of the device
+ /// </summary>
+ public class Capture : BaseCommand
+ {
+ #region Internal classes (options and resultant objects)
+
+ /// <summary>
+ /// Represents captureImage action options.
+ /// </summary>
+ [DataContract]
+ public class CaptureImageOptions
+ {
+ /// <summary>
+ /// The maximum number of images the device user can capture in a single capture operation. The value must be greater than or equal to 1 (defaults to 1).
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "limit")]
+ public int Limit { get; set; }
+
+ public static CaptureImageOptions Default
+ {
+ get { return new CaptureImageOptions() { Limit = 1 }; }
+ }
+ }
+
+ /// <summary>
+ /// Represents captureAudio action options.
+ /// </summary>
+ [DataContract]
+ public class CaptureAudioOptions
+ {
+ /// <summary>
+ /// The maximum number of audio files the device user can capture in a single capture operation. The value must be greater than or equal to 1 (defaults to 1).
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "limit")]
+ public int Limit { get; set; }
+
+ public static CaptureAudioOptions Default
+ {
+ get { return new CaptureAudioOptions() { Limit = 1 }; }
+ }
+ }
+
+ /// <summary>
+ /// Represents captureVideo action options.
+ /// </summary>
+ [DataContract]
+ public class CaptureVideoOptions
+ {
+ /// <summary>
+ /// The maximum number of video files the device user can capture in a single capture operation. The value must be greater than or equal to 1 (defaults to 1).
+ /// </summary>
+ [DataMember(IsRequired = false, Name = "limit")]
+ public int Limit { get; set; }
+
+ public static CaptureVideoOptions Default
+ {
+ get { return new CaptureVideoOptions() { Limit = 1 }; }
+ }
+ }
+
+ /// <summary>
+ /// Represents getFormatData action options.
+ /// </summary>
+ [DataContract]
+ public class MediaFormatOptions
+ {
+ /// <summary>
+ /// File path
+ /// </summary>
+ [DataMember(IsRequired = true, Name = "fullPath")]
+ public string FullPath { get; set; }
+
+ /// <summary>
+ /// File mime type
+ /// </summary>
+ [DataMember(Name = "type")]
+ public string Type { get; set; }
+
+ }
+
+ /// <summary>
+ /// Stores image info
+ /// </summary>
+ [DataContract]
+ public class MediaFile
+ {
+
+ [DataMember(Name = "name")]
+ public string FileName { get; set; }
+
+ [DataMember(Name = "fullPath")]
+ public string FilePath { get; set; }
+
+ [DataMember(Name = "type")]
+ public string Type { get; set; }
+
+ [DataMember(Name = "lastModifiedDate")]
+ public string LastModifiedDate { get; set; }
+
+ [DataMember(Name = "size")]
+ public long Size { get; set; }
+
+ public MediaFile(string filePath, Picture image)
+ {
+ this.FilePath = filePath;
+ this.FileName = System.IO.Path.GetFileName(this.FilePath);
+ this.Type = MimeTypeMapper.GetMimeType(FileName);
+ this.Size = image.GetImage().Length;
+
+ using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ this.LastModifiedDate = storage.GetLastWriteTime(filePath).DateTime.ToString();
+ }
+
+ }
+
+ public MediaFile(string filePath, Stream stream)
+ {
+ this.FilePath = filePath;
+ this.FileName = System.IO.Path.GetFileName(this.FilePath);
+ this.Type = MimeTypeMapper.GetMimeType(FileName);
+ this.Size = stream.Length;
+
+ using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ this.LastModifiedDate = storage.GetLastWriteTime(filePath).DateTime.ToString();
+ }
+ }
+ }
+
+ /// <summary>
+ /// Stores additional media file data
+ /// </summary>
+ [DataContract]
+ public class MediaFileData
+ {
+ [DataMember(Name = "height")]
+ public int Height { get; set; }
+
+ [DataMember(Name = "width")]
+ public int Width { get; set; }
+
+ [DataMember(Name = "bitrate")]
+ public int Bitrate { get; set; }
+
+ [DataMember(Name = "duration")]
+ public int Duration { get; set; }
+
+ [DataMember(Name = "codecs")]
+ public string Codecs { get; set; }
+
+ public MediaFileData(WriteableBitmap image)
+ {
+ this.Height = image.PixelHeight;
+ this.Width = image.PixelWidth;
+ this.Bitrate = 0;
+ this.Duration = 0;
+ this.Codecs = "";
+ }
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Folder to store captured images
+ /// </summary>
+ private string isoFolder = "CapturedImagesCache";
+
+ /// <summary>
+ /// Capture Image options
+ /// </summary>
+ protected CaptureImageOptions captureImageOptions;
+
+ /// <summary>
+ /// Capture Audio options
+ /// </summary>
+ protected CaptureAudioOptions captureAudioOptions;
+
+ /// <summary>
+ /// Capture Video options
+ /// </summary>
+ protected CaptureVideoOptions captureVideoOptions;
+
+ /// <summary>
+ /// Used to open camera application
+ /// </summary>
+ private CameraCaptureTask cameraTask;
+
+ /// <summary>
+ /// Used for audio recording
+ /// </summary>
+ private AudioCaptureTask audioCaptureTask;
+
+ /// <summary>
+ /// Used for video recording
+ /// </summary>
+ private VideoCaptureTask videoCaptureTask;
+
+ /// <summary>
+ /// Stores information about captured files
+ /// </summary>
+ List<MediaFile> files = new List<MediaFile>();
+
+ /// <summary>
+ /// Launches default camera application to capture image
+ /// </summary>
+ /// <param name="options">may contains limit or mode parameters</param>
+ public void captureImage(string options)
+ {
+ try
+ {
+ try
+ {
+
+ string args = JSON.JsonHelper.Deserialize<string[]>(options)[0];
+ this.captureImageOptions = String.IsNullOrEmpty(args) ? CaptureImageOptions.Default : JSON.JsonHelper.Deserialize<CaptureImageOptions>(args);
+
+ }
+ catch (Exception ex)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, ex.Message));
+ return;
+ }
+
+
+ cameraTask = new CameraCaptureTask();
+ cameraTask.Completed += this.cameraTask_Completed;
+ cameraTask.Show();
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ }
+
+ /// <summary>
+ /// Launches our own audio recording control to capture audio
+ /// </summary>
+ /// <param name="options">may contains additional parameters</param>
+ public void captureAudio(string options)
+ {
+ try
+ {
+ try
+ {
+ string args = JSON.JsonHelper.Deserialize<string[]>(options)[0];
+ this.captureAudioOptions = String.IsNullOrEmpty(args) ? CaptureAudioOptions.Default : JSON.JsonHelper.Deserialize<CaptureAudioOptions>(args);
+
+ }
+ catch (Exception ex)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, ex.Message));
+ return;
+ }
+
+ audioCaptureTask = new AudioCaptureTask();
+ audioCaptureTask.Completed += audioRecordingTask_Completed;
+ audioCaptureTask.Show();
+
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ }
+
+ /// <summary>
+ /// Launches our own video recording control to capture video
+ /// </summary>
+ /// <param name="options">may contains additional parameters</param>
+ public void captureVideo(string options)
+ {
+ try
+ {
+ try
+ {
+ string args = JSON.JsonHelper.Deserialize<string[]>(options)[0];
+ this.captureVideoOptions = String.IsNullOrEmpty(args) ? CaptureVideoOptions.Default : JSON.JsonHelper.Deserialize<CaptureVideoOptions>(args);
+
+ }
+ catch (Exception ex)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, ex.Message));
+ return;
+ }
+
+ videoCaptureTask = new VideoCaptureTask();
+ videoCaptureTask.Completed += videoRecordingTask_Completed;
+ videoCaptureTask.Show();
+
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ }
+
+ /// <summary>
+ /// Retrieves the format information of the media file.
+ /// </summary>
+ /// <param name="options"></param>
+ public void getFormatData(string options)
+ {
+ try
+ {
+ MediaFormatOptions mediaFormatOptions;
+ try
+ {
+ mediaFormatOptions = new MediaFormatOptions();
+ string[] optionStrings = JSON.JsonHelper.Deserialize<string[]>(options);
+ mediaFormatOptions.FullPath = optionStrings[0];
+ mediaFormatOptions.Type = optionStrings[1];
+ }
+ catch (Exception ex)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, ex.Message));
+ return;
+ }
+
+ if (string.IsNullOrEmpty(mediaFormatOptions.FullPath))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ }
+
+ string mimeType = mediaFormatOptions.Type;
+
+ if (string.IsNullOrEmpty(mimeType))
+ {
+ mimeType = MimeTypeMapper.GetMimeType(mediaFormatOptions.FullPath);
+ }
+
+ if (mimeType.Equals("image/jpeg"))
+ {
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ WriteableBitmap image = ExtractImageFromLocalStorage(mediaFormatOptions.FullPath);
+
+ if (image == null)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "File not found"));
+ return;
+ }
+
+ MediaFileData mediaData = new MediaFileData(image);
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, mediaData));
+ });
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR));
+ }
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR));
+ }
+ }
+
+ /// <summary>
+ /// Opens specified file in media player
+ /// </summary>
+ /// <param name="options">MediaFile to play</param>
+ public void play(string options)
+ {
+ try
+ {
+ MediaFile file;
+
+ try
+ {
+ file = String.IsNullOrEmpty(options) ? null : JSON.JsonHelper.Deserialize<MediaFile[]>(options)[0];
+
+ }
+ catch (Exception ex)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, ex.Message));
+ return;
+ }
+
+ if (file == null || String.IsNullOrEmpty(file.FilePath))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "File path is missing"));
+ return;
+ }
+
+ // if url starts with '/' media player throws FileNotFound exception
+ Uri fileUri = new Uri(file.FilePath.TrimStart(new char[] { '/', '\\' }), UriKind.Relative);
+
+ MediaPlayerLauncher player = new MediaPlayerLauncher();
+ player.Media = fileUri;
+ player.Location = MediaLocationType.Data;
+ player.Show();
+
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+
+ }
+ catch (Exception e)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+ }
+ }
+
+
+ /// <summary>
+ /// Handles result of capture to save image information
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="e">stores information about current captured image</param>
+ private void cameraTask_Completed(object sender, PhotoResult e)
+ {
+
+ if (e.Error != null)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR));
+ return;
+ }
+
+ switch (e.TaskResult)
+ {
+ case TaskResult.OK:
+ try
+ {
+ string fileName = System.IO.Path.GetFileName(e.OriginalFileName);
+
+ // Save image in media library
+ MediaLibrary library = new MediaLibrary();
+ Picture image = library.SavePicture(fileName, e.ChosenPhoto);
+
+ int orient = ImageExifHelper.getImageOrientationFromStream(e.ChosenPhoto);
+ int newAngle = 0;
+ switch (orient)
+ {
+ case ImageExifOrientation.LandscapeLeft:
+ newAngle = 90;
+ break;
+ case ImageExifOrientation.PortraitUpsideDown:
+ newAngle = 180;
+ break;
+ case ImageExifOrientation.LandscapeRight:
+ newAngle = 270;
+ break;
+ case ImageExifOrientation.Portrait:
+ default: break; // 0 default already set
+ }
+
+ Stream rotImageStream = ImageExifHelper.RotateStream(e.ChosenPhoto, newAngle);
+
+ // Save image in isolated storage
+
+ // we should return stream position back after saving stream to media library
+ rotImageStream.Seek(0, SeekOrigin.Begin);
+
+ byte[] imageBytes = new byte[rotImageStream.Length];
+ rotImageStream.Read(imageBytes, 0, imageBytes.Length);
+ rotImageStream.Dispose();
+ string pathLocalStorage = this.SaveImageToLocalStorage(fileName, isoFolder, imageBytes);
+ imageBytes = null;
+ // Get image data
+ MediaFile data = new MediaFile(pathLocalStorage, image);
+
+ this.files.Add(data);
+
+ if (files.Count < this.captureImageOptions.Limit)
+ {
+ cameraTask.Show();
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, files));
+ files.Clear();
+ }
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Error capturing image."));
+ }
+ break;
+
+ case TaskResult.Cancel:
+ if (files.Count > 0)
+ {
+ // User canceled operation, but some images were made
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, files));
+ files.Clear();
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Canceled."));
+ }
+ break;
+
+ default:
+ if (files.Count > 0)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, files));
+ files.Clear();
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Did not complete!"));
+ }
+ break;
+ }
+ }
+
+ /// <summary>
+ /// Handles result of audio recording tasks
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="e">stores information about current captured audio</param>
+ private void audioRecordingTask_Completed(object sender, AudioResult e)
+ {
+
+ if (e.Error != null)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR));
+ return;
+ }
+
+ switch (e.TaskResult)
+ {
+ case TaskResult.OK:
+ try
+ {
+ // Get image data
+ MediaFile data = new MediaFile(e.AudioFileName, e.AudioFile);
+
+ this.files.Add(data);
+
+ if (files.Count < this.captureAudioOptions.Limit)
+ {
+ audioCaptureTask.Show();
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, files));
+ files.Clear();
+ }
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Error capturing audio."));
+ }
+ break;
+
+ case TaskResult.Cancel:
+ if (files.Count > 0)
+ {
+ // User canceled operation, but some audio clips were made
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, files));
+ files.Clear();
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Canceled."));
+ }
+ break;
+
+ default:
+ if (files.Count > 0)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, files));
+ files.Clear();
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Did not complete!"));
+ }
+ break;
+ }
+ }
+
+ /// <summary>
+ /// Handles result of video recording tasks
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="e">stores information about current captured video</param>
+ private void videoRecordingTask_Completed(object sender, VideoResult e)
+ {
+
+ if (e.Error != null)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR));
+ return;
+ }
+
+ switch (e.TaskResult)
+ {
+ case TaskResult.OK:
+ try
+ {
+ // Get image data
+ MediaFile data = new MediaFile(e.VideoFileName, e.VideoFile);
+
+ this.files.Add(data);
+
+ if (files.Count < this.captureVideoOptions.Limit)
+ {
+ videoCaptureTask.Show();
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, files));
+ files.Clear();
+ }
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Error capturing video."));
+ }
+ break;
+
+ case TaskResult.Cancel:
+ if (files.Count > 0)
+ {
+ // User canceled operation, but some video clips were made
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, files));
+ files.Clear();
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Canceled."));
+ }
+ break;
+
+ default:
+ if (files.Count > 0)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, files));
+ files.Clear();
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Did not complete!"));
+ }
+ break;
+ }
+ }
+
+ /// <summary>
+ /// Extract file from Isolated Storage as WriteableBitmap object
+ /// </summary>
+ /// <param name="filePath"></param>
+ /// <returns></returns>
+ private WriteableBitmap ExtractImageFromLocalStorage(string filePath)
+ {
+ try
+ {
+
+ var isoFile = IsolatedStorageFile.GetUserStoreForApplication();
+
+ using (var imageStream = isoFile.OpenFile(filePath, FileMode.Open, FileAccess.Read))
+ {
+ var imageSource = PictureDecoder.DecodeJpeg(imageStream);
+ return imageSource;
+ }
+ }
+ catch (Exception)
+ {
+ return null;
+ }
+ }
+
+
+ /// <summary>
+ /// Saves captured image in isolated storage
+ /// </summary>
+ /// <param name="imageFileName">image file name</param>
+ /// <param name="imageFolder">folder to store images</param>
+ /// <returns>Image path</returns>
+ private string SaveImageToLocalStorage(string imageFileName, string imageFolder, byte[] imageBytes)
+ {
+ if (imageBytes == null)
+ {
+ throw new ArgumentNullException("imageBytes");
+ }
+ try
+ {
+ var isoFile = IsolatedStorageFile.GetUserStoreForApplication();
+
+ if (!isoFile.DirectoryExists(imageFolder))
+ {
+ isoFile.CreateDirectory(imageFolder);
+ }
+ string filePath = System.IO.Path.Combine("/" + imageFolder + "/", imageFileName);
+
+ using (IsolatedStorageFileStream stream = isoFile.CreateFile(filePath))
+ {
+ stream.Write(imageBytes, 0, imageBytes.Length);
+ }
+
+ return filePath;
+ }
+ catch (Exception)
+ {
+ //TODO: log or do something else
+ throw;
+ }
+ }
+
+
+ }
+}
\ No newline at end of file
[12/37] Add WP7 and WP8 platform files.
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/www/css/index.css
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/www/css/index.css b/lib/cordova-wp8/templates/standalone/www/css/index.css
new file mode 100644
index 0000000..f1f9d76
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/www/css/index.css
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+* {
+ -webkit-touch-callout: none; /* prevent callout to copy image, etc when tap to hold */
+ -webkit-text-size-adjust: none; /* prevent webkit from resizing text to fit */
+ -webkit-tap-highlight-color: rgba(0,0,0,0); /* make transparent link selection, adjust last value opacity 0 to 1.0 */
+ -webkit-user-select: none; /* prevent copy paste, to allow, change 'none' to 'text' */
+}
+
+body {
+ background-color:#E4E4E4;
+ background-image:linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
+ background-image:-webkit-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
+ background-image:-ms-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
+ background-image:-webkit-gradient(
+ linear,
+ left top,
+ left bottom,
+ color-stop(0, #A7A7A7),
+ color-stop(0.51, #E4E4E4)
+ );
+ background-attachment:fixed;
+ font-family:'HelveticaNeue-Light', 'HelveticaNeue', Helvetica, Arial, sans-serif;
+ font-size:12px;
+ height:100%;
+ margin:0px;
+ padding:0px;
+ text-transform:uppercase;
+ width:100%;
+}
+
+/* Portrait layout (default) */
+.app {
+ background:url(../img/logo.png) no-repeat center top; /* 170px x 200px */
+ position:absolute; /* position in the center of the screen */
+ left:50%;
+ top:50%;
+ height:50px; /* text area height */
+ width:225px; /* text area width */
+ text-align:center;
+ padding:180px 0px 0px 0px; /* image height is 200px (bottom 20px are overlapped with text) */
+ margin:-115px 0px 0px -112px; /* offset vertical: half of image height and text area height */
+ /* offset horizontal: half of text area width */
+}
+
+/* Landscape layout (with min-width) */
+@media screen and (min-aspect-ratio: 1/1) and (min-width:400px) {
+ .app {
+ background-position:left center;
+ padding:75px 0px 75px 170px; /* padding-top + padding-bottom + text area = image height */
+ margin:-90px 0px 0px -198px; /* offset vertical: half of image height */
+ /* offset horizontal: half of image width and text area width */
+ }
+}
+
+h1 {
+ font-size:24px;
+ font-weight:normal;
+ margin:0px;
+ overflow:visible;
+ padding:0px;
+ text-align:center;
+}
+
+.event {
+ border-radius:4px;
+ -webkit-border-radius:4px;
+ color:#FFFFFF;
+ font-size:12px;
+ margin:0px 30px;
+ padding:2px 0px;
+}
+
+.event.listening {
+ background-color:#333333;
+ display:block;
+}
+
+.event.received {
+ background-color:#4B946A;
+ display:none;
+}
+
+@keyframes fade {
+ from { opacity: 1.0; }
+ 50% { opacity: 0.4; }
+ to { opacity: 1.0; }
+}
+
+@-webkit-keyframes fade {
+ from { opacity: 1.0; }
+ 50% { opacity: 0.4; }
+ to { opacity: 1.0; }
+}
+
+.blink {
+ animation:fade 3000ms infinite;
+ -webkit-animation:fade 3000ms infinite;
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/www/img/logo.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/www/img/logo.png b/lib/cordova-wp8/templates/standalone/www/img/logo.png
new file mode 100644
index 0000000..9519e7d
Binary files /dev/null and b/lib/cordova-wp8/templates/standalone/www/img/logo.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/www/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/www/index.html b/lib/cordova-wp8/templates/standalone/www/index.html
new file mode 100644
index 0000000..31f61f4
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/www/index.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<!--
+ 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.
+-->
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta name="format-detection" content="telephone=no" />
+ <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
+ <link rel="stylesheet" type="text/css" href="css/index.css" />
+ <title>Hello World</title>
+ </head>
+ <body>
+ <div class="app">
+ <h1>Apache Cordova</h1>
+ <div id="deviceready" class="blink">
+ <p class="event listening">Connecting to Device</p>
+ <p class="event received">Device is Ready</p>
+ </div>
+ </div>
+ <script type="text/javascript" src="cordova-2.7.0.js"></script>
+ <script type="text/javascript" src="js/index.js"></script>
+ <script type="text/javascript">
+ app.initialize();
+ </script>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/www/js/index.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/www/js/index.js b/lib/cordova-wp8/templates/standalone/www/js/index.js
new file mode 100644
index 0000000..3b75d3f
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/www/js/index.js
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+var app = {
+ // Application Constructor
+ initialize: function() {
+ this.bindEvents();
+ },
+ // Bind Event Listeners
+ //
+ // Bind any events that are required on startup. Common events are:
+ // `load`, `deviceready`, `offline`, and `online`.
+ bindEvents: function() {
+ document.addEventListener('deviceready', this.onDeviceReady, false);
+ },
+ // deviceready Event Handler
+ //
+ // The scope of `this` is the event. In order to call the `receivedEvent`
+ // function, we must explicity call `app.receivedEvent(...);`
+ onDeviceReady: function() {
+ app.receivedEvent('deviceready');
+ },
+ // Update DOM on a Received Event
+ receivedEvent: function(id) {
+ var parentElement = document.getElementById(id);
+ var listeningElement = parentElement.querySelector('.listening');
+ var receivedElement = parentElement.querySelector('.received');
+
+ listeningElement.setAttribute('style', 'display:none;');
+ receivedElement.setAttribute('style', 'display:block;');
+
+ console.log('Received Event: ' + id);
+ }
+};
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/vs/MyTemplateStandAlone.vstemplate
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/vs/MyTemplateStandAlone.vstemplate b/lib/cordova-wp8/templates/vs/MyTemplateStandAlone.vstemplate
new file mode 100644
index 0000000..d7e4a70
--- /dev/null
+++ b/lib/cordova-wp8/templates/vs/MyTemplateStandAlone.vstemplate
@@ -0,0 +1,113 @@
+<VSTemplate Version="3.0.0" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005" Type="Project">
+ <TemplateData>
+ <Name>CordovaWP8_2_7_0</Name>
+ <Description>Cordova 2.7.0 for Windows Phone 8 using the Cordova source code directly.</Description>
+ <ProjectType>CSharp</ProjectType>
+ <ProjectSubType>
+ </ProjectSubType>
+ <SortOrder>1000</SortOrder>
+ <CreateNewFolder>true</CreateNewFolder>
+ <DefaultName>CordovaWP8_2_7_0</DefaultName>
+ <ProvideDefaultName>true</ProvideDefaultName>
+ <LocationField>Enabled</LocationField>
+ <EnableLocationBrowseButton>true</EnableLocationBrowseButton>
+ <Icon>__TemplateIcon.png</Icon>
+ <PreviewImage>__PreviewImage.jpg</PreviewImage>
+ </TemplateData>
+ <TemplateContent>
+ <Project TargetFileName="CordovaAppProj.csproj" File="CordovaAppProj.csproj" ReplaceParameters="true">
+ <ProjectItem ReplaceParameters="true" TargetFileName="App.xaml">App.xaml</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="App.xaml.cs">App.xaml.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="false" TargetFileName="ApplicationIcon.png">ApplicationIcon.png</ProjectItem>
+ <ProjectItem ReplaceParameters="false" TargetFileName="Background.png">Background.png</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="config.xml">config.xml</ProjectItem>
+ <Folder Name="cordovalib" TargetFolderName="cordovalib">
+ <ProjectItem ReplaceParameters="true" TargetFileName="BrowserMouseHelper.cs">BrowserMouseHelper.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="CommandFactory.cs">CommandFactory.cs</ProjectItem>
+ <Folder Name="Commands" TargetFolderName="Commands">
+ <ProjectItem ReplaceParameters="true" TargetFileName="BaseCommand.cs">BaseCommand.cs</ProjectItem>
+ </Folder>
+ <ProjectItem ReplaceParameters="true" TargetFileName="ConfigHandler.cs">ConfigHandler.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="CordovaCommandCall.cs">CordovaCommandCall.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="CordovaView.xaml">CordovaView.xaml</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="CordovaView.xaml.cs">CordovaView.xaml.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="DOMStorageHelper.cs">DOMStorageHelper.cs</ProjectItem>
+ <Folder Name="JSON" TargetFolderName="JSON">
+ <ProjectItem ReplaceParameters="true" TargetFileName="JsonHelper.cs">JsonHelper.cs</ProjectItem>
+ </Folder>
+ <ProjectItem ReplaceParameters="true" TargetFileName="NativeExecution.cs">NativeExecution.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="OrientationHelper.cs">OrientationHelper.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="PluginResult.cs">PluginResult.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="ScriptCallback.cs">ScriptCallback.cs</ProjectItem>
+ </Folder>
+ <Folder Name="Images" TargetFolderName="Images">
+ <ProjectItem ReplaceParameters="false" TargetFileName="appbar.back.rest.png">appbar.back.rest.png</ProjectItem>
+ <ProjectItem ReplaceParameters="false" TargetFileName="appbar.close.rest.png">appbar.close.rest.png</ProjectItem>
+ <ProjectItem ReplaceParameters="false" TargetFileName="appbar.feature.video.rest.png">appbar.feature.video.rest.png</ProjectItem>
+ <ProjectItem ReplaceParameters="false" TargetFileName="appbar.next.rest.png">appbar.next.rest.png</ProjectItem>
+ <ProjectItem ReplaceParameters="false" TargetFileName="appbar.save.rest.png">appbar.save.rest.png</ProjectItem>
+ <ProjectItem ReplaceParameters="false" TargetFileName="appbar.stop.rest.png">appbar.stop.rest.png</ProjectItem>
+ </Folder>
+ <ProjectItem ReplaceParameters="true" TargetFileName="MainPage.xaml">MainPage.xaml</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="MainPage.xaml.cs">MainPage.xaml.cs</ProjectItem>
+ <Folder Name="Plugins" TargetFolderName="Plugins">
+ <ProjectItem ReplaceParameters="true" TargetFileName="Accelerometer.cs">Accelerometer.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="AudioFormatsHelper.cs">AudioFormatsHelper.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="AudioPlayer.cs">AudioPlayer.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="Battery.cs">Battery.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="Camera.cs">Camera.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="Capture.cs">Capture.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="Compass.cs">Compass.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="Contacts.cs">Contacts.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="DebugConsole.cs">DebugConsole.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="Device.cs">Device.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="File.cs">File.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="FileTransfer.cs">FileTransfer.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="GeoLocation.cs">GeoLocation.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="Globalization.cs">Globalization.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="ImageExifHelper.cs">ImageExifHelper.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="InAppBrowser.cs">InAppBrowser.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="Media.cs">Media.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="MimeTypeMapper.cs">MimeTypeMapper.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="NetworkStatus.cs">NetworkStatus.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="Notification.cs">Notification.cs</ProjectItem>
+ <Folder Name="UI" TargetFolderName="UI">
+ <ProjectItem ReplaceParameters="true" TargetFileName="AudioCaptureTask.cs">AudioCaptureTask.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="AudioRecorder.xaml">AudioRecorder.xaml</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="AudioRecorder.xaml.cs">AudioRecorder.xaml.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="ImageCapture.xaml">ImageCapture.xaml</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="ImageCapture.xaml.cs">ImageCapture.xaml.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="NotificationBox.xaml">NotificationBox.xaml</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="NotificationBox.xaml.cs">NotificationBox.xaml.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="VideoCaptureTask.cs">VideoCaptureTask.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="VideoRecorder.xaml">VideoRecorder.xaml</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="VideoRecorder.xaml.cs">VideoRecorder.xaml.cs</ProjectItem>
+ </Folder>
+ </Folder>
+ <Folder Name="Properties" TargetFolderName="Properties">
+ <ProjectItem ReplaceParameters="true" TargetFileName="AppManifest.xml">AppManifest.xml</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="AssemblyInfo.cs">AssemblyInfo.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="WMAppManifest.xml">WMAppManifest.xml</ProjectItem>
+ </Folder>
+ <Folder Name="resources" TargetFolderName="resources">
+ <ProjectItem ReplaceParameters="false" TargetFileName="notification-beep.wav">notification-beep.wav</ProjectItem>
+ </Folder>
+ <Folder Name="Service References" TargetFolderName="Service References" />
+ <ProjectItem ReplaceParameters="false" TargetFileName="SplashScreenImage.jpg">SplashScreenImage.jpg</ProjectItem>
+ <ProjectItem ReplaceParameters="false" TargetFileName="VERSION">VERSION</ProjectItem>
+ <Folder Name="www" TargetFolderName="www">
+ <ProjectItem ReplaceParameters="true" TargetFileName="cordova-2.7.0.js">cordova-2.7.0.js</ProjectItem>
+ <Folder Name="css" TargetFolderName="css">
+ <ProjectItem ReplaceParameters="true" TargetFileName="index.css">index.css</ProjectItem>
+ </Folder>
+ <Folder Name="img" TargetFolderName="img">
+ <ProjectItem ReplaceParameters="false" TargetFileName="logo.png">logo.png</ProjectItem>
+ </Folder>
+ <ProjectItem ReplaceParameters="true" TargetFileName="index.html">index.html</ProjectItem>
+ <Folder Name="js" TargetFolderName="js">
+ <ProjectItem ReplaceParameters="true" TargetFileName="index.js">index.js</ProjectItem>
+ </Folder>
+ </Folder>
+ </Project>
+ </TemplateContent>
+</VSTemplate>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/vs/description.txt
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/vs/description.txt b/lib/cordova-wp8/templates/vs/description.txt
new file mode 100644
index 0000000..b8c91ec
--- /dev/null
+++ b/lib/cordova-wp8/templates/vs/description.txt
@@ -0,0 +1,8 @@
+CordovaWP8_2_6_0_Full
+Apache Cordova 2.7.0 Windows Phone 8 App using a pre-built dll.
+
+CordovaWP8_2_6_0_StandAlone
+Apache Cordova 2.7.0 Windows Phone 8 App including all framework source code.
+
+
+
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/vs/pg_templateIcon.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/vs/pg_templateIcon.png b/lib/cordova-wp8/templates/vs/pg_templateIcon.png
new file mode 100644
index 0000000..75c17c7
Binary files /dev/null and b/lib/cordova-wp8/templates/vs/pg_templateIcon.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/vs/pg_templatePreview.jpg
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/vs/pg_templatePreview.jpg b/lib/cordova-wp8/templates/vs/pg_templatePreview.jpg
new file mode 100644
index 0000000..1d72941
Binary files /dev/null and b/lib/cordova-wp8/templates/vs/pg_templatePreview.jpg differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/App.xaml
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/App.xaml b/lib/cordova-wp8/tests/MobileSpecUnitTests/App.xaml
new file mode 100644
index 0000000..ac01322
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/App.xaml
@@ -0,0 +1,38 @@
+<!--
+ 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.
+-->
+<Application
+ x:Class="MobileSpecUnitTests.App"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
+ xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone">
+
+ <!--Application Resources-->
+ <Application.Resources>
+ <MediaElement x:Key="PhoneGapMediaPlayer" Visibility="Collapsed" />
+ </Application.Resources>
+
+ <Application.ApplicationLifetimeObjects>
+ <!--Required object that handles lifetime events for the application-->
+ <shell:PhoneApplicationService
+ Launching="Application_Launching" Closing="Application_Closing"
+ Activated="Application_Activated" Deactivated="Application_Deactivated"/>
+ </Application.ApplicationLifetimeObjects>
+
+</Application>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/App.xaml.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/App.xaml.cs b/lib/cordova-wp8/tests/MobileSpecUnitTests/App.xaml.cs
new file mode 100644
index 0000000..53d9a90
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/App.xaml.cs
@@ -0,0 +1,158 @@
+/*
+ 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.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.Navigation;
+using System.Windows.Shapes;
+using Microsoft.Phone.Controls;
+using Microsoft.Phone.Shell;
+
+namespace MobileSpecUnitTests
+{
+ public partial class App : Application
+ {
+ /// <summary>
+ /// Provides easy access to the root frame of the Phone Application.
+ /// </summary>
+ /// <returns>The root frame of the Phone Application.</returns>
+ public PhoneApplicationFrame RootFrame { get; private set; }
+
+ /// <summary>
+ /// Constructor for the Application object.
+ /// </summary>
+ public App()
+ {
+ // Global handler for uncaught exceptions.
+ UnhandledException += Application_UnhandledException;
+
+ // Show graphics profiling information while debugging.
+ if (System.Diagnostics.Debugger.IsAttached)
+ {
+ // Display the current frame rate counters.
+ Application.Current.Host.Settings.EnableFrameRateCounter = true;
+
+ // Show the areas of the app that are being redrawn in each frame.
+ //Application.Current.Host.Settings.EnableRedrawRegions = true;
+
+ // Enable non-production analysis visualization mode,
+ // which shows areas of a page that are being GPU accelerated with a colored overlay.
+ //Application.Current.Host.Settings.EnableCacheVisualization = true;
+ }
+
+ // Standard Silverlight initialization
+ InitializeComponent();
+
+ // Phone-specific initialization
+ InitializePhoneApplication();
+ }
+
+ // Code to execute when the application is launching (eg, from Start)
+ // This code will not execute when the application is reactivated
+ private void Application_Launching(object sender, LaunchingEventArgs e)
+ {
+ System.Diagnostics.Debug.WriteLine("Application_Launching");
+ }
+
+ // Code to execute when the application is activated (brought to foreground)
+ // This code will not execute when the application is first launched
+ private void Application_Activated(object sender, ActivatedEventArgs e)
+ {
+ System.Diagnostics.Debug.WriteLine("Application_Activated");
+ }
+
+ // Code to execute when the application is deactivated (sent to background)
+ // This code will not execute when the application is closing
+ private void Application_Deactivated(object sender, DeactivatedEventArgs e)
+ {
+ System.Diagnostics.Debug.WriteLine("Application_Deactivated");
+ }
+
+ // Code to execute when the application is closing (eg, user hit Back)
+ // This code will not execute when the application is deactivated
+ private void Application_Closing(object sender, ClosingEventArgs e)
+ {
+ System.Diagnostics.Debug.WriteLine("Application_Closing");
+ }
+
+ // Code to execute if a navigation fails
+ private void RootFrame_NavigationFailed(object sender, NavigationFailedEventArgs e)
+ {
+ if (System.Diagnostics.Debugger.IsAttached)
+ {
+ // A navigation has failed; break into the debugger
+ System.Diagnostics.Debugger.Break();
+ }
+ }
+
+ // Code to execute on Unhandled Exceptions
+ private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
+ {
+ if (System.Diagnostics.Debugger.IsAttached)
+ {
+ // An unhandled exception has occurred; break into the debugger
+ System.Diagnostics.Debugger.Break();
+ }
+ }
+
+ #region Phone application initialization
+
+ // Avoid double-initialization
+ private bool phoneApplicationInitialized = false;
+
+ // Do not add any additional code to this method
+ private void InitializePhoneApplication()
+ {
+ if (phoneApplicationInitialized)
+ return;
+
+ // Create the frame but don't set it as RootVisual yet; this allows the splash
+ // screen to remain active until the application is ready to render.
+ RootFrame = new PhoneApplicationFrame();
+ RootFrame.Navigated += CompleteInitializePhoneApplication;
+
+ // Handle navigation failures
+ RootFrame.NavigationFailed += RootFrame_NavigationFailed;
+
+ // Ensure we don't initialize again
+ phoneApplicationInitialized = true;
+ }
+
+ // Do not add any additional code to this method
+ private void CompleteInitializePhoneApplication(object sender, NavigationEventArgs e)
+ {
+ // Set the root visual to allow the application to render
+ if (RootVisual != RootFrame)
+ RootVisual = RootFrame;
+
+ // Remove this handler since it is no longer needed
+ RootFrame.Navigated -= CompleteInitializePhoneApplication;
+ }
+
+ #endregion
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/ApplicationIcon.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/ApplicationIcon.png b/lib/cordova-wp8/tests/MobileSpecUnitTests/ApplicationIcon.png
new file mode 100644
index 0000000..6b69046
Binary files /dev/null and b/lib/cordova-wp8/tests/MobileSpecUnitTests/ApplicationIcon.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/Background.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/Background.png b/lib/cordova-wp8/tests/MobileSpecUnitTests/Background.png
new file mode 100644
index 0000000..2667df4
Binary files /dev/null and b/lib/cordova-wp8/tests/MobileSpecUnitTests/Background.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/MainPage.xaml
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/MainPage.xaml b/lib/cordova-wp8/tests/MobileSpecUnitTests/MainPage.xaml
new file mode 100644
index 0000000..4b39b4e
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/MainPage.xaml
@@ -0,0 +1,52 @@
+<!--
+ 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.
+-->
+<phone:PhoneApplicationPage
+ x:Class="MobileSpecUnitTests.MainPage"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
+ xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:my="clr-namespace:WPCordovaClassLib;assembly=WPCordovaClassLib"
+ FontFamily="{StaticResource PhoneFontFamilyNormal}"
+ FontSize="{StaticResource PhoneFontSizeNormal}"
+ Foreground="{StaticResource PhoneForegroundBrush}"
+ SupportedOrientations="Portrait" Orientation="Portrait"
+ mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
+ shell:SystemTray.IsVisible="True">
+
+ <!--LayoutRoot is the root grid where all page content is placed-->
+ <Grid x:Name="LayoutRoot" Background="Transparent">
+ <Grid.RowDefinitions>
+ <RowDefinition Height="*"/>
+ </Grid.RowDefinitions>
+
+ <my:CordovaView Name="PGView"
+ VerticalAlignment="Stretch"
+ HorizontalAlignment="Stretch"
+ Margin="0,0,0,0">
+ </my:CordovaView>
+
+
+ </Grid>
+
+
+
+</phone:PhoneApplicationPage>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/MainPage.xaml.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/MainPage.xaml.cs b/lib/cordova-wp8/tests/MobileSpecUnitTests/MainPage.xaml.cs
new file mode 100644
index 0000000..a81888b
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/MainPage.xaml.cs
@@ -0,0 +1,42 @@
+/*
+ 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.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;
+
+namespace MobileSpecUnitTests
+{
+ public partial class MainPage : PhoneApplicationPage
+ {
+ public MainPage()
+ {
+ InitializeComponent();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/MobileSpecUnitTests.csproj
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/MobileSpecUnitTests.csproj b/lib/cordova-wp8/tests/MobileSpecUnitTests/MobileSpecUnitTests.csproj
new file mode 100644
index 0000000..6c8ce71
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/MobileSpecUnitTests.csproj
@@ -0,0 +1,247 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>10.0.20506</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{86DC5E2F-4AEE-42E3-9471-A082B9BEBEAC}</ProjectGuid>
+ <ProjectTypeGuids>{C089C8C0-30E0-4E22-80C0-CE093F111A43};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>MobileSpecUnitTests</RootNamespace>
+ <AssemblyName>MobileSpecUnitTests</AssemblyName>
+ <TargetFrameworkVersion>v8.0</TargetFrameworkVersion>
+ <SilverlightVersion>
+ </SilverlightVersion>
+ <TargetFrameworkProfile>
+ </TargetFrameworkProfile>
+ <TargetFrameworkIdentifier>WindowsPhone</TargetFrameworkIdentifier>
+ <SilverlightApplication>true</SilverlightApplication>
+ <SupportedCultures>
+ </SupportedCultures>
+ <XapOutputs>true</XapOutputs>
+ <GenerateSilverlightManifest>true</GenerateSilverlightManifest>
+ <XapFilename>MobileSpecUnitTests_$(Configuration)_$(Platform).xap</XapFilename>
+ <SilverlightManifestTemplate>Properties\AppManifest.xml</SilverlightManifestTemplate>
+ <SilverlightAppEntry>MobileSpecUnitTests.App</SilverlightAppEntry>
+ <ValidateXaml>true</ValidateXaml>
+ <ThrowErrorsInValidation>true</ThrowErrorsInValidation>
+ <MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>Bin\Debug</OutputPath>
+ <DefineConstants>DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <Prefer32Bit>false</Prefer32Bit>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>Bin\Release</OutputPath>
+ <DefineConstants>TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <Prefer32Bit>false</Prefer32Bit>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
+ <DebugSymbols>true</DebugSymbols>
+ <OutputPath>Bin\x86\Debug</OutputPath>
+ <DefineConstants>DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <DebugType>full</DebugType>
+ <PlatformTarget>
+ </PlatformTarget>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+ <Optimize>false</Optimize>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
+ <OutputPath>Bin\x86\Release</OutputPath>
+ <DefineConstants>TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
+ <Optimize>true</Optimize>
+ <NoStdLib>true</NoStdLib>
+ <DebugType>pdbonly</DebugType>
+ <PlatformTarget>
+ </PlatformTarget>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+ <Prefer32Bit>false</Prefer32Bit>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
+ <DebugSymbols>true</DebugSymbols>
+ <OutputPath>Bin\ARM\Debug</OutputPath>
+ <DefineConstants>DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <DebugType>full</DebugType>
+ <PlatformTarget>
+ </PlatformTarget>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+ <Prefer32Bit>false</Prefer32Bit>
+ <Optimize>false</Optimize>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
+ <OutputPath>Bin\ARM\Release</OutputPath>
+ <DefineConstants>TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
+ <Optimize>true</Optimize>
+ <NoStdLib>true</NoStdLib>
+ <DebugType>pdbonly</DebugType>
+ <PlatformTarget>
+ </PlatformTarget>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="App.xaml.cs">
+ <DependentUpon>App.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="MainPage.xaml.cs">
+ <DependentUpon>MainPage.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ApplicationDefinition Include="App.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </ApplicationDefinition>
+ <Page Include="MainPage.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="Properties\AppManifest.xml" />
+ <None Include="Properties\WMAppManifest.xml">
+ <SubType>Designer</SubType>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <Content Include="ApplicationIcon.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="Background.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="www\accelerometer\index.html" />
+ <Content Include="www\audio\index.html" />
+ <Content Include="www\autotest\html\HtmlReporter.js" />
+ <Content Include="www\autotest\html\HtmlReporterHelpers.js" />
+ <Content Include="www\autotest\html\ReporterView.js" />
+ <Content Include="www\autotest\html\SpecView.js" />
+ <Content Include="www\autotest\html\SuiteView.js" />
+ <Content Include="www\autotest\html\TrivialReporter.js" />
+ <Content Include="www\autotest\index.html" />
+ <Content Include="www\autotest\jasmine.css" />
+ <Content Include="www\autotest\jasmine.js" />
+ <Content Include="www\autotest\pages\accelerometer.html" />
+ <Content Include="www\autotest\pages\all.html" />
+ <Content Include="www\autotest\pages\battery.html" />
+ <Content Include="www\autotest\pages\bridge.html" />
+ <Content Include="www\autotest\pages\camera.html" />
+ <Content Include="www\autotest\pages\capture.html" />
+ <Content Include="www\autotest\pages\compass.html" />
+ <Content Include="www\autotest\pages\contacts.html" />
+ <Content Include="www\autotest\pages\datauri.html" />
+ <Content Include="www\autotest\pages\device.html" />
+ <Content Include="www\autotest\pages\file.html" />
+ <Content Include="www\autotest\pages\filetransfer.html" />
+ <Content Include="www\autotest\pages\geolocation.html" />
+ <Content Include="www\autotest\pages\globalization.html" />
+ <Content Include="www\autotest\pages\media.html" />
+ <Content Include="www\autotest\pages\network.html" />
+ <Content Include="www\autotest\pages\notification.html" />
+ <Content Include="www\autotest\pages\platform.html" />
+ <Content Include="www\autotest\pages\storage.html" />
+ <Content Include="www\autotest\test-runner.js" />
+ <Content Include="www\autotest\tests\accelerometer.tests.js" />
+ <Content Include="www\autotest\tests\battery.tests.js" />
+ <Content Include="www\autotest\tests\bridge.tests.js" />
+ <Content Include="www\autotest\tests\camera.tests.js" />
+ <Content Include="www\autotest\tests\capture.tests.js" />
+ <Content Include="www\autotest\tests\compass.tests.js" />
+ <Content Include="www\autotest\tests\contacts.tests.js" />
+ <Content Include="www\autotest\tests\datauri.tests.js" />
+ <Content Include="www\autotest\tests\device.tests.js" />
+ <Content Include="www\autotest\tests\file.tests.js" />
+ <Content Include="www\autotest\tests\filetransfer.tests.js" />
+ <Content Include="www\autotest\tests\geolocation.tests.js" />
+ <Content Include="www\autotest\tests\globalization.tests.js" />
+ <Content Include="www\autotest\tests\media.tests.js" />
+ <Content Include="www\autotest\tests\network.tests.js" />
+ <Content Include="www\autotest\tests\notification.tests.js" />
+ <Content Include="www\autotest\tests\platform.tests.js" />
+ <Content Include="www\autotest\tests\storage.tests.js" />
+ <Content Include="www\battery\index.html" />
+ <Content Include="www\camera\index.html" />
+ <Content Include="www\compass\index.html" />
+ <Content Include="www\contacts\index.html" />
+ <Content Include="www\cordova-2.5.0.js" />
+ <Content Include="www\cordova.js" />
+ <Content Include="www\events\index.html" />
+ <Content Include="www\index.html">
+ <SubType>Designer</SubType>
+ </Content>
+ <Content Include="www\location\index.html" />
+ <Content Include="www\main.js" />
+ <Content Include="www\master.css" />
+ <Content Include="SplashScreenImage.jpg" />
+ <Content Include="www\misc\index.html" />
+ <Content Include="www\misc\page2.html" />
+ <Content Include="www\network\index.html" />
+ <Content Include="www\notification\index.html" />
+ <Content Include="www\sql\index.html" />
+ <Content Include="www\storage\index.html" />
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\framework\WPCordovaClassLib.csproj">
+ <Project>{FC6A1A70-892D-46AD-9E4A-9793F72AF780}</Project>
+ <Name>WPCordovaClassLib</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <Folder Include="www\execbenchmark\" />
+ </ItemGroup>
+ <Import Project="$(MSBuildExtensionsPath)\Microsoft\$(TargetFrameworkIdentifier)\$(TargetFrameworkVersion)\Microsoft.$(TargetFrameworkIdentifier).$(TargetFrameworkVersion).Overrides.targets" />
+ <Import Project="$(MSBuildExtensionsPath)\Microsoft\$(TargetFrameworkIdentifier)\$(TargetFrameworkVersion)\Microsoft.$(TargetFrameworkIdentifier).CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+ <ProjectExtensions />
+ <PropertyGroup>
+ </PropertyGroup>
+</Project>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/MobileSpecUnitTests.sln
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/MobileSpecUnitTests.sln b/lib/cordova-wp8/tests/MobileSpecUnitTests/MobileSpecUnitTests.sln
new file mode 100644
index 0000000..20257da
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/MobileSpecUnitTests.sln
@@ -0,0 +1,44 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MobileSpecUnitTests", "MobileSpecUnitTests.csproj", "{86DC5E2F-4AEE-42E3-9471-A082B9BEBEAC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WPCordovaClassLib", "..\..\framework\WPCordovaClassLib.csproj", "{FC6A1A70-892D-46AD-9E4A-9793F72AF780}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|ARM = Debug|ARM
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|ARM = Release|ARM
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {86DC5E2F-4AEE-42E3-9471-A082B9BEBEAC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {86DC5E2F-4AEE-42E3-9471-A082B9BEBEAC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {86DC5E2F-4AEE-42E3-9471-A082B9BEBEAC}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {86DC5E2F-4AEE-42E3-9471-A082B9BEBEAC}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {86DC5E2F-4AEE-42E3-9471-A082B9BEBEAC}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {86DC5E2F-4AEE-42E3-9471-A082B9BEBEAC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {86DC5E2F-4AEE-42E3-9471-A082B9BEBEAC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {86DC5E2F-4AEE-42E3-9471-A082B9BEBEAC}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {86DC5E2F-4AEE-42E3-9471-A082B9BEBEAC}.Release|ARM.ActiveCfg = Release|Any CPU
+ {86DC5E2F-4AEE-42E3-9471-A082B9BEBEAC}.Release|x86.ActiveCfg = Release|Any CPU
+ {FC6A1A70-892D-46AD-9E4A-9793F72AF780}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FC6A1A70-892D-46AD-9E4A-9793F72AF780}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FC6A1A70-892D-46AD-9E4A-9793F72AF780}.Debug|ARM.ActiveCfg = Debug|ARM
+ {FC6A1A70-892D-46AD-9E4A-9793F72AF780}.Debug|ARM.Build.0 = Debug|ARM
+ {FC6A1A70-892D-46AD-9E4A-9793F72AF780}.Debug|x86.ActiveCfg = Debug|x86
+ {FC6A1A70-892D-46AD-9E4A-9793F72AF780}.Debug|x86.Build.0 = Debug|x86
+ {FC6A1A70-892D-46AD-9E4A-9793F72AF780}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FC6A1A70-892D-46AD-9E4A-9793F72AF780}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FC6A1A70-892D-46AD-9E4A-9793F72AF780}.Release|ARM.ActiveCfg = Release|ARM
+ {FC6A1A70-892D-46AD-9E4A-9793F72AF780}.Release|ARM.Build.0 = Release|ARM
+ {FC6A1A70-892D-46AD-9E4A-9793F72AF780}.Release|x86.ActiveCfg = Release|x86
+ {FC6A1A70-892D-46AD-9E4A-9793F72AF780}.Release|x86.Build.0 = Release|x86
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/Properties/AppManifest.xml
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/Properties/AppManifest.xml b/lib/cordova-wp8/tests/MobileSpecUnitTests/Properties/AppManifest.xml
new file mode 100644
index 0000000..6712a11
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/Properties/AppManifest.xml
@@ -0,0 +1,6 @@
+<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+>
+ <Deployment.Parts>
+ </Deployment.Parts>
+</Deployment>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/Properties/AssemblyInfo.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/Properties/AssemblyInfo.cs b/lib/cordova-wp8/tests/MobileSpecUnitTests/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..5acaa9c
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/Properties/AssemblyInfo.cs
@@ -0,0 +1,35 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("MobileSpecUnitTests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("MobileSpecUnitTests")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2011")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("ce0ba3ac-f23b-47d7-b37b-09bdd19ebefe")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/Properties/WMAppManifest.xml
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/Properties/WMAppManifest.xml b/lib/cordova-wp8/tests/MobileSpecUnitTests/Properties/WMAppManifest.xml
new file mode 100644
index 0000000..009cc2e
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/Properties/WMAppManifest.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Deployment xmlns="http://schemas.microsoft.com/windowsphone/2012/deployment" AppPlatformVersion="8.0">
+ <DefaultLanguage xmlns="" code="" />
+ <App xmlns="" ProductID="{f2c6c498-143c-44e6-b107-2f71bf3e08b9}" Title="MobileSpecUnitTests" RuntimeType="Silverlight" Version="1.0.0.0" Genre="apps.normal" Author="MobileSpecUnitTests author" Description="Sample description" Publisher="MobileSpecUnitTests" PublisherID="{8a4bc540-418c-471e-b8fd-184444b00802}">
+ <IconPath IsRelative="true" IsResource="false">ApplicationIcon.png</IconPath>
+ <Capabilities>
+ <Capability Name="ID_CAP_GAMERSERVICES" />
+ <Capability Name="ID_CAP_IDENTITY_DEVICE" />
+ <Capability Name="ID_CAP_IDENTITY_USER" />
+ <Capability Name="ID_CAP_LOCATION" />
+ <Capability Name="ID_CAP_MICROPHONE" />
+ <Capability Name="ID_CAP_NETWORKING" />
+ <Capability Name="ID_CAP_PHONEDIALER" />
+ <Capability Name="ID_CAP_PUSH_NOTIFICATION" />
+ <Capability Name="ID_CAP_SENSORS" />
+ <Capability Name="ID_CAP_WEBBROWSERCOMPONENT" />
+ <Capability Name="ID_CAP_CONTACTS" />
+ <Capability Name="ID_CAP_SENSORS" />
+ <Capability Name="ID_CAP_ISV_CAMERA" />
+ <Capability Name="ID_CAP_MEDIALIB_AUDIO" />
+ <Capability Name="ID_CAP_MEDIALIB_PLAYBACK" />
+ <Capability Name="ID_CAP_MEDIALIB_PHOTO" />
+ </Capabilities>
+ <Tasks>
+ <DefaultTask Name="_default" NavigationPage="MainPage.xaml" />
+ </Tasks>
+ <Tokens>
+ <PrimaryToken TokenID="MobileSpecUnitTestsToken" TaskName="_default">
+ <TemplateFlip>
+ <SmallImageURI IsResource="false" IsRelative="true">Background.png</SmallImageURI>
+ <Count>0</Count>
+ <BackgroundImageURI IsResource="false" IsRelative="true">Background.png</BackgroundImageURI>
+ <Title>MobileSpecUnitTests</Title>
+ <BackContent></BackContent>
+ <BackBackgroundImageURI></BackBackgroundImageURI>
+ <BackTitle></BackTitle>
+ <LargeBackgroundImageURI></LargeBackgroundImageURI>
+ <LargeBackContent></LargeBackContent>
+ <LargeBackBackgroundImageURI></LargeBackBackgroundImageURI>
+ <DeviceLockImageURI></DeviceLockImageURI>
+ <HasLarge>false</HasLarge>
+ </TemplateFlip>
+ </PrimaryToken>
+ </Tokens>
+ <ScreenResolutions>
+ <ScreenResolution Name="ID_RESOLUTION_WVGA" />
+ <ScreenResolution Name="ID_RESOLUTION_WXGA" />
+ <ScreenResolution Name="ID_RESOLUTION_HD720P" />
+ </ScreenResolutions>
+ </App>
+</Deployment>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/SplashScreenImage.jpg
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/SplashScreenImage.jpg b/lib/cordova-wp8/tests/MobileSpecUnitTests/SplashScreenImage.jpg
new file mode 100644
index 0000000..479d3e4
Binary files /dev/null and b/lib/cordova-wp8/tests/MobileSpecUnitTests/SplashScreenImage.jpg differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/accelerometer/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/accelerometer/index.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/accelerometer/index.html
new file mode 100644
index 0000000..efa043b
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/accelerometer/index.html
@@ -0,0 +1,138 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width,height=device-height,user-scalable=no,initial-scale=1.0" />
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8"> <!-- ISO-8859-1 -->
+ <title>Cordova Mobile Spec</title>
+ <link rel="stylesheet" href="../master.css" type="text/css" media="screen" title="no title" charset="utf-8">
+ <script type="text/javascript" charset="utf-8" src="../cordova.js"></script>
+
+
+<script type="text/javascript" charset="utf-8">
+
+ var deviceReady = false;
+
+ function roundNumber(num) {
+ var dec = 3;
+ var result = Math.round(num*Math.pow(10,dec))/Math.pow(10,dec);
+ return result;
+ }
+
+ //-------------------------------------------------------------------------
+ // Acceleration
+ //-------------------------------------------------------------------------
+ var watchAccelId = null;
+
+ /**
+ * Start watching acceleration
+ */
+ var watchAccel = function() {
+ console.log("watchAccel()");
+
+ // Success callback
+ var success = function(a){
+ document.getElementById('x').innerHTML = roundNumber(a.x);
+ document.getElementById('y').innerHTML = roundNumber(a.y);
+ document.getElementById('z').innerHTML = roundNumber(a.z);
+ console.log("watchAccel success callback");
+ };
+
+ // Fail callback
+ var fail = function(e){
+ console.log("watchAccel fail callback with error code "+e);
+ stopAccel();
+ setAccelStatus(Accelerometer.ERROR_MSG[e]);
+ };
+
+ // Update acceleration every 1 sec
+ var opt = {};
+ opt.frequency = 1000;
+ watchAccelId = navigator.accelerometer.watchAcceleration(success, fail, opt);
+
+ setAccelStatus("Running");
+ };
+
+ /**
+ * Stop watching the acceleration
+ */
+ var stopAccel = function() {
+ console.log("stopAccel()");
+ setAccelStatus("Stopped");
+ if (watchAccelId) {
+ navigator.accelerometer.clearWatch(watchAccelId);
+ watchAccelId = null;
+ }
+ };
+
+ /**
+ * Get current acceleration
+ */
+ var getAccel = function() {
+ console.log("getAccel()");
+
+ // Stop accel if running
+ stopAccel();
+
+ // Success callback
+ var success = function(a){
+ document.getElementById('x').innerHTML = roundNumber(a.x);
+ document.getElementById('y').innerHTML = roundNumber(a.y);
+ document.getElementById('z').innerHTML = roundNumber(a.z);
+ };
+
+ // Fail callback
+ var fail = function(e){
+ console.log("getAccel fail callback with error code "+e);
+ setAccelStatus(Accelerometer.ERROR_MSG[e]);
+ };
+
+ // Make call
+ var opt = {};
+ navigator.accelerometer.getCurrentAcceleration(success, fail, opt);
+ };
+
+ /**
+ * Set accelerometer status
+ */
+ var setAccelStatus = function(status) {
+ document.getElementById('accel_status').innerHTML = status;
+ };
+
+ /**
+ * Function called when page has finished loading.
+ */
+ function init() {
+ console.log("accelerometer.init()");
+ document.addEventListener("deviceready", function() {
+ deviceReady = true;
+ console.log("Device="+device.platform+" "+device.version);
+ }, false);
+ window.setTimeout(function() {
+ if (!deviceReady) {
+ alert("Error: PhoneGap did not initialize. Demo will not run correctly.");
+ }
+ },1000);
+ }
+
+</script>
+
+ </head>
+ <body onload="init();" id="stage" class="theme">
+
+ <h1>Acceleration</h1>
+ <div id="info">
+ <div id="accel_status">Stopped</div>
+ <div ><table width="100%">
+ <tr><td width="20%">X:</td><td id="x"> </td></tr>
+ <tr><td width="20%">Y:</td><td id="y"> </td></tr>
+ <tr><td width="20%">Z:</td><td id="z"> </td></tr>
+ </table></div>
+ </div>
+
+ <h2>Action</h2>
+ <div class="btn large" onclick="getAccel();">Get Acceleration</div>
+ <div class="btn large" onclick="watchAccel();">Start Watch</div>
+ <div class="btn large" onclick="stopAccel();">Clear Watch</div>
+ <h2> </h2><div class="backBtn" onclick="backHome();">Back</div>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/audio/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/audio/index.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/audio/index.html
new file mode 100644
index 0000000..42cfe83
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/audio/index.html
@@ -0,0 +1,394 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width,height=device-height,user-scalable=no,initial-scale=1.0" />
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8"> <!-- ISO-8859-1 -->
+ <title>Cordova Audio Tests</title>
+ <link rel="stylesheet" href="../master.css" type="text/css" media="screen" title="no title" charset="utf-8"/>
+ <script type="text/javascript" charset="utf-8" src="../cordova.js"></script>
+
+
+<script type="text/javascript" charset="utf-8">
+
+ var deviceReady = false;
+
+ //-------------------------------------------------------------------------
+ // Audio player
+ //-------------------------------------------------------------------------
+ var media1 = null;
+ var media1Timer = null;
+ var audioSrc = null;
+ var recordSrc = "myRecording.mp3";
+
+ /**
+ * Play audio
+ */
+ function playAudio(url) {
+ console.log("playAudio()");
+ console.log(" -- media="+media1);
+
+ //var src = "http://neuga.s3.amazonaws.com/onclassical/strings-or gan.mp3";
+ var src = "http://audio.ibeat.org/content/p1rj1s/p1rj1s_-_rockGuitar.mp3";
+ //var src = "/android_asset/www/Jet_Sledding.mp4"; // no work
+ //var src = "http://vprbbc.streamguys.net/vprbbc24.mp3"; // mp3 streaming
+
+ if (url) {
+ src = url;
+ }
+
+ // Stop playing if src is different from currently playing source
+ if (src != audioSrc) {
+ if (media1 != null) {
+ stopAudio();
+ media1 = null;
+ }
+ }
+
+ if (media1 == null) {
+
+
+ // TEST STREAMING AUDIO PLAYBACK
+ //var src = "http://nunzioweb.com/misc/Bon_Jovi-Crush_Mystery_Train.mp3"; // works
+ //var src = "http://nunzioweb.com/misc/Bon_Jovi-Crush_Mystery_Train.m3u"; // doesn't work
+ //var src = "http://www.wav-sounds.com/cartoon/bugsbunny1.wav"; // works
+ //var src = "http://www.angelfire.com/fl5/html-tutorial/a/couldyou.mid"; // doesn't work
+ //var src = "MusicSearch/mp3/train.mp3"; // works
+ //var src = "bryce.mp3"; // works
+ //var src = "/android_asset/www/bryce.mp3"; // works
+
+ media1 = new Media(src,
+ function() {
+ console.log("playAudio():Audio Success");
+ },
+ function(err) {
+ console.log("playAudio():Audio Error: "+err.code);
+ setAudioStatus("Error: " + err.code);
+ },
+ function(status) {
+ console.log("playAudio():Audio Status: "+status);
+ setAudioStatus(Media.MEDIA_MSG[status]);
+
+ // If stopped, then stop getting current position
+ if (Media.MEDIA_STOPPED == status) {
+ clearInterval(media1Timer);
+ media1Timer = null;
+ setAudioPosition("0 sec");
+ }
+ });
+ }
+ audioSrc = src;
+ document.getElementById('audio_duration').innerHTML = "";
+ // Play audio
+ media1.play();
+ if (media1Timer == null && media1.getCurrentPosition) {
+ media1Timer = setInterval(
+ function() {
+ media1.getCurrentPosition(
+ function(position) {
+ console.log("Pos="+position);
+ if (position >= 0.0) {
+ setAudioPosition(position+" sec");
+ }
+ },
+ function(e) {
+ console.log("Error getting pos="+e);
+ setAudioPosition("Error: "+e);
+ }
+ );
+ },
+ 1000
+ );
+ }
+
+ // Get duration
+ var counter = 0;
+ var timerDur = setInterval(
+ function() {
+ counter = counter + 100;
+ if (counter > 2000) {
+ clearInterval(timerDur);
+ }
+ var dur = media1.getDuration();
+ if (dur > 0) {
+ clearInterval(timerDur);
+ document.getElementById('audio_duration').innerHTML = dur + " sec";
+ }
+ }, 100);
+ }
+
+ /**
+ * Pause audio playback
+ */
+ function pauseAudio() {
+ console.log("pauseAudio()");
+ if (media1) {
+ media1.pause();
+ }
+ }
+
+ /**
+ * Stop audio
+ */
+ function stopAudio() {
+ console.log("stopAudio()");
+ if (media1) {
+ media1.stop();
+ media1.release();
+ }
+ clearInterval(media1Timer);
+ media1Timer = null;
+ }
+
+ /**
+ * Set audio status
+ */
+ var setAudioStatus = function(status) {
+ document.getElementById('audio_status').innerHTML = status;
+ };
+
+ /**
+ * Set audio position
+ */
+ var setAudioPosition = function(position) {
+ document.getElementById('audio_position').innerHTML = position;
+ };
+
+ //-------------------------------------------------------------------------
+ // Audio recorder
+ //-------------------------------------------------------------------------
+ var mediaRec = null;
+ var recTime = 0;
+
+ /**
+ * Record audio
+ */
+ function recordAudio() {
+ console.log("recordAudio()");
+ console.log(" -- media="+mediaRec);
+ if (mediaRec == null) {
+
+ var src = recordSrc;
+ mediaRec = new Media(src,
+ function() {
+ console.log("recordAudio():Audio Success");
+ },
+ function(err) {
+ console.log("recordAudio():Audio Error: "+err.code);
+ setAudioStatus("Error: " + err.code);
+ },
+ function(status) {
+ console.log("recordAudio():Audio Status: "+status);
+ setAudioStatus(Media.MEDIA_MSG[status]);
+ }
+ );
+ }
+
+ navigator.notification.beep(1);
+
+ // Record audio
+ mediaRec.startRecord();
+
+ // Stop recording after 10 sec
+ recTime = 0;
+ var recInterval = setInterval(function() {
+ recTime = recTime + 1;
+ setAudioPosition(recTime+" sec");
+ if (recTime >= 10) {
+ clearInterval(recInterval);
+ if (mediaRec.stopAudioRecord){
+ mediaRec.stopAudioRecord();
+ } else {
+ mediaRec.stopRecord();
+ }
+ console.log("recordAudio(): stop");
+ navigator.notification.beep(1);
+ }
+ }, 1000);
+ }
+
+ /**
+ * Play back recorded audio
+ */
+ function playRecording() {
+ playAudio(recordSrc);
+ }
+
+ /**
+ * Function to create a file for iOS recording
+ */
+ function getRecordSrc() {
+ var fsFail = function(error) {
+ console.log("error creating file for iOS recording");
+ };
+ var gotFile = function(file) {
+ recordSrc = file.fullPath;
+ //console.log("recording Src: " + recordSrc);
+ };
+ var gotFS = function(fileSystem) {
+ fileSystem.root.getFile("iOSRecording.wav", {create: true}, gotFile, fsFail);
+ };
+ window.requestFileSystem(LocalFileSystem.TEMPORARY, 0, gotFS, fsFail);
+ }
+
+ /**
+ * Function to create a file for BB recording
+ */
+ function getRecordSrcBB() {
+ var fsFail = function(error) {
+ console.log("error creating file for BB recording");
+ };
+ var gotFile = function(file) {
+ recordSrc = file.fullPath;
+ };
+ var gotFS = function(fileSystem) {
+ fileSystem.root.getFile("BBRecording.amr", {create: true}, gotFile, fsFail);
+ };
+ window.requestFileSystem(LocalFileSystem.TEMPORARY, 0, gotFS, fsFail);
+ }
+
+ /**
+ * Function called when page has finished loading.
+ */
+ function init() {
+ document.addEventListener("deviceready", function() {
+ deviceReady = true;
+ if (device.platform.indexOf("iPhone") !=-1 || device.platform.indexOf("iPad") !=-1)
+ {
+ getRecordSrc();
+ } else if (typeof blackberry !== 'undefined') {
+ getRecordSrcBB();
+ }
+ console.log("Device="+device.platform+" "+device.version);
+ }, false);
+ window.setTimeout(function() {
+ if (!deviceReady) {
+ alert("Error: PhoneGap did not initialize. Demo will not run correctly.");
+ }
+ },1000);
+ }
+
+ /**
+ * for forced updates of position after a successful seek
+ */
+ function updatePosition() {
+ media1.getCurrentPosition(
+ function(position) {
+ console.log("Pos="+position);
+ if (position >= 0.0) {
+ setAudioPosition(position+" sec");
+ }
+ },
+ function(e) {
+ console.log("Error getting pos="+e);
+ setAudioPosition("Error: "+e);
+ });
+ }
+
+ /**
+ *
+ */
+ function seekAudio(mode) {
+ var time = document.getElementById("seekinput").value;
+ if (time == "") {
+ time = 5000;
+ } else {
+ time = time * 1000; //we expect the input to be in seconds
+ }
+ if (media1 == null) {
+ console.log("seekTo requested while media1 is null");
+ if (audioSrc == null) {
+ audioSrc = "http://audio.ibeat.org/content/p1rj1s/p1rj1s_-_rockGuitar.mp3";
+ }
+ media1 = new Media(audioSrc,
+ function() {
+ console.log("seekToAudio():Audio Success");
+ },
+ function(err) {
+ console.log("seekAudio():Audio Error: "+err.code);
+ setAudioStatus("Error: " + err.code);
+ },
+ function(status) {
+ console.log("seekAudio():Audio Status: "+status);
+ setAudioStatus(Media.MEDIA_MSG[status]);
+
+ // If stopped, then stop getting current position
+ if (Media.MEDIA_STOPPED == status) {
+ clearInterval(media1Timer);
+ media1Timer = null;
+ setAudioPosition("0 sec");
+ }
+ });
+ }
+
+ media1.getCurrentPosition(
+ function (position) {
+ var deltat = time;
+ if (mode == "by") {
+ deltat = time + position * 1000;
+ }
+ media1.seekTo(deltat,
+ function () {
+ console.log("seekAudioTo():Audio Success");
+ //force an update on the position display
+ updatePosition();
+ },
+ function (err) {
+ console.log("seekAudioTo():Audio Error: " + err.code);
+ });
+ },
+ function(e) {
+ console.log("Error getting pos="+e);
+ setAudioPosition("Error: "+e);
+ });
+ }
+
+</script>
+
+ </head>
+ <body onload="init();" id="stage" class="theme">
+
+ <h1>Audio</h1>
+ <div id="info">
+ <table width="100%">
+ <tr><td><b>Status:</b></td><td id="audio_status"> </td></tr>
+ <tr><td><b>Duration:</b></td><td id="audio_duration"></td></tr>
+ <tr><td><b>Position:</b></td><td id="audio_position"></td></tr>
+ </table>
+ </div>
+ <h2>Action</h2>
+ <table>
+ <tr>
+ <th colspan=3>Play Sample Audio</th>
+ </tr>
+ <tr>
+ <td><div class="btn large" style="width:100%;" onclick="playAudio();">Play</div></td>
+ <td><div class="btn large" style="width:100%;" onclick="pauseAudio();">Pause</div></td>
+ <td><div class="btn large" style="width:100%;" onclick="stopAudio();">Stop</div></td>
+ </tr>
+ <tr>
+ <td><div class="btn large" style="width:100%;" onclick="seekAudio('by');">Seek By</div></td>
+ <td><div class="btn large" style="width:100%;" onclick="seekAudio('to');">Seek To</div></td>
+ <td>
+ <div style="width:100%;">
+ <input class="input numeric" type="number" id="seekinput" value="in seconds">
+ </div>
+ </td>
+ <td><h2>s</h2></td>
+ </tr>
+ <tr>
+ <th colspan=3><br><br>Record Audio</th>
+ </tr>
+ <tr>
+ <td colspan=3><div class="btn large" onclick="recordAudio();">Record Audio for 10 sec</a></td>
+ </tr>
+ <tr>
+ <td><div class="btn large" style="width:100%;" onclick="playRecording();">Play</div></td>
+ <td><div class="btn large" style="width:100%;" onclick="pauseAudio();">Pause</div></td>
+ <td><div class="btn large" style="width:100%;" onclick="stopAudio();">Stop</div></td>
+ </tr>
+ </table>
+
+ <h2> </h2><div class="backBtn" onclick="backHome();">Back</div>
+
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/html/HtmlReporter.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/html/HtmlReporter.js b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/html/HtmlReporter.js
new file mode 100644
index 0000000..7d9d924
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/html/HtmlReporter.js
@@ -0,0 +1,101 @@
+jasmine.HtmlReporter = function(_doc) {
+ var self = this;
+ var doc = _doc || window.document;
+
+ var reporterView;
+
+ var dom = {};
+
+ // Jasmine Reporter Public Interface
+ self.logRunningSpecs = false;
+
+ self.reportRunnerStarting = function(runner) {
+ var specs = runner.specs() || [];
+
+ if (specs.length == 0) {
+ return;
+ }
+
+ createReporterDom(runner.env.versionString());
+ doc.body.appendChild(dom.reporter);
+
+ reporterView = new jasmine.HtmlReporter.ReporterView(dom);
+ reporterView.addSpecs(specs, self.specFilter);
+ };
+
+ self.reportRunnerResults = function(runner) {
+ reporterView && reporterView.complete();
+ };
+
+ self.reportSuiteResults = function(suite) {
+ reporterView.suiteComplete(suite);
+ };
+
+ self.reportSpecStarting = function(spec) {
+ if (self.logRunningSpecs) {
+ self.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
+ }
+ };
+
+ self.reportSpecResults = function(spec) {
+ reporterView.specComplete(spec);
+ };
+
+ self.log = function() {
+ var console = jasmine.getGlobal().console;
+ if (console && console.log) {
+ if (console.log.apply) {
+ console.log.apply(console, arguments);
+ } else {
+ console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
+ }
+ }
+ };
+
+ self.specFilter = function(spec) {
+ if (!focusedSpecName()) {
+ return true;
+ }
+
+ return spec.getFullName().indexOf(focusedSpecName()) === 0;
+ };
+
+ return self;
+
+ function focusedSpecName() {
+ var specName;
+
+ (function memoizeFocusedSpec() {
+ if (specName) {
+ return;
+ }
+
+ var paramMap = [];
+ var params = doc.location.search.substring(1).split('&');
+
+ for (var i = 0; i < params.length; i++) {
+ var p = params[i].split('=');
+ paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
+ }
+
+ specName = paramMap.spec;
+ })();
+
+ return specName;
+ }
+
+ function createReporterDom(version) {
+ dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' },
+ dom.banner = self.createDom('div', { className: 'banner' },
+ self.createDom('span', { className: 'title' }, "Jasmine "),
+ self.createDom('span', { className: 'version' }, version)),
+
+ dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}),
+ dom.alert = self.createDom('div', {className: 'alert'}),
+ dom.results = self.createDom('div', {className: 'results'},
+ dom.summary = self.createDom('div', { className: 'summary' }),
+ dom.details = self.createDom('div', { id: 'details' }))
+ );
+ }
+};
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter);
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/html/HtmlReporterHelpers.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/html/HtmlReporterHelpers.js b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/html/HtmlReporterHelpers.js
new file mode 100644
index 0000000..745e1e0
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/html/HtmlReporterHelpers.js
@@ -0,0 +1,60 @@
+jasmine.HtmlReporterHelpers = {};
+
+jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) {
+ var el = document.createElement(type);
+
+ for (var i = 2; i < arguments.length; i++) {
+ var child = arguments[i];
+
+ if (typeof child === 'string') {
+ el.appendChild(document.createTextNode(child));
+ } else {
+ if (child) {
+ el.appendChild(child);
+ }
+ }
+ }
+
+ for (var attr in attrs) {
+ if (attr == "className") {
+ el[attr] = attrs[attr];
+ } else {
+ el.setAttribute(attr, attrs[attr]);
+ }
+ }
+
+ return el;
+};
+
+jasmine.HtmlReporterHelpers.getSpecStatus = function(child) {
+ var results = child.results();
+ var status = results.passed() ? 'passed' : 'failed';
+ if (results.skipped) {
+ status = 'skipped';
+ }
+
+ return status;
+};
+
+jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) {
+ var parentDiv = this.dom.summary;
+ var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite';
+ var parent = child[parentSuite];
+
+ if (parent) {
+ if (typeof this.views.suites[parent.id] == 'undefined') {
+ this.views.suites[parent.id] = new jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views);
+ }
+ parentDiv = this.views.suites[parent.id].element;
+ }
+
+ parentDiv.appendChild(childElement);
+};
+
+
+jasmine.HtmlReporterHelpers.addHelpers = function(ctor) {
+ for(var fn in jasmine.HtmlReporterHelpers) {
+ ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn];
+ }
+};
+
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/html/ReporterView.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/html/ReporterView.js b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/html/ReporterView.js
new file mode 100644
index 0000000..6a6d005
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/html/ReporterView.js
@@ -0,0 +1,164 @@
+jasmine.HtmlReporter.ReporterView = function(dom) {
+ this.startedAt = new Date();
+ this.runningSpecCount = 0;
+ this.completeSpecCount = 0;
+ this.passedCount = 0;
+ this.failedCount = 0;
+ this.skippedCount = 0;
+
+ this.createResultsMenu = function() {
+ this.resultsMenu = this.createDom('span', {className: 'resultsMenu bar'},
+ this.summaryMenuItem = this.createDom('a', {className: 'summaryMenuItem', href: "#"}, '0 specs'),
+ ' | ',
+ this.detailsMenuItem = this.createDom('a', {className: 'detailsMenuItem', href: "#"}, '0 failing'));
+
+ this.summaryMenuItem.onclick = function() {
+ dom.reporter.className = dom.reporter.className.replace(/ showDetails/g, '');
+ };
+
+ this.detailsMenuItem.onclick = function() {
+ showDetails();
+ };
+ };
+
+ this.addSpecs = function(specs, specFilter) {
+ this.totalSpecCount = specs.length;
+
+ this.views = {
+ specs: {},
+ suites: {}
+ };
+
+ for (var i = 0; i < specs.length; i++) {
+ var spec = specs[i];
+ this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom, this.views);
+ if (specFilter(spec)) {
+ this.runningSpecCount++;
+ }
+ }
+ };
+
+ this.specComplete = function(spec) {
+ this.completeSpecCount++;
+
+ if (isUndefined(this.views.specs[spec.id])) {
+ this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom);
+ }
+
+ var specView = this.views.specs[spec.id];
+
+ switch (specView.status()) {
+ case 'passed':
+ this.passedCount++;
+ break;
+
+ case 'failed':
+ this.failedCount++;
+ break;
+
+ case 'skipped':
+ this.skippedCount++;
+ break;
+ }
+
+ specView.refresh();
+ this.refresh();
+ };
+
+ this.suiteComplete = function(suite) {
+ var suiteView = this.views.suites[suite.id];
+ if (isUndefined(suiteView)) {
+ return;
+ }
+ suiteView.refresh();
+ };
+
+ this.refresh = function() {
+
+ if (isUndefined(this.resultsMenu)) {
+ this.createResultsMenu();
+ }
+
+ // currently running UI
+ if (isUndefined(this.runningAlert)) {
+ this.runningAlert = this.createDom('a', {href: "?", className: "runningAlert bar"});
+ dom.alert.appendChild(this.runningAlert);
+ }
+ this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount);
+
+ // skipped specs UI
+ if (isUndefined(this.skippedAlert)) {
+ this.skippedAlert = this.createDom('a', {href: "?", className: "skippedAlert bar"});
+ }
+
+ this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
+
+ if (this.skippedCount === 1 && isDefined(dom.alert)) {
+ dom.alert.appendChild(this.skippedAlert);
+ }
+
+ // passing specs UI
+ if (isUndefined(this.passedAlert)) {
+ this.passedAlert = this.createDom('span', {href: "?", className: "passingAlert bar"});
+ }
+ this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount);
+
+ // failing specs UI
+ if (isUndefined(this.failedAlert)) {
+ this.failedAlert = this.createDom('span', {href: "?", className: "failingAlert bar"});
+ }
+ this.failedAlert.innerHTML = "Failing " + specPluralizedFor(this.failedCount);
+
+ if (this.failedCount === 1 && isDefined(dom.alert)) {
+ dom.alert.appendChild(this.failedAlert);
+ dom.alert.appendChild(this.resultsMenu);
+ }
+
+ // summary info
+ this.summaryMenuItem.innerHTML = "" + specPluralizedFor(this.runningSpecCount);
+ this.detailsMenuItem.innerHTML = "" + this.failedCount + " failing";
+ };
+
+ this.complete = function() {
+ dom.alert.removeChild(this.runningAlert);
+
+ this.skippedAlert.innerHTML = "Ran " + this.runningSpecCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
+
+ if (this.failedCount === 0) {
+ dom.alert.appendChild(this.createDom('span', {className: 'passingAlert bar'}, "Passing " + specPluralizedFor(this.passedCount)));
+ } else {
+ showDetails();
+ }
+
+ dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"));
+ };
+
+ return this;
+
+ function showDetails() {
+ if (dom.reporter.className.search(/showDetails/) === -1) {
+ dom.reporter.className += " showDetails";
+ }
+ }
+
+ function isUndefined(obj) {
+ return typeof obj === 'undefined';
+ }
+
+ function isDefined(obj) {
+ return !isUndefined(obj);
+ }
+
+ function specPluralizedFor(count) {
+ var str = count + " spec";
+ if (count > 1) {
+ str += "s"
+ }
+ return str;
+ }
+
+};
+
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.ReporterView);
+
+
[21/37] Add WP7 and WP8 platform files.
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/www/css/index.css
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/www/css/index.css b/lib/cordova-wp7/templates/standalone/www/css/index.css
new file mode 100644
index 0000000..1d34d88
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/www/css/index.css
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+* {
+ -webkit-touch-callout: none; /* prevent callout to copy image, etc when tap to hold */
+ -webkit-text-size-adjust: none; /* prevent WebKit from resizing text to fit */
+ -webkit-tap-highlight-color: rgba(0,0,0,0); /* make transparent link selection, adjust last value opacity 0 to 1.0 */
+ -webkit-user-select: none; /* prevent copy paste, to allow, change 'none' to 'text' */
+}
+
+body {
+ background-color:#E4E4E4;
+ background-image:linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
+ background-image:-webkit-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
+ background-image:-ms-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
+ background-image:-webkit-gradient(
+ linear,
+ left top,
+ left bottom,
+ color-stop(0, #A7A7A7),
+ color-stop(0.51, #E4E4E4)
+ );
+ background-attachment:fixed;
+ font-family:'HelveticaNeue-Light', 'HelveticaNeue', Helvetica, Arial, sans-serif;
+ font-size:12px;
+ height:100%;
+ margin:0px;
+ padding:0px;
+ text-transform:uppercase;
+ width:100%;
+}
+
+/* Portrait layout (default) */
+.app {
+ background:url(../img/logo.png) no-repeat center top; /* 170px x 200px */
+ position:absolute; /* position in the center of the screen */
+ left:50%;
+ top:50%;
+ height:50px; /* text area height */
+ width:225px; /* text area width */
+ text-align:center;
+ padding:180px 0px 0px 0px; /* image height is 200px (bottom 20px are overlapped with text) */
+ margin:-115px 0px 0px -112px; /* offset vertical: half of image height and text area height */
+ /* offset horizontal: half of text area width */
+}
+
+/* Landscape layout (with min-width) */
+@media screen and (min-aspect-ratio: 1/1) and (min-width:400px) {
+ .app {
+ background-position:left center;
+ padding:75px 0px 75px 170px; /* padding-top + padding-bottom + text area = image height */
+ margin:-90px 0px 0px -198px; /* offset vertical: half of image height */
+ /* offset horizontal: half of image width and text area width */
+ }
+}
+
+h1 {
+ font-size:24px;
+ font-weight:normal;
+ margin:0px;
+ overflow:visible;
+ padding:0px;
+ text-align:center;
+}
+
+.event {
+ border-radius:4px;
+ -webkit-border-radius:4px;
+ color:#FFFFFF;
+ font-size:12px;
+ margin:0px 30px;
+ padding:2px 0px;
+}
+
+.event.listening {
+ background-color:#333333;
+ display:block;
+}
+
+.event.received {
+ background-color:#4B946A;
+ display:none;
+}
+
+@keyframes fade {
+ from { opacity: 1.0; }
+ 50% { opacity: 0.4; }
+ to { opacity: 1.0; }
+}
+
+@-webkit-keyframes fade {
+ from { opacity: 1.0; }
+ 50% { opacity: 0.4; }
+ to { opacity: 1.0; }
+}
+
+.blink {
+ animation:fade 3000ms infinite;
+ -webkit-animation:fade 3000ms infinite;
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/www/img/logo.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/www/img/logo.png b/lib/cordova-wp7/templates/standalone/www/img/logo.png
new file mode 100644
index 0000000..9519e7d
Binary files /dev/null and b/lib/cordova-wp7/templates/standalone/www/img/logo.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/www/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/www/index.html b/lib/cordova-wp7/templates/standalone/www/index.html
new file mode 100644
index 0000000..31f61f4
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/www/index.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<!--
+ 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.
+-->
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta name="format-detection" content="telephone=no" />
+ <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
+ <link rel="stylesheet" type="text/css" href="css/index.css" />
+ <title>Hello World</title>
+ </head>
+ <body>
+ <div class="app">
+ <h1>Apache Cordova</h1>
+ <div id="deviceready" class="blink">
+ <p class="event listening">Connecting to Device</p>
+ <p class="event received">Device is Ready</p>
+ </div>
+ </div>
+ <script type="text/javascript" src="cordova-2.7.0.js"></script>
+ <script type="text/javascript" src="js/index.js"></script>
+ <script type="text/javascript">
+ app.initialize();
+ </script>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/www/js/index.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/www/js/index.js b/lib/cordova-wp7/templates/standalone/www/js/index.js
new file mode 100644
index 0000000..bf02e98
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/www/js/index.js
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+var app = {
+ // Application Constructor
+ initialize: function() {
+ this.bindEvents();
+ },
+ // Bind Event Listeners
+ //
+ // Bind any events that are required on startup. Common events are:
+ // `load`, `deviceready`, `offline`, and `online`.
+ bindEvents: function() {
+ document.addEventListener('deviceready', this.onDeviceReady, false);
+ },
+ // deviceready Event Handler
+ //
+ // The scope of `this` is the event. In order to call the `receivedEvent`
+ // function, we must explicitly call `app.receivedEvent(...);`
+ onDeviceReady: function() {
+ app.receivedEvent('deviceready');
+ },
+ // Update DOM on a Received Event
+ receivedEvent: function(id) {
+ var parentElement = document.getElementById(id);
+ var listeningElement = parentElement.querySelector('.listening');
+ var receivedElement = parentElement.querySelector('.received');
+
+ listeningElement.setAttribute('style', 'display:none;');
+ receivedElement.setAttribute('style', 'display:block;');
+
+ console.log('Received Event: ' + id);
+ }
+};
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/vs/MyTemplateStandAlone.vstemplate
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/vs/MyTemplateStandAlone.vstemplate b/lib/cordova-wp7/templates/vs/MyTemplateStandAlone.vstemplate
new file mode 100644
index 0000000..34b949d
--- /dev/null
+++ b/lib/cordova-wp7/templates/vs/MyTemplateStandAlone.vstemplate
@@ -0,0 +1,115 @@
+<VSTemplate Version="3.0.0" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005" Type="Project">
+ <TemplateData>
+ <Name>CordovaWP7_2_7_0</Name>
+ <Description>Cordova 2.7.0 for Windows Phone 7.5 using the Cordova source code directly.</Description>
+ <ProjectType>CSharp</ProjectType>
+ <ProjectSubType>
+ </ProjectSubType>
+ <SortOrder>1000</SortOrder>
+ <CreateNewFolder>true</CreateNewFolder>
+ <DefaultName>CordovaWP7_2_7_0</DefaultName>
+ <ProvideDefaultName>true</ProvideDefaultName>
+ <LocationField>Enabled</LocationField>
+ <EnableLocationBrowseButton>true</EnableLocationBrowseButton>
+ <Icon>__TemplateIcon.png</Icon>
+ <PreviewImage>__PreviewImage.jpg</PreviewImage>
+ </TemplateData>
+ <TemplateContent>
+ <Project TargetFileName="CordovaAppProj.csproj" File="CordovaAppProj.csproj" ReplaceParameters="true">
+ <ProjectItem ReplaceParameters="true" TargetFileName="App.xaml">App.xaml</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="App.xaml.cs">App.xaml.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="false" TargetFileName="ApplicationIcon.png">ApplicationIcon.png</ProjectItem>
+ <ProjectItem ReplaceParameters="false" TargetFileName="Background.png">Background.png</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="BuildManifestProcessor.js">BuildManifestProcessor.js</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="config.xml">config.xml</ProjectItem>
+ <Folder Name="cordovalib" TargetFolderName="cordovalib">
+ <ProjectItem ReplaceParameters="true" TargetFileName="BrowserMouseHelper.cs">BrowserMouseHelper.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="CommandFactory.cs">CommandFactory.cs</ProjectItem>
+ <Folder Name="Commands" TargetFolderName="Commands">
+ <ProjectItem ReplaceParameters="true" TargetFileName="BaseCommand.cs">BaseCommand.cs</ProjectItem>
+ </Folder>
+ <ProjectItem ReplaceParameters="true" TargetFileName="ConfigHandler.cs">ConfigHandler.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="CordovaCommandCall.cs">CordovaCommandCall.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="CordovaView.xaml">CordovaView.xaml</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="CordovaView.xaml.cs">CordovaView.xaml.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="DOMStorageHelper.cs">DOMStorageHelper.cs</ProjectItem>
+ <Folder Name="JSON" TargetFolderName="JSON">
+ <ProjectItem ReplaceParameters="true" TargetFileName="JsonHelper.cs">JsonHelper.cs</ProjectItem>
+ </Folder>
+ <ProjectItem ReplaceParameters="true" TargetFileName="NativeExecution.cs">NativeExecution.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="OrientationHelper.cs">OrientationHelper.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="PluginResult.cs">PluginResult.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="ScriptCallback.cs">ScriptCallback.cs</ProjectItem>
+ </Folder>
+ <ProjectItem ReplaceParameters="true" TargetFileName="CordovaSourceDictionary.xml">CordovaSourceDictionary.xml</ProjectItem>
+ <Folder Name="Images" TargetFolderName="Images">
+ <ProjectItem ReplaceParameters="false" TargetFileName="appbar.back.rest.png">appbar.back.rest.png</ProjectItem>
+ <ProjectItem ReplaceParameters="false" TargetFileName="appbar.close.rest.png">appbar.close.rest.png</ProjectItem>
+ <ProjectItem ReplaceParameters="false" TargetFileName="appbar.feature.video.rest.png">appbar.feature.video.rest.png</ProjectItem>
+ <ProjectItem ReplaceParameters="false" TargetFileName="appbar.next.rest.png">appbar.next.rest.png</ProjectItem>
+ <ProjectItem ReplaceParameters="false" TargetFileName="appbar.save.rest.png">appbar.save.rest.png</ProjectItem>
+ <ProjectItem ReplaceParameters="false" TargetFileName="appbar.stop.rest.png">appbar.stop.rest.png</ProjectItem>
+ </Folder>
+ <ProjectItem ReplaceParameters="true" TargetFileName="MainPage.xaml">MainPage.xaml</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="MainPage.xaml.cs">MainPage.xaml.cs</ProjectItem>
+ <Folder Name="Plugins" TargetFolderName="Plugins">
+ <ProjectItem ReplaceParameters="true" TargetFileName="Accelerometer.cs">Accelerometer.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="AudioFormatsHelper.cs">AudioFormatsHelper.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="AudioPlayer.cs">AudioPlayer.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="Battery.cs">Battery.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="Camera.cs">Camera.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="Capture.cs">Capture.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="Compass.cs">Compass.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="Contacts.cs">Contacts.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="DebugConsole.cs">DebugConsole.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="Device.cs">Device.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="File.cs">File.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="FileTransfer.cs">FileTransfer.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="GeoLocation.cs">GeoLocation.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="Globalization.cs">Globalization.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="ImageExifHelper.cs">ImageExifHelper.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="InAppBrowser.cs">InAppBrowser.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="Media.cs">Media.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="MimeTypeMapper.cs">MimeTypeMapper.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="NetworkStatus.cs">NetworkStatus.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="Notification.cs">Notification.cs</ProjectItem>
+ <Folder Name="UI" TargetFolderName="UI">
+ <ProjectItem ReplaceParameters="true" TargetFileName="AudioCaptureTask.cs">AudioCaptureTask.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="AudioRecorder.xaml">AudioRecorder.xaml</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="AudioRecorder.xaml.cs">AudioRecorder.xaml.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="ImageCapture.xaml">ImageCapture.xaml</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="ImageCapture.xaml.cs">ImageCapture.xaml.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="NotificationBox.xaml">NotificationBox.xaml</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="NotificationBox.xaml.cs">NotificationBox.xaml.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="VideoCaptureTask.cs">VideoCaptureTask.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="VideoRecorder.xaml">VideoRecorder.xaml</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="VideoRecorder.xaml.cs">VideoRecorder.xaml.cs</ProjectItem>
+ </Folder>
+ </Folder>
+ <Folder Name="Properties" TargetFolderName="Properties">
+ <ProjectItem ReplaceParameters="true" TargetFileName="AppManifest.xml">AppManifest.xml</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="AssemblyInfo.cs">AssemblyInfo.cs</ProjectItem>
+ <ProjectItem ReplaceParameters="true" TargetFileName="WMAppManifest.xml">WMAppManifest.xml</ProjectItem>
+ </Folder>
+ <Folder Name="resources" TargetFolderName="resources">
+ <ProjectItem ReplaceParameters="false" TargetFileName="notification-beep.wav">notification-beep.wav</ProjectItem>
+ </Folder>
+ <Folder Name="Service References" TargetFolderName="Service References" />
+ <ProjectItem ReplaceParameters="false" TargetFileName="SplashScreenImage.jpg">SplashScreenImage.jpg</ProjectItem>
+ <ProjectItem ReplaceParameters="false" TargetFileName="VERSION">VERSION</ProjectItem>
+ <Folder Name="www" TargetFolderName="www">
+ <ProjectItem ReplaceParameters="true" TargetFileName="cordova-2.7.0.js">cordova-2.7.0.js</ProjectItem>
+ <Folder Name="css" TargetFolderName="css">
+ <ProjectItem ReplaceParameters="true" TargetFileName="index.css">index.css</ProjectItem>
+ </Folder>
+ <Folder Name="img" TargetFolderName="img">
+ <ProjectItem ReplaceParameters="false" TargetFileName="logo.png">logo.png</ProjectItem>
+ </Folder>
+ <ProjectItem ReplaceParameters="true" TargetFileName="index.html">index.html</ProjectItem>
+ <Folder Name="js" TargetFolderName="js">
+ <ProjectItem ReplaceParameters="true" TargetFileName="index.js">index.js</ProjectItem>
+ </Folder>
+ </Folder>
+ </Project>
+ </TemplateContent>
+</VSTemplate>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/vs/description.txt
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/vs/description.txt b/lib/cordova-wp7/templates/vs/description.txt
new file mode 100644
index 0000000..089ad81
--- /dev/null
+++ b/lib/cordova-wp7/templates/vs/description.txt
@@ -0,0 +1,4 @@
+CordovaStarter
+
+Starter project for building a Cordova app for Windows Phone version: 2.6.0
+
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/vs/pg_templateIcon.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/vs/pg_templateIcon.png b/lib/cordova-wp7/templates/vs/pg_templateIcon.png
new file mode 100644
index 0000000..75c17c7
Binary files /dev/null and b/lib/cordova-wp7/templates/vs/pg_templateIcon.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/vs/pg_templatePreview.jpg
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/vs/pg_templatePreview.jpg b/lib/cordova-wp7/templates/vs/pg_templatePreview.jpg
new file mode 100644
index 0000000..1d72941
Binary files /dev/null and b/lib/cordova-wp7/templates/vs/pg_templatePreview.jpg differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/tests/README.md
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/tests/README.md b/lib/cordova-wp7/tests/README.md
new file mode 100644
index 0000000..cdf9516
--- /dev/null
+++ b/lib/cordova-wp7/tests/README.md
@@ -0,0 +1,7 @@
+Tests Have Moved
+===
+
+Tests now live in the MobileSpec repo at:
+https://github.com/apache/incubator-cordova-mobile-spec
+
+You will need to create a new project, and add the mobile-spec files to it to run the tests.
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/tooling/scripts/buildjs.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/tooling/scripts/buildjs.bat b/lib/cordova-wp7/tooling/scripts/buildjs.bat
new file mode 100644
index 0000000..28d2423
--- /dev/null
+++ b/lib/cordova-wp7/tooling/scripts/buildjs.bat
@@ -0,0 +1,2 @@
+@echo off
+cscript "%~dp0\buildjs.js" %* //nologo
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/tooling/scripts/buildjs.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/tooling/scripts/buildjs.js b/lib/cordova-wp7/tooling/scripts/buildjs.js
new file mode 100644
index 0000000..b5c51ad
--- /dev/null
+++ b/lib/cordova-wp7/tooling/scripts/buildjs.js
@@ -0,0 +1,209 @@
+/*
+ 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.
+*/
+
+var fso = WScript.CreateObject('Scripting.FileSystemObject'),
+ shell = WScript.CreateObject("shell.application"),
+ wscript_shell = WScript.CreateObject("WScript.Shell");
+
+var args = WScript.Arguments,
+ //Root folder of cordova-wp7 (i.e C:\Cordova\cordova-wp7)
+ ROOT = WScript.ScriptFullName.split('\\tooling\\', 1),
+ //Sub folder containing templates
+ TEMPLATES_PATH = '\\templates',
+ //Sub folder for standalone project
+ STANDALONE_PATH = TEMPLATES_PATH + '\\standalone',
+ //Sub folder containing framework
+ FRAMEWORK_PATH = '\\framework',
+ //Subfolder containing example project
+ EXAMPLE_PATH = '\\example',
+ //Git Repositories
+ CORDOVA_JS = "https://git-wip-us.apache.org/repos/asf/cordova-js.git",
+ // get version
+ VERSION = read(ROOT+'\\VERSION').replace(/\r\n/,'').replace(/\n/,''),
+ BUILD_DESTINATION;
+
+function Log(msg) {
+ WScript.StdOut.WriteLine(msg);
+}
+
+// help function
+function Usage()
+{
+ Log("");
+ Log("This Script builds the given virsion of cordova.js and injects it into this or the given cordova-wp7 ");
+ Log("");
+ Log("Usage: buildjs [ Version PathTOCordovaWP7 ]");
+ Log(" Version : The version of cordova.js to build (must already be tagged)");
+ Log(" PathTOCordovaWP7 : The path to the cordova directory where the new cordova.js will go.");
+ Log("examples:");
+ Log(" buildjs 2.5.0rc1 //Puts cordova-2.5.0rc1 as the cordova.js in the current working directory");
+ Log(" buildjs 2.4.0 C:\\Users\\anonymous\\Desktop\\cordova-wp7 //Puts cordova-2.4.0.js in the given directory");
+ Log(" buildjs //Builds the version of cordova.js from the root folder and adds it to the working directory repo");
+ Log("");
+}
+
+// returns the contents of a file
+function read(filename) {
+ //Log('Reading in ' + filename);
+ if(fso.FileExists(filename))
+ {
+ var f=fso.OpenTextFile(filename, 1,2);
+ var s=f.ReadAll();
+ f.Close();
+ return s;
+ }
+ else
+ {
+ Log('Cannot read non-existant file : ' + filename);
+ WScript.Quit(1);
+ }
+ return null;
+}
+
+// executes a commmand in the shell
+function exec(command) {
+ var oShell=wscript_shell.Exec(command);
+ while (oShell.Status === 0) {
+ WScript.sleep(100);
+ }
+}
+
+// executes a commmand in the shell
+function exec_verbose(command) {
+ //Log("Command: " + command);
+ var oShell=wscript_shell.Exec(command);
+ while (oShell.Status === 0) {
+ //Wait a little bit so we're not super looping
+ WScript.sleep(100);
+ //Print any stdout output from the script
+ if(!oShell.StdOut.AtEndOfStream) {
+ var line = oShell.StdOut.ReadLine();
+ Log(line);
+ }
+ }
+ //Check to make sure our scripts did not encounter an error
+ if(!oShell.StdErr.AtEndOfStream)
+ {
+ var err_line = oShell.StdErr.ReadAll();
+ WScript.StdErr.WriteLine(err_line);
+ WScript.Quit(1);
+ }
+}
+
+function build_js(path)
+{
+ if(fso.FolderExists(path + '\\temp'))
+ {
+ fso.DeleteFolder(path + '\\temp', true);
+ }
+ fso.CreateFolder(path + '\\temp');
+ wscript_shell.CurrentDirectory = path + '\\temp';
+
+ Log('\tCloning js tagged with ' + VERSION + '...');
+ exec('%comspec% /c git clone ' + CORDOVA_JS + ' && cd cordova-js && git fetch && git checkout ' + VERSION );
+ if(!fso.FolderExists(path + '\\temp\\cordova-js'))
+ {
+ WScript.StdErr.WriteLine("ERROR: Failed to clone cordova-js. Aborting...");
+ WScript.Quit(1);
+ }
+ wscript_shell.CurrentDirectory = path + '\\temp\\cordova-js';
+ Log("Building Cordova.js...");
+
+ exec_verbose('%comspec% /c jake build');
+ if(!fso.FolderExists(path + '\\temp\\cordova-js\\pkg'))
+ {
+ WScript.StdErr.WriteLine("ERROR: Failed to build cordova-js. Aborting...");
+ WScript.Quit(1);
+ }
+
+ //copy the javascript wherever it needs to go.
+ wscript_shell.CurrentDirectory = path + '\\temp\\cordova-js\\pkg';
+ exec('%comspec% /c copy /Y cordova.windowsphone.js ' + path + STANDALONE_PATH + '\\www\\cordova-' + VERSION + '.js');
+ exec('%comspec% /c copy /Y cordova.windowsphone.js ' + path + EXAMPLE_PATH + '\\www\\cordova-' + VERSION + '.js');
+
+ //TODO: Delete old cordova.js (done in reversion.js)
+
+ Log("SUCESS");
+}
+
+function set_path(some_arg)
+{
+ if(some_arg.indexOf('-p:')!= -1)
+ {
+ var path = some_arg.split('-p:')[1];
+ if(fso.FolderExists(path) && fso.FolderExists(path + '\\tooling'))
+ {
+ BUILD_DESTINATION = path;
+ return true;
+ }
+ else
+ {
+ Log("ERROR: The given path is not a cordova-wp7 repo, or");
+ Log(" does not exist. If your trying to reversion a");
+ Log(" cordova repo other then this one, please provide");
+ Log(" it's path in the form: -p:C:\\Path\\to\\repo");
+ WScript.Quit(1);
+ }
+
+ }
+ return false;
+}
+
+Log("");
+
+if(args.Count() > 1)
+{
+ set_path(args(1));
+}
+
+if(args.Count() > 0)
+{
+ //Support help flags
+ if(args(0).indexOf("--help") > -1 ||
+ args(0).indexOf("/?") > -1 )
+ {
+ Usage();
+ WScript.Quit(1);
+ }
+
+ if(args(0).match(/(\d+)[.](\d+)[.](\d+)(rc\d)?/))
+ {
+ VERSION = args(0);
+ if(args.Count() == 1)
+ {
+ BUILD_DESTINATION = ROOT;
+ }
+ }
+ else if(set_path(arg(0))) {} //do nothing
+ else
+ {
+ Log("The provided version number is invalid, please provide");
+ Log(" a version number in the format Major.Minor.Fix[rc#]");
+ Usage();
+ WScript.Quit(1);
+ }
+}
+else
+{
+ BUILD_DESTINATION = ROOT;
+}
+
+//If we haven't quit by here, build the damn javascript!
+Log("Creating js for " + BUILD_DESTINATION);
+build_js(BUILD_DESTINATION);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/tooling/scripts/dist.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/tooling/scripts/dist.bat b/lib/cordova-wp7/tooling/scripts/dist.bat
new file mode 100644
index 0000000..a1c0e1d
--- /dev/null
+++ b/lib/cordova-wp7/tooling/scripts/dist.bat
@@ -0,0 +1,2 @@
+@echo off
+cscript "%~dp0\dist.js" %* //nologo
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/tooling/scripts/dist.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/tooling/scripts/dist.js b/lib/cordova-wp7/tooling/scripts/dist.js
new file mode 100644
index 0000000..4303202
--- /dev/null
+++ b/lib/cordova-wp7/tooling/scripts/dist.js
@@ -0,0 +1,217 @@
+/*
+ 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.
+*/
+
+
+/*************************************************/
+/**************** REQUIREMENTS *****************/
+/*************************************************/
+/*
+Paths:
+ - path to git.exe -> C:\msysgit\bin
+ - path to msbuild -> C:\Windows\Microsoft.NET\Framework\v4.0.30319
+Famework
+ - .NET 4.0
+ - Windows phone SDKs
+
+
+/************ Globals ********/
+
+var fso = WScript.CreateObject('Scripting.FileSystemObject'),
+ wscript_shell = WScript.CreateObject("WScript.Shell");
+
+//Set up directory structure of current release
+ //arguments passed in
+var args = WScript.Arguments,
+ //Root folder of cordova-wp7 (i.e C:\Cordova\cordova-wp7)
+ ROOT = WScript.ScriptFullName.split('\\tooling\\', 1),
+ // tooling scripts
+ SCRIPTS = '\\tooling\\scripts';
+ //Get version number
+ VERSION=read(ROOT+'\\VERSION').replace(/\r\n/,'').replace(/\n/,'');
+
+//Destination to build to
+var BUILD_DESTINATION;
+//current script that is running
+var current_script = "dist";
+// replace the directory
+var replace = false;
+
+
+/*************************************************/
+/**************** FUNCTIONS ********************/
+/*************************************************/
+
+
+// help function
+function Usage() {
+ Log("");
+ Log("This is a command line tool for building new releases. It will package a new release");
+ Log(" of a cordova-wp7 project, reversioning it to match the VERSION file in the root directory.");
+ Log("Usage: dist [ <NEW_PATH_FOR_BUILD> | -f ] ");
+ Log(" -f : force tool to reversion the current repositoy.");
+ Log(" <NEW_PATH_FOR_BUILD> : path to create the new reversioned repositoy in.");
+ Log("");
+}
+
+// logs messaged to stdout and stderr
+function Log(msg, error) {
+ if (error) {
+ WScript.StdErr.WriteLine(msg);
+ }
+ else {
+ WScript.StdOut.WriteLine(msg);
+ }
+}
+
+// returns the contents of a file
+function read(filename) {
+ //Log('Reading in ' + filename);
+ if(fso.FileExists(filename)) {
+ var f=fso.OpenTextFile(filename, 1,2);
+ var s=f.ReadAll();
+ f.Close();
+ return s;
+ }
+ else {
+ Log('Cannot read non-existant file : ' + filename, true);
+ WScript.Quit(1);
+ }
+ return null;
+}
+
+// executes a commmand in the shell
+function exec(command) {
+ Log("Command: " + command);
+ var oShell=wscript_shell.Exec(command);
+ while (oShell.Status === 0) {
+ //Wait a little bit so we're not super looping
+ WScript.sleep(100);
+ //Print any stdout output from the script
+ if(!oShell.StdOut.AtEndOfStream) {
+ var line = oShell.StdOut.ReadLine();
+ Log(line);
+ }
+ }
+ //Check to make sure our scripts did not encounter an error
+ if(!oShell.StdErr.AtEndOfStream) {
+ var err_line = oShell.StdErr.ReadAll();
+ Log(err_line, true);
+ Log("ERROR: Could not complete distribution, failed while running: " + current_script, true);
+ WScript.Quit(1);
+ }
+}
+
+function space() {
+ Log("");
+ Log("*****************************************************");
+ Log("");
+}
+
+
+/*************************************************/
+/************** MAIN SCRIPT ********************/
+/*************************************************/
+
+if (args.Count() > 0) {
+ if (args.Count() == 1) {
+ // support help flags
+ if (args(0).indexOf("--help") > -1 ||
+ args(0).indexOf("/?") > -1 ) {
+ Usage();
+ WScript.Quit(1);
+ }
+ else if (args(0) == '-f') {
+ BUILD_DESTINATION = ROOT;
+ replace = true;
+ }
+ else {
+ BUILD_DESTINATION = args(0);
+ }
+
+ }
+ else if (args.Count() == 2) {
+ if (args(0) == '-f') {
+ replace = true;
+ BUILD_DESTINATION = args(1);
+ } else {
+ BUILD_DESTINATION = args(0);
+ if (args(1) == '-f') {
+ replace = true;
+ }
+ else {
+ Log('WARNING : "' + args(1) + '" is not regognized, attempting to continue distribution.');
+ }
+ }
+ }
+ else {
+ Log("Error : too many arguments provided.", true);
+ WScript.Quit(1);
+ }
+
+}
+else {
+ Usage();
+ WScript.Quit(1);
+}
+
+
+/*************************************************/
+/****************** Step 1 *********************/
+/*************************************************/
+/** - Copy source code to new directory **/
+/*************************************************/
+if (!replace) {
+ current_script = "new.js";
+ exec('cscript ' + ROOT + SCRIPTS + '\\new.js ' + BUILD_DESTINATION + ' //nologo');
+ space();
+}
+
+/*************************************************/
+/****************** Step 2 *********************/
+/*************************************************/
+/** - Retag everything with new version numbers **/
+/** - Delete any generated files and cordova.js **/
+/** - Rebuild dll **/
+/*************************************************/
+current_script = "reversion.js";
+exec('cscript ' + BUILD_DESTINATION + SCRIPTS + '\\reversion.js ' + VERSION + ' //nologo');
+space();
+
+/*************************************************/
+/****************** Step 3 *********************/
+/*************************************************/
+/** - Download tagged version of cordova.js **/
+/** - build cordova.js **/
+/** - windows.cordova.js -> templates + example **/
+/*************************************************/
+current_script = "buildjs.js";
+exec('cscript ' + BUILD_DESTINATION + SCRIPTS + '\\buildjs.js //nologo');
+space();
+
+/*************************************************/
+/****************** Step 5 *********************/
+/*************************************************/
+/** - Build templates **/
+/** - Zip templates **/
+/** - inject into Visual Studio **/
+/*************************************************/
+current_script = "package.js";
+exec('cscript ' + BUILD_DESTINATION + SCRIPTS + '\\package.js //nologo');
+space();
+Log("Distribution Complete.");
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/tooling/scripts/new.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/tooling/scripts/new.bat b/lib/cordova-wp7/tooling/scripts/new.bat
new file mode 100644
index 0000000..cb08e2e
--- /dev/null
+++ b/lib/cordova-wp7/tooling/scripts/new.bat
@@ -0,0 +1,2 @@
+@echo off
+cscript "%~dp0\new.js" %* //nologo
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/tooling/scripts/new.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/tooling/scripts/new.js b/lib/cordova-wp7/tooling/scripts/new.js
new file mode 100644
index 0000000..c17dc94
--- /dev/null
+++ b/lib/cordova-wp7/tooling/scripts/new.js
@@ -0,0 +1,151 @@
+/*
+ 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.
+*/
+
+var fso = WScript.CreateObject('Scripting.FileSystemObject'),
+ shell = WScript.CreateObject("shell.application"),
+ wscript_shell = WScript.CreateObject("WScript.Shell");
+
+var args = WScript.Arguments,
+ //Root folder of cordova-wp7 (i.e C:\Cordova\cordova-wp7)
+ ROOT = WScript.ScriptFullName.split('\\tooling\\', 1),
+ //Sub folder containing templates
+ TEMPLATES_PATH = '\\templates',
+ //Sub folder containing framework
+ FRAMEWORK_PATH = '\\framework',
+ //Subfolder containing example project
+ EXAMPLE_PATH = '\\example';
+// git repo for cordova-wp7
+var CORDOVA_WP7 = 'https://git-wip-us.apache.org/repos/asf/cordova-wp7.git';
+//Destination to build to
+var BUILD_DESTINATION;
+// pull the project down from github?
+var GET_NEW = false;
+
+// help function
+function Usage()
+{
+ WScript.StdOut.WriteLine("");
+ WScript.StdOut.WriteLine("Usage: new [ PathToDestinationFolder ]");
+ WScript.StdOut.WriteLine(" PathToDestinationFolder : Folder you wish to be created for a new cordova-wp7 repo");
+ WScript.StdOut.WriteLine("examples:");
+ WScript.StdOut.WriteLine(" new C:\\Users\\anonymous\\Desktop\\cordova-wp7");
+ WScript.StdOut.WriteLine("");
+}
+
+// returns the contents of a file
+function read(filename) {
+ //WScript.StdOut.WriteLine('Reading in ' + filename);
+ if(fso.FileExists(filename))
+ {
+ var f=fso.OpenTextFile(filename, 1,2);
+ var s=f.ReadAll();
+ f.Close();
+ return s;
+ }
+ else
+ {
+ WScript.StdErr.WriteLine('Cannot read non-existant file : ' + filename);
+ WScript.Quit(1);
+ }
+ return null;
+}
+
+// executes a commmand in the shell
+function exec(command) {
+ var oShell=wscript_shell.Exec(command);
+ while (oShell.Status === 0) {
+ WScript.sleep(100);
+ }
+}
+
+function copy_to(path)
+{
+ //Copy everything over to BUILD_DESTINATION
+ var dest = shell.NameSpace(path);
+ WScript.StdOut.WriteLine("Copying files to build directory...");
+
+ /** copy by file instead? (just what we need)**/
+ dest.CopyHere(ROOT + "\\bin", 4|20);
+ dest.CopyHere(ROOT + EXAMPLE_PATH, 4|20); //Should mostly be copied from standalone
+ dest.CopyHere(ROOT + FRAMEWORK_PATH, 4|20);
+ dest.CopyHere(ROOT + TEMPLATES_PATH, 4|20);
+ dest.CopyHere(ROOT + "\\tests", 4|20);
+ dest.CopyHere(ROOT + "\\tooling", 4|20);
+ dest.CopyHere(ROOT + "\\.gitignore", 4|20);
+ dest.CopyHere(ROOT + "\\LICENSE", 4|20);
+ dest.CopyHere(ROOT + "\\NOTICE", 4|20);
+ dest.CopyHere(ROOT + "\\README.md", 4|20);
+ dest.CopyHere(ROOT + "\\VERSION", 4|20);
+}
+
+WScript.StdOut.WriteLine("");
+
+if(args.Count() > 0)
+{
+ if(fso.FolderExists(args(0)))
+ {
+ WScript.StdErr.WriteLine("The given directory already exists!");
+ Usage();
+ WScript.Quit(1);
+ }
+ else
+ {
+ BUILD_DESTINATION = args(0);
+
+ }
+
+ if(!GET_NEW) {
+
+ if(fso.FolderExists(BUILD_DESTINATION))
+ {
+ WScript.StdErr.WriteLine("The given directory already exists!");
+ Usage();
+ WScript.Quit(1);
+ }
+ else
+ {
+ BUILD_DESTINATION = args(0);
+ }
+
+ // set up file structure
+ fso.CreateFolder(BUILD_DESTINATION);
+ // copy nessisary files
+ copy_to(BUILD_DESTINATION);
+ }
+ else
+ {
+ wscript_shell.CurrentDirectory = arg(0) + '\\..';
+ BUILD_DESTINATION = wscript_shell.CurrentDirectory + '\\cordova-wp7';
+
+ WScript.StdOut.WriteLine('Cloning cordova-wp7 from git, build destination now ' + BUILD_DESTINATION);
+ if(fso.FolderExists(BUILD_DESTINATION))
+ {
+ WScript.StdErr.WriteLine("Could not clone cordova-wp7 from git because it's directory already exists!");
+ WScript.Quit(1);
+ }
+
+ exec('git clone ' + CORDOVA_WP7); //git fetch --tags && git checkout?
+
+ }
+}
+else
+{
+ Usage();
+ WScript.Quit(1);
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/tooling/scripts/package.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/tooling/scripts/package.bat b/lib/cordova-wp7/tooling/scripts/package.bat
new file mode 100644
index 0000000..c00551e
--- /dev/null
+++ b/lib/cordova-wp7/tooling/scripts/package.bat
@@ -0,0 +1,2 @@
+@echo off
+cscript "%~dp0\package.js" %* //nologo
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/tooling/scripts/package.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/tooling/scripts/package.js b/lib/cordova-wp7/tooling/scripts/package.js
new file mode 100644
index 0000000..f3970a8
--- /dev/null
+++ b/lib/cordova-wp7/tooling/scripts/package.js
@@ -0,0 +1,213 @@
+/*
+ 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.
+*/
+
+var fso = WScript.CreateObject('Scripting.FileSystemObject'),
+ shell = WScript.CreateObject("shell.application"),
+ wscript_shell = WScript.CreateObject("WScript.Shell");
+
+var args = WScript.Arguments,
+ // root folder of cordova-wp7 (i.e C:\Cordova\cordova-wp7)
+ ROOT = WScript.ScriptFullName.split('\\tooling\\', 1),
+ // sub folder containing templates
+ TEMPLATES_PATH = '\\templates',
+ // sub folder for standalone project
+ STANDALONE_PATH = TEMPLATES_PATH + '\\standalone',
+ // sub folder containing framework
+ FRAMEWORK_PATH = '\\framework',
+ // subfolder containing example project
+ EXAMPLE_PATH = '\\example',
+ // get version number
+ VERSION=read(ROOT+'\\VERSION').replace(/\r\n/,'').replace(/\n/,''),
+ BASE_VERSION = VERSION.split('rc', 1) + ".0";
+
+// destination directory to package
+var BUILD_DESTINATION;
+// add templates to visual studio?
+var ADD_TO_VS = false;
+// build the dll?
+var BUILD_DLL = false;
+
+function Log(msg) { WScript.StdOut.WriteLine(msg); }
+
+// help function
+function Usage()
+{
+ Log("");
+ Log("Usage: package [ PathToCordovaWP7 ]");
+ Log(" PathToCordovaWP7 : Cordova-wp7 repo you wish to package for release");
+ Log("examples:");
+ Log(" package C:\\Users\\anonymous\\Desktop\\cordova-wp7");
+ Log(" package // packages current cordova directory");
+ Log("");
+}
+
+// returns the contents of a file
+function read(filename) {
+ //Log('Reading in ' + filename);
+ if(fso.FileExists(filename))
+ {
+ var f=fso.OpenTextFile(filename, 1,2);
+ var s=f.ReadAll();
+ f.Close();
+ return s;
+ }
+ else
+ {
+ Log('ERROR: Cannot read non-existant file : ' + filename);
+ WScript.Quit(1);
+ }
+ return null;
+}
+
+// executes a commmand in the shell
+function exec(command) {
+ var oShell=wscript_shell.Exec(command);
+ while (oShell.Status === 0) {
+ WScript.sleep(100);
+ }
+}
+
+// executes a commmand in the shell
+function exec_verbose(command) {
+ Log("Command: " + command);
+ var oShell=wscript_shell.Exec(command);
+ while (oShell.Status === 0) {
+ //Wait a little bit so we're not super looping
+ WScript.sleep(100);
+ //Print any stdout output from the script
+ if(!oShell.StdOut.AtEndOfStream) {
+ var line = oShell.StdOut.ReadLine();
+ Log(line);
+ }
+ }
+ //Check to make sure our scripts did not encounter an error
+ if(!oShell.StdErr.AtEndOfStream)
+ {
+ var err_line = oShell.StdErr.ReadAll();
+ WScript.StdErr.WriteLine(err_line);
+ WScript.Quit(1);
+ }
+}
+
+// packages templates into .zip
+function package_templates()
+{
+ Log("Creating template .zip files ...");
+
+ var template_path = BUILD_DESTINATION + '\\CordovaWP7_' + VERSION.replace(/\./g, '_') + '.zip';
+ if(fso.FileExists(template_path))
+ {
+ fso.DeleteFile(template_path);
+ }
+
+ exec('%comspec% /c copy /Y ' + BUILD_DESTINATION + TEMPLATES_PATH + '\\vs\\MyTemplateStandAlone.vstemplate ' + BUILD_DESTINATION + STANDALONE_PATH + '\\MyTemplate.vstemplate');
+ exec('%comspec% /c copy /Y ' + BUILD_DESTINATION + TEMPLATES_PATH + '\\vs\\pg_templateIcon.png ' + BUILD_DESTINATION + STANDALONE_PATH + '\\__TemplateIcon.png');
+ exec('%comspec% /c copy /Y ' + BUILD_DESTINATION + TEMPLATES_PATH + '\\vs\\pg_templatePreview.jpg ' + BUILD_DESTINATION + STANDALONE_PATH + '\\__PreviewImage.jpg');
+ exec('%comspec% /c copy /Y ' + BUILD_DESTINATION + '\\VERSION ' + BUILD_DESTINATION + STANDALONE_PATH);
+
+ exec_verbose('cscript ' + BUILD_DESTINATION + '\\tooling\\scripts\\win-zip.js ' + template_path + ' ' + BUILD_DESTINATION + STANDALONE_PATH + '\\ //nologo');
+
+
+ if(ADD_TO_VS)
+ {
+ var template_dir = wscript_shell.ExpandEnvironmentStrings("%USERPROFILE%") + '\\Documents\\Visual Studio 2012\\Templates\\ProjectTemplates';
+ if(fso.FolderExists(template_dir ))
+ {
+ dest = shell.NameSpace(template_dir);
+ dest.CopyHere(template_path, 4|20);
+ }
+ else
+ {
+ Log("WARNING: Could not find template directory in Visual Studio,\n you can manually copy over the template .zip files.");
+ }
+ }
+}
+
+// builds the new cordova dll and copys it to the full template (only done because of the version referance in Device.cs)
+function build_dll()
+{
+ Log("Packaging .dll ...");
+ // move to framework directory
+ wscript_shell.CurrentDirectory = BUILD_DESTINATION + FRAMEWORK_PATH;
+ // build .dll in Release
+ exec_verbose('msbuild /p:Configuration=Release;VersionNumber=' + VERSION + ';BaseVersionNumber=' + BASE_VERSION);
+ //Check if file dll was created
+ if(!fso.FileExists(BUILD_DESTINATION + FRAMEWORK_PATH + '\\Bin\\Release\\WPCordovaClassLib.dll'))
+ {
+ WScript.StdErr.WriteLine('ERROR: MSBuild failed to create .dll.');
+ WScript.Quit(1);
+ }
+
+ Log("SUCESS");
+}
+
+// delete any unnessisary files when finished
+function cleanUp() {
+
+ if(fso.FileExists(BUILD_DESTINATION + STANDALONE_PATH + '\\MyTemplate.vstemplate')) {
+ fso.DeleteFile(BUILD_DESTINATION + STANDALONE_PATH + '\\MyTemplate.vstemplate');
+ }
+ if(fso.FileExists(BUILD_DESTINATION + STANDALONE_PATH + '\\__PreviewImage.jpg')) {
+ fso.DeleteFile(BUILD_DESTINATION + STANDALONE_PATH + '\\__PreviewImage.jpg');
+ }
+ if(fso.FileExists(BUILD_DESTINATION + STANDALONE_PATH + '\\__TemplateIcon.png')) {
+ fso.DeleteFile(BUILD_DESTINATION + STANDALONE_PATH + '\\__TemplateIcon.png');
+ }
+ //Add any other cleanup here
+}
+
+
+Log("");
+
+if(args.Count() > 0)
+{
+ //Support help flags
+ if(args(0).indexOf("--help") > -1 ||
+ args(0).indexOf("/?") > -1 )
+ {
+ Usage();
+ WScript.Quit(1);
+ }
+
+ if(fso.FolderExists(args(0)) && fso.FolderExists(args(0) + '\\tooling'))
+ {
+ BUILD_DESTINATION = args(0);
+ }
+ else
+ {
+ Log("ERROR: The given directory is not a cordova-wp7 repo.");
+ Usage();
+ WScript.Quit(1);
+
+ }
+}
+else
+{
+ BUILD_DESTINATION = ROOT;
+}
+
+// build dll for full template
+if (BUILD_DLL) {
+ build_dll();
+}
+
+// build/package the templates
+package_templates(BUILD_DESTINATION);
+
+cleanUp();
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/tooling/scripts/reversion.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/tooling/scripts/reversion.bat b/lib/cordova-wp7/tooling/scripts/reversion.bat
new file mode 100644
index 0000000..b35ab08
--- /dev/null
+++ b/lib/cordova-wp7/tooling/scripts/reversion.bat
@@ -0,0 +1,2 @@
+@echo off
+cscript "%~dp0\reversion.js" %* //nologo
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/tooling/scripts/reversion.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/tooling/scripts/reversion.js b/lib/cordova-wp7/tooling/scripts/reversion.js
new file mode 100644
index 0000000..3b42fc4
--- /dev/null
+++ b/lib/cordova-wp7/tooling/scripts/reversion.js
@@ -0,0 +1,277 @@
+/*
+ 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.
+*/
+
+
+/************ Globals ********/
+
+var fso = WScript.CreateObject('Scripting.FileSystemObject'),
+ shell = WScript.CreateObject("shell.application"),
+ wscript_shell = WScript.CreateObject("WScript.Shell");
+
+//Set up directory structure of current release
+ //arguments passed in
+var args = WScript.Arguments,
+ //Root folder of cordova-wp7 (i.e C:\Cordova\cordova-wp7)
+ ROOT = WScript.ScriptFullName.split('\\tooling\\', 1),
+ //Sub folder containing templates
+ TEMPLATES_PATH = '\\templates',
+ //Sub folder for standalone project
+ STANDALONE_PATH = TEMPLATES_PATH + '\\standalone',
+ //Sub folder containing framework
+ FRAMEWORK_PATH = '\\framework',
+ //Subfolder containing example project
+ EXAMPLE_PATH = '\\example',
+ //Path to cordovalib folder, containing source for .dll
+ CORDOVA_LIB = STANDALONE_PATH + '\\cordovalib',
+ //Get version number
+ VERSION='',
+ BASE_VERSION = '';
+
+//Destination to build to
+var BUILD_DESTINATION;
+
+// help function
+function Usage()
+{
+ WScript.StdOut.WriteLine("");
+ WScript.StdOut.WriteLine("Usage: reversion [ Version PathTOCordovaWP7 ]");
+ WScript.StdOut.WriteLine(" Version : The new version for codova-wp7");
+ WScript.StdOut.WriteLine(" PathTOCordovaWP7 : The path to the cordova directory being reversioned.");
+ WScript.StdOut.WriteLine("examples:");
+ WScript.StdOut.WriteLine(" reversion 2.5.0rc1 //Reversions the current working directory");
+ WScript.StdOut.WriteLine(" reversion 2.5.0 C :\\Users\\anonymous\\Desktop\\cordova-wp7");
+ WScript.StdOut.WriteLine("");
+}
+
+var ForReading = 1, ForWriting = 2, ForAppending = 8;
+var TristateUseDefault = -2, TristateTrue = -1, TristateFalse = 0;
+
+// returns the contents of a file
+function read(filename) {
+ //WScript.Echo('Reading in ' + filename);
+ if(fso.FileExists(filename))
+ {
+ var f=fso.OpenTextFile(filename, 1,2);
+ var s=f.ReadAll();
+ f.Close();
+ return s;
+ }
+ else
+ {
+ WScript.StdErr.WriteLine('Cannot read non-existant file : ' + filename);
+ WScript.Quit(1);
+ }
+ return null;
+}
+
+// writes the contents to the specified file
+function write(filename, contents) {
+ var f=fso.OpenTextFile(filename, ForWriting, TristateTrue);
+ f.Write(contents);
+ f.Close();
+}
+
+// replaces the matches of regexp with replacement
+function replaceInFile(filename, regexp, replacement) {
+ //WScript.Echo("Replaceing with "+replacement+ " in:");
+ var text = read(filename).replace(regexp,replacement);
+ //WScript.Echo(text);
+ write(filename,text);
+}
+
+// executes a commmand in the shell
+function exec(command) {
+ var oShell=wscript_shell.Exec(command);
+ while (oShell.Status === 0) {
+ WScript.sleep(100);
+ }
+}
+
+// executes a commmand in the shell
+function exec_verbose(command) {
+ //WScript.StdOut.WriteLine("Command: " + command);
+ var oShell=wscript_shell.Exec(command);
+ while (oShell.Status === 0) {
+ //Wait a little bit so we're not super looping
+ WScript.sleep(100);
+ //Print any stdout output from the script
+ if(!oShell.StdOut.AtEndOfStream) {
+ var line = oShell.StdOut.ReadLine();
+ WScript.StdOut.WriteLine(line);
+ }
+ }
+ //Check to make sure our scripts did not encounter an error
+ if(!oShell.StdErr.AtEndOfStream)
+ {
+ var err_line = oShell.StdErr.ReadAll();
+ WScript.StdErr.WriteLine(err_line);
+ WScript.Quit(1);
+ }
+}
+
+function updateVersionNumbers() {
+ WScript.StdOut.WriteLine("Updating version numbers....");
+ var version_regex = /(\d+)[.](\d+)[.](\d+)(rc\d)?/;
+ replaceInFile(BUILD_DESTINATION + '\\VERSION', version_regex, VERSION);
+ // replace assembaly versions in framework
+ var framework_regex = /Description\(\"(\d+)[.](\d+)[.](\d+)(rc\d)?\"\)\]/; //Will match ("x.x.x[rcx]")]
+ replaceInFile(BUILD_DESTINATION + FRAMEWORK_PATH + "\\Properties\\AssemblyInfo.cs", framework_regex, "Description(\"" + VERSION + "\")]");
+ framework_regex = /Version\(\"(\d+)[.](\d+)[.](\d+)[.](\d+)\"\)\]/g;
+ replaceInFile(BUILD_DESTINATION + FRAMEWORK_PATH + "\\Properties\\AssemblyInfo.cs", framework_regex, "Version(\"" + BASE_VERSION + "\")]");
+
+ // update standalone project
+ exec('%comspec% /c copy /Y /V ' + BUILD_DESTINATION + "\\VERSION " + BUILD_DESTINATION + STANDALONE_PATH + "\\VERSION");
+ var cordova_regex = /cordova-(\d+)[.](\d+)[.](\d+)(rc\d)?/g; //Matches *first* cordova-x.x.x[rcx] (just ad g at end to make global)
+ replaceInFile(BUILD_DESTINATION + STANDALONE_PATH + '\\CordovaAppProj.csproj', cordova_regex, "cordova-" + VERSION);
+ replaceInFile(BUILD_DESTINATION + STANDALONE_PATH + '\\www\\index.html', cordova_regex, "cordova-" + VERSION);
+ version_regex = /return\s*\"(\d+)[.](\d+)[.](\d+)(rc\d)?/; //Matches return "x.x.x[rcx]
+
+ WScript.StdOut.WriteLine("path = " + BUILD_DESTINATION + CORDOVA_LIB + '\\Plugins\\Device.cs');
+ replaceInFile(BUILD_DESTINATION + CORDOVA_LIB + '\\..\\Plugins\\Device.cs', version_regex, "return \"" + VERSION);
+
+ // update example proj
+ replaceInFile(BUILD_DESTINATION + EXAMPLE_PATH + '\\CordovaExample.csproj', cordova_regex, "cordova-" + VERSION);
+ version_regex = /VERSION\s*\=\s*\'(\d+)[.](\d+)[.](\d+)(rc\d)?/; //Matches VERSION = x.x.x[rcx]
+ replaceInFile(BUILD_DESTINATION + EXAMPLE_PATH + '\\www\\cordova-current.js', version_regex, "VERSION = \'" + VERSION);
+
+ // update template discription
+ version_regex = /Cordova\s*(\d+)[.](\d+)[.](\d+)(rc\d)?\s*Windows/g; //Matches version: x.x.x[rcx]
+ replaceInFile(BUILD_DESTINATION + TEMPLATES_PATH + '\\vs\\description.txt', version_regex, "Cordova " + VERSION + " Windows");
+
+ // update .vstemplate files for the template zips.
+ var name_regex = /CordovaWP7[_](\d+)[_](\d+)[_](\d+)(rc\d)?/g;
+ var discript_regex = /Cordova\s*(\d+)[.](\d+)[.](\d+)(rc\d)?/;
+
+ replaceInFile(BUILD_DESTINATION + TEMPLATES_PATH + '\\vs\\MyTemplateStandAlone.vstemplate', name_regex, 'CordovaWP7_' + VERSION.replace(/\./g, '_'));
+ replaceInFile(BUILD_DESTINATION + TEMPLATES_PATH + '\\vs\\MyTemplateStandAlone.vstemplate', discript_regex, "Cordova " + VERSION);
+ replaceInFile(BUILD_DESTINATION + TEMPLATES_PATH + '\\vs\\MyTemplateStandAlone.vstemplate', cordova_regex, "cordova-" + VERSION);
+}
+
+// delete all cordova.js and generated files (templates) from old version numbers
+function cleanup()
+{
+ WScript.StdOut.WriteLine("Cleanup");
+ // remove old template .zip files
+ if(fso.FileExists(BUILD_DESTINATION + '\\*.zip'))
+ {
+ fso.DeleteFile(BUILD_DESTINATION + '\\*.zip');
+ }
+ // remove any generated framework files
+ if(fso.FolderExists(BUILD_DESTINATION + FRAMEWORK_PATH + '\\Bin'))
+ {
+ fso.DeleteFolder(BUILD_DESTINATION + FRAMEWORK_PATH + '\\Bin');
+ }
+ if(fso.FolderExists(BUILD_DESTINATION + FRAMEWORK_PATH + '\\obj'))
+ {
+ fso.DeleteFolder(BUILD_DESTINATION + FRAMEWORK_PATH + '\\obj');
+ }
+ // remove any generated CordovaDeploy
+ if(fso.FolderExists(BUILD_DESTINATION + '\\tooling\\CordovaDeploy\\CordovaDeploy\\bin'))
+ {
+ fso.DeleteFolder(BUILD_DESTINATION + '\\tooling\\CordovaDeploy\\CordovaDeploy\\bin');
+ }
+ if(fso.FolderExists(BUILD_DESTINATION + '\\tooling\\CordovaDeploy\\CordovaDeploy\\obj'))
+ {
+ fso.DeleteFolder(BUILD_DESTINATION + '\\tooling\\CordovaDeploy\\CordovaDeploy\\obj');
+ }
+ //remove old template .zip files
+ WScript.Echo(BUILD_DESTINATION);
+ var root_folder = shell.NameSpace(BUILD_DESTINATION + '\\').Items();
+ for(var i = 0; i < root_folder.Count; i++)
+ {
+ if(root_folder.Item(i).Name.match(/CordovaWP7[_](\d+)[_](\d+)[_](\d+)(rc\d)?/))
+ {
+ fso.DeleteFile(BUILD_DESTINATION + '\\' + root_folder.Item(i).Name);
+ }
+ }
+ // remove old cordova.js
+ var example_www = shell.NameSpace(BUILD_DESTINATION + EXAMPLE_PATH + '\\www').Items();
+ for(i = 0; i < example_www.Count; i++)
+ {
+ if(example_www.Item(i).Name.match(/cordova\-(\d+)[.](\d+)[.](\d+)(rc\d)?[.]js/))
+ {
+ fso.DeleteFile(BUILD_DESTINATION + EXAMPLE_PATH + '\\www\\' + example_www.Item(i).Name);
+ }
+ }
+
+ var standalone_www = shell.NameSpace(BUILD_DESTINATION + STANDALONE_PATH + '\\www').Items();
+ for(i = 0; i < standalone_www.Count; i++)
+ {
+ if(standalone_www.Item(i).Name.match(/cordova\-(\d+)[.](\d+)[.](\d+)(rc\d)?[.]js/))
+ {
+ fso.DeleteFile(BUILD_DESTINATION + STANDALONE_PATH + '\\www\\' + standalone_www.Item(i).Name);
+ }
+ }
+}
+
+
+WScript.StdOut.WriteLine("");
+
+if(args.Count() > 1)
+{
+ if(fso.FolderExists(args(1)) && fso.FolderExists(args(1) + '\\tooling'))
+ {
+ BUILD_DESTINATION = args(1);
+ }
+ else
+ {
+ WScript.StdErr.WriteLine("The given path is not a cordova-wp7 repo, if");
+ WScript.StdErr.WriteLine(" your trying to reversion a cordova-wp7 repo");
+ WScript.StdErr.WriteLine(" other then this one, please provide its path.");
+ Usage();
+ WScript.Quit(1);
+ }
+}
+
+if(args.Count() > 0)
+{
+ //Support help flags
+ if(args(0).indexOf("--help") > -1 ||
+ args(0).indexOf("/?") > -1 )
+ {
+ Usage();
+ WScript.Quit(1);
+ }
+
+ if(args(0).match(/(\d+)[.](\d+)[.](\d+)(rc\d)?/))
+ {
+ VERSION = args(0);
+ BASE_VERSION = VERSION.split('rc', 1) + ".0";
+ if(args.Count() < 2)
+ {
+ BUILD_DESTINATION = ROOT;
+ }
+ // remove old cordova.js files and any generated files
+ cleanup();
+ // update version numbers
+ updateVersionNumbers();
+ }
+ else
+ {
+ WScript.StdOut.WriteLine("The version number is invalid, please provide");
+ WScript.StdOut.WriteLine(" a version number in the format Major.Minor.Fix[rc#]");
+ Usage();
+ WScript.Quit(1);
+ }
+}
+else
+{
+ Usage();
+ WScript.Quit(1);
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/tooling/scripts/win-zip.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/tooling/scripts/win-zip.js b/lib/cordova-wp7/tooling/scripts/win-zip.js
new file mode 100644
index 0000000..3d8dc1a
--- /dev/null
+++ b/lib/cordova-wp7/tooling/scripts/win-zip.js
@@ -0,0 +1,32 @@
+/*
+ * Script for zipping the contents of a directory.
+ */
+
+// get commman line arguments
+var objArgs = WScript.Arguments;
+var zipPath = objArgs(0);
+var sourcePath = objArgs(1);
+
+
+// create empty ZIP file and open for adding
+var fso = new ActiveXObject("Scripting.FileSystemObject");
+var file = fso.CreateTextFile(zipPath, true);
+
+// create twenty-two byte "fingerprint" for .zip
+file.write("PK");
+file.write(String.fromCharCode(5));
+file.write(String.fromCharCode(6));
+file.write('\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0');
+file.Close();
+
+// open .zip foder and copy contents of sourcePath
+var objShell = new ActiveXObject("shell.application");
+var zipFolder = objShell.NameSpace(zipPath);
+var sourceItems = objShell.NameSpace(sourcePath).items();
+if (zipFolder !== null) {
+ zipFolder.CopyHere(sourceItems, 4|20|16);
+ WScript.Sleep(4000);
+}
+else {
+ WScript.StdErr.WriteLine('Failed to create .zip file.');
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/LICENSE
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/LICENSE b/lib/cordova-wp8/LICENSE
new file mode 100644
index 0000000..6a504ba
--- /dev/null
+++ b/lib/cordova-wp8/LICENSE
@@ -0,0 +1,12 @@
+
+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.
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/NOTICE
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/NOTICE b/lib/cordova-wp8/NOTICE
new file mode 100644
index 0000000..c38e7d7
--- /dev/null
+++ b/lib/cordova-wp8/NOTICE
@@ -0,0 +1,5 @@
+Apache Cordova
+Copyright 2012 The Apache Software Foundation
+
+This product includes software developed by
+The Apache Software Foundation (http://www.apache.org)
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/README.md
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/README.md b/lib/cordova-wp8/README.md
new file mode 100644
index 0000000..8d772b3
--- /dev/null
+++ b/lib/cordova-wp8/README.md
@@ -0,0 +1,42 @@
+Apache Cordova for Windows Phone 8
+===
+
+Apache Cordova WP8 is a .net application library that lets you create Apache Cordova applications targeting Windows Phone 8 devices.
+Apache Cordova based applications are, at the core, an application written with web technology: HTML, CSS and JavaScript.
+
+Requires
+---
+
+- Windows Phone SDK 8 [http://www.microsoft.com/en-us/download/details.aspx?id=35471]
+
+
+Getting Started
+---
+
+- copy the file templates/CordovaStarter-x.x.x.zip to the folder : \My Documents\Visual Studio 2012\Templates\ProjectTemplates\
+ - if you have just installed VisualStudio, you should launch it once to create this folder
+ - if you prefer, you may add the project instead to the "Silverlight for Windows Phone" subfolder of "Visual C#". This is up to you, and only affects where the project template is shown when creating a new project. Also, You may need to create this folder.
+- Launch Visual Studio 2012 and select to create a new project
+ - CordovaStarter should be listed as an option, give your new project a name
+ - Note: The description will let you know the version of Cordova you are targetting, if you have multiple templates.
+ - If you do not see it, you may have to select the top level 'Visual C#' to see it
+- Build and Run it!
+
+
+Known Problem Areas
+---
+
+Many of the Media APIs will not function as expected when debugging while connect to the device with the Zune software.
+To get around this, you need to use the Windows Phone Connect tool. For details, please check out this [MSDN blog article](http://blogs.msdn.com/b/jaimer/archive/2010/11/03/tips-for-debugging-wp7-media-apps-with-wpconnect.aspx).
+
+
+BUGS?
+-----
+File them at Apache Incubator
+https://issues.apache.org/jira/browse/CB
+
+Further Reading
+---
+
+- [http://docs.phonegap.com](http://docs.phonegap.com)
+- [http://wiki.phonegap.com](http://wiki.phonegap.com)
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/VERSION
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/VERSION b/lib/cordova-wp8/VERSION
new file mode 100644
index 0000000..9aa3464
--- /dev/null
+++ b/lib/cordova-wp8/VERSION
@@ -0,0 +1 @@
+2.7.0
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/framework/Images/appbar.back.rest.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/framework/Images/appbar.back.rest.png b/lib/cordova-wp8/framework/Images/appbar.back.rest.png
new file mode 100644
index 0000000..4bc2b92
Binary files /dev/null and b/lib/cordova-wp8/framework/Images/appbar.back.rest.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/framework/Images/appbar.close.rest.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/framework/Images/appbar.close.rest.png b/lib/cordova-wp8/framework/Images/appbar.close.rest.png
new file mode 100644
index 0000000..8166a1c
Binary files /dev/null and b/lib/cordova-wp8/framework/Images/appbar.close.rest.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/framework/Images/appbar.feature.video.rest.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/framework/Images/appbar.feature.video.rest.png b/lib/cordova-wp8/framework/Images/appbar.feature.video.rest.png
new file mode 100644
index 0000000..baff565
Binary files /dev/null and b/lib/cordova-wp8/framework/Images/appbar.feature.video.rest.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/framework/Images/appbar.next.rest.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/framework/Images/appbar.next.rest.png b/lib/cordova-wp8/framework/Images/appbar.next.rest.png
new file mode 100644
index 0000000..ed577d7
Binary files /dev/null and b/lib/cordova-wp8/framework/Images/appbar.next.rest.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/framework/Images/appbar.save.rest.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/framework/Images/appbar.save.rest.png b/lib/cordova-wp8/framework/Images/appbar.save.rest.png
new file mode 100644
index 0000000..d49940e
Binary files /dev/null and b/lib/cordova-wp8/framework/Images/appbar.save.rest.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/framework/Images/appbar.stop.rest.png
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/framework/Images/appbar.stop.rest.png b/lib/cordova-wp8/framework/Images/appbar.stop.rest.png
new file mode 100644
index 0000000..4dd724f
Binary files /dev/null and b/lib/cordova-wp8/framework/Images/appbar.stop.rest.png differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/framework/Properties/AssemblyInfo.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/framework/Properties/AssemblyInfo.cs b/lib/cordova-wp8/framework/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..4ed7003
--- /dev/null
+++ b/lib/cordova-wp8/framework/Properties/AssemblyInfo.cs
@@ -0,0 +1,35 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("WPCordovaClassLib")]
+[assembly: AssemblyDescription("2.7.0")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Apache Cordova")]
+[assembly: AssemblyProduct("WPCordovaClassLib")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("633ee7ad-9a75-4b68-96e9-281528c50275")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("2.7.0.0")]
+[assembly: AssemblyFileVersion("2.7.0.0")]
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/framework/WPCordovaClassLib.csproj
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/framework/WPCordovaClassLib.csproj b/lib/cordova-wp8/framework/WPCordovaClassLib.csproj
new file mode 100644
index 0000000..55da878
--- /dev/null
+++ b/lib/cordova-wp8/framework/WPCordovaClassLib.csproj
@@ -0,0 +1,313 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>10.0.20506</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{FC6A1A70-892D-46AD-9E4A-9793F72AF780}</ProjectGuid>
+ <ProjectTypeGuids>{C089C8C0-30E0-4E22-80C0-CE093F111A43};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>WPCordovaClassLib</RootNamespace>
+ <AssemblyName>WPCordovaClassLib</AssemblyName>
+ <AssemblyVersion>$(BaseVersionNumber)</AssemblyVersion>
+ <AssemblyFileVersion>$(BaseVersionNumber)</AssemblyFileVersion>
+ <AssemblyDescription>$(VersionNumber)</AssemblyDescription>
+ <TargetFrameworkVersion>v8.0</TargetFrameworkVersion>
+ <SilverlightVersion>
+ </SilverlightVersion>
+ <TargetFrameworkProfile>
+ </TargetFrameworkProfile>
+ <TargetFrameworkIdentifier>WindowsPhone</TargetFrameworkIdentifier>
+ <SilverlightApplication>false</SilverlightApplication>
+ <ValidateXaml>true</ValidateXaml>
+ <ThrowErrorsInValidation>true</ThrowErrorsInValidation>
+ <MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>Bin\Debug</OutputPath>
+ <DefineConstants>TRACE;DEBUG;SILVERLIGHT;WINDOWS_PHONE;CORDOVA_CLASSLIB</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <Prefer32Bit>false</Prefer32Bit>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>Bin\Release</OutputPath>
+ <DefineConstants>TRACE;DEBUG;SILVERLIGHT;WINDOWS_PHONE;CORDOVA_CLASSLIB</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <NoConfig>true</NoConfig>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <DocumentationFile>
+ </DocumentationFile>
+ <Prefer32Bit>false</Prefer32Bit>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
+ <DebugSymbols>true</DebugSymbols>
+ <OutputPath>Bin\x86\Debug</OutputPath>
+ <DefineConstants>DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <DebugType>full</DebugType>
+ <PlatformTarget>
+ </PlatformTarget>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+ <Prefer32Bit>false</Prefer32Bit>
+ <Optimize>false</Optimize>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
+ <OutputPath>Bin\x86\Release</OutputPath>
+ <DefineConstants>DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
+ <Optimize>true</Optimize>
+ <NoStdLib>true</NoStdLib>
+ <DebugType>pdbonly</DebugType>
+ <PlatformTarget>
+ </PlatformTarget>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+ <Prefer32Bit>false</Prefer32Bit>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
+ <DebugSymbols>true</DebugSymbols>
+ <OutputPath>Bin\ARM\Debug</OutputPath>
+ <DefineConstants>DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
+ <NoStdLib>true</NoStdLib>
+ <DebugType>full</DebugType>
+ <PlatformTarget>
+ </PlatformTarget>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+ <Prefer32Bit>false</Prefer32Bit>
+ <Optimize>false</Optimize>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
+ <OutputPath>Bin\ARM\Release</OutputPath>
+ <DefineConstants>DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
+ <Optimize>true</Optimize>
+ <NoStdLib>true</NoStdLib>
+ <DebugType>pdbonly</DebugType>
+ <PlatformTarget>
+ </PlatformTarget>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+ <Prefer32Bit>false</Prefer32Bit>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="..\templates\standalone\cordovalib\BrowserMouseHelper.cs">
+ <Link>CordovaLib\BrowserMouseHelper.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\cordovalib\CommandFactory.cs">
+ <Link>CordovaLib\CommandFactory.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\cordovalib\Commands\BaseCommand.cs">
+ <Link>CordovaLib\Commands\BaseCommand.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\cordovalib\ConfigHandler.cs">
+ <Link>CordovaLib\ConfigHandler.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\cordovalib\CordovaCommandCall.cs">
+ <Link>CordovaLib\CordovaCommandCall.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\cordovalib\CordovaView.xaml.cs">
+ <Link>CordovaLib\CordovaView.xaml.cs</Link>
+ <DependentUpon>CordovaView.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="..\templates\standalone\cordovalib\DOMStorageHelper.cs">
+ <Link>CordovaLib\DOMStorageHelper.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\cordovalib\JSON\JsonHelper.cs">
+ <Link>CordovaLib\JSON\JsonHelper.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\cordovalib\NativeExecution.cs">
+ <Link>CordovaLib\NativeExecution.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\cordovalib\OrientationHelper.cs">
+ <Link>CordovaLib\OrientationHelper.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\cordovalib\PluginResult.cs">
+ <Link>CordovaLib\PluginResult.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\cordovalib\ScriptCallback.cs">
+ <Link>CordovaLib\ScriptCallback.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\Accelerometer.cs">
+ <Link>CordovaLib\Plugins\Accelerometer.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\AudioFormatsHelper.cs">
+ <Link>CordovaLib\Plugins\AudioFormatsHelper.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\AudioPlayer.cs">
+ <Link>CordovaLib\Plugins\AudioPlayer.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\Battery.cs">
+ <Link>CordovaLib\Plugins\Battery.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\Camera.cs">
+ <Link>CordovaLib\Plugins\Camera.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\Capture.cs">
+ <Link>CordovaLib\Plugins\Capture.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\Compass.cs">
+ <Link>CordovaLib\Plugins\Compass.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\Contacts.cs">
+ <Link>CordovaLib\Plugins\Contacts.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\DebugConsole.cs">
+ <Link>CordovaLib\Plugins\DebugConsole.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\Device.cs">
+ <Link>CordovaLib\Plugins\Device.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\File.cs">
+ <Link>CordovaLib\Plugins\File.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\FileTransfer.cs">
+ <Link>CordovaLib\Plugins\FileTransfer.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\GeoLocation.cs">
+ <Link>CordovaLib\Plugins\GeoLocation.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\Globalization.cs">
+ <Link>CordovaLib\Plugins\Globalization.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\ImageExifHelper.cs">
+ <Link>CordovaLib\Plugins\ImageExifHelper.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\InAppBrowser.cs">
+ <Link>CordovaLib\Plugins\InAppBrowser.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\Media.cs">
+ <Link>CordovaLib\Plugins\Media.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\MimeTypeMapper.cs">
+ <Link>CordovaLib\Plugins\MimeTypeMapper.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\NetworkStatus.cs">
+ <Link>CordovaLib\Plugins\NetworkStatus.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\Notification.cs">
+ <Link>CordovaLib\Plugins\Notification.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\UI\AudioCaptureTask.cs">
+ <Link>CordovaLib\Plugins\UI\AudioCaptureTask.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\UI\AudioRecorder.xaml.cs">
+ <Link>CordovaLib\Plugins\UI\AudioRecorder.xaml.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\UI\ImageCapture.xaml.cs">
+ <Link>CordovaLib\Plugins\UI\ImageCapture.xaml.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\UI\NotificationBox.xaml.cs">
+ <Link>CordovaLib\Plugins\UI\NotificationBox.xaml.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\UI\VideoCaptureTask.cs">
+ <Link>CordovaLib\Plugins\UI\VideoCaptureTask.cs</Link>
+ </Compile>
+ <Compile Include="..\templates\standalone\Plugins\UI\VideoRecorder.xaml.cs">
+ <Link>CordovaLib\Plugins\UI\VideoRecorder.xaml.cs</Link>
+ </Compile>
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Content Include="..\templates\standalone\cordovalib\resources\notification-beep.wav">
+ <Link>CordovaLib\resources\notification-beep.wav</Link>
+ </Content>
+ <Content Include="Images\appbar.back.rest.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="Images\appbar.close.rest.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="Images\appbar.feature.video.rest.png">
+ <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+ </Content>
+ <Content Include="Images\appbar.next.rest.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="Images\appbar.stop.rest.png">
+ <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+ </Content>
+ <Content Include="Images\appbar.save.rest.png">
+ <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+ </Content>
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
+ </ItemGroup>
+ <ItemGroup>
+ <Resource Include="resources\notification-beep.wav" />
+ </ItemGroup>
+ <ItemGroup>
+ <Page Include="..\templates\standalone\cordovalib\CordovaView.xaml">
+ <Link>CordovaLib\CordovaView.xaml</Link>
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="..\templates\standalone\Plugins\UI\AudioRecorder.xaml">
+ <Link>CordovaLib\Plugins\UI\AudioRecorder.xaml</Link>
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="..\templates\standalone\Plugins\UI\ImageCapture.xaml">
+ <Link>CordovaLib\Plugins\UI\ImageCapture.xaml</Link>
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="..\templates\standalone\Plugins\UI\NotificationBox.xaml">
+ <Link>CordovaLib\Plugins\UI\NotificationBox.xaml</Link>
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="..\templates\standalone\Plugins\UI\VideoRecorder.xaml">
+ <Link>CordovaLib\Plugins\UI\VideoRecorder.xaml</Link>
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ </ItemGroup>
+ <Import Project="$(MSBuildExtensionsPath)\Microsoft\$(TargetFrameworkIdentifier)\$(TargetFrameworkVersion)\Microsoft.$(TargetFrameworkIdentifier).$(TargetFrameworkVersion).Overrides.targets" />
+ <Import Project="$(MSBuildExtensionsPath)\Microsoft\$(TargetFrameworkIdentifier)\$(TargetFrameworkVersion)\Microsoft.$(TargetFrameworkIdentifier).CSharp.targets" />
+ <ProjectExtensions />
+ <PropertyGroup>
+ <PreBuildEvent>
+ </PreBuildEvent>
+ </PropertyGroup>
+ <PropertyGroup>
+ <PostBuildEvent>
+ </PostBuildEvent>
+ </PropertyGroup>
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
\ No newline at end of file
[08/37] Add WP7 and WP8 platform files.
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/file.tests.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/file.tests.js b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/file.tests.js
new file mode 100644
index 0000000..06d8ec8
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/file.tests.js
@@ -0,0 +1,3462 @@
+describe('File API', function() {
+ // Adding a Jasmine helper matcher, to report errors when comparing to FileError better.
+ var fileErrorMap = {
+ 1: 'NOT_FOUND_ERR',
+ 2: 'SECURITY_ERR',
+ 3: 'ABORT_ERR',
+ 4: 'NOT_READABLE_ERR',
+ 5: 'ENCODING_ERR',
+ 6: 'NO_MODIFICATION_ALLOWED_ERR',
+ 7: 'INVALID_STATE_ERR',
+ 8: 'SYNTAX_ERR',
+ 9: 'INVALID_MODIFICATION_ERR',
+ 10:'QUOTA_EXCEEDED_ERR',
+ 11:'TYPE_MISMATCH_ERR',
+ 12:'PATH_EXISTS_ERR'
+ };
+ beforeEach(function() {
+ this.addMatchers({
+ toBeFileError: function(code) {
+ var error = this.actual;
+ this.message = function(){
+ return "Expected FileError with code " + fileErrorMap[error.code] + " (" + error.code + ") to be " + fileErrorMap[code] + "(" + code + ")";
+ };
+ return (error.code == code);
+ },
+ toCanonicallyMatch:function(path){
+ this.message = function(){
+ return "Expected paths to match : " + path + " should be " + this.actual;
+ };
+
+ var a = path.split("/").join("").split("\\").join("");
+ var b = this.actual.split("/").join("").split("\\").join("");
+
+ return a == b;
+ }
+ });
+ });
+
+ // HELPER FUNCTIONS
+
+ // deletes specified file or directory
+ var deleteEntry = function(name, success, error) {
+ // deletes entry, if it exists
+ window.resolveLocalFileSystemURI(root.toURL() + '/' + name,
+ function(entry) {
+ if (entry.isDirectory === true) {
+ entry.removeRecursively(success, error);
+ } else {
+ entry.remove(success, error);
+ }
+ }, success);
+ };
+ // deletes file, if it exists, then invokes callback
+ var deleteFile = function(fileName, callback) {
+ root.getFile(fileName, null,
+ // remove file system entry
+ function(entry) {
+ entry.remove(callback, function() { console.log('[ERROR] deleteFile cleanup method invoked fail callback.'); });
+ },
+ // doesn't exist
+ callback);
+ };
+ // deletes and re-creates the specified file
+ var createFile = function(fileName, success, error) {
+ deleteEntry(fileName, function() {
+ root.getFile(fileName, {create: true}, success, error);
+ }, error);
+ };
+ // deletes and re-creates the specified directory
+ var createDirectory = function(dirName, success, error) {
+ deleteEntry(dirName, function() {
+ root.getDirectory(dirName, {create: true}, success, error);
+ }, error);
+ };
+
+ var createFail = function(module) {
+ return jasmine.createSpy().andCallFake(function(err) {
+ console.log('[ERROR ' + module + '] ' + JSON.stringify(err));
+ });
+ };
+
+ var createWin = function(module) {
+ return jasmine.createSpy().andCallFake(function() {
+ console.log('[ERROR ' + module + '] Unexpected success callback');
+ });
+ };
+
+ describe('FileError object', function() {
+ it("should define FileError constants", function() {
+ expect(FileError.NOT_FOUND_ERR).toBe(1);
+ expect(FileError.SECURITY_ERR).toBe(2);
+ expect(FileError.ABORT_ERR).toBe(3);
+ expect(FileError.NOT_READABLE_ERR).toBe(4);
+ expect(FileError.ENCODING_ERR).toBe(5);
+ expect(FileError.NO_MODIFICATION_ALLOWED_ERR).toBe(6);
+ expect(FileError.INVALID_STATE_ERR).toBe(7);
+ expect(FileError.SYNTAX_ERR).toBe(8);
+ expect(FileError.INVALID_MODIFICATION_ERR).toBe(9);
+ expect(FileError.QUOTA_EXCEEDED_ERR).toBe(10);
+ expect(FileError.TYPE_MISMATCH_ERR).toBe(11);
+ expect(FileError.PATH_EXISTS_ERR).toBe(12);
+ });
+ });
+
+ describe('LocalFileSystem', function() {
+
+ it("should define LocalFileSystem constants", function() {
+ expect(LocalFileSystem.TEMPORARY).toBe(0);
+ expect(LocalFileSystem.PERSISTENT).toBe(1);
+ });
+
+ describe('window.requestFileSystem', function() {
+ it("should be defined", function() {
+ expect(window.requestFileSystem).toBeDefined();
+ });
+ it("should be able to retrieve a PERSISTENT file system", function() {
+ var win = jasmine.createSpy().andCallFake(function(fileSystem) {
+ expect(fileSystem).toBeDefined();
+ expect(fileSystem.name).toBeDefined();
+ expect(fileSystem.name).toBe("persistent");
+ expect(fileSystem.root).toBeDefined();
+ }),
+ fail = createFail('window.requestFileSystem');
+
+ // retrieve PERSISTENT file system
+ runs(function() {
+ window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, win, fail);
+ });
+
+ waitsFor(function() { return win.wasCalled; }, "success callback never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(fail).not.toHaveBeenCalled();
+ expect(win).toHaveBeenCalled();
+ });
+ });
+ it("should be able to retrieve a TEMPORARY file system", function() {
+ var win = jasmine.createSpy().andCallFake(function(fileSystem) {
+ expect(fileSystem).toBeDefined();
+ expect(fileSystem.name).toBeDefined();
+ expect(fileSystem.name).toBe("temporary");
+ expect(fileSystem.root).toBeDefined();
+ }),
+ fail = createFail('window.requestFileSystem');
+
+ // Request the file system
+ runs(function() {
+ window.requestFileSystem(LocalFileSystem.TEMPORARY, 0, win, fail);
+ });
+
+ waitsFor(function() { return win.wasCalled; }, "success callback never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(fail).not.toHaveBeenCalled();
+ expect(win).toHaveBeenCalled();
+ });
+ });
+ it("should error if you request a file system that is too large", function() {
+ var fail = jasmine.createSpy().andCallFake(function(error) {
+ expect(error).toBeDefined();
+ expect(error).toBeFileError(FileError.QUOTA_EXCEEDED_ERR);
+ }),
+ win = createWin('window.requestFileSystem');
+
+ // Request the file system
+ runs(function() {
+ window.requestFileSystem(LocalFileSystem.TEMPORARY, 1000000000000000, win, fail);
+ });
+
+ waitsFor(function() { return fail.wasCalled; }, "error callback never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(win).not.toHaveBeenCalled();
+ expect(fail).toHaveBeenCalled();
+ });
+ });
+ it("should error out if you request a file system that does not exist", function() {
+ var fail = jasmine.createSpy().andCallFake(function(error) {
+ expect(error).toBeDefined();
+ expect(error).toBeFileError(FileError.SYNTAX_ERR);
+ }),
+ win = createWin('window.requestFileSystem');
+
+ // Request the file system
+ runs(function() {
+ window.requestFileSystem(-1, 0, win, fail);
+ });
+
+ waitsFor(function() { return fail.wasCalled; }, "error callback never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(win).not.toHaveBeenCalled();
+ expect(fail).toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('window.resolveLocalFileSystemURI', function() {
+ it("should be defined", function() {
+ expect(window.resolveLocalFileSystemURI).toBeDefined();
+ });
+ it("should resolve a valid file name", function() {
+ var fileName = "resolve.file.uri",
+ win = jasmine.createSpy().andCallFake(function(fileEntry) {
+ expect(fileEntry).toBeDefined();
+ expect(fileEntry.name).toCanonicallyMatch(fileName);
+
+ // cleanup
+ deleteEntry(fileName);
+ }),
+ fail = createFail('window.resolveLocalFileSystemURI');
+ resolveCallback = jasmine.createSpy().andCallFake(function(entry) {
+ // lookup file system entry
+ runs(function() {
+ window.resolveLocalFileSystemURI(entry.toURL(), win, fail);
+ });
+
+ waitsFor(function() { return win.wasCalled; }, "resolveLocalFileSystemURI callback never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(win).toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+
+ // create a new file entry
+ runs(function() {
+ createFile(fileName, resolveCallback, fail);
+ });
+
+ waitsFor(function() { return resolveCallback.wasCalled; }, "createFile callback never called", Tests.TEST_TIMEOUT);
+ });
+ it("resolve valid file name with parameters", function() {
+ var fileName = "resolve.file.uri.params",
+ win = jasmine.createSpy().andCallFake(function(fileEntry) {
+ expect(fileEntry).toBeDefined();
+ expect(fileEntry.name).toBe(fileName);
+
+ // cleanup
+ deleteEntry(fileName);
+ }),
+ fail = createFail('window.resolveLocalFileSystemURI');
+ resolveCallback = jasmine.createSpy().andCallFake(function(entry) {
+ // lookup file system entry
+ runs(function() {
+ window.resolveLocalFileSystemURI(entry.toURL() + "?1234567890", win, fail);
+ });
+
+ waitsFor(function() { return win.wasCalled; }, "resolveLocalFileSystemURI callback never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(win).toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+
+ // create a new file entry
+ runs(function() {
+ createFile(fileName, resolveCallback, fail);
+ });
+
+ waitsFor(function() { return resolveCallback.wasCalled; }, "createFile callback never called", Tests.TEST_TIMEOUT);
+ });
+ it("should error (NOT_FOUND_ERR) when resolving (non-existent) invalid file name", function() {
+ var fail = jasmine.createSpy().andCallFake(function(error) {
+ expect(error).toBeDefined();
+ expect(error).toBeFileError(FileError.NOT_FOUND_ERR);
+ }),
+ win = createWin('window.resolveLocalFileSystemURI');
+
+ // lookup file system entry
+ runs(function() {
+ window.resolveLocalFileSystemURI("file:///this.is.not.a.valid.file.txt", win, fail);
+ });
+
+ waitsFor(function() { return fail.wasCalled; }, "error callback never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(fail).toHaveBeenCalled();
+ expect(win).not.toHaveBeenCalled();
+ });
+ });
+ it("should error (ENCODING_ERR) when resolving invalid URI with leading /", function() {
+ var fail = jasmine.createSpy().andCallFake(function(error) {
+ expect(error).toBeDefined();
+ expect(error).toBeFileError(FileError.ENCODING_ERR);
+ }),
+ win = createWin('window.resolveLocalFileSystemURI');
+
+ // lookup file system entry
+ runs(function() {
+ window.resolveLocalFileSystemURI("/this.is.not.a.valid.url", win, fail);
+ });
+
+ waitsFor(function() { return fail.wasCalled; }, "error callback never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(fail).toHaveBeenCalled();
+ expect(win).not.toHaveBeenCalled();
+ });
+ });
+ });
+ });
+
+ describe('Metadata interface', function() {
+ it("should exist and have the right properties", function() {
+ var metadata = new Metadata();
+ expect(metadata).toBeDefined();
+ expect(metadata.modificationTime).toBeDefined();
+ });
+ });
+
+ describe('Flags interface', function() {
+ it("should exist and have the right properties", function() {
+ var flags = new Flags(false, true);
+ expect(flags).toBeDefined();
+ expect(flags.create).toBeDefined();
+ expect(flags.create).toBe(false);
+ expect(flags.exclusive).toBeDefined();
+ expect(flags.exclusive).toBe(true);
+ });
+ });
+
+ describe('FileSystem interface', function() {
+ it("should have a root that is a DirectoryEntry", function() {
+ var win = jasmine.createSpy().andCallFake(function(entry) {
+ expect(entry).toBeDefined();
+ expect(entry.isFile).toBe(false);
+ expect(entry.isDirectory).toBe(true);
+ expect(entry.name).toBeDefined();
+ expect(entry.fullPath).toBeDefined();
+ expect(entry.getMetadata).toBeDefined();
+ expect(entry.moveTo).toBeDefined();
+ expect(entry.copyTo).toBeDefined();
+ expect(entry.toURL).toBeDefined();
+ expect(entry.remove).toBeDefined();
+ expect(entry.getParent).toBeDefined();
+ expect(entry.createReader).toBeDefined();
+ expect(entry.getFile).toBeDefined();
+ expect(entry.getDirectory).toBeDefined();
+ expect(entry.removeRecursively).toBeDefined();
+ }),
+ fail = createFail('FileSystem');
+
+ runs(function() {
+ window.resolveLocalFileSystemURI(root.toURL(), win, fail);
+ });
+
+ waitsFor(function() { return win.wasCalled; }, "success callback never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(fail).not.toHaveBeenCalled();
+ expect(win).toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('DirectoryEntry', function() {
+ it("getFile: get Entry for file that does not exist", function() {
+ var fileName = "de.no.file",
+ filePath = root.fullPath + '/' + fileName,
+ fail = jasmine.createSpy().andCallFake(function(error) {
+ expect(error).toBeDefined();
+ expect(error).toBeFileError(FileError.NOT_FOUND_ERR);
+ }),
+ win = createWin('DirectoryEntry');
+
+ // create:false, exclusive:false, file does not exist
+ runs(function() {
+ root.getFile(fileName, {create:false}, win, fail);
+ });
+
+ waitsFor(function() { return fail.wasCalled; }, "error callback never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(fail).toHaveBeenCalled();
+ expect(win).not.toHaveBeenCalled();
+ });
+ });
+ it("etFile: create new file", function() {
+ var fileName = "de.create.file",
+ filePath = root.fullPath + '/' + fileName,
+ win = jasmine.createSpy().andCallFake(function(entry) {
+ expect(entry).toBeDefined();
+ expect(entry.isFile).toBe(true);
+ expect(entry.isDirectory).toBe(false);
+ expect(entry.name).toCanonicallyMatch(fileName);
+ expect(entry.fullPath).toBe(filePath);
+ // cleanup
+ entry.remove(null, null);
+ }),
+ fail = createFail('DirectoryEntry');
+
+ // create:true, exclusive:false, file does not exist
+ runs(function() {
+ root.getFile(fileName, {create: true}, win, fail);
+ });
+
+ waitsFor(function() { return win.wasCalled; }, "success callback never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(win).toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ it("getFile: create new file (exclusive)", function() {
+ var fileName = "de.create.exclusive.file",
+ filePath = root.fullPath + '/' + fileName,
+ win = jasmine.createSpy().andCallFake(function(entry) {
+ expect(entry).toBeDefined();
+ expect(entry.isFile).toBe(true);
+ expect(entry.isDirectory).toBe(false);
+ expect(entry.name).toBe(fileName);
+ expect(entry.fullPath).toBe(filePath);
+
+ // cleanup
+ entry.remove(null, null);
+ }),
+ fail = createFail('DirectoryEntry');
+
+ // create:true, exclusive:true, file does not exist
+ runs(function() {
+ root.getFile(fileName, {create: true, exclusive:true}, win, fail);
+ });
+
+ waitsFor(function() { return win.wasCalled; }, "success callback never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(win).toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ it("getFile: create file that already exists", function() {
+ var fileName = "de.create.existing.file",
+ filePath = root.fullPath + '/' + fileName,
+ getFile = jasmine.createSpy().andCallFake(function(file) {
+ // create:true, exclusive:false, file exists
+ runs(function() {
+ root.getFile(fileName, {create:true}, win, fail);
+ });
+
+ waitsFor(function() { return win.wasCalled; }, "win was never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(win).toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ });
+ }),
+ fail = createFail('DirectoryEntry'),
+ win = jasmine.createSpy().andCallFake(function(entry) {
+ expect(entry).toBeDefined();
+ expect(entry.isFile).toBe(true);
+ expect(entry.isDirectory).toBe(false);
+ expect(entry.name).toCanonicallyMatch(fileName);
+ expect(entry.fullPath).toBe(filePath);
+
+ // cleanup
+ entry.remove(null, fail);
+ });
+ // create file to kick off it
+ runs(function() {
+ root.getFile(fileName, {create:true}, getFile, fail);
+ });
+
+ waitsFor(function() { return getFile.wasCalled; }, "getFile was never called", Tests.TEST_TIMEOUT);
+ });
+ it("getFile: create file that already exists (exclusive)", function() {
+ var fileName = "de.create.exclusive.existing.file",
+ filePath = root.fullPath + '/' + fileName,
+ existingFile,
+ getFile = jasmine.createSpy().andCallFake(function(file) {
+ existingFile = file;
+ // create:true, exclusive:true, file exists
+ runs(function() {
+ root.getFile(fileName, {create:true, exclusive:true}, win, fail);
+ });
+
+ waitsFor(function() { return fail.wasCalled; }, "fail never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(fail).toHaveBeenCalled();
+ expect(win).not.toHaveBeenCalled();
+ });
+ }),
+ fail = jasmine.createSpy().andCallFake(function(error) {
+ expect(error).toBeDefined();
+ expect(error).toBeFileError(FileError.PATH_EXISTS_ERR);
+
+ // cleanup
+ existingFile.remove(null, fail);
+ }),
+ win = createWin('DirectoryEntry');
+
+ // create file to kick off it
+ runs(function() {
+ root.getFile(fileName, {create:true}, getFile, fail);
+ });
+
+ waitsFor(function() { return getFile.wasCalled; }, "getFile never called", Tests.TEST_TIMEOUT);
+ });
+ it("getFile: get Entry for existing file", function() {
+ var fileName = "de.get.file",
+ filePath = root.fullPath + '/' + fileName,
+ win = jasmine.createSpy().andCallFake(function(entry) {
+ expect(entry).toBeDefined();
+ expect(entry.isFile).toBe(true);
+ expect(entry.isDirectory).toBe(false);
+ expect(entry.name).toCanonicallyMatch(fileName);
+ expect(entry.fullPath).toCanonicallyMatch(filePath);
+
+ entry.remove(null, fail); //clean up
+ }),
+ fail = createFail('DirectoryEntry'),
+ getFile = jasmine.createSpy().andCallFake(function(file) {
+ // create:false, exclusive:false, file exists
+ runs(function() {
+ root.getFile(fileName, {create:false}, win, fail);
+ });
+
+ waitsFor(function() { return win.wasCalled; }, "getFile success callback", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(win).toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+
+ // create file to kick off it
+ runs(function() {
+ root.getFile(fileName, {create:true}, getFile, fail);
+ });
+
+ waitsFor(function() { return getFile.wasCalled; }, "file creation", Tests.TEST_TIMEOUT);
+ });
+ it("DirectoryEntry.getFile: get FileEntry for invalid path", function() {
+ var fileName = "de:invalid:path",
+ fail = jasmine.createSpy().andCallFake(function(error) {
+ expect(error).toBeDefined();
+ expect(error).toBeFileError(FileError.ENCODING_ERR);
+ }),
+ win = createWin('DirectoryEntry');
+
+ // create:false, exclusive:false, invalid path
+ runs(function() {
+ root.getFile(fileName, {create:false}, win, fail);
+ });
+
+ waitsFor(function() { return fail.wasCalled; }, "fail never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(fail).toHaveBeenCalled();
+ expect(win).not.toHaveBeenCalled();
+ });
+
+ });
+ it("DirectoryEntry.getDirectory: get Entry for directory that does not exist", function() {
+ var dirName = "de.no.dir",
+ dirPath = root.fullPath + '/' + dirName,
+ fail = jasmine.createSpy().andCallFake(function(error) {
+ expect(error).toBeDefined();
+ expect(error).toBeFileError(FileError.NOT_FOUND_ERR);
+ }),
+ win = createWin('DirectoryEntry');
+
+ // create:false, exclusive:false, directory does not exist
+ runs(function() {
+ root.getDirectory(dirName, {create:false}, win, fail);
+ });
+
+ waitsFor(function() { return fail.wasCalled; }, "fail never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(fail).toHaveBeenCalled();
+ expect(win).not.toHaveBeenCalled();
+ });
+ });
+ it("DirectoryEntry.getDirectory: create new dir with space then resolveFileSystemURI", function() {
+ var dirName = "de create dir",
+ dirPath = root.fullPath + '/' + dirName,
+ getDir = jasmine.createSpy().andCallFake(function(dirEntry) {
+ var dirURI = dirEntry.toURL();
+ // now encode URI and try to resolve
+ runs(function() {
+ window.resolveLocalFileSystemURI(dirURI, win, fail);
+ });
+
+ waitsFor(function() { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(win).toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ });
+
+ }), win = jasmine.createSpy().andCallFake(function(directory) {
+ expect(directory).toBeDefined();
+ expect(directory.isFile).toBe(false);
+ expect(directory.isDirectory).toBe(true);
+ expect(directory.name).toCanonicallyMatch(dirName);
+ expect(directory.fullPath).toCanonicallyMatch(dirPath);
+
+ // cleanup
+ directory.remove(null, fail);
+ }),
+ fail = createFail('DirectoryEntry');
+
+ // create:true, exclusive:false, directory does not exist
+ runs(function() {
+ root.getDirectory(dirName, {create: true}, getDir, fail);
+ });
+
+ waitsFor(function() { return getDir.wasCalled; }, "getDir never called", Tests.TEST_TIMEOUT);
+ });
+ it("DirectoryEntry.getDirectory: create new dir with space resolveFileSystemURI with encoded URI", function() {
+ var dirName = "de create dir",
+ dirPath = root.fullPath + '/' + dirName,
+ getDir = jasmine.createSpy().andCallFake(function(dirEntry) {
+ var dirURI = dirEntry.toURL();
+ // now encode URI and try to resolve
+ runs(function() {
+ window.resolveLocalFileSystemURI(encodeURI(dirURI), win, fail);
+ });
+
+ waitsFor(function() { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(win).toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ });
+ }),
+ win = jasmine.createSpy().andCallFake(function(directory) {
+ expect(directory).toBeDefined();
+ expect(directory.isFile).toBe(false);
+ expect(directory.isDirectory).toBe(true);
+ expect(directory.name).toCanonicallyMatch(dirName);
+ expect(directory.fullPath).toCanonicallyMatch(dirPath);
+ // cleanup
+ directory.remove(null, fail);
+ }),
+ fail = createFail('DirectoryEntry');
+
+ // create:true, exclusive:false, directory does not exist
+ runs(function() {
+ root.getDirectory(dirName, {create: true}, getDir, fail);
+ });
+
+ waitsFor(function() { return getDir.wasCalled; }, "getDir never called", Tests.TEST_TIMEOUT);
+ });
+
+ it("DirectoryEntry.getDirectory: create new directory", function() {
+ var dirName = "de.create.dir",
+ dirPath = root.fullPath + '/' + dirName,
+ win = jasmine.createSpy().andCallFake(function(directory) {
+ expect(directory).toBeDefined();
+ expect(directory.isFile).toBe(false);
+ expect(directory.isDirectory).toBe(true);
+ expect(directory.name).toCanonicallyMatch(dirName);
+ expect(directory.fullPath).toCanonicallyMatch(dirPath);
+
+ // cleanup
+ directory.remove(null, fail);
+ }),
+ fail = createFail('DirectoryEntry');
+
+ // create:true, exclusive:false, directory does not exist
+ runs(function() {
+ root.getDirectory(dirName, {create: true}, win, fail);
+ });
+
+ waitsFor(function() { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(win).toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+
+ it("DirectoryEntry.getDirectory: create new directory (exclusive)", function() {
+ var dirName = "de.create.exclusive.dir",
+ dirPath = root.fullPath + '/' + dirName,
+ win = jasmine.createSpy().andCallFake(function(directory) {
+ expect(directory).toBeDefined();
+ expect(directory.isFile).toBe(false);
+ expect(directory.isDirectory).toBe(true);
+ expect(directory.name).toCanonicallyMatch(dirName);
+ expect(directory.fullPath).toCanonicallyMatch(dirPath);
+
+ // cleanup
+ directory.remove(null, fail);
+ }),
+ fail = createFail('DirectoryEntry');
+ // create:true, exclusive:true, directory does not exist
+ runs(function() {
+ root.getDirectory(dirName, {create: true, exclusive:true}, win, fail);
+ });
+
+ waitsFor(function() { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(win).toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ it("DirectoryEntry.getDirectory: create directory that already exists", function() {
+ var dirName = "de.create.existing.dir",
+ dirPath = root.fullPath + '/' + dirName,
+ getDir = jasmine.createSpy().andCallFake(function(directory) {
+ // create:true, exclusive:false, directory exists
+ runs(function() {
+ root.getDirectory(dirName, {create:true}, win, fail);
+ });
+
+ waitsFor(function() { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(win).toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ });
+ }),
+ win = jasmine.createSpy().andCallFake(function(directory) {
+ expect(directory).toBeDefined();
+ expect(directory.isFile).toBe(false);
+ expect(directory.isDirectory).toBe(true);
+ expect(directory.name).toCanonicallyMatch(dirName);
+ expect(directory.fullPath).toCanonicallyMatch(dirPath);
+
+ // cleanup
+ directory.remove(null, fail);
+ }),
+ fail = createFail('DirectoryEntry');
+
+ // create directory to kick off it
+ runs(function() {
+ root.getDirectory(dirName, {create:true}, getDir, this.fail);
+ });
+
+ waitsFor(function() { return getDir.wasCalled; }, "getDir never called", Tests.TEST_TIMEOUT);
+ });
+ it("DirectoryEntry.getDirectory: create directory that already exists (exclusive)", function() {
+ var dirName = "de.create.exclusive.existing.dir",
+ dirPath = root.fullPath + '/' + dirName,
+ existingDir,
+ getDir = jasmine.createSpy().andCallFake(function(directory) {
+ existingDir = directory;
+ // create:true, exclusive:true, directory exists
+ runs(function() {
+ root.getDirectory(dirName, {create:true, exclusive:true}, win, fail);
+ });
+
+ waitsFor(function() { return fail.wasCalled; }, "fail never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(fail).toHaveBeenCalled();
+ expect(win).not.toHaveBeenCalled();
+ });
+ }),
+ fail = jasmine.createSpy().andCallFake(function(error) {
+ expect(error).toBeDefined();
+ expect(error).toBeFileError(FileError.PATH_EXISTS_ERR);
+
+ // cleanup
+ existingDir.remove(null, fail);
+ }),
+ win = createWin('DirectoryEntry');
+
+ // create directory to kick off it
+ runs(function() {
+ root.getDirectory(dirName, {create:true}, getDir, fail);
+ });
+
+ waitsFor(function() { return getDir.wasCalled; }, "getDir never called", Tests.TEST_TIMEOUT);
+ });
+ it("DirectoryEntry.getDirectory: get Entry for existing directory", function() {
+ var dirName = "de.get.dir",
+ dirPath = root.fullPath + '/' + dirName,
+ getDir = jasmine.createSpy().andCallFake(function(directory) {
+ // create:false, exclusive:false, directory exists
+ runs(function() {
+ root.getDirectory(dirName, {create:false}, win, fail);
+ });
+
+ waitsFor(function() { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(win).toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ });
+ }),
+ win = jasmine.createSpy().andCallFake(function(directory) {
+ expect(directory).toBeDefined();
+ expect(directory.isFile).toBe(false);
+ expect(directory.isDirectory).toBe(true);
+ expect(directory.name).toCanonicallyMatch(dirName);
+
+ expect(directory.fullPath).toCanonicallyMatch(dirPath);
+
+ // cleanup
+ directory.remove(null, fail);
+ }),
+ fail = createFail('DirectoryEntry');
+
+ // create directory to kick off it
+ root.getDirectory(dirName, {create:true}, getDir, fail);
+ });
+ it("DirectoryEntry.getDirectory: get DirectoryEntry for invalid path", function() {
+ var dirName = "de:invalid:path",
+ fail = jasmine.createSpy().andCallFake(function(error) {
+ expect(error).toBeDefined();
+ expect(error).toBeFileError(FileError.ENCODING_ERR);
+ }),
+ win = createWin('DirectoryEntry');
+
+ // create:false, exclusive:false, invalid path
+ runs(function() {
+ root.getDirectory(dirName, {create:false}, win, fail);
+ });
+
+ waitsFor(function() { return fail.wasCalled; }, "fail never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(fail).toHaveBeenCalled();
+ expect(win).not.toHaveBeenCalled();
+ });
+ });
+ it("DirectoryEntry.getDirectory: get DirectoryEntry for existing file", function() {
+ var fileName = "de.existing.file",
+ existingFile,
+ filePath = root.fullPath + '/' + fileName,
+ getDir = jasmine.createSpy().andCallFake(function(file) {
+ existingFile = file;
+ // create:false, exclusive:false, existing file
+ runs(function() {
+ root.getDirectory(fileName, {create:false}, win, fail);
+ });
+
+ waitsFor(function() { return fail.wasCalled; }, "fail never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(fail).toHaveBeenCalled();
+ expect(win).not.toHaveBeenCalled();
+ });
+ }),
+ fail = jasmine.createSpy().andCallFake(function(error) {
+ expect(error).toBeDefined();
+ expect(error).toBeFileError(FileError.TYPE_MISMATCH_ERR);
+
+ // cleanup
+ existingFile.remove(null, null);
+ }),
+ win = createWin('DirectoryEntry');
+
+ // create file to kick off it
+ runs(function() {
+ root.getFile(fileName, {create:true}, getDir, fail);
+ });
+
+ waitsFor(function() { return getDir.wasCalled; }, "getDir was called", Tests.TEST_TIMEOUT);
+ });
+ it("DirectoryEntry.getFile: get FileEntry for existing directory", function() {
+ var dirName = "de.existing.dir",
+ existingDir,
+ dirPath = root.fullPath + '/' + dirName,
+ getFile = jasmine.createSpy().andCallFake(function(directory) {
+ existingDir = directory;
+ // create:false, exclusive:false, existing directory
+ runs(function() {
+ root.getFile(dirName, {create:false}, win, fail);
+ });
+
+ waitsFor(function() { return fail.wasCalled; }, "fail never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(fail).toHaveBeenCalled();
+ expect(win).not.toHaveBeenCalled();
+ });
+ }),
+ fail = jasmine.createSpy().andCallFake(function(error) {
+ expect(error).toBeDefined();
+ expect(error).toBeFileError(FileError.TYPE_MISMATCH_ERR);
+
+ // cleanup
+ existingDir.remove(null, null);
+ }),
+ win = createWin('DirectoryEntry');
+
+ // create directory to kick off it
+ runs(function() {
+ root.getDirectory(dirName, {create:true}, getFile, fail);
+ });
+
+ waitsFor(function() { return getFile.wasCalled; }, "getFile never called", Tests.TEST_TIMEOUT);
+ });
+ it("DirectoryEntry.removeRecursively on directory", function() {
+ var dirName = "de.removeRecursively",
+ subDirName = "dir",
+ dirPath = root.fullPath + '/' + dirName,
+ //subDirPath = this.root.fullPath + '/' + subDirName,
+ subDirPath = dirPath + '/' + subDirName,
+ entryCallback = jasmine.createSpy().andCallFake(function(entry) {
+ // delete directory
+ var deleteDirectory = jasmine.createSpy().andCallFake(function(directory) {
+ runs(function() {
+ entry.removeRecursively(remove, fail);
+ });
+
+ waitsFor(function() { return remove.wasCalled; }, "remove never called", Tests.TEST_TIMEOUT);
+ });
+ // create a sub-directory within directory
+ runs(function() {
+ entry.getDirectory(subDirName, {create: true}, deleteDirectory, fail);
+ });
+
+ waitsFor(function() { return deleteDirectory.wasCalled; }, "deleteDirectory never called", Tests.TEST_TIMEOUT);
+ }),
+ remove = jasmine.createSpy().andCallFake(function() {
+ // it that removed directory no longer exists
+ runs(function() {
+ root.getDirectory(dirName, {create:false}, win, dirExists);
+ });
+
+ waitsFor(function() { return dirExists.wasCalled; }, "dirExists never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(dirExists).toHaveBeenCalled();
+ expect(win).not.toHaveBeenCalled();
+ });
+ }),
+ dirExists = jasmine.createSpy().andCallFake(function(error){
+ expect(error).toBeDefined();
+ expect(error).toBeFileError(FileError.NOT_FOUND_ERR);
+ }),
+ fail = createFail('DirectoryEntry'),
+ win = createWin('DirectoryEntry');
+
+ // create a new directory entry to kick off it
+ runs(function() {
+ root.getDirectory(dirName, {create:true}, entryCallback, fail);
+ });
+
+ waitsFor(function() { return entryCallback.wasCalled; }, "entryCallback never called", Tests.TEST_TIMEOUT);
+ });
+ it("createReader: create reader on existing directory", function() {
+ // create reader for root directory
+ var reader = root.createReader();
+ expect(reader).toBeDefined();
+ expect(typeof reader.readEntries).toBe('function');
+ });
+ it("removeRecursively on root file system", function() {
+ var remove = jasmine.createSpy().andCallFake(function(error) {
+ expect(error).toBeDefined();
+ expect(error).toBeFileError(FileError.NO_MODIFICATION_ALLOWED_ERR);
+ }),
+ win = createWin('DirectoryEntry');
+
+ // remove root file system
+ runs(function() {
+ root.removeRecursively(win, remove);
+ });
+
+ waitsFor(function() { return remove.wasCalled; }, "remove never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(win).not.toHaveBeenCalled();
+ expect(remove).toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('DirectoryReader interface', function() {
+ describe("readEntries", function() {
+ it("should read contents of existing directory", function() {
+ var reader,
+ win = jasmine.createSpy().andCallFake(function(entries) {
+ expect(entries).toBeDefined();
+ expect(entries instanceof Array).toBe(true);
+ }),
+ fail = createFail('DirectoryReader');
+
+ // create reader for root directory
+ reader = root.createReader();
+ // read entries
+ runs(function() {
+ reader.readEntries(win, fail);
+ });
+
+ waitsFor(function() { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(win).toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ it("should read contents of directory that has been removed", function() {
+ var dirName = "de.createReader.notfound",
+ dirPath = root.fullPath + '/' + dirName,
+ entryCallback = jasmine.createSpy().andCallFake(function(directory) {
+ // read entries
+ var readEntries = jasmine.createSpy().andCallFake(function() {
+ var reader = directory.createReader();
+
+ runs(function() {
+ reader.readEntries(win, itReader);
+ });
+
+ waitsFor(function() { return itReader.wasCalled; }, "itReader never called", Tests.TEST_TIMEOUT);
+ });
+ // delete directory
+ runs(function() {
+ directory.removeRecursively(readEntries, fail);
+ });
+
+ waitsFor(function() { return readEntries.wasCalled; }, "readEntries never called", Tests.TEST_TIMEOUT);
+ }),
+ itReader = jasmine.createSpy().andCallFake(function(error) {
+ var itDirectoryExists = jasmine.createSpy().andCallFake(function(error) {
+ expect(error).toBeDefined();
+ expect(error).toBeFileError(FileError.NOT_FOUND_ERR);
+ });
+
+ expect(error).toBeDefined();
+ expect(error).toBeFileError(FileError.NOT_FOUND_ERR);
+
+ runs(function() {
+ root.getDirectory(dirName, {create:false}, win, itDirectoryExists);
+ });
+
+ waitsFor(function() { return itDirectoryExists.wasCalled; }, "itDirectoryExists never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(itDirectoryExists).toHaveBeenCalled();
+ expect(win).not.toHaveBeenCalled();
+ });
+ }),
+ fail = createFail('DirectoryReader'),
+ win = createWin('DirectoryReader');
+
+ // create a new directory entry to kick off it
+ runs(function() {
+ root.getDirectory(dirName, {create:true}, entryCallback, fail);
+ });
+
+ waitsFor(function() { return entryCallback.wasCalled; }, "entryCallback never called", Tests.TEST_TIMEOUT);
+ });
+ });
+ });
+
+ describe('File', function() {
+ it("constructor should be defined", function() {
+ expect(File).toBeDefined();
+ expect(typeof File).toBe('function');
+ });
+ it("should be define File attributes", function() {
+ var file = new File();
+ expect(file.name).toBeDefined();
+ expect(file.fullPath).toBeDefined();
+ expect(file.type).toBeDefined();
+ expect(file.lastModifiedDate).toBeDefined();
+ expect(file.size).toBeDefined();
+ });
+ });
+
+ describe('FileEntry', function() {
+ it("should be define FileEntry methods", function() {
+ var fileName = "fe.methods",
+ itFileEntry = jasmine.createSpy().andCallFake(function(fileEntry) {
+ expect(fileEntry).toBeDefined();
+ expect(typeof fileEntry.createWriter).toBe('function');
+ expect(typeof fileEntry.file).toBe('function');
+
+ // cleanup
+ fileEntry.remove(null, fail);
+ }),
+ fail = createFail('FileEntry');
+
+ // create a new file entry to kick off it
+ runs(function() {
+ root.getFile(fileName, {create:true}, itFileEntry, fail);
+ });
+
+ waitsFor(function() { return itFileEntry.wasCalled; }, "itFileEntry never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(itFileEntry).toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ it("createWriter should return a FileWriter object", function() {
+ var fileName = "fe.createWriter",
+ itFile,
+ entryCallback = jasmine.createSpy().andCallFake(function(fileEntry) {
+ itFile = fileEntry;
+
+ runs(function() {
+ fileEntry.createWriter(itWriter, fail);
+ });
+
+ waitsFor(function() { return itWriter.wasCalled; }, "itWriter", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(itWriter).toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ });
+ }),
+ itWriter = jasmine.createSpy().andCallFake(function(writer) {
+ expect(writer).toBeDefined();
+ expect(writer instanceof FileWriter).toBe(true);
+
+ // cleanup
+ itFile.remove(null, fail);
+ }),
+ fail = createFail('FileEntry');
+
+ // create a new file entry to kick off it
+ runs(function() {
+ root.getFile(fileName, {create:true}, entryCallback, fail);
+ });
+
+ waitsFor(function() { return entryCallback.wasCalled; }, "entryCallback never called", Tests.TEST_TIMEOUT);
+ });
+ it("file should return a File object", function() {
+ var fileName = "fe.file",
+ newFile,
+ entryCallback = jasmine.createSpy().andCallFake(function(fileEntry) {
+ newFile = fileEntry;
+
+ runs(function() {
+ fileEntry.file(itFile, fail);
+ });
+
+ waitsFor(function() { return itFile.wasCalled; }, "itFile never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(itFile).toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ });
+ }),
+ itFile = jasmine.createSpy().andCallFake(function(file) {
+ expect(file).toBeDefined();
+ expect(file instanceof File).toBe(true);
+
+ // cleanup
+ newFile.remove(null, fail);
+ }),
+ fail = createFail('FileEntry');
+
+ // create a new file entry to kick off it
+ runs(function() {
+ root.getFile(fileName, {create:true}, entryCallback, fail);
+ });
+
+ waitsFor(function() { return entryCallback.wasCalled; }, "entryCallback never called", Tests.TEST_TIMEOUT);
+ });
+ it("file: on File that has been removed", function() {
+ var fileName = "fe.no.file",
+ entryCallback = jasmine.createSpy().andCallFake(function(fileEntry) {
+ // create File object
+ var getFile = jasmine.createSpy().andCallFake(function() {
+ runs(function() {
+ fileEntry.file(win, itFile);
+ });
+
+ waitsFor(function() { return itFile.wasCalled; }, "itFile never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(itFile).toHaveBeenCalled();
+ expect(win).not.toHaveBeenCalled();
+ });
+ });
+ // delete file
+ runs(function() {
+ fileEntry.remove(getFile, fail);
+ });
+
+ waitsFor(function() { return getFile.wasCalled; }, "getFile never called", Tests.TEST_TIMEOUT);
+ }),
+ itFile = jasmine.createSpy().andCallFake(function(error) {
+ expect(error).toBeDefined();
+ expect(error).toBeFileError(FileError.NOT_FOUND_ERR);
+ }),
+ fail = createFail('FileEntry'),
+ win = createWin('FileEntry');
+
+ // create a new file entry to kick off it
+ runs(function() {
+ root.getFile(fileName, {create:true}, entryCallback, fail);
+ });
+
+ waitsFor(function() { return entryCallback.wasCalled; }, "entryCallback never called", Tests.TEST_TIMEOUT);
+ });
+ });
+ describe('Entry', function() {
+ it("Entry object", function() {
+ var fileName = "entry",
+ fullPath = root.fullPath + '/' + fileName,
+ fail = createFail('Entry'),
+ itEntry = jasmine.createSpy().andCallFake(function(entry) {
+ expect(entry).toBeDefined();
+ expect(entry.isFile).toBe(true);
+ expect(entry.isDirectory).toBe(false);
+ expect(entry.name).toCanonicallyMatch(fileName);
+ expect(entry.fullPath).toCanonicallyMatch(fullPath);
+ expect(typeof entry.getMetadata).toBe('function');
+ expect(typeof entry.setMetadata).toBe('function');
+ expect(typeof entry.moveTo).toBe('function');
+ expect(typeof entry.copyTo).toBe('function');
+ expect(typeof entry.toURL).toBe('function');
+ expect(typeof entry.remove).toBe('function');
+ expect(typeof entry.getParent).toBe('function');
+ expect(typeof entry.createWriter).toBe('function');
+ expect(typeof entry.file).toBe('function');
+
+ // cleanup
+ deleteEntry(fileName);
+ });
+
+ // create a new file entry
+ runs(function() {
+ createFile(fileName, itEntry, fail);
+ });
+
+ waitsFor(function() { return itEntry.wasCalled; }, "itEntry", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(itEntry).toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ it("Entry.getMetadata on file", function() {
+ var fileName = "entry.metadata.file",
+ entryCallback = jasmine.createSpy().andCallFake(function(entry) {
+ runs(function() {
+ entry.getMetadata(itMetadata, fail);
+ });
+
+ waitsFor(function() { return itMetadata.wasCalled; }, "itMetadata never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(itMetadata).toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ });
+ }),
+ fail = createFail('Entry'),
+ itMetadata = jasmine.createSpy().andCallFake(function(metadata) {
+ expect(metadata).toBeDefined();
+ expect(metadata.modificationTime instanceof Date).toBe(true);
+
+ // cleanup
+ deleteEntry(fileName);
+ });
+
+ // create a new file entry
+ createFile(fileName, entryCallback, fail);
+ });
+ it("Entry.getMetadata on directory", function() {
+ var dirName = "entry.metadata.dir",
+ entryCallback = jasmine.createSpy().andCallFake(function(entry) {
+ runs(function() {
+ entry.getMetadata(itMetadata, fail);
+ });
+
+ waitsFor(function() { return itMetadata.wasCalled; }, "itMetadata never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(itMetadata).toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ });
+ }),
+ fail = createFail('Entry'),
+ itMetadata = jasmine.createSpy().andCallFake(function(metadata) {
+ expect(metadata).toBeDefined();
+ expect(metadata.modificationTime instanceof Date).toBe(true);
+
+ // cleanup
+ deleteEntry(dirName);
+ });
+
+ // create a new directory entry
+ runs(function() {
+ createDirectory(dirName, entryCallback, fail);
+ });
+
+ waitsFor(function() { return entryCallback.wasCalled; }, "entryCallback never called", Tests.TEST_TIMEOUT);
+ });
+ it("Entry.getParent on file in root file system", function() {
+ var fileName = "entry.parent.file",
+ rootPath = root.fullPath,
+ fail = createFail('Entry'),
+ entryCallback = jasmine.createSpy().andCallFake(function(entry) {
+ runs(function() {
+ entry.getParent(itParent, fail);
+ });
+
+ waitsFor(function() { return itParent.wasCalled; }, "itCalled never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(itParent).toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ });
+ }),
+ itParent = jasmine.createSpy().andCallFake(function(parent) {
+ expect(parent).toBeDefined();
+ expect(parent.fullPath).toCanonicallyMatch(rootPath);
+
+ // cleanup
+ deleteEntry(fileName);
+ });
+
+ // create a new file entry
+ runs(function() {
+ createFile(fileName, entryCallback, fail);
+ });
+
+ waitsFor(function() { return entryCallback.wasCalled; }, "entryCallback never called", Tests.TEST_TIMEOUT);
+ });
+ it("Entry.getParent on directory in root file system", function() {
+ var dirName = "entry.parent.dir",
+ rootPath = root.fullPath,
+ fail = createFail('Entry'),
+ entryCallback = jasmine.createSpy().andCallFake(function(entry) {
+ runs(function() {
+ entry.getParent(itParent, fail);
+ });
+
+ waitsFor(function() { return itParent.wasCalled; }, "itParent never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(itParent).toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ });
+ }),
+ itParent = jasmine.createSpy().andCallFake(function(parent) {
+ expect(parent).toBeDefined();
+ expect(parent.fullPath).toCanonicallyMatch(rootPath);
+
+ // cleanup
+ deleteEntry(dirName);
+ });
+
+ // create a new directory entry
+ runs(function() {
+ createDirectory(dirName, entryCallback, fail);
+ });
+
+ waitsFor(function() { return entryCallback.wasCalled; }, "entryCallback never called", Tests.TEST_TIMEOUT);
+ });
+ it("Entry.getParent on root file system", function() {
+ var rootPath = root.fullPath,
+ itParent = jasmine.createSpy().andCallFake(function(parent) {
+ expect(parent).toBeDefined();
+ expect(parent.fullPath).toCanonicallyMatch(rootPath);
+ }),
+ fail = createFail('Entry');
+
+ // create a new directory entry
+ runs(function() {
+ root.getParent(itParent, fail);
+ });
+
+ waitsFor(function() { return itParent.wasCalled; }, "itParent never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(itParent).toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ it("Entry.toURL on file", function() {
+ var fileName = "entry.uri.file",
+ rootPath = root.fullPath,
+ itURI = jasmine.createSpy().andCallFake(function(entry) {
+ var uri = entry.toURL();
+ expect(uri).toBeDefined();
+ expect(uri.indexOf(rootPath)).not.toBe(-1);
+
+ // cleanup
+ deleteEntry(fileName);
+ }),
+ fail = createFail('Entry');
+
+ // create a new file entry
+ runs(function() {
+ createFile(fileName, itURI, fail);
+ });
+
+ waitsFor(function() { return itURI.wasCalled; }, "itURI never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(itURI).toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ it("Entry.toURL on directory", function() {
+ var dirName = "entry.uri.dir",
+ rootPath = root.fullPath,
+ itURI = jasmine.createSpy().andCallFake(function(entry) {
+ var uri = entry.toURL();
+ expect(uri).toBeDefined();
+ expect(uri.indexOf(rootPath)).not.toBe(-1);
+
+ // cleanup
+ deleteEntry(dirName);
+ }),
+ fail = createFail('Entry');
+
+ // create a new directory entry
+ runs(function() {
+ createDirectory(dirName, itURI, fail);
+ });
+
+ waitsFor(function() { return itURI.wasCalled; }, "itURI never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(itURI).toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ it("Entry.remove on file", function() {
+ var fileName = "entry.rm.file",
+ fullPath = root.fullPath + '/' + fileName,
+ win = createWin('Entry'),
+ entryCallback = jasmine.createSpy().andCallFake(function(entry) {
+ var checkRemove = jasmine.createSpy().andCallFake(function() {
+ runs(function() {
+ root.getFile(fileName, null, win, itRemove);
+ });
+
+ waitsFor(function() { return itRemove.wasCalled; }, "itRemove never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(win).not.toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ expect(itRemove).toHaveBeenCalled();
+ });
+ });
+ expect(entry).toBeDefined();
+
+ runs(function() {
+ entry.remove(checkRemove, fail);
+ });
+
+ waitsFor(function() { return checkRemove.wasCalled; }, "checkRemove never called", Tests.TEST_TIMEOUT);
+ }),
+ itRemove = jasmine.createSpy().andCallFake(function(error) {
+ expect(error).toBeDefined();
+ expect(error).toBeFileError(FileError.NOT_FOUND_ERR);
+ // cleanup
+ deleteEntry(fileName);
+ }),
+ fail = createFail('Entry');
+
+ // create a new file entry
+ runs(function() {
+ createFile(fileName, entryCallback, fail);
+ });
+
+ waitsFor(function() { return entryCallback.wasCalled; }, "entryCallback never called", Tests.TEST_TIMEOUT);
+ });
+ it("remove on empty directory", function() {
+ var dirName = "entry.rm.dir",
+ fullPath = root.fullPath + '/' + dirName,
+ entryCallback = jasmine.createSpy().andCallFake(function(entry) {
+ var checkRemove = jasmine.createSpy().andCallFake(function() {
+ runs(function() {
+ root.getDirectory(dirName, null, win, itRemove);
+ });
+
+ waitsFor(function() { return itRemove.wasCalled; }, "itRemove never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(itRemove).toHaveBeenCalled();
+ expect(win).not.toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+
+ expect(entry).toBeDefined();
+
+ runs(function() {
+ entry.remove(checkRemove, fail);
+ });
+
+ waitsFor(function() { return checkRemove.wasCalled; }, "checkRemove never called", Tests.TEST_TIMEOUT);
+ }),
+ itRemove = jasmine.createSpy().andCallFake(function(error) {
+ expect(error).toBeDefined();
+ expect(error).toBeFileError(FileError.NOT_FOUND_ERR);
+ // cleanup
+ deleteEntry(dirName);
+ }),
+ win = createWin('Entry'),
+ fail = createFail('Entry');
+
+ // create a new directory entry
+ runs(function() {
+ createDirectory(dirName, entryCallback, fail);
+ });
+
+ waitsFor(function() { return entryCallback.wasCalled; }, "entryCallback never called", Tests.TEST_TIMEOUT);
+ });
+ it("remove on non-empty directory", function() {
+ var dirName = "entry.rm.dir.not.empty",
+ fullPath = root.fullPath + '/' + dirName,
+ fileName = "remove.txt",
+ entryCallback = jasmine.createSpy().andCallFake(function(entry) {
+ var checkFile = jasmine.createSpy().andCallFake(function(error) {
+ expect(error).toBeDefined();
+ expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR);
+ // verify that dir still exists
+ runs(function() {
+ root.getDirectory(dirName, null, itRemove, fail);
+ });
+
+ waitsFor(function() { return itRemove.wasCalled; }, "itRemove never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(win).not.toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ expect(itRemove).toHaveBeenCalled();
+ });
+ });
+ // delete directory
+ var deleteDirectory = jasmine.createSpy().andCallFake(function(fileEntry) {
+ runs(function() {
+ entry.remove(win, checkFile);
+ });
+
+ waitsFor(function() { return checkFile.wasCalled; }, "checkFile never called", Tests.TEST_TIMEOUT);
+ });
+ // create a file within directory, then try to delete directory
+ runs(function() {
+ entry.getFile(fileName, {create: true}, deleteDirectory, fail);
+ });
+
+ waitsFor(function() { return deleteDirectory.wasCalled; }, "deleteDirectory never called", Tests.TEST_TIMEOUT);
+ }),
+ itRemove = jasmine.createSpy().andCallFake(function(entry) {
+ expect(entry).toBeDefined();
+ expect(entry.fullPath).toCanonicallyMatch(fullPath);
+ // cleanup
+ deleteEntry(dirName);
+ }),
+ win = createWin('Entry'),
+ fail = createFail('Entry');
+
+ // create a new directory entry
+ runs(function() {
+ createDirectory(dirName, entryCallback, fail);
+ });
+
+ waitsFor(function() { return entryCallback.wasCalled; }, "entryCallback never called", Tests.TEST_TIMEOUT);
+ });
+ it("remove on root file system", function() {
+ var itRemove = jasmine.createSpy().andCallFake(function(error) {
+ expect(error).toBeDefined();
+ expect(error).toBeFileError(FileError.NO_MODIFICATION_ALLOWED_ERR);
+ }),
+ win = createWin('Entry');
+
+ // remove entry that doesn't exist
+ runs(function() {
+ root.remove(win, itRemove);
+ });
+
+ waitsFor(function() { return itRemove.wasCalled; }, "itRemove never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(win).not.toHaveBeenCalled();
+ expect(itRemove).toHaveBeenCalled();
+ });
+ });
+ it("copyTo: file", function() {
+ var file1 = "entry.copy.file1",
+ file2 = "entry.copy.file2",
+ fullPath = root.fullPath + '/' + file2,
+ fail = createFail('Entry'),
+ entryCallback = jasmine.createSpy().andCallFake(function(entry) {
+ // copy file1 to file2
+ runs(function() {
+ entry.copyTo(root, file2, itCopy, fail);
+ });
+
+ waitsFor(function() { return itCopy.wasCalled; }, "itCopy never called", Tests.TEST_TIMEOUT);
+ }),
+ itCopy = jasmine.createSpy().andCallFake(function(entry) {
+ expect(entry).toBeDefined();
+ expect(entry.isFile).toBe(true);
+ expect(entry.isDirectory).toBe(false);
+ expect(entry.fullPath).toCanonicallyMatch(fullPath);
+ expect(entry.name).toCanonicallyMatch(file2);
+
+ runs(function() {
+ root.getFile(file2, {create:false}, itFileExists, fail);
+ });
+
+ waitsFor(function() { return itFileExists.wasCalled; }, "itFileExists never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(fail).not.toHaveBeenCalled();
+ expect(itFileExists).toHaveBeenCalled();
+ });
+ }),
+ itFileExists = jasmine.createSpy().andCallFake(function(entry2) {
+ // a bit redundant since copy returned this entry already
+ expect(entry2).toBeDefined();
+ expect(entry2.isFile).toBe(true);
+ expect(entry2.isDirectory).toBe(false);
+ expect(entry2.fullPath).toCanonicallyMatch(fullPath);
+ expect(entry2.name).toCanonicallyMatch(file2);
+
+ // cleanup
+ deleteEntry(file1);
+ deleteEntry(file2);
+ });
+
+ // create a new file entry to kick off it
+ runs(function() {
+ createFile(file1, entryCallback, fail);
+ });
+
+ waitsFor(function() { return entryCallback.wasCalled; }, "entryCallback never called", Tests.TEST_TIMEOUT);
+ });
+ it("copyTo: file onto itself", function() {
+ var file1 = "entry.copy.fos.file1",
+ entryCallback = jasmine.createSpy().andCallFake(function(entry) {
+ // copy file1 onto itself
+ runs(function() {
+ entry.copyTo(root, null, win, itCopy);
+ });
+
+ waitsFor(function() { return itCopy.wasCalled; }, "itCopy never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(itCopy).toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ expect(win).not.toHaveBeenCalled();
+ });
+ }),
+ fail = createFail('Entry'),
+ win = createWin('Entry'),
+ itCopy = jasmine.createSpy().andCallFake(function(error) {
+ expect(error).toBeDefined();
+ expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR);
+
+ // cleanup
+ deleteEntry(file1);
+ });
+
+ // create a new file entry to kick off it
+ runs(function() {
+ createFile(file1, entryCallback, fail);
+ });
+
+ waitsFor(function() { return entryCallback.wasCalled; }, "entryCallback never called", Tests.TEST_TIMEOUT);
+ });
+ it("copyTo: directory", function() {
+ var file1 = "file1",
+ srcDir = "entry.copy.srcDir",
+ dstDir = "entry.copy.dstDir",
+ dstPath = root.fullPath + '/' + dstDir,
+ filePath = dstPath + '/' + file1,
+ entryCallback = jasmine.createSpy().andCallFake(function(directory) {
+ var copyDir = jasmine.createSpy().andCallFake(function(fileEntry) {
+ // copy srcDir to dstDir
+ runs(function() {
+ directory.copyTo(root, dstDir, itCopy, fail);
+ });
+
+ waitsFor(function() { return itCopy.wasCalled; }, "itCopy never called", Tests.TEST_TIMEOUT);
+ });
+
+ // create a file within new directory
+ runs(function() {
+ directory.getFile(file1, {create: true}, copyDir, fail);
+ });
+
+ waitsFor(function() { return copyDir.wasCalled; }, "copyDir never called", Tests.TEST_TIMEOUT);
+ }),
+ itCopy = jasmine.createSpy().andCallFake(function(directory) {
+ expect(directory).toBeDefined();
+ expect(directory.isFile).toBe(false);
+ expect(directory.isDirectory).toBe(true);
+ expect(directory.fullPath).toCanonicallyMatch(dstPath);
+ expect(directory.name).toCanonicallyMatch(dstDir);
+
+ runs(function() {
+ root.getDirectory(dstDir, {create:false}, itDirExists, fail);
+ });
+
+ waitsFor(function() { return itDirExists.wasCalled; }, "itDirExists never called", Tests.TEST_TIMEOUT);
+ }),
+ itDirExists = jasmine.createSpy().andCallFake(function(dirEntry) {
+ expect(dirEntry).toBeDefined();
+ expect(dirEntry.isFile).toBe(false);
+ expect(dirEntry.isDirectory).toBe(true);
+ expect(dirEntry.fullPath).toCanonicallyMatch(dstPath);
+ expect(dirEntry.name).toCanonicallyMatch(dstDir);
+
+ runs(function() {
+ dirEntry.getFile(file1, {create:false}, itFileExists, fail);
+ });
+
+ waitsFor(function() { return itFileExists.wasCalled; }, "itFileExists never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(itFileExists).toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ });
+ }),
+ itFileExists = jasmine.createSpy().andCallFake(function(fileEntry) {
+ expect(fileEntry).toBeDefined();
+ expect(fileEntry.isFile).toBe(true);
+ expect(fileEntry.isDirectory).toBe(false);
+ expect(fileEntry.fullPath).toCanonicallyMatch(filePath);
+ expect(fileEntry.name).toCanonicallyMatch(file1);
+
+ // cleanup
+ deleteEntry(srcDir);
+ deleteEntry(dstDir);
+ }),
+ fail = createFail('Entry');
+
+ // create a new directory entry to kick off it
+ runs(function() {
+ createDirectory(srcDir, entryCallback, fail);
+ });
+
+ waitsFor(function() { return entryCallback.wasCalled; }, "entryCallback never called", Tests.TEST_TIMEOUT);
+ });
+ it("copyTo: directory to backup at same root directory", function() {
+ var file1 = "file1",
+ srcDir = "entry.copy.srcDirSame",
+ dstDir = "entry.copy.srcDirSame-backup",
+ dstPath = root.fullPath + '/' + dstDir,
+ filePath = dstPath + '/' + file1,
+ fail = createFail('Entry copyTo: directory to backup at same root'),
+ entryCallback = function(directory) {
+ var copyDir = function(fileEntry) {
+ // copy srcDir to dstDir
+ directory.copyTo(root, dstDir, itCopy, fail);
+ };
+ // create a file within new directory
+ directory.getFile(file1, {create: true}, copyDir, fail);
+ },
+ itCopy = function(directory) {
+ expect(directory).toBeDefined();
+ expect(directory.isFile).toBe(false);
+ expect(directory.isDirectory).toBe(true);
+ expect(directory.fullPath).toCanonicallyMatch(dstPath);
+ expect(directory.name).toCanonicallyMatch(dstDir);
+
+ root.getDirectory(dstDir, {create:false}, itDirExists, fail);
+ },
+ itDirExists = function(dirEntry) {
+ expect(dirEntry).toBeDefined();
+ expect(dirEntry.isFile).toBe(false);
+ expect(dirEntry.isDirectory).toBe(true);
+ expect(dirEntry.fullPath).toCanonicallyMatch(dstPath);
+ expect(dirEntry.name).toCanonicallyMatch(dstDir);
+
+ dirEntry.getFile(file1, {create:false}, itFileExists, fail);
+ },
+ itFileExists = jasmine.createSpy().andCallFake(function(fileEntry) {
+ var cleanSrc = jasmine.createSpy();
+ var cleanDst = jasmine.createSpy();
+ runs(function() {
+ expect(fileEntry).toBeDefined();
+ expect(fileEntry.isFile).toBe(true);
+ expect(fileEntry.isDirectory).toBe(false);
+ expect(fileEntry.fullPath).toCanonicallyMatch(filePath);
+ expect(fileEntry.name).toCanonicallyMatch(file1);
+ expect(fail).not.toHaveBeenCalled();
+
+ // cleanup
+ deleteEntry(srcDir, cleanSrc);
+ deleteEntry(dstDir, cleanDst);
+ });
+
+ waitsFor(function() { return cleanSrc.wasCalled && cleanDst.wasCalled; }, "cleanSrc and cleanDst cleanup methods", Tests.TEST_TIMEOUT);
+ });
+
+ // create a new directory entry to kick off it
+ runs(function() {
+ createDirectory(srcDir, entryCallback, fail);
+ });
+
+ waitsFor(function() { return itFileExists.wasCalled; }, "itFileExists", 10000);
+ });
+ it("copyTo: directory onto itself", function() {
+ var file1 = "file1",
+ srcDir = "entry.copy.dos.srcDir",
+ srcPath = root.fullPath + '/' + srcDir,
+ filePath = srcPath + '/' + file1,
+ win = createWin('Entry'),
+ fail = createFail('Entry copyTo: directory onto itself'),
+ entryCallback = jasmine.createSpy().andCallFake(function(directory) {
+ var copyDir = jasmine.createSpy().andCallFake(function(fileEntry) {
+ // copy srcDir onto itself
+ runs(function() {
+ directory.copyTo(root, null, win, itCopy);
+ });
+
+ waitsFor(function() { return itCopy.wasCalled; }, "itCopy never called", Tests.TEST_TIMEOUT);
+ });
+ // create a file within new directory
+ runs(function() {
+ directory.getFile(file1, {create: true}, copyDir, fail);
+ });
+
+ waitsFor(function() { return copyDir.wasCalled; }, "copyDir never called", Tests.TEST_TIMEOUT);
+ }),
+ itCopy = jasmine.createSpy().andCallFake(function(error) {
+ expect(error).toBeDefined();
+ expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR);
+
+ runs(function() {
+ root.getDirectory(srcDir, {create:false}, itDirectoryExists, fail);
+ });
+
+ waitsFor(function() { return itDirectoryExists.wasCalled; }, "itDirectoryExists", Tests.TEST_TIMEOUT);
+ }),
+ itDirectoryExists = jasmine.createSpy().andCallFake(function(dirEntry) {
+ // returning confirms existence so just check fullPath entry
+ expect(dirEntry).toBeDefined();
+ expect(dirEntry.fullPath).toCanonicallyMatch(srcPath);
+
+ runs(function() {
+ dirEntry.getFile(file1, {create:false}, itFileExists, fail);
+ });
+
+ waitsFor(function() { return itFileExists.wasCalled; }, "itFileExists never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(win).not.toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ expect(itFileExists).toHaveBeenCalled();
+ });
+ }),
+ itFileExists = jasmine.createSpy().andCallFake(function(fileEntry) {
+ expect(fileEntry).toBeDefined();
+ expect(fileEntry.fullPath).toCanonicallyMatch(filePath);
+
+ // cleanup
+ deleteEntry(srcDir);
+ });
+
+ // create a new directory entry to kick off it
+ runs(function() {
+ createDirectory(srcDir, entryCallback, fail);
+ });
+
+ waitsFor(function() { return entryCallback.wasCalled; }, "entryCallback never called", Tests.TEST_TIMEOUT);
+ });
+ it("copyTo: directory into itself", function() {
+ var srcDir = "entry.copy.dis.srcDir",
+ dstDir = "entry.copy.dis.dstDir",
+ fail = createFail('Entry'),
+ win = createWin('Entry'),
+ srcPath = root.fullPath + '/' + srcDir,
+ entryCallback = jasmine.createSpy().andCallFake(function(directory) {
+ // copy source directory into itself
+ runs(function() {
+ directory.copyTo(directory, dstDir, win, itCopy);
+ });
+
+ waitsFor(function() { return itCopy.wasCalled; }, "itCopy", Tests.TEST_TIMEOUT);
+ }),
+ itCopy = jasmine.createSpy().andCallFake(function(error) {
+ expect(error).toBeDefined();
+ expect(error).toBeFileError(FileError.INVALID_MODIFICATION_ERR);
+
+ runs(function() {
+ root.getDirectory(srcDir, {create:false}, itDirectoryExists, fail);
+ });
+
+ waitsFor(function() { return itDirectoryExists.wasCalled; }, "itDirectoryExists never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(itDirectoryExists).toHaveBeenCalled();
+ expect(win).not.toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ });
+ }),
+ itDirectoryExists = jasmine.createSpy().andCallFake(function(dirEntry) {
+ // returning confirms existence so just check fullPath entry
+ expect(dirEntry).toBeDefined();
+ expect(dirEntry.fullPath).toCanonicallyMatch(srcPath);
+
+ // cleanup
+ deleteEntry(srcDir);
+ });
+
+ // create a new directory entry to kick off it
+ runs(function() {
+ createDirectory(srcDir, entryCallback, fail);
+ });
+
+ waitsFor(function() { return entryCallback.wasCalled; }, "entryCallback never called", Tests.TEST_TIMEOUT);
+ });
+ it("copyTo: directory that does not exist", function() {
+ var file1 = "entry.copy.dnf.file1",
+ dstDir = "entry.copy.dnf.dstDir",
+ filePath = root.fullPath + '/' + file1,
+ dstPath = root.fullPath + '/' + dstDir,
+ win = createWin('Entry'),
+ fail = createFail('Entry'),
+ entryCallback = jasmine.createSpy().andCallFake(function(entry) {
+ // copy file to target directory that does not exist
+ runs(function() {
+ directory = new DirectoryEntry();
+ directory.fullPath = dstPath;
+ entry.copyTo(directory, null, win, itCopy);
+ });
+
+ waitsFor(function() { return itCopy.wasCalled; }, "itCopy never called", Tests.TEST_TIMEOUT);
+ }),
+ itCopy = jasmine.createSpy().andCallFake(function(error) {
+ expect(error).toBeDefined();
+ expect(error).toBeFileError(FileError.NOT_FOUND_ERR);
+ runs(function() {
+ root.getFile(file1, {create: false}, itFileExists, fail);
+ });
+
+ waitsFor(function() { return itFileExists.wasCalled; }, "itFileExists never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ expect(itFileExists).toHaveBeenCalled();
+ expect(win).not.toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ });
+ }),
+ itFileExists = jasmine.createSpy().andCallFake(function(fileEntry) {
+ expect(fileEntry).toBeDefined();
+ expect(fileEntry.fullPath).toCanonicallyMatch(filePath);
+
+ // cleanup
+ deleteEntry(file1);
+ });
+
+ // create a new file entry to kick off it
+ runs(function() {
+ createFile(file1, entryCallback, fail);
+ });
+
+ waitsFor(function() { return entryCallback.wasCalled; }, "entryCallback never called", Tests.TEST_TIMEOUT);
+ });
+ it("copyTo: invalid target name", function() {
+ var file1 = "entry.copy.itn.file1",
+ file2 = "bad:file:name",
+ filePath = root.fullPath + '/' + file1,
+ fail = createFail('Entry'),
+ win = createWin('Entry'),
+ entryCallback = jasmine.createSpy().andCallFake(function(entry) {
+ // copy file1 to file2
+ runs(function() {
+ entry.copyTo(root, file2, win, itCopy);
+ });
+
+ waitsFor(function() { return itCopy.wasCalled; }, "itCopy
<TRUNCATED>
[07/37] Add WP7 and WP8 platform files.
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/filetransfer.tests.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/filetransfer.tests.js b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/filetransfer.tests.js
new file mode 100644
index 0000000..8c1cd35
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/filetransfer.tests.js
@@ -0,0 +1,513 @@
+/*
+ *
+ * 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.
+ *
+*/
+
+describe('FileTransfer', function() {
+ // https://github.com/don/cordova-filetransfer
+ var server = "http://cordova-filetransfer.jitsu.com";
+
+ // deletes and re-creates the specified content
+ var writeFile = function(fileName, fileContent, success, error) {
+ deleteFile(fileName, function() {
+ root.getFile(fileName, {create: true}, function(fileEntry) {
+ fileEntry.createWriter(function (writer) {
+
+ writer.onwrite = function(evt) {
+ success(fileEntry);
+ };
+
+ writer.onabort = function(evt) {
+ error(evt);
+ };
+
+ writer.error = function(evt) {
+ error(evt);
+ };
+
+ writer.write(fileContent + "\n");
+ }, error);
+ }, error);
+ });
+ };
+
+ var readFileEntry = function(entry, success, error) {
+ entry.file(function(file) {
+ var reader = new FileReader();
+ reader.onerror = error;
+ reader.onload = function(e) {
+ success(reader.result);
+ };
+ reader.readAsText(file);
+ }, error);
+ };
+
+ var getMalformedUrl = function() {
+ if (device.platform.match(/Android/i)) {
+ // bad protocol causes a MalformedUrlException on Android
+ return "httpssss://example.com";
+ } else {
+ // iOS doesn't care about protocol, space in hostname causes error
+ return "httpssss://exa mple.com";
+ }
+ };
+
+ // deletes file, if it exists, then invokes callback
+ var deleteFile = function(fileName, callback) {
+ callback = callback || function() {};
+ var spy = jasmine.createSpy().andCallFake(callback);
+ root.getFile(fileName, null,
+ // remove file system entry
+ function(entry) {
+ entry.remove(spy, spy);
+ },
+ // doesn't exist
+ spy);
+ waitsFor(function() { return spy.wasCalled; }, Tests.TEST_TIMEOUT);
+ };
+
+ it("should exist and be constructable", function() {
+ var ft = new FileTransfer();
+ expect(ft).toBeDefined();
+ });
+ it("should contain proper functions", function() {
+ var ft = new FileTransfer();
+ expect(typeof ft.upload).toBe('function');
+ expect(typeof ft.download).toBe('function');
+ });
+ describe('FileTransferError', function() {
+ it("FileTransferError constants should be defined", function() {
+ expect(FileTransferError.FILE_NOT_FOUND_ERR).toBe(1);
+ expect(FileTransferError.INVALID_URL_ERR).toBe(2);
+ expect(FileTransferError.CONNECTION_ERR).toBe(3);
+ });
+ });
+
+ describe('download method', function() {
+
+ // NOTE: if download tests are failing, check the white list
+ // Android
+ // <access origin="httpssss://example.com"/>
+ // <access origin="apache.org" subdomains="true" />
+ // <access origin="cordova-filetransfer.jitsu.com"/>
+ // iOS
+ // # Cordova.plist
+ // ExternalHosts
+ // - Item 1 String cordova-filetransfer.jitsu.com
+ // - Item 2 String *.apache.org
+
+ it("should be able to download a file using http", function() {
+ var fail = createDoNotCallSpy('downloadFail');
+ var remoteFile = server + "/robots.txt"
+ var localFileName = remoteFile.substring(remoteFile.lastIndexOf('/')+1);
+ var lastProgressEvent = null;
+
+ var downloadWin = jasmine.createSpy().andCallFake(function(entry) {
+ expect(entry.name).toBe(localFileName);
+ expect(lastProgressEvent.loaded).toBeGreaterThan(1);
+ });
+
+ this.after(function() {
+ deleteFile(localFileName);
+ });
+ runs(function() {
+ var ft = new FileTransfer();
+ ft.onprogress = function(e) {
+ lastProgressEvent = e;
+ };
+ ft.download(remoteFile, root.fullPath + "/" + localFileName, downloadWin, fail);
+ });
+
+ waitsForAny(downloadWin, fail);
+ });
+ it("should be able to download a file using https", function() {
+ var remoteFile = "https://www.apache.org/licenses/";
+ var localFileName = 'httpstest.html';
+ var downloadFail = createDoNotCallSpy('downloadFail', 'Ensure ' + remoteFile + ' is in the white-list');
+ var fileFail = createDoNotCallSpy('fileFail');
+ var downloadWin = function(entry) {
+ readFileEntry(entry, fileWin, fileFail);
+ };
+ var fileWin = jasmine.createSpy().andCallFake(function(content) {
+ expect(content).toMatch(/The Apache Software Foundation/);
+ });
+
+ this.after(function() {
+ deleteFile(localFileName);
+ });
+ runs(function() {
+ var ft = new FileTransfer();
+ ft.download(remoteFile, root.fullPath + "/" + localFileName, downloadWin, downloadFail);
+ });
+
+ waitsForAny(fileWin, downloadFail, fileFail);
+ });
+ it("should be stopped by abort() right away", function() {
+ var downloadWin = createDoNotCallSpy('downloadWin');
+ var remoteFile = 'http://audio.ibeat.org/content/p1rj1s/p1rj1s_-_rockGuitar.mp3';
+ var localFileName = remoteFile.substring(remoteFile.lastIndexOf('/')+1);
+ var startTime = +new Date();
+
+ var downloadFail = jasmine.createSpy().andCallFake(function(e) {
+ expect(e.code).toBe(FileTransferError.ABORT_ERR);
+ expect(new Date() - startTime).toBeLessThan(300);
+ });
+
+ this.after(function() {
+ deleteFile(localFileName);
+ });
+ runs(function() {
+ var ft = new FileTransfer();
+ ft.abort(); // should be a no-op.
+ ft.download(remoteFile, root.fullPath + "/" + localFileName, downloadWin, downloadFail);
+ ft.abort();
+ ft.abort(); // should be a no-op.
+ });
+
+ waitsForAny(downloadWin, downloadFail);
+ });
+ it("should get http status on failure", function() {
+ var downloadWin = createDoNotCallSpy('downloadWin');
+
+ var remoteFile = server + "/404";
+ var localFileName = remoteFile.substring(remoteFile.lastIndexOf('/')+1);
+ var downloadFail = jasmine.createSpy().andCallFake(function(error) {
+ expect(error.http_status).toBe(404);
+ expect(error.http_status).not.toBe(401, "Ensure " + remoteFile + " is in the white list");
+ });
+
+ this.after(function() {
+ deleteFile(localFileName);
+ });
+ runs(function() {
+ var ft = new FileTransfer();
+ ft.download(remoteFile, root.fullPath + "/" + localFileName, downloadWin, downloadFail);
+ });
+
+ waitsForAny(downloadWin, downloadFail);
+ });
+ it("should handle malformed urls", function() {
+ var downloadWin = createDoNotCallSpy('downloadWin');
+
+ var remoteFile = getMalformedUrl();
+ var localFileName = "download_malformed_url.txt";
+ var downloadFail = jasmine.createSpy().andCallFake(function(error) {
+ // Note: Android needs the bad protocol to be added to the access list
+ // <access origin=".*"/> won't match because ^https?:// is prepended to the regex
+ // The bad protocol must begin with http to avoid automatic prefix
+ expect(error.http_status).not.toBe(401, "Ensure " + remoteFile + " is in the white list");
+ expect(error.code).toBe(FileTransferError.INVALID_URL_ERR);
+ });
+
+ this.after(function() {
+ deleteFile(localFileName);
+ });
+ runs(function() {
+ var ft = new FileTransfer();
+ ft.download(remoteFile, root.fullPath + "/" + localFileName, downloadWin, downloadFail);
+ });
+
+ waitsForAny(downloadWin, downloadFail);
+ });
+ it("should handle unknown host", function() {
+ var downloadWin = createDoNotCallSpy('downloadWin');
+
+ var remoteFile = "http://foobar.apache.org/index.html";
+ var localFileName = remoteFile.substring(remoteFile.lastIndexOf('/')+1);
+ var downloadFail = jasmine.createSpy().andCallFake(function(error) {
+ expect(error.code).toBe(FileTransferError.CONNECTION_ERR);
+ });
+
+ runs(function() {
+ var ft = new FileTransfer();
+ ft.download(remoteFile, root.fullPath + "/" + localFileName, downloadWin, downloadFail);
+ });
+
+ waitsForAny(downloadWin, downloadFail);
+ });
+ it("should handle bad file path", function() {
+ var downloadWin = createDoNotCallSpy('downloadWin');
+
+ var remoteFile = server;
+ var badFilePath = "c:\\54321";
+ var downloadFail = jasmine.createSpy().andCallFake(function(error) {
+ expect(error.code).toBe(FileTransferError.FILE_NOT_FOUND_ERR);
+ });
+
+ runs(function() {
+ var ft = new FileTransfer();
+ ft.download(remoteFile, badFilePath, downloadWin, downloadFail);
+ });
+
+ waitsForAny(downloadWin, downloadFail);
+ });
+ });
+ describe('upload method', function() {
+
+ it("should be able to upload a file", function() {
+ var remoteFile = server + "/upload";
+ var localFileName = "upload.txt";
+ var fileContents = 'This file should upload';
+
+ var fileFail = createDoNotCallSpy('fileFail');
+ var uploadFail = createDoNotCallSpy('uploadFail', "Ensure " + remoteFile + " is in the white list");
+ var lastProgressEvent = null;
+
+ var uploadWin = jasmine.createSpy().andCallFake(function(uploadResult) {
+ expect(uploadResult.bytesSent).toBeGreaterThan(0);
+ expect(uploadResult.responseCode).toBe(200);
+ expect(uploadResult.response).toMatch(/fields:\s*{\s*value1.*/);
+ });
+
+ var fileWin = function(fileEntry) {
+ ft = new FileTransfer();
+
+ var options = new FileUploadOptions();
+ options.fileKey = "file";
+ options.fileName = localFileName;
+ options.mimeType = "text/plain";
+
+ var params = new Object();
+ params.value1 = "test";
+ params.value2 = "param";
+ options.params = params;
+
+ ft.onprogress = function(e) {
+ expect(e.lengthComputable).toBe(true);
+ expect(e.total).toBeGreaterThan(0);
+ expect(e.loaded).toBeGreaterThan(0);
+ lastProgressEvent = e;
+ };
+
+ // removing options cause Android to timeout
+ ft.upload(fileEntry.fullPath, remoteFile, uploadWin, uploadFail, options);
+ };
+
+ this.after(function() {
+ deleteFile(localFileName);
+ });
+ runs(function() {
+ writeFile(localFileName, fileContents, fileWin, fileFail);
+ });
+
+ waitsForAny(uploadWin, uploadFail, fileFail);
+ runs(function() {
+ expect(lastProgressEvent).not.toBeNull('expected progress events');
+ });
+ });
+ it("should be stopped by abort() right away.", function() {
+ var remoteFile = server + "/upload";
+ var localFileName = "upload.txt";
+
+ var fileFail = createDoNotCallSpy('fileFail');
+ var uploadWin = createDoNotCallSpy('uploadWin', 'Should have been aborted');
+ var startTime;
+
+ var uploadFail = jasmine.createSpy().andCallFake(function(e) {
+ expect(e.code).toBe(FileTransferError.ABORT_ERR);
+ expect(new Date() - startTime).toBeLessThan(300);
+ });
+
+ var fileWin = function(fileEntry) {
+ ft = new FileTransfer();
+
+ var options = new FileUploadOptions();
+ options.fileKey = "file";
+ options.fileName = localFileName;
+ options.mimeType = "text/plain";
+
+ startTime = +new Date();
+ // removing options cause Android to timeout
+ ft.abort(); // should be a no-op.
+ ft.upload(fileEntry.fullPath, remoteFile, uploadWin, uploadFail, options);
+ ft.abort();
+ ft.abort(); // should be a no-op.
+ };
+
+ this.after(function() {
+ deleteFile(localFileName);
+ });
+ runs(function() {
+ writeFile(localFileName, new Array(10000).join('aborttest!'), fileWin, fileFail);
+ });
+
+ waitsForAny(uploadWin, uploadFail, fileFail);
+ });
+ it("should get http status on failure", function() {
+ var fileFail = createDoNotCallSpy('fileFail');
+ var uploadWin = createDoNotCallSpy('uploadWin');
+
+ var remoteFile = server + "/403";
+ var localFileName = "upload_expect_fail.txt";
+ var uploadFail = jasmine.createSpy().andCallFake(function(error) {
+ expect(error.http_status).toBe(403);
+ expect(error.http_status).not.toBe(401, "Ensure " + remoteFile + " is in the white list");
+ });
+
+ var fileWin = function(fileEntry) {
+ var ft = new FileTransfer();
+
+ var options = new FileUploadOptions();
+ options.fileKey="file";
+ options.fileName=fileEntry.name;
+ options.mimeType="text/plain";
+
+ ft.upload(fileEntry.fullPath, remoteFile, uploadWin, uploadFail, options);
+ };
+
+ this.after(function() {
+ deleteFile(localFileName);
+ });
+ runs(function() {
+ writeFile(localFileName, "this file should fail to upload", fileWin, fileFail);
+ });
+
+ waitsForAny(uploadWin, uploadFail, fileFail);
+ });
+ it("should handle malformed urls", function() {
+ var fileFail = createDoNotCallSpy('fileFail');
+ var uploadWin = createDoNotCallSpy('uploadWin');
+
+ var remoteFile = getMalformedUrl();
+ var localFileName = "malformed_url.txt";
+ var uploadFail = jasmine.createSpy().andCallFake(function(error) {
+ expect(error.code).toBe(FileTransferError.INVALID_URL_ERR);
+ expect(error.http_status).not.toBe(401, "Ensure " + remoteFile + " is in the white list");
+ });
+ var fileWin = function(fileEntry) {
+ var ft = new FileTransfer();
+ ft.upload(fileEntry.fullPath, remoteFile, uploadWin, uploadFail, {});
+ };
+
+ this.after(function() {
+ deleteFile(localFileName);
+ });
+ runs(function() {
+ writeFile(localFileName, "Some content", fileWin, fileFail);
+ });
+
+ waitsForAny(uploadWin, uploadFail, fileFail);
+ });
+ it("should handle unknown host", function() {
+ var fileFail = createDoNotCallSpy('fileFail');
+ var uploadWin = createDoNotCallSpy('uploadWin');
+
+ var remoteFile = "http://foobar.apache.org/robots.txt";
+ var localFileName = remoteFile.substring(remoteFile.lastIndexOf('/')+1);
+ var uploadFail = jasmine.createSpy().andCallFake(function(error) {
+ expect(error.code).toBe(FileTransferError.CONNECTION_ERR);
+ expect(error.http_status).not.toBe(401, "Ensure " + remoteFile + " is in the white list");
+ });
+ var fileWin = function(fileEntry) {
+ var ft = new FileTransfer();
+ ft.upload(fileEntry.fullPath, remoteFile, uploadWin, uploadFail, {});
+ };
+
+ this.after(function() {
+ deleteFile(localFileName);
+ });
+ runs(function() {
+ writeFile(localFileName, "# allow all", fileWin, fileFail);
+ });
+
+ waitsForAny(uploadWin, uploadFail, fileFail);
+ });
+ it("should handle missing file", function() {
+ var uploadWin = createDoNotCallSpy('uploadWin');
+
+ var remoteFile = server + "/upload";
+ var localFileName = "does_not_exist.txt";
+
+ var uploadFail = jasmine.createSpy().andCallFake(function(error) {
+ expect(error.code).toBe(FileTransferError.FILE_NOT_FOUND_ERR);
+ expect(error.http_status).not.toBe(401, "Ensure " + remoteFile + " is in the white list");
+ });
+
+ runs(function() {
+ var ft = new FileTransfer();
+ ft.upload(root.fullPath + "/" + localFileName, remoteFile, uploadWin, uploadFail);
+ });
+
+ waitsForAny(uploadWin, uploadFail);
+ });
+ it("should handle bad file path", function() {
+ var uploadWin = createDoNotCallSpy('uploadWin');
+
+ var remoteFile = server + "/upload";
+
+ var uploadFail = jasmine.createSpy().andCallFake(function(error) {
+ expect(error.code).toBe(FileTransferError.FILE_NOT_FOUND_ERR);
+ expect(error.http_status).not.toBe(401, "Ensure " + remoteFile + " is in the white list");
+ });
+
+ runs(function() {
+ var ft = new FileTransfer();
+ ft.upload("/usr/local/bad/file/path.txt", remoteFile, uploadWin, uploadFail);
+ });
+
+ waitsForAny(uploadWin, uploadFail);
+ });
+ it("should be able to set custom headers", function() {
+ var remoteFile = "http://whatheaders.com";
+ var localFileName = "upload.txt";
+
+ var fileFail = function() {};
+ var uploadFail = createDoNotCallSpy('uploadFail', "Ensure " + remoteFile + " is in the white list and that Content-Length header is being set.");
+
+ var uploadWin = jasmine.createSpy().andCallFake(function(uploadResult) {
+ expect(uploadResult.bytesSent).toBeGreaterThan(0);
+ expect(uploadResult.responseCode).toBe(200);
+ expect(uploadResult.response).toBeDefined();
+ var responseHtml = decodeURIComponent(uploadResult.response);
+ expect(responseHtml).toMatch(/CustomHeader1[\s\S]*CustomValue1/i);
+ expect(responseHtml).toMatch(/CustomHeader2[\s\S]*CustomValue2[\s\S]*CustomValue3/i, "Should allow array values");
+ });
+
+ var fileWin = function(fileEntry) {
+ ft = new FileTransfer();
+
+ var options = new FileUploadOptions();
+ options.fileKey = "file";
+ options.fileName = localFileName;
+ options.mimeType = "text/plain";
+
+ var params = new Object();
+ params.value1 = "test";
+ params.value2 = "param";
+ options.params = params;
+ options.headers = {
+ "CustomHeader1": "CustomValue1",
+ "CustomHeader2": ["CustomValue2", "CustomValue3"],
+ };
+
+ // removing options cause Android to timeout
+ ft.upload(fileEntry.fullPath, remoteFile, uploadWin, uploadFail, options);
+ };
+
+ this.after(function() {
+ deleteFile(localFileName);
+ });
+ runs(function() {
+ writeFile(localFileName, "this file should upload", fileWin, fileFail);
+ });
+
+ waitsForAny(uploadWin, uploadFail);
+ });
+ });
+});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/geolocation.tests.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/geolocation.tests.js b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/geolocation.tests.js
new file mode 100644
index 0000000..7d1d6ce
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/geolocation.tests.js
@@ -0,0 +1,119 @@
+describe('Geolocation (navigator.geolocation)', function () {
+ it("should exist", function() {
+ expect(navigator.geolocation).toBeDefined();
+ });
+
+ it("should contain a getCurrentPosition function", function() {
+ expect(typeof navigator.geolocation.getCurrentPosition).toBeDefined();
+ expect(typeof navigator.geolocation.getCurrentPosition == 'function').toBe(true);
+ });
+
+ it("should contain a watchPosition function", function() {
+ expect(typeof navigator.geolocation.watchPosition).toBeDefined();
+ expect(typeof navigator.geolocation.watchPosition == 'function').toBe(true);
+ });
+
+ it("should contain a clearWatch function", function() {
+ expect(typeof navigator.geolocation.clearWatch).toBeDefined();
+ expect(typeof navigator.geolocation.clearWatch == 'function').toBe(true);
+ });
+
+ describe('getCurrentPosition method', function() {
+ describe('error callback', function() {
+ it("should be called if we set timeout to 0 and maximumAge to a very small number", function() {
+ console.log("Here I am");
+ var win = jasmine.createSpy(),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ navigator.geolocation.getCurrentPosition(win, fail, {
+ maximumAge: 0,
+ timeout: 0
+ });
+ });
+
+ waitsFor(function () { return fail.wasCalled; }, "fail never called", 250); //small timeout as this should fire very fast
+
+ runs(function () {
+ expect(win).not.toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('success callback', function() {
+ it("should be called with a Position object", function() {
+ var win = jasmine.createSpy().andCallFake(function(p) {
+ expect(p.coords).toBeDefined();
+ expect(p.timestamp).toBeDefined();
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ navigator.geolocation.getCurrentPosition(win, fail, {
+ maximumAge:300000 // 5 minutes maximum age of cached position
+ });
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", 20000);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ });
+ });
+
+ describe('watchPosition method', function() {
+ describe('error callback', function() {
+ var errorWatch = null;
+
+ afterEach(function() {
+ navigator.geolocation.clearWatch(errorWatch);
+ });
+ it("should be called if we set timeout to 0 and maximumAge to a very small number", function() {
+ var win = jasmine.createSpy(),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ errorWatch = navigator.geolocation.watchPosition(win, fail, {
+ maximumAge: 0,
+ timeout: 0
+ });
+ });
+
+ waitsFor(function () { return fail.wasCalled; }, "fail never called", 250); // small timeout as this hsould fire very quickly
+
+ runs(function () {
+ expect(win).not.toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('success callback', function() {
+ var successWatch = null;
+
+ afterEach(function() {
+ navigator.geolocation.clearWatch(successWatch);
+ });
+ it("should be called with a Position object", function() {
+ var win = jasmine.createSpy().andCallFake(function(p) {
+ expect(p.coords).toBeDefined();
+ expect(p.timestamp).toBeDefined();
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ successWatch = navigator.geolocation.watchPosition(win, fail, {
+ maximumAge:(5 * 60 * 1000) // 5 minutes maximum age of cached position
+ });
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", 20000);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ });
+ });
+});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/globalization.tests.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/globalization.tests.js b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/globalization.tests.js
new file mode 100644
index 0000000..6903aee
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/globalization.tests.js
@@ -0,0 +1,808 @@
+describe('Globalization (navigator.globalization)', function () {
+ it("should exist", function() {
+ expect(navigator.globalization).toBeDefined();
+ });
+
+ describe("getLocaleName", function() {
+ it("should exist", function() {
+ expect(typeof navigator.globalization.getLocaleName).toBeDefined();
+ expect(typeof navigator.globalization.getLocaleName == 'function').toBe(true);
+ });
+ it("getLocaleName success callback should be called with a Properties object", function() {
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a).toBeDefined();
+ expect(typeof a).toBe('object');
+ expect(a.value).toBeDefined();
+ expect(typeof a.value).toBe('string');
+ expect(a.value.length > 0).toBe(true);
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ navigator.globalization.getLocaleName(win, fail);
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe("dateToString", function() {
+ it("should exist", function() {
+ expect(typeof navigator.globalization.dateToString).toBeDefined();
+ expect(typeof navigator.globalization.dateToString == 'function').toBe(true);
+ });
+ it("dateToString using default options, success callback should be called with a Properties object", function() {
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a).toBeDefined();
+ expect(typeof a).toBe('object');
+ expect(a.value).toBeDefined();
+ expect(typeof a.value).toBe('string');
+ expect(a.value.length > 0).toBe(true);
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ navigator.globalization.dateToString(new Date(), win, fail);
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ it("dateToString using formatLength=short and selector=date options, success callback should be called with a Properties object", function() {
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a).toBeDefined();
+ expect(typeof a).toBe('object');
+ expect(a.value).toBeDefined();
+ expect(typeof a.value).toBe('string');
+ expect(a.value.length > 0).toBe(true);
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ navigator.globalization.dateToString(new Date(), win, fail, {formatLength: 'short', selector: 'date'});
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ it("dateToString using formatLength=full and selector=date options, success callback should be called with a Properties object", function() {
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a).toBeDefined();
+ expect(typeof a).toBe('object');
+ expect(a.value).toBeDefined();
+ expect(typeof a.value).toBe('string');
+ expect(a.value.length > 0).toBe(true);
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ navigator.globalization.dateToString(new Date(), win, fail, {formatLength: 'full', selector: 'date'});
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ it("dateToString using formatLength=medium and selector=date and time(default) options, success callback should be called with a Properties object", function() {
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a).toBeDefined();
+ expect(typeof a).toBe('object');
+ expect(a.value).toBeDefined();
+ expect(typeof a.value).toBe('string');
+ expect(a.value.length > 0).toBe(true);
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ navigator.globalization.dateToString(new Date(), win, fail, {formatLength: 'medium'});
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ it("dateToString using formatLength=long and selector=date and time(default) options, success callback should be called with a Properties object", function() {
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a).toBeDefined();
+ expect(typeof a).toBe('object');
+ expect(a.value).toBeDefined();
+ expect(typeof a.value).toBe('string');
+ expect(a.value.length > 0).toBe(true);
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ navigator.globalization.dateToString(new Date(), win, fail, {formatLength: 'long'});
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ it("dateToString using formatLength=full and selector=date and time(default) options, success callback should be called with a Properties object", function() {
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a).toBeDefined();
+ expect(typeof a).toBe('object');
+ expect(a.value).toBeDefined();
+ expect(typeof a.value).toBe('string');
+ expect(a.value.length > 0).toBe(true);
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ navigator.globalization.dateToString(new Date(), win, fail, {formatLength: 'full'});
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe("stringToDate", function() {
+ it("should exist", function() {
+ expect(typeof navigator.globalization.stringToDate).toBeDefined();
+ expect(typeof navigator.globalization.stringToDate == 'function').toBe(true);
+ });
+ it("stringToDate using default options, success callback should be called with a Properties object", function() {
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a).toBeDefined();
+ expect(typeof a).toBe('object');
+ expect(a.year).toBeDefined();
+ expect(typeof a.year).toBe('number');
+ expect(a.year >= 0 && a.year <=9999).toBe(true);
+ expect(a.month).toBeDefined();
+ expect(typeof a.month).toBe('number');
+ expect(a.month >= 0 && a.month <=11).toBe(true);
+ expect(a.day).toBeDefined();
+ expect(typeof a.day).toBe('number');
+ expect(a.day >= 1 && a.day <=31).toBe(true);
+ expect(a.hour).toBeDefined();
+ expect(typeof a.hour).toBe('number');
+ expect(a.hour >= 0 && a.hour <=23).toBe(true);
+ expect(a.minute).toBeDefined();
+ expect(typeof a.minute).toBe('number');
+ expect(a.minute >= 0 && a.minute <=59).toBe(true);
+ expect(a.second).toBeDefined();
+ expect(typeof a.second).toBe('number');
+ expect(a.second >= 0 && a.second <=59).toBe(true);
+ expect(a.millisecond).toBeDefined();
+ expect(typeof a.millisecond).toBe('number');
+ }),
+ fail = jasmine.createSpy();
+
+ var win2 = function(a) {
+ navigator.globalization.stringToDate(a.value, win, fail);
+ };
+
+ runs(function () {
+ navigator.globalization.dateToString(new Date(), win2, fail);
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ it("stringToDate using formatLength=short and selector=date options, success callback should be called with a Properties object", function() {
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a).toBeDefined();
+ expect(typeof a).toBe('object');
+ expect(a.year).toBeDefined();
+ expect(typeof a.year).toBe('number');
+ expect(a.year >= 0 && a.year <=9999).toBe(true);
+ expect(a.month).toBeDefined();
+ expect(typeof a.month).toBe('number');
+ expect(a.month >= 0 && a.month <=11).toBe(true);
+ expect(a.day).toBeDefined();
+ expect(typeof a.day).toBe('number');
+ expect(a.day >= 1 && a.day <=31).toBe(true);
+ expect(a.hour).toBeDefined();
+ expect(typeof a.hour).toBe('number');
+ expect(a.hour >= 0 && a.hour <=23).toBe(true);
+ expect(a.minute).toBeDefined();
+ expect(typeof a.minute).toBe('number');
+ expect(a.minute >= 0 && a.minute <=59).toBe(true);
+ expect(a.second).toBeDefined();
+ expect(typeof a.second).toBe('number');
+ expect(a.second >= 0 && a.second <=59).toBe(true);
+ expect(a.millisecond).toBeDefined();
+ expect(typeof a.millisecond).toBe('number');
+ }),
+ fail = jasmine.createSpy();
+
+ var win2 = function(a) {
+ navigator.globalization.stringToDate(a.value, win, fail, {formatLength: 'short', selector: 'date'});
+ };
+
+ runs(function () {
+ navigator.globalization.dateToString(new Date(), win2, fail, {formatLength: 'short', selector: 'date'});
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ it("stringToDate using formatLength=full and selector=date options, success callback should be called with a Properties object", function() {
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a).toBeDefined();
+ expect(typeof a).toBe('object');
+ expect(a.year).toBeDefined();
+ expect(typeof a.year).toBe('number');
+ expect(a.year >= 0 && a.year <=9999).toBe(true);
+ expect(a.month).toBeDefined();
+ expect(typeof a.month).toBe('number');
+ expect(a.month >= 0 && a.month <=11).toBe(true);
+ expect(a.day).toBeDefined();
+ expect(typeof a.day).toBe('number');
+ expect(a.day >= 1 && a.day <=31).toBe(true);
+ expect(a.hour).toBeDefined();
+ expect(typeof a.hour).toBe('number');
+ expect(a.hour >= 0 && a.hour <=23).toBe(true);
+ expect(a.minute).toBeDefined();
+ expect(typeof a.minute).toBe('number');
+ expect(a.minute >= 0 && a.minute <=59).toBe(true);
+ expect(a.second).toBeDefined();
+ expect(typeof a.second).toBe('number');
+ expect(a.second >= 0 && a.second <=59).toBe(true);
+ expect(a.millisecond).toBeDefined();
+ expect(typeof a.millisecond).toBe('number');
+ }),
+ fail = jasmine.createSpy();
+
+ var win2 = function(a) {
+ navigator.globalization.stringToDate(a.value, win, fail, {formatLength: 'full', selector: 'date'});
+ };
+ runs(function () {
+ navigator.globalization.dateToString(new Date(), win2, fail, {formatLength: 'full', selector: 'date'});
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ it("stringToDate using invalid date, error callback should be called with a GlobalizationError object", function() {
+ var win = jasmine.createSpy(),
+ fail = jasmine.createSpy().andCallFake(function(a) {
+ expect(a).toBeDefined();
+ expect(typeof a).toBe('object');
+ expect(a.code).toBeDefined();
+ expect(typeof a.code).toBe('number');
+ expect(a.code === GlobalizationError.PARSING_ERROR).toBe(true);
+ expect(a.message).toBeDefined();
+ expect(typeof a.message).toBe('string');
+ expect(a.message !== "").toBe(true);
+ });
+
+ runs(function () {
+ navigator.globalization.stringToDate('notADate', win, fail, {selector:'foobar'});
+ });
+
+ waitsFor(function () { return fail.wasCalled; }, "fail never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(win).not.toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe("getDatePattern", function() {
+ it("should exist", function() {
+ expect(typeof navigator.globalization.getDatePattern).toBeDefined();
+ expect(typeof navigator.globalization.getDatePattern == 'function').toBe(true);
+ });
+ it("getDatePattern using default options, success callback should be called with a Properties object", function() {
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a).toBeDefined();
+ expect(typeof a).toBe('object');
+ expect(a.pattern).toBeDefined();
+ expect(typeof a.pattern).toBe('string');
+ expect(a.pattern.length > 0).toBe(true);
+ expect(a.timezone).toBeDefined();
+ expect(typeof a.timezone).toBe('string');
+ expect(a.timezone.length > 0).toBe(true);
+ expect(a.utc_offset).toBeDefined();
+ expect(typeof a.utc_offset).toBe('number');
+ expect(a.dst_offset).toBeDefined();
+ expect(typeof a.dst_offset).toBe('number');
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ navigator.globalization.getDatePattern(win, fail);
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ it("getDatePattern using formatLength=medium and selector=date options, success callback should be called with a Properties object", function() {
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a).toBeDefined();
+ expect(typeof a).toBe('object');
+ expect(a.pattern).toBeDefined();
+ expect(typeof a.pattern).toBe('string');
+ expect(a.pattern.length > 0).toBe(true);
+ expect(a.timezone).toBeDefined();
+ expect(typeof a.timezone).toBe('string');
+ expect(a.timezone.length > 0).toBe(true);
+ expect(a.utc_offset).toBeDefined();
+ expect(typeof a.utc_offset).toBe('number');
+ expect(a.dst_offset).toBeDefined();
+ expect(typeof a.dst_offset).toBe('number');
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ navigator.globalization.getDatePattern(win, fail, {formatLength: 'medium', selector: 'date'});
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe("getDateNames", function() {
+ it("should exist", function() {
+ expect(typeof navigator.globalization.getDateNames).toBeDefined();
+ expect(typeof navigator.globalization.getDateNames == 'function').toBe(true);
+ });
+ it("getDateNames using default options, success callback should be called with a Properties object", function() {
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a).toBeDefined();
+ expect(typeof a).toBe('object');
+ expect(a.value).toBeDefined();
+ expect(a.value instanceof Array).toBe(true);
+ expect(a.value.length > 0).toBe(true);
+ expect(typeof a.value[0]).toBe('string');
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ navigator.globalization.getDateNames(win, fail);
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ it("getDateNames using type=narrow and item=days options, success callback should be called with a Properties object", function() {
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a).toBeDefined();
+ expect(typeof a).toBe('object');
+ expect(a.value).toBeDefined();
+ expect(a.value instanceof Array).toBe(true);
+ expect(a.value.length > 0).toBe(true);
+ expect(typeof a.value[0]).toBe('string');
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ navigator.globalization.getDateNames(win, fail, {type: 'narrow', item: 'days'});
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ it("getDateNames using type=narrow and item=months options, success callback should be called with a Properties object", function() {
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a).toBeDefined();
+ expect(typeof a).toBe('object');
+ expect(a.value).toBeDefined();
+ expect(a.value instanceof Array).toBe(true);
+ expect(a.value.length > 0).toBe(true);
+ expect(typeof a.value[0]).toBe('string');
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ navigator.globalization.getDateNames(win, fail, {type: 'narrow', item: 'months'});
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ it("getDateNames using type=wide and item=days options, success callback should be called with a Properties object", function() {
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a).toBeDefined();
+ expect(typeof a).toBe('object');
+ expect(a.value).toBeDefined();
+ expect(a.value instanceof Array).toBe(true);
+ expect(a.value.length > 0).toBe(true);
+ expect(typeof a.value[0]).toBe('string');
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ navigator.globalization.getDateNames(win, fail, {item: 'days'});
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ it("getDateNames using type=wide and item=months options, success callback should be called with a Properties object", function() {
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a).toBeDefined();
+ expect(typeof a).toBe('object');
+ expect(a.value).toBeDefined();
+ expect(a.value instanceof Array).toBe(true);
+ expect(a.value.length > 0).toBe(true);
+ expect(typeof a.value[0]).toBe('string');
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ navigator.globalization.getDateNames(win, fail, {item: 'months'});
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe("isDayLightSavingsTime", function() {
+ it("should exist", function() {
+ expect(typeof navigator.globalization.isDayLightSavingsTime).toBeDefined();
+ expect(typeof navigator.globalization.isDayLightSavingsTime == 'function').toBe(true);
+ });
+ it("isDayLightSavingsTime using default options, success callback should be called with a Properties object", function() {
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a).toBeDefined();
+ expect(typeof a).toBe('object');
+ expect(a.dst).toBeDefined();
+ expect(typeof a.dst).toBe('boolean');
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ navigator.globalization.isDayLightSavingsTime(new Date(), win, fail);
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe("getFirstDayOfWeek", function() {
+ it("should exist", function() {
+ expect(typeof navigator.globalization.getFirstDayOfWeek).toBeDefined();
+ expect(typeof navigator.globalization.getFirstDayOfWeek == 'function').toBe(true);
+ });
+ it("getFirstDayOfWeek success callback should be called with a Properties object", function() {
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a).toBeDefined();
+ expect(typeof a).toBe('object');
+ expect(a.value).toBeDefined();
+ expect(typeof a.value).toBe('number');
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ navigator.globalization.getFirstDayOfWeek(win, fail);
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe("numberToString", function() {
+ it("should exist", function() {
+ expect(typeof navigator.globalization.numberToString).toBeDefined();
+ expect(typeof navigator.globalization.numberToString == 'function').toBe(true);
+ });
+ it("numberToString using default options, should be called with a Properties object", function() {
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a).toBeDefined();
+ expect(typeof a).toBe('object');
+ expect(a.value).toBeDefined();
+ expect(typeof a.value).toBe('string');
+ expect(a.value.length > 0).toBe(true);
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ navigator.globalization.numberToString(3.25, win, fail);
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ it("numberToString using type=percent options, should be called with a Properties object", function() {
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a).toBeDefined();
+ expect(typeof a).toBe('object');
+ expect(a.value).toBeDefined();
+ expect(typeof a.value).toBe('string');
+ expect(a.value.length > 0).toBe(true);
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ navigator.globalization.numberToString(.25, win, fail, {type: 'percent'});
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ it("numberToString using type=currency options, should be called with a Properties object", function() {
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a).toBeDefined();
+ expect(typeof a).toBe('object');
+ expect(a.value).toBeDefined();
+ expect(typeof a.value).toBe('string');
+ expect(a.value.length > 0).toBe(true);
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ navigator.globalization.numberToString(5.20, win, fail, {type: 'currency'});
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe("stringToNumber", function() {
+ it("should exist", function() {
+ expect(typeof navigator.globalization.stringToNumber).toBeDefined();
+ expect(typeof navigator.globalization.stringToNumber == 'function').toBe(true);
+ });
+ it("stringToNumber using default options, should be called with a Properties object", function() {
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a).toBeDefined();
+ expect(typeof a).toBe('object');
+ expect(a.value).toBeDefined();
+ expect(typeof a.value).toBe('number');
+ expect(a.value > 0).toBe(true);
+ }),
+ fail = jasmine.createSpy();
+
+ var win2 = function(a) {
+ navigator.globalization.stringToNumber(a.value, win, fail);
+ };
+
+ runs(function () {
+ navigator.globalization.numberToString(3.25, win2, fail);
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ it("stringToNumber using type=percent options, should be called with a Properties object", function() {
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a).toBeDefined();
+ expect(typeof a).toBe('object');
+ expect(a.value).toBeDefined();
+ expect(typeof a.value).toBe('number');
+ expect(a.value > 0).toBe(true);
+ }),
+ fail = jasmine.createSpy();
+
+ var win2 = function(a) {
+ navigator.globalization.stringToNumber(a.value, win, fail, {type: 'percent'});
+ };
+
+ runs(function () {
+ navigator.globalization.numberToString(.25, win2, fail, {type: 'percent'});
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe("getNumberPattern", function() {
+ it("should exist", function() {
+ expect(typeof navigator.globalization.getNumberPattern).toBeDefined();
+ expect(typeof navigator.globalization.getNumberPattern == 'function').toBe(true);
+ });
+ it("getNumberPattern using default options, success callback should be called with a Properties object", function() {
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a).toBeDefined();
+ expect(typeof a).toBe('object');
+ expect(a.pattern).toBeDefined();
+ expect(typeof a.pattern).toBe('string');
+ expect(a.pattern.length > 0).toBe(true);
+ expect(typeof a.symbol).toBe('string');
+ expect(typeof a.fraction).toBe('number');
+ expect(typeof a.rounding).toBe('number');
+ expect(a.positive).toBeDefined();
+ expect(typeof a.positive).toBe('string');
+ expect(a.positive.length >= 0).toBe(true);
+ expect(a.negative).toBeDefined();
+ expect(typeof a.negative).toBe('string');
+ expect(a.negative.length >= 0).toBe(true);
+ expect(a.decimal).toBeDefined();
+ expect(typeof a.decimal).toBe('string');
+ expect(a.decimal.length > 0).toBe(true);
+ expect(a.grouping).toBeDefined();
+ expect(typeof a.grouping).toBe('string');
+ expect(a.grouping.length > 0).toBe(true);
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ navigator.globalization.getNumberPattern(win, fail);
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ it("getNumberPattern using type=percent, success callback should be called with a Properties object", function() {
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a).toBeDefined();
+ expect(typeof a).toBe('object');
+ expect(a.pattern).toBeDefined();
+ expect(typeof a.pattern).toBe('string');
+ expect(a.pattern.length > 0).toBe(true);
+ expect(typeof a.symbol).toBe('string');
+ expect(typeof a.fraction).toBe('number');
+ expect(typeof a.rounding).toBe('number');
+ expect(a.positive).toBeDefined();
+ expect(typeof a.positive).toBe('string');
+ expect(a.positive.length >= 0).toBe(true);
+ expect(a.negative).toBeDefined();
+ expect(typeof a.negative).toBe('string');
+ expect(a.negative.length >= 0).toBe(true);
+ expect(a.decimal).toBeDefined();
+ expect(typeof a.decimal).toBe('string');
+ expect(a.decimal.length > 0).toBe(true);
+ expect(a.grouping).toBeDefined();
+ expect(typeof a.grouping).toBe('string');
+ expect(a.grouping.length > 0).toBe(true);
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ navigator.globalization.getNumberPattern(win, fail, {type: 'percent'});
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ it("getNumberPattern using type=currency, success callback should be called with a Properties object", function() {
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a).toBeDefined();
+ expect(typeof a).toBe('object');
+ expect(a.pattern).toBeDefined();
+ expect(typeof a.pattern).toBe('string');
+ expect(a.pattern.length > 0).toBe(true);
+ expect(typeof a.symbol).toBe('string');
+ expect(typeof a.fraction).toBe('number');
+ expect(typeof a.rounding).toBe('number');
+ expect(a.positive).toBeDefined();
+ expect(typeof a.positive).toBe('string');
+ expect(a.positive.length >= 0).toBe(true);
+ expect(a.negative).toBeDefined();
+ expect(typeof a.negative).toBe('string');
+ expect(a.negative.length >= 0).toBe(true);
+ expect(a.decimal).toBeDefined();
+ expect(typeof a.decimal).toBe('string');
+ expect(a.decimal.length > 0).toBe(true);
+ expect(a.grouping).toBeDefined();
+ expect(typeof a.grouping).toBe('string');
+ expect(a.grouping.length > 0).toBe(true);
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ navigator.globalization.getNumberPattern(win, fail, {type: 'currency'});
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe("getCurrencyPattern", function() {
+ it("should exist", function() {
+ expect(typeof navigator.globalization.getCurrencyPattern).toBeDefined();
+ expect(typeof navigator.globalization.getCurrencyPattern == 'function').toBe(true);
+ });
+ it("getCurrencyPattern using EUR for currency, success callback should be called with a Properties object", function() {
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a).toBeDefined();
+ expect(typeof a).toBe('object');
+ expect(a.pattern).toBeDefined();
+ expect(typeof a.pattern).toBe('string');
+ expect(a.pattern.length > 0).toBe(true);
+ expect(a.code).toBeDefined();
+ expect(typeof a.code).toBe('string');
+ expect(a.code.length > 0).toBe(true);
+ expect(typeof a.fraction).toBe('number');
+ expect(typeof a.rounding).toBe('number');
+ expect(a.decimal).toBeDefined();
+ expect(typeof a.decimal).toBe('string');
+ expect(a.decimal.length >= 0).toBe(true);
+ expect(a.grouping).toBeDefined();
+ expect(typeof a.grouping).toBe('string');
+ expect(a.grouping.length >= 0).toBe(true);
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ navigator.globalization.getCurrencyPattern("EUR", win, fail);
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ });
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/media.tests.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/media.tests.js b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/media.tests.js
new file mode 100644
index 0000000..d0e6c4f
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/media.tests.js
@@ -0,0 +1,144 @@
+describe('Media', function () {
+ it("should exist", function() {
+ expect(Media).toBeDefined();
+ expect(typeof Media).toBe("function");
+ });
+
+ it("should have the following properties", function() {
+ var media1 = new Media("dummy");
+ expect(media1.id).toBeDefined();
+ expect(media1.src).toBeDefined();
+ expect(media1._duration).toBeDefined();
+ expect(media1._position).toBeDefined();
+ media1.release();
+ });
+
+ it("should define constants for Media errors", function() {
+ expect(MediaError).toBeDefined();
+ expect(MediaError.MEDIA_ERR_NONE_ACTIVE).toBe(0);
+ expect(MediaError.MEDIA_ERR_ABORTED).toBe(1);
+ expect(MediaError.MEDIA_ERR_NETWORK).toBe(2);
+ expect(MediaError.MEDIA_ERR_DECODE).toBe(3);
+ expect(MediaError.MEDIA_ERR_NONE_SUPPORTED).toBe(4);
+ });
+
+ it("should contain a play function", function() {
+ var media1 = new Media();
+ expect(media1.play).toBeDefined();
+ expect(typeof media1.play).toBe('function');
+ media1.release();
+ });
+
+ it("should contain a stop function", function() {
+ var media1 = new Media();
+ expect(media1.stop).toBeDefined();
+ expect(typeof media1.stop).toBe('function');
+ media1.release();
+ });
+
+ it("should contain a seekTo function", function() {
+ var media1 = new Media();
+ expect(media1.seekTo).toBeDefined();
+ expect(typeof media1.seekTo).toBe('function');
+ media1.release();
+ });
+
+ it("should contain a pause function", function() {
+ var media1 = new Media();
+ expect(media1.pause).toBeDefined();
+ expect(typeof media1.pause).toBe('function');
+ media1.release();
+ });
+
+ it("should contain a getDuration function", function() {
+ var media1 = new Media();
+ expect(media1.getDuration).toBeDefined();
+ expect(typeof media1.getDuration).toBe('function');
+ media1.release();
+ });
+
+ it("should contain a getCurrentPosition function", function() {
+ var media1 = new Media();
+ expect(media1.getCurrentPosition).toBeDefined();
+ expect(typeof media1.getCurrentPosition).toBe('function');
+ media1.release();
+ });
+
+ it("should contain a startRecord function", function() {
+ var media1 = new Media();
+ expect(media1.startRecord).toBeDefined();
+ expect(typeof media1.startRecord).toBe('function');
+ media1.release();
+ });
+
+ it("should contain a stopRecord function", function() {
+ var media1 = new Media();
+ expect(media1.stopRecord).toBeDefined();
+ expect(typeof media1.stopRecord).toBe('function');
+ media1.release();
+ });
+
+ it("should contain a release function", function() {
+ var media1 = new Media();
+ expect(media1.release).toBeDefined();
+ expect(typeof media1.release).toBe('function');
+ media1.release();
+ });
+
+ it("should contain a setVolume function", function() {
+ var media1 = new Media();
+ expect(media1.setVolume).toBeDefined();
+ expect(typeof media1.setVolume).toBe('function');
+ media1.release();
+ });
+
+ it("should return MediaError for bad filename", function() {
+ var badMedia = null,
+ win = jasmine.createSpy(),
+ fail = jasmine.createSpy().andCallFake(function (result) {
+ expect(result).toBeDefined();
+ expect(result.code).toBe(MediaError.MEDIA_ERR_ABORTED);
+ });
+
+ runs(function () {
+ badMedia = new Media("invalid.file.name", win,fail);
+ badMedia.play();
+ });
+
+ waitsFor(function () { return fail.wasCalled; }, Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(win).not.toHaveBeenCalled();
+ badMedia.release();
+ });
+ });
+
+ it("position should be set properly", function() {
+ var media1 = new Media("http://audio.ibeat.org/content/p1rj1s/p1rj1s_-_rockGuitar.mp3"),
+ test = jasmine.createSpy().andCallFake(function(position) {
+ console.log("position = " + position);
+ expect(position).toBeGreaterThan(0.0);
+ media1.stop()
+ media1.release();
+ });
+
+ media1.play();
+
+ waits(5000);
+
+ runs(function () {
+ media1.getCurrentPosition(test, function () {});
+ });
+
+ waitsFor(function () { return test.wasCalled; }, Tests.TEST_TIMEOUT);
+ });
+
+ it("duration should be set properly", function() {
+ var media1 = new Media("http://audio.ibeat.org/content/p1rj1s/p1rj1s_-_rockGuitar.mp3");
+ media1.play();
+ waits(5000);
+ runs(function () {
+ expect(media1.getDuration()).toBeGreaterThan(0.0);
+ });
+ });
+});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/network.tests.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/network.tests.js b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/network.tests.js
new file mode 100644
index 0000000..780097f
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/network.tests.js
@@ -0,0 +1,25 @@
+describe('Network (navigator.network)', function () {
+ it("should exist", function() {
+ expect(navigator.network).toBeDefined();
+ });
+
+ describe('Network Information API', function () {
+ it("connection should exist", function() {
+ expect(navigator.network.connection).toBeDefined();
+ });
+
+ it("should contain connection properties", function() {
+ expect(navigator.network.connection.type).toBeDefined();
+ });
+
+ it("should define constants for connection status", function() {
+ expect(Connection.UNKNOWN).toBe("unknown");
+ expect(Connection.ETHERNET).toBe("ethernet");
+ expect(Connection.WIFI).toBe("wifi");
+ expect(Connection.CELL_2G).toBe("2g");
+ expect(Connection.CELL_3G).toBe("3g");
+ expect(Connection.CELL_4G).toBe("4g");
+ expect(Connection.NONE).toBe("none");
+ });
+ });
+});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/notification.tests.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/notification.tests.js b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/notification.tests.js
new file mode 100644
index 0000000..61c795d
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/notification.tests.js
@@ -0,0 +1,20 @@
+describe('Notification (navigator.notification)', function () {
+ it("should exist", function() {
+ expect(navigator.notification).toBeDefined();
+ });
+
+ it("should contain a vibrate function", function() {
+ expect(typeof navigator.notification.vibrate).toBeDefined();
+ expect(typeof navigator.notification.vibrate).toBe("function");
+ });
+
+ it("should contain a beep function", function() {
+ expect(typeof navigator.notification.beep).toBeDefined();
+ expect(typeof navigator.notification.beep).toBe("function");
+ });
+
+ it("should contain a alert function", function() {
+ expect(typeof navigator.notification.alert).toBeDefined();
+ expect(typeof navigator.notification.alert).toBe("function");
+ });
+});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/platform.tests.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/platform.tests.js b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/platform.tests.js
new file mode 100644
index 0000000..f44fcb3
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/platform.tests.js
@@ -0,0 +1,10 @@
+describe('Platform (cordova)', function () {
+ it("should exist", function() {
+ expect(cordova).toBeDefined();
+ });
+
+ it("exec method should exist", function() {
+ expect(cordova.exec).toBeDefined();
+ expect(typeof cordova.exec).toBe('function');
+ });
+});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/storage.tests.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/storage.tests.js b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/storage.tests.js
new file mode 100644
index 0000000..08ea608
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/storage.tests.js
@@ -0,0 +1,174 @@
+describe("Session Storage", function () {
+ it("should exist", function () {
+ expect(window.sessionStorage).toBeDefined();
+ expect(typeof window.sessionStorage.length).not.toBe('undefined');
+ expect(typeof(window.sessionStorage.key)).toBe('function');
+ expect(typeof(window.sessionStorage.getItem)).toBe('function');
+ expect(typeof(window.sessionStorage.setItem)).toBe('function');
+ expect(typeof(window.sessionStorage.removeItem)).toBe('function');
+ expect(typeof(window.sessionStorage.clear)).toBe('function');
+ });
+
+ it("check length", function () {
+ expect(window.sessionStorage.length).toBe(0);
+ window.sessionStorage.setItem("key","value");
+ expect(window.sessionStorage.length).toBe(1);
+ window.sessionStorage.removeItem("key");
+ expect(window.sessionStorage.length).toBe(0);
+ });
+
+ it("check key", function () {
+ expect(window.sessionStorage.key(0)).toBe(null);
+ window.sessionStorage.setItem("test","value");
+ expect(window.sessionStorage.key(0)).toBe("test");
+ window.sessionStorage.removeItem("test");
+ expect(window.sessionStorage.key(0)).toBe(null);
+ });
+
+ it("check getItem", function() {
+ expect(window.sessionStorage.getItem("item")).toBe(null);
+ window.sessionStorage.setItem("item","value");
+ expect(window.sessionStorage.getItem("item")).toBe("value");
+ window.sessionStorage.removeItem("item");
+ expect(window.sessionStorage.getItem("item")).toBe(null);
+ });
+
+ it("check setItem", function() {
+ expect(window.sessionStorage.getItem("item")).toBe(null);
+ window.sessionStorage.setItem("item","value");
+ expect(window.sessionStorage.getItem("item")).toBe("value");
+ window.sessionStorage.setItem("item","newval");
+ expect(window.sessionStorage.getItem("item")).toBe("newval");
+ window.sessionStorage.removeItem("item");
+ expect(window.sessionStorage.getItem("item")).toBe(null);
+ });
+
+ it("can remove an item", function () {
+ expect(window.sessionStorage.getItem("item")).toBe(null);
+ window.sessionStorage.setItem("item","value");
+ expect(window.sessionStorage.getItem("item")).toBe("value");
+ window.sessionStorage.removeItem("item");
+ expect(window.sessionStorage.getItem("item")).toBe(null);
+ });
+
+ it("check clear", function() {
+ window.sessionStorage.setItem("item1","value");
+ window.sessionStorage.setItem("item2","value");
+ window.sessionStorage.setItem("item3","value");
+ expect(window.sessionStorage.length).toBe(3);
+ window.sessionStorage.clear();
+ expect(window.sessionStorage.length).toBe(0);
+ });
+
+ it("check dot notation", function() {
+ expect(window.sessionStorage.item).not.toBeDefined();
+ window.sessionStorage.item = "value";
+ expect(window.sessionStorage.item).toBe("value");
+ window.sessionStorage.removeItem("item");
+ expect(window.sessionStorage.item).not.toBeDefined();
+ });
+
+ describe("Local Storage", function () {
+ it("should exist", function() {
+ expect(window.localStorage).toBeDefined();
+ expect(window.localStorage.length).toBeDefined();
+ expect(typeof window.localStorage.key).toBe("function");
+ expect(typeof window.localStorage.getItem).toBe("function");
+ expect(typeof window.localStorage.setItem).toBe("function");
+ expect(typeof window.localStorage.removeItem).toBe("function");
+ expect(typeof window.localStorage.clear).toBe("function");
+ });
+
+ it("check length", function() {
+ expect(window.localStorage.length).toBe(0);
+ window.localStorage.setItem("key","value");
+ expect(window.localStorage.length).toBe(1);
+ window.localStorage.removeItem("key");
+ expect(window.localStorage.length).toBe(0);
+ });
+
+ it("check key", function() {
+ expect(window.localStorage.key(0)).toBe(null);
+ window.localStorage.setItem("test","value");
+ expect(window.localStorage.key(0)).toBe("test");
+ window.localStorage.removeItem("test");
+ expect(window.localStorage.key(0)).toBe(null);
+ });
+
+ it("check getItem", function() {
+ expect(window.localStorage.getItem("item")).toBe(null);
+ window.localStorage.setItem("item","value");
+ expect(window.localStorage.getItem("item")).toBe("value");
+ window.localStorage.removeItem("item");
+ expect(window.localStorage.getItem("item")).toBe(null);
+ });
+
+ it("check setItem", function() {
+ expect(window.localStorage.getItem("item")).toBe(null);
+ window.localStorage.setItem("item","value");
+ expect(window.localStorage.getItem("item")).toBe("value");
+ window.localStorage.setItem("item","newval");
+ expect(window.localStorage.getItem("item")).toBe("newval");
+ window.localStorage.removeItem("item");
+ expect(window.localStorage.getItem("item")).toBe(null);
+ });
+
+ it("check removeItem", function() {
+ expect(window.localStorage.getItem("item")).toBe(null);
+ window.localStorage.setItem("item","value");
+ expect(window.localStorage.getItem("item")).toBe("value");
+ window.localStorage.removeItem("item");
+ expect(window.localStorage.getItem("item")).toBe(null);
+ });
+
+ it("check clear", function() {
+ expect(window.localStorage.getItem("item1")).toBe(null);
+ expect(window.localStorage.getItem("item2")).toBe(null);
+ expect(window.localStorage.getItem("item3")).toBe(null);
+ window.localStorage.setItem("item1","value");
+ window.localStorage.setItem("item2","value");
+ window.localStorage.setItem("item3","value");
+ expect(window.localStorage.getItem("item1")).toBe("value");
+ expect(window.localStorage.getItem("item2")).toBe("value");
+ expect(window.localStorage.getItem("item3")).toBe("value");
+ expect(window.localStorage.length).toBe(3);
+ window.localStorage.clear();
+ expect(window.localStorage.length).toBe(0);
+ expect(window.localStorage.getItem("item1")).toBe(null);
+ expect(window.localStorage.getItem("item2")).toBe(null);
+ expect(window.localStorage.getItem("item3")).toBe(null);
+ });
+
+ it("check dot notation", function() {
+ expect(window.localStorage.item).not.toBeDefined();
+ window.localStorage.item = "value";
+ expect(window.localStorage.item).toBe("value");
+ window.localStorage.removeItem("item");
+ expect(window.localStorage.item).not.toBeDefined();
+ });
+ });
+
+ describe("HTML 5 Storage", function () {
+ it("should exist", function() {
+ expect(window.openDatabase).toBeDefined();
+ });
+
+ it("Should be able to create and drop tables", function() {
+ var win = jasmine.createSpy('win');
+ var fail1 = createDoNotCallSpy('fail1');
+ var fail2 = createDoNotCallSpy('fail2');
+ var db = openDatabase("Database", "1.0", "HTML5 Database API example", 5*1024*1024);
+ db.transaction(function(t) {
+ t.executeSql('CREATE TABLE IF NOT EXISTS foo(id int, name varchar(255));');
+ t.executeSql('CREATE TABLE IF NOT EXISTS foo2(id int, name varchar(255));');
+ }, fail1, step2);
+ function step2() {
+ db.transaction(function(t) {
+ t.executeSql('DROP TABLE foo;');
+ t.executeSql('DROP TABLE foo2');
+ }, fail2, win);
+ }
+ waitsForAny(win, fail1, fail2);
+ });
+ });
+});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/battery/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/battery/index.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/battery/index.html
new file mode 100644
index 0000000..394988c
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/battery/index.html
@@ -0,0 +1,96 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width,height=device-height,user-scalable=no,maximum-scale=1.0,initial-scale=1.0" />
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8"> <!-- ISO-8859-1 -->
+ <title>Cordova Mobile Spec</title>
+ <link rel="stylesheet" href="../master.css" type="text/css" media="screen" title="no title" charset="utf-8">
+ <script type="text/javascript" charset="utf-8" src="../cordova.js"></script>
+
+
+<script type="text/javascript" charset="utf-8">
+
+ var deviceReady = false;
+
+ /**
+ * Function called when page has finished loading.
+ */
+ function init() {
+ document.addEventListener("deviceready", function() {
+ deviceReady = true;
+ console.log("Device="+device.platform+" "+device.version);
+ }, false);
+ window.setTimeout(function() {
+ if (!deviceReady) {
+ alert("Error: PhoneGap did not initialize. Demo will not run correctly.");
+ }
+ },1000);
+ }
+
+ /* Battery */
+ function updateInfo(info) {
+ document.getElementById('level').innerText = info.level;
+ document.getElementById('isPlugged').innerText = info.isPlugged;
+ if (info.level > 5) {
+ document.getElementById('crit').innerText = "false";
+ }
+ if (info.level > 20) {
+ document.getElementById('low').innerText = "false";
+ }
+ }
+
+ function batteryLow(info) {
+ document.getElementById('low').innerText = "true";
+ }
+
+ function batteryCritical(info) {
+ document.getElementById('crit').innerText = "true";
+ }
+
+ function addBattery() {
+ window.addEventListener("batterystatus", updateInfo, false);
+ }
+
+ function removeBattery() {
+ window.removeEventListener("batterystatus", updateInfo, false);
+ }
+
+ function addLow() {
+ window.addEventListener("batterylow", batteryLow, false);
+ }
+
+ function removeLow() {
+ window.removeEventListener("batterylow", batteryLow, false);
+ }
+
+ function addCritical() {
+ window.addEventListener("batterycritical", batteryCritical, false);
+ }
+
+ function removeCritical() {
+ window.removeEventListener("batterycritical", batteryCritical, false);
+ }
+
+</script>
+
+ </head>
+ <body onload="init();" id="stage" class="theme">
+
+ <h1>Battery</h1>
+ <div id="info">
+ <b>Status:</b> <span id="battery_status"></span><br>
+ Level: <span id="level"></span><br/>
+ Plugged: <span id="isPlugged"></span><br/>
+ Low: <span id="low"></span><br/>
+ Critical: <span id="crit"></span><br/>
+ </div>
+ <h2>Action</h2>
+ <div class="btn large" onclick="addBattery();">Add "batterystatus" listener</div>
+ <div class="btn large" onclick="removeBattery();">Remove "batterystatus" listener</div>
+ <div class="btn large" onclick="addLow();">Add "batterylow" listener</div>
+ <div class="btn large" onclick="removeLow();">Remove "batterylow" listener</div>
+ <div class="btn large" onclick="addCritical();">Add "batterycritical" listener</div>
+ <div class="btn large" onclick="removeCritical();">Remove "batterycritical" listener</div>
+ <h2> </h2><div class="backBtn" onclick="backHome();">Back</div>
+ </body>
+</html>
[23/37] Add WP7 and WP8 platform files.
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/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/f59ddbbd/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/f59ddbbd/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/f59ddbbd/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/f59ddbbd/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/f59ddbbd/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/f59ddbbd/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/f59ddbbd/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/f59ddbbd/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/f59ddbbd/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/f59ddbbd/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
[17/37] Add WP7 and WP8 platform files.
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/FileTransfer.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/FileTransfer.cs b/lib/cordova-wp8/templates/standalone/Plugins/FileTransfer.cs
new file mode 100644
index 0000000..e585895
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/FileTransfer.cs
@@ -0,0 +1,526 @@
+/*
+ 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.IO;
+using System.IO.IsolatedStorage;
+using System.Net;
+using System.Runtime.Serialization;
+using System.Windows;
+using System.Security;
+using System.Diagnostics;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ public class FileTransfer : BaseCommand
+ {
+ public class DownloadRequestState
+ {
+ // This class stores the State of the request.
+ public HttpWebRequest request;
+ public DownloadOptions options;
+
+ public DownloadRequestState()
+ {
+ request = null;
+ options = null;
+ }
+ }
+
+ /// <summary>
+ /// Boundary symbol
+ /// </summary>
+ private string Boundary = "----------------------------" + DateTime.Now.Ticks.ToString("x");
+
+ // Error codes
+ public const int FileNotFoundError = 1;
+ public const int InvalidUrlError = 2;
+ public const int ConnectionError = 3;
+
+ /// <summary>
+ /// Options for downloading file
+ /// </summary>
+ [DataContract]
+ public class DownloadOptions
+ {
+ /// <summary>
+ /// File path to download to
+ /// </summary>
+ [DataMember(Name = "filePath", IsRequired = true)]
+ public string FilePath { get; set; }
+
+ /// <summary>
+ /// Server address to the file to download
+ /// </summary>
+ [DataMember(Name = "url", IsRequired = true)]
+ public string Url { get; set; }
+ }
+
+ /// <summary>
+ /// Options for uploading file
+ /// </summary>
+ [DataContract]
+ public class UploadOptions
+ {
+ /// <summary>
+ /// File path to upload
+ /// </summary>
+ [DataMember(Name = "filePath", IsRequired = true)]
+ public string FilePath { get; set; }
+
+ /// <summary>
+ /// Server address
+ /// </summary>
+ [DataMember(Name = "server", IsRequired = true)]
+ public string Server { get; set; }
+
+ /// <summary>
+ /// File key
+ /// </summary>
+ [DataMember(Name = "fileKey")]
+ public string FileKey { get; set; }
+
+ /// <summary>
+ /// File name on the server
+ /// </summary>
+ [DataMember(Name = "fileName")]
+ public string FileName { get; set; }
+
+ /// <summary>
+ /// File Mime type
+ /// </summary>
+ [DataMember(Name = "mimeType")]
+ public string MimeType { get; set; }
+
+
+ /// <summary>
+ /// Additional options
+ /// </summary>
+ [DataMember(Name = "params")]
+ public string Params { get; set; }
+
+ /// <summary>
+ /// Flag to recognize if we should trust every host (only in debug environments)
+ /// </summary>
+ [DataMember(Name = "debug")]
+ public bool Debug { get; set; }
+
+ /// <summary>
+ /// Creates options object with default parameters
+ /// </summary>
+ public UploadOptions()
+ {
+ this.SetDefaultValues(new StreamingContext());
+ }
+
+ /// <summary>
+ /// Initializes default values for class fields.
+ /// Implemented in separate method because default constructor is not invoked during deserialization.
+ /// </summary>
+ /// <param name="context"></param>
+ [OnDeserializing()]
+ public void SetDefaultValues(StreamingContext context)
+ {
+ this.FileKey = "file";
+ this.FileName = "image.jpg";
+ this.MimeType = "image/jpeg";
+ }
+
+ }
+
+ /// <summary>
+ /// Uploading response info
+ /// </summary>
+ [DataContract]
+ public class FileUploadResult
+ {
+ /// <summary>
+ /// Amount of sent bytes
+ /// </summary>
+ [DataMember(Name = "bytesSent")]
+ public long BytesSent { get; set; }
+
+ /// <summary>
+ /// Server response code
+ /// </summary>
+ [DataMember(Name = "responseCode")]
+ public long ResponseCode { get; set; }
+
+ /// <summary>
+ /// Server response
+ /// </summary>
+ [DataMember(Name = "response", EmitDefaultValue = false)]
+ public string Response { get; set; }
+
+ /// <summary>
+ /// Creates FileUploadResult object with response values
+ /// </summary>
+ /// <param name="bytesSent">Amount of sent bytes</param>
+ /// <param name="responseCode">Server response code</param>
+ /// <param name="response">Server response</param>
+ public FileUploadResult(long bytesSent, long responseCode, string response)
+ {
+ this.BytesSent = bytesSent;
+ this.ResponseCode = responseCode;
+ this.Response = response;
+ }
+ }
+
+ /// <summary>
+ /// Represents transfer error codes for callback
+ /// </summary>
+ [DataContract]
+ public class FileTransferError
+ {
+ /// <summary>
+ /// Error code
+ /// </summary>
+ [DataMember(Name = "code", IsRequired = true)]
+ public int Code { get; set; }
+
+ /// <summary>
+ /// The source URI
+ /// </summary>
+ [DataMember(Name = "source", IsRequired = true)]
+ public string Source { get; set; }
+
+ /// <summary>
+ /// The target URI
+ /// </summary>
+ [DataMember(Name = "target", IsRequired = true)]
+ public string Target { get; set; }
+
+ /// <summary>
+ /// The http status code response from the remote URI
+ /// </summary>
+ [DataMember(Name = "http_status", IsRequired = true)]
+ public int HttpStatus { get; set; }
+
+ /// <summary>
+ /// Creates FileTransferError object
+ /// </summary>
+ /// <param name="errorCode">Error code</param>
+ public FileTransferError(int errorCode)
+ {
+ this.Code = errorCode;
+ this.Source = null;
+ this.Target = null;
+ this.HttpStatus = 0;
+ }
+ public FileTransferError(int errorCode, string source, string target, int status)
+ {
+ this.Code = errorCode;
+ this.Source = source;
+ this.Target = target;
+ this.HttpStatus = status;
+ }
+ }
+
+ /// <summary>
+ /// Upload options
+ /// </summary>
+ private UploadOptions uploadOptions;
+
+ /// <summary>
+ /// Bytes sent
+ /// </summary>
+ private long bytesSent;
+
+ /// <summary>
+ /// sends a file to a server
+ /// </summary>
+ /// <param name="options">Upload options</param>
+ public void upload(string options)
+ {
+ Debug.WriteLine("options = " + options);
+ options = options.Replace("{}", "null");
+
+ try
+ {
+ try
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+ uploadOptions = JSON.JsonHelper.Deserialize<UploadOptions>(args[0]);
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ Uri serverUri;
+ try
+ {
+ serverUri = new Uri(uploadOptions.Server);
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(InvalidUrlError, uploadOptions.Server, null, 0)));
+ return;
+ }
+ HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(serverUri);
+ webRequest.ContentType = "multipart/form-data;boundary=" + Boundary;
+ webRequest.Method = "POST";
+ webRequest.BeginGetRequestStream(WriteCallback, webRequest);
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(ConnectionError)));
+ }
+ }
+
+ public void download(string options)
+ {
+ DownloadOptions downloadOptions = null;
+ HttpWebRequest webRequest = null;
+
+ try
+ {
+ string[] optionStrings = JSON.JsonHelper.Deserialize<string[]>(options);
+
+ downloadOptions = new DownloadOptions();// JSON.JsonHelper.Deserialize<DownloadOptions>(options);
+ downloadOptions.Url = optionStrings[0];
+ downloadOptions.FilePath = optionStrings[1];
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ try
+ {
+ webRequest = (HttpWebRequest)WebRequest.Create(downloadOptions.Url);
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(InvalidUrlError, downloadOptions.Url, null, 0)));
+ return;
+ }
+
+ if (downloadOptions != null && webRequest != null)
+ {
+ DownloadRequestState state = new DownloadRequestState();
+ state.options = downloadOptions;
+ state.request = webRequest;
+ webRequest.BeginGetResponse(new AsyncCallback(downloadCallback), state);
+ }
+
+
+
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="asynchronousResult"></param>
+ private void downloadCallback(IAsyncResult asynchronousResult)
+ {
+ DownloadRequestState reqState = (DownloadRequestState)asynchronousResult.AsyncState;
+ HttpWebRequest request = reqState.request;
+
+ try
+ {
+ HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
+
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ // create the file if not exists
+ if (!isoFile.FileExists(reqState.options.FilePath))
+ {
+ var file = isoFile.CreateFile(reqState.options.FilePath);
+ file.Close();
+ }
+
+ using (FileStream fileStream = new IsolatedStorageFileStream(reqState.options.FilePath, FileMode.Open, FileAccess.Write, isoFile))
+ {
+ long totalBytes = response.ContentLength;
+ int bytesRead = 0;
+ using (BinaryReader reader = new BinaryReader(response.GetResponseStream()))
+ {
+
+ using (BinaryWriter writer = new BinaryWriter(fileStream))
+ {
+ int BUFFER_SIZE = 1024;
+ byte[] buffer;
+
+ while (true)
+ {
+ buffer = reader.ReadBytes(BUFFER_SIZE);
+ // fire a progress event ?
+ bytesRead += buffer.Length;
+ if (buffer.Length > 0)
+ {
+ writer.Write(buffer);
+ }
+ else
+ {
+ writer.Close();
+ reader.Close();
+ fileStream.Close();
+ break;
+ }
+ }
+ }
+
+ }
+
+
+ }
+ }
+ WPCordovaClassLib.Cordova.Commands.File.FileEntry entry = new WPCordovaClassLib.Cordova.Commands.File.FileEntry(reqState.options.FilePath);
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, entry));
+ }
+ catch (IsolatedStorageException)
+ {
+ // Trying to write the file somewhere within the IsoStorage.
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(FileNotFoundError)));
+ }
+ catch (SecurityException)
+ {
+ // Trying to write the file somewhere not allowed.
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(FileNotFoundError)));
+ }
+ catch (WebException webex)
+ {
+ // TODO: probably need better work here to properly respond with all http status codes back to JS
+ // Right now am jumping through hoops just to detect 404.
+ if ((webex.Status == WebExceptionStatus.ProtocolError && ((HttpWebResponse)webex.Response).StatusCode == HttpStatusCode.NotFound) || webex.Status == WebExceptionStatus.UnknownError)
+ {
+ // Weird MSFT detection of 404... seriously... just give us the f(*&#$@ status code as a number ffs!!!
+ // "Numbers for HTTP status codes? Nah.... let's create our own set of enums/structs to abstract that stuff away."
+ // FACEPALM
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(ConnectionError, null, null, 404)));
+ }
+ else
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(ConnectionError)));
+ }
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(FileNotFoundError)));
+ }
+ }
+
+
+
+ /// <summary>
+ /// Read file from Isolated Storage and sends it to server
+ /// </summary>
+ /// <param name="asynchronousResult"></param>
+ private void WriteCallback(IAsyncResult asynchronousResult)
+ {
+ try
+ {
+ HttpWebRequest webRequest = (HttpWebRequest)asynchronousResult.AsyncState;
+ using (Stream requestStream = (webRequest.EndGetRequestStream(asynchronousResult)))
+ {
+ string lineStart = "--";
+ string lineEnd = Environment.NewLine;
+ byte[] boundaryBytes = System.Text.Encoding.UTF8.GetBytes(lineStart + Boundary + lineEnd);
+ string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"" + lineEnd + lineEnd + "{1}" + lineEnd;
+
+ if (uploadOptions.Params != null)
+ {
+
+ string[] arrParams = uploadOptions.Params.Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries);
+
+ foreach (string param in arrParams)
+ {
+ string[] split = param.Split('=');
+ string key = split[0];
+ string val = split[1];
+ requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
+ string formItem = string.Format(formdataTemplate, key, val);
+ byte[] formItemBytes = System.Text.Encoding.UTF8.GetBytes(formItem);
+ requestStream.Write(formItemBytes, 0, formItemBytes.Length);
+ }
+ requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
+ }
+ using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ if (!isoFile.FileExists(uploadOptions.FilePath))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(FileNotFoundError, uploadOptions.Server, uploadOptions.FilePath, 0)));
+ return;
+ }
+
+ using (FileStream fileStream = new IsolatedStorageFileStream(uploadOptions.FilePath, FileMode.Open, isoFile))
+ {
+ string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"" + lineEnd + "Content-Type: {2}" + lineEnd + lineEnd;
+ string header = string.Format(headerTemplate, uploadOptions.FileKey, uploadOptions.FileName, uploadOptions.MimeType);
+ byte[] headerBytes = System.Text.Encoding.UTF8.GetBytes(header);
+ requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
+ requestStream.Write(headerBytes, 0, headerBytes.Length);
+ byte[] buffer = new byte[4096];
+ int bytesRead = 0;
+
+ while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
+ {
+ requestStream.Write(buffer, 0, bytesRead);
+ bytesSent += bytesRead;
+ }
+ }
+ byte[] endRequest = System.Text.Encoding.UTF8.GetBytes(lineEnd + lineStart + Boundary + lineStart + lineEnd);
+ requestStream.Write(endRequest, 0, endRequest.Length);
+ }
+ }
+ webRequest.BeginGetResponse(ReadCallback, webRequest);
+ }
+ catch (Exception)
+ {
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new FileTransferError(ConnectionError)));
+ });
+ }
+ }
+
+ /// <summary>
+ /// Reads response into FileUploadResult
+ /// </summary>
+ /// <param name="asynchronousResult"></param>
+ private void ReadCallback(IAsyncResult asynchronousResult)
+ {
+ try
+ {
+ HttpWebRequest webRequest = (HttpWebRequest)asynchronousResult.AsyncState;
+ using (HttpWebResponse response = (HttpWebResponse)webRequest.EndGetResponse(asynchronousResult))
+ {
+ using (Stream streamResponse = response.GetResponseStream())
+ {
+ using (StreamReader streamReader = new StreamReader(streamResponse))
+ {
+ string responseString = streamReader.ReadToEnd();
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, new FileUploadResult(bytesSent, (long)response.StatusCode, responseString)));
+ });
+ }
+ }
+ }
+ }
+ catch (Exception)
+ {
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ FileTransferError transferError = new FileTransferError(ConnectionError, uploadOptions.Server, uploadOptions.FilePath, 403);
+ DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, transferError));
+ });
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/GeoLocation.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/GeoLocation.cs b/lib/cordova-wp8/templates/standalone/Plugins/GeoLocation.cs
new file mode 100644
index 0000000..c53cb29
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/GeoLocation.cs
@@ -0,0 +1,34 @@
+/*
+ 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.Runtime.Serialization;
+using System.Threading;
+using System.Device.Location;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ /// <summary>
+ /// This is a command stub, the browser provides the correct implementation. We use this to trigger the static analyzer that we require this permission
+ /// </summary>
+ public class GeoLocation
+ {
+ /* Unreachable code, by design -jm */
+ private void triggerGeoInclusion()
+ {
+ new GeoCoordinateWatcher();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/Globalization.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/Globalization.cs b/lib/cordova-wp8/templates/standalone/Plugins/Globalization.cs
new file mode 100644
index 0000000..2c2f468
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/Globalization.cs
@@ -0,0 +1,1177 @@
+/*
+ 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.Globalization;
+using System.Runtime.Serialization;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ /// <summary>
+ /// Provides information about system locale, culture settings, number formats, ect.
+ /// </summary>
+ public class Globalization : BaseCommand
+ {
+
+ #region Globalization errors
+
+ /// <summary>
+ /// Globalization error codes.
+ /// </summary>
+ public enum ErrorCode : int
+ {
+ UnknownError = 0,
+ FormattingError = 1,
+ ParsingError = 2,
+ PatternError = 3
+ }
+
+ /// <summary>
+ /// Represents globalization error object.
+ /// </summary>
+ [DataContract]
+ public class GlobalizationError
+ {
+ #region Error messages
+ /// <summary>
+ /// Error messages
+ /// </summary>
+ public const string UnknownError = "UNKNOWN_ERROR";
+ public const string FormattingError = "FORMATTIN_ERROR";
+ public const string ParsingError = "PARSING_ERROR";
+ public const string PatternError = "PATTERN_ERROR";
+
+ #endregion
+
+ /// <summary>
+ /// Error code
+ /// </summary>
+ [DataMember(Name = "code", IsRequired = false)]
+ public ErrorCode Code { get; set; }
+
+ /// <summary>
+ /// Error message
+ /// </summary>
+ [DataMember(Name = "message", IsRequired = false)]
+ public string Message { get; set; }
+
+ /// <summary>
+ /// Default constructor
+ /// </summary>
+ public GlobalizationError()
+ {
+ this.Code = ErrorCode.UnknownError;
+ this.Message = UnknownError;
+ }
+
+ /// <summary>
+ /// Constructor setting error code
+ /// </summary>
+ public GlobalizationError(ErrorCode error)
+ {
+ this.Code = error;
+
+ switch (error)
+ {
+ case ErrorCode.ParsingError:
+ {
+ this.Message = ParsingError;
+ break;
+ }
+ case ErrorCode.FormattingError:
+ {
+ this.Message = FormattingError;
+ break;
+ }
+ case ErrorCode.PatternError:
+ {
+ this.Message = PatternError;
+ break;
+ }
+ default:
+ {
+ this.Message = UnknownError;
+ break;
+ }
+ }
+ }
+ }
+
+ #endregion
+
+ #region Globalization options
+
+ /// <summary>
+ /// Represents globalization options.
+ /// </summary>
+ [DataContract]
+ public class GlobalizationOptions
+ {
+ #region available option values
+ /// <summary>
+ /// Number pattern types.
+ /// </summary>
+ public const string Percent = "percent";
+ public const string Currency = "currency";
+ public const string Decimal = "decimal";
+
+ /// <summary>
+ /// Format length types
+ /// </summary>
+ public const string Short = "short";
+ public const string Medium = "medium";
+ public const string Long = "long";
+ public const string Full = "full";
+
+ /// <summary>
+ /// Selector types
+ /// </summary>
+ public const string TimeSelector = "time";
+ public const string DateSelector = "date";
+ public const string DateAndTimeSelector = "date and time";
+
+ /// <summary>
+ /// Date name types
+ /// </summary>
+ public const string Narrow = "narrow";
+ public const string Wide = "wide";
+
+ /// <summary>
+ /// Date name items
+ /// </summary>
+ public const string Months = "months";
+ public const string Days = "days";
+
+ #endregion
+
+ /// <summary>
+ /// Additional options
+ /// </summary>
+ [DataMember(Name = "options", IsRequired = false)]
+ public Options AdditionalOptions { get; set; }
+
+ /// <summary>
+ /// Date to convert
+ /// </summary>
+ [DataMember(Name = "date", IsRequired = false)]
+ public long Date { get; set; }
+
+ /// <summary>
+ /// Date as stirng
+ /// </summary>
+ [DataMember(Name = "dateString", IsRequired = false)]
+ public string DateString { get; set; }
+
+ /// <summary>
+ /// Currency code
+ /// </summary>
+ [DataMember(Name = "currencyCode", IsRequired = false)]
+ public string CurrencyCode { get; set; }
+
+ /// <summary>
+ /// Number as string
+ /// </summary>
+ [DataMember(Name = "numberString", IsRequired = false)]
+ public string NumberString { get; set; }
+
+ /// <summary>
+ /// Number to convert
+ /// </summary>
+ [DataMember(Name = "number", IsRequired = false)]
+ public double Number { get; set; }
+ }
+
+ /// <summary>
+ /// Represents additional options
+ /// </summary>
+ [DataContract]
+ public class Options
+ {
+ /// <summary>
+ /// Pattern type
+ /// </summary>
+ [DataMember(Name = "type", IsRequired = false)]
+ public string Type { get; set; }
+
+ /// <summary>
+ /// Format length
+ /// </summary>
+ [DataMember(Name = "formatLength", IsRequired = false)]
+ public string FormatLength { get; set; }
+
+ /// <summary>
+ /// Selector
+ /// </summary>
+ [DataMember(Name = "selector", IsRequired = false)]
+ public string Selector { get; set; }
+
+ /// <summary>
+ /// Date name item
+ /// </summary>
+ [DataMember(Name = "item", IsRequired = false)]
+ public string Item { get; set; }
+ }
+
+ #endregion
+
+ #region returned objects
+
+ #region Number pattern object
+
+ /// <summary>
+ /// Represents number pattern
+ /// </summary>
+ [DataContract]
+ public class NumberPattern
+ {
+ /// <summary>
+ /// Pattern
+ /// </summary>
+ [DataMember(Name = "pattern", IsRequired = false)]
+ public string Pattern { get; set; }
+
+ /// <summary>
+ /// Symbol
+ /// </summary>
+ [DataMember(Name = "symbol", IsRequired = false)]
+ public string Symbol { get; set; }
+
+ /// <summary>
+ /// Fraction
+ /// </summary>
+ [DataMember(Name = "fraction", IsRequired = false)]
+ public int Fraction { get; set; }
+
+ /// <summary>
+ /// Positive
+ /// </summary>
+ [DataMember(Name = "positive", IsRequired = false)]
+ public string Positive { get; set; }
+
+ /// <summary>
+ /// Negative
+ /// </summary>
+ [DataMember(Name = "negative", IsRequired = false)]
+ public string Negative { get; set; }
+
+ /// <summary>
+ /// Rounding
+ /// </summary>
+ [DataMember(Name = "rounding", IsRequired = false)]
+ public int Rounding { get; set; }
+
+ /// <summary>
+ /// Decimal
+ /// </summary>
+ [DataMember(Name = "decimal", IsRequired = false)]
+ public string Decimal { get; set; }
+
+ /// <summary>
+ /// Grouping
+ /// </summary>
+ [DataMember(Name = "grouping", IsRequired = false)]
+ public string Grouping { get; set; }
+
+ /// <summary>
+ /// Constructor of the class
+ /// </summary>
+ /// <param name="pattern"></param>
+ /// <param name="symbol"></param>
+ /// <param name="fraction"></param>
+ /// <param name="positive"></param>
+ /// <param name="negative"></param>
+ /// <param name="rounding"></param>
+ /// <param name="dec"></param>
+ /// <param name="grouping"></param>
+ public NumberPattern(string pattern, string symbol, int fraction, string positive, string negative, int rounding, string dec, string grouping)
+ {
+ this.Pattern = pattern;
+ this.Symbol = symbol;
+ this.Fraction = fraction;
+ this.Positive = positive;
+ this.Negative = negative;
+ this.Rounding = rounding;
+ this.Decimal = dec;
+ this.Grouping = grouping;
+ }
+ }
+ #endregion
+
+ #region Date format object
+
+ /// <summary>
+ /// Represents date format
+ /// </summary>
+ [DataContract]
+ public class DateFormat
+ {
+ /// <summary>
+ /// Year
+ /// </summary>
+ [DataMember(Name = "year", IsRequired = false)]
+ public int Year { get; set; }
+
+ /// <summary>
+ /// Month
+ /// </summary>
+ [DataMember(Name = "month", IsRequired = false)]
+ public int Month { get; set; }
+
+ /// <summary>
+ /// Day
+ /// </summary>
+ [DataMember(Name = "day", IsRequired = false)]
+ public int Day { get; set; }
+
+ /// <summary>
+ /// Hour
+ /// </summary>
+ [DataMember(Name = "hour", IsRequired = false)]
+ public int Hour { get; set; }
+
+ /// <summary>
+ /// Minute
+ /// </summary>
+ [DataMember(Name = "minute", IsRequired = false)]
+ public int Minute { get; set; }
+
+ /// <summary>
+ /// Second
+ /// </summary>
+ [DataMember(Name = "second", IsRequired = false)]
+ public int Second { get; set; }
+
+ /// <summary>
+ /// Millisecond
+ /// </summary>
+ [DataMember(Name = "millisecond", IsRequired = false)]
+ public int Millisecond { get; set; }
+
+ public DateFormat(int year, int month, int day, int hour, int minute, int second, int millisecond)
+ {
+ this.Year = year;
+ this.Month = month;
+ this.Day = day;
+ this.Hour = hour;
+ this.Minute = minute;
+ this.Millisecond = millisecond;
+ }
+
+ }
+ #endregion
+
+ #region Date pattern object
+
+ /// <summary>
+ /// Represents date pattern object
+ /// </summary>
+ [DataContract]
+ public class DatePattern
+ {
+
+ /// <summary>
+ /// Date pattern
+ /// </summary>
+ [DataMember(Name = "pattern", IsRequired = false)]
+ public string Pattern { get; set; }
+
+ /// <summary>
+ /// TimeZone
+ /// </summary>
+ [DataMember(Name = "timezone", IsRequired = false)]
+ public string TimeZone { get; set; }
+
+ /// <summary>
+ /// UTC offset
+ /// </summary>
+ [DataMember(Name = "utc_offset", IsRequired = false)]
+ public double UtcOffset { get; set; }
+
+ /// <summary>
+ /// Dst offset
+ /// </summary>
+ [DataMember(Name = "dst_offset", IsRequired = false)]
+ public double DstOffset { get; set; }
+
+ /// <summary>
+ /// Constructor of the class
+ /// </summary>
+ /// <param name="pattern"></param>
+ /// <param name="timezone"></param>
+ /// <param name="utcOffset"></param>
+ /// <param name="dstOffset"></param>
+ public DatePattern(string pattern, string timezone, double utcOffset, double dstOffset)
+ {
+ this.Pattern = pattern;
+ this.TimeZone = timezone;
+ this.UtcOffset = utcOffset;
+ this.DstOffset = dstOffset;
+ }
+
+ }
+
+ #endregion
+
+ #endregion
+
+ #region Locale info
+
+ /// <summary>
+ /// Gets the string identifier for the client's current locale setting.
+ /// </summary>
+ /// <param name="options"></param>
+ public void getLocaleName(string options)
+ {
+ try
+ {
+ var locale = RegionInfo.CurrentRegion.TwoLetterISORegionName;
+ PluginResult result = new PluginResult(PluginResult.Status.OK, this.WrapIntoJSON(locale));
+ this.DispatchCommandResult(result);
+ }
+ catch (Exception)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError()));
+ }
+ }
+
+ /// <summary>
+ /// Gets the string identifier for the client's current language.
+ /// </summary>
+ /// <param name="options"></param>
+ public void getPreferredLanguage(string options)
+ {
+ try
+ {
+ var language = CultureInfo.CurrentCulture.TwoLetterISOLanguageName;
+ PluginResult result = new PluginResult(PluginResult.Status.OK, this.WrapIntoJSON(language));
+ this.DispatchCommandResult(result);
+ }
+ catch (Exception)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError()));
+ }
+ }
+
+ #endregion
+
+ #region Date and time info
+
+ /// <summary>
+ /// Gets whether daylight savings time is in effect for a given date using the client's
+ /// time zone and calendar.
+ /// </summary>
+ /// <param name="opitons">Date to daylight savings check.</param>
+ public void isDayLightSavingsTime(string options)
+ {
+ GlobalizationOptions globalOptions;
+
+ try
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+ globalOptions = JSON.JsonHelper.Deserialize<GlobalizationOptions>(args[0]);
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ try
+ {
+ DateTime start = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+ DateTime date = start.AddMilliseconds(globalOptions.Date).ToLocalTime();
+ TimeZoneInfo localZone = TimeZoneInfo.Local;
+ bool isDaylightSavingTime = localZone.IsDaylightSavingTime(date);
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.OK, this.WrapIntoJSON(isDaylightSavingTime, "dst")));
+ }
+ catch (Exception)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError()));
+ }
+ }
+
+ /// <summary>
+ /// Gets the first day of the week according to the client's user preferences and calendar.
+ /// The days of the week are numbered starting from 1 where 1 is considered to be Sunday.
+ /// </summary>
+ /// <param name="options"></param>
+ public void getFirstDayOfWeek(string options)
+ {
+ try
+ {
+ // DateTimeFormat returns days of the week numbered from zero, so we have to increase returned value by one.
+ var firstDayOfWeek = (int)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek + 1;
+ PluginResult result = new PluginResult(PluginResult.Status.OK, this.WrapIntoJSON(firstDayOfWeek));
+ this.DispatchCommandResult(result);
+ }
+ catch (Exception)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError()));
+ }
+ }
+
+ #endregion
+
+ #region Formatting
+
+ /// <summary>
+ /// Gets a date formatted as a string according to the client's user preferences and calendar using the time zone of the client.
+ /// </summary>
+ /// <param name="options"></param>
+ public void dateToString(string options)
+ {
+ GlobalizationOptions globalOptions;
+
+ try
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+ globalOptions = JSON.JsonHelper.Deserialize<GlobalizationOptions>(args[0]);
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ try
+ {
+ DateTime start = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+ DateTime date = start.AddMilliseconds(globalOptions.Date).ToLocalTime();
+
+ string format = "{0:M/dd/yy H:m:s}"; //short datetime by default
+ int formatLength = 0; //default format
+ int selector = 0; //default selector
+
+ if (globalOptions.AdditionalOptions != null)
+ {
+ if (globalOptions.AdditionalOptions.FormatLength != null)
+ {
+ string t = globalOptions.AdditionalOptions.FormatLength;
+
+ if (t.Equals(GlobalizationOptions.Full))
+ {
+ formatLength++;
+ }
+ }
+
+ if (globalOptions.AdditionalOptions.Selector != null)
+ {
+ string t = globalOptions.AdditionalOptions.Selector;
+
+ if (t.Equals(GlobalizationOptions.DateSelector))
+ {
+ selector += 10;
+ }
+ else if (t.Equals(GlobalizationOptions.TimeSelector))
+ {
+ selector += 20;
+ }
+ }
+
+ //determine return value
+ int method = formatLength + selector;
+
+ switch (method)
+ {
+ case 1: // full datetime
+ {
+ format = "{0:MMMM/dddd/yyyy HH:mm:ss tt}";
+ break;
+ }
+ case 10: // short date
+ {
+ format = "{0:d}";
+ break;
+ }
+ case 11: // full date
+ {
+ format = "{0:D}";
+ break;
+ }
+ case 20: // short time
+ {
+ format = "{0:t}";
+ break;
+ }
+ case 21: // full time
+ {
+ format = "{0:T}";
+ break;
+ }
+ default: // short datetime
+ {
+ format = "{0:M/dd/yy H:m:s}";
+ break;
+ }
+ }
+ }
+
+ string formattedValue = string.Format(CultureInfo.CurrentCulture, format, date);
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.OK, this.WrapIntoJSON(formattedValue)));
+ }
+ catch (Exception)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError(ErrorCode.FormattingError)));
+ }
+ }
+
+ /// <summary>
+ /// Parses a date formatted as a string according to the client's user preferences and calendar using the time zone of the client and returns the corresponding date object
+ /// </summary>
+ /// <param name="options"></param>
+ public void stringToDate(string options)
+ {
+ GlobalizationOptions globalOptions;
+
+ try
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+ globalOptions = JSON.JsonHelper.Deserialize<GlobalizationOptions>(args[0]);
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ try
+ {
+ if (string.IsNullOrEmpty(globalOptions.DateString))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ string format = "M/dd/yy H:m:s"; // short datetime by default
+ int formatLength = 0; //default format
+ int selector = 0; //default selector
+
+ if (globalOptions.AdditionalOptions != null)
+ {
+ if (globalOptions.AdditionalOptions.FormatLength != null)
+ {
+ string t = globalOptions.AdditionalOptions.FormatLength;
+
+ if (t.Equals(GlobalizationOptions.Full))
+ {
+ formatLength++;
+ }
+ }
+
+ if (globalOptions.AdditionalOptions.Selector != null)
+ {
+ string t = globalOptions.AdditionalOptions.Selector;
+
+ if (t.Equals(GlobalizationOptions.DateSelector))
+ {
+ selector += 10;
+ }
+ else if (t.Equals(GlobalizationOptions.TimeSelector))
+ {
+ selector += 20;
+ }
+ }
+
+ //determine return value
+ int method = formatLength + selector;
+
+ switch (method)
+ {
+ case 1: // full datetime
+ {
+ format = "MMMM/dddd/yyyy HH:mm:ss tt";
+ break;
+ }
+ case 10: // short date
+ {
+ format = "d";
+ break;
+ }
+ case 11: // full date
+ {
+ format = "D";
+ break;
+ }
+ case 20: // short time
+ {
+ format = "t";
+ break;
+ }
+ case 21: // full time
+ {
+ format = "T";
+ break;
+ }
+ default: // short datetime
+ {
+ format = "M/dd/yy H:m:s";
+ break;
+ }
+ }
+ }
+
+ DateTime date = DateTime.ParseExact(globalOptions.DateString, format, CultureInfo.CurrentCulture);
+ DateFormat dateFormat = new DateFormat(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, date.Millisecond);
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.OK, dateFormat));
+
+ }
+ catch (Exception)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError(ErrorCode.ParsingError)));
+ }
+ }
+
+ /// <summary>
+ /// Gets a pattern string for formatting and parsing dates according to the client's user preferences.
+ /// </summary>
+ /// <param name="options"></param>
+ public void getDatePattern(string options)
+ {
+ GlobalizationOptions globalOptions;
+
+ try
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+ globalOptions = JSON.JsonHelper.Deserialize<GlobalizationOptions>(args[0]);
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ try
+ {
+ DateTimeFormatInfo dateFormatInfo = DateTimeFormatInfo.CurrentInfo;
+ string pattern = dateFormatInfo.FullDateTimePattern; // full datetime by default
+ int formatLength = 0; //default format
+ int selector = 0; //default selector
+
+ if (globalOptions.AdditionalOptions != null)
+ {
+ if (globalOptions.AdditionalOptions.FormatLength != null)
+ {
+ string t = globalOptions.AdditionalOptions.FormatLength;
+
+ if (t.Equals(GlobalizationOptions.Full))
+ {
+ formatLength++;
+ }
+ }
+
+ if (globalOptions.AdditionalOptions.Selector != null)
+ {
+ string t = globalOptions.AdditionalOptions.Selector;
+
+ if (t.Equals(GlobalizationOptions.DateSelector))
+ {
+ selector += 10;
+ }
+ else if (t.Equals(GlobalizationOptions.TimeSelector))
+ {
+ selector += 20;
+ }
+ }
+
+ //determine return value
+ int method = formatLength + selector;
+
+ switch (method)
+ {
+ case 1: // full datetime
+ {
+ pattern = dateFormatInfo.FullDateTimePattern;
+ break;
+ }
+ case 10: // short date
+ {
+ pattern = dateFormatInfo.ShortDatePattern;
+ break;
+ }
+ case 11: // full date
+ {
+ pattern = dateFormatInfo.LongDatePattern;
+ break;
+ }
+ case 20: // short time
+ {
+ pattern = dateFormatInfo.ShortTimePattern;
+ break;
+ }
+ case 21: // full time
+ {
+ pattern = dateFormatInfo.LongTimePattern;
+ break;
+ }
+ default: // short datetime
+ {
+ // Seems like C# doesn't support short datetime pattern so we use full format
+ // http://msdn.microsoft.com/en-us/library/1at0z4ew%28v=vs.71%29.aspx
+ pattern = dateFormatInfo.FullDateTimePattern;
+ break;
+ }
+ }
+ }
+
+ TimeZoneInfo localZone = TimeZoneInfo.Local;
+ DatePattern datePattern = new DatePattern(pattern, localZone.DisplayName, localZone.BaseUtcOffset.TotalSeconds, 0);
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.OK, datePattern));
+ }
+ catch (Exception)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError(ErrorCode.PatternError)));
+ }
+ }
+
+ /// <summary>
+ /// Gets an array of either the names of the months or days of the week according to the client's user preferences and calendar.
+ /// </summary>
+ /// <param name="options"></param>
+ public void getDateNames(string options)
+ {
+ GlobalizationOptions globalOptions;
+
+ try
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+ globalOptions = JSON.JsonHelper.Deserialize<GlobalizationOptions>(args[0]);
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ try
+ {
+ int type = 0; //default wide
+ int item = 0; //default months
+
+ if (globalOptions.AdditionalOptions != null)
+ {
+ if (globalOptions.AdditionalOptions.Type != null)
+ {
+ string t = globalOptions.AdditionalOptions.Type;
+
+ if (t.Equals(GlobalizationOptions.Narrow))
+ {
+ type++;
+ }
+ }
+
+ if (globalOptions.AdditionalOptions.Item != null)
+ {
+ string t = globalOptions.AdditionalOptions.Item;
+
+ if (t.Equals(GlobalizationOptions.Days))
+ {
+ item += 10;
+ }
+ }
+ }
+
+ //determine return value
+ int method = item + type;
+ string[] namesArray;
+ CultureInfo currentCulture = CultureInfo.CurrentCulture;
+
+ if (method == 1) //months and narrow
+ {
+ namesArray = currentCulture.DateTimeFormat.AbbreviatedMonthNames;
+ }
+ else if (method == 10) //days and wide
+ {
+ namesArray = currentCulture.DateTimeFormat.DayNames;
+ }
+ else if (method == 11) //days and narrow
+ {
+ namesArray = currentCulture.DateTimeFormat.AbbreviatedDayNames;
+ }
+ else //default: months and wide
+ {
+ namesArray = currentCulture.DateTimeFormat.MonthNames;
+ }
+
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.OK, this.WrapIntoJSON(namesArray)));
+ }
+ catch (Exception)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError()));
+ }
+ }
+
+ /// <summary>
+ /// Gets a number formatted as a string according to the client's user preferences.
+ /// </summary>
+ /// <param name="options"></param>
+ public void numberToString(string options)
+ {
+ GlobalizationOptions globalOptions;
+
+ try
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+ globalOptions = JSON.JsonHelper.Deserialize<GlobalizationOptions>(args[0]);
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ try
+ {
+ string format = string.Empty;
+ string numberFormatType = (globalOptions.AdditionalOptions == null || string.IsNullOrEmpty(globalOptions.AdditionalOptions.Type)) ?
+ GlobalizationOptions.Decimal : globalOptions.AdditionalOptions.Type;
+
+ switch (numberFormatType)
+ {
+ case GlobalizationOptions.Percent:
+ {
+ format = "{0:p}";
+ break;
+ }
+
+ case GlobalizationOptions.Currency:
+ {
+ format = "{0:c}";
+ break;
+ }
+
+ default:
+ {
+ format = "{0:f}";
+ break;
+ }
+ }
+
+ string formattedValue = string.Format(CultureInfo.CurrentCulture, format, globalOptions.Number);
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.OK, this.WrapIntoJSON(formattedValue)));
+
+ }
+ catch (Exception)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError(ErrorCode.FormattingError)));
+ }
+ }
+
+ /// <summary>
+ /// Gets a number formatted as a string according to the client's user preferences and returns the corresponding number.
+ /// </summary>
+ /// <param name="options"></param>
+ public void stringToNumber(string options)
+ {
+ GlobalizationOptions globalOptions;
+
+ try
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+ globalOptions = JSON.JsonHelper.Deserialize<GlobalizationOptions>(args[0]);
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ try
+ {
+ if (string.IsNullOrEmpty(globalOptions.NumberString))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ string numberString = globalOptions.NumberString;
+ string numberFormatType = (globalOptions.AdditionalOptions == null || string.IsNullOrEmpty(globalOptions.AdditionalOptions.Type)) ?
+ GlobalizationOptions.Decimal : globalOptions.AdditionalOptions.Type;
+
+ NumberStyles numberStyle;
+
+ switch (numberFormatType)
+ {
+ case GlobalizationOptions.Percent:
+ {
+ numberStyle = NumberStyles.Any;
+ numberString = numberString.Replace(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.PercentSymbol, "");
+ break;
+ }
+
+ case GlobalizationOptions.Currency:
+ {
+ numberStyle = NumberStyles.Currency;
+ break;
+ }
+
+ default:
+ {
+ numberStyle = NumberStyles.Number;
+ break;
+ }
+ }
+
+ double value = double.Parse(numberString, numberStyle, CultureInfo.CurrentCulture);
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.OK, this.WrapIntoJSON(value)));
+
+ }
+ catch (Exception)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError(ErrorCode.ParsingError)));
+ }
+ }
+
+
+ /// <summary>
+ /// Gets a pattern string for formatting and parsing numbers according to the client's user preferences.
+ /// </summary>
+ /// <param name="options"></param>
+ public void getNumberPattern(string options)
+ {
+ GlobalizationOptions globalOptions;
+
+ try
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+ globalOptions = JSON.JsonHelper.Deserialize<GlobalizationOptions>(args[0]);
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ try
+ {
+ CultureInfo cultureInfo = CultureInfo.CurrentCulture;
+ NumberFormatInfo formatInfo = cultureInfo.NumberFormat;
+ string numberFormatType = (globalOptions.AdditionalOptions == null || string.IsNullOrEmpty(globalOptions.AdditionalOptions.Type)) ?
+ GlobalizationOptions.Decimal : globalOptions.AdditionalOptions.Type;
+ NumberPattern pattern = null;
+ string symbol;
+
+ // TODO find out how to get format pattern and the number of fraction digits
+ switch (numberFormatType)
+ {
+ case GlobalizationOptions.Percent:
+ {
+ symbol = formatInfo.PercentSymbol;
+ pattern = new NumberPattern("", symbol, 0, formatInfo.PercentPositivePattern.ToString(), formatInfo.PercentNegativePattern.ToString(), 0, formatInfo.PercentDecimalSeparator, formatInfo.PercentGroupSeparator);
+ break;
+ }
+ case GlobalizationOptions.Currency:
+ {
+ symbol = formatInfo.CurrencySymbol;
+ pattern = new NumberPattern("", symbol, 0, formatInfo.CurrencyPositivePattern.ToString(), formatInfo.CurrencyNegativePattern.ToString(), 0, formatInfo.CurrencyDecimalSeparator, formatInfo.CurrencyGroupSeparator);
+ break;
+ }
+ default:
+ {
+ symbol = formatInfo.NumberDecimalSeparator;
+ pattern = new NumberPattern("", symbol, 0, "", formatInfo.NumberNegativePattern.ToString(), 0, formatInfo.NumberDecimalSeparator, formatInfo.NumberGroupSeparator);
+ break;
+ }
+ }
+
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.OK, pattern));
+ }
+ catch (Exception)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError(ErrorCode.PatternError)));
+ }
+ }
+
+ /// <summary>
+ /// Gets a pattern string for formatting and parsing currency values according to the client's user preferences and ISO 4217 currency code.
+ /// </summary>
+ /// <param name="options"></param>
+ public void getCurrencyPattern(string options)
+ {
+ GlobalizationOptions globalOptions;
+
+ try
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+ globalOptions = JSON.JsonHelper.Deserialize<GlobalizationOptions>(args[0]);
+ }
+ catch (Exception)
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ try
+ {
+ if (string.IsNullOrEmpty(globalOptions.CurrencyCode))
+ {
+ DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+ return;
+ }
+
+ string currencyCode = globalOptions.CurrencyCode;
+
+ // temporary not supported via lack of api required
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.INVALID_ACTION, "Not supported"));
+ return;
+
+ // TODO find the way to get currency info from currency code
+ // http://stackoverflow.com/questions/12373800/3-digit-currency-code-to-currency-symbol
+ // http://stackoverflow.com/questions/6924067/how-to-get-specific-culture-currency-pattern
+ // CultureInfo cultureInfo = new CultureInfo(currencyCode);
+ // NumberFormatInfo numberFormat = cultureInfo.NumberFormat;
+ }
+ catch (Exception)
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError(ErrorCode.FormattingError)));
+ }
+ }
+
+ #endregion
+
+ #region private methods
+
+ /// <summary>
+ /// Wraps data into JSON format
+ /// </summary>
+ /// <param name="data">data</param>
+ /// <returns>data formatted as JSON object</returns>
+ private string WrapIntoJSON<T>(T data, string keyName = "value")
+ {
+ string param = "{0}";
+ string stringifiedData = data.ToString();
+
+ if (data.GetType() == typeof(string))
+ {
+ param = "\"" + param + "\"";
+ }
+
+ if (data.GetType() == typeof(bool))
+ {
+ stringifiedData = stringifiedData.ToLower();
+ }
+
+ if (data.GetType() == typeof(string[]))
+ {
+ stringifiedData = JSON.JsonHelper.Serialize(data);
+ }
+
+ var formattedData = string.Format("\"" + keyName + "\":" + param, stringifiedData);
+ formattedData = "{" + formattedData + "}";
+
+ return formattedData;
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/ImageExifHelper.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/ImageExifHelper.cs b/lib/cordova-wp8/templates/standalone/Plugins/ImageExifHelper.cs
new file mode 100644
index 0000000..68ddf87
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/ImageExifHelper.cs
@@ -0,0 +1,209 @@
+/*
+ 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.IO;
+using System.Windows.Media.Imaging;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ public class ImageExifOrientation
+ {
+ public const int Portrait = 1;
+ public const int PortraitUpsideDown = 3;
+ public const int LandscapeLeft = 6;
+ public const int LandscapeRight = 8;
+ }
+
+ public class ImageExifHelper
+ {
+
+ public static Stream RotateStream(Stream stream, int angle)
+ {
+ stream.Position = 0;
+ if (angle % 90 != 0 || angle < 0)
+ {
+ throw new ArgumentException();
+ }
+ if (angle % 360 == 0)
+ {
+ return stream;
+ }
+
+ angle = angle % 360;
+
+ BitmapImage bitmap = new BitmapImage();
+ bitmap.SetSource(stream);
+ WriteableBitmap wbSource = new WriteableBitmap(bitmap);
+
+ WriteableBitmap wbTarget = null;
+
+ int srcPixelWidth = wbSource.PixelWidth;
+ int srcPixelHeight = wbSource.PixelHeight;
+
+ if (angle % 180 == 0)
+ {
+ wbTarget = new WriteableBitmap(srcPixelWidth, srcPixelHeight);
+ }
+ else
+ {
+ wbTarget = new WriteableBitmap(srcPixelHeight, srcPixelWidth);
+ }
+
+ int destPixelWidth = wbTarget.PixelWidth;
+ int[] srcPxls = wbSource.Pixels;
+ int[] destPxls = wbTarget.Pixels;
+
+ // this ugly if/else is to avoid a conditional check for every pixel
+ if (angle == 90)
+ {
+ for (int x = 0; x < srcPixelWidth; x++)
+ {
+ for (int y = 0; y < srcPixelHeight; y++)
+ {
+ destPxls[(srcPixelHeight - y - 1) + (x * destPixelWidth)] = srcPxls[x + y * srcPixelWidth];
+ }
+ }
+ }
+ else if (angle == 180)
+ {
+ for (int x = 0; x < srcPixelWidth; x++)
+ {
+ for (int y = 0; y < srcPixelHeight; y++)
+ {
+ destPxls[(srcPixelWidth - x - 1) + (srcPixelHeight - y - 1) * srcPixelWidth] = srcPxls[x + y * srcPixelWidth];
+ }
+ }
+ }
+ else if (angle == 270)
+ {
+ for (int x = 0; x < srcPixelWidth; x++)
+ {
+ for (int y = 0; y < srcPixelHeight; y++)
+ {
+ destPxls[y + (srcPixelWidth - x - 1) * destPixelWidth] = srcPxls[x + y * srcPixelWidth];
+ }
+ }
+ }
+
+ MemoryStream targetStream = new MemoryStream();
+ wbTarget.SaveJpeg(targetStream, destPixelWidth, wbTarget.PixelHeight, 0, 100);
+ return targetStream;
+ }
+
+ public static int getImageOrientationFromStream(Stream imgStream)
+ {
+
+ // 0xFFD8 : jpgHeader
+ // 0xFFE1 :
+ // 0x???? : length of exif data
+ // 0x????, 0x???? : Chars 'E','x','i','f'
+ // 0x0000 : 2 empty bytes
+ // <== mark beginning of tags SIZE:ID:VALUE
+ // 0x???? : 'II' or 'MM' for Intel or Motorola ( always getting II on my WP7 devices ), determins littleEndian-ness
+ // 0x002A : marker value
+ // 0x???? : offset to the Image File Data
+
+ // XXXX possible space before actual tag data ... we skip to mark + offset
+
+ // 0x???? number of exif tags present
+
+ // make sure we are at the begining
+ imgStream.Seek(0, SeekOrigin.Begin);
+ BinaryReader reader = new BinaryReader(imgStream);
+
+ byte[] jpgHdr = reader.ReadBytes(2); // always (0xFFD8)
+
+ byte start = reader.ReadByte(); // 0xFF
+ byte index = reader.ReadByte(); // 0xE1
+
+ while (start == 0xFF && index != 0xE1) // This never seems to happen, todo: optimize
+ {
+ // Get the data length
+ ushort dLen = BitConverter.ToUInt16(reader.ReadBytes(2), 0);
+ // skip along
+ reader.ReadBytes(dLen - 2);
+ start = reader.ReadByte();
+ index = reader.ReadByte();
+ }
+
+ // It's only success if we found the 0xFFE1 marker
+ if (start != 0xFF || index != 0xE1)
+ {
+ // throw new Exception("Could not find Exif data block");
+ Debug.WriteLine("Did not find EXIF data");
+ return 0;
+ }
+
+ // read 2 byte length of EXIF data
+ ushort exifLen = BitConverter.ToUInt16(reader.ReadBytes(2), 0);
+ String exif = ""; // build the string
+ for (var n = 0; n < 4; n++)
+ {
+ exif += reader.ReadChar();
+ }
+ if (exif != "Exif")
+ {
+ // did not find exif data ...
+ Debug.WriteLine("Did not find EXIF data");
+ return 0;
+ }
+
+ // read 2 empty bytes
+ //ushort emptyBytes = BitConverter.ToUInt16(reader.ReadBytes(2), 0);
+ reader.ReadBytes(2);
+
+ long headerMark = reader.BaseStream.Position; // where are we now <==
+
+ //bool isLEndian = (reader.ReadChar() + "" + reader.ReadChar()) == "II";
+ reader.ReadBytes(2); // 'II' or 'MM', but we don't care
+
+ if (0x002A != BitConverter.ToUInt16(reader.ReadBytes(2), 0))
+ {
+ Debug.WriteLine("Error in data != 0x002A");
+ return 0;
+ }
+
+ // Get the offset to the IFD (image file directory)
+ ushort imgOffset = BitConverter.ToUInt16(reader.ReadBytes(2), 0);
+
+ imgStream.Position = headerMark + imgOffset;
+ ushort tagCount = BitConverter.ToUInt16(reader.ReadBytes(2), 0);
+ for (ushort x = 0; x < tagCount; x++)
+ {
+ // Orientation = 0x112, aka 274
+ if (0x112 == BitConverter.ToUInt16(reader.ReadBytes(2), 0))
+ {
+ ushort dType = BitConverter.ToUInt16(reader.ReadBytes(2), 0);
+ // don't care ..
+ uint comps = reader.ReadUInt32();
+ byte[] tagData = reader.ReadBytes(4);
+ int orientation = (int)tagData[0];
+ Debug.WriteLine("orientation = " + orientation.ToString());
+ return orientation;
+ // 6 means rotate clockwise 90 deg
+ // 8 means rotate counter-clockwise 90 deg
+ // 1 means all is good
+ // 3 means flip vertical
+ }
+ // skip to the next item, 12 bytes each
+ reader.BaseStream.Seek(10, SeekOrigin.Current);
+ }
+ return 0;
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/Plugins/InAppBrowser.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/Plugins/InAppBrowser.cs b/lib/cordova-wp8/templates/standalone/Plugins/InAppBrowser.cs
new file mode 100644
index 0000000..2741355
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/Plugins/InAppBrowser.cs
@@ -0,0 +1,271 @@
+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;
+using System.Diagnostics;
+using System.Runtime.Serialization;
+using WPCordovaClassLib.Cordova;
+using WPCordovaClassLib.Cordova.Commands;
+using WPCordovaClassLib.Cordova.JSON;
+using Microsoft.Phone.Shell;
+using Microsoft.Phone.Tasks;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ [DataContract]
+ public class BrowserOptions
+ {
+ [DataMember]
+ public string url;
+
+ [DataMember]
+ public bool isGeolocationEnabled;
+ }
+
+ public class InAppBrowser : BaseCommand
+ {
+
+ private static WebBrowser browser;
+ private static ApplicationBarIconButton backButton;
+ private static ApplicationBarIconButton fwdButton;
+
+ public void open(string options)
+ {
+ string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+ //BrowserOptions opts = JSON.JsonHelper.Deserialize<BrowserOptions>(options);
+ string urlLoc = args[0];
+ string target = args[1];
+ /*
+ _self - opens in the Cordova WebView if url is in the white-list, else it opens in the InAppBrowser
+ _blank - always open in the InAppBrowser
+ _system - always open in the system web browser
+ */
+ switch (target)
+ {
+ case "_blank":
+ ShowInAppBrowser(urlLoc);
+ break;
+ case "_self":
+ ShowCordovaBrowser(urlLoc);
+ break;
+ case "_system":
+ ShowSystemBrowser(urlLoc);
+ break;
+ }
+
+
+ }
+
+ private void ShowCordovaBrowser(string url)
+ {
+ Uri loc = new Uri(url, UriKind.RelativeOrAbsolute);
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
+ if (frame != null)
+ {
+ PhoneApplicationPage page = frame.Content as PhoneApplicationPage;
+ if (page != null)
+ {
+ CordovaView cView = page.FindName("CordovaView") as CordovaView;
+ if (cView != null)
+ {
+ WebBrowser br = cView.Browser;
+ br.Navigate(loc);
+ }
+ }
+
+ }
+ });
+ }
+
+ private void ShowSystemBrowser(string url)
+ {
+ WebBrowserTask webBrowserTask = new WebBrowserTask();
+ webBrowserTask.Uri = new Uri(url, UriKind.Absolute);
+ webBrowserTask.Show();
+ }
+
+
+ private void ShowInAppBrowser(string url)
+ {
+ Uri loc = new Uri(url);
+
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ if (browser != null)
+ {
+ //browser.IsGeolocationEnabled = opts.isGeolocationEnabled;
+ browser.Navigate(loc);
+ }
+ else
+ {
+ PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
+ if (frame != null)
+ {
+ PhoneApplicationPage page = frame.Content as PhoneApplicationPage;
+
+ string baseImageUrl = "Images/";
+
+ if (page != null)
+ {
+ Grid grid = page.FindName("LayoutRoot") as Grid;
+ if (grid != null)
+ {
+ browser = new WebBrowser();
+ browser.IsScriptEnabled = true;
+ browser.LoadCompleted += new System.Windows.Navigation.LoadCompletedEventHandler(browser_LoadCompleted);
+
+ browser.Navigating += new EventHandler<NavigatingEventArgs>(browser_Navigating);
+ browser.NavigationFailed += new System.Windows.Navigation.NavigationFailedEventHandler(browser_NavigationFailed);
+ browser.Navigated += new EventHandler<System.Windows.Navigation.NavigationEventArgs>(browser_Navigated);
+ browser.Navigate(loc);
+ //browser.IsGeolocationEnabled = opts.isGeolocationEnabled;
+ grid.Children.Add(browser);
+ }
+
+ ApplicationBar bar = new ApplicationBar();
+ bar.BackgroundColor = Colors.Gray;
+ bar.IsMenuEnabled = false;
+
+ backButton = new ApplicationBarIconButton();
+ backButton.Text = "Back";
+
+ backButton.IconUri = new Uri(baseImageUrl + "appbar.back.rest.png", UriKind.Relative);
+ backButton.Click += new EventHandler(backButton_Click);
+ backButton.IsEnabled = false;
+ bar.Buttons.Add(backButton);
+
+
+ fwdButton = new ApplicationBarIconButton();
+ fwdButton.Text = "Forward";
+ fwdButton.IconUri = new Uri(baseImageUrl + "appbar.next.rest.png", UriKind.Relative);
+ fwdButton.Click += new EventHandler(fwdButton_Click);
+ fwdButton.IsEnabled = false;
+ bar.Buttons.Add(fwdButton);
+
+ ApplicationBarIconButton closeBtn = new ApplicationBarIconButton();
+ closeBtn.Text = "Close";
+ closeBtn.IconUri = new Uri(baseImageUrl + "appbar.close.rest.png", UriKind.Relative);
+ closeBtn.Click += new EventHandler(closeBtn_Click);
+ bar.Buttons.Add(closeBtn);
+
+ page.ApplicationBar = bar;
+ }
+
+ }
+ }
+ });
+ }
+
+ void browser_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
+ {
+
+ }
+
+ void fwdButton_Click(object sender, EventArgs e)
+ {
+ if (browser != null)
+ {
+ try
+ {
+ browser.GoForward();
+ //browser.InvokeScript("execScript", "history.forward();");
+ }
+ catch (Exception)
+ {
+
+ }
+ }
+ }
+
+ void backButton_Click(object sender, EventArgs e)
+ {
+ if (browser != null)
+ {
+ try
+ {
+ browser.GoBack();
+ //browser.InvokeScript("execScript", "history.back();");
+ }
+ catch (Exception)
+ {
+
+ }
+ }
+ }
+
+ void closeBtn_Click(object sender, EventArgs e)
+ {
+ this.close();
+ }
+
+
+ public void close(string options = "")
+ {
+ if (browser != null)
+ {
+ Deployment.Current.Dispatcher.BeginInvoke(() =>
+ {
+ PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
+ if (frame != null)
+ {
+ PhoneApplicationPage page = frame.Content as PhoneApplicationPage;
+ if (page != null)
+ {
+ Grid grid = page.FindName("LayoutRoot") as Grid;
+ if (grid != null)
+ {
+ grid.Children.Remove(browser);
+ }
+ page.ApplicationBar = null;
+ }
+ }
+ browser = null;
+ string message = "{\"type\":\"exit\"}";
+ PluginResult result = new PluginResult(PluginResult.Status.OK, message);
+ result.KeepCallback = false;
+ this.DispatchCommandResult(result);
+ });
+ }
+ }
+
+ void browser_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
+ {
+ if (browser != null)
+ {
+ backButton.IsEnabled = browser.CanGoBack;
+ fwdButton.IsEnabled = browser.CanGoForward;
+
+ }
+ string message = "{\"type\":\"loadstop\", \"url\":\"" + e.Uri.AbsoluteUri + "\"}";
+ PluginResult result = new PluginResult(PluginResult.Status.OK, message);
+ result.KeepCallback = true;
+ this.DispatchCommandResult(result);
+ }
+
+ void browser_NavigationFailed(object sender, System.Windows.Navigation.NavigationFailedEventArgs e)
+ {
+ string message = "{\"type\":\"error\",\"url\":\"" + e.Uri.AbsoluteUri + "\"}";
+ PluginResult result = new PluginResult(PluginResult.Status.ERROR, message);
+ result.KeepCallback = true;
+ this.DispatchCommandResult(result);
+ }
+
+ void browser_Navigating(object sender, NavigatingEventArgs e)
+ {
+ string message = "{\"type\":\"loadstart\",\"url\":\"" + e.Uri.AbsoluteUri + "\"}";
+ PluginResult result = new PluginResult(PluginResult.Status.OK, message);
+ result.KeepCallback = true;
+ this.DispatchCommandResult(result);
+ }
+
+ }
+}
[31/37] Add WP7 and WP8 support to cordova-cli.
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/spec/platform-script/wp8/wp8.spec.js
----------------------------------------------------------------------
diff --git a/spec/platform-script/wp8/wp8.spec.js b/spec/platform-script/wp8/wp8.spec.js
new file mode 100644
index 0000000..998094c
--- /dev/null
+++ b/spec/platform-script/wp8/wp8.spec.js
@@ -0,0 +1,99 @@
+var cordova = require('../../../cordova'),
+ shell = require('shelljs'),
+ path = require('path'),
+ fs = require('fs'),
+ wp8_parser = require('../../../src/metadata/wp8_parser'),
+ tempDir = path.join(__dirname, '..', '..', '..', 'temp'),
+ fixtures = path.join(__dirname, '..', '..', 'fixtures'),
+ cordova_project = path.join(fixtures, 'projects', 'cordova');
+
+var cwd = process.cwd();
+
+describe('Test:', function() {
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+
+ describe('\'platform add wp8\'', function() {
+ var sh, cr;
+ var fake_reqs_check = function() {
+ expect(cr.mostRecentCall.args).toBeDefined();
+ cr.mostRecentCall.args[0](false);
+ };
+ var fake_create = function(a_path) {
+ shell.mkdir('-p', a_path);
+ fs.writeFileSync(path.join(a_path, 'wp7Project.csproj'), 'hi', 'utf-8');
+ fs.writeFileSync(path.join(a_path, 'wp7Project.sln'), 'hi', 'utf-8');
+ sh.mostRecentCall.args[2](0, '');
+ };
+ beforeEach(function() {
+ sh = spyOn(shell, 'exec');
+ cr = spyOn(wp8_parser, 'check_requirements');
+ shell.rm('-rf', tempDir);
+ cordova.create(tempDir);
+ process.chdir(tempDir);
+ });
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+ it('should shell out to wp8 /bin/create', function() {
+ cordova.platform('add', 'wp8');
+ fake_reqs_check();
+ var shell_cmd = sh.mostRecentCall.args[0];
+ var create_cmd = path.join('wp8', 'bin', 'create');
+ expect(shell_cmd).toContain(create_cmd);
+ });
+ it('should call wp8_parser\'s update_project', function() {
+ spyOn(wp8_parser.prototype, 'update_project');
+ cordova.platform('add', 'wp8');
+ fake_reqs_check();
+ fake_create(path.join(tempDir, 'platforms', 'wp8'));
+ expect(wp8_parser.prototype.update_project).toHaveBeenCalled();
+ });
+ });
+
+ describe('\'emulate wp8\'', function() {
+ beforeEach(function() {
+ process.chdir(tempDir);
+ });
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+ shell.rm('-rf', tempDir);
+ cordova.create(tempDir);
+ shell.cp('-rf', path.join(cordova_project, 'platforms', 'wp8'), path.join(tempDir, 'platforms'));
+ it('should shell out to run command on wp8', function() {
+ var proj_spy = spyOn(wp8_parser.prototype, 'update_project');
+ var s = spyOn(require('shelljs'), 'exec');
+ cordova.emulate('wp8');
+ proj_spy.mostRecentCall.args[1](); // update_project fake
+ expect(s).toHaveBeenCalled();
+ var emulate_cmd = path.join('wp8', 'cordova', 'run');
+ expect(s.mostRecentCall.args[0]).toContain(emulate_cmd);
+ });
+ it('should call wp8_parser\'s update_project', function() {
+ spyOn(require('shelljs'), 'exec');
+ spyOn(wp8_parser.prototype, 'update_project');
+ cordova.emulate('wp8');
+ expect(wp8_parser.prototype.update_project).toHaveBeenCalled();
+ });
+ });
+
+ describe('\'compile wp8\'', function() {
+ beforeEach(function() {
+ process.chdir(tempDir);
+ });
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+ shell.rm('-rf', tempDir);
+ cordova.create(tempDir);
+ shell.cp('-rf', path.join(cordova_project, 'platforms', 'wp8'), path.join(tempDir, 'platforms'));
+ it('should shell out to build command', function() {
+ var build_cmd = path.join('wp8', 'cordova', 'build');
+ var s = spyOn(require('shelljs'), 'exec').andReturn({code:0});
+ cordova.compile('wp8');
+ expect(s.mostRecentCall.args[0]).toContain(build_cmd);
+ });
+ });
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/spec/platform-script/wp8/wp8_parser.spec.js
----------------------------------------------------------------------
diff --git a/spec/platform-script/wp8/wp8_parser.spec.js b/spec/platform-script/wp8/wp8_parser.spec.js
new file mode 100644
index 0000000..5669e02
--- /dev/null
+++ b/spec/platform-script/wp8/wp8_parser.spec.js
@@ -0,0 +1,249 @@
+
+/**
+ 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.
+*/
+var wp8_parser = require('../../../src/metadata/wp8_parser'),
+ config_parser = require('../../../src/config_parser'),
+ util = require('../../../src/util'),
+ path = require('path'),
+ shell = require('shelljs'),
+ fs = require('fs'),
+ os = require('os'),
+ et = require('elementtree'),
+ cordova = require('../../../cordova'),
+ projects_path = path.join(__dirname, '..', '..', 'fixtures', 'projects'),
+ wp8_path = path.join(projects_path, 'native', 'wp8_fixture'),
+ project_path = path.join(projects_path, 'cordova'),
+ wp8_project_path = path.join(project_path, 'platforms', 'wp8');
+
+var www_config = util.projectConfig(project_path);
+var original_www_config = fs.readFileSync(www_config, 'utf-8');
+
+describe('wp8 project parser', function() {
+ it('should throw an exception with a path that is not a native wp8 project', function() {
+ expect(function() {
+ var project = new wp8_parser(process.cwd());
+ }).toThrow();
+ });
+ it('should accept a proper native wp8 project path as construction parameter', function() {
+ expect(function() {
+ var project = new wp8_parser(wp8_path);
+ expect(project).toBeDefined();
+ }).not.toThrow();
+ });
+
+ describe('update_from_config method', function() {
+ var config;
+ var project = new wp8_parser(wp8_path);
+
+ var manifest_path = path.join(wp8_path, 'Properties', 'WMAppManifest.xml');
+ var csproj_path = project.csproj_path;
+ var sln_path = project.sln_path;
+ var app_xaml_path = path.join(wp8_path, 'App.xaml');
+ var app_cs_path = path.join(wp8_path, 'App.xaml.cs');
+ var main_xaml_path = path.join(wp8_path, 'MainPage.xaml');
+ var main_cs_path = path.join(wp8_path, 'MainPage.xaml.cs');
+
+
+ var original_manifest = fs.readFileSync(manifest_path, 'utf-8');
+ var original_csproj = fs.readFileSync(csproj_path, 'utf-8');
+ var original_sln = fs.readFileSync(sln_path, 'utf-8');
+ var original_app_xaml = fs.readFileSync(app_xaml_path, 'utf-8');
+ var original_app_cs = fs.readFileSync(app_cs_path, 'utf-8');
+ var original_main_xaml = fs.readFileSync(main_xaml_path, 'utf-8');
+ var original_main_cs = fs.readFileSync(main_cs_path, 'utf-8');
+
+ beforeEach(function() {
+ project = new wp8_parser(wp8_path);
+ config = new config_parser(www_config);
+ });
+ afterEach(function() {
+ fs.writeFileSync(manifest_path, original_manifest, 'utf-8');
+ // csproj file changes name if app changes name
+ fs.unlinkSync(project.csproj_path);
+ fs.unlinkSync(project.sln_path);
+ fs.writeFileSync(csproj_path, original_csproj, 'utf-8');
+ fs.writeFileSync(sln_path, original_sln, 'utf-8');
+ fs.writeFileSync(app_xaml_path, original_app_xaml, 'utf-8');
+ fs.writeFileSync(app_cs_path, original_app_cs, 'utf-8');
+ fs.writeFileSync(main_xaml_path, original_main_xaml, 'utf-8');
+ fs.writeFileSync(main_cs_path, original_main_cs, 'utf-8');
+ });
+ it('should throw an exception if a non config_parser object is passed into it', function() {
+ expect(function() {
+ project.update_from_config({});
+ }).toThrow();
+ });
+ it('should update the application name properly', function() {
+ var test_name = 'bond. james bond.';
+ config.name(test_name);
+ project.update_from_config(config);
+ var raw_manifest = fs.readFileSync(manifest_path, 'utf-8');
+ //Strip three bytes that windows adds (http://www.multiasking.com/2012/11/851)
+ var cleaned_manifest = raw_manifest.replace('\ufeff', '');
+ var manifest = new et.ElementTree(et.XML(cleaned_manifest));
+ var app_name = manifest.find('.//App[@Title]')['attrib']['Title'];
+ expect(app_name).toBe(test_name);
+
+ //check for the proper name of csproj and solution files
+ test_name = test_name.replace(/(\.\s|\s\.|\s+|\.+)/g, '_'); //make it a ligitamate name
+ expect(project.csproj_path).toContain(test_name);
+ expect(project.sln_path).toContain(test_name);
+ });
+ it('should update the application package name properly', function() {
+ var test_package = 'ca.filmaj.dewd'
+ config.packageName(test_package);
+ project.update_from_config(config);
+
+ // check csproj file (use regex instead of elementtree?)
+ var raw_csproj = fs.readFileSync(project.csproj_path, 'utf-8');
+ var cleaned_csproj = raw_csproj.replace(/^\uFEFF/i, '');
+ var csproj = new et.ElementTree(et.XML(cleaned_csproj));
+ expect(csproj.find('.//RootNamespace').text).toEqual(test_package);
+ expect(csproj.find('.//AssemblyName').text).toEqual(test_package);
+ expect(csproj.find('.//XapFilename').text).toEqual(test_package + '.xap');
+ expect(csproj.find('.//SilverlightAppEntry').text).toEqual(test_package + '.App');
+
+ // check app.xaml (use regex instead of elementtree?)
+ var new_app_xaml = fs.readFileSync(app_xaml_path, 'utf-8');
+ var cleaned_app_xaml = new_app_xaml.replace(/^\uFEFF/i, '');
+ var app_xaml = new et.ElementTree(et.XML(cleaned_app_xaml));
+ expect(app_xaml._root.attrib['x:Class']).toEqual(test_package + '.App');
+
+ // check app.xaml.cs
+ var new_app_cs = fs.readFileSync(app_cs_path, 'utf-8');
+ expect(new_app_cs).toContain('namespace ' + test_package);
+
+ // check MainPage.xaml (use regex instead of elementtree?)
+ var new_main_xaml = fs.readFileSync(main_xaml_path, 'utf-8');
+ var cleaned_main_xaml = new_main_xaml.replace(/^\uFEFF/i, '');
+ var main_xaml = new et.ElementTree(et.XML(cleaned_main_xaml));
+ expect(main_xaml._root.attrib['x:Class']).toEqual(test_package + '.MainPage');
+
+ //check MainPage.xaml.cs
+ var new_main_cs = fs.readFileSync(main_cs_path, 'utf-8');
+ expect(new_main_cs).toContain('namespace ' + test_package);
+ });
+ xdescribe('preferences', function() {
+ it('should not change default project preferences and copy over additional project preferences to platform-level config.xml', function() {
+ /*config.preference.add({name:'henrik',value:'sedin'});
+ project.update_from_config(config);
+
+ var native_config = new et.ElementTree(et.XML(fs.readFileSync(android_config, 'utf-8')));
+ var ps = native_config.findall('preference');
+ expect(ps.length).toEqual(7);
+ expect(ps[0].attrib.name).toEqual('useBrowserHistory');
+ expect(ps[0].attrib.value).toEqual('true');
+ expect(ps[6].attrib.name).toEqual('henrik');
+ expect(ps[6].attrib.value).toEqual('sedin');*/
+
+ // TODO : figure out if this is supported
+ //expect(true).toBe(false);
+ });
+ it('should override a default project preference if applicable', function() {
+ /*config.preference.add({name:'useBrowserHistory',value:'false'});
+ project.update_from_config(config);
+
+ var native_config = new et.ElementTree(et.XML(fs.readFileSync(android_config, 'utf-8')));
+ var ps = native_config.findall('preference');
+ expect(ps.length).toEqual(6);
+ expect(ps[0].attrib.name).toEqual('useBrowserHistory');
+ expect(ps[0].attrib.value).toEqual('false');*/
+
+ // TODO : figure out if this is supported
+ //expect(true).toBe(false);
+ });
+ });
+ });
+
+ describe('cross-platform project level methods', function() {
+ var parser, config;
+
+ beforeEach(function() {
+ parser = new wp8_parser(wp8_project_path);
+ config = new config_parser(www_config);
+ });
+ afterEach(function() {
+ });
+ describe('update_www method', function() {
+ it('should update all www assets', function() {
+ var newFile = path.join(util.projectWww(project_path), 'somescript.js');
+ this.after(function() {
+ shell.rm('-f', newFile);
+ });
+ fs.writeFileSync(newFile, 'alert("sup");', 'utf-8');
+ parser.update_www();
+ expect(fs.existsSync(path.join(wp8_project_path, 'www', 'somescript.js'))).toBe(true);
+ });
+ it('should write out windows-phone js to cordova.js', function() {
+ parser.update_www();
+ var raw_version = fs.readFileSync(path.join(util.libDirectory, 'cordova-wp8', 'VERSION'), 'utf-8');
+ var wp8_version = raw_version.replace(/\r\n/,'').replace(/\n/,'');
+ expect(fs.readFileSync(path.join(wp8_project_path, 'www', 'cordova.js'),'utf-8')).toEqual(fs.readFileSync(path.join(util.libDirectory, 'cordova-wp8', 'templates', 'standalone', 'www', 'cordova-' + wp8_version + '.js'), 'utf-8'));
+ });
+ });
+
+ xdescribe('update_overrides method',function() {
+ /*var mergesPath = path.join(util.appDir(project_path), 'merges', 'android');
+ var newFile = path.join(mergesPath, 'merge.js');
+ beforeEach(function() {
+ shell.mkdir('-p', mergesPath);
+ fs.writeFileSync(newFile, 'alert("sup");', 'utf-8');
+ });
+ afterEach(function() {
+ shell.rm('-rf', mergesPath);
+ });
+ it('should copy a new file from merges into www', function() {
+ parser.update_overrides();
+ expect(fs.existsSync(path.join(wp8_project_path, 'assets', 'www', 'merge.js'))).toBe(true);
+ });
+
+ it('should copy a file from merges over a file in www', function() {
+ var newFileWWW = path.join(util.projectWww(project_path), 'merge.js');
+ fs.writeFileSync(newFileWWW, 'var foo=1;', 'utf-8');
+ this.after(function() {
+ shell.rm('-rf', newFileWWW);
+ });
+ parser.update_overrides();
+ expect(fs.existsSync(path.join(wp8_project_path, 'assets', 'www', 'merge.js'))).toBe(true);
+ expect(fs.readFileSync(path.join(wp8_project_path, 'assets', 'www', 'merge.js'),'utf-8')).toEqual('alert("sup");');
+ });*/
+
+ // TODO : figure out if this is supported
+ //expect(true).toBe(false);
+ });
+
+ describe('update_project method', function() {
+ it('should invoke update_www', function() {
+ var spyWww = spyOn(parser, 'update_www');
+ parser.update_project(config);
+ expect(spyWww).toHaveBeenCalled();
+ });
+ it('should invoke update_from_config', function() {
+ var spyConfig = spyOn(parser, 'update_from_config');
+ parser.update_project(config);
+ expect(spyConfig).toHaveBeenCalled();
+ });
+ it('should call out to util.deleteSvnFolders', function() {
+ var spy = spyOn(util, 'deleteSvnFolders');
+ parser.update_project(config);
+ expect(spy).toHaveBeenCalled();
+ });
+ });
+ });
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/src/compile.js
----------------------------------------------------------------------
diff --git a/src/compile.js b/src/compile.js
index 4efbd6b..c88c36e 100644
--- a/src/compile.js
+++ b/src/compile.js
@@ -19,14 +19,11 @@
var cordova_util = require('./util'),
path = require('path'),
config_parser = require('./config_parser'),
- platform = require('./platform'),
fs = require('fs'),
shell = require('shelljs'),
et = require('elementtree'),
hooker = require('./hooker'),
- n = require('ncallbacks'),
- prompt = require('prompt'),
- util = require('util');
+ n = require('ncallbacks');
function shell_out_to_debug(projectRoot, platform, callback) {
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/src/create.js
----------------------------------------------------------------------
diff --git a/src/create.js b/src/create.js
index 0f7c8a6..f1d1792 100644
--- a/src/create.js
+++ b/src/create.js
@@ -45,7 +45,7 @@ module.exports = function create (dir, id, name) {
id = id || DEFAULT_ID;
name = name || DEFAULT_NAME;
- if (!(dir && (dir[0] == '~' || dir[0] == '/'))) {
+ if (!(dir && (dir[0] == '~' || dir[0] == '/' || dir[0] + dir[1] == 'C:'))) {
dir = dir ? path.join(process.cwd(), dir) : process.cwd();
}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/src/emulate.js
----------------------------------------------------------------------
diff --git a/src/emulate.js b/src/emulate.js
index 7acb441..b396eeb 100644
--- a/src/emulate.js
+++ b/src/emulate.js
@@ -23,6 +23,8 @@ var cordova_util = require('./util'),
android_parser = require('./metadata/android_parser'),
ios_parser = require('./metadata/ios_parser'),
blackberry_parser = require('./metadata/blackberry_parser'),
+ wp7_parser = require('./metadata/wp7_parser'),
+ wp8_parser = require('./metadata/wp8_parser'),
platform = require('./platform'),
fs = require('fs'),
ls = fs.readdirSync,
@@ -33,16 +35,16 @@ var cordova_util = require('./util'),
var parsers = {
"android":android_parser,
"ios":ios_parser,
- "blackberry":blackberry_parser
+ "blackberry":blackberry_parser,
+ "wp7":wp7_parser,
+ "wp8":wp8_parser
};
function shell_out_to_emulate(root, platform, callback) {
- var cmd = '"' + path.join(root, 'platforms', platform, 'cordova', 'emulate') + '"';
+ var cmd = '"' + path.join(root, 'platforms', platform, 'cordova', 'run') + '"';
// TODO: PLATFORM LIBRARY INCONSISTENCY
if (platform == 'blackberry') {
cmd = 'ant -f "' + path.join(root, 'platforms', platform, 'build.xml') + '" qnx load-simulator';
- } else if (platform.indexOf('android') > -1) {
- cmd = '"' + path.join(root, 'platforms', platform, 'cordova', 'run') + '"';
}
shell.exec(cmd, {silent:true, async:true}, function(code, output) {
if (code > 0) {
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/src/metadata/wp7_parser.js
----------------------------------------------------------------------
diff --git a/src/metadata/wp7_parser.js b/src/metadata/wp7_parser.js
new file mode 100644
index 0000000..289eca0
--- /dev/null
+++ b/src/metadata/wp7_parser.js
@@ -0,0 +1,160 @@
+
+/**
+ 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.
+*/
+var fs = require('fs'),
+ path = require('path'),
+ et = require('elementtree'),
+ util = require('../util'),
+ shell = require('shelljs'),
+ config_parser = require('../config_parser');
+
+module.exports = function wp7_parser(project) {
+ try {
+ // TODO : Check that it's not a wp7 project?
+ var csproj_file = fs.readdirSync(project).filter(function(e) { return e.match(/\.csproj$/i); })[0];
+ if (!csproj_file) throw new Error('The provided path "' + project + '" is not a Windows Phone 8 project.');
+ this.wp7_proj_dir = project;
+ this.csproj_path = path.join(this.wp7_proj_dir, csproj_file);
+ this.sln_path = path.join(this.wp7_proj_dir, csproj_file.replace(/\.csproj/, '.sln'));
+ } catch(e) {
+ throw new Error('The provided path "' + project + '" is not a Windows Phone 8 project.' + e);
+ }
+ this.manifest_path = path.join(this.wp7_proj_dir, 'Properties', 'WMAppManifest.xml');
+};
+
+module.exports.check_requirements = function(callback) {
+ shell.exec(path.join(util.libDirectory, 'cordova-wp7', 'bin', 'check_reqs'), {silent:true, async:true}, function(code, output) {
+ if (code != 0) {
+ callback(output);
+ } else {
+ callback(false);
+ }
+ });
+};
+
+module.exports.prototype = {
+ update_from_config:function(config) {
+ //check config parser
+ if (config instanceof config_parser) {
+ } else throw new Error('update_from_config requires a config_parser object');
+
+ // Update app name by editing app title in Properties\WMAppManifest.xml
+ var name = config.name();
+ var man = fs.readFileSync(this.manifest_path, 'utf-8');
+ //Strip three bytes that windows adds (http://www.multiasking.com/2012/11/851/)
+ var cleanedMan = man.replace('\ufeff', '');
+ var manifest = new et.ElementTree(et.XML(cleanedMan));
+ var prev_name = manifest.find('.//App[@Title]')['attrib']['Title'];
+ if(prev_name != name)
+ {
+ //console.log("Updating app name from " + prev_name + " to " + name);
+ manifest.find('.//App').attrib.Title = name;
+ manifest.find('.//Title').text = name;
+ fs.writeFileSync(this.manifest_path, manifest.write({indent: 4}), 'utf-8');
+
+ //update name of sln and csproj.
+ name = name.replace(/(\.\s|\s\.|\s+|\.+)/g, '_'); //make it a ligitamate name
+ prev_name = prev_name.replace(/(\.\s|\s\.|\s+|\.+)/g, '_');
+ // TODO: might return .sln.user? (generated file)
+ var sln_name = fs.readdirSync(this.wp7_proj_dir).filter(function(e) { return e.match(/\.sln$/i); })[0];
+ var sln_path = path.join(this.wp7_proj_dir, sln_name);
+ var sln_file = fs.readFileSync(sln_path, 'utf-8');
+ var name_regex = new RegExp(prev_name, "g");
+ fs.writeFileSync(sln_path, sln_file.replace(name_regex, name), 'utf-8');
+ shell.mv('-f', this.csproj_path, path.join(this.wp7_proj_dir, name + '.csproj'));
+ this.csproj_path = path.join(this.wp7_proj_dir, name + '.csproj');
+ shell.mv('-f', sln_path, path.join(this.wp7_proj_dir, name + '.sln'));
+ this.sln_path = path.join(this.wp7_proj_dir, name + '.sln');
+ }
+
+ // Update package name by changing:
+ /* - CordovaAppProj.csproj
+ * - MainPage.xaml
+ * - MainPage.xaml.cs
+ * - App.xaml
+ * - App.xaml.cs
+ */
+ var pkg = config.packageName();
+ var raw = fs.readFileSync(this.csproj_path, 'utf-8');
+ var cleanedPage = raw.replace(/^\uFEFF/i, '');
+ var csproj = new et.ElementTree(et.XML(cleanedPage));
+ prev_name = csproj.find('.//RootNamespace').text;
+ if(prev_name != pkg)
+ {
+ //console.log("Updating package name from " + prev_name + " to " + pkg);
+ //CordovaAppProj.csproj
+ csproj.find('.//RootNamespace').text = pkg;
+ csproj.find('.//AssemblyName').text = pkg;
+ csproj.find('.//XapFilename').text = pkg + '.xap';
+ csproj.find('.//SilverlightAppEntry').text = pkg + '.App';
+ fs.writeFileSync(this.csproj_path, csproj.write({indent: 4}), 'utf-8');
+ //MainPage.xaml
+ raw = fs.readFileSync(path.join(this.wp7_proj_dir, 'MainPage.xaml'), 'utf-8');
+ // Remove potential UTF Byte Order Mark
+ cleanedPage = raw.replace(/^\uFEFF/i, '');
+ var mainPageXAML = new et.ElementTree(et.XML(cleanedPage));
+ mainPageXAML._root.attrib['x:Class'] = pkg + '.MainPage';
+ fs.writeFileSync(path.join(this.wp7_proj_dir, 'MainPage.xaml'), mainPageXAML.write({indent: 4}), 'utf-8');
+ //MainPage.xaml.cs
+ var mainPageCS = fs.readFileSync(path.join(this.wp7_proj_dir, 'MainPage.xaml.cs'), 'utf-8');
+ var namespaceRegEx = new RegExp('namespace ' + prev_name);
+ fs.writeFileSync(path.join(this.wp7_proj_dir, 'MainPage.xaml.cs'), mainPageCS.replace(namespaceRegEx, 'namespace ' + pkg), 'utf-8');
+ //App.xaml
+ raw = fs.readFileSync(path.join(this.wp7_proj_dir, 'App.xaml'), 'utf-8');
+ cleanedPage = raw.replace(/^\uFEFF/i, '');
+ var appXAML = new et.ElementTree(et.XML(cleanedPage));
+ appXAML._root.attrib['x:Class'] = pkg + '.App';
+ fs.writeFileSync(path.join(this.wp7_proj_dir, 'App.xaml'), appXAML.write({indent: 4}), 'utf-8');
+ //App.xaml.cs
+ var appCS = fs.readFileSync(path.join(this.wp7_proj_dir, 'App.xaml.cs'), 'utf-8');
+ fs.writeFileSync(path.join(this.wp7_proj_dir, 'App.xaml.cs'), appCS.replace(namespaceRegEx, 'namespace ' + pkg), 'utf-8');
+ }
+ },
+ // Returns the platform-specific www directory.
+ www_dir:function() {
+ return path.join(this.wp7_proj_dir, 'www');
+ },
+ // copyies the app www folder into the wp7 project's www folder
+ update_www:function() {
+ var project_www = path.join(this.wp7_proj_dir, '..', '..', util.projectWww());
+ // remove stock platform assets
+ shell.rm('-rf', this.www_dir());
+ // copy over all app www assets
+ shell.cp('-rf', project_www, this.wp7_proj_dir);
+
+ // copy over wp7 lib's cordova.js
+ var raw_version = fs.readFileSync(path.join(util.libDirectory, 'cordova-wp7', 'VERSION'), 'utf-8')
+ var VERSION = raw_version.replace(/\r\n/,'').replace(/\n/,'');
+ var cordovajs_path = path.join(util.libDirectory, 'cordova-wp7', 'templates', 'standalone', 'www', 'cordova-' + VERSION + '.js');
+ fs.writeFileSync(path.join(this.www_dir(), 'cordova.js'), fs.readFileSync(cordovajs_path, 'utf-8'), 'utf-8');
+ },
+ // calls the nessesary functions to update the wp7 project
+ update_project:function(cfg, callback) {
+ //console.log("Updating wp7 project...");
+
+ this.update_from_config(cfg);
+ this.update_www();
+ util.deleteSvnFolders(this.www_dir());
+
+ //console.log("Done updating.");
+
+ if (callback) callback();
+ }
+};
+
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/src/metadata/wp8_parser.js
----------------------------------------------------------------------
diff --git a/src/metadata/wp8_parser.js b/src/metadata/wp8_parser.js
new file mode 100644
index 0000000..5ecb6dc
--- /dev/null
+++ b/src/metadata/wp8_parser.js
@@ -0,0 +1,158 @@
+
+/**
+ 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.
+*/
+var fs = require('fs'),
+ path = require('path'),
+ et = require('elementtree'),
+ util = require('../util'),
+ shell = require('shelljs'),
+ config_parser = require('../config_parser');
+
+module.exports = function wp8_parser(project) {
+ try {
+ // TODO : Check that it's not a wp7 project?
+ var csproj_file = fs.readdirSync(project).filter(function(e) { return e.match(/\.csproj$/i); })[0];
+ if (!csproj_file) throw new Error('The provided path "' + project + '" is not a Windows Phone 8 project.');
+ this.wp8_proj_dir = project;
+ this.csproj_path = path.join(this.wp8_proj_dir, csproj_file);
+ this.sln_path = path.join(this.wp8_proj_dir, csproj_file.replace(/\.csproj/, '.sln'));
+ } catch(e) {
+ throw new Error('The provided path "' + project + '" is not a Windows Phone 8 project.' + e);
+ }
+ this.manifest_path = path.join(this.wp8_proj_dir, 'Properties', 'WMAppManifest.xml');
+};
+
+module.exports.check_requirements = function(callback) {
+ shell.exec(path.join(util.libDirectory, 'cordova-wp8', 'bin', 'check_reqs'), {silent:true, async:true}, function(code, output) {
+ if (code != 0) {
+ callback(output);
+ } else {
+ callback(false);
+ }
+ });
+};
+
+module.exports.prototype = {
+ update_from_config:function(config) {
+ //check config parser
+ if (config instanceof config_parser) {
+ } else throw new Error('update_from_config requires a config_parser object');
+
+ // Update app name by editing app title in Properties\WMAppManifest.xml
+ var name = config.name();
+ var man = fs.readFileSync(this.manifest_path, 'utf-8');
+ //Strip three bytes that windows adds (http://www.multiasking.com/2012/11/851/)
+ var cleanedMan = man.replace('\ufeff', '');
+ var manifest = new et.ElementTree(et.XML(cleanedMan));
+ var prev_name = manifest.find('.//App[@Title]')['attrib']['Title'];
+ if(prev_name != name)
+ {
+ //console.log("Updating app name from " + prev_name + " to " + name);
+ manifest.find('.//App').attrib.Title = name;
+ manifest.find('.//Title').text = name;
+ fs.writeFileSync(this.manifest_path, manifest.write({indent: 4}), 'utf-8');
+
+ //update name of sln and csproj.
+ name = name.replace(/(\.\s|\s\.|\s+|\.+)/g, '_'); //make it a ligitamate name
+ prev_name = prev_name.replace(/(\.\s|\s\.|\s+|\.+)/g, '_');
+ var sln_path = path.join(this.wp8_proj_dir, prev_name + '.sln');
+ var sln_file = fs.readFileSync(sln_path, 'utf-8');
+ var name_regex = new RegExp(prev_name, "g");
+ fs.writeFileSync(sln_path, sln_file.replace(name_regex, name), 'utf-8');
+ shell.mv('-f', this.csproj_path, path.join(this.wp8_proj_dir, name + '.csproj'));
+ this.csproj_path = path.join(this.wp8_proj_dir, name + '.csproj');
+ shell.mv('-f', sln_path, path.join(this.wp8_proj_dir, name + '.sln'));
+ this.sln_path = path.join(this.wp8_proj_dir, name + '.sln');
+ }
+
+ // Update package name by changing:
+ /* - CordovaAppProj.csproj
+ * - MainPage.xaml
+ * - MainPage.xaml.cs
+ * - App.xaml
+ * - App.xaml.cs
+ */
+ var pkg = config.packageName();
+ var raw = fs.readFileSync(this.csproj_path, 'utf-8');
+ var cleanedPage = raw.replace(/^\uFEFF/i, '');
+ var csproj = new et.ElementTree(et.XML(cleanedPage));
+ prev_name = csproj.find('.//RootNamespace').text;
+ if(prev_name != pkg)
+ {
+ //console.log("Updating package name from " + prev_name + " to " + pkg);
+ //CordovaAppProj.csproj
+ csproj.find('.//RootNamespace').text = pkg;
+ csproj.find('.//AssemblyName').text = pkg;
+ csproj.find('.//XapFilename').text = pkg + '.xap';
+ csproj.find('.//SilverlightAppEntry').text = pkg + '.App';
+ fs.writeFileSync(this.csproj_path, csproj.write({indent: 4}), 'utf-8');
+ //MainPage.xaml
+ raw = fs.readFileSync(path.join(this.wp8_proj_dir, 'MainPage.xaml'), 'utf-8');
+ // Remove potential UTF Byte Order Mark
+ cleanedPage = raw.replace(/^\uFEFF/i, '');
+ var mainPageXAML = new et.ElementTree(et.XML(cleanedPage));
+ mainPageXAML._root.attrib['x:Class'] = pkg + '.MainPage';
+ fs.writeFileSync(path.join(this.wp8_proj_dir, 'MainPage.xaml'), mainPageXAML.write({indent: 4}), 'utf-8');
+ //MainPage.xaml.cs
+ var mainPageCS = fs.readFileSync(path.join(this.wp8_proj_dir, 'MainPage.xaml.cs'), 'utf-8');
+ var namespaceRegEx = new RegExp('namespace ' + prev_name);
+ fs.writeFileSync(path.join(this.wp8_proj_dir, 'MainPage.xaml.cs'), mainPageCS.replace(namespaceRegEx, 'namespace ' + pkg), 'utf-8');
+ //App.xaml
+ raw = fs.readFileSync(path.join(this.wp8_proj_dir, 'App.xaml'), 'utf-8');
+ cleanedPage = raw.replace(/^\uFEFF/i, '');
+ var appXAML = new et.ElementTree(et.XML(cleanedPage));
+ appXAML._root.attrib['x:Class'] = pkg + '.App';
+ fs.writeFileSync(path.join(this.wp8_proj_dir, 'App.xaml'), appXAML.write({indent: 4}), 'utf-8');
+ //App.xaml.cs
+ var appCS = fs.readFileSync(path.join(this.wp8_proj_dir, 'App.xaml.cs'), 'utf-8');
+ fs.writeFileSync(path.join(this.wp8_proj_dir, 'App.xaml.cs'), appCS.replace(namespaceRegEx, 'namespace ' + pkg), 'utf-8');
+ }
+ },
+ // Returns the platform-specific www directory.
+ www_dir:function() {
+ return path.join(this.wp8_proj_dir, 'www');
+ },
+ // copyies the app www folder into the wp8 project's www folder
+ update_www:function() {
+ var project_www = path.join(this.wp8_proj_dir, '..', '..', util.projectWww());
+ // remove stock platform assets
+ shell.rm('-rf', this.www_dir());
+ // copy over all app www assets
+ shell.cp('-rf', project_www, this.wp8_proj_dir);
+
+ // copy over wp8 lib's cordova.js
+ var raw_version = fs.readFileSync(path.join(util.libDirectory, 'cordova-wp8', 'VERSION'), 'utf-8')
+ var VERSION = raw_version.replace(/\r\n/,'').replace(/\n/,'');
+ var cordovajs_path = path.join(util.libDirectory, 'cordova-wp8', 'templates', 'standalone', 'www', 'cordova-' + VERSION + '.js');
+ fs.writeFileSync(path.join(this.www_dir(), 'cordova.js'), fs.readFileSync(cordovajs_path, 'utf-8'), 'utf-8');
+ },
+ // calls the nessesary functions to update the wp8 project
+ update_project:function(cfg, callback) {
+ //console.log("Updating wp8 project...");
+
+ this.update_from_config(cfg);
+ this.update_www();
+ util.deleteSvnFolders(this.www_dir());
+
+ //console.log("Done updating.");
+
+ if (callback) callback();
+ }
+};
+
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/src/platform.js
----------------------------------------------------------------------
diff --git a/src/platform.js b/src/platform.js
index 00f2157..15285fb 100644
--- a/src/platform.js
+++ b/src/platform.js
@@ -26,12 +26,16 @@ var config_parser = require('./config_parser'),
android_parser = require('./metadata/android_parser'),
ios_parser = require('./metadata/ios_parser'),
blackberry_parser = require('./metadata/blackberry_parser'),
+ wp7_parser = require('./metadata/wp7_parser'),
+ wp8_parser = require('./metadata/wp8_parser'),
shell = require('shelljs');
var parsers = {
"android":android_parser,
"ios":ios_parser,
- "blackberry":blackberry_parser
+ "blackberry":blackberry_parser,
+ "wp7":wp7_parser,
+ "wp8":wp8_parser
};
module.exports = function platform(command, targets, callback) {
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/src/plugin.js
----------------------------------------------------------------------
diff --git a/src/plugin.js b/src/plugin.js
index 8997f97..b6d9911 100644
--- a/src/plugin.js
+++ b/src/plugin.js
@@ -108,6 +108,7 @@ module.exports = function plugin(command, targets, callback) {
intersection.forEach(function(platform) {
var cmd = util.format('%s --platform %s --project "%s" --plugin "%s"', cli, platform, path.join(projectRoot, 'platforms', platform), target);
var plugin_cli = shell.exec(cmd, {silent:true});
+ if(!plugin_cli) throw new Error('Plugman command failed to execute for ' + platform + '.');
if (plugin_cli.code > 0) throw new Error('An error occured during plugin installation for ' + platform + '. ' + plugin_cli.output);
});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/src/plugin_loader.js
----------------------------------------------------------------------
diff --git a/src/plugin_loader.js b/src/plugin_loader.js
index 3798e2f..b4730b4 100644
--- a/src/plugin_loader.js
+++ b/src/plugin_loader.js
@@ -25,6 +25,8 @@ var path = require('path'),
android_parser = require('./metadata/android_parser'),
blackberry_parser= require('./metadata/blackberry_parser'),
ios_parser = require('./metadata/ios_parser'),
+ wp7_parser = require('./metadata/wp7_parser'),
+ wp8_parser = require('./metadata/wp8_parser'),
exec = require('child_process').exec,
et = require('elementtree');
@@ -88,6 +90,13 @@ module.exports = function plugin_loader(platform) {
case 'blackberry':
parser = new blackberry_parser(path.join(projectRoot, 'platforms', 'blackberry'));
break;
+ case 'wp7':
+ parser = new wp7_parser(path.join(projectRoot, 'platforms', 'wp7'));
+ break;
+ case 'wp8':
+ parser = new wp8_parser(path.join(projectRoot, 'platforms', 'wp8'));
+ break;
+
}
plugins && plugins.forEach(function(plugin) {
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/src/util.js
----------------------------------------------------------------------
diff --git a/src/util.js b/src/util.js
index 7ebbb17..cd34533 100644
--- a/src/util.js
+++ b/src/util.js
@@ -76,5 +76,11 @@ module.exports = {
}
return plugins;
+ },
+ projectWww: function(projectDir) {
+ return path.join(projectDir, 'www');
+ },
+ projectConfig: function(projectDir) {
+ return path.join(projectDir, 'www', 'config.xml');
}
};
[14/37] Add WP7 and WP8 platform files.
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordovalib/BrowserMouseHelper.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordovalib/BrowserMouseHelper.cs b/lib/cordova-wp8/templates/standalone/cordovalib/BrowserMouseHelper.cs
new file mode 100644
index 0000000..fc83e03
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordovalib/BrowserMouseHelper.cs
@@ -0,0 +1,162 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+using System.Linq;
+using System.Windows;
+using System.Windows.Controls;
+using Microsoft.Phone.Controls;
+using System.Windows.Input;
+using System.Diagnostics;
+using System.Windows.Media;
+using System;
+using System.Collections.Generic;
+
+namespace WPCordovaClassLib
+{
+
+ /// <summary>
+ /// Suppresses pinch zoom and optionally scrolling of the WebBrowser control
+ /// </summary>
+ public class BrowserMouseHelper
+ {
+ private WebBrowser _browser;
+
+ /// <summary>
+ /// Gets or sets whether to suppress the scrolling of
+ /// the WebBrowser control;
+ /// </summary>
+ public bool ScrollDisabled {
+ get;
+ set;
+ }
+
+ private bool userScalable = true;
+ private double maxScale = 2.0;
+ private double minScale = 0.5;
+ protected Border border;
+
+ /// <summary>
+ /// Represent min delta value to consider event as a mouse move. Experimental calculated.
+ /// </summary>
+ private const int MouseMoveDeltaThreshold = 10;
+
+ public BrowserMouseHelper(ref WebBrowser browser)
+ {
+ _browser = browser;
+ browser.Loaded += new RoutedEventHandler(browser_Loaded);
+ }
+
+ private void browser_Loaded(object sender, RoutedEventArgs e)
+ {
+ var border0 = VisualTreeHelper.GetChild(_browser, 0);
+ var border1 = VisualTreeHelper.GetChild(border0, 0);
+ var panZoom = VisualTreeHelper.GetChild(border1, 0);
+ var grid = VisualTreeHelper.GetChild(panZoom, 0);
+ var grid2 = VisualTreeHelper.GetChild(grid, 0);
+ border = VisualTreeHelper.GetChild(grid2, 0) as Border;
+
+ if (border != null)
+ {
+ border.ManipulationDelta += Border_ManipulationDelta;
+ border.ManipulationCompleted += Border_ManipulationCompleted;
+ }
+
+ _browser.LoadCompleted += Browser_LoadCompleted;
+
+ }
+
+ void ParseViewportMeta()
+ {
+ string metaScript = "(function() { return document.querySelector('meta[name=viewport]').content; })()";
+
+ try
+ {
+ string metaContent = _browser.InvokeScript("eval", new string[] { metaScript }) as string;
+ string[] arr = metaContent.Split(new[] { ' ', ',', ';' }, StringSplitOptions.RemoveEmptyEntries);
+ Dictionary<string, string> metaDictionary = new Dictionary<string, string>();
+ foreach (string val in arr)
+ {
+ string[] keyVal = val.Split('=');
+ metaDictionary.Add(keyVal[0], keyVal[1]);
+ }
+
+ this.userScalable = false; // reset to default
+ if (metaDictionary.ContainsKey("user-scalable"))
+ {
+ this.userScalable = metaDictionary["user-scalable"] == "yes";
+ }
+
+ this.maxScale = 2.0;// reset to default
+ if (metaDictionary.ContainsKey("maximum-scale"))
+ {
+ this.maxScale = double.Parse(metaDictionary["maximum-scale"]);
+ }
+
+ this.minScale = 0.5;// reset to default
+ if (metaDictionary.ContainsKey("minimum-scale"))
+ {
+ this.minScale = double.Parse(metaDictionary["minimum-scale"]);
+ }
+ }
+ catch (Exception)
+ {
+
+ }
+ }
+
+ void Browser_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
+ {
+ ParseViewportMeta();
+ }
+
+ #region ManipulationEvents
+
+ private void Border_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
+ {
+ //Debug.WriteLine("Border_ManipulationDelta");
+ // optionally suppress zoom
+ if ((ScrollDisabled || !userScalable) && (e.DeltaManipulation.Scale.X != 0.0 || e.DeltaManipulation.Scale.Y != 0.0))
+ {
+ e.Handled = true;
+ }
+ // optionally suppress scrolling
+ if (ScrollDisabled && (e.DeltaManipulation.Translation.X != 0.0 || e.DeltaManipulation.Translation.Y != 0.0))
+ {
+ e.Handled = true;
+ }
+ }
+
+ private void Border_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
+ {
+ //Debug.WriteLine("Border_ManipulationCompleted");
+ // suppress zoom
+ if (!userScalable && e.FinalVelocities != null)
+ {
+ if (e.FinalVelocities.ExpansionVelocity.X != 0.0 ||
+ e.FinalVelocities.ExpansionVelocity.Y != 0.0)
+ {
+ e.Handled = true;
+ }
+ }
+ }
+
+
+ #endregion
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordovalib/CommandFactory.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordovalib/CommandFactory.cs b/lib/cordova-wp8/templates/standalone/cordovalib/CommandFactory.cs
new file mode 100644
index 0000000..974ee79
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordovalib/CommandFactory.cs
@@ -0,0 +1,112 @@
+/*
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+using System;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using System.Collections.Generic;
+using WPCordovaClassLib.Cordova.Commands;
+using System.Reflection;
+using System.Diagnostics;
+
+namespace WPCordovaClassLib.Cordova
+{
+ /// <summary>
+ /// Provides functionality to create Cordova command by name.
+ /// </summary>
+ public static class CommandFactory
+ {
+ /// <summary>
+ /// Represents predefined namespace name for custom plugins
+ /// </summary>
+ private static readonly string CustomPluginNamespacePrefix = "Cordova.Extension.Commands.";
+
+ private static readonly string BaseCommandNamespacePrefix = "WPCordovaClassLib.Cordova.Commands.";
+
+ /// <summary>
+ /// Cache instantiated commands in a map.
+ /// </summary>
+
+ private static Dictionary<string, BaseCommand> commandMap = new Dictionary<string, BaseCommand>();
+
+ /// <summary>
+ /// Creates command using command class name. Returns null for unknown commands.
+ /// </summary>
+ /// <param name="service">Command class name, for example Device or Notification</param>
+ /// <returns>Command class instance or null</returns>
+ public static BaseCommand CreateByServiceName(string service)
+ {
+
+ if (string.IsNullOrEmpty(service))
+ {
+ throw new ArgumentNullException("service", "service to create can't be null");
+ }
+
+ if (!commandMap.ContainsKey(service))
+ {
+
+ Type t = Type.GetType(BaseCommandNamespacePrefix + service);
+
+ // custom plugin could be defined in own namespace and assembly
+ if (t == null)
+ {
+ string serviceFullName = service.Contains(".") ? service : CustomPluginNamespacePrefix + service;
+
+ foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
+ {
+ // in this case service name represents full type name including namespace
+ t = a.GetType(serviceFullName);
+
+ if (t == null) // try the Commands Namespace
+ {
+ t = a.GetType(BaseCommandNamespacePrefix + service);
+ }
+
+ if (t != null)
+ {
+ break;
+ }
+ }
+
+ }
+
+ // unknown command, still didn't find it
+ if (t == null)
+ {
+ Debug.WriteLine("Unable to locate command :: " + service);
+ return null;
+ }
+
+ commandMap[service] = Activator.CreateInstance(t) as BaseCommand;
+ }
+
+ return commandMap[service];
+ }
+
+ public static void ResetAllCommands()
+ {
+ foreach (BaseCommand bc in commandMap.Values)
+ {
+ bc.OnReset();
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordovalib/Commands/BaseCommand.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordovalib/Commands/BaseCommand.cs b/lib/cordova-wp8/templates/standalone/cordovalib/Commands/BaseCommand.cs
new file mode 100644
index 0000000..9de0e4d
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordovalib/Commands/BaseCommand.cs
@@ -0,0 +1,187 @@
+/*
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+using System;
+using System.Reflection;
+using Microsoft.Phone.Shell;
+using System.Diagnostics;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ public abstract class BaseCommand : IDisposable
+ {
+ /*
+ * All commands + plugins must extend BaseCommand, because they are dealt with as BaseCommands in CordovaView.xaml.cs
+ *
+ **/
+
+ public event EventHandler<PluginResult> OnCommandResult;
+
+ public event EventHandler<ScriptCallback> OnCustomScript;
+
+ public string CurrentCommandCallbackId { get; set; }
+
+ public BaseCommand()
+ {
+ ResultHandlers = new Dictionary<string, EventHandler<PluginResult>>();
+ PhoneApplicationService service = PhoneApplicationService.Current;
+ service.Activated += this.OnResume;
+ service.Deactivated += this.OnPause;
+ }
+
+ protected Dictionary<string, EventHandler<PluginResult>> ResultHandlers;
+ public void AddResultHandler(string callbackId, EventHandler<PluginResult> handler)
+ {
+ ResultHandlers.Add(callbackId, handler);
+ }
+ public bool RemoveResultHandler(string callbackId)
+ {
+ return ResultHandlers.Remove(callbackId);
+ }
+
+ /*
+ * InvokeMethodNamed will call the named method of a BaseCommand subclass if it exists and pass the variable arguments list along.
+ **/
+
+ public object InvokeMethodNamed(string callbackId, string methodName, params object[] args)
+ {
+ //Debug.WriteLine(string.Format("InvokeMethodNamed:{0} callbackId:{1}",methodName,callbackId));
+ this.CurrentCommandCallbackId = callbackId;
+ return InvokeMethodNamed(methodName, args);
+ }
+
+ public object InvokeMethodNamed(string methodName, params object[] args)
+ {
+ MethodInfo mInfo = this.GetType().GetMethod(methodName);
+
+ if (mInfo != null)
+ {
+ // every function handles DispatchCommandResult by itself
+ return mInfo.Invoke(this, args);
+ }
+
+ // actually methodName could refer to a property
+ if (args == null || args.Length == 0 ||
+ (args.Length == 1 && "undefined".Equals(args[0])))
+ {
+ PropertyInfo pInfo = this.GetType().GetProperty(methodName);
+ if (pInfo != null)
+ {
+ object res = pInfo.GetValue(this, null);
+
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, res));
+
+ return res;
+ }
+ }
+
+ throw new MissingMethodException(methodName);
+
+ }
+
+ [Obsolete]
+ public void InvokeCustomScript(ScriptCallback script, bool removeHandler)
+ {
+ if (this.OnCustomScript != null)
+ {
+ this.OnCustomScript(this, script);
+ if (removeHandler)
+ {
+ this.OnCustomScript = null;
+ }
+ }
+ }
+
+ public void DispatchCommandResult()
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.NO_RESULT));
+ }
+
+ public void DispatchCommandResult(PluginResult result,string callbackId="")
+ {
+ if (!string.IsNullOrEmpty(callbackId))
+ {
+ result.CallbackId = callbackId;
+ }
+ else
+ {
+ result.CallbackId = this.CurrentCommandCallbackId;
+ }
+
+ if (ResultHandlers.ContainsKey(result.CallbackId))
+ {
+ ResultHandlers[result.CallbackId](this, result);
+ }
+ else if (this.OnCommandResult != null)
+ {
+ OnCommandResult(this, result);
+ }
+ else
+ {
+ Debug.WriteLine("Failed to locate callback for id : " + result.CallbackId);
+ }
+
+ if (!result.KeepCallback)
+ {
+ this.Dispose();
+ }
+
+ }
+
+
+ /// <summary>
+ /// Occurs when the application is being deactivated.
+ /// </summary>
+ public virtual void OnReset() {}
+
+ /// <summary>
+ /// Occurs when the application is being loaded, and the config.xml has an autoload entry
+ /// </summary>
+ public virtual void OnInit() {}
+
+
+ /// <summary>
+ /// Occurs when the application is being deactivated.
+ /// </summary>
+ public virtual void OnPause(object sender, DeactivatedEventArgs e) {}
+
+ /// <summary>
+ /// Occurs when the application is being made active after previously being put
+ /// into a dormant state or tombstoned.
+ /// </summary>
+ public virtual void OnResume(object sender, Microsoft.Phone.Shell.ActivatedEventArgs e) {}
+
+ public void Dispose()
+ {
+ PhoneApplicationService service = PhoneApplicationService.Current;
+ service.Activated -= this.OnResume;
+ service.Deactivated -= this.OnPause;
+ this.OnCommandResult = null;
+ }
+
+ public static string GetBaseURL()
+ {
+#if CORDOVA_CLASSLIB
+ return "/WPCordovaClassLib;component/";
+#else
+ return "./";
+#endif
+ }
+ }
+
+
+
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordovalib/ConfigHandler.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordovalib/ConfigHandler.cs b/lib/cordova-wp8/templates/standalone/cordovalib/ConfigHandler.cs
new file mode 100644
index 0000000..06806d3
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordovalib/ConfigHandler.cs
@@ -0,0 +1,242 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Resources;
+using System.Xml.Linq;
+
+namespace WPCordovaClassLib.CordovaLib
+{
+ class ConfigHandler
+ {
+ public class PluginConfig
+ {
+ public PluginConfig(string name, bool autoLoad = false)
+ {
+ Name = name;
+ isAutoLoad = autoLoad;
+ }
+ public string Name;
+ public bool isAutoLoad;
+ }
+
+ protected Dictionary<string, PluginConfig> AllowedPlugins;
+ protected List<string> AllowedDomains;
+ protected Dictionary<string, string> Preferences;
+
+ protected bool AllowAllDomains = false;
+ protected bool AllowAllPlugins = false;
+
+ public ConfigHandler()
+ {
+ AllowedPlugins = new Dictionary<string, PluginConfig>();
+ AllowedDomains = new List<string>();
+ Preferences = new Dictionary<string, string>();
+ }
+
+ public string GetPreference(string key)
+ {
+ return Preferences[key];
+ }
+
+ protected static string[] AllowedSchemes = { "http", "https", "ftp", "ftps" };
+ protected bool SchemeIsAllowed(string scheme)
+ {
+ return AllowedSchemes.Contains(scheme);
+ }
+
+ protected void AddWhiteListEntry(string origin, bool allowSubdomains)
+ {
+
+ if (origin == "*")
+ {
+ AllowAllDomains = true;
+ }
+
+ if (AllowAllDomains)
+ {
+ return;
+ }
+
+ string hostMatchingRegex = "";
+ string hostName;
+
+ try
+ {
+
+ Uri uri = new Uri(origin.Replace("*", "replaced-text"), UriKind.Absolute);
+
+ string tempHostName = uri.Host.Replace("replaced-text", "*");
+ //if (uri.HostNameType == UriHostNameType.Dns){}
+ // starts with wildcard match - we make the first '.' optional (so '*.org.apache.cordova' will match 'org.apache.cordova')
+ if (tempHostName.StartsWith("*."))
+ { //"(\\s{0}|*.)"
+ hostName = @"\w*.*" + tempHostName.Substring(2).Replace(".", @"\.").Replace("*", @"\w*");
+ }
+ else
+ {
+ hostName = tempHostName.Replace(".", @"\.").Replace("*", @"\w*");
+ }
+ // "^https?://"
+ hostMatchingRegex = uri.Scheme + "://" + hostName + uri.PathAndQuery;
+ Debug.WriteLine("Adding regex :: " + hostMatchingRegex);
+ AllowedDomains.Add(hostMatchingRegex);
+
+ }
+ catch (Exception)
+ {
+ Debug.WriteLine("Invalid Whitelist entry (probably missing the protocol):: " + origin);
+ }
+
+ }
+
+ /**
+
+ An access request is granted for a given URI if there exists an item inside the access-request list such that:
+
+ - The URI's scheme component is the same as scheme; and
+ - if subdomains is false or if the URI's host component is not a domain name (as defined in [RFC1034]), the URI's host component is the same as host; or
+ - if subdomains is true, the URI's host component is either the same as host, or is a subdomain of host (as defined in [RFC1034]); and
+ - the URI's port component is the same as port.
+
+ **/
+
+ public bool URLIsAllowed(string url)
+ {
+ // Debug.WriteLine("Testing URLIsAllowed : " + url);
+ // easy case first
+ if (this.AllowAllDomains)
+ {
+ return true;
+ }
+ else
+ {
+ // start simple
+ Uri uri = new Uri(url, UriKind.RelativeOrAbsolute);
+ if (uri.IsAbsoluteUri)
+ {
+ if (this.SchemeIsAllowed(uri.Scheme))
+ {
+ // additional test because our pattern will always have a trailing '/'
+ string matchUrl = url;
+ if (uri.PathAndQuery == "/")
+ {
+ matchUrl = url + "/";
+ }
+ foreach (string pattern in AllowedDomains)
+ {
+ if (Regex.IsMatch(matchUrl, pattern))
+ {
+ // make sure it is at the start, and not part of the query string
+ // special case :: http://some.other.domain/page.html?x=1&g=http://build.apache.org/
+ if (Regex.IsMatch(uri.Scheme + "://" + uri.Host + "/", pattern) ||
+ (!Regex.IsMatch(uri.PathAndQuery, pattern)))
+ {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public bool IsPluginAllowed(string key)
+ {
+ return AllowAllPlugins || AllowedPlugins.Keys.Contains(key);
+ }
+
+ public string[] AutoloadPlugins
+ {
+ get
+ {
+ var res = from results in AllowedPlugins.TakeWhile(p => p.Value.isAutoLoad)
+ select results.Value.Name;
+
+ foreach (var s in res)
+ {
+ Debug.WriteLine(s);
+ }
+ //string[] res = from results in (AllowedPlugins.Where(p => p.Value.isAutoLoad) )
+ // select (string)results.Key;
+
+ return new string[] { "", "asd" };
+ }
+ }
+
+
+ public void LoadAppPackageConfig()
+ {
+ StreamResourceInfo streamInfo = Application.GetResourceStream(new Uri("config.xml", UriKind.Relative));
+
+ if (streamInfo != null)
+ {
+ StreamReader sr = new StreamReader(streamInfo.Stream);
+ //This will Read Keys Collection for the xml file
+ XDocument document = XDocument.Parse(sr.ReadToEnd());
+
+ var plugins = from results in document.Descendants("plugin")
+ select new
+ {
+ name = (string)results.Attribute("name"),
+ autoLoad = results.Attribute("onload")
+ };
+
+ foreach (var plugin in plugins)
+ {
+ Debug.WriteLine("plugin " + plugin.name);
+ PluginConfig pConfig = new PluginConfig(plugin.name, plugin.autoLoad != null && plugin.autoLoad.Value == "true");
+ if (pConfig.Name == "*")
+ {
+ AllowAllPlugins = true;
+ // break; wait, don't, some still could be autoload
+ }
+ else
+ {
+ AllowedPlugins.Add(pConfig.Name, pConfig);
+ }
+ }
+
+ var preferences = from results in document.Descendants("preference")
+ select new
+ {
+ name = (string)results.Attribute("name"),
+ value = (string)results.Attribute("value")
+ };
+
+ foreach (var pref in preferences)
+ {
+ Debug.WriteLine("pref" + pref.name + ", " + pref.value);
+ }
+
+ var accessList = from results in document.Descendants("access")
+ select new
+ {
+ origin = (string)results.Attribute("origin"),
+ subdomains = (string)results.Attribute("subdomains") == "true"
+ };
+
+ foreach (var accessElem in accessList)
+ {
+ AddWhiteListEntry(accessElem.origin, accessElem.subdomains);
+ }
+ }
+ else
+ {
+ // no config.xml, allow all
+ AllowAllDomains = true;
+ AllowAllPlugins = true;
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordovalib/CordovaCommandCall.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordovalib/CordovaCommandCall.cs b/lib/cordova-wp8/templates/standalone/cordovalib/CordovaCommandCall.cs
new file mode 100644
index 0000000..facc991
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordovalib/CordovaCommandCall.cs
@@ -0,0 +1,99 @@
+/*
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+using System;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using System.Linq;
+using System.Collections.Generic;
+
+namespace WPCordovaClassLib.Cordova
+{
+ /// <summary>
+ /// Represents Cordova native command call: action callback, etc
+ /// </summary>
+ public class CordovaCommandCall
+ {
+ public String Service { get; private set; }
+ public String Action { get; private set; }
+ public String CallbackId { get; private set; }
+ public String Args { get; private set; }
+
+ /// <summary>
+ /// Retrieves command call parameters and creates wrapper for them
+ /// </summary>
+ /// <param name="commandStr">Command string in the form 'service/action/callback/args'</param>
+ /// <returns>New class instance or null of string does not represent Cordova command</returns>
+ public static CordovaCommandCall Parse(string commandStr)
+ {
+ System.Diagnostics.Debug.WriteLine("CommandString : " + commandStr);
+ if (string.IsNullOrEmpty(commandStr))
+ {
+ return null;
+ }
+
+ string[] split = commandStr.Split('/');
+ if (split.Length < 3)
+ {
+ return null;
+ }
+
+ CordovaCommandCall commandCallParameters = new CordovaCommandCall();
+ commandCallParameters.Service = split[0];
+ commandCallParameters.Action = split[1];
+ commandCallParameters.CallbackId = split[2];
+
+ try
+ {
+ string arg = split.Length <= 3 ? "[]" : String.Join("/", split.Skip(3));
+ if (!arg.StartsWith("[")) // save the exception
+ {
+ arg = string.Format("[{0}]", arg);
+ }
+ List<string> args = JSON.JsonHelper.Deserialize<List<string>>(arg);
+ args.Add(commandCallParameters.CallbackId);
+ commandCallParameters.Args = JSON.JsonHelper.Serialize(args.ToArray());
+ }
+ catch (Exception)
+ {
+ return null;
+ }
+ // sanity check for illegal names
+ // was failing with ::
+ // CordovaCommandResult :: 1, Device1, {"status":1,"message":"{\"name\":\"XD.....
+ if (commandCallParameters.Service.IndexOfAny(new char[] { '@', ':', ',', '!', ' ' }) > -1)
+ {
+ return null;
+ }
+
+ return commandCallParameters;
+ }
+
+
+ /// <summary>
+ /// Private ctr to disable class creation.
+ /// New class instance must be initialized via CordovaCommandCall.Parse static method.
+ /// </summary>
+ private CordovaCommandCall() { }
+
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordovalib/CordovaView.xaml
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordovalib/CordovaView.xaml b/lib/cordova-wp8/templates/standalone/cordovalib/CordovaView.xaml
new file mode 100644
index 0000000..41d7631
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordovalib/CordovaView.xaml
@@ -0,0 +1,65 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<UserControl x:Class="WPCordovaClassLib.CordovaView"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ mc:Ignorable="d"
+ FontFamily="{StaticResource PhoneFontFamilyNormal}"
+ FontSize="{StaticResource PhoneFontSizeNormal}"
+ Foreground="{StaticResource PhoneForegroundBrush}"
+ d:DesignHeight="480" d:DesignWidth="480"
+ xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone">
+
+ <Grid x:Name="LayoutRoot" Background="Transparent">
+
+ <phone:WebBrowser x:Name="CordovaBrowser"
+ Opacity="0"
+ HorizontalAlignment="Stretch"
+ VerticalAlignment="Stretch"
+ IsScriptEnabled="True"
+ Foreground="White"
+ Background="Black"
+ Navigated="CordovaBrowser_Navigated"
+ Loaded="CordovaBrowser_Loaded"
+ Unloaded="CordovaBrowser_Unloaded"
+ ScriptNotify="CordovaBrowser_ScriptNotify"
+ LoadCompleted="CordovaBrowser_LoadCompleted"
+ Navigating="CordovaBrowser_Navigating"
+ NavigationFailed="CordovaBrowser_NavigationFailed"
+ IsGeolocationEnabled="True">
+ <phone:WebBrowser.Projection>
+ <PlaneProjection x:Name="BrowserProjector" CenterOfRotationX="0" RotationY="-180"/>
+ </phone:WebBrowser.Projection>
+ <phone:WebBrowser.Resources>
+ <Storyboard x:Name="RotateIn" BeginTime="0:0:0.5">
+ <DoubleAnimation
+ Storyboard.TargetName="BrowserProjector"
+ Storyboard.TargetProperty="RotationY"
+ To="0" Duration="0:0:0.6"/>
+ </Storyboard>
+ </phone:WebBrowser.Resources>
+
+ </phone:WebBrowser>
+
+ </Grid>
+</UserControl>
+
+
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordovalib/CordovaView.xaml.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordovalib/CordovaView.xaml.cs b/lib/cordova-wp8/templates/standalone/cordovalib/CordovaView.xaml.cs
new file mode 100644
index 0000000..7b92f65
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordovalib/CordovaView.xaml.cs
@@ -0,0 +1,503 @@
+/*
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using Microsoft.Phone.Controls;
+using System.IO.IsolatedStorage;
+using System.Windows.Resources;
+using System.Windows.Interop;
+using System.Runtime.Serialization.Json;
+using System.IO;
+using System.ComponentModel;
+using System.Xml.Linq;
+using WPCordovaClassLib.Cordova.Commands;
+using System.Diagnostics;
+using System.Text;
+using WPCordovaClassLib.Cordova;
+using System.Threading;
+using Microsoft.Phone.Shell;
+using WPCordovaClassLib.Cordova.JSON;
+using WPCordovaClassLib.CordovaLib;
+
+
+
+namespace WPCordovaClassLib
+{
+ public partial class CordovaView : UserControl
+ {
+
+ /// <summary>
+ /// Indicates whether web control has been loaded and no additional initialization is needed.
+ /// Prevents data clearing during page transitions.
+ /// </summary>
+ private bool IsBrowserInitialized = false;
+
+ /// <summary>
+ /// Set when the user attaches a back button handler inside the WebBrowser
+ /// </summary>
+ private bool OverrideBackButton = false;
+
+ /// <summary>
+ /// Sentinal to keep track of page changes as a result of the hardware back button
+ /// Set to false when the back-button is pressed, which calls js window.history.back()
+ /// If the page changes as a result of the back button the event is cancelled.
+ /// </summary>
+ private bool PageDidChange = false;
+
+ private static string AppRoot = "";
+
+
+ /// <summary>
+ /// Handles native api calls
+ /// </summary>
+ private NativeExecution nativeExecution;
+
+ protected BrowserMouseHelper bmHelper;
+ protected DOMStorageHelper domStorageHelper;
+ protected OrientationHelper orientationHelper;
+
+ private ConfigHandler configHandler;
+
+ public System.Windows.Controls.Grid _LayoutRoot
+ {
+ get
+ {
+ return ((System.Windows.Controls.Grid)(this.FindName("LayoutRoot")));
+ }
+ }
+
+ public WebBrowser Browser
+ {
+ get
+ {
+ return CordovaBrowser;
+ }
+ }
+
+ /*
+ * Setting StartPageUri only has an effect if called before the view is loaded.
+ **/
+ protected Uri _startPageUri = null;
+ public Uri StartPageUri
+ {
+ get
+ {
+ if (_startPageUri == null)
+ {
+ // default
+ return new Uri(AppRoot + "www/index.html", UriKind.Relative);
+ }
+ else
+ {
+ return _startPageUri;
+ }
+ }
+ set
+ {
+ if (!this.IsBrowserInitialized)
+ {
+ _startPageUri = value;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets whether to suppress bouncy scrolling of
+ /// the WebBrowser control;
+ /// </summary>
+ public bool DisableBouncyScrolling
+ {
+ get;
+ set;
+ }
+
+ public CordovaView()
+ {
+
+ InitializeComponent();
+
+ if (DesignerProperties.IsInDesignTool)
+ {
+ return;
+ }
+
+
+ StartupMode mode = PhoneApplicationService.Current.StartupMode;
+
+ if (mode == StartupMode.Launch)
+ {
+ PhoneApplicationService service = PhoneApplicationService.Current;
+ service.Activated += new EventHandler<Microsoft.Phone.Shell.ActivatedEventArgs>(AppActivated);
+ service.Launching += new EventHandler<LaunchingEventArgs>(AppLaunching);
+ service.Deactivated += new EventHandler<DeactivatedEventArgs>(AppDeactivated);
+ service.Closing += new EventHandler<ClosingEventArgs>(AppClosing);
+ }
+ else
+ {
+
+ }
+
+ // initializes native execution logic
+ configHandler = new ConfigHandler();
+ configHandler.LoadAppPackageConfig();
+
+ nativeExecution = new NativeExecution(ref this.CordovaBrowser);
+ bmHelper = new BrowserMouseHelper(ref this.CordovaBrowser);
+ }
+
+
+
+ void AppClosing(object sender, ClosingEventArgs e)
+ {
+ Debug.WriteLine("AppClosing");
+ }
+
+ void AppDeactivated(object sender, DeactivatedEventArgs e)
+ {
+ Debug.WriteLine("INFO: AppDeactivated");
+
+ try
+ {
+ CordovaBrowser.InvokeScript("eval", new string[] { "cordova.fireDocumentEvent('pause');" });
+ }
+ catch (Exception)
+ {
+ Debug.WriteLine("ERROR: Pause event error");
+ }
+ }
+
+ void AppLaunching(object sender, LaunchingEventArgs e)
+ {
+ Debug.WriteLine("INFO: AppLaunching");
+ }
+
+ void AppActivated(object sender, Microsoft.Phone.Shell.ActivatedEventArgs e)
+ {
+ Debug.WriteLine("INFO: AppActivated");
+ try
+ {
+ CordovaBrowser.InvokeScript("eval", new string[] { "cordova.fireDocumentEvent('resume');" });
+ }
+ catch (Exception)
+ {
+ Debug.WriteLine("ERROR: Resume event error");
+ }
+ }
+
+ void CordovaBrowser_Loaded(object sender, RoutedEventArgs e)
+ {
+ this.bmHelper.ScrollDisabled = this.DisableBouncyScrolling;
+
+ if (DesignerProperties.IsInDesignTool)
+ {
+ return;
+ }
+
+ // prevents refreshing web control to initial state during pages transitions
+ if (this.IsBrowserInitialized) return;
+
+
+
+ this.domStorageHelper = new DOMStorageHelper(this.CordovaBrowser);
+
+ try
+ {
+
+ // Before we possibly clean the ISO-Store, we need to grab our generated UUID, so we can rewrite it after.
+ string deviceUUID = "";
+
+ using (IsolatedStorageFile appStorage = IsolatedStorageFile.GetUserStoreForApplication())
+ {
+ try
+ {
+ IsolatedStorageFileStream fileStream = new IsolatedStorageFileStream("DeviceID.txt", FileMode.Open, FileAccess.Read, appStorage);
+
+ using (StreamReader reader = new StreamReader(fileStream))
+ {
+ deviceUUID = reader.ReadLine();
+ }
+ }
+ catch (Exception /*ex*/)
+ {
+ deviceUUID = Guid.NewGuid().ToString();
+ }
+
+ Debug.WriteLine("Updating IsolatedStorage for APP:DeviceID :: " + deviceUUID);
+ IsolatedStorageFileStream file = new IsolatedStorageFileStream("DeviceID.txt", FileMode.Create, FileAccess.Write, appStorage);
+ using (StreamWriter writeFile = new StreamWriter(file))
+ {
+ writeFile.WriteLine(deviceUUID);
+ writeFile.Close();
+ }
+
+ }
+
+ /*
+ * 11/08/12 Ruslan Kokorev
+ * Copying files to isolated storage is no more required in WP8. WebBrowser control now works with files located in XAP.
+ */
+
+ //StreamResourceInfo streamInfo = Application.GetResourceStream(new Uri("CordovaSourceDictionary.xml", UriKind.Relative));
+
+ //if (streamInfo != null)
+ //{
+ // StreamReader sr = new StreamReader(streamInfo.Stream);
+ // //This will Read Keys Collection for the xml file
+
+ // XDocument document = XDocument.Parse(sr.ReadToEnd());
+
+ // var files = from results in document.Descendants("FilePath")
+ // select new
+ // {
+ // path = (string)results.Attribute("Value")
+ // };
+ // StreamResourceInfo fileResourceStreamInfo;
+
+ // using (IsolatedStorageFile appStorage = IsolatedStorageFile.GetUserStoreForApplication())
+ // {
+
+ // foreach (var file in files)
+ // {
+ // fileResourceStreamInfo = Application.GetResourceStream(new Uri(file.path, UriKind.Relative));
+
+ // if (fileResourceStreamInfo != null)
+ // {
+ // using (BinaryReader br = new BinaryReader(fileResourceStreamInfo.Stream))
+ // {
+ // byte[] data = br.ReadBytes((int)fileResourceStreamInfo.Stream.Length);
+
+ // string strBaseDir = AppRoot + file.path.Substring(0, file.path.LastIndexOf(System.IO.Path.DirectorySeparatorChar));
+
+ // if (!appStorage.DirectoryExists(strBaseDir))
+ // {
+ // Debug.WriteLine("INFO: Creating Directory :: " + strBaseDir);
+ // appStorage.CreateDirectory(strBaseDir);
+ // }
+
+ // // This will truncate/overwrite an existing file, or
+ // using (IsolatedStorageFileStream outFile = appStorage.OpenFile(AppRoot + file.path, FileMode.Create))
+ // {
+ // Debug.WriteLine("INFO: Writing data for " + AppRoot + file.path + " and length = " + data.Length);
+ // using (var writer = new BinaryWriter(outFile))
+ // {
+ // writer.Write(data);
+ // }
+ // }
+ // }
+ // }
+ // else
+ // {
+ // Debug.WriteLine("ERROR: Failed to write file :: " + file.path + " did you forget to add it to the project?");
+ // }
+ // }
+ // }
+ //}
+
+ CordovaBrowser.Navigate(StartPageUri);
+ IsBrowserInitialized = true;
+ AttachHardwareButtonHandlers();
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine("ERROR: Exception in CordovaBrowser_Loaded :: {0}", ex.Message);
+ }
+ }
+
+ void AttachHardwareButtonHandlers()
+ {
+ PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
+ if (frame != null)
+ {
+ PhoneApplicationPage page = frame.Content as PhoneApplicationPage;
+
+ if (page != null)
+ {
+ page.BackKeyPress += new EventHandler<CancelEventArgs>(page_BackKeyPress);
+
+ this.orientationHelper = new OrientationHelper(this.CordovaBrowser, page);
+
+ }
+ }
+ }
+
+ void page_BackKeyPress(object sender, CancelEventArgs e)
+ {
+
+ if (OverrideBackButton)
+ {
+ try
+ {
+ CordovaBrowser.InvokeScript("eval", new string[] { "cordova.fireDocumentEvent('backbutton');" });
+ e.Cancel = true;
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine("Exception while invoking backbutton into cordova view: " + ex.Message);
+ }
+ }
+ else
+ {
+ try
+ {
+ PageDidChange = false;
+
+ Uri uriBefore = this.Browser.Source;
+ // calling js history.back with result in a page change if history was valid.
+ CordovaBrowser.InvokeScript("eval", new string[] { "(function(){window.history.back();})()" });
+
+ Uri uriAfter = this.Browser.Source;
+
+ e.Cancel = PageDidChange || (uriBefore != uriAfter);
+ }
+ catch (Exception)
+ {
+ e.Cancel = false; // exit the app ... ?
+ }
+ }
+ }
+
+ void CordovaBrowser_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
+ {
+ string[] autoloadPlugs = this.configHandler.AutoloadPlugins;
+ foreach (string plugName in autoloadPlugs)
+ {
+ // nativeExecution.ProcessCommand(commandCallParams);
+ }
+
+ string nativeReady = "(function(){ cordova.require('cordova/channel').onNativeReady.fire()})();";
+
+ try
+ {
+ CordovaBrowser.InvokeScript("execScript", new string[] { nativeReady });
+ }
+ catch (Exception /*ex*/)
+ {
+ Debug.WriteLine("Error calling js to fire nativeReady event. Did you include cordova-x.x.x.js in your html script tag?");
+ }
+
+ if (this.CordovaBrowser.Opacity < 1)
+ {
+ this.CordovaBrowser.Opacity = 1;
+ RotateIn.Begin();
+ }
+ }
+
+
+ void CordovaBrowser_Navigating(object sender, NavigatingEventArgs e)
+ {
+ if (!configHandler.URLIsAllowed(e.Uri.ToString()))
+ {
+ Debug.WriteLine("Whitelist exception: Stopping browser from navigating to :: " + e.Uri.ToString());
+ e.Cancel = true;
+ return;
+ }
+
+ this.PageDidChange = true;
+ this.nativeExecution.ResetAllCommands();
+ }
+
+ /*
+ * This method does the work of routing commands
+ * NotifyEventArgs.Value contains a string passed from JS
+ * If the command already exists in our map, we will just attempt to call the method(action) specified, and pass the args along
+ * Otherwise, we create a new instance of the command, add it to the map, and call it ...
+ * This method may also receive JS error messages caught by window.onerror, in any case where the commandStr does not appear to be a valid command
+ * it is simply output to the debugger output, and the method returns.
+ *
+ **/
+ void CordovaBrowser_ScriptNotify(object sender, NotifyEventArgs e)
+ {
+ string commandStr = e.Value;
+
+ if (commandStr.IndexOf("DOMStorage") == 0)
+ {
+ this.domStorageHelper.HandleStorageCommand(commandStr);
+ return;
+ }
+ else if (commandStr.IndexOf("Orientation") == 0)
+ {
+ this.orientationHelper.HandleCommand(commandStr);
+ return;
+ }
+
+ CordovaCommandCall commandCallParams = CordovaCommandCall.Parse(commandStr);
+
+ if (commandCallParams == null)
+ {
+ // ERROR
+ Debug.WriteLine("ScriptNotify :: " + commandStr);
+ }
+ else if (commandCallParams.Service == "CoreEvents")
+ {
+ switch (commandCallParams.Action.ToLower())
+ {
+ case "overridebackbutton":
+ string arg0 = JsonHelper.Deserialize<string[]>(commandCallParams.Args)[0];
+ this.OverrideBackButton = (arg0 != null && arg0.Length > 0 && arg0.ToLower() == "true");
+ break;
+ }
+ }
+ else
+ {
+ if (configHandler.IsPluginAllowed(commandCallParams.Service))
+ {
+ nativeExecution.ProcessCommand(commandCallParams);
+ }
+ else
+ {
+ Debug.WriteLine("Error::Plugin not allowed in config.xml. " + commandCallParams.Service);
+ }
+ }
+ }
+
+ public void LoadPage(string url)
+ {
+ if (this.configHandler.URLIsAllowed(url))
+ {
+ this.CordovaBrowser.Navigate(new Uri(url, UriKind.RelativeOrAbsolute));
+ }
+ else
+ {
+ Debug.WriteLine("Oops, Can't load url based on config.xml :: " + url);
+ }
+ }
+
+ private void CordovaBrowser_Unloaded(object sender, RoutedEventArgs e)
+ {
+
+ }
+
+ private void CordovaBrowser_NavigationFailed(object sender, System.Windows.Navigation.NavigationFailedEventArgs e)
+ {
+ Debug.WriteLine("CordovaBrowser_NavigationFailed :: " + e.Uri.ToString());
+ }
+
+ private void CordovaBrowser_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
+ {
+ Debug.WriteLine("CordovaBrowser_Navigated :: " + e.Uri.ToString());
+ }
+
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordovalib/DOMStorageHelper.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordovalib/DOMStorageHelper.cs b/lib/cordova-wp8/templates/standalone/cordovalib/DOMStorageHelper.cs
new file mode 100644
index 0000000..01b6273
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordovalib/DOMStorageHelper.cs
@@ -0,0 +1,145 @@
+/*
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+using System;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using System.IO.IsolatedStorage;
+using System.Collections.Generic;
+using Microsoft.Phone.Controls;
+using System.Linq;
+using WPCordovaClassLib.Cordova.JSON;
+
+/*
+ * Translates DOMStorage API between JS and Isolated Storage
+ * Missing pieces : QUOTA_EXCEEDED_ERR + StorageEvent
+ * */
+
+namespace WPCordovaClassLib
+{
+ public class DOMStorageHelper
+ {
+ protected WebBrowser webBrowser1;
+
+ public DOMStorageHelper(WebBrowser aBrowser)
+ {
+ this.webBrowser1 = aBrowser;
+ // always clear session at creation
+ UserSettings["sessionStorage"] = new Dictionary<string, string>();
+
+ if (!UserSettings.Contains("localStorage"))
+ {
+ UserSettings["localStorage"] = new Dictionary<string, string>();
+ UserSettings.Save();
+ }
+ Application.Current.Exit += new EventHandler(OnAppExit);
+ }
+
+ void OnAppExit(object sender, EventArgs e)
+ {
+ UserSettings.Remove("sessionStorage");
+ UserSettings.Save();
+ }
+
+ protected IsolatedStorageSettings UserSettings
+ {
+ get
+ {
+ return IsolatedStorageSettings.ApplicationSettings;
+ }
+ }
+
+ protected Dictionary<string, string> getStorageByType(string type)
+ {
+ if (!UserSettings.Contains(type))
+ {
+ UserSettings[type] = new Dictionary<string, string>();
+ UserSettings.Save();
+ }
+ return UserSettings[type] as Dictionary<string, string>;
+ }
+
+
+ public void HandleStorageCommand(string commandStr)
+ {
+
+ string[] split = commandStr.Split('/');
+ if (split.Length > 3)
+ {
+ string api = split[0];
+ string type = split[1]; // localStorage || sessionStorage
+ string command = split[2];
+ string param = split[3];
+
+ Dictionary<string, string> currentStorage = getStorageByType(type);
+
+ switch (command)
+ {
+ case "get":
+ {
+
+ if (currentStorage.Keys.Contains(param))
+ {
+ string value = currentStorage[param];
+ webBrowser1.InvokeScript("execScript", "window." + type + ".onResult('" + param + "','" + value + "');");
+ }
+ else
+ {
+ webBrowser1.InvokeScript("execScript", "window." + type + ".onResult('" + param + "');");
+ }
+
+ }
+ break;
+ case "load":
+ {
+ string[] keys = currentStorage.Keys.ToArray();
+ string jsonString = JsonHelper.Serialize(keys);
+ string callbackJS = "window." + type + ".onKeysChanged('" + jsonString + "');";
+ webBrowser1.InvokeScript("execScript", callbackJS);
+ }
+ break;
+ case "set":
+ {
+ // TODO: check that length is not out of bounds
+ currentStorage[param] = split[4];
+ UserSettings.Save();
+ string[] keys = currentStorage.Keys.ToArray();
+ string jsonString = JsonHelper.Serialize(keys);
+ string callbackJS = "window." + type + ".onKeysChanged('" + jsonString + "');";
+ webBrowser1.InvokeScript("execScript", callbackJS);
+ }
+ break;
+ case "remove":
+ currentStorage.Remove(param);
+ UserSettings.Save();
+ break;
+ case "clear":
+ currentStorage = new Dictionary<string, string>();
+ UserSettings[type] = currentStorage;
+ UserSettings.Save();
+ break;
+ }
+
+ }
+
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordovalib/JSON/JsonHelper.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordovalib/JSON/JsonHelper.cs b/lib/cordova-wp8/templates/standalone/cordovalib/JSON/JsonHelper.cs
new file mode 100644
index 0000000..44511f6
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordovalib/JSON/JsonHelper.cs
@@ -0,0 +1,97 @@
+/*
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+using System;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using System.Runtime.Serialization.Json;
+using System.IO;
+using System.Collections.Generic;
+using System.Text;
+using System.Diagnostics;
+
+namespace WPCordovaClassLib.Cordova.JSON
+{
+ /// <summary>
+ /// Provides JSON serialization/deserialization functionality.
+ /// </summary>
+ public static class JsonHelper
+ {
+ /// <summary>
+ /// Serializes object to JSON string representation
+ /// </summary>
+ /// <param name="obj">object to serialize</param>
+ /// <returns>JSON representation of the object. Returns 'null' string for null passed as argument</returns>
+ public static string Serialize(object obj)
+ {
+ if (obj == null)
+ {
+ return "null";
+ }
+
+ DataContractJsonSerializer ser = new DataContractJsonSerializer(obj.GetType());
+
+ MemoryStream ms = new MemoryStream();
+ ser.WriteObject(ms, obj);
+
+ ms.Position = 0;
+
+ string json = String.Empty;
+
+ using (StreamReader sr = new StreamReader(ms))
+ {
+ json = sr.ReadToEnd();
+ }
+
+ ms.Close();
+
+ return json;
+
+ }
+
+ /// <summary>
+ /// Parses json string to object instance
+ /// </summary>
+ /// <typeparam name="T">type of the object</typeparam>
+ /// <param name="json">json string representation of the object</param>
+ /// <returns>Deserialized object instance</returns>
+ public static T Deserialize<T>(string json)
+ {
+ DataContractJsonSerializer deserializer = new DataContractJsonSerializer(typeof(T));
+ object result = null;
+ try
+ {
+ using (MemoryStream mem = new MemoryStream(Encoding.UTF8.GetBytes(json)))
+ {
+ result = deserializer.ReadObject(mem);
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine(ex.Message);
+ Debug.WriteLine("Failed to deserialize " + typeof(T) + " with JSON value :: " + json);
+ }
+
+ return (T)result;
+
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordovalib/NativeExecution.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordovalib/NativeExecution.cs b/lib/cordova-wp8/templates/standalone/cordovalib/NativeExecution.cs
new file mode 100644
index 0000000..af6b207
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordovalib/NativeExecution.cs
@@ -0,0 +1,246 @@
+/*
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+using System;
+using System.Diagnostics;
+using System.Threading;
+using Microsoft.Devices;
+using Microsoft.Phone.Controls;
+using WPCordovaClassLib.Cordova.Commands;
+using System.Windows;
+
+namespace WPCordovaClassLib.Cordova
+{
+ /// <summary>
+ /// Implements logic to execute native command and return result back.
+ /// All commands are executed asynchronous.
+ /// </summary>
+ public class NativeExecution
+ {
+ /// <summary>
+ /// Reference to web part where application is hosted
+ /// </summary>
+ private readonly WebBrowser webBrowser;
+
+ /// <summary>
+ /// Creates new instance of a NativeExecution class.
+ /// </summary>
+ /// <param name="browser">Reference to web part where application is hosted</param>
+ public NativeExecution(ref WebBrowser browser)
+ {
+ if (browser == null)
+ {
+ throw new ArgumentNullException("browser");
+ }
+
+ this.webBrowser = browser;
+ }
+
+ /// <summary>
+ /// Returns where application is running on emulator
+ /// </summary>
+ /// <returns>True if running on emulator, otherwise False</returns>
+ public static bool IsRunningOnEmulator()
+ {
+ return Microsoft.Devices.Environment.DeviceType == DeviceType.Emulator;
+ }
+
+ public void ResetAllCommands()
+ {
+ CommandFactory.ResetAllCommands();
+ }
+
+ public void AutoLoadCommand(string commandService)
+ {
+ BaseCommand bc = CommandFactory.CreateByServiceName(commandService);
+ if (bc != null)
+ {
+ bc.OnInit();
+ }
+
+ }
+
+ /// <summary>
+ /// Executes command and returns result back.
+ /// </summary>
+ /// <param name="commandCallParams">Command to execute</param>
+ public void ProcessCommand(CordovaCommandCall commandCallParams)
+ {
+
+ if (commandCallParams == null)
+ {
+ throw new ArgumentNullException("commandCallParams");
+ }
+
+ try
+ {
+ BaseCommand bc = CommandFactory.CreateByServiceName(commandCallParams.Service);
+
+ if (bc == null)
+ {
+ this.OnCommandResult(commandCallParams.CallbackId, new PluginResult(PluginResult.Status.CLASS_NOT_FOUND_EXCEPTION));
+ return;
+ }
+
+ EventHandler<PluginResult> OnCommandResultHandler = delegate(object o, PluginResult res)
+ {
+ if (res.CallbackId == null || res.CallbackId == commandCallParams.CallbackId)
+ {
+ this.OnCommandResult(commandCallParams.CallbackId, res);
+ if (!res.KeepCallback)
+ {
+ bc.RemoveResultHandler(commandCallParams.CallbackId);
+ }
+ }
+ };
+
+ //bc.OnCommandResult += OnCommandResultHandler;
+ bc.AddResultHandler(commandCallParams.CallbackId, OnCommandResultHandler);
+
+ EventHandler<ScriptCallback> OnCustomScriptHandler = delegate(object o, ScriptCallback script)
+ {
+ this.InvokeScriptCallback(script);
+ };
+
+ bc.OnCustomScript += OnCustomScriptHandler;
+
+ ThreadStart methodInvokation = () =>
+ {
+ try
+ {
+ bc.InvokeMethodNamed(commandCallParams.CallbackId,commandCallParams.Action, commandCallParams.Args);
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine("ERROR: Exception in ProcessCommand :: " + ex.Message);
+ bc.RemoveResultHandler(commandCallParams.CallbackId);
+ bc.OnCustomScript -= OnCustomScriptHandler;
+
+ Debug.WriteLine("ERROR: failed to InvokeMethodNamed :: " + commandCallParams.Action + " on Object :: " + commandCallParams.Service);
+ this.OnCommandResult(commandCallParams.CallbackId, new PluginResult(PluginResult.Status.INVALID_ACTION));
+ return;
+ }
+ };
+
+ if ((bc is File) || (bc is Accelerometer))
+ {
+ // Due to some issues with the IsolatedStorage in current version of WP8 SDK we have to run all File Api commands synchronously.
+ // TODO: test this in WP8 RTM
+ methodInvokation.Invoke();
+ }
+ else
+ {
+ new Thread(methodInvokation).Start();
+ }
+
+
+ }
+ catch (Exception ex)
+ {
+ // ERROR
+ Debug.WriteLine(String.Format("ERROR: Unable to execute command :: {0}:{1}:{3} ",
+ commandCallParams.Service, commandCallParams.Action, ex.Message));
+
+ this.OnCommandResult(commandCallParams.CallbackId, new PluginResult(PluginResult.Status.ERROR));
+ return;
+ }
+ }
+
+ /// <summary>
+ /// Handles command execution result.
+ /// </summary>
+ /// <param name="callbackId">Command callback identifier on client side</param>
+ /// <param name="result">Execution result</param>
+ private void OnCommandResult(string callbackId, PluginResult result)
+ {
+ #region args checking
+
+ if (result == null)
+ {
+ Debug.WriteLine("ERROR: OnCommandResult missing result argument");
+ return;
+ }
+
+ if (String.IsNullOrEmpty(callbackId))
+ {
+ Debug.WriteLine("ERROR: OnCommandResult missing callbackId argument");
+ return;
+ }
+
+ if (!String.IsNullOrEmpty(result.CallbackId) && callbackId != result.CallbackId)
+ {
+ Debug.WriteLine("Multiple Overlapping Results :: " + result.CallbackId + " :: " + callbackId);
+ return;
+ }
+
+ #endregion
+
+ string jsonResult = result.ToJSONString();
+
+ string callback;
+ string args = string.Format("('{0}',{1});", callbackId, jsonResult);
+
+ if (result.Result == PluginResult.Status.NO_RESULT ||
+ result.Result == PluginResult.Status.OK)
+ {
+ callback = @"(function(callbackId,args) {
+ try { args.message = JSON.parse(args.message); } catch (ex) { }
+ cordova.callbackSuccess(callbackId,args);
+ })" + args;
+ }
+ else
+ {
+ callback = @"(function(callbackId,args) {
+ try { args.message = JSON.parse(args.message); } catch (ex) { }
+ cordova.callbackError(callbackId,args);
+ })" + args;
+ }
+ this.InvokeScriptCallback(new ScriptCallback("eval", new string[] { callback }));
+
+ }
+
+ /// <summary>
+ /// Executes client java script
+ /// </summary>
+ /// <param name="script">Script to execute on client side</param>
+ private void InvokeScriptCallback(ScriptCallback script)
+ {
+ if (script == null)
+ {
+ throw new ArgumentNullException("script");
+ }
+
+ if (String.IsNullOrEmpty(script.ScriptName))
+ {
+ throw new ArgumentNullException("ScriptName");
+ }
+
+ //Debug.WriteLine("INFO:: About to invoke ::" + script.ScriptName + " with args ::" + script.Args[0]);
+ this.webBrowser.Dispatcher.BeginInvoke((ThreadStart)delegate()
+ {
+ try
+ {
+ //Debug.WriteLine("INFO:: InvokingScript::" + script.ScriptName + " with args ::" + script.Args[0]);
+ this.webBrowser.InvokeScript(script.ScriptName, script.Args);
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine("ERROR: Exception in InvokeScriptCallback :: " + ex.Message);
+ }
+
+ });
+ }
+
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordovalib/OrientationHelper.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordovalib/OrientationHelper.cs b/lib/cordova-wp8/templates/standalone/cordovalib/OrientationHelper.cs
new file mode 100644
index 0000000..0e29b22
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordovalib/OrientationHelper.cs
@@ -0,0 +1,128 @@
+/*
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+using System;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using Microsoft.Phone.Controls;
+
+namespace WPCordovaClassLib.Cordova
+{
+ public class OrientationHelper
+ {
+ protected WebBrowser CordovaBrowser;
+ protected PhoneApplicationPage Page;
+ // private PageOrientation CurrentOrientation = PageOrientation.PortraitUp;
+ //private PageOrientation[] SupportedOrientations; // TODO:
+
+ public OrientationHelper(WebBrowser browser, PhoneApplicationPage page)
+ {
+ CordovaBrowser = browser;
+ Page = page;
+
+ Page.OrientationChanged += new EventHandler<OrientationChangedEventArgs>(page_OrientationChanged);
+ CordovaBrowser.LoadCompleted += new System.Windows.Navigation.LoadCompletedEventHandler(browser_LoadCompleted);
+
+
+ }
+
+ void browser_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
+ {
+ int i = 0;
+
+ switch (Page.Orientation)
+ {
+ case PageOrientation.Portrait: // intentional fall through
+ case PageOrientation.PortraitUp:
+ i = 0;
+ break;
+ case PageOrientation.PortraitDown:
+ i = 180;
+ break;
+ case PageOrientation.Landscape: // intentional fall through
+ case PageOrientation.LandscapeLeft:
+ i = -90;
+ break;
+ case PageOrientation.LandscapeRight:
+ i = 90;
+ break;
+ }
+ // Cordova.fireEvent('orientationchange', window);
+ string jsCallback = String.Format("window.orientation = {0};", i);
+
+ try
+ {
+ CordovaBrowser.InvokeScript("execScript", jsCallback);
+ }
+ catch (Exception)
+ {
+ }
+ }
+
+ void page_OrientationChanged(object sender, OrientationChangedEventArgs e)
+ {
+ int i = 0;
+
+ switch (e.Orientation)
+ {
+ case PageOrientation.Portrait: // intentional fall through
+ case PageOrientation.PortraitUp:
+ i = 0;
+ break;
+ case PageOrientation.PortraitDown:
+ i = 180;
+ break;
+ case PageOrientation.Landscape: // intentional fall through
+ case PageOrientation.LandscapeLeft:
+ i = -90;
+ break;
+ case PageOrientation.LandscapeRight:
+ i = 90;
+ break;
+ }
+ // Cordova.fireEvent('orientationchange', window);
+ string jsCallback = String.Format("window.orientation = {0};", i);
+
+ try
+ {
+
+ CordovaBrowser.InvokeScript("execScript", jsCallback);
+
+ jsCallback = "var evt = document.createEvent('HTMLEvents');";
+ jsCallback += "evt.initEvent( 'orientationchange', true, false );";
+ jsCallback += "window.dispatchEvent(evt);";
+ jsCallback += "if(window.onorientationchange){window.onorientationchange(evt);}";
+
+ CordovaBrowser.InvokeScript("execScript", jsCallback);
+ }
+ catch (Exception)
+ {
+ }
+ }
+
+ public void HandleCommand(string commandStr)
+ {
+
+ }
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordovalib/PluginResult.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordovalib/PluginResult.cs b/lib/cordova-wp8/templates/standalone/cordovalib/PluginResult.cs
new file mode 100644
index 0000000..00017d2
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordovalib/PluginResult.cs
@@ -0,0 +1,139 @@
+/*
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+using System;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using System.Text;
+using System.Diagnostics;
+
+namespace WPCordovaClassLib.Cordova
+{
+ /// <summary>
+ /// Represents command execution result
+ /// </summary>
+ public class PluginResult : EventArgs
+ {
+ /// <summary>
+ /// Predefined resultant messages
+ /// </summary>
+ public static string[] StatusMessages = new string[]
+ {
+ "No result",
+ "OK",
+ "Class not found",
+ "Illegal access",
+ "Instantiation error",
+ "Malformed url",
+ "IO error",
+ "Invalid action",
+ "JSON error",
+ "Error"
+ };
+
+ /// <summary>
+ /// Possible command results status codes
+ /// </summary>
+ public enum Status : int
+ {
+ NO_RESULT = 0,
+ OK,
+ CLASS_NOT_FOUND_EXCEPTION,
+ ILLEGAL_ACCESS_EXCEPTION,
+ INSTANTIATION_EXCEPTION,
+ MALFORMED_URL_EXCEPTION,
+ IO_EXCEPTION,
+ INVALID_ACTION,
+ JSON_EXCEPTION,
+ ERROR
+ };
+
+ public Status Result { get; private set; }
+ public string Message { get; set; }
+ public bool KeepCallback { get; set; }
+ public string CallbackId { get; set; }
+
+ /// <summary>
+ /// Whether command succeded or not
+ /// </summary>
+ public bool IsSuccess
+ {
+ get
+ {
+ return this.Result == Status.OK || this.Result == Status.NO_RESULT;
+ }
+ }
+
+ /// <summary>
+ /// Creates new instance of the PluginResult class.
+ /// </summary>
+ /// <param name="status">Execution result</param>
+ public PluginResult(Status status)
+ : this(status, PluginResult.StatusMessages[(int)status])
+ {
+ }
+
+ /// <summary>
+ /// Creates new instance of the PluginResult class.
+ /// </summary>
+ /// <param name="status">Execution result</param>
+ /// <param name="message">The message</param>
+ public PluginResult(Status status, object message)
+ {
+ this.Result = status;
+ this.Message = JSON.JsonHelper.Serialize(message);
+ }
+
+ public string ToJSONString()
+ {
+ string res = String.Format("\"status\":{0},\"message\":{1},\"keepCallback\":{2}",
+ (int)this.Result,
+ this.Message,
+ this.KeepCallback.ToString().ToLower());
+
+ res = "{" + res + "}";
+ return res;
+
+ }
+
+ [Obsolete]
+ public string ToCallbackString(string callbackId, string successCallback, string errorCallback)
+ {
+ if (this.IsSuccess)
+ {
+ StringBuilder buf = new StringBuilder("");
+ buf.Append(String.Format("{0}('{1}',{2});", successCallback, callbackId, this.ToJSONString()));
+ return buf.ToString();
+ }
+ else
+ {
+ return String.Format("{0}('{1}',{2});", errorCallback, callbackId, this.ToJSONString());
+ }
+ }
+
+ public override String ToString()
+ {
+ return this.ToJSONString();
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordovalib/ScriptCallback.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordovalib/ScriptCallback.cs b/lib/cordova-wp8/templates/standalone/cordovalib/ScriptCallback.cs
new file mode 100644
index 0000000..7878134
--- /dev/null
+++ b/lib/cordova-wp8/templates/standalone/cordovalib/ScriptCallback.cs
@@ -0,0 +1,80 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+using System;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using WPCordovaClassLib.Cordova.JSON;
+using System.Diagnostics;
+
+namespace WPCordovaClassLib.Cordova
+{
+ /// <summary>
+ /// Represents client script function to execute
+ /// </summary>
+ public class ScriptCallback : EventArgs
+ {
+ /// <summary>
+ /// The scripting function to execute.
+ /// </summary>
+ public string ScriptName { get; private set; }
+
+ /// <summary>
+ /// A variable number of strings to pass to the function as parameters.
+ /// </summary>
+ public string[] Args { get; private set; }
+
+ /// <summary>
+ /// Creates new instance of a ScriptCallback class.
+ /// </summary>
+ /// <param name="function">The scripting function to execute</param>
+ /// <param name="args">A variable number of strings to pass to the function as parameters</param>
+ public ScriptCallback(string function, string[] args)
+ {
+ this.ScriptName = function;
+ this.Args = args;
+ }
+
+ /// <summary>
+ /// Creates new instance of a ScriptCallback class.
+ /// </summary>
+ /// <param name="function">The scripting function to execute</param>
+ /// <param name="id">The id argument</param>
+ /// <param name="msg">The message argument</param>
+ /// <param name="value">The value argument</param>
+ public ScriptCallback(string function, string id, object msg, object value)
+ {
+ this.ScriptName = function;
+
+ String arg = String.Format("{{\"id\": {0}, \"msg\": {1}, \"value\": {2}}}",
+ JsonHelper.Serialize(id), JsonHelper.Serialize(msg), JsonHelper.Serialize(value));
+
+ this.Args = new string[] { arg };
+ }
+
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/cordovalib/resources/notification-beep.wav
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/cordovalib/resources/notification-beep.wav b/lib/cordova-wp8/templates/standalone/cordovalib/resources/notification-beep.wav
new file mode 100644
index 0000000..d0ad085
Binary files /dev/null and b/lib/cordova-wp8/templates/standalone/cordovalib/resources/notification-beep.wav differ
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/templates/standalone/resources/notification-beep.wav
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/templates/standalone/resources/notification-beep.wav b/lib/cordova-wp8/templates/standalone/resources/notification-beep.wav
new file mode 100644
index 0000000..d0ad085
Binary files /dev/null and b/lib/cordova-wp8/templates/standalone/resources/notification-beep.wav differ
[11/37] Add WP7 and WP8 platform files.
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/html/SpecView.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/html/SpecView.js b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/html/SpecView.js
new file mode 100644
index 0000000..8769bb8
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/html/SpecView.js
@@ -0,0 +1,79 @@
+jasmine.HtmlReporter.SpecView = function(spec, dom, views) {
+ this.spec = spec;
+ this.dom = dom;
+ this.views = views;
+
+ this.symbol = this.createDom('li', { className: 'pending' });
+ this.dom.symbolSummary.appendChild(this.symbol);
+
+ this.summary = this.createDom('div', { className: 'specSummary' },
+ this.createDom('a', {
+ className: 'description',
+ href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
+ title: this.spec.getFullName()
+ }, this.spec.description)
+ );
+
+ this.detail = this.createDom('div', { className: 'specDetail' },
+ this.createDom('a', {
+ className: 'description',
+ href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
+ title: this.spec.getFullName()
+ }, this.spec.getFullName())
+ );
+};
+
+jasmine.HtmlReporter.SpecView.prototype.status = function() {
+ return this.getSpecStatus(this.spec);
+};
+
+jasmine.HtmlReporter.SpecView.prototype.refresh = function() {
+ this.symbol.className = this.status();
+
+ switch (this.status()) {
+ case 'skipped':
+ break;
+
+ case 'passed':
+ this.appendSummaryToSuiteDiv();
+ break;
+
+ case 'failed':
+ this.appendSummaryToSuiteDiv();
+ this.appendFailureDetail();
+ break;
+ }
+};
+
+jasmine.HtmlReporter.SpecView.prototype.appendSummaryToSuiteDiv = function() {
+ this.summary.className += ' ' + this.status();
+ this.appendToSummary(this.spec, this.summary);
+};
+
+jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() {
+ this.detail.className += ' ' + this.status();
+
+ var resultItems = this.spec.results().getItems();
+ var messagesDiv = this.createDom('div', { className: 'messages' });
+
+ for (var i = 0; i < resultItems.length; i++) {
+ var result = resultItems[i];
+
+ if (result.type == 'log') {
+ messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
+ } else if (result.type == 'expect' && result.passed && !result.passed()) {
+ messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
+
+ if (result.trace.stack) {
+ messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
+ }
+ }
+ }
+
+ if (messagesDiv.childNodes.length > 0) {
+ this.detail.appendChild(messagesDiv);
+ this.dom.details.appendChild(this.detail);
+ }
+};
+
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/html/SuiteView.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/html/SuiteView.js b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/html/SuiteView.js
new file mode 100644
index 0000000..19a1efa
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/html/SuiteView.js
@@ -0,0 +1,22 @@
+jasmine.HtmlReporter.SuiteView = function(suite, dom, views) {
+ this.suite = suite;
+ this.dom = dom;
+ this.views = views;
+
+ this.element = this.createDom('div', { className: 'suite' },
+ this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(this.suite.getFullName()) }, this.suite.description)
+ );
+
+ this.appendToSummary(this.suite, this.element);
+};
+
+jasmine.HtmlReporter.SuiteView.prototype.status = function() {
+ return this.getSpecStatus(this.suite);
+};
+
+jasmine.HtmlReporter.SuiteView.prototype.refresh = function() {
+ this.element.className += " " + this.status();
+};
+
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView);
+
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/html/TrivialReporter.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/html/TrivialReporter.js b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/html/TrivialReporter.js
new file mode 100644
index 0000000..167ac50
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/html/TrivialReporter.js
@@ -0,0 +1,192 @@
+/* @deprecated Use jasmine.HtmlReporter instead
+ */
+jasmine.TrivialReporter = function(doc) {
+ this.document = doc || document;
+ this.suiteDivs = {};
+ this.logRunningSpecs = false;
+};
+
+jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
+ var el = document.createElement(type);
+
+ for (var i = 2; i < arguments.length; i++) {
+ var child = arguments[i];
+
+ if (typeof child === 'string') {
+ el.appendChild(document.createTextNode(child));
+ } else {
+ if (child) { el.appendChild(child); }
+ }
+ }
+
+ for (var attr in attrs) {
+ if (attr == "className") {
+ el[attr] = attrs[attr];
+ } else {
+ el.setAttribute(attr, attrs[attr]);
+ }
+ }
+
+ return el;
+};
+
+jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
+ var showPassed, showSkipped;
+
+ this.outerDiv = this.createDom('div', { id: 'TrivialReporter', className: 'jasmine_reporter' },
+ this.createDom('div', { className: 'banner' },
+ this.createDom('div', { className: 'logo' },
+ this.createDom('span', { className: 'title' }, "Jasmine"),
+ this.createDom('span', { className: 'version' }, runner.env.versionString())),
+ this.createDom('div', { className: 'options' },
+ "Show ",
+ showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
+ this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
+ showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
+ this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
+ )
+ ),
+
+ this.runnerDiv = this.createDom('div', { className: 'runner running' },
+ this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
+ this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
+ this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
+ );
+
+ this.document.body.appendChild(this.outerDiv);
+
+ var suites = runner.suites();
+ for (var i = 0; i < suites.length; i++) {
+ var suite = suites[i];
+ var suiteDiv = this.createDom('div', { className: 'suite' },
+ this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
+ this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
+ this.suiteDivs[suite.id] = suiteDiv;
+ var parentDiv = this.outerDiv;
+ if (suite.parentSuite) {
+ parentDiv = this.suiteDivs[suite.parentSuite.id];
+ }
+ parentDiv.appendChild(suiteDiv);
+ }
+
+ this.startedAt = new Date();
+
+ var self = this;
+ showPassed.onclick = function(evt) {
+ if (showPassed.checked) {
+ self.outerDiv.className += ' show-passed';
+ } else {
+ self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
+ }
+ };
+
+ showSkipped.onclick = function(evt) {
+ if (showSkipped.checked) {
+ self.outerDiv.className += ' show-skipped';
+ } else {
+ self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
+ }
+ };
+};
+
+jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
+ var results = runner.results();
+ var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
+ this.runnerDiv.setAttribute("class", className);
+ //do it twice for IE
+ this.runnerDiv.setAttribute("className", className);
+ var specs = runner.specs();
+ var specCount = 0;
+ for (var i = 0; i < specs.length; i++) {
+ if (this.specFilter(specs[i])) {
+ specCount++;
+ }
+ }
+ var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
+ message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
+ this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
+
+ this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
+};
+
+jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
+ var results = suite.results();
+ var status = results.passed() ? 'passed' : 'failed';
+ if (results.totalCount === 0) { // todo: change this to check results.skipped
+ status = 'skipped';
+ }
+ this.suiteDivs[suite.id].className += " " + status;
+};
+
+jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
+ if (this.logRunningSpecs) {
+ this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
+ }
+};
+
+jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
+ var results = spec.results();
+ var status = results.passed() ? 'passed' : 'failed';
+ if (results.skipped) {
+ status = 'skipped';
+ }
+ var specDiv = this.createDom('div', { className: 'spec ' + status },
+ this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
+ this.createDom('a', {
+ className: 'description',
+ href: '?spec=' + encodeURIComponent(spec.getFullName()),
+ title: spec.getFullName()
+ }, spec.description));
+
+
+ var resultItems = results.getItems();
+ var messagesDiv = this.createDom('div', { className: 'messages' });
+ for (var i = 0; i < resultItems.length; i++) {
+ var result = resultItems[i];
+
+ if (result.type == 'log') {
+ messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
+ } else if (result.type == 'expect' && result.passed && !result.passed()) {
+ messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
+
+ if (result.trace.stack) {
+ messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
+ }
+ }
+ }
+
+ if (messagesDiv.childNodes.length > 0) {
+ specDiv.appendChild(messagesDiv);
+ }
+
+ this.suiteDivs[spec.suite.id].appendChild(specDiv);
+};
+
+jasmine.TrivialReporter.prototype.log = function() {
+ var console = jasmine.getGlobal().console;
+ if (console && console.log) {
+ if (console.log.apply) {
+ console.log.apply(console, arguments);
+ } else {
+ console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
+ }
+ }
+};
+
+jasmine.TrivialReporter.prototype.getLocation = function() {
+ return this.document.location;
+};
+
+jasmine.TrivialReporter.prototype.specFilter = function(spec) {
+ var paramMap = {};
+ var params = this.getLocation().search.substring(1).split('&');
+ for (var i = 0; i < params.length; i++) {
+ var p = params[i].split('=');
+ paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
+ }
+
+ if (!paramMap.spec) {
+ return true;
+ }
+ return spec.getFullName().indexOf(paramMap.spec) === 0;
+};
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/index.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/index.html
new file mode 100644
index 0000000..cf1117f
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/index.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
+ <meta name="viewport" content="width=device-width, height=device-height, user-scalable=yes, initial-scale=1.0;" />
+
+ <title>Cordova API Specs</title>
+
+ <link rel="stylesheet" href="../master.css" type="text/css" media="screen" title="no title" charset="utf-8">
+ <script type="text/javascript" src="../cordova.js"></script>
+ </head>
+ <body id="stage" class="theme">
+ <h1>Cordova API Specs</h1>
+
+ <a href="pages/all.html" class="btn large" style="width:100%;">Run All Tests</a>
+ <a href="pages/accelerometer.html" class="btn large" style="width:100%;">Run Accelerometer Tests</a>
+ <a href="pages/battery.html" class="btn large" style="width:100%;">Run Battery Tests</a>
+ <a href="pages/camera.html" class="btn large" style="width:100%;">Run Camera Tests</a>
+ <a href="pages/capture.html" class="btn large" style="width:100%;">Run Capture Tests</a>
+ <a href="pages/compass.html" class="btn large" style="width:100%;">Run Compass Tests</a>
+ <a href="pages/contacts.html" class="btn large" style="width:100%;">Run Contacts Tests</a>
+ <a href="pages/datauri.html" class="btn large" style="width:100%;">Run Data URI Tests</a>
+ <a href="pages/device.html" class="btn large" style="width:100%;">Run Device Tests</a>
+ <a href="pages/file.html" class="btn large" style="width:100%;">Run File Tests</a>
+ <a href="pages/filetransfer.html" class="btn large" style="width:100%;">Run FileTransfer Tests</a>
+ <a href="pages/geolocation.html" class="btn large" style="width:100%;">Run Geolocation Tests</a>
+ <a href="pages/globalization.html" class="btn large" style="width:100%;">Run Globalization Tests</a>
+ <a href="pages/media.html" class="btn large" style="width:100%;">Run Media Tests</a>
+ <a href="pages/network.html" class="btn large" style="width:100%;">Run Network Tests</a>
+ <a href="pages/notification.html" class="btn large" style="width:100%;">Run Notification Tests</a>
+ <a href="pages/platform.html" class="btn large" style="width:100%;">Run Platform Tests</a>
+ <a href="pages/storage.html" class="btn large" style="width:100%;">Run Storage Tests</a>
+ <a href="pages/bridge.html" class="btn large" style="width:100%;">Run Bridge Tests</a>
+
+ <h2> </h2><div class="backBtn" onclick="backHome();">Back</div>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/jasmine.css
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/jasmine.css b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/jasmine.css
new file mode 100644
index 0000000..826e575
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/jasmine.css
@@ -0,0 +1,81 @@
+body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; }
+
+#HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
+#HTMLReporter a { text-decoration: none; }
+#HTMLReporter a:hover { text-decoration: underline; }
+#HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; }
+#HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; }
+#HTMLReporter #jasmine_content { position: fixed; right: 100%; }
+#HTMLReporter .version { color: #aaaaaa; }
+#HTMLReporter .banner { margin-top: 14px; }
+#HTMLReporter .duration { color: #aaaaaa; float: right; }
+#HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; }
+#HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; }
+#HTMLReporter .symbolSummary li.passed { font-size: 14px; }
+#HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; }
+#HTMLReporter .symbolSummary li.failed { line-height: 9px; }
+#HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
+#HTMLReporter .symbolSummary li.skipped { font-size: 14px; }
+#HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; }
+#HTMLReporter .symbolSummary li.pending { line-height: 11px; }
+#HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; }
+#HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
+#HTMLReporter .runningAlert { background-color: #666666; }
+#HTMLReporter .skippedAlert { background-color: #aaaaaa; }
+#HTMLReporter .skippedAlert:first-child { background-color: #333333; }
+#HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; }
+#HTMLReporter .passingAlert { background-color: #a6b779; }
+#HTMLReporter .passingAlert:first-child { background-color: #5e7d00; }
+#HTMLReporter .failingAlert { background-color: #cf867e; }
+#HTMLReporter .failingAlert:first-child { background-color: #b03911; }
+#HTMLReporter .results { margin-top: 14px; }
+#HTMLReporter #details { display: none; }
+#HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; }
+#HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
+#HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
+#HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
+#HTMLReporter.showDetails .summary { display: none; }
+#HTMLReporter.showDetails #details { display: block; }
+#HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
+#HTMLReporter .summary { margin-top: 14px; }
+#HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; }
+#HTMLReporter .summary .specSummary.passed a { color: #5e7d00; }
+#HTMLReporter .summary .specSummary.failed a { color: #b03911; }
+#HTMLReporter .description + .suite { margin-top: 0; }
+#HTMLReporter .suite { margin-top: 14px; }
+#HTMLReporter .suite a { color: #333333; }
+#HTMLReporter #details .specDetail { margin-bottom: 28px; }
+#HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; }
+#HTMLReporter .resultMessage { padding-top: 14px; color: #333333; }
+#HTMLReporter .resultMessage span.result { display: block; }
+#HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }
+
+#TrivialReporter { padding: 8px 13px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ }
+#TrivialReporter a:visited, #TrivialReporter a { color: #303; }
+#TrivialReporter a:hover, #TrivialReporter a:active { color: blue; }
+#TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; }
+#TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; }
+#TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; }
+#TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; }
+#TrivialReporter .runner.running { background-color: yellow; }
+#TrivialReporter .options { text-align: right; font-size: .8em; }
+#TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; }
+#TrivialReporter .suite .suite { margin: 5px; }
+#TrivialReporter .suite.passed { background-color: #dfd; }
+#TrivialReporter .suite.failed { background-color: #fdd; }
+#TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; }
+#TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; }
+#TrivialReporter .spec.failed { background-color: #fbb; border-color: red; }
+#TrivialReporter .spec.passed { background-color: #bfb; border-color: green; }
+#TrivialReporter .spec.skipped { background-color: #bbb; }
+#TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; }
+#TrivialReporter .passed { background-color: #cfc; display: none; }
+#TrivialReporter .failed { background-color: #fbb; }
+#TrivialReporter .skipped { color: #777; background-color: #eee; display: none; }
+#TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; }
+#TrivialReporter .resultMessage .mismatch { color: black; }
+#TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; }
+#TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; }
+#TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; }
+#TrivialReporter #jasmine_content { position: fixed; right: 100%; }
+#TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; }
[32/37] git commit: Add WP7 and WP8 support to cordova-cli.
Posted by mw...@apache.org.
Add WP7 and WP8 support to cordova-cli.
Project: http://git-wip-us.apache.org/repos/asf/cordova-cli/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-cli/commit/ddfa0837
Tree: http://git-wip-us.apache.org/repos/asf/cordova-cli/tree/ddfa0837
Diff: http://git-wip-us.apache.org/repos/asf/cordova-cli/diff/ddfa0837
Branch: refs/heads/master
Commit: ddfa08371e1ecc84d667a682a14dd9ac7ce72ee6
Parents: f59ddbb
Author: Benn Mapes <be...@gmail.com>
Authored: Tue May 14 15:27:19 2013 -0700
Committer: Michael Brooks <mi...@michaelbrooks.ca>
Committed: Wed May 15 10:21:35 2013 -0700
----------------------------------------------------------------------
bootstrap.js | 13 +-
package.json | 1 +
platforms.js | 2 +-
spec/cordova-cli/compile.spec.js | 106 +++----
spec/cordova-cli/config_parser.spec.js | 9 +-
spec/cordova-cli/create.spec.js | 9 +-
spec/cordova-cli/emulate.spec.js | 106 ++-----
spec/cordova-cli/hooker.spec.js | 54 +++-
spec/cordova-cli/platform.spec.js | 139 ++-------
spec/cordova-cli/plugin.spec.js | 8 +-
spec/cordova-cli/plugin_parser.spec.js | 4 +-
spec/cordova-cli/prepare.spec.js | 44 +--
spec/cordova-cli/serve.spec.js | 16 +-
spec/cordova-cli/util.spec.js | 34 ++
spec/platform-script/android/android.spec.js | 98 ++++++
.../platform-script/android/android_parser.spec.js | 10 +-
spec/platform-script/blackberry/blackberry.spec.js | 105 ++++++
.../blackberry/blackberry_parser.spec.js | 10 +-
spec/platform-script/ios/ios.spec.js | 99 ++++++
spec/platform-script/ios/ios_parser.spec.js | 13 +-
spec/platform-script/wp7/wp7.spec.js | 99 ++++++
spec/platform-script/wp7/wp7_parser.spec.js | 249 +++++++++++++++
spec/platform-script/wp8/wp8.spec.js | 99 ++++++
spec/platform-script/wp8/wp8_parser.spec.js | 249 +++++++++++++++
src/compile.js | 5 +-
src/create.js | 2 +-
src/emulate.js | 10 +-
src/metadata/wp7_parser.js | 160 +++++++++
src/metadata/wp8_parser.js | 158 +++++++++
src/platform.js | 6 +-
src/plugin.js | 1 +
src/plugin_loader.js | 9 +
src/util.js | 6 +
33 files changed, 1578 insertions(+), 355 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/bootstrap.js
----------------------------------------------------------------------
diff --git a/bootstrap.js b/bootstrap.js
index f96df76..8cf0135 100644
--- a/bootstrap.js
+++ b/bootstrap.js
@@ -25,6 +25,8 @@ var util = require('./src/util'),
a_parser = require('./src/metadata/android_parser'),
b_parser = require('./src/metadata/blackberry_parser'),
i_parser = require('./src/metadata/ios_parser'),
+ wp7_parser= require('./src/metadata/wp7_parser'),
+ wp8_parser= require('./src/metadata/wp8_parser'),
n = require('ncallbacks'),
path = require('path'),
fs = require('fs'),
@@ -35,7 +37,9 @@ var util = require('./src/util'),
var min_reqs = {
"android":a_parser.check_requirements,
"ios":i_parser.check_requirements,
- "blackberry":b_parser.check_requirements
+ "blackberry":b_parser.check_requirements,
+ "wp7":wp7_parser.check_requirements,
+ "wp8":wp7_parser.check_requirements
}
// Create native projects using bin/create
@@ -68,16 +72,15 @@ var end = n(platforms.length, function() {
platforms.forEach(function(platform) {
min_reqs[platform](function(err) {
if (err) {
- console.error('WARNING: Your system does not meet requirements to create ' + platform + 'projects. See error output below.');
+ console.error('WARNING: Your system does not meet requirements to create ' + platform + ' projects. See error output below.');
console.error(err);
console.error('SKIPPING ' + platform + ' bootstrap.');
} else {
console.log('SUCCESS: Minimum requirements for ' + platform + ' met.');
var fix_path = path.join(tempDir, platform + '_fixture');
- var create = path.join(util.libDirectory, 'cordova-' + platform, 'bin', 'create');
+ var create = path.join(util.libDirectory, 'cordova-' + platform, 'bin', 'create');
console.log('BOOTSTRAPPING ' + platform + '...');
var cmd = create + ' "' + fix_path + '" org.apache.cordova.cordovaExample cordovaExample';
- if (platform == 'blackberry') cmd = create + ' "' + fix_path + '" cordovaExample';
shell.exec(cmd, {silent:true, async:true}, function(code, output) {
if (code > 0) {
console.error('ERROR! Could not create a native ' + platform + ' project test fixture. See below for error output.');
@@ -109,4 +112,4 @@ platforms.forEach(function(platform) {
});
}
});
-});
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/package.json
----------------------------------------------------------------------
diff --git a/package.json b/package.json
index 96e53bd..b706c93 100644
--- a/package.json
+++ b/package.json
@@ -48,6 +48,7 @@
{"name": "Braden Shepherdson", "email":"braden@chromium.org"},
{"name": "Gord Tanner", "email":"gtanner@gmail.com"},
{"name": "Tim Kim", "email": "timk@adobe.com"},
+ {"name": "Benn Mapes", "email": "Benn.Mapes@gmail.com"},
{"name": "Michael Wolf", "email": "Michael.Wolf@Cynergy.com"}
],
"license": "Apache version 2.0"
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/platforms.js
----------------------------------------------------------------------
diff --git a/platforms.js b/platforms.js
index be295a8..542f734 100644
--- a/platforms.js
+++ b/platforms.js
@@ -17,4 +17,4 @@
under the License.
*/
-module.exports = ['ios', 'android', 'blackberry'];
+module.exports = ['ios', 'android', 'blackberry', 'wp7', 'wp8'];
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/spec/cordova-cli/compile.spec.js
----------------------------------------------------------------------
diff --git a/spec/cordova-cli/compile.spec.js b/spec/cordova-cli/compile.spec.js
index f13792a..814d2ab 100644
--- a/spec/cordova-cli/compile.spec.js
+++ b/spec/cordova-cli/compile.spec.js
@@ -16,22 +16,19 @@
specific language governing permissions and limitations
under the License.
*/
-var cordova = require('../cordova'),
- et = require('elementtree'),
+var cordova = require('../../cordova'),
shell = require('shelljs'),
path = require('path'),
fs = require('fs'),
- config_parser = require('../src/config_parser'),
- android_parser = require('../src/metadata/android_parser'),
- ios_parser = require('../src/metadata/ios_parser'),
- blackberry_parser = require('../src/metadata/blackberry_parser'),
- hooker = require('../src/hooker'),
- fixtures = path.join(__dirname, 'fixtures'),
+ events = require('../../src/events'),
+ hooker = require('../../src/hooker'),
+ fixtures = path.join(__dirname, '..', 'fixtures'),
hooks = path.join(fixtures, 'hooks'),
- tempDir = path.join(__dirname, '..', 'temp'),
+ tempDir = path.join(__dirname, '..', '..', 'temp'),
cordova_project = path.join(fixtures, 'projects', 'cordova');
var cwd = process.cwd();
+
describe('compile command', function() {
beforeEach(function() {
shell.rm('-rf', tempDir);
@@ -53,12 +50,12 @@ describe('compile command', function() {
it('should run inside a Cordova-based project with at least one added platform', function() {
// move platform project fixtures over to fake cordova into thinking platforms were added
// TODO: possibly add this to helper?
- shell.mv('-f', path.join(cordova_project, 'platforms', 'blackberry'), path.join(tempDir));
- shell.mv('-f', path.join(cordova_project, 'platforms', 'ios'), path.join(tempDir));
+ // Just make a folder instead of moving the whole platform?
+ shell.mkdir('-p', tempDir);
+ shell.mv('-f', path.join(cordova_project, 'platforms', 'android'), path.join(tempDir));
this.after(function() {
process.chdir(cwd);
- shell.mv('-f', path.join(tempDir, 'blackberry'), path.join(cordova_project, 'platforms', 'blackberry'));
- shell.mv('-f', path.join(tempDir, 'ios'), path.join(cordova_project, 'platforms', 'ios'));
+ shell.mv('-f', path.join(tempDir, 'android'), path.join(cordova_project, 'platforms', 'android'));
});
process.chdir(cordova_project);
@@ -78,10 +75,29 @@ describe('compile command', function() {
shell.mkdir('-p', tempDir);
process.chdir(tempDir);
+ // we don't actually want it building the project (if it does somehow exist)
+ var sh_spy = spyOn(shell, 'exec');
+
expect(function() {
cordova.compile();
}).toThrow();
});
+ /* Is this a repeat of the util.spec.js test? */
+ it('should not treat a .gitignore file as a platform', function() {
+ var gitignore = path.join(cordova_project, 'platforms', '.gitignore');
+ fs.writeFileSync(gitignore, 'somethinghere', 'utf-8');
+ this.after(function() {
+ shell.rm('-f', gitignore);
+ process.chdir(cwd);
+ });
+
+ var s = spyOn(shell, 'exec');
+ process.chdir(cordova_project);
+ cordova.compile();
+ for (call in s.calls) {
+ expect(s.calls[call].args[0]).not.toMatch(/\.gitignore/);
+ }
+ });
describe('hooks', function() {
var s;
@@ -91,13 +107,11 @@ describe('compile command', function() {
describe('when platforms are added', function() {
beforeEach(function() {
- shell.mv('-f', path.join(cordova_project, 'platforms', 'blackberry'), path.join(tempDir));
- shell.mv('-f', path.join(cordova_project, 'platforms', 'ios'), path.join(tempDir));
+ shell.mv('-f', path.join(cordova_project, 'platforms', 'android'), path.join(tempDir));
process.chdir(cordova_project);
});
afterEach(function() {
- shell.mv('-f', path.join(tempDir, 'blackberry'), path.join(cordova_project, 'platforms', 'blackberry'));
- shell.mv('-f', path.join(tempDir, 'ios'), path.join(cordova_project, 'platforms', 'ios'));
+ shell.mv('-f', path.join(tempDir, 'android'), path.join(cordova_project, 'platforms', 'android'));
process.chdir(cwd);
});
@@ -106,11 +120,14 @@ describe('compile command', function() {
cordova.compile();
expect(s).toHaveBeenCalledWith('before_compile');
});
- it('should fire after hooks through the hooker module', function() {
- var sh_spy = spyOn(shell, 'exec');
- cordova.compile();
- sh_spy.mostRecentCall.args[2](0); // shell cb
- expect(s).toHaveBeenCalledWith('after_compile');
+ it('should fire after hooks through the hooker module', function(done) {
+ spyOn(shell, 'exec').andCallFake(function(cmd, options, callback) {
+ callback(0, 'fucking eh');
+ });
+ cordova.compile('android', function() {
+ expect(hooker.prototype.fire).toHaveBeenCalledWith('after_compile');
+ done();
+ });
});
});
@@ -131,49 +148,4 @@ describe('compile command', function() {
});
});
});
- describe('per platform', function() {
- beforeEach(function() {
- process.chdir(cordova_project);
- });
-
- afterEach(function() {
- process.chdir(cwd);
- });
-
- describe('Android', function() {
- it('should shell out to build command on Android', function() {
- var s = spyOn(require('shelljs'), 'exec').andReturn({code:0});
- cordova.compile('android');
- expect(s.mostRecentCall.args[0].match(/\/cordova\/build/)).not.toBeNull();
- });
- });
- describe('iOS', function() {
- it('should shell out to build command on iOS', function() {
- var s = spyOn(require('shelljs'), 'exec');
- cordova.compile('ios');
- expect(s).toHaveBeenCalled();
- expect(s.mostRecentCall.args[0].match(/\/cordova\/build/)).not.toBeNull();
- });
- });
- describe('BlackBerry', function() {
- it('should shell out to ant command on blackberry', function() {
- var s = spyOn(shell, 'exec');
- cordova.compile('blackberry');
- expect(s).toHaveBeenCalled();
- expect(s.mostRecentCall.args[0]).toMatch(/ant -f .*build\.xml" qnx load-device/);
- });
- });
- it('should not treat a .gitignore file as a platform', function() {
- var gitignore = path.join(cordova_project, 'platforms', '.gitignore');
- fs.writeFileSync(gitignore, 'somethinghere', 'utf-8');
- this.after(function() {
- shell.rm('-f', gitignore);
- });
- var s = spyOn(shell, 'exec');
- cordova.compile();
- expect(s.calls[0].args[0]).not.toMatch(/\.gitignore/);
- expect(s.calls[1].args[0]).not.toMatch(/\.gitignore/);
- expect(s.calls[1].args[0]).not.toMatch(/\.gitignore/);
- });
- });
});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/spec/cordova-cli/config_parser.spec.js
----------------------------------------------------------------------
diff --git a/spec/cordova-cli/config_parser.spec.js b/spec/cordova-cli/config_parser.spec.js
index 99bc717..77658fb 100644
--- a/spec/cordova-cli/config_parser.spec.js
+++ b/spec/cordova-cli/config_parser.spec.js
@@ -17,14 +17,15 @@
specific language governing permissions and limitations
under the License.
*/
-var cordova = require('../cordova'),
+var cordova = require('../../cordova'),
path = require('path'),
fs = require('fs'),
shell = require('shelljs'),
- config_parser = require('../src/config_parser'),
- tempDir = path.join(__dirname, '..', 'temp'),
+ config_parser = require('../../src/config_parser'),
+ tempDir = path.join(__dirname, '..', '..', 'temp'),
et = require('elementtree'),
- xml = path.join(tempDir, 'www', 'config.xml');
+ util = require('../../src/util'),
+ xml = util.projectConfig(tempDir);
describe('config.xml parser', function () {
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/spec/cordova-cli/create.spec.js
----------------------------------------------------------------------
diff --git a/spec/cordova-cli/create.spec.js b/spec/cordova-cli/create.spec.js
index fcb3e76..8a31ed6 100644
--- a/spec/cordova-cli/create.spec.js
+++ b/spec/cordova-cli/create.spec.js
@@ -1,8 +1,9 @@
-var cordova = require('../cordova'),
+var cordova = require('../../cordova'),
path = require('path'),
shell = require('shelljs'),
fs = require('fs'),
- tempDir = path.join(__dirname, '..', 'temp');
+ util = require('../../src/util'),
+ tempDir = path.join(__dirname, '..', '..', 'temp');
describe('create command', function () {
beforeEach(function() {
@@ -54,14 +55,14 @@ describe('create command', function () {
expect(fs.lstatSync(path.join(tempDir, '.cordova', 'config.json')).isFile()).toBe(true);
- expect(fs.readFileSync(path.join(tempDir, 'www', 'config.xml')).toString('utf8')).toMatch(/<name>balls<\/name>/);
+ expect(fs.readFileSync(util.projectConfig(tempDir)).toString('utf8')).toMatch(/<name>balls<\/name>/);
});
it('should create a cordova project in the specified dir with specified name and id if provided', function() {
cordova.create(tempDir, "birdy.nam.nam", "numnum");
expect(fs.lstatSync(path.join(tempDir, '.cordova', 'config.json')).isFile()).toBe(true);
- var config = fs.readFileSync(path.join(tempDir, 'www', 'config.xml')).toString('utf8');
+ var config = fs.readFileSync(util.projectConfig(tempDir)).toString('utf8');
expect(config).toMatch(/<name>numnum<\/name>/);
expect(config).toMatch(/id="birdy\.nam\.nam"/);
});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/spec/cordova-cli/emulate.spec.js
----------------------------------------------------------------------
diff --git a/spec/cordova-cli/emulate.spec.js b/spec/cordova-cli/emulate.spec.js
index 3a4d1a4..a3e5136 100644
--- a/spec/cordova-cli/emulate.spec.js
+++ b/spec/cordova-cli/emulate.spec.js
@@ -16,19 +16,17 @@
specific language governing permissions and limitations
under the License.
*/
-var cordova = require('../cordova'),
+var cordova = require('../../cordova'),
et = require('elementtree'),
shell = require('shelljs'),
path = require('path'),
fs = require('fs'),
- config_parser = require('../src/config_parser'),
- android_parser = require('../src/metadata/android_parser'),
- ios_parser = require('../src/metadata/ios_parser'),
- blackberry_parser = require('../src/metadata/blackberry_parser'),
- hooker = require('../src/hooker'),
- fixtures = path.join(__dirname, 'fixtures'),
+ config_parser = require('../../src/config_parser'),
+ android_parser = require('../../src/metadata/android_parser'),
+ hooker = require('../../src/hooker'),
+ fixtures = path.join(__dirname, '..', 'fixtures'),
hooks = path.join(fixtures, 'hooks'),
- tempDir = path.join(__dirname, '..', 'temp'),
+ tempDir = path.join(__dirname, '..', '..', 'temp'),
cordova_project = path.join(fixtures, 'projects', 'cordova');
var cwd = process.cwd();
@@ -36,7 +34,7 @@ var cwd = process.cwd();
describe('emulate command', function() {
beforeEach(function() {
shell.rm('-rf', tempDir);
- shell.mkdir('-p', tempDir);
+ cordova.create(tempDir);
});
it('should not run inside a Cordova-based project with no added platforms', function() {
@@ -44,7 +42,6 @@ describe('emulate command', function() {
process.chdir(cwd);
});
- cordova.create(tempDir);
process.chdir(tempDir);
expect(function() {
cordova.emulate();
@@ -52,19 +49,15 @@ describe('emulate command', function() {
});
it('should run inside a Cordova-based project with at least one added platform', function() {
- shell.mv('-f', path.join(cordova_project, 'platforms', 'blackberry'), path.join(tempDir));
- shell.mv('-f', path.join(cordova_project, 'platforms', 'ios'), path.join(tempDir));
this.after(function() {
process.chdir(cwd);
- shell.mv('-f', path.join(tempDir, 'blackberry'), path.join(cordova_project, 'platforms', 'blackberry'));
- shell.mv('-f', path.join(tempDir, 'ios'), path.join(cordova_project, 'platforms', 'ios'));
});
- process.chdir(cordova_project);
-
var s = spyOn(shell, 'exec');
var a_spy = spyOn(android_parser.prototype, 'update_project');
expect(function() {
+ shell.cp('-Rf', path.join(cordova_project, 'platforms', 'android'), path.join(tempDir, 'platforms'));
+ process.chdir(tempDir);
cordova.emulate();
a_spy.mostRecentCall.args[1](); // fake out android parser
expect(s).toHaveBeenCalled();
@@ -82,97 +75,40 @@ describe('emulate command', function() {
cordova.emulate();
}).toThrow();
});
- describe('per platform', function() {
- beforeEach(function() {
- process.chdir(cordova_project);
- });
-
- afterEach(function() {
- process.chdir(cwd);
- });
-
- describe('Android', function() {
- var s;
- beforeEach(function() {
- s = spyOn(require('shelljs'), 'exec');
- });
- it('should shell out to run command on Android', function() {
- cordova.emulate('android');
- expect(s.mostRecentCall.args[0].match(/\/cordova\/run/)).not.toBeNull();
- });
- it('should call android_parser\'s update_project', function() {
- var spy = spyOn(android_parser.prototype, 'update_project');
- cordova.emulate('android');
- expect(spy).toHaveBeenCalled();
- });
- });
- describe('iOS', function() {
- it('should shell out to emulate command on iOS', function() {
- var s = spyOn(require('shelljs'), 'exec');
- var proj_spy = spyOn(ios_parser.prototype, 'update_project');
- cordova.emulate('ios');
- proj_spy.mostRecentCall.args[1]();
- expect(s).toHaveBeenCalled();
- expect(s.mostRecentCall.args[0].match(/\/cordova\/emulate/)).not.toBeNull();
- });
- it('should call ios_parser\'s update_project', function() {
- var s = spyOn(ios_parser.prototype, 'update_project');
- cordova.emulate('ios');
- expect(s).toHaveBeenCalled();
- });
- });
- describe('BlackBerry', function() {
- it('should shell out to ant command on blackberry', function() {
- var proj_spy = spyOn(blackberry_parser.prototype, 'update_project');
- var s = spyOn(require('shelljs'), 'exec');
- cordova.emulate('blackberry');
- proj_spy.mostRecentCall.args[1](); // update_project fake
- expect(s).toHaveBeenCalled();
- expect(s.mostRecentCall.args[0]).toMatch(/ant -f .*build\.xml" qnx load-simulator/);
- });
- it('should call blackberry_parser\'s update_project', function() {
- var s = spyOn(blackberry_parser.prototype, 'update_project');
- cordova.emulate('blackberry');
- expect(s).toHaveBeenCalled();
- });
- });
- });
describe('hooks', function() {
- var s, sh, ap;
+ var s;
beforeEach(function() {
s = spyOn(hooker.prototype, 'fire').andReturn(true);
});
describe('when platforms are added', function() {
beforeEach(function() {
- shell.mv('-f', path.join(cordova_project, 'platforms', 'blackberry'), path.join(tempDir));
- shell.mv('-f', path.join(cordova_project, 'platforms', 'ios'), path.join(tempDir));
- sh = spyOn(shell, 'exec');
- ap = spyOn(android_parser.prototype, 'update_project');
- process.chdir(cordova_project);
+ shell.cp('-Rf', path.join(cordova_project, 'platforms', 'android'), path.join(tempDir, 'platforms'));
+ process.chdir(tempDir);
});
afterEach(function() {
- shell.mv('-f', path.join(tempDir, 'blackberry'), path.join(cordova_project, 'platforms', 'blackberry'));
- shell.mv('-f', path.join(tempDir, 'ios'), path.join(cordova_project, 'platforms', 'ios'));
process.chdir(cwd);
});
it('should fire before hooks through the hooker module', function() {
+
+ spyOn(shell, 'exec');
cordova.emulate();
- expect(s).toHaveBeenCalledWith('before_emulate');
+ expect(hooker.prototype.fire).toHaveBeenCalledWith('before_emulate');
});
it('should fire after hooks through the hooker module', function() {
- cordova.emulate();
- ap.mostRecentCall.args[1](); // fake parser call
- sh.mostRecentCall.args[2](0); //fake shell call
- expect(s).toHaveBeenCalledWith('after_emulate');
+ spyOn(shell, 'exec').andCallFake(function(cmd, options, callback) {
+ callback(0, 'fucking eh');
+ });
+ cordova.emulate('android', function() {
+ expect(hooker.prototype.fire).toHaveBeenCalledWith('after_emulate');
+ });
});
});
describe('with no platforms added', function() {
beforeEach(function() {
- cordova.create(tempDir);
process.chdir(tempDir);
});
afterEach(function() {
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/spec/cordova-cli/hooker.spec.js
----------------------------------------------------------------------
diff --git a/spec/cordova-cli/hooker.spec.js b/spec/cordova-cli/hooker.spec.js
index 4a0ca7d..ff92f43 100644
--- a/spec/cordova-cli/hooker.spec.js
+++ b/spec/cordova-cli/hooker.spec.js
@@ -1,4 +1,4 @@
-/**
+ /**
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
@@ -16,14 +16,16 @@
specific language governing permissions and limitations
under the License.
*/
-var hooker = require('../src/hooker'),
+var hooker = require('../../src/hooker'),
shell = require('shelljs'),
path = require('path'),
fs = require('fs'),
- tempDir= path.join(__dirname, '..', 'temp'),
- hooks = path.join(__dirname, 'fixtures', 'hooks'),
- cordova= require('../cordova');
+ os = require('os'),
+ tempDir= path.join(__dirname, '..', '..', 'temp'),
+ hooks = path.join(__dirname, '..', 'fixtures', 'hooks'),
+ cordova= require('../../cordova');
+var platform = os.platform();
var cwd = process.cwd();
describe('hooker', function() {
@@ -67,8 +69,14 @@ describe('hooker', function() {
}).not.toThrow();
});
it('should throw if any script exits with non-zero code', function() {
- var script = path.join(tempDir, '.cordova', 'hooks', 'before_build', 'fail.sh');
- shell.cp(path.join(hooks, 'fail', 'fail.sh'), script);
+ var script;
+ if (platform.match(/(win32|win64)/)) {
+ script = path.join(tempDir, '.cordova', 'hooks', 'before_build', 'fail.bat');
+ shell.cp(path.join(hooks, 'fail', 'fail.bat'), script);
+ } else {
+ script = path.join(tempDir, '.cordova', 'hooks', 'before_build', 'fail.sh');
+ shell.cp(path.join(hooks, 'fail', 'fail.sh'), script);
+ }
fs.chmodSync(script, '754');
expect(function() {
h.fire('before_build');
@@ -79,7 +87,13 @@ describe('hooker', function() {
describe('success', function() {
it('should execute all scripts in order and return true', function() {
var hook = path.join(tempDir, '.cordova', 'hooks', 'before_build');
- shell.cp(path.join(hooks, 'test', '*'), path.join(hook, '.'));
+ if (platform.match(/(win32|win64)/)) {
+ shell.cp(path.join(hooks, 'test', '0.bat'), hook);
+ shell.cp(path.join(hooks, 'test', '1.bat'), hook);
+ } else {
+ shell.cp(path.join(hooks, 'test', '0.sh'), hook);
+ shell.cp(path.join(hooks, 'test', '1.sh'), hook);
+ }
fs.readdirSync(hook).forEach(function(script) {
fs.chmodSync(path.join(hook, script), '754');
});
@@ -89,12 +103,21 @@ describe('hooker', function() {
returnValue = h.fire('before_build');
}).not.toThrow();
expect(returnValue).toBe(true);
- expect(s.calls[0].args[0]).toMatch(/0.sh/);
- expect(s.calls[1].args[0]).toMatch(/1.sh/);
+ if (platform.match(/(win32|win64)/)) {
+ expect(s.calls[0].args[0]).toMatch(/0.bat/);
+ expect(s.calls[1].args[0]).toMatch(/1.bat/);
+ } else {
+ expect(s.calls[0].args[0]).toMatch(/0.sh/);
+ expect(s.calls[1].args[0]).toMatch(/1.sh/);
+ }
});
it('should pass the project root folder as parameter into the project-level hooks', function() {
var hook = path.join(tempDir, '.cordova', 'hooks', 'before_build');
- shell.cp(path.join(hooks, 'test', '0.sh'), path.join(hook, '.'));
+ if (platform.match(/(win32|win64)/)) {
+ shell.cp(path.join(hooks, 'test', '0.bat'), hook);
+ } else {
+ shell.cp(path.join(hooks, 'test', '0.sh'), hook);
+ }
fs.readdirSync(hook).forEach(function(script) {
fs.chmodSync(path.join(hook, script), '754');
});
@@ -104,8 +127,13 @@ describe('hooker', function() {
returnValue = h.fire('before_build');
}).not.toThrow();
expect(returnValue).toBe(true);
- var paramRegex = new RegExp('0.sh "'+tempDir+'"$');
- expect(s.calls[0].args[0]).toMatch(paramRegex);
+ var param_str;
+ if (platform.match(/(win32|win64)/)) {
+ param_str = '0.bat "'+tempDir+'"';
+ } else {
+ param_str = '0.sh "'+tempDir+'"';
+ }
+ expect(s.calls[0].args[0].indexOf(param_str)).not.toEqual(-1);
});
describe('module-level hooks', function() {
var handler = jasmine.createSpy();
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/spec/cordova-cli/platform.spec.js
----------------------------------------------------------------------
diff --git a/spec/cordova-cli/platform.spec.js b/spec/cordova-cli/platform.spec.js
index 7138c7e..bbf3959 100644
--- a/spec/cordova-cli/platform.spec.js
+++ b/spec/cordova-cli/platform.spec.js
@@ -16,22 +16,21 @@
specific language governing permissions and limitations
under the License.
*/
-var cordova = require('../cordova'),
+var cordova = require('../../cordova'),
path = require('path'),
shell = require('shelljs'),
request = require('request'),
fs = require('fs'),
et = require('elementtree'),
- config_parser = require('../src/config_parser'),
+ config_parser = require('../../src/config_parser'),
helper = require('./helper'),
- util = require('../src/util'),
- hooker = require('../src/hooker'),
- platforms = require('../platforms'),
- tempDir = path.join(__dirname, '..', 'temp');
- android_parser = require('../src/metadata/android_parser'),
- ios_parser = require('../src/metadata/ios_parser'),
- cordova_project = path.join(__dirname, 'fixtures', 'projects', 'cordova'),
- blackberry_parser = require('../src/metadata/blackberry_parser');
+ util = require('../../src/util'),
+ hooker = require('../../src/hooker'),
+ platforms = require('../../platforms'),
+ tempDir = path.join(__dirname, '..', '..', 'temp');
+ android_parser = require('../../src/metadata/android_parser'),
+ blackberry_parser = require('../../src/metadata/blackberry_parser'),
+ cordova_project = path.join(__dirname, '..', 'fixtures', 'projects', 'cordova');
var cwd = process.cwd();
@@ -84,7 +83,11 @@ describe('platform command', function() {
});
it('should list out added platforms in a project', function() {
- expect(cordova.platform('list').length).toEqual(3);
+ process.chdir(tempDir);
+ cordova.create(tempDir);
+ shell.cp('-Rf', path.join(cordova_project, 'platforms', 'android'), path.join(tempDir, 'platforms'));
+ shell.cp('-Rf', path.join(cordova_project, 'platforms', 'blackberry'), path.join(tempDir, 'platforms'));
+ expect(cordova.platform('list').length).toEqual(2);
});
});
@@ -97,109 +100,23 @@ describe('platform command', function() {
afterEach(function() {
process.chdir(cwd);
});
-
- describe('android', function() {
- var sh, cr;
- var fake_reqs_check = function() {
- cr.mostRecentCall.args[0](false);
- };
- var fake_create = function(a_path) {
- shell.mkdir('-p', a_path);
- fs.writeFileSync(path.join(a_path, 'AndroidManifest.xml'), 'hi', 'utf-8');
- sh.mostRecentCall.args[2](0, '');
- };
- beforeEach(function() {
- sh = spyOn(shell, 'exec');
- cr = spyOn(android_parser, 'check_requirements');
- });
-
- it('should shell out to android ./bin/create', function() {
- cordova.platform('add', 'android');
- fake_reqs_check();
- var shell_cmd = sh.mostRecentCall.args[0];
- expect(shell_cmd).toMatch(/android\/bin\/create/);
- });
- it('should call android_parser\'s update_project', function() {
- var s = spyOn(android_parser.prototype, 'update_project');
- cordova.platform('add', 'android');
- fake_reqs_check();
- fake_create(path.join(tempDir, 'platforms', 'android'));
- expect(s).toHaveBeenCalled();
- });
- });
- describe('ios', function() {
- var sh, cr;
- var fake_reqs_check = function() {
- cr.mostRecentCall.args[0](false);
- };
- var fake_create = function(a_path) {
- shell.mkdir('-p', a_path);
- fs.writeFileSync(path.join(a_path, 'poo.xcodeproj'), 'hi', 'utf-8');
- shell.mkdir('-p', path.join(a_path, 'poo'));
- shell.cp(path.join(cordova_project, 'www', 'config.xml'), path.join(a_path, 'poo', 'config.xml'));
- sh.mostRecentCall.args[2](0, '');
- };
- beforeEach(function() {
- sh = spyOn(shell, 'exec');
- cr = spyOn(ios_parser, 'check_requirements');
- });
- it('should shell out to ios ./bin/create', function() {
- cordova.platform('add', 'ios');
- fake_reqs_check();
- var shell_cmd = sh.mostRecentCall.args[0];
- expect(shell_cmd).toMatch(/ios\/bin\/create/);
- });
- it('should call ios_parser\'s update_project', function() {
- var s = spyOn(ios_parser.prototype, 'update_project');
- cordova.platform('add', 'ios');
- fake_reqs_check();
- fake_create(path.join(tempDir, 'platforms', 'ios'));
- expect(s).toHaveBeenCalled();
- });
- });
- describe('blackberry', function() {
- var sh, cr;
- var fake_reqs_check = function() {
- cr.mostRecentCall.args[0](false);
- };
- var fake_create = function(a_path) {
- shell.mkdir('-p', path.join(a_path, 'www'));
- fs.writeFileSync(path.join(a_path, 'project.properties'), 'hi', 'utf-8');
- fs.writeFileSync(path.join(a_path, 'build.xml'), 'hi', 'utf-8');
- shell.cp(path.join(cordova_project, 'www', 'config.xml'), path.join(a_path, 'www', 'config.xml'));
- sh.mostRecentCall.args[2](0, '');
- };
- beforeEach(function() {
- sh = spyOn(shell, 'exec');
- cr = spyOn(blackberry_parser, 'check_requirements');
- });
- it('should shell out to blackberry bin/create', function() {
- cordova.platform('add', 'blackberry');
- fake_reqs_check();
- var shell_cmd = sh.mostRecentCall.args[0];
- expect(shell_cmd).toMatch(/blackberry\/bin\/create/);
- });
- it('should call blackberry_parser\'s update_project', function() {
- var s = spyOn(blackberry_parser.prototype, 'update_project');
- cordova.platform('add', 'blackberry');
- fake_reqs_check();
- fake_create(path.join(tempDir, 'platforms', 'blackberry'));
- expect(s).toHaveBeenCalled();
- });
- });
+
it('should handle multiple platforms', function() {
var arc = spyOn(android_parser, 'check_requirements');
- var irc = spyOn(ios_parser, 'check_requirements');
+ var brc = spyOn(blackberry_parser, 'check_requirements');
var sh = spyOn(shell, 'exec');
- cordova.platform('add', ['android', 'ios']);
+ cordova.platform('add', ['android', 'blackberry']);
arc.mostRecentCall.args[0](false);
- irc.mostRecentCall.args[0](false);
- expect(sh.argsForCall[0][0]).toMatch(/android\/bin\/create/);
- expect(sh.argsForCall[1][0]).toMatch(/ios\/bin\/create/);
+ brc.mostRecentCall.args[0](false);
+ var android_create = path.join('android', 'bin', 'create');
+ var bb_create = path.join('blackberry', 'bin', 'create');
+ expect(sh.argsForCall[0][0]).toContain(android_create);
+ expect(sh.argsForCall[1][0]).toContain(bb_create);
});
});
- describe('`remove`',function() {
+ describe('`remove`',function() {
+ var num_platforms = fs.readdirSync(path.join(cordova_project, 'platforms')).length;
beforeEach(function() {
process.chdir(cordova_project);
shell.cp('-rf', path.join(cordova_project, 'platforms' ,'*'), tempDir);
@@ -212,11 +129,11 @@ describe('platform command', function() {
it('should remove a supported and added platform', function() {
cordova.platform('remove', 'android');
- expect(cordova.platform('ls').length).toEqual(2);
+ expect(cordova.platform('ls').length).toEqual(num_platforms - 1);
});
it('should be able to remove multiple platforms', function() {
- cordova.platform('remove', ['android','ios']);
- expect(cordova.platform('ls').length).toEqual(1);
+ cordova.platform('remove', ['android','blackberry']);
+ expect(cordova.platform('ls').length).toEqual(num_platforms - 2);
});
});
@@ -280,7 +197,7 @@ describe('platform command', function() {
});
describe('platform.supports(name, callback)', function() {
- var androidParser = require('../src/metadata/android_parser');
+ var androidParser = require('../../src/metadata/android_parser');
beforeEach(function() {
spyOn(androidParser, 'check_requirements');
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/spec/cordova-cli/plugin.spec.js
----------------------------------------------------------------------
diff --git a/spec/cordova-cli/plugin.spec.js b/spec/cordova-cli/plugin.spec.js
index 3d370e7..061738f 100644
--- a/spec/cordova-cli/plugin.spec.js
+++ b/spec/cordova-cli/plugin.spec.js
@@ -16,13 +16,13 @@
specific language governing permissions and limitations
under the License.
*/
-var cordova = require('../cordova'),
+var cordova = require('../../cordova'),
path = require('path'),
shell = require('shelljs'),
fs = require('fs'),
- hooker = require('../src/hooker'),
- tempDir = path.join(__dirname, '..', 'temp'),
- fixturesDir = path.join(__dirname, 'fixtures'),
+ hooker = require('../../src/hooker'),
+ tempDir = path.join(__dirname, '..', '..', 'temp'),
+ fixturesDir = path.join(__dirname, '..', 'fixtures'),
testPlugin = path.join(fixturesDir, 'plugins', 'test'),
cordova_project = path.join(fixturesDir, 'projects', 'cordova'),
androidPlugin = path.join(fixturesDir, 'plugins', 'android');
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/spec/cordova-cli/plugin_parser.spec.js
----------------------------------------------------------------------
diff --git a/spec/cordova-cli/plugin_parser.spec.js b/spec/cordova-cli/plugin_parser.spec.js
index 4391003..15b5993 100644
--- a/spec/cordova-cli/plugin_parser.spec.js
+++ b/spec/cordova-cli/plugin_parser.spec.js
@@ -17,10 +17,10 @@
specific language governing permissions and limitations
under the License.
*/
-var cordova = require('../cordova'),
+var cordova = require('../../cordova'),
path = require('path'),
fs = require('fs'),
- plugin_parser = require('../src/plugin_parser'),
+ plugin_parser = require('../../src/plugin_parser'),
et = require('elementtree'),
xml = path.join(__dirname, '..', 'fixtures', 'plugins', 'test', 'plugin.xml');
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/spec/cordova-cli/prepare.spec.js
----------------------------------------------------------------------
diff --git a/spec/cordova-cli/prepare.spec.js b/spec/cordova-cli/prepare.spec.js
index f232b3e..da77935 100644
--- a/spec/cordova-cli/prepare.spec.js
+++ b/spec/cordova-cli/prepare.spec.js
@@ -16,19 +16,16 @@
specific language governing permissions and limitations
under the License.
*/
-var cordova = require('../cordova'),
+var cordova = require('../../cordova'),
et = require('elementtree'),
shell = require('shelljs'),
path = require('path'),
fs = require('fs'),
- config_parser = require('../src/config_parser'),
- android_parser = require('../src/metadata/android_parser'),
- ios_parser = require('../src/metadata/ios_parser'),
- blackberry_parser = require('../src/metadata/blackberry_parser'),
- hooker = require('../src/hooker'),
- fixtures = path.join(__dirname, 'fixtures'),
+ config_parser = require('../../src/config_parser'),
+ hooker = require('../../src/hooker'),
+ fixtures = path.join(__dirname, '..', 'fixtures'),
hooks = path.join(fixtures, 'hooks'),
- tempDir = path.join(__dirname, '..', 'temp'),
+ tempDir = path.join(__dirname, '..', '..', 'temp'),
cordova_project = path.join(fixtures, 'projects', 'cordova');
var cwd = process.cwd();
@@ -36,7 +33,7 @@ var cwd = process.cwd();
describe('prepare command', function() {
beforeEach(function() {
shell.rm('-rf', tempDir);
- shell.mkdir('-p', tempDir);
+ cordova.create(tempDir);
});
it('should not run inside a Cordova-based project with no added platforms', function() {
@@ -44,7 +41,6 @@ describe('prepare command', function() {
process.chdir(cwd);
});
- cordova.create(tempDir);
process.chdir(tempDir);
expect(function() {
cordova.prepare();
@@ -54,20 +50,17 @@ describe('prepare command', function() {
it('should run inside a Cordova-based project with at least one added platform', function() {
// move platform project fixtures over to fake cordova into thinking platforms were added
// TODO: possibly add this to helper?
- shell.mv('-f', path.join(cordova_project, 'platforms', 'blackberry'), path.join(tempDir));
this.after(function() {
process.chdir(cwd);
- shell.mv('-f', path.join(tempDir, 'blackberry'), path.join(cordova_project, 'platforms', 'blackberry'));
});
- process.chdir(cordova_project);
-
- var a_parser_spy = spyOn(android_parser.prototype, 'update_project');
- var i_parser_spy = spyOn(ios_parser.prototype, 'update_project');
+ spyOn(shell, 'exec');
expect(function() {
+ shell.cp('-Rf', path.join(cordova_project, 'platforms', 'android'), path.join(tempDir, 'platforms'));
+ process.chdir(tempDir);
+ var a_parser_spy = spyOn(android_parser.prototype, 'update_project');
cordova.prepare();
expect(a_parser_spy).toHaveBeenCalled();
- expect(i_parser_spy).toHaveBeenCalled();
}).not.toThrow();
});
it('should not run outside of a Cordova-based project', function() {
@@ -91,13 +84,11 @@ describe('prepare command', function() {
describe('when platforms are added', function() {
beforeEach(function() {
- shell.mv('-f', path.join(cordova_project, 'platforms', 'blackberry'), path.join(tempDir));
- shell.mv('-f', path.join(cordova_project, 'platforms', 'ios'), path.join(tempDir));
- process.chdir(cordova_project);
+ shell.cp('-rf', path.join(cordova_project, 'platforms', 'android'), path.join(tempDir, 'platforms'));
+ process.chdir(tempDir);
});
afterEach(function() {
- shell.mv('-f', path.join(tempDir, 'blackberry'), path.join(cordova_project, 'platforms', 'blackberry'));
- shell.mv('-f', path.join(tempDir, 'ios'), path.join(cordova_project, 'platforms', 'ios'));
+ shell.rm('-rf', path.join(tempDir, 'platforms', 'android'));
process.chdir(cwd);
});
@@ -106,15 +97,16 @@ describe('prepare command', function() {
expect(s).toHaveBeenCalledWith('before_prepare');
});
it('should fire after hooks through the hooker module', function() {
- var parser_spy = spyOn(android_parser.prototype, 'update_project');
- cordova.prepare();
- parser_spy.mostRecentCall.args[1](); // parser cb
- expect(s).toHaveBeenCalledWith('after_prepare');
+ spyOn(shell, 'exec');
+ cordova.prepare('android', function() {
+ expect(hooker.prototype.fire).toHaveBeenCalledWith('after_prepare');
+ });
});
});
describe('with no platforms added', function() {
beforeEach(function() {
+ shell.rm('-rf', tempDir);
cordova.create(tempDir);
process.chdir(tempDir);
});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/spec/cordova-cli/serve.spec.js
----------------------------------------------------------------------
diff --git a/spec/cordova-cli/serve.spec.js b/spec/cordova-cli/serve.spec.js
index 8d00cab..2e61212 100644
--- a/spec/cordova-cli/serve.spec.js
+++ b/spec/cordova-cli/serve.spec.js
@@ -17,18 +17,20 @@
specific language governing permissions and limitations
under the License.
*/
-var cordova = require('../cordova'),
+var cordova = require('../../cordova'),
path = require('path'),
shell = require('shelljs'),
request = require('request'),
fs = require('fs'),
- util = require('../src/util'),
- hooker = require('../src/hooker'),
- tempDir = path.join(__dirname, '..', 'temp'),
+ util = require('../../src/util'),
+ hooker = require('../../src/hooker'),
+ tempDir = path.join(__dirname, '..', '..', 'temp'),
http = require('http'),
- android_parser = require('../src/metadata/android_parser'),
- ios_parser = require('../src/metadata/ios_parser'),
- blackberry_parser = require('../src/metadata/blackberry_parser');
+ android_parser = require('../../src/metadata/android_parser'),
+ ios_parser = require('../../src/metadata/ios_parser'),
+ blackberry_parser = require('../../src/metadata/blackberry_parser'),
+ wp7_parser = require('../../src/metadata/wp7_parser'),
+ wp8_parser = require('../../src/metadata/wp8_parser');
var cwd = process.cwd();
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/spec/cordova-cli/util.spec.js
----------------------------------------------------------------------
diff --git a/spec/cordova-cli/util.spec.js b/spec/cordova-cli/util.spec.js
new file mode 100644
index 0000000..787b00f
--- /dev/null
+++ b/spec/cordova-cli/util.spec.js
@@ -0,0 +1,34 @@
+var cordova = require('../../cordova'),
+ shell = require('shelljs'),
+ path = require('path'),
+ fs = require('fs'),
+ cordova_util = require('../../src/util'),
+ fixtures = path.join(__dirname, '..', 'fixtures'),
+ cordova_project = path.join(fixtures, 'projects', 'cordova');
+
+
+var cwd = process.cwd();
+
+describe('util command', function() {
+ beforeEach(function() {
+ process.chdir(cordova_project);
+ });
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+ describe('listPlatforms', function() {
+ it('should not treat a .gitignore file as a platform', function() {
+ var gitignore = path.join(cordova_project, 'platforms', '.gitignore');
+ fs.writeFileSync(gitignore, 'somethinghere', 'utf-8');
+ this.after(function() {
+ shell.rm('-f', gitignore);
+ });
+
+ var s = spyOn(shell, 'exec');
+ var platforms = cordova_util.listPlatforms(cordova_project);
+ platforms.forEach(function(platform) {
+ expect(platform).not.toMatch(/\.gitignore/);
+ });
+ });
+ });
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/spec/platform-script/android/android.spec.js
----------------------------------------------------------------------
diff --git a/spec/platform-script/android/android.spec.js b/spec/platform-script/android/android.spec.js
new file mode 100644
index 0000000..8c39af0
--- /dev/null
+++ b/spec/platform-script/android/android.spec.js
@@ -0,0 +1,98 @@
+var cordova = require('../../../cordova'),
+ shell = require('shelljs'),
+ path = require('path'),
+ fs = require('fs'),
+ android_parser = require('../../../src/metadata/android_parser'),
+ tempDir = path.join(__dirname, '..', '..', '..', 'temp'),
+ fixtures = path.join(__dirname, '..', '..', 'fixtures'),
+ cordova_project = path.join(fixtures, 'projects', 'cordova');
+
+var cwd = process.cwd();
+
+describe('Test:', function() {
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+
+ describe('\'platform add android\'', function() {
+ var sh, cr;
+ var fake_reqs_check = function() {
+ expect(cr.mostRecentCall.args).toBeDefined();
+ cr.mostRecentCall.args[0](false);
+ };
+ var fake_create = function(a_path) {
+ shell.mkdir('-p', a_path);
+ fs.writeFileSync(path.join(a_path, 'AndroidManifest.xml'), 'hi', 'utf-8');
+ sh.mostRecentCall.args[2](0, '');
+ };
+ beforeEach(function() {
+ sh = spyOn(shell, 'exec');
+ cr = spyOn(android_parser, 'check_requirements');
+ shell.rm('-rf', tempDir);
+ cordova.create(tempDir);
+ process.chdir(tempDir);
+ });
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+ it('should shell out to android /bin/create', function() {
+ cordova.platform('add', 'android');
+ fake_reqs_check();
+ var shell_cmd = sh.mostRecentCall.args[0];
+ var create_cmd = path.join('android', 'bin', 'create');
+ expect(shell_cmd).toContain(create_cmd);
+ });
+ it('should call android_parser\'s update_project', function() {
+ spyOn(android_parser.prototype, 'update_project');
+ cordova.platform('add', 'android');
+ fake_reqs_check();
+ fake_create(path.join(tempDir, 'platforms', 'android'));
+ expect(android_parser.prototype.update_project).toHaveBeenCalled();
+ });
+ });
+
+ describe('\'emulate android\'', function() {
+ beforeEach(function() {
+ process.chdir(tempDir);
+ });
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+ shell.rm('-rf', tempDir);
+ cordova.create(tempDir);
+ shell.cp('-rf', path.join(cordova_project, 'platforms', 'android'), path.join(tempDir, 'platforms'));
+ it('should shell out to run command on Android', function() {
+ var proj_spy = spyOn(android_parser.prototype, 'update_project');
+ var s = spyOn(require('shelljs'), 'exec');
+ cordova.emulate('android');
+ proj_spy.mostRecentCall.args[1](); // update_project fake
+ expect(s).toHaveBeenCalled();
+ var emulate_cmd = path.join('android', 'cordova', 'run');
+ expect(s.mostRecentCall.args[0]).toContain(emulate_cmd);
+ });
+ it('should call android_parser\'s update_project', function() {
+ spyOn(require('shelljs'), 'exec');
+ spyOn(android_parser.prototype, 'update_project');
+ cordova.emulate('android');
+ expect(android_parser.prototype.update_project).toHaveBeenCalled();
+ });
+ });
+
+ describe('\'compile android\'', function() {
+ beforeEach(function() {
+ process.chdir(tempDir);
+ });
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+ shell.rm('-rf', tempDir);
+ cordova.create(tempDir);
+ shell.cp('-rf', path.join(cordova_project, 'platforms', 'android'), path.join(tempDir, 'platforms'));
+ it('should shell out to build command', function() {
+ var build_cmd = path.join('android', 'cordova', 'build');
+ var s = spyOn(require('shelljs'), 'exec').andReturn({code:0});
+ cordova.compile('android');
+ expect(s.mostRecentCall.args[0]).toContain(build_cmd);
+ });
+ });
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/spec/platform-script/android/android_parser.spec.js
----------------------------------------------------------------------
diff --git a/spec/platform-script/android/android_parser.spec.js b/spec/platform-script/android/android_parser.spec.js
index d051c6f..84c7903 100644
--- a/spec/platform-script/android/android_parser.spec.js
+++ b/spec/platform-script/android/android_parser.spec.js
@@ -17,15 +17,15 @@
specific language governing permissions and limitations
under the License.
*/
-var android_parser = require('../../src/metadata/android_parser'),
- config_parser = require('../../src/config_parser'),
- util = require('../../src/util'),
+var android_parser = require('../../../src/metadata/android_parser'),
+ config_parser = require('../../../src/config_parser'),
+ util = require('../../../src/util'),
path = require('path'),
shell = require('shelljs'),
fs = require('fs'),
et = require('elementtree'),
- cordova = require('../../cordova'),
- projects_path = path.join(__dirname, '..', 'fixtures', 'projects'),
+ cordova = require('../../../cordova'),
+ projects_path = path.join(__dirname, '..', '..', 'fixtures', 'projects'),
android_path = path.join(projects_path, 'native', 'android_fixture'),
project_path = path.join(projects_path, 'cordova'),
android_project_path = path.join(project_path, 'platforms', 'android');
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/spec/platform-script/blackberry/blackberry.spec.js
----------------------------------------------------------------------
diff --git a/spec/platform-script/blackberry/blackberry.spec.js b/spec/platform-script/blackberry/blackberry.spec.js
new file mode 100644
index 0000000..ff997c1
--- /dev/null
+++ b/spec/platform-script/blackberry/blackberry.spec.js
@@ -0,0 +1,105 @@
+var cordova = require('../../../cordova'),
+ shell = require('shelljs'),
+ path = require('path'),
+ fs = require('fs'),
+ blackberry_parser = require('../../../src/metadata/blackberry_parser'),
+ tempDir = path.join(__dirname, '..', '..', '..', 'temp'),
+ fixtures = path.join(__dirname, '..', '..', 'fixtures'),
+ cordova_project = path.join(fixtures, 'projects', 'cordova');
+
+var cwd = process.cwd();
+
+describe('Test:', function() {
+
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+
+ describe('\'platform add blackberry\'', function() {
+ var sh, cr;
+ var fake_reqs_check = function() {
+ expect(cr.mostRecentCall.args).toBeDefined();
+ cr.mostRecentCall.args[0](false);
+ };
+ var fake_create = function(a_path) {
+ shell.mkdir('-p', path.join(a_path, 'www'));
+ fs.writeFileSync(path.join(a_path, 'project.properties'), 'hi', 'utf-8');
+ fs.writeFileSync(path.join(a_path, 'build.xml'), 'hi', 'utf-8');
+ shell.cp('-rf', path.join(cordova_project, 'platforms', 'blackberry', 'www', 'config.xml'), path.join(a_path, 'www'));
+ sh.mostRecentCall.args[2](0, '');
+ };
+ beforeEach(function() {
+ sh = spyOn(shell, 'exec');
+ cr = spyOn(blackberry_parser, 'check_requirements');
+ shell.rm('-rf', tempDir);
+ cordova.create(tempDir);
+ process.chdir(tempDir);
+ });
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+ it('should check requirements when adding', function() {
+ cordova.platform('add', 'blackberry');
+ expect(blackberry_parser.check_requirements).toHaveBeenCalled();
+ });
+ it('should shell out to blackberry bin/create', function() {
+ cordova.platform('add', 'blackberry');
+ fake_reqs_check();
+ var shell_cmd = sh.mostRecentCall.args[0];
+ var create_cmd = path.join('blackberry', 'bin', 'create');
+ expect(shell_cmd).toContain(create_cmd);
+ });
+ it('should call blackberry_parser\'s update_project', function() {
+ spyOn(blackberry_parser.prototype, 'update_project');
+ cordova.platform('add', 'blackberry');
+ fake_reqs_check();
+ fake_create(path.join(tempDir, 'platforms', 'blackberry'));
+ expect(blackberry_parser.prototype.update_project).toHaveBeenCalled();
+ });
+ });
+
+ describe('\'emulate blackberry\'', function() {
+ beforeEach(function() {
+ process.chdir(tempDir);
+ });
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+ shell.rm('-rf', tempDir);
+ cordova.create(tempDir);
+ shell.cp('-rf', path.join(cordova_project, 'platforms', 'blackberry'), path.join(tempDir, 'platforms'));
+ it('should shell out to ant command on blackberry', function() {
+ var proj_spy = spyOn(blackberry_parser.prototype, 'update_project');
+ var s = spyOn(require('shelljs'), 'exec');
+ cordova.emulate('blackberry');
+ proj_spy.mostRecentCall.args[1](); // update_project fake
+ expect(s).toHaveBeenCalled();
+ var emulate_cmd = 'ant -f .*build\.xml" qnx load-simulator';
+ expect(s.mostRecentCall.args[0]).toMatch(emulate_cmd);
+ });
+ it('should call blackberry_parser\'s update_project', function() {
+ spyOn(require('shelljs'), 'exec');
+ spyOn(blackberry_parser.prototype, 'update_project');
+ cordova.emulate('blackberry');
+ expect(blackberry_parser.prototype.update_project).toHaveBeenCalled();
+ });
+ });
+
+ describe('\'compile blackberry\'', function() {
+ beforeEach(function() {
+ process.chdir(tempDir);
+ });
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+ shell.rm('-rf', tempDir);
+ cordova.create(tempDir);
+ shell.cp('-rf', path.join(cordova_project, 'platforms', 'blackberry'), path.join(tempDir, 'platforms'));
+ it('should shell out to build command', function() {
+ var build_cmd = 'build.xml" qnx load-device';
+ var s = spyOn(require('shelljs'), 'exec').andReturn({code:0});
+ cordova.compile('blackberry');
+ expect(s.mostRecentCall.args[0]).toContain(build_cmd);
+ });
+ });
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/spec/platform-script/blackberry/blackberry_parser.spec.js
----------------------------------------------------------------------
diff --git a/spec/platform-script/blackberry/blackberry_parser.spec.js b/spec/platform-script/blackberry/blackberry_parser.spec.js
index 12d5294..d183f7f 100644
--- a/spec/platform-script/blackberry/blackberry_parser.spec.js
+++ b/spec/platform-script/blackberry/blackberry_parser.spec.js
@@ -17,15 +17,15 @@
specific language governing permissions and limitations
under the License.
*/
-var blackberry_parser = require('../../src/metadata/blackberry_parser'),
- config_parser = require('../../src/config_parser'),
+var blackberry_parser = require('../../../src/metadata/blackberry_parser'),
+ config_parser = require('../../../src/config_parser'),
path = require('path'),
- util = require('../../src/util'),
+ util = require('../../../src/util'),
et = require('elementtree'),
shell = require('shelljs'),
- cordova = require('../../cordova'),
+ cordova = require('../../../cordova'),
fs = require('fs'),
- projects_path = path.join(__dirname, '..', 'fixtures', 'projects'),
+ projects_path = path.join(__dirname, '..', '..', 'fixtures', 'projects'),
blackberry_path = path.join(projects_path, 'native', 'blackberry_fixture'),
project_path = path.join(projects_path, 'cordova'),
blackberry_project_path = path.join(project_path, 'platforms', 'blackberry');
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/spec/platform-script/ios/ios.spec.js
----------------------------------------------------------------------
diff --git a/spec/platform-script/ios/ios.spec.js b/spec/platform-script/ios/ios.spec.js
new file mode 100644
index 0000000..0fecd75
--- /dev/null
+++ b/spec/platform-script/ios/ios.spec.js
@@ -0,0 +1,99 @@
+var cordova = require('../../../cordova'),
+ shell = require('shelljs'),
+ path = require('path'),
+ fs = require('fs'),
+ ios_parser = require('../../../src/metadata/ios_parser'),
+ tempDir = path.join(__dirname, '..', '..', '..', 'temp'),
+ fixtures = path.join(__dirname, '..', '..', 'fixtures'),
+ cordova_project = path.join(fixtures, 'projects', 'cordova');
+
+var cwd = process.cwd();
+
+describe('Test:', function() {
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+
+ describe('\'platform add ios\'', function() {
+ var sh, cr;
+ var fake_reqs_check = function() {
+ cr.mostRecentCall.args[0](false);
+ };
+ var fake_create = function(a_path) {
+ shell.mkdir('-p', a_path);
+ fs.writeFileSync(path.join(a_path, 'poo.xcodeproj'), 'hi', 'utf-8');
+ shell.mkdir('-p', path.join(a_path, 'poo'));
+ shell.cp(path.join(cordova_project, 'www', 'config.xml'), path.join(a_path, 'poo', 'config.xml'));
+ sh.mostRecentCall.args[2](0, '');
+ };
+ beforeEach(function() {
+ sh = spyOn(shell, 'exec');
+ cr = spyOn(ios_parser, 'check_requirements');
+ shell.rm('-rf', tempDir);
+ cordova.create(tempDir);
+ process.chdir(tempDir);
+ });
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+ it('should shell out to ios /bin/create', function() {
+ cordova.platform('add', 'ios');
+ fake_reqs_check();
+ var shell_cmd = sh.mostRecentCall.args[0];
+ var create_cmd = path.join('ios', 'bin', 'create');
+ expect(shell_cmd).toContain(create_cmd);
+ });
+ it('should call ios_parser\'s update_project', function() {
+ spyOn(ios_parser.prototype, 'update_project');
+ cordova.platform('add', 'ios');
+ fake_reqs_check();
+ fake_create(path.join(tempDir, 'platforms', 'ios'));
+ expect(ios_parser.prototype.update_project).toHaveBeenCalled();
+ });
+ });
+
+ describe('\'emulate ios\'', function() {
+ beforeEach(function() {
+ process.chdir(tempDir);
+ });
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+ shell.rm('-rf', tempDir);
+ cordova.create(tempDir);
+ shell.cp('-rf', path.join(cordova_project, 'platforms', 'ios'), path.join(tempDir, 'platforms'));
+ it('should shell out to run command on ios', function() {
+ var proj_spy = spyOn(ios_parser.prototype, 'update_project');
+ var s = spyOn(require('shelljs'), 'exec');
+ cordova.emulate('ios');
+ proj_spy.mostRecentCall.args[1](); // update_project fake
+ expect(s).toHaveBeenCalled();
+ var emulate_cmd = path.join('ios', 'cordova', 'run');
+ expect(s.mostRecentCall.args[0]).toContain(emulate_cmd);
+ });
+ it('should call ios_parser\'s update_project', function() {
+ spyOn(require('shelljs'), 'exec');
+ spyOn(ios_parser.prototype, 'update_project');
+ cordova.emulate('ios');
+ expect(ios_parser.prototype.update_project).toHaveBeenCalled();
+ });
+ });
+
+ describe('\'compile ios\'', function() {
+ beforeEach(function() {
+ process.chdir(tempDir);
+ });
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+ shell.rm('-rf', tempDir);
+ cordova.create(tempDir);
+ shell.cp('-rf', path.join(cordova_project, 'platforms', 'ios'), path.join(tempDir, 'platforms'));
+ it('should shell out to build command', function() {
+ var build_cmd = path.join('ios', 'cordova', 'build');
+ var s = spyOn(require('shelljs'), 'exec').andReturn({code:0});
+ cordova.compile('ios');
+ expect(s.mostRecentCall.args[0]).toContain(build_cmd);
+ });
+ });
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/spec/platform-script/ios/ios_parser.spec.js
----------------------------------------------------------------------
diff --git a/spec/platform-script/ios/ios_parser.spec.js b/spec/platform-script/ios/ios_parser.spec.js
index dbd4816..b0c2aeb 100644
--- a/spec/platform-script/ios/ios_parser.spec.js
+++ b/spec/platform-script/ios/ios_parser.spec.js
@@ -17,16 +17,17 @@
under the License.
*/
-var ios_parser = require('../../src/metadata/ios_parser'),
- config_parser = require('../../src/config_parser'),
- cordova = require('../../cordova'),
- util = require('../../src/util'),
+var ios_parser = require('../../../src/metadata/ios_parser'),
+ config_parser = require('../../../src/config_parser'),
+ cordova = require('../../../cordova'),
+ util = require('../../../src/util'),
path = require('path'),
shell = require('shelljs'),
fs = require('fs'),
+ os = require('os'),
et = require('elementtree'),
- projects_path = path.join(__dirname, '..', 'fixtures', 'projects')
-ios_path = path.join(projects_path, 'native', 'ios_fixture'),
+ projects_path = path.join(__dirname, '..', '..', 'fixtures', 'projects')
+ ios_path = path.join(projects_path, 'native', 'ios_fixture'),
project_path = path.join(projects_path, 'cordova'),
ios_project_path = path.join(project_path, 'platforms', 'ios');
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/spec/platform-script/wp7/wp7.spec.js
----------------------------------------------------------------------
diff --git a/spec/platform-script/wp7/wp7.spec.js b/spec/platform-script/wp7/wp7.spec.js
new file mode 100644
index 0000000..6b7f3b4
--- /dev/null
+++ b/spec/platform-script/wp7/wp7.spec.js
@@ -0,0 +1,99 @@
+var cordova = require('../../../cordova'),
+ shell = require('shelljs'),
+ path = require('path'),
+ fs = require('fs'),
+ wp7_parser = require('../../../src/metadata/wp7_parser'),
+ tempDir = path.join(__dirname, '..', '..', '..', 'temp'),
+ fixtures = path.join(__dirname, '..', '..', 'fixtures'),
+ cordova_project = path.join(fixtures, 'projects', 'cordova');
+
+var cwd = process.cwd();
+
+describe('Test:', function() {
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+
+ describe('\'platform add wp7\'', function() {
+ var sh, cr;
+ var fake_reqs_check = function() {
+ expect(cr.mostRecentCall.args).toBeDefined();
+ cr.mostRecentCall.args[0](false);
+ };
+ var fake_create = function(a_path) {
+ shell.mkdir('-p', a_path);
+ fs.writeFileSync(path.join(a_path, 'wp7Project.csproj'), 'hi', 'utf-8');
+ fs.writeFileSync(path.join(a_path, 'wp7Project.sln'), 'hi', 'utf-8');
+ sh.mostRecentCall.args[2](0, '');
+ };
+ beforeEach(function() {
+ sh = spyOn(shell, 'exec');
+ cr = spyOn(wp7_parser, 'check_requirements');
+ shell.rm('-rf', tempDir);
+ cordova.create(tempDir);
+ process.chdir(tempDir);
+ });
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+ it('should shell out to wp7 /bin/create', function() {
+ cordova.platform('add', 'wp7');
+ fake_reqs_check();
+ var shell_cmd = sh.mostRecentCall.args[0];
+ var create_cmd = path.join('wp7', 'bin', 'create');
+ expect(shell_cmd).toContain(create_cmd);
+ });
+ it('should call wp7_parser\'s update_project', function() {
+ spyOn(wp7_parser.prototype, 'update_project');
+ cordova.platform('add', 'wp7');
+ fake_reqs_check();
+ fake_create(path.join(tempDir, 'platforms', 'wp7'));
+ expect(wp7_parser.prototype.update_project).toHaveBeenCalled();
+ });
+ });
+
+ describe('\'emulate wp7\'', function() {
+ beforeEach(function() {
+ process.chdir(tempDir);
+ });
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+ shell.rm('-rf', tempDir);
+ cordova.create(tempDir);
+ shell.cp('-rf', path.join(cordova_project, 'platforms', 'wp7'), path.join(tempDir, 'platforms'));
+ it('should shell out to run command on wp7', function() {
+ var proj_spy = spyOn(wp7_parser.prototype, 'update_project');
+ var s = spyOn(require('shelljs'), 'exec');
+ cordova.emulate('wp7');
+ proj_spy.mostRecentCall.args[1](); // update_project fake
+ expect(s).toHaveBeenCalled();
+ var emulate_cmd = path.join('wp7', 'cordova', 'run');
+ expect(s.mostRecentCall.args[0]).toContain(emulate_cmd);
+ });
+ it('should call wp7_parser\'s update_project', function() {
+ spyOn(require('shelljs'), 'exec');
+ spyOn(wp7_parser.prototype, 'update_project');
+ cordova.emulate('wp7');
+ expect(wp7_parser.prototype.update_project).toHaveBeenCalled();
+ });
+ });
+
+ describe('\'compile wp7\'', function() {
+ beforeEach(function() {
+ process.chdir(tempDir);
+ });
+ afterEach(function() {
+ process.chdir(cwd);
+ });
+ shell.rm('-rf', tempDir);
+ cordova.create(tempDir);
+ shell.cp('-rf', path.join(cordova_project, 'platforms', 'wp7'), path.join(tempDir, 'platforms'));
+ it('should shell out to build command', function() {
+ var build_cmd = path.join('wp7', 'cordova', 'build');
+ var s = spyOn(require('shelljs'), 'exec').andReturn({code:0});
+ cordova.compile('wp7');
+ expect(s.mostRecentCall.args[0]).toContain(build_cmd);
+ });
+ });
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ddfa0837/spec/platform-script/wp7/wp7_parser.spec.js
----------------------------------------------------------------------
diff --git a/spec/platform-script/wp7/wp7_parser.spec.js b/spec/platform-script/wp7/wp7_parser.spec.js
new file mode 100644
index 0000000..7840bff
--- /dev/null
+++ b/spec/platform-script/wp7/wp7_parser.spec.js
@@ -0,0 +1,249 @@
+
+/**
+ 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.
+*/
+var wp7_parser = require('../../../src/metadata/wp7_parser'),
+ config_parser = require('../../../src/config_parser'),
+ util = require('../../../src/util'),
+ path = require('path'),
+ shell = require('shelljs'),
+ fs = require('fs'),
+ os = require('os'),
+ et = require('elementtree'),
+ cordova = require('../../../cordova'),
+ projects_path = path.join(__dirname, '..', '..', 'fixtures', 'projects'),
+ wp7_path = path.join(projects_path, 'native', 'wp7_fixture'),
+ project_path = path.join(projects_path, 'cordova'),
+ wp7_project_path = path.join(project_path, 'platforms', 'wp7');
+
+var www_config = util.projectConfig(project_path);
+var original_www_config = fs.readFileSync(www_config, 'utf-8');
+
+describe('wp7 project parser', function() {
+ it('should throw an exception with a path that is not a native wp7 project', function() {
+ expect(function() {
+ var project = new wp7_parser(process.cwd());
+ }).toThrow();
+ });
+ it('should accept a proper native wp7 project path as construction parameter', function() {
+ expect(function() {
+ var project = new wp7_parser(wp7_path);
+ expect(project).toBeDefined();
+ }).not.toThrow();
+ });
+
+ describe('update_from_config method', function() {
+ var config;
+ var project = new wp7_parser(wp7_path);
+
+ var manifest_path = path.join(wp7_path, 'Properties', 'WMAppManifest.xml');
+ var csproj_path = project.csproj_path;
+ var sln_path = project.sln_path;
+ var app_xaml_path = path.join(wp7_path, 'App.xaml');
+ var app_cs_path = path.join(wp7_path, 'App.xaml.cs');
+ var main_xaml_path = path.join(wp7_path, 'MainPage.xaml');
+ var main_cs_path = path.join(wp7_path, 'MainPage.xaml.cs');
+
+
+ var original_manifest = fs.readFileSync(manifest_path, 'utf-8');
+ var original_csproj = fs.readFileSync(csproj_path, 'utf-8');
+ var original_sln = fs.readFileSync(sln_path, 'utf-8');
+ var original_app_xaml = fs.readFileSync(app_xaml_path, 'utf-8');
+ var original_app_cs = fs.readFileSync(app_cs_path, 'utf-8');
+ var original_main_xaml = fs.readFileSync(main_xaml_path, 'utf-8');
+ var original_main_cs = fs.readFileSync(main_cs_path, 'utf-8');
+
+ beforeEach(function() {
+ project = new wp7_parser(wp7_path);
+ config = new config_parser(www_config);
+ });
+ afterEach(function() {
+ fs.writeFileSync(manifest_path, original_manifest, 'utf-8');
+ // csproj file changes name if app changes name
+ fs.unlinkSync(project.csproj_path);
+ fs.unlinkSync(project.sln_path);
+ fs.writeFileSync(csproj_path, original_csproj, 'utf-8');
+ fs.writeFileSync(sln_path, original_sln, 'utf-8');
+ fs.writeFileSync(app_xaml_path, original_app_xaml, 'utf-8');
+ fs.writeFileSync(app_cs_path, original_app_cs, 'utf-8');
+ fs.writeFileSync(main_xaml_path, original_main_xaml, 'utf-8');
+ fs.writeFileSync(main_cs_path, original_main_cs, 'utf-8');
+ });
+ it('should throw an exception if a non config_parser object is passed into it', function() {
+ expect(function() {
+ project.update_from_config({});
+ }).toThrow();
+ });
+ it('should update the application name properly', function() {
+ var test_name = 'bond. james bond.';
+ config.name(test_name);
+ project.update_from_config(config);
+ var raw_manifest = fs.readFileSync(manifest_path, 'utf-8');
+ //Strip three bytes that windows adds (http://www.multiasking.com/2012/11/851)
+ var cleaned_manifest = raw_manifest.replace('\ufeff', '');
+ var manifest = new et.ElementTree(et.XML(cleaned_manifest));
+ var app_name = manifest.find('.//App[@Title]')['attrib']['Title'];
+ expect(app_name).toBe(test_name);
+
+ //check for the proper name of csproj and solution files
+ test_name = test_name.replace(/(\.\s|\s\.|\s+|\.+)/g, '_'); //make it a ligitamate name
+ expect(project.csproj_path).toContain(test_name);
+ expect(project.sln_path).toContain(test_name);
+ });
+ it('should update the application package name properly', function() {
+ var test_package = 'ca.filmaj.dewd'
+ config.packageName(test_package);
+ project.update_from_config(config);
+
+ // check csproj file (use regex instead of elementtree?)
+ var raw_csproj = fs.readFileSync(project.csproj_path, 'utf-8');
+ var cleaned_csproj = raw_csproj.replace(/^\uFEFF/i, '');
+ var csproj = new et.ElementTree(et.XML(cleaned_csproj));
+ expect(csproj.find('.//RootNamespace').text).toEqual(test_package);
+ expect(csproj.find('.//AssemblyName').text).toEqual(test_package);
+ expect(csproj.find('.//XapFilename').text).toEqual(test_package + '.xap');
+ expect(csproj.find('.//SilverlightAppEntry').text).toEqual(test_package + '.App');
+
+ // check app.xaml (use regex instead of elementtree?)
+ var new_app_xaml = fs.readFileSync(app_xaml_path, 'utf-8');
+ var cleaned_app_xaml = new_app_xaml.replace(/^\uFEFF/i, '');
+ var app_xaml = new et.ElementTree(et.XML(cleaned_app_xaml));
+ expect(app_xaml._root.attrib['x:Class']).toEqual(test_package + '.App');
+
+ // check app.xaml.cs
+ var new_app_cs = fs.readFileSync(app_cs_path, 'utf-8');
+ expect(new_app_cs).toContain('namespace ' + test_package);
+
+ // check MainPage.xaml (use regex instead of elementtree?)
+ var new_main_xaml = fs.readFileSync(main_xaml_path, 'utf-8');
+ var cleaned_main_xaml = new_main_xaml.replace(/^\uFEFF/i, '');
+ var main_xaml = new et.ElementTree(et.XML(cleaned_main_xaml));
+ expect(main_xaml._root.attrib['x:Class']).toEqual(test_package + '.MainPage');
+
+ //check MainPage.xaml.cs
+ var new_main_cs = fs.readFileSync(main_cs_path, 'utf-8');
+ expect(new_main_cs).toContain('namespace ' + test_package);
+ });
+ xdescribe('preferences', function() {
+ it('should not change default project preferences and copy over additional project preferences to platform-level config.xml', function() {
+ /*config.preference.add({name:'henrik',value:'sedin'});
+ project.update_from_config(config);
+
+ var native_config = new et.ElementTree(et.XML(fs.readFileSync(android_config, 'utf-8')));
+ var ps = native_config.findall('preference');
+ expect(ps.length).toEqual(7);
+ expect(ps[0].attrib.name).toEqual('useBrowserHistory');
+ expect(ps[0].attrib.value).toEqual('true');
+ expect(ps[6].attrib.name).toEqual('henrik');
+ expect(ps[6].attrib.value).toEqual('sedin');*/
+
+ // TODO : figure out if this is supported
+ //expect(true).toBe(false);
+ });
+ it('should override a default project preference if applicable', function() {
+ /*config.preference.add({name:'useBrowserHistory',value:'false'});
+ project.update_from_config(config);
+
+ var native_config = new et.ElementTree(et.XML(fs.readFileSync(android_config, 'utf-8')));
+ var ps = native_config.findall('preference');
+ expect(ps.length).toEqual(6);
+ expect(ps[0].attrib.name).toEqual('useBrowserHistory');
+ expect(ps[0].attrib.value).toEqual('false');*/
+
+ // TODO : figure out if this is supported
+ //expect(true).toBe(false);
+ });
+ });
+ });
+
+ describe('cross-platform project level methods', function() {
+ var parser, config;
+
+ beforeEach(function() {
+ parser = new wp7_parser(wp7_project_path);
+ config = new config_parser(www_config);
+ });
+ afterEach(function() {
+ });
+ describe('update_www method', function() {
+ it('should update all www assets', function() {
+ var newFile = path.join(util.projectWww(project_path), 'somescript.js');
+ this.after(function() {
+ shell.rm('-f', newFile);
+ });
+ fs.writeFileSync(newFile, 'alert("sup");', 'utf-8');
+ parser.update_www();
+ expect(fs.existsSync(path.join(wp7_project_path, 'www', 'somescript.js'))).toBe(true);
+ });
+ it('should write out windows-phone js to cordova.js', function() {
+ parser.update_www();
+ var raw_version = fs.readFileSync(path.join(util.libDirectory, 'cordova-wp7', 'VERSION'), 'utf-8');
+ var wp7_version = raw_version.replace(/\r\n/,'').replace(/\n/,'');
+ expect(fs.readFileSync(path.join(wp7_project_path, 'www', 'cordova.js'),'utf-8')).toEqual(fs.readFileSync(path.join(util.libDirectory, 'cordova-wp7', 'templates', 'standalone', 'www', 'cordova-' + wp7_version + '.js'), 'utf-8'));
+ });
+ });
+
+ xdescribe('update_overrides method',function() {
+ /*var mergesPath = path.join(util.appDir(project_path), 'merges', 'android');
+ var newFile = path.join(mergesPath, 'merge.js');
+ beforeEach(function() {
+ shell.mkdir('-p', mergesPath);
+ fs.writeFileSync(newFile, 'alert("sup");', 'utf-8');
+ });
+ afterEach(function() {
+ shell.rm('-rf', mergesPath);
+ });
+ it('should copy a new file from merges into www', function() {
+ parser.update_overrides();
+ expect(fs.existsSync(path.join(wp7_project_path, 'assets', 'www', 'merge.js'))).toBe(true);
+ });
+
+ it('should copy a file from merges over a file in www', function() {
+ var newFileWWW = path.join(util.projectWww(project_path), 'merge.js');
+ fs.writeFileSync(newFileWWW, 'var foo=1;', 'utf-8');
+ this.after(function() {
+ shell.rm('-rf', newFileWWW);
+ });
+ parser.update_overrides();
+ expect(fs.existsSync(path.join(wp7_project_path, 'assets', 'www', 'merge.js'))).toBe(true);
+ expect(fs.readFileSync(path.join(wp7_project_path, 'assets', 'www', 'merge.js'),'utf-8')).toEqual('alert("sup");');
+ });*/
+
+ // TODO : figure out if this is supported
+ //expect(true).toBe(false);
+ });
+
+ describe('update_project method', function() {
+ it('should invoke update_www', function() {
+ var spyWww = spyOn(parser, 'update_www');
+ parser.update_project(config);
+ expect(spyWww).toHaveBeenCalled();
+ });
+ it('should invoke update_from_config', function() {
+ var spyConfig = spyOn(parser, 'update_from_config');
+ parser.update_project(config);
+ expect(spyConfig).toHaveBeenCalled();
+ });
+ it('should call out to util.deleteSvnFolders', function() {
+ var spy = spyOn(util, 'deleteSvnFolders');
+ parser.update_project(config);
+ expect(spy).toHaveBeenCalled();
+ });
+ });
+ });
+});
\ No newline at end of file
[24/37] Add WP7 and WP8 platform files.
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy/CordovaDeploy.csproj
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy/CordovaDeploy.csproj b/lib/cordova-wp7/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy/CordovaDeploy.csproj
new file mode 100644
index 0000000..fb9949f
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy/CordovaDeploy.csproj
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+ <ProductVersion>8.0.30703</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{E752165B-AF59-4FF0-8601-A2A69FE09E0E}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>CordovaDeploy</RootNamespace>
+ <AssemblyName>CordovaDeploy</AssemblyName>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+ <TargetFrameworkProfile>Client</TargetFrameworkProfile>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+ <PlatformTarget>x86</PlatformTarget>
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+ <PlatformTarget>x86</PlatformTarget>
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="Microsoft.Smartdevice.Connectivity, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>C:\Program Files (x86)\Common Files\microsoft shared\Phone Tools\CoreCon\10.0\Bin\Microsoft.Smartdevice.Connectivity.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Program.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy/Program.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy/Program.cs b/lib/cordova-wp7/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy/Program.cs
new file mode 100644
index 0000000..2e70187
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy/Program.cs
@@ -0,0 +1,235 @@
+/*
+ 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.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.SmartDevice.Connectivity;
+using System.Collections.ObjectModel;
+using System.Diagnostics;
+using System.IO;
+using System.Xml.XPath;
+using System.Xml;
+using System.Xml.Linq;
+
+
+namespace CordovaDeploy
+{
+
+ class DeployTool
+ {
+
+ static void Usage()
+ {
+ Log("Usage: CordovaDeploy [ -devices BuildOutputPath -d:DeviceIndex ]");
+ Log(" -devices : lists the devices and exits");
+ Log(" BuildOutputPath : path to the built application, typically Bin/Debug/ or Bin/Release/");
+ Log(" -d : index of the device to deploy, default is 0 ");
+ Log("examples:");
+ Log(" CordovaDeploy -devices");
+ Log(" CordovaDeploy Bin/Debug");
+ Log(" CordovaDeploy Bin/Release -d:1");
+
+ }
+
+ static void ReadWait()
+ {
+ //Console.WriteLine("\nPress ENTER to continue...");
+ //Console.Read();
+ }
+
+ static void Log(string msg, bool error = false)
+ {
+ Debug.WriteLine(msg);
+ if (error)
+ {
+ Console.Error.WriteLine(msg);
+ }
+ else
+ {
+ Console.Out.WriteLine(msg);
+ }
+ }
+
+ static Guid ReadAppId(string root)
+ {
+ Guid appID = Guid.Empty;
+ string manifestFilePath = root + @"\Properties\WMAppManifest.xml";
+
+ if (File.Exists(manifestFilePath))
+ {
+ XDocument xdoc = XDocument.Load(manifestFilePath);
+ var appNode = xdoc.Root.Descendants("App").FirstOrDefault();
+ if (appNode != null)
+ {
+ string guidStr = appNode.Attribute("ProductID").Value;
+ appID = new Guid(guidStr);
+ }
+ else
+ {
+ Log(string.Format("Unable to find appID, expected to find an App.ProductID property defined in the file {0}", manifestFilePath), true);
+ }
+ }
+ else
+ {
+ Log(string.Format("Error: the file {0} does not exist", manifestFilePath), true);
+ }
+
+
+ return appID;
+ }
+
+
+
+ static void ListDevices()
+ {
+ // Get CoreCon WP7 SDK
+ DatastoreManager dsmgrObj = new DatastoreManager(1033);
+ Platform WP7SDK = dsmgrObj.GetPlatforms().Single(p => p.Name == "Windows Phone 7");
+ Collection<Device> devices = WP7SDK.GetDevices();
+ for (int index = 0; index < devices.Count; index++)
+ {
+ Device d = devices[index];
+ string info = string.Format("{0} : {1} : {2}", index.ToString(), d.Id, d.Name);
+ Log(info);
+ }
+ }
+
+ static void Main(string[] args)
+ {
+ int deviceIndex = 0;
+
+ string iconFilePath = "";
+ string xapFilePath = "";
+ Guid appID = Guid.Empty;
+
+ string root = Directory.GetCurrentDirectory();
+
+ if (args.Length < 1)
+ {
+ Usage();
+ ReadWait();
+ return;
+ }
+ else if (args[0] == "-devices")
+ {
+ ListDevices();
+ return;
+ }
+ else if (args.Length > 1 && args[1].StartsWith("-d:"))
+ {
+ deviceIndex = int.Parse(args[1].Substring(3));
+ }
+
+
+ if (Directory.Exists(args[0]))
+ {
+ DirectoryInfo info = new DirectoryInfo(args[0]);
+ root = info.FullName;
+ }
+
+ appID = ReadAppId(root);
+ if (appID == Guid.Empty)
+ {
+ // Logging of errors is done in ReadAppId
+ return;
+ }
+
+ if (File.Exists(root + @"\ApplicationIcon.png"))
+ {
+ iconFilePath = root + @"\ApplicationIcon.png";
+ }
+ else
+ {
+ Log(string.Format("Error: could not find application icon at {0}", root + @"\ApplicationIcon.png"), true);
+ ReadWait();
+ return;
+ }
+
+ try {
+ xapFilePath = Directory.GetFiles(root + @"\Bin\Debug", "*.xap").FirstOrDefault();
+ } catch (DirectoryNotFoundException e) {
+ try {
+ xapFilePath = Directory.GetFiles(root + @"\Bin\Release", "*.xap").FirstOrDefault();
+ } catch (DirectoryNotFoundException ex) {
+ Log(string.Format("Error: could not find project build directoy in {0}", root), true);
+ Log("make sure your app has been successfully built before deploying.", true);
+ }
+ }
+
+ if (string.IsNullOrEmpty(xapFilePath))
+ {
+ Log(string.Format("Error: could not find application .xap in folder {0}", root), true);
+ ReadWait();
+ return;
+ }
+
+
+ // Get CoreCon WP7 SDK
+ DatastoreManager dsmgrObj = new DatastoreManager(1033);
+ Collection<Platform> WP7SDKs = dsmgrObj.GetPlatforms();
+ Platform WP7SDK = dsmgrObj.GetPlatforms().Single(p => p.Name == "Windows Phone 7");
+
+ Collection<Device> devices = null;
+
+ devices = WP7SDK.GetDevices();
+
+ //// Get Emulator / Device
+ Device WP7Device = devices[deviceIndex];
+
+ if (WP7Device != null)
+ {
+ RemoteApplication app;
+ bool isConnected = WP7Device.IsConnected();
+
+ Debug.WriteLine(WP7Device.ToString());
+
+ if (!isConnected)
+ {
+ try
+ {
+ WP7Device.Connect();
+ }
+ catch (Exception ex)
+ {
+ Log("Error: " + ex.Message, true);
+ ReadWait();
+ return;
+ }
+ }
+
+ if (WP7Device.IsApplicationInstalled(appID))
+ {
+ Log("Uninstalling XAP from " + WP7Device.Name);
+ app = WP7Device.GetApplication(appID);
+ app.Uninstall();
+ }
+
+ Log("Installing app on " + WP7Device.Name);
+ app = WP7Device.InstallApplication(appID, appID, "NormalApp", iconFilePath, xapFilePath);
+
+ Log("Launching app on " + WP7Device.Name);
+ app.Launch();
+
+ ReadWait();
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy/Properties/AssemblyInfo.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy/Properties/AssemblyInfo.cs b/lib/cordova-wp7/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..3c26c87
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/cordova/lib/CordovaDeploy/CordovaDeploy/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("CordovaDeploy")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("CordovaDeploy")]
+[assembly: AssemblyCopyright("Copyright © 2012")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("256b11aa-d4bb-48cf-8024-7c040421fa8d")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/cordova/lib/build.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordova/lib/build.js b/lib/cordova-wp7/templates/standalone/cordova/lib/build.js
new file mode 100644
index 0000000..9986a7e
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/cordova/lib/build.js
@@ -0,0 +1,181 @@
+/*
+ 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.
+*/
+
+
+var fso = WScript.CreateObject('Scripting.FileSystemObject');
+var wscript_shell = WScript.CreateObject("WScript.Shell");
+
+var args = WScript.Arguments;
+
+// working dir
+var ROOT = WScript.ScriptFullName.split('\\cordova\\lib\\build.js').join('');
+
+// help/usage function
+function Usage() {
+ Log("");
+ Log("Usage: build [ --debug | --release ]");
+ Log(" --help : Displays this dialog.");
+ Log(" --debug : Cleans and builds project in debug mode.");
+ Log(" --release : Cleans and builds project in release mode.");
+ Log("examples:");
+ Log(" build ");
+ Log(" build --debug");
+ Log(" build --release");
+ Log("");
+}
+
+// logs messaged to stdout and stderr
+function Log(msg, error) {
+ if (error) {
+ WScript.StdErr.WriteLine(msg);
+ }
+ else {
+ WScript.StdOut.WriteLine(msg);
+ }
+}
+
+// executes a commmand in the shell
+function exec_verbose(command) {
+ //Log("Command: " + command);
+ var oShell=wscript_shell.Exec(command);
+ while (oShell.Status == 0) {
+ //Wait a little bit so we're not super looping
+ WScript.sleep(100);
+ //Print any stdout output from the script
+ if (!oShell.StdOut.AtEndOfStream) {
+ var line = oShell.StdOut.ReadLine();
+ Log(line);
+ }
+ }
+ //Check to make sure our scripts did not encounter an error
+ if (!oShell.StdErr.AtEndOfStream) {
+ var line = oShell.StdErr.ReadAll();
+ Log(line, true);
+ WScript.Quit(2);
+ }
+}
+
+// checks to see if a .csproj file exists in the project root
+function is_cordova_project(path) {
+ if (fso.FolderExists(path)) {
+ var proj_folder = fso.GetFolder(path);
+ var proj_files = new Enumerator(proj_folder.Files);
+ for (;!proj_files.atEnd(); proj_files.moveNext()) {
+ if (fso.GetExtensionName(proj_files.item()) == 'csproj') {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+// builds the project and .xap in release mode
+function build_xap_release(path) {
+ Log("Building Cordova-WP8 Project:");
+ Log("\tConfiguration : Release");
+ Log("\tDirectory : " + path);
+
+ wscript_shell.CurrentDirectory = path;
+ exec_verbose('msbuild /clp:NoSummary;NoItemAndPropertyList;Verbosity=minimal /nologo /p:Configuration=Release');
+
+ // check if file xap was created
+ if (fso.FolderExists(path + '\\Bin\\Release')) {
+ var out_folder = fso.GetFolder(path + '\\Bin\\Release');
+ var out_files = new Enumerator(out_folder.Files);
+ for (;!out_files.atEnd(); out_files.moveNext()) {
+ if (fso.GetExtensionName(out_files.item()) == 'xap') {
+ Log("BUILD SUCCESS.");
+ return;
+ }
+ }
+ }
+ Log('ERROR: MSBuild failed to create .xap when building cordova-wp8 for release.', true);
+ WScript.Quit(2);
+}
+
+// builds the project and .xap in debug mode
+function build_xap_debug(path) {
+ Log("Building Cordova-WP8 Project:");
+ Log("\tConfiguration : Debug");
+ Log("\tDirectory : " + path);
+
+ wscript_shell.CurrentDirectory = path;
+ exec_verbose('msbuild /clp:NoSummary;NoItemAndPropertyList;Verbosity=minimal /nologo /p:Configuration=Debug');
+
+ // check if file xap was created
+ if (fso.FolderExists(path + '\\Bin\\Debug')) {
+ var out_folder = fso.GetFolder(path + '\\Bin\\Debug');
+ var out_files = new Enumerator(out_folder.Files);
+ for (;!out_files.atEnd(); out_files.moveNext()) {
+ if (fso.GetExtensionName(out_files.item()) == 'xap') {
+ Log("BUILD SUCCESS.");
+ return;
+ }
+ }
+ }
+ Log('ERROR: MSBuild failed to create .xap when building cordova-wp8 for debugging.', true);
+ WScript.Quit(2);
+}
+
+
+Log("");
+
+if (args.Count() > 0) {
+ // support help flags
+ if (args(0) == "--help" || args(0) == "/?" ||
+ args(0) == "help" || args(0) == "-help" || args(0) == "/help") {
+ Usage();
+ WScript.Quit(2);
+ }
+ else if (args.Count() > 1) {
+ Log("Error: Too many arguments.", true);
+ Usage();
+ WScript.Quit(2);
+ }
+ else if (fso.FolderExists(ROOT)) {
+ if (!is_cordova_project(ROOT)) {
+ Log('Error: .csproj file not found in ' + ROOT, true);
+ Log('could not build project.', true);
+ WScript.Quit(2);
+ }
+
+ if (args(0) == "--debug" || args(0) == "-d") {
+ exec_verbose('%comspec% /c ' + ROOT + '\\cordova\\clean');
+ build_xap_debug(ROOT);
+ }
+ else if (args(0) == "--release" || args(0) == "-r") {
+ exec_verbose('%comspec% /c ' + ROOT + '\\cordova\\clean');
+ build_xap_release(ROOT);
+ }
+ else {
+ Log("Error: \"" + args(0) + "\" is not recognized as a build option", true);
+ Usage();
+ WScript.Quit(2);
+ }
+ }
+ else {
+ Log("Error: Project directory not found,", true);
+ Usage();
+ WScript.Quit(2);
+ }
+}
+else {
+ Log("WARNING: [ --debug | --release ] not specified, defaulting to debug...");
+ build_xap_debug(ROOT);
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/cordova/lib/clean.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordova/lib/clean.js b/lib/cordova-wp7/templates/standalone/cordova/lib/clean.js
new file mode 100644
index 0000000..3a8c871
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/cordova/lib/clean.js
@@ -0,0 +1,124 @@
+/*
+ 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.
+*/
+
+
+var fso = WScript.CreateObject('Scripting.FileSystemObject');
+var wscript_shell = WScript.CreateObject("WScript.Shell");
+var args = WScript.Arguments;
+// working dir
+var ROOT = WScript.ScriptFullName.split('\\cordova\\lib\\clean.js').join('');
+
+
+// help function
+function Usage() {
+ Log("");
+ Log("Usage: clean [ --debug | --release ]");
+ Log(" --debug : Cleans generated debug files in project.");
+ Log(" --release : Cleans generated release files in project.");
+ Log("examples:");
+ Log(" clean --debug");
+ Log(" clean");
+ Log(" - deletes all generated files in project");
+ Log("");
+}
+
+// logs to stdout or stderr
+function Log(msg, error) {
+ if (error) {
+ WScript.StdErr.WriteLine(msg);
+ }
+ else {
+ WScript.StdOut.WriteLine(msg);
+ }
+}
+
+// cleans any generated files in the cordova project
+function clean_project(path) {
+ if (fso.FolderExists(path + "\\obj")) {
+ fso.DeleteFolder(path + "\\obj");
+ }
+ if (fso.FolderExists(path + "\\Bin")) {
+ fso.DeleteFolder(path + "\\Bin");
+ }
+ //TODO: delete CordovaAppProj.csproj.user as well? Service References?
+}
+
+// cleans any files generated by build --debug
+function clean_debug(path) {
+ if (fso.FolderExists(path + "\\obj\\Debug")) {
+ fso.DeleteFolder(path + "\\obj\\Debug");
+ }
+ if (fso.FolderExists(path + "\\Bin\\Debug")) {
+ fso.DeleteFolder(path + "\\Bin\\Debug");
+ }
+}
+
+// cleans any files generated by build --release
+function clean_release(path) {
+ if (fso.FolderExists(path + "\\obj\\Release")) {
+ fso.DeleteFolder(path + "\\obj\\Release");
+ }
+ if (fso.FolderExists(path + "\\Bin\\Release")) {
+ fso.DeleteFolder(path + "\\Bin\\Release");
+ }
+}
+
+
+if (args.Count() > 0) {
+ // support help flags
+ if (args(0) == "--help" || args(0) == "/?" ||
+ args(0) == "help" || args(0) == "-help" || args(0) == "/help") {
+ Usage();
+ WScript.Quit(2);
+ }
+ else if (args.Count() > 1) {
+ Log("Error: Too many arguments.", true);
+ Usage();
+ WScript.Quit(2);
+ }
+ else if (fso.FolderExists(ROOT)) {
+ if (args(0) == "--debug" || args(0) == "-d") {
+ clean_debug(ROOT);
+ }
+ else if (args(0) == "--release" || args(0) == "-r") {
+ clean_release(ROOT);
+ }
+ else {
+ Log("Error: \"" + args(0) + "\" is not recognized as a build option", true);
+ Usage();
+ WScript.Quit(2);
+ }
+ }
+ else {
+ Log("Error: Project directory not found,", true);
+ Usage();
+ WScript.Quit(2);
+ }
+}
+else {
+ if (fso.FolderExists(ROOT)) {
+ Log("Cleaning cordova project...");
+ clean_project(ROOT);
+ }
+ else {
+ Log("Error: Project directory not found,", true);
+ Usage();
+ WScript.Quit(2);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/cordova/lib/deploy.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordova/lib/deploy.js b/lib/cordova-wp7/templates/standalone/cordova/lib/deploy.js
new file mode 100644
index 0000000..29a3f7d
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/cordova/lib/deploy.js
@@ -0,0 +1,326 @@
+/*
+ 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.
+*/
+
+
+var fso = WScript.CreateObject('Scripting.FileSystemObject');
+var wscript_shell = WScript.CreateObject("WScript.Shell");
+
+var args = WScript.Arguments;
+// working dir
+var ROOT = WScript.ScriptFullName.split('\\cordova\\lib\\deploy.js').join('');
+ // path to CordovaDeploy.exe
+var CORDOVA_DEPLOY_EXE = '\\cordova\\lib\\CordovaDeploy\\CordovaDeploy\\bin\\Debug\\CordovaDeploy.exe';
+ // path to CordovaDeploy
+var CORDOVA_DEPLOY = '\\cordova\\lib\\CordovaDeploy';
+
+//build types
+var NONE = 0,
+ DEBUG = 1,
+ RELEASE = 2,
+ NO_BUILD = 3;
+var build_type = NONE;
+
+
+// help function
+function Usage() {
+ Log("");
+ Log("Usage: run [ --device | --emulator | --target=<id> ] [ --debug | --release | --nobuild ]");
+ Log(" --device : Deploys and runs the project on the connected device.");
+ Log(" --emulator : Deploys and runs the project on an emulator.");
+ Log(" --target=<id> : Deploys and runs the project on the specified target.");
+ Log(" --debug : Builds project in debug mode.");
+ Log(" --release : Builds project in release mode.");
+ Log(" --nobuild : Ueses pre-built xap, or errors if project is not built.");
+ Log("examples:");
+ Log(" run");
+ Log(" run --emulator");
+ Log(" run --device");
+ Log(" run --target=7988B8C3-3ADE-488d-BA3E-D052AC9DC710");
+ Log(" run --device --release");
+ Log(" run --emulator --debug");
+ Log("");
+}
+
+// log to stdout or stderr
+function Log(msg, error) {
+ if (error) {
+ WScript.StdErr.WriteLine(msg);
+ }
+ else {
+ WScript.StdOut.WriteLine(msg);
+ }
+}
+
+var ForReading = 1, ForWriting = 2, ForAppending = 8;
+var TristateUseDefault = 2, TristateTrue = 1, TristateFalse = 0;
+
+
+// executes a commmand in the shell
+function exec(command) {
+ var oShell=wscript_shell.Exec(command);
+ while (oShell.Status == 0) {
+ WScript.sleep(100);
+ }
+}
+
+// executes a commmand in the shell
+function exec_verbose(command) {
+ //Log("Command: " + command);
+ var oShell=wscript_shell.Exec(command);
+ while (oShell.Status == 0) {
+ //Wait a little bit so we're not super looping
+ WScript.sleep(100);
+ //Print any stdout output from the script
+ if (!oShell.StdOut.AtEndOfStream) {
+ var line = oShell.StdOut.ReadAll();
+ Log(line);
+ }
+ }
+ //Check to make sure our scripts did not encounter an error
+ if (!oShell.StdErr.AtEndOfStream) {
+ var line = oShell.StdErr.ReadAll();
+ Log(line, true);
+ WScript.Quit(2);
+ }
+}
+
+// returns the contents of a file
+function read(filename) {
+ if (fso.FileExists(filename)) {
+ var f=fso.OpenTextFile(filename, 1,2);
+ var s=f.ReadAll();
+ f.Close();
+ return s;
+ }
+ else {
+ Log('Cannot read non-existant file : ' + filename, true);
+ WScript.Quit(2);
+ }
+ return null;
+}
+
+// builds the CordovaDeploy.exe if it does not already exist
+function cordovaDeploy(path) {
+ if (fso.FileExists(path + CORDOVA_DEPLOY_EXE)) {
+ return;
+ }
+
+ Log('CordovaDeploy.exe not found, attempting to build CordovaDeploy.exe...');
+
+ // build CordovaDeploy.exe
+ if (fso.FolderExists(path + '\\cordova') && fso.FolderExists(path + CORDOVA_DEPLOY) &&
+ fso.FileExists(path + CORDOVA_DEPLOY + '\\CordovaDeploy.sln')) {
+ // delete any previously generated files
+ if (fso.FolderExists(path + CORDOVA_DEPLOY + '\\CordovaDeploy\\obj')) {
+ fso.DeleteFolder(path + CORDOVA_DEPLOY + '\\CordovaDeploy\\obj');
+ }
+ if (fso.FolderExists(path + CORDOVA_DEPLOY + '\\CordovaDeploy\\Bin')) {
+ fso.DeleteFolder(path + CORDOVA_DEPLOY + '\\CordovaDeploy\\Bin');
+ }
+ exec_verbose('msbuild ' + path + CORDOVA_DEPLOY + '\\CordovaDeploy.sln');
+
+ if (fso.FileExists(path + CORDOVA_DEPLOY_EXE)) {
+ Log('CordovaDeploy.exe compiled, SUCCESS.');
+ }
+ else {
+ Log('ERROR: MSBUILD FAILED TO COMPILE CordovaDeploy.exe', true);
+ WScript.Quit(2);
+ }
+ }
+ else {
+ Log('ERROR: CordovaDeploy.sln not found, unable to compile CordovaDeploy tool.', true);
+ WScript.Quit(2);
+ }
+}
+
+// launches project on device
+function device(path)
+{
+ cordovaDeploy(path);
+ if (fso.FileExists(path + CORDOVA_DEPLOY_EXE)) {
+ Log('Deploying to device ...');
+ //TODO: get device ID from list-devices and deploy to first one
+ exec_verbose('%comspec% /c ' + path + CORDOVA_DEPLOY_EXE + ' ' + path + ' -d:0');
+ }
+ else
+ {
+ Log('Error: Failed to find CordovaDeploy.exe in ' + path, true);
+ Log('DEPLOY FAILED.', true);
+ WScript.Quit(2);
+ }
+}
+
+// launches project on emulator
+function emulator(path)
+{
+ cordovaDeploy(path);
+ if (fso.FileExists(path + CORDOVA_DEPLOY_EXE)) {
+ Log('Deploying to emulator ...');
+ //TODO: get emulator ID from list-emulators and deploy to first one
+ exec_verbose('%comspec% /c ' + path + CORDOVA_DEPLOY_EXE + ' ' + path + ' -d:1');
+ }
+ else
+ {
+ Log('Error: Failed to find CordovaDeploy.exe in ' + path, true);
+ Log('DEPLOY FAILED.', true);
+ WScript.Quit(2);
+ }
+}
+
+// builds and launches the project on the specified target
+function target(path, device_id) {
+ if (!fso.FileExists(path + CORDOVA_DEPLOY_EXE)) {
+ cordovaDeploy(path);
+ }
+ wscript_shell.CurrentDirectory = path + CORDOVA_DEPLOY + '\\CordovaDeploy\\bin\\Debug';
+ var cmd = 'CordovaDeploy -devices';
+ var out = wscript_shell.Exec(cmd);
+ while(out.Status == 0) {
+ WScript.Sleep(100);
+ }
+ if (!out.StdErr.AtEndOfStream) {
+ var line = out.StdErr.ReadAll();
+ Log("Error calling CordovaDeploy : ", true);
+ Log(line, true);
+ WScript.Quit(2);
+ }
+ else {
+ if (!out.StdOut.AtEndOfStream) {
+ var line = out.StdOut.ReadAll();
+ var targets = line.split('\r\n');
+ var check_id = new RegExp(device_id);
+ for (target in targets) {
+ if (targets[target].match(check_id)) {
+ //TODO: this only gets single digit index, account for device index of 10+?
+ var index = targets[target].substr(0,1);
+ exec_verbose(path + CORDOVA_DEPLOY_EXE + ' ' + path + ' -d:' + index);
+ return;
+ }
+ }
+ Log('Error : target ' + device_id + ' was not found.', true);
+ Log('DEPLOY FAILED.', true);
+ WScript.Quit(2);
+ }
+ else {
+ Log('Error : CordovaDeploy Failed to find any devices', true);
+ Log('DEPLOY FAILED.', true);
+ WScript.Quit(2);
+ }
+ }
+}
+
+function build(path) {
+ switch (build_type) {
+ case DEBUG :
+ exec_verbose('%comspec% /c ' + ROOT + '\\cordova\\build --debug');
+ break;
+ case RELEASE :
+ exec_verbose('%comspec% /c ' + ROOT + '\\cordova\\build --release');
+ break;
+ case NO_BUILD :
+ break;
+ case NONE :
+ Log("WARNING: [ --debug | --release | --nobuild ] not specified, defaulting to --debug.");
+ exec_verbose('%comspec% /c ' + ROOT + '\\cordova\\build --debug');
+ break;
+ default :
+ Log("Build option not recognized: " + build_type, true);
+ WScript.Quit(2);
+ break;
+ }
+}
+
+
+if (args.Count() > 0) {
+ // support help flags
+ if (args(0) == "--help" || args(0) == "/?" ||
+ args(0) == "help" || args(0) == "-help" || args(0) == "/help") {
+ Usage();
+ WScript.Quit(2);
+ }
+ else if (args.Count() > 2) {
+ Log('Error: Too many arguments.', true);
+ Usage();
+ WScript.Quit(2);
+ }
+ else if (fso.FolderExists(ROOT)) {
+ if (args.Count() > 1) {
+ if (args(1) == "--release") {
+ build_type = RELEASE;
+ }
+ else if (args(1) == "--debug") {
+ build_type = DEBUG;
+ }
+ else if (args(1) == "--nobuild") {
+ build_type = NO_BUILD;
+ }
+ else {
+ Log('Error: \"' + args(1) + '\" is not recognized as a deploy option', true);
+ Usage();
+ WScript.Quit(2);
+ }
+ }
+
+ if (args(0) == "--emulator" || args(0) == "-e") {
+ build(ROOT);
+ emulator(ROOT);
+ }
+ else if (args(0) == "--device" || args(0) == "-d") {
+ build(ROOT);
+ device(ROOT);
+ }
+ else if (args(0).substr(0,9) == "--target=") {
+ build(ROOT);
+ var device_id = args(0).split("--target=").join("");
+ target(ROOT, device_id);
+ }
+ else {
+ Log("WARNING: [ --target=<ID> | --emulator | --device ] not specified, defaulting to --emulator");
+ if (args(0) == "--release") {
+ build_type = RELEASE;
+ build(ROOT);
+ emulator(ROOT);
+ }
+ else if (args(0) == "--debug") {
+ build_type = DEBUG;
+ build(ROOT);
+ emulator(ROOT);
+ }
+ else if (args(0) == "--nobuild") {
+ build_type = NO_BUILD;
+ emulator(ROOT);
+ }
+ else {
+ Log('Error: \"' + args(0) + '\" is not recognized as a deploy option', true);
+ Usage();
+ WScript.Quit(2);
+ }
+ }
+ }
+ else {
+ Log('Error: Project directory not found,', true);
+ Usage();
+ WScript.Quit(2);
+ }
+}
+else {
+ Log("WARNING: [ --target=<ID> | --emulator | --device ] not specified, defaulting to --emulator");
+ build(ROOT);
+ emulator(ROOT);
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/cordova/lib/install-device.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordova/lib/install-device.bat b/lib/cordova-wp7/templates/standalone/cordova/lib/install-device.bat
new file mode 100644
index 0000000..9507c36
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/cordova/lib/install-device.bat
@@ -0,0 +1,9 @@
+@ECHO OFF
+SET full_path=%~dp0
+IF EXIST %full_path%deploy.js (
+ cscript "%full_path%deploy.js" %* --device --nobuild //nologo
+) ELSE (
+ ECHO.
+ ECHO ERROR: Could not find 'deploy.js' in cordova/lib, aborting...>&2
+ EXIT /B 1
+)
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/cordova/lib/install-emulator.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordova/lib/install-emulator.bat b/lib/cordova-wp7/templates/standalone/cordova/lib/install-emulator.bat
new file mode 100644
index 0000000..b3ee451
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/cordova/lib/install-emulator.bat
@@ -0,0 +1,9 @@
+@ECHO OFF
+SET full_path=%~dp0
+IF EXIST %full_path%deploy.js (
+ cscript "%full_path%deploy.js" %* --emulator --nobuild //nologo
+) ELSE (
+ ECHO.
+ ECHO ERROR: Could not find 'deploy.js' in cordova/lib, aborting...>&2
+ EXIT /B 1
+)
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/cordova/lib/list-devices.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordova/lib/list-devices.bat b/lib/cordova-wp7/templates/standalone/cordova/lib/list-devices.bat
new file mode 100644
index 0000000..bf4492b
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/cordova/lib/list-devices.bat
@@ -0,0 +1,9 @@
+@ECHO OFF
+SET full_path=%~dp0
+IF EXIST %full_path%target-list.js (
+ cscript "%full_path%target-list.js" %* --devices //nologo
+) ELSE (
+ ECHO.
+ ECHO ERROR: Could not find 'target-list.js' in cordova/lib, aborting...>&2
+ EXIT /B 1
+)
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/cordova/lib/list-emulator-images.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordova/lib/list-emulator-images.bat b/lib/cordova-wp7/templates/standalone/cordova/lib/list-emulator-images.bat
new file mode 100644
index 0000000..3f571c7
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/cordova/lib/list-emulator-images.bat
@@ -0,0 +1,9 @@
+@ECHO OFF
+SET full_path=%~dp0
+IF EXIST %full_path%target-list.js (
+ cscript "%full_path%target-list.js" %* --emulators //nologo
+) ELSE (
+ ECHO.
+ ECHO ERROR: Could not find 'target-list.js' in cordova/lib, aborting...>&2
+ EXIT /B 1
+)
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/cordova/lib/list-started-emulators.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordova/lib/list-started-emulators.bat b/lib/cordova-wp7/templates/standalone/cordova/lib/list-started-emulators.bat
new file mode 100644
index 0000000..d779b5d
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/cordova/lib/list-started-emulators.bat
@@ -0,0 +1,3 @@
+@ECHO OFF
+ECHO Sorry, list-started-emulators is not availible yet for Windows Phone. 1>&2
+EXIT /B 1
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/cordova/lib/log.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordova/lib/log.js b/lib/cordova-wp7/templates/standalone/cordova/lib/log.js
new file mode 100644
index 0000000..0b4ea7d
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/cordova/lib/log.js
@@ -0,0 +1,77 @@
+/*
+ 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.
+*/
+
+
+var fso = WScript.CreateObject('Scripting.FileSystemObject');
+var wscript_shell = WScript.CreateObject("WScript.Shell");
+var args = WScript.Arguments;
+// working dir
+var ROOT = WScript.ScriptFullName.split('\\cordova\\lib\\log.js').join('');
+
+
+// help function
+function Usage() {
+ Log("");
+ Log("Usage: log");
+ Log("examples:");
+ Log(" log");
+ Log(" - logs output from running application *NOT IMPLIMENTED*");
+ Log("");
+}
+
+// logs to stdout or stderr
+function Log(msg, error) {
+ if (error) {
+ WScript.StdErr.WriteLine(msg);
+ }
+ else {
+ WScript.StdOut.WriteLine(msg);
+ }
+}
+
+// log output from running projects *NOT IMPLEMENTED*
+function log_output(path) {
+ Log("ERROR: Logging is not supported on Windows Phone", true);
+ WScript.Quit(1);
+}
+
+
+if (args.Count() > 0) {
+ // support help flags
+ if (args(0) == "--help" || args(0) == "/?" ||
+ args(0) == "help" || args(0) == "-help" || args(0) == "/help") {
+ Usage();
+ WScript.Quit(2);
+ }
+ else {
+ Log("Error: \"" + args(0) + "\" is not recognized as a log option.", true);
+ Usage();
+ WScript.Quit(2);
+ }
+}
+else {
+ if (fso.FolderExists(ROOT)) {
+ log_output(ROOT);
+ }
+ else {
+ Log("Error: Project directory not found,", true);
+ Usage();
+ WScript.Quit(2);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/cordova/lib/start-emulator.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordova/lib/start-emulator.bat b/lib/cordova-wp7/templates/standalone/cordova/lib/start-emulator.bat
new file mode 100644
index 0000000..19983fd
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/cordova/lib/start-emulator.bat
@@ -0,0 +1,3 @@
+@ECHO OFF
+ECHO Sorry, start-emulator is not availible yet for Windows Phone. 1>&2
+EXIT /B 1
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/cordova/lib/target-list.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordova/lib/target-list.js b/lib/cordova-wp7/templates/standalone/cordova/lib/target-list.js
new file mode 100644
index 0000000..805eea5
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/cordova/lib/target-list.js
@@ -0,0 +1,233 @@
+/*
+ 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.
+*/
+
+
+var fso = WScript.CreateObject('Scripting.FileSystemObject');
+var wscript_shell = WScript.CreateObject("WScript.Shell");
+
+var args = WScript.Arguments;
+// working dir
+var ROOT = WScript.ScriptFullName.split('\\cordova\\lib\\target-list.js').join('');
+ // path to CordovaDeploy.exe
+var CORDOVA_DEPLOY_EXE = '\\cordova\\lib\\CordovaDeploy\\CordovaDeploy\\bin\\Debug\\CordovaDeploy.exe';
+ // path to CordovaDeploy
+var CORDOVA_DEPLOY = '\\cordova\\lib\\CordovaDeploy';
+
+// help/usage function
+function Usage() {
+ Log("");
+ Log("Usage: cscript target-list.js [ --emulators | --devices | --started_emulators | --all ]");
+ Log(" --emulators : List the possible target emulators availible.");
+ Log(" --devices : List the possible target devices availible. *NOT IMPLEMENTED YET*");
+ Log(" --started_emulators : List any started emulators availible. *NOT IMPLEMENTED YET*");
+ Log(" --all : List all devices returned by CordovaDeploy.exe -devices ");
+ Log("examples:");
+ Log(" cscript target-list.js --emulators");
+ Log(" cscript target-list.js --devices");
+ Log(" cscript target-list.js --started_emulators");
+ Log(" cscript target-list.js --all");
+ Log("");
+}
+
+// logs messaged to stdout and stderr
+function Log(msg, error) {
+ if (error) {
+ WScript.StdErr.WriteLine(msg);
+ }
+ else {
+ WScript.StdOut.WriteLine(msg);
+ }
+}
+
+// executes a commmand in the shell
+function exec(command) {
+ var oShell=wscript_shell.Exec(command);
+ while (oShell.Status == 0) {
+ //Wait a little bit so we're not super looping
+ WScript.sleep(100);
+ //Print output? Naa.....
+ if (!oShell.StdOut.AtEndOfStream) {
+ var line = oShell.StdOut.ReadAll();
+ //Log(line);
+ }
+ }
+ //Check to make sure our scripts did not encounter an error
+ if (!oShell.StdErr.AtEndOfStream) {
+ var line = oShell.StdErr.ReadAll();
+ Log(line, true);
+ WScript.Quit(2);
+ }
+}
+
+// returns all possible targets generated by the CordovaDeploy tool
+function get_targets(path) {
+ if (!fso.FileExists(path + CORDOVA_DEPLOY_EXE)) {
+ cordovaDeploy(path);
+ }
+ wscript_shell.CurrentDirectory = path + CORDOVA_DEPLOY + '\\CordovaDeploy\\bin\\Debug';
+ var cmd = 'CordovaDeploy -devices';
+ var out = wscript_shell.Exec(cmd);
+ while(out.Status == 0) {
+ WScript.Sleep(100);
+ }
+ //Check to make sure our script did not encounter an error
+ if (!out.StdErr.AtEndOfStream) {
+ var line = out.StdErr.ReadAll();
+ Log("Error calling CordovaDeploy : ", true);
+ Log(line, true);
+ WScript.Quit(2);
+ }
+ else {
+ if (!out.StdOut.AtEndOfStream) {
+ var line = out.StdOut.ReadAll();
+ var targets = line.split('\r\n');
+ //format (ID DESCRIPTION)
+ for (i in targets) {
+ // remove device index and separator colen
+ targets[i] = targets[i].replace(/\d*\s\:\s/, '').replace(/\:\s/, '');
+ }
+ return targets;
+ }
+ else {
+ Log('Error : CordovaDeploy Failed to find any devices', true);
+ WScript.Quit(2);
+ }
+ }
+}
+
+function list_targets(path) {
+ var targets = get_targets(path);
+ for (i in targets) {
+ Log(targets[i]);
+ }
+}
+
+// lists the Device returned by CordovaDeploy (NOTE: this does not indicate that a device is connected)
+function list_devices(path) {
+ var targets = get_targets(path);
+ var device_found = false;
+ for (i in targets) {
+ if (targets[i].match(/Device/)) {
+ Log(targets[i]);
+ device_found = true;
+ }
+ }
+ if (device_found) {
+ Log('');
+ Log('WARNING : This does not mean that a device is connected, make');
+ Log(' sure your device is connected before deploying to it.');
+ }
+}
+
+// lists the emulators availible to CordovaDeploy
+function list_emulator_images(path) {
+ var targets = get_targets(path);
+ for (i in targets) {
+ if (targets[i].match(/Emulator/)) {
+ Log(targets[i]);
+ }
+ }
+}
+
+// lists any started emulators *NOT IMPLEMENTED*
+function list_started_emulators(path) {
+ Log('ERROR : list-started-emulators is not supported on Windows Phone.', true);
+ WScript.Quit(1);
+}
+
+// builds the CordovaDeploy.exe if it does not already exist
+function cordovaDeploy(path) {
+ if (fso.FileExists(path + CORDOVA_DEPLOY_EXE)) {
+ return;
+ }
+
+ // build CordovaDeploy.exe
+ if (fso.FolderExists(path + '\\cordova') && fso.FolderExists(path + CORDOVA_DEPLOY) &&
+ fso.FileExists(path + CORDOVA_DEPLOY + '\\CordovaDeploy.sln')) {
+ // delete any previously generated files
+ if (fso.FolderExists(path + CORDOVA_DEPLOY + "\\CordovaDeploy\\obj")) {
+ fso.DeleteFolder(path + CORDOVA_DEPLOY + "\\CordovaDeploy\\obj");
+ }
+ if (fso.FolderExists(path + CORDOVA_DEPLOY + "\\CordovaDeploy\\Bin")) {
+ fso.DeleteFolder(path + CORDOVA_DEPLOY + "\\CordovaDeploy\\Bin");
+ }
+ exec('msbuild ' + path + CORDOVA_DEPLOY + '\\CordovaDeploy.sln');
+
+ if (fso.FileExists(path + CORDOVA_DEPLOY_EXE)) {
+ return;
+ }
+ else {
+ Log("ERROR: MSBUILD FAILED TO COMPILE CordovaDeploy.exe", true);
+ WScript.Quit(2);
+ }
+ }
+ else {
+ Log("ERROR: CordovaDeploy.sln not found, unable to compile CordovaDeploy tool.", true);
+ WScript.Quit(2);
+ }
+}
+
+
+if (args.Count() > 0) {
+ // support help flags
+ if (args(0) == "--help" || args(0) == "/?" ||
+ args(0) == "help" || args(0) == "-help" || args(0) == "/help") {
+ Usage();
+ WScript.Quit(2);
+ }
+ else if (args.Count() > 1) {
+ Log("Error: Too many arguments.", true);
+ Usage();
+ WScript.Quit(2);
+ }
+ else if (fso.FolderExists(ROOT)) {
+ if (!fso.FolderExists(ROOT + '\\cordova')) {
+ Log("Error: cordova tooling folder not found in project directory,", true);
+ Log("could not lsit targets.", true);
+ WScript.Quit(2);
+ }
+
+ if (args(0) == "--emulators" || args(0) == "-e") {
+ list_emulator_images(ROOT);
+ }
+ else if (args(0) == "--devices" || args(0) == "-d") {
+ list_devices(ROOT);
+ }
+ else if (args(0) == "--started_emulators" || args(0) == "-s") {
+ list_started_emulators(ROOT);
+ }
+ else if (args(0) == "--all" || args(0) == "-a") {
+ list_targets(ROOT);
+ }
+ else {
+ Log("Error: \"" + args(0) + "\" is not recognized as a target-list option", true);
+ Usage();
+ WScript.Quit(2);
+ }
+ }
+ else {
+ Log("Error: Project directory not found,", true);
+ Usage();
+ WScript.Quit(2);
+ }
+}
+else {
+ Log("WARNING: target list not specified, showing all targets...");
+ list_targets(ROOT);
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/cordova/log.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordova/log.bat b/lib/cordova-wp7/templates/standalone/cordova/log.bat
new file mode 100644
index 0000000..46dbe5c
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/cordova/log.bat
@@ -0,0 +1,3 @@
+@ECHO OFF
+ECHO Sorry, loging is yet supported for Windows Phone. 1>&2
+EXIT /B 1
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/cordova/run.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordova/run.bat b/lib/cordova-wp7/templates/standalone/cordova/run.bat
new file mode 100644
index 0000000..b966856
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/cordova/run.bat
@@ -0,0 +1,9 @@
+@ECHO OFF
+SET full_path=%~dp0
+IF EXIST %full_path%lib\deploy.js (
+ cscript "%full_path%lib\deploy.js" %* //nologo
+) ELSE (
+ ECHO.
+ ECHO ERROR: Could not find 'deploy.js' in cordova/lib, aborting...>&2
+ EXIT /B 1
+)
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/cordovalib/BrowserMouseHelper.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordovalib/BrowserMouseHelper.cs b/lib/cordova-wp7/templates/standalone/cordovalib/BrowserMouseHelper.cs
new file mode 100644
index 0000000..acd1bcd
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/cordovalib/BrowserMouseHelper.cs
@@ -0,0 +1,345 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+using System.Linq;
+using System.Windows;
+using System.Windows.Controls;
+using Microsoft.Phone.Controls;
+using System.Windows.Input;
+using System.Diagnostics;
+using System.Windows.Media;
+using System;
+using System.Collections.Generic;
+
+namespace WPCordovaClassLib
+{
+
+ /// <summary>
+ /// Suppresses pinch zoom and optionally scrolling of the WebBrowser control
+ /// </summary>
+ public class BrowserMouseHelper
+ {
+
+ /**
+ *
+ * Full Script below, in use it is minified.
+ */
+ /*
+ private static string mouseScript =
+ @"(function(win,doc){
+ var mPro = MouseEvent.prototype;
+ var def = Object.defineProperty;
+ def( mPro, 'pageX', {
+ configurable: true,
+ get: function(){ return this.clientX }
+ });
+ def( mPro, 'pageY', {
+ configurable: true,
+ get: function(){ return this.clientY }
+ });
+
+ win.onNativeMouseEvent = function(type,x,y){
+ try {
+ var xMod = screen.logicalXDPI / screen.deviceXDPI;
+ var yMod = screen.logicalYDPI / screen.deviceYDPI;
+ var evt = doc.createEvent('MouseEvents');
+ var xPos = doc.body.scrollLeft + Math.round(xMod * x);
+ var yPos = doc.body.scrollTop + Math.round(yMod * y);
+ var element = doc.elementFromPoint(xPos,yPos);
+
+ evt.initMouseEvent(type, true, true, win, 1, xPos, yPos, xPos, yPos, false, false, false, false, 0, element);
+ evt.timeStamp = +new Date;
+ evt.isCordovaEvent = true;
+
+ var canceled = element ? !element.dispatchEvent(evt) : !doc.dispatchEvent(evt);
+ return canceled ? 'true' : 'false';
+ }
+ catch(e) { return e;}
+ }
+ })(window,document);";
+ */
+
+ private static string MinifiedMouseScript = "(function(g,a){var c=MouseEvent.prototype,d=Object.defineProperty;d(c,'pageX',{configurable:!0,get:function(){return this.clientX}});d(c,'pageY',{configurable:!0,get:function(){return this.clientY}});g.onNativeMouseEvent=function(c,d,i)"
+ + "{try{var j=screen.logicalXDPI/screen.deviceXDPI,k=screen.logicalYDPI/screen.deviceYDPI,b=a.createEvent('MouseEvents'),e=a.body.scrollLeft+Math.round(j*d),f=a.body.scrollTop+Math.round(k*i),h=a.elementFromPoint(e,f);b.initMouseEvent(c,!0,!0,g,1,e,f,e,f,!1,!1,!1,!1,0,"
+ + "h);b.timeStamp=+new Date;b.isCordovaEvent=!0;return(h?!h.dispatchEvent(b):!a.dispatchEvent(b))?'true':'false'}catch(l){return l}}})(window,document);";
+
+
+ private WebBrowser _browser;
+
+ /// <summary>
+ /// Gets or sets whether to suppress the scrolling of
+ /// the WebBrowser control;
+ /// </summary>
+ public bool ScrollDisabled { get; set; }
+
+ private bool userScalable = true;
+ private double maxScale = 2.0;
+ private double minScale = 0.5;
+ protected Border border;
+ private bool firstMouseMove = false;
+
+ /// <summary>
+ /// Represents last known mouse down position.
+ /// Used to determine mouse move delta to avoid duplicate mouse events.
+ /// </summary>
+ private Point mouseDownPos;
+
+ /// <summary>
+ /// Represent min delta value to consider event as a mouse move. Experimental calculated.
+ /// </summary>
+ private const int MouseMoveDeltaThreshold = 10;
+
+
+ public BrowserMouseHelper(ref WebBrowser browser)
+ {
+ _browser = browser;
+ browser.Loaded += new RoutedEventHandler(browser_Loaded);
+ }
+
+ private void browser_Loaded(object sender, RoutedEventArgs e)
+ {
+ var border0 = VisualTreeHelper.GetChild(_browser, 0);
+ var border1 = VisualTreeHelper.GetChild(border0, 0);
+ var panZoom = VisualTreeHelper.GetChild(border1, 0);
+ var grid = VisualTreeHelper.GetChild(panZoom, 0);
+ border = VisualTreeHelper.GetChild(grid, 0) as Border;
+
+ if (border != null)
+ {
+ border.ManipulationStarted += Border_ManipulationStarted;
+ border.ManipulationDelta += Border_ManipulationDelta;
+ border.ManipulationCompleted += Border_ManipulationCompleted;
+ border.DoubleTap += Border_DoubleTap;
+ border.Tap += Border_Tap;
+ border.Hold += Border_Hold;
+ border.MouseLeftButtonDown += Border_MouseLeftButtonDown;
+ }
+
+ _browser.LoadCompleted += Browser_LoadCompleted;
+
+ }
+
+
+
+
+ void ParseViewportMeta()
+ {
+ string metaScript = "(function() { return document.querySelector('meta[name=viewport]').content; })()";
+
+ try
+ {
+ string metaContent = _browser.InvokeScript("eval", new string[] { metaScript }) as string;
+ string[] arr = metaContent.Split(new[] { ' ', ',', ';' }, StringSplitOptions.RemoveEmptyEntries);
+ Dictionary<string, string> metaDictionary = new Dictionary<string, string>();
+ foreach (string val in arr)
+ {
+ string[] keyVal = val.Split('=');
+ metaDictionary.Add(keyVal[0], keyVal[1]);
+ }
+
+ this.userScalable = false; // reset to default
+ if (metaDictionary.ContainsKey("user-scalable"))
+ {
+ this.userScalable = metaDictionary["user-scalable"] == "yes";
+ }
+
+ this.maxScale = 2.0;// reset to default
+ if (metaDictionary.ContainsKey("maximum-scale"))
+ {
+ this.maxScale = double.Parse(metaDictionary["maximum-scale"]);
+ }
+
+ this.minScale = 0.5;// reset to default
+ if (metaDictionary.ContainsKey("minimum-scale"))
+ {
+ this.minScale = double.Parse(metaDictionary["minimum-scale"]);
+ }
+ }
+ catch (Exception)
+ {
+
+ }
+ }
+
+ void Browser_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
+ {
+ ParseViewportMeta();
+
+ try
+ {
+ _browser.InvokeScript("execScript", MinifiedMouseScript);
+ }
+ catch (Exception)
+ {
+ Debug.WriteLine("BrowserHelper Failed to install mouse script in WebBrowser");
+ }
+ }
+
+ bool InvokeSimulatedMouseEvent(string eventName, Point pos)
+ {
+ bool bCancelled = false;
+ try
+ {
+ string strCancelled = _browser.InvokeScript("onNativeMouseEvent", new string[] { eventName, pos.X.ToString(), pos.Y.ToString() }) as string;
+ if (bool.TryParse(strCancelled, out bCancelled))
+ {
+ return bCancelled;
+ }
+ }
+ catch (Exception)
+ {
+ // script error
+ }
+
+ return bCancelled;
+ }
+
+ #region Hold
+
+ void Border_Hold(object sender, GestureEventArgs e)
+ {
+ //Debug.WriteLine("Border_Hold");
+ e.Handled = true;
+ }
+
+ #endregion
+
+ #region DoubleTap
+
+ void Border_DoubleTap(object sender, GestureEventArgs e)
+ {
+ //Debug.WriteLine("Border_DoubleTap");
+ e.Handled = true;
+ }
+
+ #endregion
+
+ #region Tap
+
+ void Border_Tap(object sender, GestureEventArgs e)
+ {
+ // prevents generating duplicated mouse events
+ // firstMouseMove == FALSE means we already handled this situation and generated mouse events
+ e.Handled = !this.firstMouseMove;
+ }
+ #endregion
+
+ #region MouseEvents
+
+ void Border_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
+ {
+ //Debug.WriteLine("Border_MouseLeftButtonDown");
+ border.MouseMove += new MouseEventHandler(Border_MouseMove);
+ border.MouseLeftButtonUp += new MouseButtonEventHandler(Border_MouseLeftButtonUp);
+
+ this.mouseDownPos = e.GetPosition(_browser);
+ // don't fire the down event until we know if this is a 'move' or not
+ firstMouseMove = true;
+ }
+ //
+ void Border_MouseMove(object sender, MouseEventArgs e)
+ {
+ //Debug.WriteLine("Border_MouseMove");
+ Point pos = e.GetPosition(_browser);
+ // only the return value from the first mouse move event should be used to determine if scrolling is prevented.
+ if (firstMouseMove)
+ {
+ // even for simple tap there are situations where ui control generates move with some little delta value
+ // we should avoid such situations allowing to browser control generate native js mousedown/up/click events
+ if (Math.Abs(pos.X - mouseDownPos.X) + Math.Abs(pos.Y - mouseDownPos.Y) <= MouseMoveDeltaThreshold)
+ {
+ return;
+ }
+
+ InvokeSimulatedMouseEvent("mousedown", pos);
+ firstMouseMove = false;
+ ScrollDisabled = InvokeSimulatedMouseEvent("mousemove", pos);
+ }
+ else
+ {
+ InvokeSimulatedMouseEvent("mousemove", pos);
+ }
+
+ }
+
+ void Border_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
+ {
+ //Debug.WriteLine("Border_MouseLeftButtonUp");
+ border.MouseMove -= new MouseEventHandler(Border_MouseMove);
+ border.MouseLeftButtonUp -= new MouseButtonEventHandler(Border_MouseLeftButtonUp);
+ // if firstMouseMove is false, then we have sent our simulated mousedown, so we should also send a matching mouseup
+ if (!firstMouseMove)
+ {
+ Point pos = e.GetPosition(_browser);
+ e.Handled = InvokeSimulatedMouseEvent("mouseup", pos);
+ }
+ ScrollDisabled = false;
+ }
+
+
+ #endregion
+
+ #region ManipulationEvents
+
+ void Border_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
+ {
+ //Debug.WriteLine("Border_ManipulationStarted");
+
+ if (ScrollDisabled)
+ {
+ e.Handled = true;
+ e.Complete();
+ }
+ }
+
+ private void Border_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
+ {
+ //Debug.WriteLine("Border_ManipulationDelta");
+ // optionally suppress zoom
+ if ((ScrollDisabled || !userScalable) && (e.DeltaManipulation.Scale.X != 0.0 || e.DeltaManipulation.Scale.Y != 0.0))
+ {
+ e.Handled = true;
+ e.Complete();
+ }
+ // optionally suppress scrolling
+ if (ScrollDisabled && (e.DeltaManipulation.Translation.X != 0.0 || e.DeltaManipulation.Translation.Y != 0.0))
+ {
+ e.Handled = true;
+ e.Complete();
+ }
+ }
+
+ private void Border_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
+ {
+ //Debug.WriteLine("Border_ManipulationCompleted");
+ // suppress zoom
+ if (!userScalable && e.FinalVelocities != null)
+ {
+ if (e.FinalVelocities.ExpansionVelocity.X != 0.0 ||
+ e.FinalVelocities.ExpansionVelocity.Y != 0.0)
+ {
+ e.Handled = true;
+ }
+ }
+ }
+
+
+ #endregion
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/cordovalib/CommandFactory.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordovalib/CommandFactory.cs b/lib/cordova-wp7/templates/standalone/cordovalib/CommandFactory.cs
new file mode 100644
index 0000000..893ce80
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/cordovalib/CommandFactory.cs
@@ -0,0 +1,112 @@
+/*
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+using System;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using System.Collections.Generic;
+using WPCordovaClassLib.Cordova.Commands;
+using System.Reflection;
+using System.Diagnostics;
+
+namespace WPCordovaClassLib.Cordova
+{
+ /// <summary>
+ /// Provides functionality to create phone gap command by name.
+ /// </summary>
+ public static class CommandFactory
+ {
+ /// <summary>
+ /// Represents predefined namespace name for custom plugins
+ /// </summary>
+ private static readonly string CustomPluginNamespacePrefix = "Cordova.Extension.Commands.";
+
+ private static readonly string BaseCommandNamespacePrefix = "WPCordovaClassLib.Cordova.Commands.";
+
+ /// <summary>
+ /// Cache instantiated commands in a map.
+ /// </summary>
+
+ private static Dictionary<string, BaseCommand> commandMap = new Dictionary<string, BaseCommand>();
+
+ /// <summary>
+ /// Creates command using command class name. Returns null for unknown commands.
+ /// </summary>
+ /// <param name="service">Command class name, for example Device or Notification</param>
+ /// <returns>Command class instance or null</returns>
+ public static BaseCommand CreateByServiceName(string service)
+ {
+
+ if (string.IsNullOrEmpty(service))
+ {
+ throw new ArgumentNullException("service", "service to create can't be null");
+ }
+
+ if (!commandMap.ContainsKey(service))
+ {
+
+ Type t = Type.GetType(BaseCommandNamespacePrefix + service);
+
+ // custom plugin could be defined in own namespace and assembly
+ if (t == null)
+ {
+ string serviceFullName = service.Contains(".") ? service : CustomPluginNamespacePrefix + service;
+
+ foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
+ {
+ // in this case service name represents full type name including namespace
+ t = a.GetType(serviceFullName);
+
+ if (t == null) // try the Commands Namespace
+ {
+ t = a.GetType(BaseCommandNamespacePrefix + service);
+ }
+
+ if (t != null)
+ {
+ break;
+ }
+ }
+
+ }
+
+ // unknown command, still didn't find it
+ if (t == null)
+ {
+ Debug.WriteLine("Unable to locate command :: " + service);
+ return null;
+ }
+
+ commandMap[service] = Activator.CreateInstance(t) as BaseCommand;
+ }
+
+ return commandMap[service];
+ }
+
+ public static void ResetAllCommands()
+ {
+ foreach (BaseCommand bc in commandMap.Values)
+ {
+ bc.OnReset();
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/cordovalib/Commands/BaseCommand.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordovalib/Commands/BaseCommand.cs b/lib/cordova-wp7/templates/standalone/cordovalib/Commands/BaseCommand.cs
new file mode 100644
index 0000000..ac1d2d6
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/cordovalib/Commands/BaseCommand.cs
@@ -0,0 +1,187 @@
+/*
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+using System;
+using System.Reflection;
+using Microsoft.Phone.Shell;
+using System.Diagnostics;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+ public abstract class BaseCommand : IDisposable
+ {
+ /*
+ * All commands + plugins must extend BaseCommand, because they are dealt with as BaseCommands in CordovaView.xaml.cs
+ *
+ **/
+
+ public event EventHandler<PluginResult> OnCommandResult;
+
+ public event EventHandler<ScriptCallback> OnCustomScript;
+
+ public string CurrentCommandCallbackId { get; set; }
+
+ public BaseCommand()
+ {
+ ResultHandlers = new Dictionary<string, EventHandler<PluginResult>>();
+ PhoneApplicationService service = PhoneApplicationService.Current;
+ service.Activated += this.OnResume;
+ service.Deactivated += this.OnPause;
+ }
+
+ protected Dictionary<string, EventHandler<PluginResult>> ResultHandlers;
+ public void AddResultHandler(string callbackId, EventHandler<PluginResult> handler)
+ {
+ ResultHandlers.Add(callbackId, handler);
+ }
+ public bool RemoveResultHandler(string callbackId)
+ {
+ return ResultHandlers.Remove(callbackId);
+ }
+
+ /*
+ * InvokeMethodNamed will call the named method of a BaseCommand subclass if it exists and pass the variable arguments list along.
+ **/
+
+ public object InvokeMethodNamed(string callbackId, string methodName, params object[] args)
+ {
+ //Debug.WriteLine(string.Format("InvokeMethodNamed:{0} callbackId:{1}",methodName,callbackId));
+ this.CurrentCommandCallbackId = callbackId;
+ return InvokeMethodNamed(methodName, args);
+ }
+
+ public object InvokeMethodNamed(string methodName, params object[] args)
+ {
+ MethodInfo mInfo = this.GetType().GetMethod(methodName);
+
+ if (mInfo != null)
+ {
+ // every function handles DispatchCommandResult by itself
+ return mInfo.Invoke(this, args);
+ }
+
+ // actually methodName could refer to a property
+ if (args == null || args.Length == 0 ||
+ (args.Length == 1 && "undefined".Equals(args[0])))
+ {
+ PropertyInfo pInfo = this.GetType().GetProperty(methodName);
+ if (pInfo != null)
+ {
+ object res = pInfo.GetValue(this, null);
+
+ DispatchCommandResult(new PluginResult(PluginResult.Status.OK, res));
+
+ return res;
+ }
+ }
+
+ throw new MissingMethodException(methodName);
+
+ }
+
+ [Obsolete]
+ public void InvokeCustomScript(ScriptCallback script, bool removeHandler)
+ {
+ if (this.OnCustomScript != null)
+ {
+ this.OnCustomScript(this, script);
+ if (removeHandler)
+ {
+ this.OnCustomScript = null;
+ }
+ }
+ }
+
+ public void DispatchCommandResult()
+ {
+ this.DispatchCommandResult(new PluginResult(PluginResult.Status.NO_RESULT));
+ }
+
+ public void DispatchCommandResult(PluginResult result, string callbackId = "")
+ {
+ if (!string.IsNullOrEmpty(callbackId))
+ {
+ result.CallbackId = callbackId;
+ }
+ else
+ {
+ result.CallbackId = this.CurrentCommandCallbackId;
+ }
+
+ if (ResultHandlers.ContainsKey(result.CallbackId))
+ {
+ ResultHandlers[result.CallbackId](this, result);
+ }
+ else if (this.OnCommandResult != null)
+ {
+ OnCommandResult(this, result);
+ }
+ else
+ {
+ Debug.WriteLine("Failed to locate callback for id : " + result.CallbackId);
+ }
+
+ if (!result.KeepCallback)
+ {
+ this.Dispose();
+ }
+
+ }
+
+
+ /// <summary>
+ /// Occurs when the application is being deactivated.
+ /// </summary>
+ public virtual void OnReset() {}
+
+ /// <summary>
+ /// Occurs when the application is being loaded, and the config.xml has an autoload entry
+ /// </summary>
+ public virtual void OnInit() {}
+
+
+ /// <summary>
+ /// Occurs when the application is being deactivated.
+ /// </summary>
+ public virtual void OnPause(object sender, DeactivatedEventArgs e) {}
+
+ /// <summary>
+ /// Occurs when the application is being made active after previously being put
+ /// into a dormant state or tombstoned.
+ /// </summary>
+ public virtual void OnResume(object sender, Microsoft.Phone.Shell.ActivatedEventArgs e) {}
+
+ public void Dispose()
+ {
+ PhoneApplicationService service = PhoneApplicationService.Current;
+ service.Activated -= this.OnResume;
+ service.Deactivated -= this.OnPause;
+ this.OnCommandResult = null;
+ }
+
+ public static string GetBaseURL()
+ {
+#if CORDOVA_CLASSLIB
+ return "/WPCordovaClassLib;component/";
+#else
+ return "./";
+#endif
+ }
+ }
+
+
+
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/cordovalib/ConfigHandler.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/cordovalib/ConfigHandler.cs b/lib/cordova-wp7/templates/standalone/cordovalib/ConfigHandler.cs
new file mode 100644
index 0000000..d90e9b5
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/cordovalib/ConfigHandler.cs
@@ -0,0 +1,249 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Windows;
+using System.Windows.Resources;
+using System.Xml.Linq;
+
+namespace WPCordovaClassLib.CordovaLib
+{
+ class ConfigHandler
+ {
+ protected List<string> AllowedPlugins;
+ protected List<string> AllowedDomains;
+ protected Dictionary<string, string> Preferences;
+
+ protected bool AllowAllDomains = false;
+ protected bool AllowAllPlugins = false;
+
+ public ConfigHandler()
+ {
+ AllowedPlugins = new List<string>();
+ AllowedDomains = new List<string>();
+ Preferences = new Dictionary<string, string>();
+ }
+
+ public string GetPreference(string key)
+ {
+ return Preferences[key];
+ }
+
+/*
+ - (BOOL)URLIsAllowed:(NSURL*)url
+{
+ if (self.expandedWhitelist == nil) {
+ return NO;
+ }
+
+ if (self.allowAll) {
+ return YES;
+ }
+
+ // iterate through settings ExternalHosts, check for equality
+ NSEnumerator* enumerator = [self.expandedWhitelist objectEnumerator];
+ id regex = nil;
+ NSString* urlHost = [url host];
+
+ // if the url host IS found in the whitelist, load it in the app (however UIWebViewNavigationTypeOther kicks it out to Safari)
+ // if the url host IS NOT found in the whitelist, we do nothing
+ while (regex = [enumerator nextObject]) {
+ NSPredicate* regex_test = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
+
+ if ([regex_test evaluateWithObject:urlHost] == YES) {
+ // if it matches at least one rule, return
+ return YES;
+ }
+ }
+
+ NSLog(@"%@", [self errorStringForURL:url]);
+ // if we got here, the url host is not in the white-list, do nothing
+ return NO;
+}*/
+ protected static string[] AllowedSchemes = {"http","https","ftp","ftps"};
+ protected bool SchemeIsAllowed(string scheme)
+ {
+ return AllowedSchemes.Contains(scheme);
+ }
+
+ protected string PathAndQuery(Uri uri)
+ {
+ string result = uri.LocalPath;
+ if (uri.Query.Length > 0)
+ {
+ result += uri.Query;
+ }
+ return result;
+ }
+
+ protected void AddWhiteListEntry(string origin, bool allowSubdomains)
+ {
+
+ if (origin == "*")
+ {
+ AllowAllDomains = true;
+ }
+
+ if (AllowAllDomains)
+ {
+ return;
+ }
+
+ string hostMatchingRegex = "";
+ string hostName;
+
+ try
+ {
+
+ Uri uri = new Uri(origin.Replace("*", "replaced-text"), UriKind.Absolute);
+
+ string tempHostName = uri.Host.Replace("replaced-text", "*");
+ //if (uri.HostNameType == UriHostNameType.Dns){}
+ // starts with wildcard match - we make the first '.' optional (so '*.org.apache.cordova' will match 'org.apache.cordova')
+ if (tempHostName.StartsWith("*."))
+ { //"(\\s{0}|*.)"
+ hostName = @"\w*.*" + tempHostName.Substring(2).Replace(".", @"\.").Replace("*", @"\w*");
+ }
+ else
+ {
+ hostName = tempHostName.Replace(".", @"\.").Replace("*", @"\w*");
+ }
+
+ // "^https?://"
+ hostMatchingRegex = uri.Scheme + "://" + hostName + PathAndQuery(uri);
+ //Debug.WriteLine("Adding regex :: " + hostMatchingRegex);
+ AllowedDomains.Add(hostMatchingRegex);
+
+ }
+ catch (Exception)
+ {
+ Debug.WriteLine("Invalid Whitelist entry (probably missing the protocol):: " + origin);
+ }
+
+ }
+
+ /**
+
+ An access request is granted for a given URI if there exists an item inside the access-request list such that:
+
+ - The URI's scheme component is the same as scheme; and
+ - if subdomains is false or if the URI's host component is not a domain name (as defined in [RFC1034]), the URI's host component is the same as host; or
+ - if subdomains is true, the URI's host component is either the same as host, or is a subdomain of host (as defined in [RFC1034]); and
+ - the URI's port component is the same as port.
+
+ **/
+
+ public bool URLIsAllowed(string url)
+ {
+ // easy case first
+ if (AllowAllDomains )
+ {
+ return true;
+ }
+ else
+ {
+ // start simple
+ Uri uri = new Uri(url,UriKind.RelativeOrAbsolute);
+ if (uri.IsAbsoluteUri)
+ {
+ if (this.SchemeIsAllowed(uri.Scheme))
+ {
+ // additional test because our pattern will always have a trailing '/'
+ string matchUrl = url;
+ if (PathAndQuery(uri) == "/")
+ {
+ matchUrl = url + "/";
+ }
+ foreach (string pattern in AllowedDomains)
+ {
+ if (Regex.IsMatch(matchUrl, pattern))
+ {
+ // make sure it is at the start, and not part of the query string
+ // special case :: http://some.other.domain/page.html?x=1&g=http://build.apache.org/
+ if ( Regex.IsMatch(uri.Scheme + "://" + uri.Host + "/", pattern) ||
+ (!Regex.IsMatch(PathAndQuery(uri), pattern)))
+ {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public bool IsPluginAllowed(string key)
+ {
+ return AllowAllPlugins || AllowedPlugins.Contains(key);
+ }
+
+
+ public void LoadAppPackageConfig()
+ {
+ StreamResourceInfo streamInfo = Application.GetResourceStream(new Uri("config.xml", UriKind.Relative));
+
+ if (streamInfo != null)
+ {
+ StreamReader sr = new StreamReader(streamInfo.Stream);
+ //This will Read Keys Collection for the xml file
+ XDocument document = XDocument.Parse(sr.ReadToEnd());
+
+ var plugins = from results in document.Descendants("plugin")
+ select new { name = (string)results.Attribute("name") };
+
+
+ foreach (var plugin in plugins)
+ {
+ Debug.WriteLine("plugin " + plugin.name);
+ if (plugin.name == "*")
+ {
+ AllowAllPlugins = true;
+ break;
+ }
+ else
+ {
+ AllowedPlugins.Add(plugin.name);
+ }
+ }
+
+ var preferences = from results in document.Descendants("preference")
+ select new
+ {
+ name = (string)results.Attribute("name"),
+ value = (string)results.Attribute("value")
+ };
+
+ foreach (var pref in preferences)
+ {
+ Debug.WriteLine("pref" + pref.name + ", " + pref.value);
+ }
+
+ var accessList = from results in document.Descendants("access")
+ select new
+ {
+ origin = (string)results.Attribute("origin"),
+ subdomains = (string)results.Attribute("subdomains") == "true"
+ };
+
+ foreach (var accessElem in accessList)
+ {
+ AddWhiteListEntry(accessElem.origin, accessElem.subdomains);
+ }
+ }
+ else
+ {
+ // no config.xml, allow all
+ AllowAllDomains = true;
+ AllowAllPlugins = true;
+ }
+ }
+ }
+}
[09/37] Add WP7 and WP8 platform files.
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/contacts.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/contacts.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/contacts.html
new file mode 100644
index 0000000..2575e13
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/contacts.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <title>Cordova: Contacts API Specs</title>
+
+ <meta name="viewport" content="width=device-width, height=device-height, user-scalable=yes, initial-scale=1.0;" />
+ <!-- Load jasmine -->
+ <link href="../jasmine.css" rel="stylesheet"/>
+ <script type="text/javascript" src="../jasmine.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporterHelpers.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporter.js"></script>
+ <script type="text/javascript" src="../html/ReporterView.js"></script>
+ <script type="text/javascript" src="../html/SpecView.js"></script>
+ <script type="text/javascript" src="../html/SuiteView.js"></script>
+ <script type="text/javascript" src="../html/TrivialReporter.js"></script>
+
+ <!-- Source -->
+ <script type="text/javascript" src="../../cordova.js"></script>
+
+ <!-- Load Test Runner -->
+ <script type="text/javascript" src="../test-runner.js"></script>
+
+ <!-- Tests -->
+ <script type="text/javascript" src="../tests/contacts.tests.js"></script>
+
+ <script type="text/javascript">
+ document.addEventListener('deviceready', function () {
+ var jasmineEnv = jasmine.getEnv();
+ jasmineEnv.updateInterval = 1000;
+
+ var htmlReporter = new jasmine.HtmlReporter();
+
+ jasmineEnv.addReporter(htmlReporter);
+
+ jasmineEnv.specFilter = function(spec) {
+ return htmlReporter.specFilter(spec);
+ };
+
+ jasmineEnv.execute();
+ }, false);
+ </script>
+</head>
+
+<body>
+ <a href="javascript:" class="backBtn" onclick="backHome();">Back</a>
+</body>
+</html>
+
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/datauri.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/datauri.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/datauri.html
new file mode 100644
index 0000000..3d5ffd2
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/datauri.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<!--
+
+ 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.
+
+-->
+<html>
+
+<head>
+ <title>Cordova: Data URI tests</title>
+
+ <meta name="viewport" content="width=device-width, height=device-height, user-scalable=yes, initial-scale=1.0;" />
+ <!-- Load jasmine -->
+ <link href="../jasmine.css" rel="stylesheet"/>
+ <script type="text/javascript" src="../jasmine.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporterHelpers.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporter.js"></script>
+ <script type="text/javascript" src="../html/ReporterView.js"></script>
+ <script type="text/javascript" src="../html/SpecView.js"></script>
+ <script type="text/javascript" src="../html/SuiteView.js"></script>
+ <script type="text/javascript" src="../html/TrivialReporter.js"></script>
+
+ <!-- Source -->
+ <script type="text/javascript" src="../../cordova.js"></script>
+
+ <!-- Load Test Runner -->
+ <script type="text/javascript" src="../test-runner.js"></script>
+
+ <!-- Tests -->
+ <script type="text/javascript" src="../tests/datauri.tests.js"></script>
+
+ <script type="text/javascript">
+ document.addEventListener('deviceready', function () {
+ var jasmineEnv = jasmine.getEnv();
+ jasmineEnv.updateInterval = 1000;
+
+ var htmlReporter = new jasmine.HtmlReporter();
+
+ jasmineEnv.addReporter(htmlReporter);
+
+ jasmineEnv.specFilter = function(spec) {
+ return htmlReporter.specFilter(spec);
+ };
+
+ jasmineEnv.execute();
+ }, false);
+ </script>
+</head>
+
+<body>
+ <a href="javascript:" class="backBtn" onclick="backHome();">Back</a>
+</body>
+</html>
+
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/device.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/device.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/device.html
new file mode 100644
index 0000000..ed25d81
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/device.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <title>Cordova: Device API Specs</title>
+
+ <meta name="viewport" content="width=device-width, height=device-height, user-scalable=yes, initial-scale=1.0;" />
+ <!-- Load jasmine -->
+ <link href="../jasmine.css" rel="stylesheet"/>
+ <script type="text/javascript" src="../jasmine.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporterHelpers.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporter.js"></script>
+ <script type="text/javascript" src="../html/ReporterView.js"></script>
+ <script type="text/javascript" src="../html/SpecView.js"></script>
+ <script type="text/javascript" src="../html/SuiteView.js"></script>
+ <script type="text/javascript" src="../html/TrivialReporter.js"></script>
+
+ <!-- Source -->
+ <script type="text/javascript" src="../../cordova.js"></script>
+
+ <!-- Load Test Runner -->
+ <script type="text/javascript" src="../test-runner.js"></script>
+
+ <!-- Tests -->
+ <script type="text/javascript" src="../tests/device.tests.js"></script>
+
+ <script type="text/javascript">
+ document.addEventListener('deviceready', function () {
+ var jasmineEnv = jasmine.getEnv();
+ jasmineEnv.updateInterval = 1000;
+
+ var htmlReporter = new jasmine.HtmlReporter();
+
+ jasmineEnv.addReporter(htmlReporter);
+
+ jasmineEnv.specFilter = function(spec) {
+ return htmlReporter.specFilter(spec);
+ };
+
+ jasmineEnv.execute();
+ }, false);
+ </script>
+</head>
+
+<body>
+ <a href="javascript:" class="backBtn" onclick="backHome();">Back</a>
+</body>
+</html>
+
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/file.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/file.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/file.html
new file mode 100644
index 0000000..d9e21ca
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/file.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Cordova: File API Specs</title>
+
+ <meta name="viewport" content="width=device-width, height=device-height, user-scalable=yes, initial-scale=1.0;" />
+ <!-- Load jasmine -->
+ <link href="../jasmine.css" rel="stylesheet"/>
+ <script type="text/javascript" src="../jasmine.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporterHelpers.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporter.js"></script>
+ <script type="text/javascript" src="../html/ReporterView.js"></script>
+ <script type="text/javascript" src="../html/SpecView.js"></script>
+ <script type="text/javascript" src="../html/SuiteView.js"></script>
+ <script type="text/javascript" src="../html/TrivialReporter.js"></script>
+
+ <!-- Source -->
+ <script type="text/javascript" src="../../cordova.js"></script>
+
+ <!-- Load Test Runner -->
+ <script type="text/javascript" src="../test-runner.js"></script>
+
+ <!-- Tests -->
+ <script type="text/javascript" src="../tests/file.tests.js"></script>
+
+ <script type="text/javascript">
+ var root, temp_root, persistent_root;
+
+ document.addEventListener('deviceready', function () {
+ // one-time retrieval of the root file system entry
+ var onError = function(e) {
+ console.log('[ERROR] Problem setting up root filesystem for test running! Error to follow.');
+ console.log(JSON.stringify(e));
+ };
+
+ window.requestFileSystem(LocalFileSystem.PERSISTENT, 0,
+ function(fileSystem) {
+ console.log('File API test Init: Setting PERSISTENT FS.');
+ root = fileSystem.root; // set in file.tests.js
+ persistent_root = root;
+
+ // Once root is set up, fire off tests
+ var jasmineEnv = jasmine.getEnv();
+ jasmineEnv.updateInterval = 1000;
+
+ var htmlReporter = new jasmine.HtmlReporter();
+
+ jasmineEnv.addReporter(htmlReporter);
+
+ jasmineEnv.specFilter = function(spec) {
+ return htmlReporter.specFilter(spec);
+ };
+
+ jasmineEnv.execute();
+ }, onError);
+ window.requestFileSystem(LocalFileSystem.TEMPORARY, 0,
+ function(fileSystem) {
+ console.log('File API test Init: Setting TEMPORARY FS.');
+ temp_root = fileSystem.root; // set in file.tests.js
+ }, onError);
+ }, false);
+ </script>
+</head>
+
+<body>
+ <a href="javascript:" class="backBtn" onclick="backHome();">Back</a>
+</body>
+</html>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/filetransfer.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/filetransfer.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/filetransfer.html
new file mode 100644
index 0000000..0fde591
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/filetransfer.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Cordova: File API Specs</title>
+
+ <meta name="viewport" content="width=device-width, height=device-height, user-scalable=yes, initial-scale=1.0;" />
+ <!-- Load jasmine -->
+ <link href="../jasmine.css" rel="stylesheet"/>
+ <script type="text/javascript" src="../jasmine.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporterHelpers.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporter.js"></script>
+ <script type="text/javascript" src="../html/ReporterView.js"></script>
+ <script type="text/javascript" src="../html/SpecView.js"></script>
+ <script type="text/javascript" src="../html/SuiteView.js"></script>
+ <script type="text/javascript" src="../html/TrivialReporter.js"></script>
+
+ <!-- Source -->
+ <script type="text/javascript" src="../../cordova.js"></script>
+
+ <!-- Load Test Runner -->
+ <script type="text/javascript" src="../test-runner.js"></script>
+
+ <!-- Tests -->
+ <script type="text/javascript" src="../tests/filetransfer.tests.js"></script>
+
+ <script type="text/javascript">
+ var root, temp_root, persistent_root;
+
+ document.addEventListener('deviceready', function () {
+ // one-time retrieval of the root file system entry
+ var onError = function(e) {
+ console.log('[ERROR] Problem setting up root filesystem for test running! Error to follow.');
+ console.log(JSON.stringify(e));
+ };
+
+ window.requestFileSystem(LocalFileSystem.PERSISTENT, 0,
+ function(fileSystem) {
+ console.log('File API test Init: Setting PERSISTENT FS.');
+ root = fileSystem.root; // set in file.tests.js
+ persistent_root = root;
+
+ // Once root is set up, fire off tests
+ var jasmineEnv = jasmine.getEnv();
+ jasmineEnv.updateInterval = 1000;
+
+ var htmlReporter = new jasmine.HtmlReporter();
+
+ jasmineEnv.addReporter(htmlReporter);
+
+ jasmineEnv.specFilter = function(spec) {
+ return htmlReporter.specFilter(spec);
+ };
+
+ jasmineEnv.execute();
+ }, onError);
+ window.requestFileSystem(LocalFileSystem.TEMPORARY, 0,
+ function(fileSystem) {
+ console.log('File API test Init: Setting TEMPORARY FS.');
+ temp_root = fileSystem.root; // set in file.tests.js
+ }, onError);
+ }, false);
+ </script>
+</head>
+
+<body>
+ <a href="javascript:" class="backBtn" onclick="backHome();">Back</a>
+</body>
+</html>
+
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/geolocation.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/geolocation.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/geolocation.html
new file mode 100644
index 0000000..578c6f4
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/geolocation.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <title>Cordova: Geolocation API Specs</title>
+
+ <meta name="viewport" content="width=device-width, height=device-height, user-scalable=yes, initial-scale=1.0;" />
+ <!-- Load jasmine -->
+ <link href="../jasmine.css" rel="stylesheet"/>
+ <script type="text/javascript" src="../jasmine.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporterHelpers.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporter.js"></script>
+ <script type="text/javascript" src="../html/ReporterView.js"></script>
+ <script type="text/javascript" src="../html/SpecView.js"></script>
+ <script type="text/javascript" src="../html/SuiteView.js"></script>
+ <script type="text/javascript" src="../html/TrivialReporter.js"></script>
+
+ <!-- Source -->
+ <script type="text/javascript" src="../../cordova.js"></script>
+
+ <!-- Load Test Runner -->
+ <script type="text/javascript" src="../test-runner.js"></script>
+
+ <!-- Tests -->
+ <script type="text/javascript" src="../tests/geolocation.tests.js"></script>
+
+ <script type="text/javascript">
+ document.addEventListener('deviceready', function () {
+ var jasmineEnv = jasmine.getEnv();
+ jasmineEnv.updateInterval = 1000;
+
+ var htmlReporter = new jasmine.HtmlReporter();
+
+ jasmineEnv.addReporter(htmlReporter);
+
+ jasmineEnv.specFilter = function(spec) {
+ return htmlReporter.specFilter(spec);
+ };
+
+ jasmineEnv.execute();
+ }, false);
+ </script>
+</head>
+
+<body>
+ <a href="javascript:" class="backBtn" onclick="backHome();">Back</a>
+</body>
+</html>
+
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/globalization.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/globalization.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/globalization.html
new file mode 100644
index 0000000..79c5acd
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/globalization.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<!--
+
+ 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.
+
+-->
+
+
+<html>
+<head>
+ <title>Cordova: Globalization API Specs</title>
+
+ <meta name="viewport" content="width=device-width, height=device-height, user-scalable=yes, initial-scale=1.0;" />
+
+ <!-- Load jasmine -->
+ <link href="../jasmine.css" rel="stylesheet"/>
+ <script type="text/javascript" src="../jasmine.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporterHelpers.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporter.js"></script>
+ <script type="text/javascript" src="../html/ReporterView.js"></script>
+ <script type="text/javascript" src="../html/SpecView.js"></script>
+ <script type="text/javascript" src="../html/SuiteView.js"></script>
+ <script type="text/javascript" src="../html/TrivialReporter.js"></script>
+
+ <!-- Source -->
+ <script type="text/javascript" src="../../cordova.js"></script>
+
+ <!-- Load Test Runner -->
+ <script type="text/javascript" src="../test-runner.js"></script>
+
+ <!-- Tests -->
+ <script type="text/javascript" src="../tests/globalization.tests.js"></script>
+
+ <script type="text/javascript">
+ document.addEventListener('deviceready', function () {
+ var jasmineEnv = jasmine.getEnv();
+ jasmineEnv.updateInterval = 1000;
+
+ var htmlReporter = new jasmine.HtmlReporter();
+
+ jasmineEnv.addReporter(htmlReporter);
+
+ jasmineEnv.specFilter = function(spec) {
+ return htmlReporter.specFilter(spec);
+ };
+
+ jasmineEnv.execute();
+ }, false);
+ </script>
+</head>
+
+<body>
+ <a href="javascript:" class="backBtn" onclick="backHome();">Back</a>
+</body>
+</html>
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/media.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/media.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/media.html
new file mode 100644
index 0000000..48d9e2d
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/media.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <title>Cordova: Media API Specs</title>
+
+ <meta name="viewport" content="width=device-width, height=device-height, user-scalable=yes, initial-scale=1.0;" />
+ <!-- Load jasmine -->
+ <link href="../jasmine.css" rel="stylesheet"/>
+ <script type="text/javascript" src="../jasmine.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporterHelpers.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporter.js"></script>
+ <script type="text/javascript" src="../html/ReporterView.js"></script>
+ <script type="text/javascript" src="../html/SpecView.js"></script>
+ <script type="text/javascript" src="../html/SuiteView.js"></script>
+ <script type="text/javascript" src="../html/TrivialReporter.js"></script>
+
+ <!-- Source -->
+ <script type="text/javascript" src="../../cordova.js"></script>
+
+ <!-- Load Test Runner -->
+ <script type="text/javascript" src="../test-runner.js"></script>
+
+ <!-- Tests -->
+ <script type="text/javascript" src="../tests/media.tests.js"></script>
+
+ <script type="text/javascript">
+ document.addEventListener('deviceready', function () {
+ var jasmineEnv = jasmine.getEnv();
+ jasmineEnv.updateInterval = 1000;
+
+ var htmlReporter = new jasmine.HtmlReporter();
+
+ jasmineEnv.addReporter(htmlReporter);
+
+ jasmineEnv.specFilter = function(spec) {
+ return htmlReporter.specFilter(spec);
+ };
+
+ jasmineEnv.execute();
+ }, false);
+ </script>
+</head>
+
+<body>
+ <a href="javascript:" class="backBtn" onclick="backHome();">Back</a>
+</body>
+</html>
+
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/network.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/network.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/network.html
new file mode 100644
index 0000000..627320c
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/network.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <title>Cordova: Network API Specs</title>
+
+ <meta name="viewport" content="width=device-width, height=device-height, user-scalable=yes, initial-scale=1.0;" />
+ <!-- Load jasmine -->
+ <link href="../jasmine.css" rel="stylesheet"/>
+ <script type="text/javascript" src="../jasmine.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporterHelpers.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporter.js"></script>
+ <script type="text/javascript" src="../html/ReporterView.js"></script>
+ <script type="text/javascript" src="../html/SpecView.js"></script>
+ <script type="text/javascript" src="../html/SuiteView.js"></script>
+ <script type="text/javascript" src="../html/TrivialReporter.js"></script>
+
+ <!-- Source -->
+ <script type="text/javascript" src="../../cordova.js"></script>
+
+ <!-- Load Test Runner -->
+ <script type="text/javascript" src="../test-runner.js"></script>
+
+ <!-- Tests -->
+ <script type="text/javascript" src="../tests/network.tests.js"></script>
+
+ <script type="text/javascript">
+ document.addEventListener('deviceready', function () {
+ var jasmineEnv = jasmine.getEnv();
+ jasmineEnv.updateInterval = 1000;
+
+ var htmlReporter = new jasmine.HtmlReporter();
+
+ jasmineEnv.addReporter(htmlReporter);
+
+ jasmineEnv.specFilter = function(spec) {
+ return htmlReporter.specFilter(spec);
+ };
+
+ jasmineEnv.execute();
+ }, false);
+ </script>
+</head>
+
+<body>
+ <a href="javascript:" class="backBtn" onclick="backHome();">Back</a>
+</body>
+</html>
+
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/notification.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/notification.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/notification.html
new file mode 100644
index 0000000..ef9d4a2
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/notification.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <title>Cordova: Notification API Specs</title>
+
+ <meta name="viewport" content="width=device-width, height=device-height, user-scalable=yes, initial-scale=1.0;" />
+ <!-- Load jasmine -->
+ <link href="../jasmine.css" rel="stylesheet"/>
+ <script type="text/javascript" src="../jasmine.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporterHelpers.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporter.js"></script>
+ <script type="text/javascript" src="../html/ReporterView.js"></script>
+ <script type="text/javascript" src="../html/SpecView.js"></script>
+ <script type="text/javascript" src="../html/SuiteView.js"></script>
+ <script type="text/javascript" src="../html/TrivialReporter.js"></script>
+
+ <!-- Source -->
+ <script type="text/javascript" src="../../cordova.js"></script>
+
+ <!-- Load Test Runner -->
+ <script type="text/javascript" src="../test-runner.js"></script>
+
+ <!-- Tests -->
+ <script type="text/javascript" src="../tests/notification.tests.js"></script>
+
+ <script type="text/javascript">
+ document.addEventListener('deviceready', function () {
+ var jasmineEnv = jasmine.getEnv();
+ jasmineEnv.updateInterval = 1000;
+
+ var htmlReporter = new jasmine.HtmlReporter();
+
+ jasmineEnv.addReporter(htmlReporter);
+
+ jasmineEnv.specFilter = function(spec) {
+ return htmlReporter.specFilter(spec);
+ };
+
+ jasmineEnv.execute();
+ }, false);
+ </script>
+</head>
+
+<body>
+ <a href="javascript:" class="backBtn" onclick="backHome();">Back</a>
+</body>
+</html>
+
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/platform.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/platform.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/platform.html
new file mode 100644
index 0000000..884ba45
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/platform.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <title>Cordova: Platform API Specs</title>
+
+ <meta name="viewport" content="width=device-width, height=device-height, user-scalable=yes, initial-scale=1.0;" />
+ <!-- Load jasmine -->
+ <link href="../jasmine.css" rel="stylesheet"/>
+ <script type="text/javascript" src="../jasmine.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporterHelpers.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporter.js"></script>
+ <script type="text/javascript" src="../html/ReporterView.js"></script>
+ <script type="text/javascript" src="../html/SpecView.js"></script>
+ <script type="text/javascript" src="../html/SuiteView.js"></script>
+ <script type="text/javascript" src="../html/TrivialReporter.js"></script>
+
+ <!-- Source -->
+ <script type="text/javascript" src="../../cordova.js"></script>
+
+ <!-- Load Test Runner -->
+ <script type="text/javascript" src="../test-runner.js"></script>
+
+ <!-- Tests -->
+ <script type="text/javascript" src="../tests/platform.tests.js"></script>
+
+ <script type="text/javascript">
+ document.addEventListener('deviceready', function () {
+ var jasmineEnv = jasmine.getEnv();
+ jasmineEnv.updateInterval = 1000;
+
+ var htmlReporter = new jasmine.HtmlReporter();
+
+ jasmineEnv.addReporter(htmlReporter);
+
+ jasmineEnv.specFilter = function(spec) {
+ return htmlReporter.specFilter(spec);
+ };
+
+ jasmineEnv.execute();
+ }, false);
+ </script>
+</head>
+
+<body>
+ <a href="javascript:" class="backBtn" onclick="backHome();">Back</a>
+</body>
+</html>
+
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/storage.html
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/storage.html b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/storage.html
new file mode 100644
index 0000000..eb0703b
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/pages/storage.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <title>Cordova: Storage API Specs</title>
+
+ <meta name="viewport" content="width=device-width, height=device-height, user-scalable=yes, initial-scale=1.0;" />
+ <!-- Load jasmine -->
+ <link href="../jasmine.css" rel="stylesheet"/>
+ <script type="text/javascript" src="../jasmine.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporterHelpers.js"></script>
+ <script type="text/javascript" src="../html/HtmlReporter.js"></script>
+ <script type="text/javascript" src="../html/ReporterView.js"></script>
+ <script type="text/javascript" src="../html/SpecView.js"></script>
+ <script type="text/javascript" src="../html/SuiteView.js"></script>
+ <script type="text/javascript" src="../html/TrivialReporter.js"></script>
+
+ <!-- Source -->
+ <script type="text/javascript" src="../../cordova.js"></script>
+
+ <!-- Load Test Runner -->
+ <script type="text/javascript" src="../test-runner.js"></script>
+
+ <!-- Tests -->
+ <script type="text/javascript" src="../tests/storage.tests.js"></script>
+
+ <script type="text/javascript">
+ document.addEventListener('deviceready', function () {
+ var jasmineEnv = jasmine.getEnv();
+ jasmineEnv.updateInterval = 1000;
+
+ var htmlReporter = new jasmine.HtmlReporter();
+
+ jasmineEnv.addReporter(htmlReporter);
+
+ jasmineEnv.specFilter = function(spec) {
+ return htmlReporter.specFilter(spec);
+ };
+
+ jasmineEnv.execute();
+ }, false);
+ </script>
+</head>
+
+<body>
+ <a href="javascript:" class="backBtn" onclick="backHome();">Back</a>
+</body>
+</html>
+
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/test-runner.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/test-runner.js b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/test-runner.js
new file mode 100644
index 0000000..e85578c
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/test-runner.js
@@ -0,0 +1,41 @@
+if (window.sessionStorage != null) {
+ window.sessionStorage.clear();
+}
+
+// Timeout is 2 seconds to allow physical devices enough
+// time to query the response. This is important for some
+// Android devices.
+var Tests = function() {};
+Tests.TEST_TIMEOUT = 7500;
+
+// Creates a spy that will fail if called.
+function createDoNotCallSpy(name, opt_extraMessage) {
+ return jasmine.createSpy().andCallFake(function() {
+ var errorMessage = name + ' should not have been called.';
+ if (arguments.length) {
+ errorMessage += ' Got args: ' + JSON.stringify(arguments);
+ }
+ if (opt_extraMessage) {
+ errorMessage += '\n' + opt_extraMessage;
+ }
+ expect(false).toBe(true, errorMessage);
+ });
+}
+
+// Waits for any of the given spys to be called.
+// Last param may be a custom timeout duration.
+function waitsForAny() {
+ var spys = [].slice.call(arguments);
+ var timeout = Tests.TEST_TIMEOUT;
+ if (typeof spys[spys.length - 1] == 'number') {
+ timeout = spys.pop();
+ }
+ waitsFor(function() {
+ for (var i = 0; i < spys.length; ++i) {
+ if (spys[i].wasCalled) {
+ return true;
+ }
+ }
+ return false;
+ }, "Expecting callbacks to be called.", timeout);
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/accelerometer.tests.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/accelerometer.tests.js b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/accelerometer.tests.js
new file mode 100644
index 0000000..0b61ac3
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/accelerometer.tests.js
@@ -0,0 +1,193 @@
+describe('Accelerometer (navigator.accelerometer)', function () {
+ it("should exist", function () {
+ expect(navigator.accelerometer).toBeDefined();
+ });
+
+ describe("getCurrentAcceleration", function() {
+ it("should exist", function() {
+ expect(typeof navigator.accelerometer.getCurrentAcceleration).toBeDefined();
+ expect(typeof navigator.accelerometer.getCurrentAcceleration == 'function').toBe(true);
+ });
+
+ it("success callback should be called with an Acceleration object", function() {
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a).toBeDefined();
+ expect(a.x).toBeDefined();
+ expect(typeof a.x == 'number').toBe(true);
+ expect(a.y).toBeDefined();
+ expect(typeof a.y == 'number').toBe(true);
+ expect(a.z).toBeDefined();
+ expect(typeof a.z == 'number').toBe(true);
+ expect(a.timestamp).toBeDefined();
+ expect(typeof a.timestamp).toBe('number');
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ navigator.accelerometer.getCurrentAcceleration(win, fail);
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+
+ it("success callback Acceleration object should have (reasonable) values for x, y and z expressed in m/s^2", function() {
+ var reasonableThreshold = 15;
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a.x).toBeLessThan(reasonableThreshold);
+ expect(a.x).toBeGreaterThan(reasonableThreshold * -1);
+ expect(a.y).toBeLessThan(reasonableThreshold);
+ expect(a.y).toBeGreaterThan(reasonableThreshold * -1);
+ expect(a.z).toBeLessThan(reasonableThreshold);
+ expect(a.z).toBeGreaterThan(reasonableThreshold * -1);
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ navigator.accelerometer.getCurrentAcceleration(win, fail);
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+
+ it("success callback Acceleration object should return a recent timestamp", function() {
+ var veryRecently = (new Date()).getTime();
+ // Need to check that dates returned are not vastly greater than a recent time stamp.
+ // In case the timestamps returned are ridiculously high
+ var reasonableTimeLimit = veryRecently + 5000; // 5 seconds from now
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a.timestamp).toBeGreaterThan(veryRecently);
+ expect(a.timestamp).toBeLessThan(reasonableTimeLimit);
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ navigator.accelerometer.getCurrentAcceleration(win, fail);
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe("watchAcceleration", function() {
+ var id;
+
+ afterEach(function() {
+ navigator.accelerometer.clearWatch(id);
+ });
+
+ it("should exist", function() {
+ expect(navigator.accelerometer.watchAcceleration).toBeDefined();
+ expect(typeof navigator.accelerometer.watchAcceleration == 'function').toBe(true);
+ });
+ it("success callback should be called with an Acceleration object", function() {
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a).toBeDefined();
+ expect(a.x).toBeDefined();
+ expect(typeof a.x == 'number').toBe(true);
+ expect(a.y).toBeDefined();
+ expect(typeof a.y == 'number').toBe(true);
+ expect(a.z).toBeDefined();
+ expect(typeof a.z == 'number').toBe(true);
+ expect(a.timestamp).toBeDefined();
+ expect(typeof a.timestamp).toBe('number');
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ id = navigator.accelerometer.watchAcceleration(win, fail, {frequency:500});
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+
+ it("success callback Acceleration object should have (reasonable) values for x, y and z expressed in m/s^2", function() {
+ var reasonableThreshold = 15;
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a.x).toBeLessThan(reasonableThreshold);
+ expect(a.x).toBeGreaterThan(reasonableThreshold * -1);
+ expect(a.y).toBeLessThan(reasonableThreshold);
+ expect(a.y).toBeGreaterThan(reasonableThreshold * -1);
+ expect(a.z).toBeLessThan(reasonableThreshold);
+ expect(a.z).toBeGreaterThan(reasonableThreshold * -1);
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ id = navigator.accelerometer.watchAcceleration(win, fail, {frequency:500});
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+
+ it("success callback Acceleration object should return a recent timestamp", function() {
+ var veryRecently = (new Date()).getTime();
+ // Need to check that dates returned are not vastly greater than a recent time stamp.
+ // In case the timestamps returned are ridiculously high
+ var reasonableTimeLimit = veryRecently + 5000; // 5 seconds from now
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a.timestamp).toBeGreaterThan(veryRecently);
+ expect(a.timestamp).toBeLessThan(reasonableTimeLimit);
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ id = navigator.accelerometer.watchAcceleration(win, fail, {frequency:500});
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe("clearWatch", function() {
+ it("should exist", function() {
+ expect(navigator.accelerometer.clearWatch).toBeDefined();
+ expect(typeof navigator.accelerometer.clearWatch == 'function').toBe(true);
+ });
+
+ it("should clear an existing watch", function() {
+ var id,
+ win = jasmine.createSpy();
+
+ runs(function() {
+ id = navigator.accelerometer.watchAcceleration(win, function() {}, {frequency:100});
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function() {
+ win.reset();
+ navigator.accelerometer.clearWatch(id);
+ });
+
+ waits(201);
+
+ runs(function() {
+ expect(win).not.toHaveBeenCalled();
+ });
+ });
+ });
+});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/battery.tests.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/battery.tests.js b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/battery.tests.js
new file mode 100644
index 0000000..7bb25af
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/battery.tests.js
@@ -0,0 +1,5 @@
+describe('Battery (navigator.battery)', function () {;
+ it("should exist", function() {
+ expect(navigator.battery).toBeDefined();
+ });
+});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/bridge.tests.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/bridge.tests.js b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/bridge.tests.js
new file mode 100644
index 0000000..ec363d7
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/bridge.tests.js
@@ -0,0 +1,128 @@
+/*
+ *
+ * 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.
+ *
+*/
+
+/* This test requires some extra code to run, because we want benchmark results */
+
+/*
+ It's never going to be OVER 9000
+ http://youtu.be/SiMHTK15Pik
+*/
+var FENCEPOST = 9000;
+
+var exec = cordova.require('cordova/exec'),
+ echo = cordova.require('cordova/plugin/echo'),
+ startTime,
+ endTime,
+ callCount,
+ durationMs = 1000,
+ asyncEcho,
+ useSetTimeout,
+ payloadSize,
+ payload;
+
+var vanillaWin = function(result) {
+ callCount++;
+ if (result != payload) {
+ console.log('Wrong echo data!');
+ }
+ var elapsedMs = new Date - startTime;
+ if (elapsedMs < durationMs) {
+ if (useSetTimeout) {
+ setTimeout(echoMessage, 0);
+ } else {
+ echoMessage();
+ }
+ } else {
+ endTime = +new Date;
+ }
+}
+
+var reset = function()
+{
+ endTime = null;
+ callCount = 0;
+ useSetTimeout = false;
+ payloadSize = 5;
+ callsPerSecond = 0;
+}
+
+var echoMessage = function()
+{
+ echo(vanillaWin, fail, payload, asyncEcho);
+}
+
+var fail = function() {
+ expect(false).toBe(true);
+};
+
+function createTestCase(jsToNativeModeName, nativeToJsModeName, testAsyncEcho) {
+ it(jsToNativeModeName + '+' + nativeToJsModeName, function() {
+ expect(exec.jsToNativeModes[jsToNativeModeName]).toBeDefined();
+ expect(exec.nativeToJsModes[nativeToJsModeName]).toBeDefined();
+ reset();
+ payload = new Array(payloadSize * 10 + 1).join('012\n\n 6789');
+ asyncEcho = testAsyncEcho;
+ exec.setJsToNativeBridgeMode(exec.jsToNativeModes[jsToNativeModeName]);
+ exec.setNativeToJsBridgeMode(exec.nativeToJsModes[nativeToJsModeName]);
+
+ waits(300);
+ runs(function() {
+ startTime = +new Date,
+ echoMessage();
+ });
+ waitsFor(function() { return endTime; }, "never completed", durationMs * 2);
+ runs(function() {
+ var elapsedMs = endTime - startTime,
+ callsPerSecond = callCount * 1000 / elapsedMs;
+ expect(callsPerSecond).toBeGreaterThan(FENCEPOST);
+ });
+ });
+};
+
+// Wait so that the first benchmark doesn't have contention.
+describe('Wait for page to load.', function() {
+ it('waiting...', function() {
+ waits(1000);
+ });
+});
+
+// Before running on Android, set the following constants in NativeToJsMessagingBridge:
+// - ENABLE_LOCATION_CHANGE_EXEC_MODE = true
+// - DISABLE_EXEC_CHAINING = true
+describe('Android bridge with', function() {
+ var testAsyncEcho = false;
+ createTestCase('PROMPT', 'POLLING', testAsyncEcho);
+ createTestCase('JS_OBJECT', 'POLLING', testAsyncEcho);
+ createTestCase('LOCATION_CHANGE', 'ONLINE_EVENT', testAsyncEcho);
+
+ testAsyncEcho = true;
+ createTestCase('PROMPT', 'POLLING', testAsyncEcho);
+ createTestCase('PROMPT', 'HANGING_GET', testAsyncEcho);
+ createTestCase('PROMPT', 'LOAD_URL', testAsyncEcho);
+ createTestCase('PROMPT', 'ONLINE_EVENT', testAsyncEcho);
+ createTestCase('PROMPT', 'PRIVATE_API', testAsyncEcho);
+
+ createTestCase('JS_OBJECT', 'POLLING', testAsyncEcho);
+ createTestCase('JS_OBJECT', 'HANGING_GET', testAsyncEcho);
+ createTestCase('JS_OBJECT', 'LOAD_URL', testAsyncEcho);
+ createTestCase('JS_OBJECT', 'ONLINE_EVENT', testAsyncEcho);
+ createTestCase('JS_OBJECT', 'PRIVATE_API', testAsyncEcho);
+});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/camera.tests.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/camera.tests.js b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/camera.tests.js
new file mode 100644
index 0000000..9b6b04c
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/camera.tests.js
@@ -0,0 +1,47 @@
+describe('Camera (navigator.camera)', function () {
+ it("should exist", function() {
+ expect(navigator.camera).toBeDefined();
+ });
+
+ it("should contain a getPicture function", function() {
+ expect(navigator.camera.getPicture).toBeDefined();
+ expect(typeof navigator.camera.getPicture == 'function').toBe(true);
+ });
+});
+
+describe('Camera Constants (window.Camera + navigator.camera)', function () {
+ it("window.Camera should exist", function() {
+ expect(window.Camera).toBeDefined();
+ });
+
+ it("should contain two DestinationType constants", function() {
+ expect(Camera.DestinationType.DATA_URL).toBe(0);
+ expect(Camera.DestinationType.FILE_URI).toBe(1);
+ expect(navigator.camera.DestinationType.DATA_URL).toBe(0);
+ expect(navigator.camera.DestinationType.FILE_URI).toBe(1);
+ });
+
+ it("should contain two EncodingType constants", function() {
+ expect(Camera.EncodingType.JPEG).toBe(0);
+ expect(Camera.EncodingType.PNG).toBe(1);
+ expect(navigator.camera.EncodingType.JPEG).toBe(0);
+ expect(navigator.camera.EncodingType.PNG).toBe(1);
+ });
+
+ it("should contain three MediaType constants", function() {
+ expect(Camera.MediaType.PICTURE).toBe(0);
+ expect(Camera.MediaType.VIDEO).toBe(1);
+ expect(Camera.MediaType.ALLMEDIA).toBe(2);
+ expect(navigator.camera.MediaType.PICTURE).toBe(0);
+ expect(navigator.camera.MediaType.VIDEO).toBe(1);
+ expect(navigator.camera.MediaType.ALLMEDIA).toBe(2);
+ });
+ it("should contain three PictureSourceType constants", function() {
+ expect(Camera.PictureSourceType.PHOTOLIBRARY).toBe(0);
+ expect(Camera.PictureSourceType.CAMERA).toBe(1);
+ expect(Camera.PictureSourceType.SAVEDPHOTOALBUM).toBe(2);
+ expect(navigator.camera.PictureSourceType.PHOTOLIBRARY).toBe(0);
+ expect(navigator.camera.PictureSourceType.CAMERA).toBe(1);
+ expect(navigator.camera.PictureSourceType.SAVEDPHOTOALBUM).toBe(2);
+ });
+});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/capture.tests.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/capture.tests.js b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/capture.tests.js
new file mode 100644
index 0000000..bffced8
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/capture.tests.js
@@ -0,0 +1,95 @@
+describe('Capture (navigator.device.capture)', function () {
+ it("should exist", function() {
+ expect(navigator.device).toBeDefined();
+ expect(navigator.device.capture).toBeDefined();
+ });
+
+ it("should have the correct properties ", function() {
+ expect(navigator.device.capture.supportedAudioModes).toBeDefined();
+ expect(navigator.device.capture.supportedImageModes).toBeDefined();
+ expect(navigator.device.capture.supportedVideoModes).toBeDefined();
+ });
+
+ it("should contain a captureAudio function", function() {
+ expect(navigator.device.capture.captureAudio).toBeDefined();
+ expect(typeof navigator.device.capture.captureAudio == 'function').toBe(true);
+ });
+
+ it("should contain a captureImage function", function() {
+ expect(navigator.device.capture.captureImage).toBeDefined();
+ expect(typeof navigator.device.capture.captureImage == 'function').toBe(true);
+ });
+
+ it("should contain a captureVideo function", function() {
+ expect(navigator.device.capture.captureVideo).toBeDefined();
+ expect(typeof navigator.device.capture.captureVideo == 'function').toBe(true);
+ });
+
+ describe('CaptureAudioOptions', function () {
+ it("CaptureAudioOptions constructor should exist", function() {
+ var options = new CaptureAudioOptions();
+ expect(options).toBeDefined();
+ expect(options.limit).toBeDefined();
+ expect(options.duration).toBeDefined();
+ expect(options.mode).toBeDefined();
+ });
+ });
+
+ describe('CaptureImageOptions', function () {
+ it("CaptureImageOptions constructor should exist", function() {
+ var options = new CaptureImageOptions();
+ expect(options).toBeDefined();
+ expect(options.limit).toBeDefined();
+ expect(options.mode).toBeDefined();
+ });
+ });
+
+ describe('CaptureVideoOptions', function () {
+ it("CaptureVideoOptions constructor should exist", function() {
+ var options = new CaptureVideoOptions();
+ expect(options).toBeDefined();
+ expect(options.limit).toBeDefined();
+ expect(options.duration).toBeDefined();
+ expect(options.mode).toBeDefined();
+ });
+ });
+
+ describe('CaptureError interface', function () {
+ it("CaptureError constants should be defined", function() {
+ expect(CaptureError.CAPTURE_INTERNAL_ERR).toBe(0);
+ expect(CaptureError.CAPTURE_APPLICATION_BUSY).toBe(1);
+ expect(CaptureError.CAPTURE_INVALID_ARGUMENT).toBe(2);
+ expect(CaptureError.CAPTURE_NO_MEDIA_FILES).toBe(3);
+ });
+
+ it("CaptureError properties should exist", function() {
+ var error = new CaptureError();
+ expect(error).toBeDefined();
+ expect(error.code).toBeDefined();
+ });
+ });
+
+ describe('MediaFileData', function () {
+ it("MediaFileData constructor should exist", function() {
+ var fileData = new MediaFileData();
+ expect(fileData).toBeDefined();
+ expect(fileData.bitrate).toBeDefined();
+ expect(fileData.codecs).toBeDefined();
+ expect(fileData.duration).toBeDefined();
+ expect(fileData.height).toBeDefined();
+ expect(fileData.width).toBeDefined();
+ });
+ });
+
+ describe('MediaFile', function () {
+ it("MediaFile constructor should exist", function() {
+ var fileData = new MediaFile();
+ expect(fileData).toBeDefined();
+ expect(fileData.name).toBeDefined();
+ expect(fileData.fullPath).toBeDefined();
+ expect(fileData.type).toBeDefined();
+ expect(fileData.lastModifiedDate).toBeDefined();
+ expect(fileData.size).toBeDefined();
+ });
+ });
+});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/compass.tests.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/compass.tests.js b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/compass.tests.js
new file mode 100644
index 0000000..a16ec0e
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/compass.tests.js
@@ -0,0 +1,76 @@
+describe('Compass (navigator.compass)', function () {
+ it("should exist", function() {
+ expect(navigator.compass).toBeDefined();
+ });
+
+ it("should contain a getCurrentHeading function", function() {
+ expect(navigator.compass.getCurrentHeading).toBeDefined();
+ expect(typeof navigator.compass.getCurrentHeading == 'function').toBe(true);
+ });
+
+ it("getCurrentHeading success callback should be called with a Heading object", function() {
+ var win = jasmine.createSpy().andCallFake(function(a) {
+ expect(a instanceof CompassHeading).toBe(true);
+ expect(a.magneticHeading).toBeDefined();
+ expect(typeof a.magneticHeading == 'number').toBe(true);
+ expect(a.trueHeading).not.toBe(undefined);
+ expect(typeof a.trueHeading == 'number' || a.trueHeading === null).toBe(true);
+ expect(a.headingAccuracy).not.toBe(undefined);
+ expect(typeof a.headingAccuracy == 'number' || a.headingAccuracy === null).toBe(true);
+ expect(typeof a.timestamp == 'number').toBe(true);
+ }),
+ fail = jasmine.createSpy();
+
+ runs(function () {
+ navigator.compass.getCurrentHeading(win, fail);
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "success callback never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ expect(win).toHaveBeenCalled();
+ });
+ });
+
+ it("should contain a watchHeading function", function() {
+ expect(navigator.compass.watchHeading).toBeDefined();
+ expect(typeof navigator.compass.watchHeading == 'function').toBe(true);
+ });
+
+ it("should contain a clearWatch function", function() {
+ expect(navigator.compass.clearWatch).toBeDefined();
+ expect(typeof navigator.compass.clearWatch == 'function').toBe(true);
+ });
+
+ describe('Compass Constants (window.CompassError)', function () {
+ it("should exist", function() {
+ expect(window.CompassError).toBeDefined();
+ expect(window.CompassError.COMPASS_INTERNAL_ERR).toBe(0);
+ expect(window.CompassError.COMPASS_NOT_SUPPORTED).toBe(20);
+ });
+ });
+
+ describe('Compass Heading model (CompassHeading)', function () {
+ it("should exist", function() {
+ expect(CompassHeading).toBeDefined();
+ });
+
+ it("should be able to create a new CompassHeading instance with no parameters", function() {
+ var h = new CompassHeading();
+ expect(h.magneticHeading).toBeDefined();
+ expect(h.trueHeading).toBeDefined();
+ expect(h.headingAccuracy).toBeDefined();
+ expect(typeof h.timestamp == 'number').toBe(true);
+ });
+
+ it("should be able to creat a new CompassHeading instance with parameters", function() {
+ var h = new CompassHeading(1,2,3,4);
+ expect(h.magneticHeading).toBe(1);
+ expect(h.trueHeading).toBe(2);
+ expect(h.headingAccuracy).toBe(3);
+ expect(h.timestamp.valueOf()).toBe(4);
+ expect(typeof h.timestamp == 'number').toBe(true);
+ });
+ });
+});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/contacts.tests.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/contacts.tests.js b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/contacts.tests.js
new file mode 100644
index 0000000..a5f41a5
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/contacts.tests.js
@@ -0,0 +1,451 @@
+// global to store a contact so it doesn't have to be created or retrieved multiple times
+// all of the setup/teardown test methods can reference the following variables to make sure to do the right cleanup
+var gContactObj = null;
+var gContactId = null;
+
+var removeContact = function(){
+ if (gContactObj) {
+ gContactObj.remove(function(){},function(){
+ console.log("[CONTACTS ERROR]: removeContact cleanup method failed to clean up test artifacts.");
+ });
+ gContactObj = null;
+ }
+};
+
+describe("Contacts (navigator.contacts)", function () {
+ it("should exist", function() {
+ expect(navigator.contacts).toBeDefined();
+ });
+
+ it("should contain a find function", function() {
+ expect(navigator.contacts.find).toBeDefined();
+ expect(typeof navigator.contacts.find).toBe('function');
+ });
+
+ describe("find method", function() {
+ it("success callback should be called with an array", function() {
+ var win = jasmine.createSpy().andCallFake(function(result) {
+ expect(result).toBeDefined();
+ expect(result instanceof Array).toBe(true);
+ }),
+ fail = jasmine.createSpy(),
+ obj = new ContactFindOptions();
+
+ runs(function () {
+ obj.filter="";
+ obj.multiple=true;
+ navigator.contacts.find(["displayName", "name", "phoneNumbers", "emails"], win, fail, obj);
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "win never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+
+ it("should throw an exception if success callback is empty", function() {
+ var fail = function() {};
+ var obj = new ContactFindOptions();
+ obj.filter="";
+ obj.multiple=true;
+
+ expect(function () {
+ navigator.contacts.find(["displayName", "name", "emails", "phoneNumbers"], null, fail, obj);
+ }).toThrow();
+ });
+
+ it("error callback should be called when no fields are specified", function() {
+ var win = jasmine.createSpy(),
+ fail = jasmine.createSpy(function(result) {
+ expect(result).toBeDefined();
+ expect(result.code).toBe(ContactError.INVALID_ARGUMENT_ERROR);
+ }),
+ obj = new ContactFindOptions();
+
+ runs(function () {
+ obj.filter="";
+ obj.multiple=true;
+ navigator.contacts.find([], win, fail, obj);
+ });
+
+ waitsFor(function () { return fail.wasCalled; }, Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(win).not.toHaveBeenCalled();
+ expect(fail).toHaveBeenCalled();
+ });
+ });
+
+ describe("with newly-created contact", function () {
+
+ afterEach(removeContact);
+
+ it("should be able to find a contact by name", function() {
+ var foundName = jasmine.createSpy().andCallFake(function(result) {
+ var bFound = false;
+ try {
+ for (var i=0; i < result.length; i++) {
+ if (result[i].name.familyName == "Delete") {
+ bFound = true;
+ break;
+ }
+ }
+ } catch(e) {
+ return false;
+ }
+ return bFound;
+ }),
+ fail = jasmine.createSpy(),
+ test = jasmine.createSpy().andCallFake(function(savedContact) {
+ console.log('in test');
+ // update so contact will get removed
+ gContactObj = savedContact;
+ // ----
+ // Find asserts
+ // ---
+ var findWin = jasmine.createSpy().andCallFake(function(object) {
+ console.log('in findwin');
+ expect(object instanceof Array).toBe(true);
+ expect(object.length >= 1).toBe(true);
+ expect(foundName(object)).toBe(true);
+ }),
+ findFail = jasmine.createSpy(),
+ obj = new ContactFindOptions();
+
+ obj.filter="Delete";
+ obj.multiple=true;
+
+ runs(function () {
+ navigator.contacts.find(["displayName", "name", "phoneNumbers", "emails"], findWin, findFail, obj);
+ });
+
+ waitsFor(function () { return foundName.wasCalled; }, "foundName not done", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(findFail).not.toHaveBeenCalled();
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+
+ runs(function () {
+ gContactObj = new Contact();
+ gContactObj.name = new ContactName();
+ gContactObj.name.familyName = "Delete";
+ gContactObj.save(test, fail);
+ });
+
+ waitsFor(function () { return test.wasCalled; }, "test not done", Tests.TEST_TIMEOUT);
+ });
+ });
+ });
+
+ describe('create method', function() {
+
+ it("should exist", function() {
+ expect(navigator.contacts.create).toBeDefined();
+ expect(typeof navigator.contacts.create).toBe('function');
+ });
+
+ it("should return a Contact object", function() {
+ var bDay = new Date(1976, 7,4);
+ var obj = navigator.contacts.create({"displayName": "test name", "gender": "male", "note": "my note", "name": {"formatted": "Mr. Test Name"}, "emails": [{"value": "here@there.com"}, {"value": "there@here.com"}], "birthday": bDay});
+
+ expect(obj).toBeDefined();
+ expect(obj.displayName).toBe('test name');
+ expect(obj.note).toBe('my note');
+ expect(obj.name.formatted).toBe('Mr. Test Name');
+ expect(obj.emails.length).toBe(2);
+ expect(obj.emails[0].value).toBe('here@there.com');
+ expect(obj.emails[1].value).toBe('there@here.com');
+ expect(obj.nickname).toBe(null);
+ expect(obj.birthday).toBe(bDay);
+ });
+ });
+
+ describe("Contact object", function () {
+ it("should be able to create instance", function() {
+ var contact = new Contact("a", "b", new ContactName("a", "b", "c", "d", "e", "f"), "c", [], [], [], [], [], "f", "i",
+ [], [], []);
+ expect(contact).toBeDefined();
+ expect(contact.id).toBe("a");
+ expect(contact.displayName).toBe("b");
+ expect(contact.name.formatted).toBe("a");
+ expect(contact.nickname).toBe("c");
+ expect(contact.phoneNumbers).toBeDefined();
+ expect(contact.emails).toBeDefined();
+ expect(contact.addresses).toBeDefined();
+ expect(contact.ims).toBeDefined();
+ expect(contact.organizations).toBeDefined();
+ expect(contact.birthday).toBe("f");
+ expect(contact.note).toBe("i");
+ expect(contact.photos).toBeDefined();
+ expect(contact.categories).toBeDefined();
+ expect(contact.urls).toBeDefined();
+ });
+
+ it("should be able to define a ContactName object", function() {
+ var contactName = new ContactName("Dr. First Last Jr.", "Last", "First", "Middle", "Dr.", "Jr.");
+ expect(contactName).toBeDefined();
+ expect(contactName.formatted).toBe("Dr. First Last Jr.");
+ expect(contactName.familyName).toBe("Last");
+ expect(contactName.givenName).toBe("First");
+ expect(contactName.middleName).toBe("Middle");
+ expect(contactName.honorificPrefix).toBe("Dr.");
+ expect(contactName.honorificSuffix).toBe("Jr.");
+ });
+
+ it("should be able to define a ContactField object", function() {
+ var contactField = new ContactField("home", "8005551212", true);
+ expect(contactField).toBeDefined();
+ expect(contactField.type).toBe("home");
+ expect(contactField.value).toBe("8005551212");
+ expect(contactField.pref).toBe(true);
+ });
+
+ it("ContactField object should coerce type and value properties to strings", function() {
+ var contactField = new ContactField(12345678, 12345678, true);
+ expect(contactField.type).toBe("12345678");
+ expect(contactField.value).toBe("12345678");
+ });
+
+ it("should be able to define a ContactAddress object", function() {
+ var contactAddress = new ContactAddress(true, "home", "a","b","c","d","e","f");
+ expect(contactAddress).toBeDefined();
+ expect(contactAddress.pref).toBe(true);
+ expect(contactAddress.type).toBe("home");
+ expect(contactAddress.formatted).toBe("a");
+ expect(contactAddress.streetAddress).toBe("b");
+ expect(contactAddress.locality).toBe("c");
+ expect(contactAddress.region).toBe("d");
+ expect(contactAddress.postalCode).toBe("e");
+ expect(contactAddress.country).toBe("f");
+ });
+
+ it("should be able to define a ContactOrganization object", function() {
+ var contactOrg = new ContactOrganization(true, "home", "a","b","c","d","e","f","g");
+ expect(contactOrg).toBeDefined();
+ expect(contactOrg.pref).toBe(true);
+ expect(contactOrg.type).toBe("home");
+ expect(contactOrg.name).toBe("a");
+ expect(contactOrg.department).toBe("b");
+ expect(contactOrg.title).toBe("c");
+ });
+
+ it("should be able to define a ContactFindOptions object", function() {
+ var contactFindOptions = new ContactFindOptions("a", true, "b");
+ expect(contactFindOptions).toBeDefined();
+ expect(contactFindOptions.filter).toBe("a");
+ expect(contactFindOptions.multiple).toBe(true);
+ });
+
+ it("should contain a clone function", function() {
+ var contact = new Contact();
+ expect(contact.clone).toBeDefined();
+ expect(typeof contact.clone).toBe('function');
+ });
+
+ it("clone function should make deep copy of Contact Object", function() {
+ var contact = new Contact();
+ contact.id=1;
+ contact.displayName="Test Name";
+ contact.nickname="Testy";
+ contact.gender="male";
+ contact.note="note to be cloned";
+ contact.name = new ContactName("Mr. Test Name");
+
+ var clonedContact = contact.clone();
+
+ expect(contact.id).toBe(1);
+ expect(clonedContact.id).toBe(null);
+ expect(clonedContact.displayName).toBe(contact.displayName);
+ expect(clonedContact.nickname).toBe(contact.nickname);
+ expect(clonedContact.gender).toBe(contact.gender);
+ expect(clonedContact.note).toBe(contact.note);
+ expect(clonedContact.name.formatted).toBe(contact.name.formatted);
+ expect(clonedContact.connected).toBe(contact.connected);
+ });
+
+ it("should contain a save function", function() {
+ var contact = new Contact();
+ expect(contact.save).toBeDefined();
+ expect(typeof contact.save).toBe('function');
+ });
+
+ it("should contain a remove function", function() {
+ var contact = new Contact();
+ expect(contact.remove).toBeDefined();
+ expect(typeof contact.remove).toBe('function');
+ });
+ });
+
+ describe('save method', function () {
+ it("should be able to save a contact", function() {
+ var bDay = new Date(1976, 6,4);
+ gContactObj = navigator.contacts.create({"gender": "male", "note": "my note", "name": {"familyName": "Delete", "givenName": "Test"}, "emails": [{"value": "here@there.com"}, {"value": "there@here.com"}], "birthday": bDay});
+
+ var saveSuccess = jasmine.createSpy().andCallFake(function(obj) {
+ expect(obj).toBeDefined();
+ expect(obj.note).toBe('my note');
+ expect(obj.name.familyName).toBe('Delete');
+ expect(obj.name.givenName).toBe('Test');
+ expect(obj.emails.length).toBe(2);
+ expect(obj.emails[0].value).toBe('here@there.com');
+ expect(obj.emails[1].value).toBe('there@here.com');
+ expect(obj.birthday.toDateString()).toBe(bDay.toDateString());
+ expect(obj.addresses).toBe(null);
+ // must store returned object in order to have id for update test below
+ gContactObj = obj;
+ }),
+ saveFail = jasmine.createSpy();
+
+ runs(function () {
+ gContactObj.save(saveSuccess, saveFail);
+ });
+
+ waitsFor(function () { return saveSuccess.wasCalled; }, "saveSuccess never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(saveFail).not.toHaveBeenCalled();
+ });
+ });
+ // HACK: there is a reliance between the previous and next test. This is bad form.
+ it("update a contact", function() {
+ expect(gContactObj).toBeDefined();
+
+ var bDay = new Date(1975, 5,4);
+ var noteText = "an UPDATED note";
+
+ var win = jasmine.createSpy().andCallFake(function(obj) {
+ expect(obj).toBeDefined();
+ expect(obj.id).toBe(gContactObj.id);
+ expect(obj.note).toBe(noteText);
+ expect(obj.birthday.toDateString()).toBe(bDay.toDateString());
+ expect(obj.emails.length).toBe(1);
+ expect(obj.emails[0].value).toBe('here@there.com');
+ removeContact(); // Clean up contact object
+ }), fail = jasmine.createSpy().andCallFake(removeContact);
+
+ runs(function () {
+ // remove an email
+ gContactObj.emails[1].value = "";
+ // change birthday
+ gContactObj.birthday = bDay;
+ // update note
+ gContactObj.note = noteText;
+ gContactObj.save(win, fail);
+ });
+
+ waitsFor(function () { return win.wasCalled; }, "saveSuccess never called", Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(fail).not.toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('Contact.remove method', function () {
+ afterEach(removeContact);
+
+ it("calling remove on a contact has an id of null should return ContactError.UNKNOWN_ERROR", function() {
+ var win = jasmine.createSpy();
+ var fail = jasmine.createSpy().andCallFake(function(result) {
+ expect(result.code).toBe(ContactError.UNKNOWN_ERROR);
+ });
+
+ runs(function () {
+ var rmContact = new Contact();
+ rmContact.remove(win, fail);
+ });
+
+ waitsFor(function () { return fail.wasCalled; }, Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(win).not.toHaveBeenCalled();
+ });
+ });
+
+ it("calling remove on a contact that does not exist should return ContactError.UNKNOWN_ERROR", function() {
+ var win = jasmine.createSpy();
+ var fail = jasmine.createSpy().andCallFake(function(result) {
+ expect(result.code).toBe(ContactError.UNKNOWN_ERROR);
+ });
+
+ runs(function () {
+ var rmContact = new Contact();
+ // this is a bit risky as some devices may have contact ids that large
+ var contact = new Contact("this string is supposed to be a unique identifier that will never show up on a device");
+ contact.remove(win, fail);
+ });
+
+ waitsFor(function () { return fail.wasCalled; }, Tests.TEST_TIMEOUT);
+
+ runs(function () {
+ expect(win).not.toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe("Round trip Contact tests (creating + save + delete + find).", function () {
+ afterEach(removeContact);
+
+ it("Creating, saving, finding a contact should work, removing it should work, after which we should not be able to find it, and we should not be able to delete it again.", function() {
+ var done = false;
+ runs(function () {
+ gContactObj = new Contact();
+ gContactObj.name = new ContactName();
+ gContactObj.name.familyName = "DeleteMe";
+ gContactObj.save(function(c_obj) {
+ var findWin = function(cs) {
+ expect(cs.length).toBe(1);
+ // update to have proper saved id
+ gContactObj = cs[0];
+ gContactObj.remove(function() {
+ var findWinAgain = function(seas) {
+ expect(seas.length).toBe(0);
+ gContactObj.remove(function() {
+ throw("success callback called after non-existent Contact object called remove(). Test failed.");
+ }, function(e) {
+ expect(e.code).toBe(ContactError.UNKNOWN_ERROR);
+ done = true;
+ });
+ };
+ var findFailAgain = function(e) {
+ throw("find error callback invoked after delete, test failed.");
+ };
+ var obj = new ContactFindOptions();
+ obj.filter="DeleteMe";
+ obj.multiple=true;
+ navigator.contacts.find(["displayName", "name", "phoneNumbers", "emails"], findWinAgain, findFailAgain, obj);
+ }, function(e) {
+ throw("Newly created contact's remove function invoked error callback. Test failed.");
+ });
+ };
+ var findFail = function(e) {
+ throw("Failure callback invoked in navigator.contacts.find call, test failed.");
+ };
+ var obj = new ContactFindOptions();
+ obj.filter="DeleteMe";
+ obj.multiple=true;
+ navigator.contacts.find(["displayName", "name", "phoneNumbers", "emails"], findWin, findFail, obj);
+ }, function(e) {
+ throw("Contact creation failed, error callback was invoked.");
+ });
+ });
+
+ waitsFor(function () { return done; }, Tests.TEST_TIMEOUT);
+ });
+ });
+
+ describe('ContactError interface', function () {
+ it("ContactError constants should be defined", function() {
+ expect(ContactError.UNKNOWN_ERROR).toBe(0);
+ expect(ContactError.INVALID_ARGUMENT_ERROR).toBe(1);
+ expect(ContactError.TIMEOUT_ERROR).toBe(2);
+ expect(ContactError.PENDING_OPERATION_ERROR).toBe(3);
+ expect(ContactError.IO_ERROR).toBe(4);
+ expect(ContactError.NOT_SUPPORTED_ERROR).toBe(5);
+ expect(ContactError.PERMISSION_DENIED_ERROR).toBe(20);
+ });
+ });
+});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/datauri.tests.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/datauri.tests.js b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/datauri.tests.js
new file mode 100644
index 0000000..2e54810
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/datauri.tests.js
@@ -0,0 +1,36 @@
+describe('data uris', function () {
+ it("should work with iframes", function() {
+ var gotFoo = false,
+ frame = document.createElement('iframe');
+ function onMessage(msg) {
+ gotFoo = gotFoo || msg.data == 'foo';
+ };
+
+ this.after(function() {
+ document.body.removeChild(frame);
+ window.removeEventListener('message', onMessage, false);
+ });
+
+ window.addEventListener('message', onMessage, false);
+ frame.src = 'data:text/html;charset=utf-8,%3Chtml%3E%3Cscript%3Eparent.postMessage%28%27foo%27%2C%27%2A%27%29%3C%2Fscript%3E%3C%2Fhtml%3E'
+ document.body.appendChild(frame);
+ waitsFor(function() {
+ return gotFoo;
+ }, 'iframe did not load.', 1000);
+ runs(function() {
+ expect(gotFoo).toBe(true);
+ });
+ });
+ it("should work with images", function() {
+ var img = new Image();
+ img.onload = jasmine.createSpy('onLoad');
+ img.onerror = jasmine.createSpy('onError');
+ img.src = 'data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7'
+ waitsFor(function() {
+ return img.onload.wasCalled || img.onerror.wasCalled;
+ }, 'image did not load or error', 1000);
+ runs(function() {
+ expect(img.onload).toHaveBeenCalled();
+ });
+ });
+});
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/device.tests.js
----------------------------------------------------------------------
diff --git a/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/device.tests.js b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/device.tests.js
new file mode 100644
index 0000000..cc322d6
--- /dev/null
+++ b/lib/cordova-wp8/tests/MobileSpecUnitTests/www/autotest/tests/device.tests.js
@@ -0,0 +1,34 @@
+describe('Device Information (window.device)', function () {
+ it("should exist", function() {
+ expect(window.device).toBeDefined();
+ });
+
+ it("should contain a platform specification that is a string", function() {
+ expect(window.device.platform).toBeDefined();
+ expect((new String(window.device.platform)).length > 0).toBe(true);
+ });
+
+ it("should contain a version specification that is a string", function() {
+ expect(window.device.version).toBeDefined();
+ expect((new String(window.device.version)).length > 0).toBe(true);
+ });
+
+ it("should contain a name specification that is a string", function() {
+ expect(window.device.name).toBeDefined();
+ expect((new String(window.device.name)).length > 0).toBe(true);
+ });
+
+ it("should contain a UUID specification that is a string or a number", function() {
+ expect(window.device.uuid).toBeDefined();
+ if (typeof window.device.uuid == 'string' || typeof window.device.uuid == 'object') {
+ expect((new String(window.device.uuid)).length > 0).toBe(true);
+ } else {
+ expect(window.device.uuid > 0).toBe(true);
+ }
+ });
+
+ it("should contain a cordova specification that is a string", function() {
+ expect(window.device.cordova).toBeDefined();
+ expect((new String(window.device.cordova)).length > 0).toBe(true);
+ });
+});
[35/37] Add Windows support to Android platform-scripts.
Posted by mw...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bed35f66/lib/cordova-android/framework/assets/js/cordova.android.js
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/assets/js/cordova.android.js b/lib/cordova-android/framework/assets/js/cordova.android.js
deleted file mode 100644
index ec1a2de..0000000
--- a/lib/cordova-android/framework/assets/js/cordova.android.js
+++ /dev/null
@@ -1,6836 +0,0 @@
-// Platform: android
-
-// commit cd29cf0f224ccf25e9d422a33fd02ef67d3a78f4
-
-// File generated at :: Thu Apr 25 2013 14:53:10 GMT-0700 (PDT)
-
-/*
- 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.
-*/
-
-;(function() {
-
-// file: lib/scripts/require.js
-
-var require,
- define;
-
-(function () {
- var modules = {};
- // Stack of moduleIds currently being built.
- var requireStack = [];
- // Map of module ID -> index into requireStack of modules currently being built.
- var inProgressModules = {};
-
- function build(module) {
- var factory = module.factory;
- module.exports = {};
- delete module.factory;
- factory(require, module.exports, module);
- return module.exports;
- }
-
- require = function (id) {
- if (!modules[id]) {
- throw "module " + id + " not found";
- } else if (id in inProgressModules) {
- var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id;
- throw "Cycle in require graph: " + cycle;
- }
- if (modules[id].factory) {
- try {
- inProgressModules[id] = requireStack.length;
- requireStack.push(id);
- return build(modules[id]);
- } finally {
- delete inProgressModules[id];
- requireStack.pop();
- }
- }
- return modules[id].exports;
- };
-
- define = function (id, factory) {
- if (modules[id]) {
- throw "module " + id + " already defined";
- }
-
- modules[id] = {
- id: id,
- factory: factory
- };
- };
-
- define.remove = function (id) {
- delete modules[id];
- };
-
- define.moduleMap = modules;
-})();
-
-//Export for use in node
-if (typeof module === "object" && typeof require === "function") {
- module.exports.require = require;
- module.exports.define = define;
-}
-
-// file: lib/cordova.js
-define("cordova", function(require, exports, module) {
-
-
-var channel = require('cordova/channel');
-
-/**
- * Listen for DOMContentLoaded and notify our channel subscribers.
- */
-document.addEventListener('DOMContentLoaded', function() {
- channel.onDOMContentLoaded.fire();
-}, false);
-if (document.readyState == 'complete' || document.readyState == 'interactive') {
- channel.onDOMContentLoaded.fire();
-}
-
-/**
- * Intercept calls to addEventListener + removeEventListener and handle deviceready,
- * resume, and pause events.
- */
-var m_document_addEventListener = document.addEventListener;
-var m_document_removeEventListener = document.removeEventListener;
-var m_window_addEventListener = window.addEventListener;
-var m_window_removeEventListener = window.removeEventListener;
-
-/**
- * Houses custom event handlers to intercept on document + window event listeners.
- */
-var documentEventHandlers = {},
- windowEventHandlers = {};
-
-document.addEventListener = function(evt, handler, capture) {
- var e = evt.toLowerCase();
- if (typeof documentEventHandlers[e] != 'undefined') {
- documentEventHandlers[e].subscribe(handler);
- } else {
- m_document_addEventListener.call(document, evt, handler, capture);
- }
-};
-
-window.addEventListener = function(evt, handler, capture) {
- var e = evt.toLowerCase();
- if (typeof windowEventHandlers[e] != 'undefined') {
- windowEventHandlers[e].subscribe(handler);
- } else {
- m_window_addEventListener.call(window, evt, handler, capture);
- }
-};
-
-document.removeEventListener = function(evt, handler, capture) {
- var e = evt.toLowerCase();
- // If unsubscribing from an event that is handled by a plugin
- if (typeof documentEventHandlers[e] != "undefined") {
- documentEventHandlers[e].unsubscribe(handler);
- } else {
- m_document_removeEventListener.call(document, evt, handler, capture);
- }
-};
-
-window.removeEventListener = function(evt, handler, capture) {
- var e = evt.toLowerCase();
- // If unsubscribing from an event that is handled by a plugin
- if (typeof windowEventHandlers[e] != "undefined") {
- windowEventHandlers[e].unsubscribe(handler);
- } else {
- m_window_removeEventListener.call(window, evt, handler, capture);
- }
-};
-
-function createEvent(type, data) {
- var event = document.createEvent('Events');
- event.initEvent(type, false, false);
- if (data) {
- for (var i in data) {
- if (data.hasOwnProperty(i)) {
- event[i] = data[i];
- }
- }
- }
- return event;
-}
-
-if(typeof window.console === "undefined") {
- window.console = {
- log:function(){}
- };
-}
-
-var cordova = {
- define:define,
- require:require,
- /**
- * Methods to add/remove your own addEventListener hijacking on document + window.
- */
- addWindowEventHandler:function(event) {
- return (windowEventHandlers[event] = channel.create(event));
- },
- addStickyDocumentEventHandler:function(event) {
- return (documentEventHandlers[event] = channel.createSticky(event));
- },
- addDocumentEventHandler:function(event) {
- return (documentEventHandlers[event] = channel.create(event));
- },
- removeWindowEventHandler:function(event) {
- delete windowEventHandlers[event];
- },
- removeDocumentEventHandler:function(event) {
- delete documentEventHandlers[event];
- },
- /**
- * Retrieve original event handlers that were replaced by Cordova
- *
- * @return object
- */
- getOriginalHandlers: function() {
- return {'document': {'addEventListener': m_document_addEventListener, 'removeEventListener': m_document_removeEventListener},
- 'window': {'addEventListener': m_window_addEventListener, 'removeEventListener': m_window_removeEventListener}};
- },
- /**
- * Method to fire event from native code
- * bNoDetach is required for events which cause an exception which needs to be caught in native code
- */
- fireDocumentEvent: function(type, data, bNoDetach) {
- var evt = createEvent(type, data);
- if (typeof documentEventHandlers[type] != 'undefined') {
- if( bNoDetach ) {
- documentEventHandlers[type].fire(evt);
- }
- else {
- setTimeout(function() {
- // Fire deviceready on listeners that were registered before cordova.js was loaded.
- if (type == 'deviceready') {
- document.dispatchEvent(evt);
- }
- documentEventHandlers[type].fire(evt);
- }, 0);
- }
- } else {
- document.dispatchEvent(evt);
- }
- },
- fireWindowEvent: function(type, data) {
- var evt = createEvent(type,data);
- if (typeof windowEventHandlers[type] != 'undefined') {
- setTimeout(function() {
- windowEventHandlers[type].fire(evt);
- }, 0);
- } else {
- window.dispatchEvent(evt);
- }
- },
-
- /**
- * Plugin callback mechanism.
- */
- // Randomize the starting callbackId to avoid collisions after refreshing or navigating.
- // This way, it's very unlikely that any new callback would get the same callbackId as an old callback.
- callbackId: Math.floor(Math.random() * 2000000000),
- callbacks: {},
- callbackStatus: {
- NO_RESULT: 0,
- OK: 1,
- CLASS_NOT_FOUND_EXCEPTION: 2,
- ILLEGAL_ACCESS_EXCEPTION: 3,
- INSTANTIATION_EXCEPTION: 4,
- MALFORMED_URL_EXCEPTION: 5,
- IO_EXCEPTION: 6,
- INVALID_ACTION: 7,
- JSON_EXCEPTION: 8,
- ERROR: 9
- },
-
- /**
- * Called by native code when returning successful result from an action.
- */
- callbackSuccess: function(callbackId, args) {
- try {
- cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback);
- } catch (e) {
- console.log("Error in error callback: " + callbackId + " = "+e);
- }
- },
-
- /**
- * Called by native code when returning error result from an action.
- */
- callbackError: function(callbackId, args) {
- // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative.
- // Derive success from status.
- try {
- cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback);
- } catch (e) {
- console.log("Error in error callback: " + callbackId + " = "+e);
- }
- },
-
- /**
- * Called by native code when returning the result from an action.
- */
- callbackFromNative: function(callbackId, success, status, args, keepCallback) {
- var callback = cordova.callbacks[callbackId];
- if (callback) {
- if (success && status == cordova.callbackStatus.OK) {
- callback.success && callback.success.apply(null, args);
- } else if (!success) {
- callback.fail && callback.fail.apply(null, args);
- }
-
- // Clear callback if not expecting any more results
- if (!keepCallback) {
- delete cordova.callbacks[callbackId];
- }
- }
- },
- addConstructor: function(func) {
- channel.onCordovaReady.subscribe(function() {
- try {
- func();
- } catch(e) {
- console.log("Failed to run constructor: " + e);
- }
- });
- }
-};
-
-// Register pause, resume and deviceready channels as events on document.
-channel.onPause = cordova.addDocumentEventHandler('pause');
-channel.onResume = cordova.addDocumentEventHandler('resume');
-channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready');
-
-module.exports = cordova;
-
-});
-
-// file: lib/common/argscheck.js
-define("cordova/argscheck", function(require, exports, module) {
-
-var exec = require('cordova/exec');
-var utils = require('cordova/utils');
-
-var moduleExports = module.exports;
-
-var typeMap = {
- 'A': 'Array',
- 'D': 'Date',
- 'N': 'Number',
- 'S': 'String',
- 'F': 'Function',
- 'O': 'Object'
-};
-
-function extractParamName(callee, argIndex) {
- return (/.*?\((.*?)\)/).exec(callee)[1].split(', ')[argIndex];
-}
-
-function checkArgs(spec, functionName, args, opt_callee) {
- if (!moduleExports.enableChecks) {
- return;
- }
- var errMsg = null;
- var typeName;
- for (var i = 0; i < spec.length; ++i) {
- var c = spec.charAt(i),
- cUpper = c.toUpperCase(),
- arg = args[i];
- // Asterix means allow anything.
- if (c == '*') {
- continue;
- }
- typeName = utils.typeName(arg);
- if ((arg === null || arg === undefined) && c == cUpper) {
- continue;
- }
- if (typeName != typeMap[cUpper]) {
- errMsg = 'Expected ' + typeMap[cUpper];
- break;
- }
- }
- if (errMsg) {
- errMsg += ', but got ' + typeName + '.';
- errMsg = 'Wrong type for parameter "' + extractParamName(opt_callee || args.callee, i) + '" of ' + functionName + ': ' + errMsg;
- // Don't log when running jake test.
- if (typeof jasmine == 'undefined') {
- console.error(errMsg);
- }
- throw TypeError(errMsg);
- }
-}
-
-function getValue(value, defaultValue) {
- return value === undefined ? defaultValue : value;
-}
-
-moduleExports.checkArgs = checkArgs;
-moduleExports.getValue = getValue;
-moduleExports.enableChecks = true;
-
-
-});
-
-// file: lib/common/builder.js
-define("cordova/builder", function(require, exports, module) {
-
-var utils = require('cordova/utils');
-
-function each(objects, func, context) {
- for (var prop in objects) {
- if (objects.hasOwnProperty(prop)) {
- func.apply(context, [objects[prop], prop]);
- }
- }
-}
-
-function clobber(obj, key, value) {
- exports.replaceHookForTesting(obj, key);
- obj[key] = value;
- // Getters can only be overridden by getters.
- if (obj[key] !== value) {
- utils.defineGetter(obj, key, function() {
- return value;
- });
- }
-}
-
-function assignOrWrapInDeprecateGetter(obj, key, value, message) {
- if (message) {
- utils.defineGetter(obj, key, function() {
- console.log(message);
- delete obj[key];
- clobber(obj, key, value);
- return value;
- });
- } else {
- clobber(obj, key, value);
- }
-}
-
-function include(parent, objects, clobber, merge) {
- each(objects, function (obj, key) {
- try {
- var result = obj.path ? require(obj.path) : {};
-
- if (clobber) {
- // Clobber if it doesn't exist.
- if (typeof parent[key] === 'undefined') {
- assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
- } else if (typeof obj.path !== 'undefined') {
- // If merging, merge properties onto parent, otherwise, clobber.
- if (merge) {
- recursiveMerge(parent[key], result);
- } else {
- assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
- }
- }
- result = parent[key];
- } else {
- // Overwrite if not currently defined.
- if (typeof parent[key] == 'undefined') {
- assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
- } else {
- // Set result to what already exists, so we can build children into it if they exist.
- result = parent[key];
- }
- }
-
- if (obj.children) {
- include(result, obj.children, clobber, merge);
- }
- } catch(e) {
- utils.alert('Exception building cordova JS globals: ' + e + ' for key "' + key + '"');
- }
- });
-}
-
-/**
- * Merge properties from one object onto another recursively. Properties from
- * the src object will overwrite existing target property.
- *
- * @param target Object to merge properties into.
- * @param src Object to merge properties from.
- */
-function recursiveMerge(target, src) {
- for (var prop in src) {
- if (src.hasOwnProperty(prop)) {
- if (target.prototype && target.prototype.constructor === target) {
- // If the target object is a constructor override off prototype.
- clobber(target.prototype, prop, src[prop]);
- } else {
- if (typeof src[prop] === 'object' && typeof target[prop] === 'object') {
- recursiveMerge(target[prop], src[prop]);
- } else {
- clobber(target, prop, src[prop]);
- }
- }
- }
- }
-}
-
-exports.buildIntoButDoNotClobber = function(objects, target) {
- include(target, objects, false, false);
-};
-exports.buildIntoAndClobber = function(objects, target) {
- include(target, objects, true, false);
-};
-exports.buildIntoAndMerge = function(objects, target) {
- include(target, objects, true, true);
-};
-exports.recursiveMerge = recursiveMerge;
-exports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter;
-exports.replaceHookForTesting = function() {};
-
-});
-
-// file: lib/common/channel.js
-define("cordova/channel", function(require, exports, module) {
-
-var utils = require('cordova/utils'),
- nextGuid = 1;
-
-/**
- * Custom pub-sub "channel" that can have functions subscribed to it
- * This object is used to define and control firing of events for
- * cordova initialization, as well as for custom events thereafter.
- *
- * The order of events during page load and Cordova startup is as follows:
- *
- * onDOMContentLoaded* Internal event that is received when the web page is loaded and parsed.
- * onNativeReady* Internal event that indicates the Cordova native side is ready.
- * onCordovaReady* Internal event fired when all Cordova JavaScript objects have been created.
- * onCordovaInfoReady* Internal event fired when device properties are available.
- * onCordovaConnectionReady* Internal event fired when the connection property has been set.
- * onDeviceReady* User event fired to indicate that Cordova is ready
- * onResume User event fired to indicate a start/resume lifecycle event
- * onPause User event fired to indicate a pause lifecycle event
- * onDestroy* Internal event fired when app is being destroyed (User should use window.onunload event, not this one).
- *
- * The events marked with an * are sticky. Once they have fired, they will stay in the fired state.
- * All listeners that subscribe after the event is fired will be executed right away.
- *
- * The only Cordova events that user code should register for are:
- * deviceready Cordova native code is initialized and Cordova APIs can be called from JavaScript
- * pause App has moved to background
- * resume App has returned to foreground
- *
- * Listeners can be registered as:
- * document.addEventListener("deviceready", myDeviceReadyListener, false);
- * document.addEventListener("resume", myResumeListener, false);
- * document.addEventListener("pause", myPauseListener, false);
- *
- * The DOM lifecycle events should be used for saving and restoring state
- * window.onload
- * window.onunload
- *
- */
-
-/**
- * Channel
- * @constructor
- * @param type String the channel name
- */
-var Channel = function(type, sticky) {
- this.type = type;
- // Map of guid -> function.
- this.handlers = {};
- // 0 = Non-sticky, 1 = Sticky non-fired, 2 = Sticky fired.
- this.state = sticky ? 1 : 0;
- // Used in sticky mode to remember args passed to fire().
- this.fireArgs = null;
- // Used by onHasSubscribersChange to know if there are any listeners.
- this.numHandlers = 0;
- // Function that is called when the first listener is subscribed, or when
- // the last listener is unsubscribed.
- this.onHasSubscribersChange = null;
-},
- channel = {
- /**
- * Calls the provided function only after all of the channels specified
- * have been fired. All channels must be sticky channels.
- */
- join: function(h, c) {
- var len = c.length,
- i = len,
- f = function() {
- if (!(--i)) h();
- };
- for (var j=0; j<len; j++) {
- if (c[j].state === 0) {
- throw Error('Can only use join with sticky channels.');
- }
- c[j].subscribe(f);
- }
- if (!len) h();
- },
- create: function(type) {
- return channel[type] = new Channel(type, false);
- },
- createSticky: function(type) {
- return channel[type] = new Channel(type, true);
- },
-
- /**
- * cordova Channels that must fire before "deviceready" is fired.
- */
- deviceReadyChannelsArray: [],
- deviceReadyChannelsMap: {},
-
- /**
- * Indicate that a feature needs to be initialized before it is ready to be used.
- * This holds up Cordova's "deviceready" event until the feature has been initialized
- * and Cordova.initComplete(feature) is called.
- *
- * @param feature {String} The unique feature name
- */
- waitForInitialization: function(feature) {
- if (feature) {
- var c = channel[feature] || this.createSticky(feature);
- this.deviceReadyChannelsMap[feature] = c;
- this.deviceReadyChannelsArray.push(c);
- }
- },
-
- /**
- * Indicate that initialization code has completed and the feature is ready to be used.
- *
- * @param feature {String} The unique feature name
- */
- initializationComplete: function(feature) {
- var c = this.deviceReadyChannelsMap[feature];
- if (c) {
- c.fire();
- }
- }
- };
-
-function forceFunction(f) {
- if (typeof f != 'function') throw "Function required as first argument!";
-}
-
-/**
- * Subscribes the given function to the channel. Any time that
- * Channel.fire is called so too will the function.
- * Optionally specify an execution context for the function
- * and a guid that can be used to stop subscribing to the channel.
- * Returns the guid.
- */
-Channel.prototype.subscribe = function(f, c) {
- // need a function to call
- forceFunction(f);
- if (this.state == 2) {
- f.apply(c || this, this.fireArgs);
- return;
- }
-
- var func = f,
- guid = f.observer_guid;
- if (typeof c == "object") { func = utils.close(c, f); }
-
- if (!guid) {
- // first time any channel has seen this subscriber
- guid = '' + nextGuid++;
- }
- func.observer_guid = guid;
- f.observer_guid = guid;
-
- // Don't add the same handler more than once.
- if (!this.handlers[guid]) {
- this.handlers[guid] = func;
- this.numHandlers++;
- if (this.numHandlers == 1) {
- this.onHasSubscribersChange && this.onHasSubscribersChange();
- }
- }
-};
-
-/**
- * Unsubscribes the function with the given guid from the channel.
- */
-Channel.prototype.unsubscribe = function(f) {
- // need a function to unsubscribe
- forceFunction(f);
-
- var guid = f.observer_guid,
- handler = this.handlers[guid];
- if (handler) {
- delete this.handlers[guid];
- this.numHandlers--;
- if (this.numHandlers === 0) {
- this.onHasSubscribersChange && this.onHasSubscribersChange();
- }
- }
-};
-
-/**
- * Calls all functions subscribed to this channel.
- */
-Channel.prototype.fire = function(e) {
- var fail = false,
- fireArgs = Array.prototype.slice.call(arguments);
- // Apply stickiness.
- if (this.state == 1) {
- this.state = 2;
- this.fireArgs = fireArgs;
- }
- if (this.numHandlers) {
- // Copy the values first so that it is safe to modify it from within
- // callbacks.
- var toCall = [];
- for (var item in this.handlers) {
- toCall.push(this.handlers[item]);
- }
- for (var i = 0; i < toCall.length; ++i) {
- toCall[i].apply(this, fireArgs);
- }
- if (this.state == 2 && this.numHandlers) {
- this.numHandlers = 0;
- this.handlers = {};
- this.onHasSubscribersChange && this.onHasSubscribersChange();
- }
- }
-};
-
-
-// defining them here so they are ready super fast!
-// DOM event that is received when the web page is loaded and parsed.
-channel.createSticky('onDOMContentLoaded');
-
-// Event to indicate the Cordova native side is ready.
-channel.createSticky('onNativeReady');
-
-// Event to indicate that all Cordova JavaScript objects have been created
-// and it's time to run plugin constructors.
-channel.createSticky('onCordovaReady');
-
-// Event to indicate that device properties are available
-channel.createSticky('onCordovaInfoReady');
-
-// Event to indicate that the connection property has been set.
-channel.createSticky('onCordovaConnectionReady');
-
-// Event to indicate that all automatically loaded JS plugins are loaded and ready.
-channel.createSticky('onPluginsReady');
-
-// Event to indicate that Cordova is ready
-channel.createSticky('onDeviceReady');
-
-// Event to indicate a resume lifecycle event
-channel.create('onResume');
-
-// Event to indicate a pause lifecycle event
-channel.create('onPause');
-
-// Event to indicate a destroy lifecycle event
-channel.createSticky('onDestroy');
-
-// Channels that must fire before "deviceready" is fired.
-channel.waitForInitialization('onCordovaReady');
-channel.waitForInitialization('onCordovaConnectionReady');
-channel.waitForInitialization('onDOMContentLoaded');
-
-module.exports = channel;
-
-});
-
-// file: lib/common/commandProxy.js
-define("cordova/commandProxy", function(require, exports, module) {
-
-
-// internal map of proxy function
-var CommandProxyMap = {};
-
-module.exports = {
-
- // example: cordova.commandProxy.add("Accelerometer",{getCurrentAcceleration: function(successCallback, errorCallback, options) {...},...);
- add:function(id,proxyObj) {
- console.log("adding proxy for " + id);
- CommandProxyMap[id] = proxyObj;
- return proxyObj;
- },
-
- // cordova.commandProxy.remove("Accelerometer");
- remove:function(id) {
- var proxy = CommandProxyMap[id];
- delete CommandProxyMap[id];
- CommandProxyMap[id] = null;
- return proxy;
- },
-
- get:function(service,action) {
- return ( CommandProxyMap[service] ? CommandProxyMap[service][action] : null );
- }
-};
-});
-
-// file: lib/android/exec.js
-define("cordova/exec", function(require, exports, module) {
-
-/**
- * Execute a cordova command. It is up to the native side whether this action
- * is synchronous or asynchronous. The native side can return:
- * Synchronous: PluginResult object as a JSON string
- * Asynchronous: Empty string ""
- * If async, the native side will cordova.callbackSuccess or cordova.callbackError,
- * depending upon the result of the action.
- *
- * @param {Function} success The success callback
- * @param {Function} fail The fail callback
- * @param {String} service The name of the service to use
- * @param {String} action Action to be run in cordova
- * @param {String[]} [args] Zero or more arguments to pass to the method
- */
-var cordova = require('cordova'),
- nativeApiProvider = require('cordova/plugin/android/nativeapiprovider'),
- utils = require('cordova/utils'),
- jsToNativeModes = {
- PROMPT: 0,
- JS_OBJECT: 1,
- // This mode is currently for benchmarking purposes only. It must be enabled
- // on the native side through the ENABLE_LOCATION_CHANGE_EXEC_MODE
- // constant within CordovaWebViewClient.java before it will work.
- LOCATION_CHANGE: 2
- },
- nativeToJsModes = {
- // Polls for messages using the JS->Native bridge.
- POLLING: 0,
- // For LOAD_URL to be viable, it would need to have a work-around for
- // the bug where the soft-keyboard gets dismissed when a message is sent.
- LOAD_URL: 1,
- // For the ONLINE_EVENT to be viable, it would need to intercept all event
- // listeners (both through addEventListener and window.ononline) as well
- // as set the navigator property itself.
- ONLINE_EVENT: 2,
- // Uses reflection to access private APIs of the WebView that can send JS
- // to be executed.
- // Requires Android 3.2.4 or above.
- PRIVATE_API: 3
- },
- jsToNativeBridgeMode, // Set lazily.
- nativeToJsBridgeMode = nativeToJsModes.ONLINE_EVENT,
- pollEnabled = false,
- messagesFromNative = [];
-
-function androidExec(success, fail, service, action, args) {
- // Set default bridge modes if they have not already been set.
- // By default, we use the failsafe, since addJavascriptInterface breaks too often
- if (jsToNativeBridgeMode === undefined) {
- androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);
- }
-
- // Process any ArrayBuffers in the args into a string.
- for (var i = 0; i < args.length; i++) {
- if (utils.typeName(args[i]) == 'ArrayBuffer') {
- args[i] = window.btoa(String.fromCharCode.apply(null, new Uint8Array(args[i])));
- }
- }
-
- var callbackId = service + cordova.callbackId++,
- argsJson = JSON.stringify(args);
-
- if (success || fail) {
- cordova.callbacks[callbackId] = {success:success, fail:fail};
- }
-
- if (jsToNativeBridgeMode == jsToNativeModes.LOCATION_CHANGE) {
- window.location = 'http://cdv_exec/' + service + '#' + action + '#' + callbackId + '#' + argsJson;
- } else {
- var messages = nativeApiProvider.get().exec(service, action, callbackId, argsJson);
- // If argsJson was received by Java as null, try again with the PROMPT bridge mode.
- // This happens in rare circumstances, such as when certain Unicode characters are passed over the bridge on a Galaxy S2. See CB-2666.
- if (jsToNativeBridgeMode == jsToNativeModes.JS_OBJECT && messages === "@Null arguments.") {
- androidExec.setJsToNativeBridgeMode(jsToNativeModes.PROMPT);
- androidExec(success, fail, service, action, args);
- androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);
- return;
- } else {
- androidExec.processMessages(messages);
- }
- }
-}
-
-function pollOnce() {
- var msg = nativeApiProvider.get().retrieveJsMessages();
- androidExec.processMessages(msg);
-}
-
-function pollingTimerFunc() {
- if (pollEnabled) {
- pollOnce();
- setTimeout(pollingTimerFunc, 50);
- }
-}
-
-function hookOnlineApis() {
- function proxyEvent(e) {
- cordova.fireWindowEvent(e.type);
- }
- // The network module takes care of firing online and offline events.
- // It currently fires them only on document though, so we bridge them
- // to window here (while first listening for exec()-releated online/offline
- // events).
- window.addEventListener('online', pollOnce, false);
- window.addEventListener('offline', pollOnce, false);
- cordova.addWindowEventHandler('online');
- cordova.addWindowEventHandler('offline');
- document.addEventListener('online', proxyEvent, false);
- document.addEventListener('offline', proxyEvent, false);
-}
-
-hookOnlineApis();
-
-androidExec.jsToNativeModes = jsToNativeModes;
-androidExec.nativeToJsModes = nativeToJsModes;
-
-androidExec.setJsToNativeBridgeMode = function(mode) {
- if (mode == jsToNativeModes.JS_OBJECT && !window._cordovaNative) {
- console.log('Falling back on PROMPT mode since _cordovaNative is missing. Expected for Android 3.2 and lower only.');
- mode = jsToNativeModes.PROMPT;
- }
- nativeApiProvider.setPreferPrompt(mode == jsToNativeModes.PROMPT);
- jsToNativeBridgeMode = mode;
-};
-
-androidExec.setNativeToJsBridgeMode = function(mode) {
- if (mode == nativeToJsBridgeMode) {
- return;
- }
- if (nativeToJsBridgeMode == nativeToJsModes.POLLING) {
- pollEnabled = false;
- }
-
- nativeToJsBridgeMode = mode;
- // Tell the native side to switch modes.
- nativeApiProvider.get().setNativeToJsBridgeMode(mode);
-
- if (mode == nativeToJsModes.POLLING) {
- pollEnabled = true;
- setTimeout(pollingTimerFunc, 1);
- }
-};
-
-// Processes a single message, as encoded by NativeToJsMessageQueue.java.
-function processMessage(message) {
- try {
- var firstChar = message.charAt(0);
- if (firstChar == 'J') {
- eval(message.slice(1));
- } else if (firstChar == 'S' || firstChar == 'F') {
- var success = firstChar == 'S';
- var keepCallback = message.charAt(1) == '1';
- var spaceIdx = message.indexOf(' ', 2);
- var status = +message.slice(2, spaceIdx);
- var nextSpaceIdx = message.indexOf(' ', spaceIdx + 1);
- var callbackId = message.slice(spaceIdx + 1, nextSpaceIdx);
- var payloadKind = message.charAt(nextSpaceIdx + 1);
- var payload;
- if (payloadKind == 's') {
- payload = message.slice(nextSpaceIdx + 2);
- } else if (payloadKind == 't') {
- payload = true;
- } else if (payloadKind == 'f') {
- payload = false;
- } else if (payloadKind == 'N') {
- payload = null;
- } else if (payloadKind == 'n') {
- payload = +message.slice(nextSpaceIdx + 2);
- } else if (payloadKind == 'A') {
- var data = message.slice(nextSpaceIdx + 2);
- var bytes = window.atob(data);
- var arraybuffer = new Uint8Array(bytes.length);
- for (var i = 0; i < bytes.length; i++) {
- arraybuffer[i] = bytes.charCodeAt(i);
- }
- payload = arraybuffer.buffer;
- } else if (payloadKind == 'S') {
- payload = window.atob(message.slice(nextSpaceIdx + 2));
- } else {
- payload = JSON.parse(message.slice(nextSpaceIdx + 1));
- }
- cordova.callbackFromNative(callbackId, success, status, [payload], keepCallback);
- } else {
- console.log("processMessage failed: invalid message:" + message);
- }
- } catch (e) {
- console.log("processMessage failed: Message: " + message);
- console.log("processMessage failed: Error: " + e);
- console.log("processMessage failed: Stack: " + e.stack);
- }
-}
-
-// This is called from the NativeToJsMessageQueue.java.
-androidExec.processMessages = function(messages) {
- if (messages) {
- messagesFromNative.push(messages);
- // Check for the reentrant case, and enqueue the message if that's the case.
- if (messagesFromNative.length > 1) {
- return;
- }
- while (messagesFromNative.length) {
- // Don't unshift until the end so that reentrancy can be detected.
- messages = messagesFromNative[0];
- // The Java side can send a * message to indicate that it
- // still has messages waiting to be retrieved.
- if (messages == '*') {
- messagesFromNative.shift();
- window.setTimeout(pollOnce, 0);
- return;
- }
-
- var spaceIdx = messages.indexOf(' ');
- var msgLen = +messages.slice(0, spaceIdx);
- var message = messages.substr(spaceIdx + 1, msgLen);
- messages = messages.slice(spaceIdx + msgLen + 1);
- processMessage(message);
- if (messages) {
- messagesFromNative[0] = messages;
- } else {
- messagesFromNative.shift();
- }
- }
- }
-};
-
-module.exports = androidExec;
-
-});
-
-// file: lib/common/modulemapper.js
-define("cordova/modulemapper", function(require, exports, module) {
-
-var builder = require('cordova/builder'),
- moduleMap = define.moduleMap,
- symbolList,
- deprecationMap;
-
-exports.reset = function() {
- symbolList = [];
- deprecationMap = {};
-};
-
-function addEntry(strategy, moduleName, symbolPath, opt_deprecationMessage) {
- if (!(moduleName in moduleMap)) {
- throw new Error('Module ' + moduleName + ' does not exist.');
- }
- symbolList.push(strategy, moduleName, symbolPath);
- if (opt_deprecationMessage) {
- deprecationMap[symbolPath] = opt_deprecationMessage;
- }
-}
-
-// Note: Android 2.3 does have Function.bind().
-exports.clobbers = function(moduleName, symbolPath, opt_deprecationMessage) {
- addEntry('c', moduleName, symbolPath, opt_deprecationMessage);
-};
-
-exports.merges = function(moduleName, symbolPath, opt_deprecationMessage) {
- addEntry('m', moduleName, symbolPath, opt_deprecationMessage);
-};
-
-exports.defaults = function(moduleName, symbolPath, opt_deprecationMessage) {
- addEntry('d', moduleName, symbolPath, opt_deprecationMessage);
-};
-
-function prepareNamespace(symbolPath, context) {
- if (!symbolPath) {
- return context;
- }
- var parts = symbolPath.split('.');
- var cur = context;
- for (var i = 0, part; part = parts[i]; ++i) {
- cur = cur[part] = cur[part] || {};
- }
- return cur;
-}
-
-exports.mapModules = function(context) {
- var origSymbols = {};
- context.CDV_origSymbols = origSymbols;
- for (var i = 0, len = symbolList.length; i < len; i += 3) {
- var strategy = symbolList[i];
- var moduleName = symbolList[i + 1];
- var symbolPath = symbolList[i + 2];
- var lastDot = symbolPath.lastIndexOf('.');
- var namespace = symbolPath.substr(0, lastDot);
- var lastName = symbolPath.substr(lastDot + 1);
-
- var module = require(moduleName);
- var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null;
- var parentObj = prepareNamespace(namespace, context);
- var target = parentObj[lastName];
-
- if (strategy == 'm' && target) {
- builder.recursiveMerge(target, module);
- } else if ((strategy == 'd' && !target) || (strategy != 'd')) {
- if (!(symbolPath in origSymbols)) {
- origSymbols[symbolPath] = target;
- }
- builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg);
- }
- }
-};
-
-exports.getOriginalSymbol = function(context, symbolPath) {
- var origSymbols = context.CDV_origSymbols;
- if (origSymbols && (symbolPath in origSymbols)) {
- return origSymbols[symbolPath];
- }
- var parts = symbolPath.split('.');
- var obj = context;
- for (var i = 0; i < parts.length; ++i) {
- obj = obj && obj[parts[i]];
- }
- return obj;
-};
-
-exports.loadMatchingModules = function(matchingRegExp) {
- for (var k in moduleMap) {
- if (matchingRegExp.exec(k)) {
- require(k);
- }
- }
-};
-
-exports.reset();
-
-
-});
-
-// file: lib/android/platform.js
-define("cordova/platform", function(require, exports, module) {
-
-module.exports = {
- id: "android",
- initialize:function() {
- var channel = require("cordova/channel"),
- cordova = require('cordova'),
- exec = require('cordova/exec'),
- modulemapper = require('cordova/modulemapper');
-
- modulemapper.loadMatchingModules(/cordova.*\/symbols$/);
- modulemapper.clobbers('cordova/plugin/android/app', 'navigator.app');
-
- modulemapper.mapModules(window);
-
- // Inject a listener for the backbutton on the document.
- var backButtonChannel = cordova.addDocumentEventHandler('backbutton');
- backButtonChannel.onHasSubscribersChange = function() {
- // If we just attached the first handler or detached the last handler,
- // let native know we need to override the back button.
- exec(null, null, "App", "overrideBackbutton", [this.numHandlers == 1]);
- };
-
- // Add hardware MENU and SEARCH button handlers
- cordova.addDocumentEventHandler('menubutton');
- cordova.addDocumentEventHandler('searchbutton');
-
- // Let native code know we are all done on the JS side.
- // Native code will then un-hide the WebView.
- channel.join(function() {
- exec(null, null, "App", "show", []);
- }, [channel.onCordovaReady]);
- }
-};
-
-});
-
-// file: lib/common/plugin/Acceleration.js
-define("cordova/plugin/Acceleration", function(require, exports, module) {
-
-var Acceleration = function(x, y, z, timestamp) {
- this.x = x;
- this.y = y;
- this.z = z;
- this.timestamp = timestamp || (new Date()).getTime();
-};
-
-module.exports = Acceleration;
-
-});
-
-// file: lib/common/plugin/Camera.js
-define("cordova/plugin/Camera", function(require, exports, module) {
-
-var argscheck = require('cordova/argscheck'),
- exec = require('cordova/exec'),
- Camera = require('cordova/plugin/CameraConstants'),
- CameraPopoverHandle = require('cordova/plugin/CameraPopoverHandle');
-
-var cameraExport = {};
-
-// Tack on the Camera Constants to the base camera plugin.
-for (var key in Camera) {
- cameraExport[key] = Camera[key];
-}
-
-/**
- * Gets a picture from source defined by "options.sourceType", and returns the
- * image as defined by the "options.destinationType" option.
-
- * The defaults are sourceType=CAMERA and destinationType=FILE_URI.
- *
- * @param {Function} successCallback
- * @param {Function} errorCallback
- * @param {Object} options
- */
-cameraExport.getPicture = function(successCallback, errorCallback, options) {
- argscheck.checkArgs('fFO', 'Camera.getPicture', arguments);
- options = options || {};
- var getValue = argscheck.getValue;
-
- var quality = getValue(options.quality, 50);
- var destinationType = getValue(options.destinationType, Camera.DestinationType.FILE_URI);
- var sourceType = getValue(options.sourceType, Camera.PictureSourceType.CAMERA);
- var targetWidth = getValue(options.targetWidth, -1);
- var targetHeight = getValue(options.targetHeight, -1);
- var encodingType = getValue(options.encodingType, Camera.EncodingType.JPEG);
- var mediaType = getValue(options.mediaType, Camera.MediaType.PICTURE);
- var allowEdit = !!options.allowEdit;
- var correctOrientation = !!options.correctOrientation;
- var saveToPhotoAlbum = !!options.saveToPhotoAlbum;
- var popoverOptions = getValue(options.popoverOptions, null);
- var cameraDirection = getValue(options.cameraDirection, Camera.Direction.BACK);
-
- var args = [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType,
- mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions, cameraDirection];
-
- exec(successCallback, errorCallback, "Camera", "takePicture", args);
- return new CameraPopoverHandle();
-};
-
-cameraExport.cleanup = function(successCallback, errorCallback) {
- exec(successCallback, errorCallback, "Camera", "cleanup", []);
-};
-
-module.exports = cameraExport;
-
-});
-
-// file: lib/common/plugin/CameraConstants.js
-define("cordova/plugin/CameraConstants", function(require, exports, module) {
-
-module.exports = {
- DestinationType:{
- DATA_URL: 0, // Return base64 encoded string
- FILE_URI: 1, // Return file uri (content://media/external/images/media/2 for Android)
- NATIVE_URI: 2 // Return native uri (eg. asset-library://... for iOS)
- },
- EncodingType:{
- JPEG: 0, // Return JPEG encoded image
- PNG: 1 // Return PNG encoded image
- },
- MediaType:{
- PICTURE: 0, // allow selection of still pictures only. DEFAULT. Will return format specified via DestinationType
- VIDEO: 1, // allow selection of video only, ONLY RETURNS URL
- ALLMEDIA : 2 // allow selection from all media types
- },
- PictureSourceType:{
- PHOTOLIBRARY : 0, // Choose image from picture library (same as SAVEDPHOTOALBUM for Android)
- CAMERA : 1, // Take picture from camera
- SAVEDPHOTOALBUM : 2 // Choose image from picture library (same as PHOTOLIBRARY for Android)
- },
- PopoverArrowDirection:{
- ARROW_UP : 1, // matches iOS UIPopoverArrowDirection constants to specify arrow location on popover
- ARROW_DOWN : 2,
- ARROW_LEFT : 4,
- ARROW_RIGHT : 8,
- ARROW_ANY : 15
- },
- Direction:{
- BACK: 0,
- FRONT: 1
- }
-};
-
-});
-
-// file: lib/common/plugin/CameraPopoverHandle.js
-define("cordova/plugin/CameraPopoverHandle", function(require, exports, module) {
-
-var exec = require('cordova/exec');
-
-/**
- * A handle to an image picker popover.
- */
-var CameraPopoverHandle = function() {
- this.setPosition = function(popoverOptions) {
- console.log('CameraPopoverHandle.setPosition is only supported on iOS.');
- };
-};
-
-module.exports = CameraPopoverHandle;
-
-});
-
-// file: lib/common/plugin/CameraPopoverOptions.js
-define("cordova/plugin/CameraPopoverOptions", function(require, exports, module) {
-
-var Camera = require('cordova/plugin/CameraConstants');
-
-/**
- * Encapsulates options for iOS Popover image picker
- */
-var CameraPopoverOptions = function(x,y,width,height,arrowDir){
- // information of rectangle that popover should be anchored to
- this.x = x || 0;
- this.y = y || 32;
- this.width = width || 320;
- this.height = height || 480;
- // The direction of the popover arrow
- this.arrowDir = arrowDir || Camera.PopoverArrowDirection.ARROW_ANY;
-};
-
-module.exports = CameraPopoverOptions;
-
-});
-
-// file: lib/common/plugin/CaptureAudioOptions.js
-define("cordova/plugin/CaptureAudioOptions", function(require, exports, module) {
-
-/**
- * Encapsulates all audio capture operation configuration options.
- */
-var CaptureAudioOptions = function(){
- // Upper limit of sound clips user can record. Value must be equal or greater than 1.
- this.limit = 1;
- // Maximum duration of a single sound clip in seconds.
- this.duration = 0;
- // The selected audio mode. Must match with one of the elements in supportedAudioModes array.
- this.mode = null;
-};
-
-module.exports = CaptureAudioOptions;
-
-});
-
-// file: lib/common/plugin/CaptureError.js
-define("cordova/plugin/CaptureError", function(require, exports, module) {
-
-/**
- * The CaptureError interface encapsulates all errors in the Capture API.
- */
-var CaptureError = function(c) {
- this.code = c || null;
-};
-
-// Camera or microphone failed to capture image or sound.
-CaptureError.CAPTURE_INTERNAL_ERR = 0;
-// Camera application or audio capture application is currently serving other capture request.
-CaptureError.CAPTURE_APPLICATION_BUSY = 1;
-// Invalid use of the API (e.g. limit parameter has value less than one).
-CaptureError.CAPTURE_INVALID_ARGUMENT = 2;
-// User exited camera application or audio capture application before capturing anything.
-CaptureError.CAPTURE_NO_MEDIA_FILES = 3;
-// The requested capture operation is not supported.
-CaptureError.CAPTURE_NOT_SUPPORTED = 20;
-
-module.exports = CaptureError;
-
-});
-
-// file: lib/common/plugin/CaptureImageOptions.js
-define("cordova/plugin/CaptureImageOptions", function(require, exports, module) {
-
-/**
- * Encapsulates all image capture operation configuration options.
- */
-var CaptureImageOptions = function(){
- // Upper limit of images user can take. Value must be equal or greater than 1.
- this.limit = 1;
- // The selected image mode. Must match with one of the elements in supportedImageModes array.
- this.mode = null;
-};
-
-module.exports = CaptureImageOptions;
-
-});
-
-// file: lib/common/plugin/CaptureVideoOptions.js
-define("cordova/plugin/CaptureVideoOptions", function(require, exports, module) {
-
-/**
- * Encapsulates all video capture operation configuration options.
- */
-var CaptureVideoOptions = function(){
- // Upper limit of videos user can record. Value must be equal or greater than 1.
- this.limit = 1;
- // Maximum duration of a single video clip in seconds.
- this.duration = 0;
- // The selected video mode. Must match with one of the elements in supportedVideoModes array.
- this.mode = null;
-};
-
-module.exports = CaptureVideoOptions;
-
-});
-
-// file: lib/common/plugin/CompassError.js
-define("cordova/plugin/CompassError", function(require, exports, module) {
-
-/**
- * CompassError.
- * An error code assigned by an implementation when an error has occurred
- * @constructor
- */
-var CompassError = function(err) {
- this.code = (err !== undefined ? err : null);
-};
-
-CompassError.COMPASS_INTERNAL_ERR = 0;
-CompassError.COMPASS_NOT_SUPPORTED = 20;
-
-module.exports = CompassError;
-
-});
-
-// file: lib/common/plugin/CompassHeading.js
-define("cordova/plugin/CompassHeading", function(require, exports, module) {
-
-var CompassHeading = function(magneticHeading, trueHeading, headingAccuracy, timestamp) {
- this.magneticHeading = magneticHeading;
- this.trueHeading = trueHeading;
- this.headingAccuracy = headingAccuracy;
- this.timestamp = timestamp || new Date().getTime();
-};
-
-module.exports = CompassHeading;
-
-});
-
-// file: lib/common/plugin/ConfigurationData.js
-define("cordova/plugin/ConfigurationData", function(require, exports, module) {
-
-/**
- * Encapsulates a set of parameters that the capture device supports.
- */
-function ConfigurationData() {
- // The ASCII-encoded string in lower case representing the media type.
- this.type = null;
- // The height attribute represents height of the image or video in pixels.
- // In the case of a sound clip this attribute has value 0.
- this.height = 0;
- // The width attribute represents width of the image or video in pixels.
- // In the case of a sound clip this attribute has value 0
- this.width = 0;
-}
-
-module.exports = ConfigurationData;
-
-});
-
-// file: lib/common/plugin/Connection.js
-define("cordova/plugin/Connection", function(require, exports, module) {
-
-/**
- * Network status
- */
-module.exports = {
- UNKNOWN: "unknown",
- ETHERNET: "ethernet",
- WIFI: "wifi",
- CELL_2G: "2g",
- CELL_3G: "3g",
- CELL_4G: "4g",
- CELL:"cellular",
- NONE: "none"
-};
-
-});
-
-// file: lib/common/plugin/Contact.js
-define("cordova/plugin/Contact", function(require, exports, module) {
-
-var argscheck = require('cordova/argscheck'),
- exec = require('cordova/exec'),
- ContactError = require('cordova/plugin/ContactError'),
- utils = require('cordova/utils');
-
-/**
-* Converts primitives into Complex Object
-* Currently only used for Date fields
-*/
-function convertIn(contact) {
- var value = contact.birthday;
- try {
- contact.birthday = new Date(parseFloat(value));
- } catch (exception){
- console.log("Cordova Contact convertIn error: exception creating date.");
- }
- return contact;
-}
-
-/**
-* Converts Complex objects into primitives
-* Only conversion at present is for Dates.
-**/
-
-function convertOut(contact) {
- var value = contact.birthday;
- if (value !== null) {
- // try to make it a Date object if it is not already
- if (!utils.isDate(value)){
- try {
- value = new Date(value);
- } catch(exception){
- value = null;
- }
- }
- if (utils.isDate(value)){
- value = value.valueOf(); // convert to milliseconds
- }
- contact.birthday = value;
- }
- return contact;
-}
-
-/**
-* Contains information about a single contact.
-* @constructor
-* @param {DOMString} id unique identifier
-* @param {DOMString} displayName
-* @param {ContactName} name
-* @param {DOMString} nickname
-* @param {Array.<ContactField>} phoneNumbers array of phone numbers
-* @param {Array.<ContactField>} emails array of email addresses
-* @param {Array.<ContactAddress>} addresses array of addresses
-* @param {Array.<ContactField>} ims instant messaging user ids
-* @param {Array.<ContactOrganization>} organizations
-* @param {DOMString} birthday contact's birthday
-* @param {DOMString} note user notes about contact
-* @param {Array.<ContactField>} photos
-* @param {Array.<ContactField>} categories
-* @param {Array.<ContactField>} urls contact's web sites
-*/
-var Contact = function (id, displayName, name, nickname, phoneNumbers, emails, addresses,
- ims, organizations, birthday, note, photos, categories, urls) {
- this.id = id || null;
- this.rawId = null;
- this.displayName = displayName || null;
- this.name = name || null; // ContactName
- this.nickname = nickname || null;
- this.phoneNumbers = phoneNumbers || null; // ContactField[]
- this.emails = emails || null; // ContactField[]
- this.addresses = addresses || null; // ContactAddress[]
- this.ims = ims || null; // ContactField[]
- this.organizations = organizations || null; // ContactOrganization[]
- this.birthday = birthday || null;
- this.note = note || null;
- this.photos = photos || null; // ContactField[]
- this.categories = categories || null; // ContactField[]
- this.urls = urls || null; // ContactField[]
-};
-
-/**
-* Removes contact from device storage.
-* @param successCB success callback
-* @param errorCB error callback
-*/
-Contact.prototype.remove = function(successCB, errorCB) {
- argscheck.checkArgs('FF', 'Contact.remove', arguments);
- var fail = errorCB && function(code) {
- errorCB(new ContactError(code));
- };
- if (this.id === null) {
- fail(ContactError.UNKNOWN_ERROR);
- }
- else {
- exec(successCB, fail, "Contacts", "remove", [this.id]);
- }
-};
-
-/**
-* Creates a deep copy of this Contact.
-* With the contact ID set to null.
-* @return copy of this Contact
-*/
-Contact.prototype.clone = function() {
- var clonedContact = utils.clone(this);
- clonedContact.id = null;
- clonedContact.rawId = null;
-
- function nullIds(arr) {
- if (arr) {
- for (var i = 0; i < arr.length; ++i) {
- arr[i].id = null;
- }
- }
- }
-
- // Loop through and clear out any id's in phones, emails, etc.
- nullIds(clonedContact.phoneNumbers);
- nullIds(clonedContact.emails);
- nullIds(clonedContact.addresses);
- nullIds(clonedContact.ims);
- nullIds(clonedContact.organizations);
- nullIds(clonedContact.categories);
- nullIds(clonedContact.photos);
- nullIds(clonedContact.urls);
- return clonedContact;
-};
-
-/**
-* Persists contact to device storage.
-* @param successCB success callback
-* @param errorCB error callback
-*/
-Contact.prototype.save = function(successCB, errorCB) {
- argscheck.checkArgs('FFO', 'Contact.save', arguments);
- var fail = errorCB && function(code) {
- errorCB(new ContactError(code));
- };
- var success = function(result) {
- if (result) {
- if (successCB) {
- var fullContact = require('cordova/plugin/contacts').create(result);
- successCB(convertIn(fullContact));
- }
- }
- else {
- // no Entry object returned
- fail(ContactError.UNKNOWN_ERROR);
- }
- };
- var dupContact = convertOut(utils.clone(this));
- exec(success, fail, "Contacts", "save", [dupContact]);
-};
-
-
-module.exports = Contact;
-
-});
-
-// file: lib/common/plugin/ContactAddress.js
-define("cordova/plugin/ContactAddress", function(require, exports, module) {
-
-/**
-* Contact address.
-* @constructor
-* @param {DOMString} id unique identifier, should only be set by native code
-* @param formatted // NOTE: not a W3C standard
-* @param streetAddress
-* @param locality
-* @param region
-* @param postalCode
-* @param country
-*/
-
-var ContactAddress = function(pref, type, formatted, streetAddress, locality, region, postalCode, country) {
- this.id = null;
- this.pref = (typeof pref != 'undefined' ? pref : false);
- this.type = type || null;
- this.formatted = formatted || null;
- this.streetAddress = streetAddress || null;
- this.locality = locality || null;
- this.region = region || null;
- this.postalCode = postalCode || null;
- this.country = country || null;
-};
-
-module.exports = ContactAddress;
-
-});
-
-// file: lib/common/plugin/ContactError.js
-define("cordova/plugin/ContactError", function(require, exports, module) {
-
-/**
- * ContactError.
- * An error code assigned by an implementation when an error has occurred
- * @constructor
- */
-var ContactError = function(err) {
- this.code = (typeof err != 'undefined' ? err : null);
-};
-
-/**
- * Error codes
- */
-ContactError.UNKNOWN_ERROR = 0;
-ContactError.INVALID_ARGUMENT_ERROR = 1;
-ContactError.TIMEOUT_ERROR = 2;
-ContactError.PENDING_OPERATION_ERROR = 3;
-ContactError.IO_ERROR = 4;
-ContactError.NOT_SUPPORTED_ERROR = 5;
-ContactError.PERMISSION_DENIED_ERROR = 20;
-
-module.exports = ContactError;
-
-});
-
-// file: lib/common/plugin/ContactField.js
-define("cordova/plugin/ContactField", function(require, exports, module) {
-
-/**
-* Generic contact field.
-* @constructor
-* @param {DOMString} id unique identifier, should only be set by native code // NOTE: not a W3C standard
-* @param type
-* @param value
-* @param pref
-*/
-var ContactField = function(type, value, pref) {
- this.id = null;
- this.type = (type && type.toString()) || null;
- this.value = (value && value.toString()) || null;
- this.pref = (typeof pref != 'undefined' ? pref : false);
-};
-
-module.exports = ContactField;
-
-});
-
-// file: lib/common/plugin/ContactFindOptions.js
-define("cordova/plugin/ContactFindOptions", function(require, exports, module) {
-
-/**
- * ContactFindOptions.
- * @constructor
- * @param filter used to match contacts against
- * @param multiple boolean used to determine if more than one contact should be returned
- */
-
-var ContactFindOptions = function(filter, multiple) {
- this.filter = filter || '';
- this.multiple = (typeof multiple != 'undefined' ? multiple : false);
-};
-
-module.exports = ContactFindOptions;
-
-});
-
-// file: lib/common/plugin/ContactName.js
-define("cordova/plugin/ContactName", function(require, exports, module) {
-
-/**
-* Contact name.
-* @constructor
-* @param formatted // NOTE: not part of W3C standard
-* @param familyName
-* @param givenName
-* @param middle
-* @param prefix
-* @param suffix
-*/
-var ContactName = function(formatted, familyName, givenName, middle, prefix, suffix) {
- this.formatted = formatted || null;
- this.familyName = familyName || null;
- this.givenName = givenName || null;
- this.middleName = middle || null;
- this.honorificPrefix = prefix || null;
- this.honorificSuffix = suffix || null;
-};
-
-module.exports = ContactName;
-
-});
-
-// file: lib/common/plugin/ContactOrganization.js
-define("cordova/plugin/ContactOrganization", function(require, exports, module) {
-
-/**
-* Contact organization.
-* @constructor
-* @param {DOMString} id unique identifier, should only be set by native code // NOTE: not a W3C standard
-* @param name
-* @param dept
-* @param title
-* @param startDate
-* @param endDate
-* @param location
-* @param desc
-*/
-
-var ContactOrganization = function(pref, type, name, dept, title) {
- this.id = null;
- this.pref = (typeof pref != 'undefined' ? pref : false);
- this.type = type || null;
- this.name = name || null;
- this.department = dept || null;
- this.title = title || null;
-};
-
-module.exports = ContactOrganization;
-
-});
-
-// file: lib/common/plugin/Coordinates.js
-define("cordova/plugin/Coordinates", function(require, exports, module) {
-
-/**
- * This class contains position information.
- * @param {Object} lat
- * @param {Object} lng
- * @param {Object} alt
- * @param {Object} acc
- * @param {Object} head
- * @param {Object} vel
- * @param {Object} altacc
- * @constructor
- */
-var Coordinates = function(lat, lng, alt, acc, head, vel, altacc) {
- /**
- * The latitude of the position.
- */
- this.latitude = lat;
- /**
- * The longitude of the position,
- */
- this.longitude = lng;
- /**
- * The accuracy of the position.
- */
- this.accuracy = acc;
- /**
- * The altitude of the position.
- */
- this.altitude = (alt !== undefined ? alt : null);
- /**
- * The direction the device is moving at the position.
- */
- this.heading = (head !== undefined ? head : null);
- /**
- * The velocity with which the device is moving at the position.
- */
- this.speed = (vel !== undefined ? vel : null);
-
- if (this.speed === 0 || this.speed === null) {
- this.heading = NaN;
- }
-
- /**
- * The altitude accuracy of the position.
- */
- this.altitudeAccuracy = (altacc !== undefined) ? altacc : null;
-};
-
-module.exports = Coordinates;
-
-});
-
-// file: lib/common/plugin/DirectoryEntry.js
-define("cordova/plugin/DirectoryEntry", function(require, exports, module) {
-
-var argscheck = require('cordova/argscheck'),
- utils = require('cordova/utils'),
- exec = require('cordova/exec'),
- Entry = require('cordova/plugin/Entry'),
- FileError = require('cordova/plugin/FileError'),
- DirectoryReader = require('cordova/plugin/DirectoryReader');
-
-/**
- * An interface representing a directory on the file system.
- *
- * {boolean} isFile always false (readonly)
- * {boolean} isDirectory always true (readonly)
- * {DOMString} name of the directory, excluding the path leading to it (readonly)
- * {DOMString} fullPath the absolute full path to the directory (readonly)
- * TODO: implement this!!! {FileSystem} filesystem on which the directory resides (readonly)
- */
-var DirectoryEntry = function(name, fullPath) {
- DirectoryEntry.__super__.constructor.call(this, false, true, name, fullPath);
-};
-
-utils.extend(DirectoryEntry, Entry);
-
-/**
- * Creates a new DirectoryReader to read entries from this directory
- */
-DirectoryEntry.prototype.createReader = function() {
- return new DirectoryReader(this.fullPath);
-};
-
-/**
- * Creates or looks up a directory
- *
- * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a directory
- * @param {Flags} options to create or exclusively create the directory
- * @param {Function} successCallback is called with the new entry
- * @param {Function} errorCallback is called with a FileError
- */
-DirectoryEntry.prototype.getDirectory = function(path, options, successCallback, errorCallback) {
- argscheck.checkArgs('sOFF', 'DirectoryEntry.getDirectory', arguments);
- var win = successCallback && function(result) {
- var entry = new DirectoryEntry(result.name, result.fullPath);
- successCallback(entry);
- };
- var fail = errorCallback && function(code) {
- errorCallback(new FileError(code));
- };
- exec(win, fail, "File", "getDirectory", [this.fullPath, path, options]);
-};
-
-/**
- * Deletes a directory and all of it's contents
- *
- * @param {Function} successCallback is called with no parameters
- * @param {Function} errorCallback is called with a FileError
- */
-DirectoryEntry.prototype.removeRecursively = function(successCallback, errorCallback) {
- argscheck.checkArgs('FF', 'DirectoryEntry.removeRecursively', arguments);
- var fail = errorCallback && function(code) {
- errorCallback(new FileError(code));
- };
- exec(successCallback, fail, "File", "removeRecursively", [this.fullPath]);
-};
-
-/**
- * Creates or looks up a file
- *
- * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a file
- * @param {Flags} options to create or exclusively create the file
- * @param {Function} successCallback is called with the new entry
- * @param {Function} errorCallback is called with a FileError
- */
-DirectoryEntry.prototype.getFile = function(path, options, successCallback, errorCallback) {
- argscheck.checkArgs('sOFF', 'DirectoryEntry.getFile', arguments);
- var win = successCallback && function(result) {
- var FileEntry = require('cordova/plugin/FileEntry');
- var entry = new FileEntry(result.name, result.fullPath);
- successCallback(entry);
- };
- var fail = errorCallback && function(code) {
- errorCallback(new FileError(code));
- };
- exec(win, fail, "File", "getFile", [this.fullPath, path, options]);
-};
-
-module.exports = DirectoryEntry;
-
-});
-
-// file: lib/common/plugin/DirectoryReader.js
-define("cordova/plugin/DirectoryReader", function(require, exports, module) {
-
-var exec = require('cordova/exec'),
- FileError = require('cordova/plugin/FileError') ;
-
-/**
- * An interface that lists the files and directories in a directory.
- */
-function DirectoryReader(path) {
- this.path = path || null;
-}
-
-/**
- * Returns a list of entries from a directory.
- *
- * @param {Function} successCallback is called with a list of entries
- * @param {Function} errorCallback is called with a FileError
- */
-DirectoryReader.prototype.readEntries = function(successCallback, errorCallback) {
- var win = typeof successCallback !== 'function' ? null : function(result) {
- var retVal = [];
- for (var i=0; i<result.length; i++) {
- var entry = null;
- if (result[i].isDirectory) {
- entry = new (require('cordova/plugin/DirectoryEntry'))();
- }
- else if (result[i].isFile) {
- entry = new (require('cordova/plugin/FileEntry'))();
- }
- entry.isDirectory = result[i].isDirectory;
- entry.isFile = result[i].isFile;
- entry.name = result[i].name;
- entry.fullPath = result[i].fullPath;
- retVal.push(entry);
- }
- successCallback(retVal);
- };
- var fail = typeof errorCallback !== 'function' ? null : function(code) {
- errorCallback(new FileError(code));
- };
- exec(win, fail, "File", "readEntries", [this.path]);
-};
-
-module.exports = DirectoryReader;
-
-});
-
-// file: lib/common/plugin/Entry.js
-define("cordova/plugin/Entry", function(require, exports, module) {
-
-var argscheck = require('cordova/argscheck'),
- exec = require('cordova/exec'),
- FileError = require('cordova/plugin/FileError'),
- Metadata = require('cordova/plugin/Metadata');
-
-/**
- * Represents a file or directory on the local file system.
- *
- * @param isFile
- * {boolean} true if Entry is a file (readonly)
- * @param isDirectory
- * {boolean} true if Entry is a directory (readonly)
- * @param name
- * {DOMString} name of the file or directory, excluding the path
- * leading to it (readonly)
- * @param fullPath
- * {DOMString} the absolute full path to the file or directory
- * (readonly)
- */
-function Entry(isFile, isDirectory, name, fullPath, fileSystem) {
- this.isFile = !!isFile;
- this.isDirectory = !!isDirectory;
- this.name = name || '';
- this.fullPath = fullPath || '';
- this.filesystem = fileSystem || null;
-}
-
-/**
- * Look up the metadata of the entry.
- *
- * @param successCallback
- * {Function} is called with a Metadata object
- * @param errorCallback
- * {Function} is called with a FileError
- */
-Entry.prototype.getMetadata = function(successCallback, errorCallback) {
- argscheck.checkArgs('FF', 'Entry.getMetadata', arguments);
- var success = successCallback && function(lastModified) {
- var metadata = new Metadata(lastModified);
- successCallback(metadata);
- };
- var fail = errorCallback && function(code) {
- errorCallback(new FileError(code));
- };
-
- exec(success, fail, "File", "getMetadata", [this.fullPath]);
-};
-
-/**
- * Set the metadata of the entry.
- *
- * @param successCallback
- * {Function} is called with a Metadata object
- * @param errorCallback
- * {Function} is called with a FileError
- * @param metadataObject
- * {Object} keys and values to set
- */
-Entry.prototype.setMetadata = function(successCallback, errorCallback, metadataObject) {
- argscheck.checkArgs('FFO', 'Entry.setMetadata', arguments);
- exec(successCallback, errorCallback, "File", "setMetadata", [this.fullPath, metadataObject]);
-};
-
-/**
- * Move a file or directory to a new location.
- *
- * @param parent
- * {DirectoryEntry} the directory to which to move this entry
- * @param newName
- * {DOMString} new name of the entry, defaults to the current name
- * @param successCallback
- * {Function} called with the new DirectoryEntry object
- * @param errorCallback
- * {Function} called with a FileError
- */
-Entry.prototype.moveTo = function(parent, newName, successCallback, errorCallback) {
- argscheck.checkArgs('oSFF', 'Entry.moveTo', arguments);
- var fail = errorCallback && function(code) {
- errorCallback(new FileError(code));
- };
- // source path
- var srcPath = this.fullPath,
- // entry name
- name = newName || this.name,
- success = function(entry) {
- if (entry) {
- if (successCallback) {
- // create appropriate Entry object
- var result = (entry.isDirectory) ? new (require('cordova/plugin/DirectoryEntry'))(entry.name, entry.fullPath) : new (require('cordova/plugin/FileEntry'))(entry.name, entry.fullPath);
- successCallback(result);
- }
- }
- else {
- // no Entry object returned
- fail && fail(FileError.NOT_FOUND_ERR);
- }
- };
-
- // copy
- exec(success, fail, "File", "moveTo", [srcPath, parent.fullPath, name]);
-};
-
-/**
- * Copy a directory to a different location.
- *
- * @param parent
- * {DirectoryEntry} the directory to which to copy the entry
- * @param newName
- * {DOMString} new name of the entry, defaults to the current name
- * @param successCallback
- * {Function} called with the new Entry object
- * @param errorCallback
- * {Function} called with a FileError
- */
-Entry.prototype.copyTo = function(parent, newName, successCallback, errorCallback) {
- argscheck.checkArgs('oSFF', 'Entry.copyTo', arguments);
- var fail = errorCallback && function(code) {
- errorCallback(new FileError(code));
- };
-
- // source path
- var srcPath = this.fullPath,
- // entry name
- name = newName || this.name,
- // success callback
- success = function(entry) {
- if (entry) {
- if (successCallback) {
- // create appropriate Entry object
- var result = (entry.isDirectory) ? new (require('cordova/plugin/DirectoryEntry'))(entry.name, entry.fullPath) : new (require('cordova/plugin/FileEntry'))(entry.name, entry.fullPath);
- successCallback(result);
- }
- }
- else {
- // no Entry object returned
- fail && fail(FileError.NOT_FOUND_ERR);
- }
- };
-
- // copy
- exec(success, fail, "File", "copyTo", [srcPath, parent.fullPath, name]);
-};
-
-/**
- * Return a URL that can be used to identify this entry.
- */
-Entry.prototype.toURL = function() {
- // fullPath attribute contains the full URL
- return this.fullPath;
-};
-
-/**
- * Returns a URI that can be used to identify this entry.
- *
- * @param {DOMString} mimeType for a FileEntry, the mime type to be used to interpret the file, when loaded through this URI.
- * @return uri
- */
-Entry.prototype.toURI = function(mimeType) {
- console.log("DEPRECATED: Update your code to use 'toURL'");
- // fullPath attribute contains the full URI
- return this.toURL();
-};
-
-/**
- * Remove a file or directory. It is an error to attempt to delete a
- * directory that is not empty. It is an error to attempt to delete a
- * root directory of a file system.
- *
- * @param successCallback {Function} called with no parameters
- * @param errorCallback {Function} called with a FileError
- */
-Entry.prototype.remove = function(successCallback, errorCallback) {
- argscheck.checkArgs('FF', 'Entry.remove', arguments);
- var fail = errorCallback && function(code) {
- errorCallback(new FileError(code));
- };
- exec(successCallback, fail, "File", "remove", [this.fullPath]);
-};
-
-/**
- * Look up the parent DirectoryEntry of this entry.
- *
- * @param successCallback {Function} called with the parent DirectoryEntry object
- * @param errorCallback {Function} called with a FileError
- */
-Entry.prototype.getParent = function(successCallback, errorCallback) {
- argscheck.checkArgs('FF', 'Entry.getParent', arguments);
- var win = successCallback && function(result) {
- var DirectoryEntry = require('cordova/plugin/DirectoryEntry');
- var entry = new DirectoryEntry(result.name, result.fullPath);
- successCallback(entry);
- };
- var fail = errorCallback && function(code) {
- errorCallback(new FileError(code));
- };
- exec(win, fail, "File", "getParent", [this.fullPath]);
-};
-
-module.exports = Entry;
-
-});
-
-// file: lib/common/plugin/File.js
-define("cordova/plugin/File", function(require, exports, module) {
-
-/**
- * Constructor.
- * name {DOMString} name of the file, without path information
- * fullPath {DOMString} the full path of the file, including the name
- * type {DOMString} mime type
- * lastModifiedDate {Date} last modified date
- * size {Number} size of the file in bytes
- */
-
-var File = function(name, fullPath, type, lastModifiedDate, size){
- this.name = name || '';
- this.fullPath = fullPath || null;
- this.type = type || null;
- this.lastModifiedDate = lastModifiedDate || null;
- this.size = size || 0;
-
- // These store the absolute start and end for slicing the file.
- this.start = 0;
- this.end = this.size;
-};
-
-/**
- * Returns a "slice" of the file. Since Cordova Files don't contain the actual
- * content, this really returns a File with adjusted start and end.
- * Slices of slices are supported.
- * start {Number} The index at which to start the slice (inclusive).
- * end {Number} The index at which to end the slice (exclusive).
- */
-File.prototype.slice = function(start, end) {
- var size = this.end - this.start;
- var newStart = 0;
- var newEnd = size;
- if (arguments.length) {
- if (start < 0) {
- newStart = Math.max(size + start, 0);
- } else {
- newStart = Math.min(size, start);
- }
- }
-
- if (arguments.length >= 2) {
- if (end < 0) {
- newEnd = Math.max(size + end, 0);
- } else {
- newEnd = Math.min(end, size);
- }
- }
-
- var newFile = new File(this.name, this.fullPath, this.type, this.lastModifiedData, this.size);
- newFile.start = this.start + newStart;
- newFile.end = this.start + newEnd;
- return newFile;
-};
-
-
-module.exports = File;
-
-});
-
-// file: lib/common/plugin/FileEntry.js
-define("cordova/plugin/FileEntry", function(require, exports, module) {
-
-var utils = require('cordova/utils'),
- exec = require('cordova/exec'),
- Entry = require('cordova/plugin/Entry'),
- FileWriter = require('cordova/plugin/FileWriter'),
- File = require('cordova/plugin/File'),
- FileError = require('cordova/plugin/FileError');
-
-/**
- * An interface representing a file on the file system.
- *
- * {boolean} isFile always true (readonly)
- * {boolean} isDirectory always false (readonly)
- * {DOMString} name of the file, excluding the path leading to it (readonly)
- * {DOMString} fullPath the absolute full path to the file (readonly)
- * {FileSystem} filesystem on which the file resides (readonly)
- */
-var FileEntry = function(name, fullPath) {
- FileEntry.__super__.constructor.apply(this, [true, false, name, fullPath]);
-};
-
-utils.extend(FileEntry, Entry);
-
-/**
- * Creates a new FileWriter associated with the file that this FileEntry represents.
- *
- * @param {Function} successCallback is called with the new FileWriter
- * @param {Function} errorCallback is called with a FileError
- */
-FileEntry.prototype.createWriter = function(successCallback, errorCallback) {
- this.file(function(filePointer) {
- var writer = new FileWriter(filePointer);
-
- if (writer.fileName === null || writer.fileName === "") {
- errorCallback && errorCallback(new FileError(FileError.INVALID_STATE_ERR));
- } else {
- successCallback && successCallback(writer);
- }
- }, errorCallback);
-};
-
-/**
- * Returns a File that represents the current state of the file that this FileEntry represents.
- *
- * @param {Function} successCallback is called with the new File object
- * @param {Function} errorCallback is called with a FileError
- */
-FileEntry.prototype.file = function(successCallback, errorCallback) {
- var win = successCallback && function(f) {
- var file = new File(f.name, f.fullPath, f.type, f.lastModifiedDate, f.size);
- successCallback(file);
- };
- var fail = errorCallback && function(code) {
- errorCallback(new FileError(code));
- };
- exec(win, fail, "File", "getFileMetadata", [this.fullPath]);
-};
-
-
-module.exports = FileEntry;
-
-});
-
-// file: lib/common/plugin/FileError.js
-define("cordova/plugin/FileError", function(require, exports, module) {
-
-/**
- * FileError
- */
-function FileError(error) {
- this.code = error || null;
-}
-
-// File error codes
-// Found in DOMException
-FileError.NOT_FOUND_ERR = 1;
-FileError.SECURITY_ERR = 2;
-FileError.ABORT_ERR = 3;
-
-// Added by File API specification
-FileError.NOT_READABLE_ERR = 4;
-FileError.ENCODING_ERR = 5;
-FileError.NO_MODIFICATION_ALLOWED_ERR = 6;
-FileError.INVALID_STATE_ERR = 7;
-FileError.SYNTAX_ERR = 8;
-FileError.INVALID_MODIFICATION_ERR = 9;
-FileError.QUOTA_EXCEEDED_ERR = 10;
-FileError.TYPE_MISMATCH_ERR = 11;
-FileError.PATH_EXISTS_ERR = 12;
-
-module.exports = FileError;
-
-});
-
-// file: lib/common/plugin/FileReader.js
-define("cordova/plugin/FileReader", function(require, exports, module) {
-
-var exec = require('cordova/exec'),
- modulemapper = require('cordova/modulemapper'),
- utils = require('cordova/utils'),
- File = require('cordova/plugin/File'),
- FileError = require('cordova/plugin/FileError'),
- ProgressEvent = require('cordova/plugin/ProgressEvent'),
- origFileReader = modulemapper.getOriginalSymbol(this, 'FileReader');
-
-/**
- * This class reads the mobile device file system.
- *
- * For Android:
- * The root directory is the root of the file system.
- * To read from the SD card, the file name is "sdcard/my_file.txt"
- * @constructor
- */
-var FileReader = function() {
- this._readyState = 0;
- this._error = null;
- this._result = null;
- this._fileName = '';
- this._realReader = origFileReader ? new origFileReader() : {};
-};
-
-// States
-FileReader.EMPTY = 0;
-FileReader.LOADING = 1;
-FileReader.DONE = 2;
-
-utils.defineGetter(FileReader.prototype, 'readyState', function() {
- return this._fileName ? this._readyState : this._realReader.readyState;
-});
-
-utils.defineGetter(FileReader.prototype, 'error', function() {
- return this._fileName ? this._error: this._realReader.error;
-});
-
-utils.defineGetter(FileReader.prototype, 'result', function() {
- return this._fileName ? this._result: this._realReader.result;
-});
-
-function defineEvent(eventName) {
- utils.defineGetterSetter(FileReader.prototype, eventName, function() {
- return this._realReader[eventName] || null;
- }, function(value) {
- this._realReader[eventName] = value;
- });
-}
-defineEvent('onloadstart'); // When the read starts.
-defineEvent('onprogress'); // While reading (and decoding) file or fileBlob data, and reporting partial file data (progress.loaded/progress.total)
-defineEvent('onload'); // When the read has successfully completed.
-defineEvent('onerror'); // When the read has failed (see errors).
-defineEvent('onloadend'); // When the request has completed (either in success or failure).
-defineEvent('onabort'); // When the read has been aborted. For instance, by invoking the abort() method.
-
-function initRead(reader, file) {
- // Already loading something
- if (reader.readyState == FileReader.LOADING) {
- throw new FileError(FileError.INVALID_STATE_ERR);
- }
-
- reader._result = null;
- reader._error = null;
- reader._readyState = FileReader.LOADING;
-
- if (typeof file == 'string') {
- // Deprecated in Cordova 2.4.
- console.warn('Using a string argument with FileReader.readAs functions is deprecated.');
- reader._fileName = file;
- } else if (typeof file.fullPath == 'string') {
- reader._fileName = file.fullPath;
- } else {
- reader._fileName = '';
- return true;
- }
-
- reader.onloadstart && reader.onloadstart(new ProgressEvent("loadstart", {target:reader}));
-}
-
-/**
- * Abort reading file.
- */
-FileReader.prototype.abort = function() {
- if (origFileReader && !this._fileName) {
- return this._realReader.abort();
- }
- this._result = null;
-
- if (this._readyState == FileReader.DONE || this._readyState == FileReader.EMPTY) {
- return;
- }
-
- this._readyState = FileReader.DONE;
-
- // If abort callback
- if (typeof this.onabort === 'function') {
- this.onabort(new ProgressEvent('abort', {target:this}));
- }
- // If load end callback
- if (typeof this.onloadend === 'function') {
- this.onloadend(new ProgressEvent('loadend', {target:this}));
- }
-};
-
-/**
- * Read text file.
- *
- * @param file {File} File object containing file properties
- * @param encoding [Optional] (see http://www.iana.org/assignments/character-sets)
- */
-FileReader.prototype.readAsText = function(file, encoding) {
- if (initRead(this, file)) {
- return this._realReader.readAsText(file, encoding);
- }
-
- // Default encoding is UTF-8
- var enc = encoding ? encoding : "UTF-8";
- var me = this;
- var execArgs = [this._fileName, enc, file.start, file.end];
-
- // Read file
- exec(
- // Success callback
- function(r) {
- // If DONE (cancelled), then don't do anything
- if (me._readyState === FileReader.DONE) {
- return;
- }
-
- // Save result
- me._result = r;
-
- // If onload callback
- if (typeof me.onload === "function") {
- me.onload(new ProgressEvent("load", {target:me}));
- }
-
- // DONE state
- me._readyState = FileReader.DONE;
-
- // If onloadend callback
- if (typeof me.onloadend === "function") {
- me.onloadend(new ProgressEvent("loadend", {target:me}));
- }
- },
- // Error callback
- function(e) {
- // If DONE (cancelled), then don't do anything
- if (me._readyState === FileReader.DONE) {
- return;
- }
-
- // DONE state
- me._readyState = FileReader.DONE;
-
- // null result
- me._result = null;
-
- // Save error
- me._error = new FileError(e);
-
- // If onerror callback
- if (typeof me.onerror === "function") {
- me.onerror(new ProgressEvent("error", {target:me}));
- }
-
- // If onloadend callback
- if (typeof me.onloadend === "function") {
- me.onloadend(new ProgressEvent("loadend", {target:me}));
- }
- }, "File", "readAsText", execArgs);
-};
-
-
-/**
- * Read file and return data as a base64 encoded data url.
- * A data url is of the form:
- * data:[<mediatype>][;base64],<data>
- *
- * @param file {File} File object containing file properties
- */
-FileReader.prototype.readAsDataURL = function(file) {
- if (initRead(this, file)) {
- return this._realReader.readAsDataURL(file);
- }
-
- var me = this;
- var execArgs = [this._fileName, file.start, file.end];
-
- // Read file
- exec(
- // Success callback
- function(r) {
- // If DONE (cancelled), then don't do anything
- if (me._readyState === FileReader.DONE) {
- return;
- }
-
- // DONE state
- me._readyState = FileReader.DONE;
-
- // Save result
- me._result = r;
-
- // If onload callback
- if (typeof me.onload === "function") {
- me.onload(new ProgressEvent("load", {target:me}));
- }
-
- // If onloadend callback
- if (typeof me.onloadend === "function") {
- me.onloadend(new ProgressEvent("loadend", {target:me}));
- }
- },
- // Error callback
- function(e) {
- // If DONE (cancelled), then don't do anything
- if (me._readyState === FileReader.DONE) {
- return;
- }
-
- // DONE state
- me._readyState = FileReader.DONE;
-
- me._result = null;
-
- // Save error
- me._error = new FileError(e);
-
- // If onerror callback
- if (typeof me.onerror === "function") {
- me.onerror(new ProgressEvent("error", {target:me}));
- }
-
- // If onloadend callback
- if (typeof me.onloadend === "function") {
- me.onloadend(new ProgressEvent("loadend", {target:me}));
- }
- }, "File", "readAsDataURL", execArgs);
-};
-
-/**
- * Read file and return data as a binary data.
- *
- * @param file {File} File object containing file properties
- */
-FileReader.prototype.readAsBinaryString = function(file) {
- if (initRead(this, file)) {
- return this._realReader.readAsBinaryString(file);
- }
-
- var me = this;
- var execArgs = [this._fileName, file.start, file.end];
-
- // Read file
- exec(
- // Success callback
- function(r) {
- // If DONE (cancelled), then don't do anything
- if (me._readyState === FileReader.DONE) {
- return;
- }
-
- // DONE state
- me._readyState = FileReader.DONE;
-
- me._result = r;
-
- // If onload callback
- if (typeof me.onload === "function") {
- me.onload(new ProgressEvent("load", {target:me}));
- }
-
- // If onloadend callback
- if (typeof me.onloadend === "function") {
- me.onloadend(new ProgressEvent("loadend", {target:me}));
- }
- },
- // Error callback
- function(e) {
- // If DONE (cancelled), then don't do anything
- if (me._readyState === FileReader.DONE) {
- return;
- }
-
- // DONE state
- me._readyState = FileReader.DONE;
-
- me._result = null;
-
- // Save error
- me._error = new FileError(e);
-
- // If onerror callback
- if (typeof me.onerror === "function") {
- me.onerror(new ProgressEvent("error", {target:me}));
- }
-
- // If onloadend callback
- if (typeof me.onloadend === "function") {
- me.onloadend(new ProgressEvent("loadend", {target:me}));
- }
- }, "File", "readAsBinaryString", execArgs);
-};
-
-/**
- * Read file and return data as a binary data.
- *
- * @param file {File} File object containing file properties
- */
-FileReader.prototype.readAsArrayBuffer = function(file) {
- if (initRead(this, file)) {
- return this._realReader.readAsArrayBuffer(file);
- }
-
- var me = this;
- var execArgs = [this._fileName, file.start, file.end];
-
- // Read file
- exec(
- // Success callback
- function(r) {
- // If DONE (cancelled), then don't do anything
- if (me._readyState === FileReader.DONE) {
- return;
- }
-
- // DONE state
- me._readyState = FileReader.DONE;
-
- me._result = r;
-
- // If onload callback
- if (typeof me.onload === "function") {
- me.onload(new ProgressEvent("load", {target:me}));
- }
-
- // If onloadend callback
- if (typeof me.onloadend === "function") {
-
<TRUNCATED>