added tests + docs

This commit is contained in:
Steven Gill 2013-05-23 15:23:28 -07:00
parent 0b6342e56c
commit acf67ccd52
27 changed files with 5061 additions and 0 deletions

50
docs/camera.cleanup.md Normal file
View File

@ -0,0 +1,50 @@
---
license: 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.
---
camera.cleanup
=================
Cleans up the image files that were taken by the camera, that were stored in a temporary storage location.
navigator.camera.cleanup( cameraSuccess, cameraError );
Description
-----------
Cleans up the image files stored in the temporary storage location, when the function `camera.getPicture` is used with `Camera.sourceType = Camera.PictureSourceType.CAMERA` and `Camera.destinationType = Camera.DestinationType.FILE_URI`
Supported Platforms
-------------------
- iOS
Example
-------------
navigator.camera.cleanup(onSuccess, onFail);
function onSuccess() {
console.log("Camera cleanup success.")
}
function onFail(message) {
alert('Failed because: ' + message);
}

220
docs/camera.getPicture.md Normal file
View File

@ -0,0 +1,220 @@
---
license: 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.
---
camera.getPicture
=================
Takes a photo using the camera or retrieves a photo from the device's album.
The image is passed to the success callback as a base64 encoded `String` or as the URI of an image file.
The method itself returns a CameraPopoverHandle object, which can be used to reposition the file selection popover.
navigator.camera.getPicture( cameraSuccess, cameraError, [ cameraOptions ] );
Description
-----------
Function `camera.getPicture` opens the device's default camera application so that the user can take a picture (if `Camera.sourceType = Camera.PictureSourceType.CAMERA`, which is the default). Once the photo is taken, the camera application closes and your application is restored.
If `Camera.sourceType = Camera.PictureSourceType.PHOTOLIBRARY` or `Camera.PictureSourceType.SAVEDPHOTOALBUM`, then a photo chooser dialog is shown, from which a photo from the album can be selected. A `CameraPopoverHandle` object, which can be used to reposition the photo chooser dialog (eg. when the device orientation changes) is returned by `camera.getPicture`.
The return value will be sent to the `cameraSuccess` function, in one of the following formats, depending on the `cameraOptions` you specify:
- A `String` containing the Base64 encoded photo image.
- A `String` representing the image file location on local storage (default).
You can do whatever you want with the encoded image or URI, for example:
- Render the image in an `<img>` tag _(see example below)_
- Save the data locally (`LocalStorage`, [Lawnchair](http://brianleroux.github.com/lawnchair/), etc)
- Post the data to a remote server
__Note:__ The image quality of pictures taken using the camera on newer devices is quite good, and images from the Photo Album will not be downscaled to a lower quality, even if a quality parameter is specified. ___Encoding such images using Base64 has caused memory issues on many newer devices. Therefore, using FILE\_URI as the 'Camera.destinationType' is highly recommended.___
Supported Platforms
-------------------
- Android
- Blackberry WebWorks (OS 5.0 and higher)
- iOS
- Windows Phone 7 and 8
- Bada 1.2
- webOS
- Tizen
- Windows 8
iOS Quirks
----------
Including a JavaScript alert() in either of the callback functions can cause problems. Wrap the alert in a setTimeout() to allow the iOS image picker or popover to fully close before the alert is displayed:
setTimeout(function() {
// do your thing here!
}, 0);
Windows Phone 7 Quirks
----------------------
Invoking the native camera application while your device is connected
via Zune will not work, and the error callback will be triggered.
Tizen Quirks
----------------------
Only 'destinationType: Camera.DestinationType.FILE_URI' and 'sourceType: Camera.PictureSourceType.PHOTOLIBRARY' are supported.
Quick Example
-------------
Take photo and retrieve Base64-encoded image:
navigator.camera.getPicture(onSuccess, onFail, { quality: 50,
destinationType: Camera.DestinationType.DATA_URL
});
function onSuccess(imageData) {
var image = document.getElementById('myImage');
image.src = "data:image/jpeg;base64," + imageData;
}
function onFail(message) {
alert('Failed because: ' + message);
}
Take photo and retrieve image file location:
navigator.camera.getPicture(onSuccess, onFail, { quality: 50,
destinationType: Camera.DestinationType.FILE_URI });
function onSuccess(imageURI) {
var image = document.getElementById('myImage');
image.src = imageURI;
}
function onFail(message) {
alert('Failed because: ' + message);
}
Full Example
------------
<!DOCTYPE html>
<html>
<head>
<title>Capture Photo</title>
<script type="text/javascript" charset="utf-8" src="cordova-x.x.x.js"></script>
<script type="text/javascript" charset="utf-8">
var pictureSource; // picture source
var destinationType; // sets the format of returned value
// Wait for Cordova to connect with the device
//
document.addEventListener("deviceready",onDeviceReady,false);
// Cordova is ready to be used!
//
function onDeviceReady() {
pictureSource=navigator.camera.PictureSourceType;
destinationType=navigator.camera.DestinationType;
}
// Called when a photo is successfully retrieved
//
function onPhotoDataSuccess(imageData) {
// Uncomment to view the base64 encoded image data
// console.log(imageData);
// Get image handle
//
var smallImage = document.getElementById('smallImage');
// Unhide image elements
//
smallImage.style.display = 'block';
// Show the captured photo
// The inline CSS rules are used to resize the image
//
smallImage.src = "data:image/jpeg;base64," + imageData;
}
// Called when a photo is successfully retrieved
//
function onPhotoURISuccess(imageURI) {
// Uncomment to view the image file URI
// console.log(imageURI);
// Get image handle
//
var largeImage = document.getElementById('largeImage');
// Unhide image elements
//
largeImage.style.display = 'block';
// Show the captured photo
// The inline CSS rules are used to resize the image
//
largeImage.src = imageURI;
}
// A button will call this function
//
function capturePhoto() {
// Take picture using device camera and retrieve image as base64-encoded string
navigator.camera.getPicture(onPhotoDataSuccess, onFail, { quality: 50,
destinationType: destinationType.DATA_URL });
}
// A button will call this function
//
function capturePhotoEdit() {
// Take picture using device camera, allow edit, and retrieve image as base64-encoded string
navigator.camera.getPicture(onPhotoDataSuccess, onFail, { quality: 20, allowEdit: true,
destinationType: destinationType.DATA_URL });
}
// A button will call this function
//
function getPhoto(source) {
// Retrieve image file location from specified source
navigator.camera.getPicture(onPhotoURISuccess, onFail, { quality: 50,
destinationType: destinationType.FILE_URI,
sourceType: source });
}
// Called if something bad happens.
//
function onFail(message) {
alert('Failed because: ' + message);
}
</script>
</head>
<body>
<button onclick="capturePhoto();">Capture Photo</button> <br>
<button onclick="capturePhotoEdit();">Capture Editable Photo</button> <br>
<button onclick="getPhoto(pictureSource.PHOTOLIBRARY);">From Photo Library</button><br>
<button onclick="getPhoto(pictureSource.SAVEDPHOTOALBUM);">From Photo Album</button><br>
<img style="display:none;width:60px;height:60px;" id="smallImage" src="" />
<img style="display:none;" id="largeImage" src="" />
</body>
</html>

97
docs/camera.md Normal file
View File

@ -0,0 +1,97 @@
---
license: 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.
---
Camera
======
> The `camera` object provides access to the device's default camera application.
Methods
-------
- camera.getPicture
- camera.cleanup
Permissions
-----------
### Android
#### app/res/xml/config.xml
<plugin name="Camera" value="org.apache.cordova.CameraLauncher" />
#### app/AndroidManifest
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
### Bada
#### manifest.xml
<Privilege>
<Name>CAMERA</Name>
</Privilege>
<Privilege>
<Name>RECORDING</Name>
</Privilege>
### BlackBerry WebWorks
#### www/plugins.xml
<plugin name="Camera" value="org.apache.cordova.camera.Camera" />
#### www/config.xml
<feature id="blackberry.media.camera" />
<rim:permissions>
<rim:permit>use_camera</rim:permit>
</rim:permissions>
### iOS
#### config.xml
<plugin name="Camera" value="CDVCamera" />
### webOS
No permissions are required.
### Windows Phone
#### Properties/WPAppManifest.xml
<Capabilities>
<Capability Name="ID_CAP_ISV_CAMERA" />
<Capability Name="ID_HW_FRONTCAMERA" />
</Capabilities>
Reference: [Application Manifest for Windows Phone](http://msdn.microsoft.com/en-us/library/ff769509%28v=vs.92%29.aspx)
### Tizen
#### config.xml
<feature name="http://tizen.org/api/application" required="true"/>
<feature name="http://tizen.org/api/application.launch" required="true"/>
Reference: [Application Manifest for Tizen Web Application](https://developer.tizen.org/help/topic/org.tizen.help.gs/Creating%20a%20Project.html?path=0_1_1_3#8814682_CreatingaProject-EditingconfigxmlFeatures)

View File

@ -0,0 +1,68 @@
---
license: 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.
---
CameraPopoverHandle
===================
A handle to the popover dialog created by `camera.getPicture`.
Methods
-------
- __setPosition:__ Set the position of the popover.
Supported Platforms
-------------------
- iOS
setPosition
-----------
Set the position of the popover.
__Parameters:__
- cameraPopoverOptions - the CameraPopoverOptions specifying the new position
Quick Example
-------------
var cameraPopoverOptions = new CameraPopoverOptions(300, 300, 100, 100, Camera.PopoverArrowDirection.ARROW_ANY);
cameraPopoverHandle.setPosition(cameraPopoverOptions);
Full Example
------------
function onSuccess(imageData) {
// Do stuff with the image!
}
function onFail(message) {
alert('Failed to get the picture: ' + message);
}
var cameraPopoverHandle = navigator.camera.getPicture(onSuccess, onFail,
{ destinationType: Camera.DestinationType.FILE_URI,
sourceType: Camera.PictureSourceType.PHOTOLIBRARY });
// Reposition the popover if the orientation changes.
window.onorientationchange = function() {
var cameraPopoverOptions = new CameraPopoverOptions(0, 0, 100, 100, 0);
cameraPopoverHandle.setPosition(cameraPopoverOptions);
}

View File

@ -0,0 +1,71 @@
---
license: 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.
---
CameraPopoverOptions
====================
Parameters only used by iOS to specify the anchor element location and arrow direction of popover used on iPad when selecting images from the library or album.
{ x : 0,
y : 32,
width : 320,
height : 480,
arrowDir : Camera.PopoverArrowDirection.ARROW_ANY
};
CameraPopoverOptions
--------------------
- __x:__ x pixel coordinate of element on the screen to anchor popover onto. (`Number`)
- __y:__ y pixel coordinate of element on the screen to anchor popover onto. (`Number`)
- __width:__ width, in pixels, of the element on the screen to anchor popover onto. (`Number`)
- __height:__ height, in pixels, of the element on the screen to anchor popover onto. (`Number`)
- __arrowDir:__ Direction the arrow on the popover should point. Defined in Camera.PopoverArrowDirection (`Number`)
Camera.PopoverArrowDirection = {
ARROW_UP : 1, // matches iOS UIPopoverArrowDirection constants
ARROW_DOWN : 2,
ARROW_LEFT : 4,
ARROW_RIGHT : 8,
ARROW_ANY : 15
};
Note that the size of the popover may change to adjust to the direction of the arrow and orientation of the screen. Make sure to account for orientation changes when specifying the anchor element location.
Quick Example
-------------
var popover = new CameraPopoverOptions(300,300,100,100,Camera.PopoverArrowDirection.ARROW_ANY);
var options = { quality: 50, destinationType: Camera.DestinationType.DATA_URL,sourceType: Camera.PictureSource.SAVEDPHOTOALBUM, popoverOptions : popover };
navigator.camera.getPicture(onSuccess, onFail, options);
function onSuccess(imageData) {
var image = document.getElementById('myImage');
image.src = "data:image/jpeg;base64," + imageData;
}
function onFail(message) {
alert('Failed because: ' + message);
}

View File

@ -0,0 +1,32 @@
---
license: 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.
---
cameraError
===========
onError callback function that provides an error message.
function(message) {
// Show a helpful message
}
Parameters
----------
- __message:__ The message is provided by the device's native code. (`String`)

View File

@ -0,0 +1,136 @@
---
license: 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.
---
cameraOptions
=============
Optional parameters to customize the camera settings.
{ quality : 75,
destinationType : Camera.DestinationType.DATA_URL,
sourceType : Camera.PictureSourceType.CAMERA,
allowEdit : true,
encodingType: Camera.EncodingType.JPEG,
targetWidth: 100,
targetHeight: 100,
popoverOptions: CameraPopoverOptions,
saveToPhotoAlbum: false };
Options
-------
- __quality:__ Quality of saved image. Range is [0, 100]. (`Number`)
- __destinationType:__ Choose the format of the return value. Defined in navigator.camera.DestinationType (`Number`)
Camera.DestinationType = {
DATA_URL : 0, // Return image as base64 encoded string
FILE_URI : 1, // Return image file URI
NATIVE_URI : 2 // Return image native URI (eg. assets-library:// on iOS or content:// on Android)
};
- __sourceType:__ Set the source of the picture. Defined in nagivator.camera.PictureSourceType (`Number`)
Camera.PictureSourceType = {
PHOTOLIBRARY : 0,
CAMERA : 1,
SAVEDPHOTOALBUM : 2
};
- __allowEdit:__ Allow simple editing of image before selection. (`Boolean`)
- __encodingType:__ Choose the encoding of the returned image file. Defined in navigator.camera.EncodingType (`Number`)
Camera.EncodingType = {
JPEG : 0, // Return JPEG encoded image
PNG : 1 // Return PNG encoded image
};
- __targetWidth:__ Width in pixels to scale image. Must be used with targetHeight. Aspect ratio is maintained. (`Number`)
- __targetHeight:__ Height in pixels to scale image. Must be used with targetWidth. Aspect ratio is maintained. (`Number`)
- __mediaType:__ Set the type of media to select from. Only works when PictureSourceType is PHOTOLIBRARY or SAVEDPHOTOALBUM. Defined in nagivator.camera.MediaType (`Number`)
Camera.MediaType = {
PICTURE: 0, // allow selection of still pictures only. DEFAULT. Will return format specified via DestinationType
VIDEO: 1, // allow selection of video only, WILL ALWAYS RETURN FILE_URI
ALLMEDIA : 2 // allow selection from all media types
};
- __correctOrientation:__ Rotate the image to correct for the orientation of the device during capture. (`Boolean`)
- __saveToPhotoAlbum:__ Save the image to the photo album on the device after capture. (`Boolean`)
- __popoverOptions:__ iOS only options to specify popover location in iPad. Defined in CameraPopoverOptions.
- __cameraDirection:__ Choose the camera to use (front- or back-facing). Defined in navigator.camera.Direction (`Number`)
Camera.Direction = {
BACK : 0, // Use the back-facing camera
FRONT : 1 // Use the front-facing camera
};
Android Quirks
--------------
- Ignores the `allowEdit` parameter.
- Camera.PictureSourceType.PHOTOLIBRARY and Camera.PictureSourceType.SAVEDPHOTOALBUM both display the same photo album.
BlackBerry Quirks
-----------------
- Ignores the `quality` parameter.
- Ignores the `sourceType` parameter.
- Ignores the `allowEdit` parameter.
- Application must have key injection permissions to close native Camera application after photo is taken.
- Using Large image sizes may result in inability to encode image on later model devices with high resolution cameras (e.g. Torch 9800).
- Camera.MediaType is not supported.
- Ignores the `correctOrientation` parameter.
- Ignores the `cameraDirection` parameter.
webOS Quirks
-----------
- Ignores the `quality` parameter.
- Ignores the `sourceType` parameter.
- Ignores the `allowEdit` parameter.
- Camera.MediaType is not supported.
- Ignores the `correctOrientation` parameter.
- Ignores the `saveToPhotoAlbum` parameter.
- Ignores the `cameraDirection` parameter.
iOS Quirks
--------------
- Set `quality` below 50 to avoid memory error on some devices.
- When `destinationType.FILE_URI` is used, photos are saved in the application's temporary directory.
Windows Phone 7 and 8 Quirks
--------------
- Ignores the `allowEdit` parameter.
- Ignores the `correctOrientation` parameter.
- Ignores the `cameraDirection` parameter.
Bada 1.2 Quirks
--------------
- options not supported
- always returns a FILE URI
Tizen Quirks
--------------
- options not supported
- always returns a FILE URI

View File

@ -0,0 +1,42 @@
---
license: 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.
---
cameraSuccess
=============
onSuccess callback function that provides the image data.
function(imageData) {
// Do something with the image
}
Parameters
----------
- __imageData:__ Base64 encoding of the image data, OR the image file URI, depending on `cameraOptions` used. (`String`)
Example
-------
// Show image
//
function cameraCallback(imageData) {
var image = document.getElementById('myImage');
image.src = "data:image/jpeg;base64," + imageData;
}

View File

@ -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);

View File

@ -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];
}
};

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;
};

59
test/autotest/index.html Normal file
View File

@ -0,0 +1,59 @@
<!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="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-incl.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>

81
test/autotest/jasmine.css Normal file
View File

@ -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; }

2530
test/autotest/jasmine.js Normal file

File diff suppressed because it is too large Load Diff

BIN
test/autotest/pages/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -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: 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-incl.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>

View File

@ -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.
*
*/
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);
}

BIN
test/autotest/tests/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,70 @@
/*
*
* 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('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("camera.spec.1 window.Camera should exist", function() {
expect(window.Camera).toBeDefined();
});
it("camera.spec.2 should contain three DestinationType constants", function() {
expect(Camera.DestinationType.DATA_URL).toBe(0);
expect(Camera.DestinationType.FILE_URI).toBe(1);
expect(Camera.DestinationType.NATIVE_URI).toBe(2);
expect(navigator.camera.DestinationType.DATA_URL).toBe(0);
expect(navigator.camera.DestinationType.FILE_URI).toBe(1);
expect(navigator.camera.DestinationType.NATIVE_URI).toBe(2);
});
it("camera.spec.3 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("camera.spec.4 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("camera.spec.5 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);
});
});

392
test/camera/index.html Normal file
View File

@ -0,0 +1,392 @@
<!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 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-incl.js"></script>
<script type="text/javascript" charset="utf-8">
var deviceReady = false;
var platformId = cordova.require('cordova/platform').id;
var CameraPopoverOptions = cordova.require('cordova/plugin/CameraPopoverOptions');
var pictureUrl = null;
var fileObj = null;
var fileEntry = null;
var pageStartTime = +new Date();
//default camera options
var camQualityDefault = ['quality value', 50];
var camDestinationTypeDefault = ['FILE_URI', 1];
var camPictureSourceTypeDefault = ['CAMERA', 1];
var camAllowEditDefault = ['allowEdit', false];
var camEncodingTypeDefault = ['JPEG', 0];
var camMediaTypeDefault = ['mediaType', 0];
var camCorrectOrientationDefault = ['correctOrientation', false];
var camSaveToPhotoAlbumDefault = ['saveToPhotoAlbum', true];
//-------------------------------------------------------------------------
// Camera
//-------------------------------------------------------------------------
function log(value) {
console.log(value);
document.getElementById('camera_status').textContent += (new Date() - pageStartTime) / 1000 + ': ' + value + '\n';
}
function clearStatus() {
document.getElementById('camera_status').innerHTML = '';
document.getElementById('camera_image').src = 'about:blank';
var canvas = document.getElementById('canvas');
canvas.width = canvas.height = 1;
pictureUrl = null;
fileObj = null;
fileEntry = null;
}
function setPicture(url, callback) {
try {
window.atob(url);
// if we got here it is a base64 string (DATA_URL)
url = "data:image/jpeg;base64," + url;
} catch (e) {
// not DATA_URL
log('URL: ' + url.slice(0, 100));
}
pictureUrl = url;
var img = document.getElementById('camera_image');
var startTime = new Date();
img.src = url;
img.onloadend = function() {
log('Image tag load time: ' + (new Date() - startTime));
callback && callback();
};
}
function onGetPictureError(e) {
log('Error getting picture: ' + e.code);
}
function getPictureWin(data) {
setPicture(data);
// TODO: Fix resolveLocalFileSystemURI to work with native-uri.
if (pictureUrl.indexOf('file:') == 0) {
resolveLocalFileSystemURI(data, function(e) {
fileEntry = e;
logCallback('resolveLocalFileSystemURI()', true)(e);
}, logCallback('resolveLocalFileSystemURI()', false));
} else if (pictureUrl.indexOf('data:image/jpeg;base64' == 0)) {
// do nothing
} else {
var path = pictureUrl.replace(/^file:\/\/(localhost)?/, '').replace(/%20/g, ' ');
fileEntry = new FileEntry('image_name.png', path);
}
}
function getPicture() {
clearStatus();
var options = extractOptions();
log('Getting picture with options: ' + JSON.stringify(options));
var popoverHandle = navigator.camera.getPicture(getPictureWin, onGetPictureError, options);
// Reposition the popover if the orientation changes.
window.onorientationchange = function() {
var newPopoverOptions = new CameraPopoverOptions(0, 0, 100, 100, 0);
popoverHandle.setPosition(newPopoverOptions);
}
}
function uploadImage() {
var ft = new FileTransfer(),
uploadcomplete=0,
progress = 0,
options = new FileUploadOptions();
options.fileKey="photo";
options.fileName='test.jpg';
options.mimeType="image/jpeg";
ft.onprogress = function(progressEvent) {
log('progress: ' + progressEvent.loaded + ' of ' + progressEvent.total);
};
var server = "http://cordova-filetransfer.jitsu.com";
ft.upload(pictureUrl, server + '/upload', win, fail, options);
function win(information_back){
log('upload complete');
}
function fail(message) {
log('upload failed: ' + JSON.stringify(message));
}
}
function logCallback(apiName, success) {
return function() {
log('Call to ' + apiName + (success ? ' success: ' : ' failed: ') + JSON.stringify([].slice.call(arguments)));
};
}
/**
* Select image from library using a NATIVE_URI destination type
* This calls FileEntry.getMetadata, FileEntry.setMetadata, FileEntry.getParent, FileEntry.file, and FileReader.readAsDataURL.
*/
function readFile() {
function onFileReadAsDataURL(evt) {
var img = document.getElementById('camera_image');
img.style.visibility = "visible";
img.style.display = "block";
img.src = evt.target.result;
log("FileReader.readAsDataURL success");
};
function onFileReceived(file) {
log('Got file: ' + JSON.stringify(file));
fileObj = file;
var reader = new FileReader();
reader.onload = function() {
log('FileReader.readAsDataURL() - length = ' + reader.result.length);
};
reader.onerror = logCallback('FileReader.readAsDataURL', false);
reader.readAsDataURL(file);
};
// Test out onFileReceived when the file object was set via a native <input> elements.
if (fileObj) {
onFileReceived(fileObj);
} else {
fileEntry.file(onFileReceived, logCallback('FileEntry.file', false));
}
}
function getFileInfo() {
// Test FileEntry API here.
fileEntry.getMetadata(logCallback('FileEntry.getMetadata', true), logCallback('FileEntry.getMetadata', false));
fileEntry.setMetadata(logCallback('FileEntry.setMetadata', true), logCallback('FileEntry.setMetadata', false), { "com.apple.MobileBackup": 1 });
fileEntry.getParent(logCallback('FileEntry.getParent', true), logCallback('FileEntry.getParent', false));
fileEntry.getParent(logCallback('FileEntry.getParent', true), logCallback('FileEntry.getParent', false));
};
/**
* Copy image from library using a NATIVE_URI destination type
* This calls FileEntry.copyTo and FileEntry.moveTo.
*/
function copyImage() {
var onFileSystemReceived = function(fileSystem) {
var destDirEntry = fileSystem.root;
// Test FileEntry API here.
fileEntry.copyTo(destDirEntry, 'copied_file.png', logCallback('FileEntry.copyTo', true), logCallback('FileEntry.copyTo', false));
fileEntry.moveTo(destDirEntry, 'moved_file.png', logCallback('FileEntry.moveTo', true), logCallback('FileEntry.moveTo', false));
};
window.requestFileSystem(LocalFileSystem.TEMPORARY, 0, onFileSystemReceived, null);
};
/**
* Write image to library using a NATIVE_URI destination type
* This calls FileEntry.createWriter, FileWriter.write, and FileWriter.truncate.
*/
function writeImage() {
var onFileWriterReceived = function(fileWriter) {
fileWriter.onwrite = logCallback('FileWriter.write', true);
fileWriter.onerror = logCallback('FileWriter.write', false);
fileWriter.write("some text!");
};
var onFileTruncateWriterReceived = function(fileWriter) {
fileWriter.onwrite = logCallback('FileWriter.truncate', true);
fileWriter.onerror = logCallback('FileWriter.truncate', false);
fileWriter.truncate(10);
};
fileEntry.createWriter(onFileWriterReceived, logCallback('FileEntry.createWriter', false));
fileEntry.createWriter(onFileTruncateWriterReceived, null);
};
function displayImageUsingCanvas() {
var canvas = document.getElementById('canvas');
var img = document.getElementById('camera_image');
var w = img.width;
var h = img.height;
h = 100 / w * h;
w = 100;
canvas.width = w;
canvas.height= h;
var context = canvas.getContext('2d');
context.drawImage(img, 0, 0, w, h);
};
/**
* Remove image from library using a NATIVE_URI destination type
* This calls FileEntry.remove.
*/
function removeImage() {
fileEntry.remove(logCallback('FileEntry.remove', true), logCallback('FileEntry.remove', false));
};
function testInputTag(inputEl) {
clearStatus();
// iOS 6 likes to dead-lock in the onchange context if you
// do any alerts or try to remote-debug.
window.setTimeout(function() {
testNativeFile2(inputEl);
}, 0);
};
function testNativeFile2(inputEl) {
if (!inputEl.value) {
alert('No file selected.');
return;
}
fileObj = inputEl.files[0];
if (!fileObj) {
alert('Got value but no file.');
return;
}
var URLApi = window.URL || window.webkitURL;
if (URLApi) {
var blobURL = URLApi.createObjectURL(fileObj);
if (blobURL) {
setPicture(blobURL, function() {
URLApi.revokeObjectURL(blobURL);
});
} else {
log('URL.createObjectURL returned null');
}
} else {
log('URL.createObjectURL() not supported.');
}
}
function extractOptions() {
var els = document.querySelectorAll('#image-options select');
var ret = {};
for (var i = 0, el; el = els[i]; ++i) {
var value = el.value;
if (value === '') continue;
if (el.isBool) {
ret[el.keyName] = !!value;
} else {
ret[el.keyName] = +value;
}
}
return ret;
}
function createOptionsEl(name, values, selectionDefault) {
var container = document.createElement('div');
container.style.display = 'inline-block';
container.appendChild(document.createTextNode(name + ': '));
var select = document.createElement('select');
select.keyName = name;
container.appendChild(select);
// if we didn't get a default value, insert the blank <default> entry
if (selectionDefault == undefined) {
var opt = document.createElement('option');
opt.value = '';
opt.text = '<default>';
select.appendChild(opt);
}
select.isBool = typeof values == 'boolean';
if (select.isBool) {
values = {'true': 1, 'false': 0};
}
for (var k in values) {
var opt = document.createElement('option');
opt.value = values[k];
opt.textContent = k;
if (selectionDefault) {
if (selectionDefault[0] == k) {
opt.selected = true;
}
}
select.appendChild(opt);
}
var optionsDiv = document.getElementById('image-options');
optionsDiv.appendChild(container);
}
/**
* Function called when page has finished loading.
*/
function init() {
document.addEventListener("deviceready", function() {
deviceReady = true;
console.log("Device="+device.platform+" "+device.version);
createOptionsEl('sourceType', Camera.PictureSourceType, camPictureSourceTypeDefault);
createOptionsEl('destinationType', Camera.DestinationType, camDestinationTypeDefault);
createOptionsEl('encodingType', Camera.EncodingType, camEncodingTypeDefault);
createOptionsEl('mediaType', Camera.MediaType, camMediaTypeDefault);
createOptionsEl('quality', {'0': 0, '50': 50, '80': 80, '100': 100}, camQualityDefault);
createOptionsEl('targetWidth', {'50': 50, '200': 200, '800': 800, '2048': 2048});
createOptionsEl('targetHeight', {'50': 50, '200': 200, '800': 800, '2048': 2048});
createOptionsEl('allowEdit', true, camAllowEditDefault);
createOptionsEl('correctOrientation', true, camCorrectOrientationDefault);
createOptionsEl('saveToPhotoAlbum', true, camSaveToPhotoAlbumDefault);
createOptionsEl('cameraDirection', Camera.Direction);
}, false);
window.setTimeout(function() {
if (!deviceReady) {
alert("Error: Apache Cordova did not initialize. Demo will not run correctly.");
}
},1000);
};
</script>
</head>
<body onload="init();" id="stage" class="theme">
<h1>Camera</h1>
<div id="info" style="white-space: pre-wrap">
<b>Status:</b> <div id="camera_status"></div>
img: <img width="100" id="camera_image">
canvas: <canvas id="canvas" width="1" height="1"></canvas>
</div>
<h2>Cordova Camera API</h2>
<div id="image-options"></div>
<div class="btn large" onclick="getPicture();">camera.getPicture()</div>
<h2>Native File Inputs</h2>
<div>input type=file <input type="file" onchange="testInputTag(this)"></div>
<div>capture=camera <input type="file" accept="image/*;capture=camera" onchange="testInputTag(this)"></div>
<div>capture=camcorder <input type="file" accept="video/*;capture=camcorder" onchange="testInputTag(this)"></div>
<div>capture=microphone <input type="file" accept="audio/*;capture=microphone" onchange="testInputTag(this)"></div>
<h2>Actions</h2>
<div class="btn large" onclick="getFileInfo();">Get File Metadata</div>
<div class="btn large" onclick="readFile();">Read with FileReader</div>
<div class="btn large" onclick="copyImage();">Copy Image</div>
<div class="btn large" onclick="writeImage();">Write Image</div>
<div class="btn large" onclick="uploadImage();">Upload Image</div>
<div class="btn large" onclick="displayImageUsingCanvas();">Draw Using Canvas</div>
<div class="btn large" onclick="removeImage();">Remove Image</div>
<h2> </h2><div class="backBtn" onclick="backHome();">Back</div>
</body>
</html>

70
test/cordova-incl.js vendored Normal file
View File

@ -0,0 +1,70 @@
/*
*
* 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 PLAT;
if (/Android/.exec(navigator.userAgent)) {
PLAT = 'android';
} else if (/(iPad)|(iPhone)|(iPod)/.exec(navigator.userAgent)) {
PLAT = 'ios';
} else if (/(BB10)|(PlayBook)|(BlackBerry)/.exec(navigator.userAgent)) {
PLAT = 'blackberry';
}
var scripts = document.getElementsByTagName('script');
var currentPath = scripts[scripts.length - 1].src;
var platformCordovaPath = currentPath.replace("cordova-incl.js", "cordova." + PLAT + ".js");
var normalCordovaPath = currentPath.replace("cordova-incl.js", "cordova.js");
var cordovaPath = normalCordovaPath;
if (PLAT) {
// XHR to local file is an error on some platforms, windowsphone for one
try {
var xhr = new XMLHttpRequest();
xhr.open("GET", platformCordovaPath, false);
xhr.onreadystatechange = function() {
if (this.readyState == this.DONE && this.responseText.length > 0) {
if(parseInt(this.status) >= 400){
cordovaPath = normalCordovaPath;
}else{
cordovaPath = platformCordovaPath;
}
}
};
xhr.send(null);
}
catch(e){
cordovaPath = normalCordovaPath;
} // access denied!
}
if (!window._doNotWriteCordovaScript) {
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);
}
}

65
test/index.html Normal file
View File

@ -0,0 +1,65 @@
<!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 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-incl.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>Model: <span id="model"> </span></h4>
<h4>Width: <span id="width"> </span>, Height: <span id="height">
</span>, Color Depth: <span id="colorDepth"></span></h4>
<h4>User-Agent: <span id="user-agent"> </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="lazyloadjs/index.html" class="btn large">Lazy Loading of cordova-incl.js</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="splashscreen/index.html" class="btn large">Splashscreen</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="benchmarks/index.html" class="btn large">Benchmarks</a>
<a href="inappbrowser/index.html" class="btn large">In App Browser</a>
</body>
</html>

163
test/main.js Normal file
View File

@ -0,0 +1,163 @@
/*
*
* 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 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("model").innerHTML = device.model;
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/cordova.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);
document.getElementById("user-agent").textContent = navigator.userAgent;
}

164
test/master.css Normal file
View File

@ -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.
*
*/
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;
min-width:295px;
max-width:97%;
padding:4px 0px 2px 10px;
word-wrap:break-word;
margin-bottom:10px;
display:inline-block;
min-height: 160px;
max-height: 300px;
overflow: auto;
-webkit-overflow-scrolling: touch;
}
#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:inline-block;
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%;
}