pre version bump
This commit is contained in:
parent
ee73adae39
commit
8066c76dfd
22
package.json
Normal file
22
package.json
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"name": "sensortoy",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "http://gitlab.silvrtree.co.uk/martind2000/sensortoy.git"
|
||||||
|
},
|
||||||
|
"author": "Martin Donnelly <martind2000@gmail.com>",
|
||||||
|
"license": "ISC",
|
||||||
|
"devDependencies": {
|
||||||
|
"gulp": "^3.9.1",
|
||||||
|
"gulp-autoprefixer": "^3.1.0",
|
||||||
|
"gulp-cache": "^0.4.5",
|
||||||
|
"gulp-concat": "^2.6.0",
|
||||||
|
"gulp-cssnano": "^2.1.2"
|
||||||
|
}
|
||||||
|
}
|
94
platforms/android/assets/www/css/progress.css
Normal file
94
platforms/android/assets/www/css/progress.css
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
/* Progress Bar */
|
||||||
|
.progress {
|
||||||
|
position: relative;
|
||||||
|
height: 4px;
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
background-color: #acece6;
|
||||||
|
border-radius: 2px;
|
||||||
|
background-clip: padding-box;
|
||||||
|
/* margin: 0.5rem 0 1rem 0; */
|
||||||
|
overflow: hidden; }
|
||||||
|
|
||||||
|
.progress .determinate {
|
||||||
|
position: absolute;
|
||||||
|
background-color: inherit;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: #26a69a;
|
||||||
|
transition: width .3s linear; }
|
||||||
|
|
||||||
|
.progress .indeterminate {
|
||||||
|
background-color: #26a69a; }
|
||||||
|
|
||||||
|
.progress .indeterminate:before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
background-color: inherit;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
will-change: left, right;
|
||||||
|
-webkit-animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
|
||||||
|
animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite; }
|
||||||
|
|
||||||
|
.progress .indeterminate:after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
background-color: inherit;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
will-change: left, right;
|
||||||
|
-webkit-animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;
|
||||||
|
animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;
|
||||||
|
-webkit-animation-delay: 1.15s;
|
||||||
|
animation-delay: 1.15s; }
|
||||||
|
|
||||||
|
@-webkit-keyframes indeterminate {
|
||||||
|
0% {
|
||||||
|
left: -35%;
|
||||||
|
right: 100%; }
|
||||||
|
60% {
|
||||||
|
left: 100%;
|
||||||
|
right: -90%; }
|
||||||
|
100% {
|
||||||
|
left: 100%;
|
||||||
|
right: -90%; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes indeterminate {
|
||||||
|
0% {
|
||||||
|
left: -35%;
|
||||||
|
right: 100%; }
|
||||||
|
60% {
|
||||||
|
left: 100%;
|
||||||
|
right: -90%; }
|
||||||
|
100% {
|
||||||
|
left: 100%;
|
||||||
|
right: -90%; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes indeterminate-short {
|
||||||
|
0% {
|
||||||
|
left: -200%;
|
||||||
|
right: 100%; }
|
||||||
|
60% {
|
||||||
|
left: 107%;
|
||||||
|
right: -8%; }
|
||||||
|
100% {
|
||||||
|
left: 107%;
|
||||||
|
right: -8%; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes indeterminate-short {
|
||||||
|
0% {
|
||||||
|
left: -200%;
|
||||||
|
right: 100%; }
|
||||||
|
60% {
|
||||||
|
left: 107%;
|
||||||
|
right: -8%; }
|
||||||
|
100% {
|
||||||
|
left: 107%;
|
||||||
|
right: -8%; }
|
||||||
|
}
|
195
platforms/android/assets/www/css/ripple.css
Normal file
195
platforms/android/assets/www/css/ripple.css
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
|
||||||
|
@-webkit-keyframes uil-ripple {
|
||||||
|
0% {
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
opacity: 0;
|
||||||
|
margin: 0 0 0 0;
|
||||||
|
}
|
||||||
|
33% {
|
||||||
|
width: 44%;
|
||||||
|
height: 44%;
|
||||||
|
margin: -22% 0 0 -22%;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
width: 88%;
|
||||||
|
height: 88%;
|
||||||
|
margin: -44% 0 0 -44%;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-webkit-keyframes uil-ripple {
|
||||||
|
0% {
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
opacity: 0;
|
||||||
|
margin: 0 0 0 0;
|
||||||
|
}
|
||||||
|
33% {
|
||||||
|
width: 44%;
|
||||||
|
height: 44%;
|
||||||
|
margin: -22% 0 0 -22%;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
width: 88%;
|
||||||
|
height: 88%;
|
||||||
|
margin: -44% 0 0 -44%;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-moz-keyframes uil-ripple {
|
||||||
|
0% {
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
opacity: 0;
|
||||||
|
margin: 0 0 0 0;
|
||||||
|
}
|
||||||
|
33% {
|
||||||
|
width: 44%;
|
||||||
|
height: 44%;
|
||||||
|
margin: -22% 0 0 -22%;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
width: 88%;
|
||||||
|
height: 88%;
|
||||||
|
margin: -44% 0 0 -44%;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-ms-keyframes uil-ripple {
|
||||||
|
0% {
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
opacity: 0;
|
||||||
|
margin: 0 0 0 0;
|
||||||
|
}
|
||||||
|
33% {
|
||||||
|
width: 44%;
|
||||||
|
height: 44%;
|
||||||
|
margin: -22% 0 0 -22%;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
width: 88%;
|
||||||
|
height: 88%;
|
||||||
|
margin: -44% 0 0 -44%;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-moz-keyframes uil-ripple {
|
||||||
|
0% {
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
opacity: 0;
|
||||||
|
margin: 0 0 0 0;
|
||||||
|
}
|
||||||
|
33% {
|
||||||
|
width: 44%;
|
||||||
|
height: 44%;
|
||||||
|
margin: -22% 0 0 -22%;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
width: 88%;
|
||||||
|
height: 88%;
|
||||||
|
margin: -44% 0 0 -44%;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-webkit-keyframes uil-ripple {
|
||||||
|
0% {
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
opacity: 0;
|
||||||
|
margin: 0 0 0 0;
|
||||||
|
}
|
||||||
|
33% {
|
||||||
|
width: 44%;
|
||||||
|
height: 44%;
|
||||||
|
margin: -22% 0 0 -22%;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
width: 88%;
|
||||||
|
height: 88%;
|
||||||
|
margin: -44% 0 0 -44%;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-o-keyframes uil-ripple {
|
||||||
|
0% {
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
opacity: 0;
|
||||||
|
margin: 0 0 0 0;
|
||||||
|
}
|
||||||
|
33% {
|
||||||
|
width: 44%;
|
||||||
|
height: 44%;
|
||||||
|
margin: -22% 0 0 -22%;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
width: 88%;
|
||||||
|
height: 88%;
|
||||||
|
margin: -44% 0 0 -44%;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes uil-ripple {
|
||||||
|
0% {
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
opacity: 0;
|
||||||
|
margin: 0 0 0 0;
|
||||||
|
}
|
||||||
|
33% {
|
||||||
|
width: 44%;
|
||||||
|
height: 44%;
|
||||||
|
margin: -22% 0 0 -22%;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
width: 88%;
|
||||||
|
height: 88%;
|
||||||
|
margin: -44% 0 0 -44%;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.uil-ripple-css {
|
||||||
|
background: none;
|
||||||
|
position: relative;
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
.uil-ripple-css div {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
margin: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
opacity: 0;
|
||||||
|
border-radius: 50%;
|
||||||
|
border-width: 12px;
|
||||||
|
border-style: solid;
|
||||||
|
-ms-animation: uil-ripple 2s ease-out infinite;
|
||||||
|
-moz-animation: uil-ripple 2s ease-out infinite;
|
||||||
|
-webkit-animation: uil-ripple 2s ease-out infinite;
|
||||||
|
-o-animation: uil-ripple 2s ease-out infinite;
|
||||||
|
animation: uil-ripple 2s ease-out infinite;
|
||||||
|
}
|
||||||
|
.uil-ripple-css div:nth-of-type(1) {
|
||||||
|
border-color: #afafb7;
|
||||||
|
}
|
||||||
|
.uil-ripple-css div:nth-of-type(2) {
|
||||||
|
border-color: #5cffd6;
|
||||||
|
-ms-animation-delay: 1s;
|
||||||
|
-moz-animation-delay: 1s;
|
||||||
|
-webkit-animation-delay: 1s;
|
||||||
|
-o-animation-delay: 1s;
|
||||||
|
animation-delay: 1s;
|
||||||
|
}
|
Binary file not shown.
BIN
platforms/android/assets/www/fonts/Ubuntu-normal-300.woff
Normal file
BIN
platforms/android/assets/www/fonts/Ubuntu-normal-300.woff
Normal file
Binary file not shown.
BIN
platforms/android/assets/www/fonts/Ubuntu-normal-400.woff
Normal file
BIN
platforms/android/assets/www/fonts/Ubuntu-normal-400.woff
Normal file
Binary file not shown.
BIN
platforms/android/assets/www/fonts/Ubuntu-normal-500.woff
Normal file
BIN
platforms/android/assets/www/fonts/Ubuntu-normal-500.woff
Normal file
Binary file not shown.
BIN
platforms/android/assets/www/fonts/Ubuntu-normal-700.woff
Normal file
BIN
platforms/android/assets/www/fonts/Ubuntu-normal-700.woff
Normal file
Binary file not shown.
Binary file not shown.
41
platforms/android/assets/www/fonts/fonts.css
Normal file
41
platforms/android/assets/www/fonts/fonts.css
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: 'Material Icons';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: url(Material_Icons-normal-400.woff) format('woff');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Ubuntu';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: url(Ubuntu-normal-300.woff) format('woff');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Ubuntu';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: url(Ubuntu-normal-400.woff) format('woff');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Ubuntu';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
src: url(Ubuntu-normal-500.woff) format('woff');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Ubuntu';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
src: url(Ubuntu-normal-700.woff) format('woff');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Ubuntu Condensed';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: url(Ubuntu_Condensed-normal-400.woff) format('woff');
|
||||||
|
}
|
144
platforms/android/assets/www/js/device/CC2650/cc2650_humidity.js
Normal file
144
platforms/android/assets/www/js/device/CC2650/cc2650_humidity.js
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* User: Martin Donnelly
|
||||||
|
* Date: 2016-05-20
|
||||||
|
* Time: 10:13
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/* global CAPABILITY, inheritsFrom */
|
||||||
|
/* global ble */
|
||||||
|
/* jshint browser: true , devel: true*/
|
||||||
|
|
||||||
|
var CC2650_HUM = function(p) {
|
||||||
|
'use strict';
|
||||||
|
this.name = 'Humidity';
|
||||||
|
this.deviceID = p.deviceID || null;
|
||||||
|
this.target = p.target || null;
|
||||||
|
|
||||||
|
this.capabilityID = 'F000AA20-0451-4000-B000-000000000000';
|
||||||
|
this.serviceDef = {
|
||||||
|
service: 'F000AA20-0451-4000-B000-000000000000',
|
||||||
|
data: 'F000AA21-0451-4000-B000-000000000000',
|
||||||
|
notification: 'F0002902-0451-4000-B000-000000000000',
|
||||||
|
configuration: 'F000AA22-0451-4000-B000-000000000000',
|
||||||
|
period: 'F000AA23-0451-4000-B000-000000000000'
|
||||||
|
|
||||||
|
};
|
||||||
|
this.data = {temp: [], humidity: []};
|
||||||
|
this.$result = {temp: null, humidity: null};
|
||||||
|
this.setFrame();
|
||||||
|
|
||||||
|
this.startService = function() {
|
||||||
|
'use strict';
|
||||||
|
if (this.deviceID !== null) {
|
||||||
|
|
||||||
|
console.log('Starting CC2650 Humidity Service on ', this.deviceID);
|
||||||
|
console.log(this.serviceDef);
|
||||||
|
this.insertFrame();
|
||||||
|
|
||||||
|
ble.startNotification(this.deviceID,
|
||||||
|
this.serviceDef.service,
|
||||||
|
this.serviceDef.data,
|
||||||
|
this.onHumidityData.bind(this),
|
||||||
|
this.onError);
|
||||||
|
|
||||||
|
//Turn on barometer
|
||||||
|
var humidityConfig = new Uint8Array(1);
|
||||||
|
humidityConfig[0] = 0x01;
|
||||||
|
ble.write(this.deviceID,
|
||||||
|
this.serviceDef.service,
|
||||||
|
this.serviceDef.configuration,
|
||||||
|
humidityConfig.buffer,
|
||||||
|
function() { console.log('Started Humidity.'); },
|
||||||
|
this.onError);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
this.onHumidityData = function(data) {
|
||||||
|
var hStr;
|
||||||
|
var tStr;
|
||||||
|
// Console.log(data);
|
||||||
|
var message;
|
||||||
|
var raw = new Uint16Array(data);
|
||||||
|
|
||||||
|
//-- calculate temperature [°C]
|
||||||
|
var temp = (raw[0] / 65536) * 165 - 40;
|
||||||
|
|
||||||
|
//-- calculate relative humidity [%RH]
|
||||||
|
var hum = (raw[1] / 65536) * 100;
|
||||||
|
|
||||||
|
tStr = temp.toFixed(2) + '°C';
|
||||||
|
hStr = hum.toFixed(2) + '%RH';
|
||||||
|
|
||||||
|
message = 'Temperature <br/>' + tStr + 'Humidity <br/>' + hStr;
|
||||||
|
|
||||||
|
this.data.temp = this.storeData(temp, this.data.temp);
|
||||||
|
this.data.humidity = this.storeData(hum, this.data.humidity);
|
||||||
|
|
||||||
|
|
||||||
|
this.$result.temp.text(tStr);
|
||||||
|
this.$result.humidity.text(hStr);
|
||||||
|
|
||||||
|
this.state = message;
|
||||||
|
|
||||||
|
// Console.log('Barometer:', this.state);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.animateGraph = function() {
|
||||||
|
this.simpleGraph(this.data.temp, 'temp');
|
||||||
|
this.simpleGraph(this.data.humidity, 'humidity');
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
this.insertFrame = function() {
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
var blankChart;
|
||||||
|
|
||||||
|
// Call the parent displayForm first...
|
||||||
|
this.superClass_.insertFrame.call(self);
|
||||||
|
|
||||||
|
var temp = this.frameID + '-t';
|
||||||
|
var humidity = this.frameID + '-h';
|
||||||
|
var row = $('<div />', {class: 'mui-row'});
|
||||||
|
|
||||||
|
$('<div />',
|
||||||
|
{class: 'mui-col-xs-3 mui--text-accent', text: 'Temp:'}).appendTo(row);
|
||||||
|
|
||||||
|
$('<div />',
|
||||||
|
{class: 'mui-col-xs-3 mui--text-dark', id: temp}).appendTo(row);
|
||||||
|
$('<div />',
|
||||||
|
{
|
||||||
|
class: 'mui-col-xs-3 mui--text-accent',
|
||||||
|
text: 'Humidity:'
|
||||||
|
}).appendTo(row);
|
||||||
|
|
||||||
|
$('<div />',
|
||||||
|
{class: 'mui-col-xs-3 mui--text-dark', id: humidity}).appendTo(row);
|
||||||
|
|
||||||
|
this.$id.append(row);
|
||||||
|
|
||||||
|
var tabBody = $('<ul>',{class: 'mui-tabs__bar mui-tabs__bar--justified'});
|
||||||
|
$('<li>',{class: 'mui--is-active tabOnWhite'}).append($('<a>',{text: 'Temperature','data-mui-toggle': 'tab', 'data-mui-controls': (temp + '-pane')})).appendTo(tabBody);
|
||||||
|
$('<li>',{class: 'tabOnWhite'}).append($('<a>',{text: 'Humidity','data-mui-toggle': 'tab', 'data-mui-controls': (humidity + '-pane')})).appendTo(tabBody);
|
||||||
|
this.$id.append(tabBody);
|
||||||
|
|
||||||
|
blankChart = this.generateBlankGraph('temp');
|
||||||
|
|
||||||
|
this.$id.append($('<div>',{class: 'mui-tabs__pane mui--is-active',id: (temp + '-pane')}).append(blankChart));
|
||||||
|
|
||||||
|
blankChart = this.generateBlankGraph('humidity');
|
||||||
|
this.$id.append($('<div>',{class: 'mui-tabs__pane',id: (humidity + '-pane')}).append(blankChart));
|
||||||
|
|
||||||
|
this.$result.temp = $('#' + temp);
|
||||||
|
this.$result.humidity = $('#' + humidity);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
inheritsFrom(CC2650_HUM, CAPABILITY);
|
||||||
|
|
||||||
|
capabilityManager.register({id:'F000AA20-0451-4000-B000-000000000000', module:CC2650_HUM});
|
@ -0,0 +1,148 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* User: Martin Donnelly
|
||||||
|
* Date: 2016-05-20
|
||||||
|
* Time: 10:13
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/* global CAPABILITY, inheritsFrom */
|
||||||
|
/* global ble */
|
||||||
|
/* jshint browser: true , devel: true*/
|
||||||
|
|
||||||
|
var CC2650_TMP = function(p) {
|
||||||
|
'use strict';
|
||||||
|
this.name = 'Thermopile';
|
||||||
|
this.deviceID = p.deviceID || null;
|
||||||
|
this.target = p.target || null;
|
||||||
|
|
||||||
|
this.capabilityID = 'F000AA00-0451-4000-B000-000000000000';
|
||||||
|
this.serviceDef = {
|
||||||
|
service: 'F000AA00-0451-4000-B000-000000000000',
|
||||||
|
data: 'F000AA01-0451-4000-B000-000000000000',
|
||||||
|
notification: 'F0002902-0451-4000-B000-000000000000',
|
||||||
|
configuration: 'F000AA02-0451-4000-B000-000000000000',
|
||||||
|
period: 'F000AA03-0451-4000-B000-000000000000'
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
this.data = {temp: [], ambient: []};
|
||||||
|
this.$result = {temp: null, ambient: null};
|
||||||
|
this.setFrame();
|
||||||
|
|
||||||
|
this.startService = function() {
|
||||||
|
'use strict';
|
||||||
|
if (this.deviceID !== null) {
|
||||||
|
|
||||||
|
console.log('Starting CC2650 Thermopile Service on ', this.deviceID);
|
||||||
|
console.log(this.serviceDef);
|
||||||
|
this.insertFrame();
|
||||||
|
|
||||||
|
ble.startNotification(this.deviceID,
|
||||||
|
this.serviceDef.service,
|
||||||
|
this.serviceDef.data,
|
||||||
|
this.onThermData.bind(this),
|
||||||
|
this.onError);
|
||||||
|
|
||||||
|
//Turn on thermopile
|
||||||
|
var tmpConfig = new Uint8Array(1);
|
||||||
|
tmpConfig[0] = 0x01;
|
||||||
|
ble.write(this.deviceID,
|
||||||
|
this.serviceDef.service,
|
||||||
|
this.serviceDef.configuration,
|
||||||
|
tmpConfig.buffer,
|
||||||
|
function() { console.log('Started Thermopile.'); },
|
||||||
|
this.onError);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
this.onThermData = function(data) {
|
||||||
|
|
||||||
|
var ambTemp;
|
||||||
|
var objTemp;
|
||||||
|
var scale_lsb = 0.03125;
|
||||||
|
var raw = new Uint16Array(data);
|
||||||
|
|
||||||
|
var it = raw[0] >> 2;
|
||||||
|
|
||||||
|
objTemp = it * scale_lsb;
|
||||||
|
|
||||||
|
it = raw[1] >> 2;
|
||||||
|
|
||||||
|
ambTemp = it * scale_lsb;
|
||||||
|
|
||||||
|
var tStr = objTemp.toFixed(2) + '°C';
|
||||||
|
var aStr = ambTemp.toFixed(2) + '°C';
|
||||||
|
|
||||||
|
this.state = ['Temp: ', tStr, ', Ambient:', aStr].join(' ');
|
||||||
|
|
||||||
|
this.data.temp = this.storeData(objTemp, this.data.temp);
|
||||||
|
this.data.ambient = this.storeData(ambTemp, this.data.ambient);
|
||||||
|
|
||||||
|
|
||||||
|
this.$result.temp.text(tStr);
|
||||||
|
this.$result.ambient.text(aStr);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
this.animateGraph = function() {
|
||||||
|
this.simpleGraph(this.data.temp, 'temp');
|
||||||
|
this.simpleGraph(this.data.ambient, 'ambient');
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
this.insertFrame = function() {
|
||||||
|
|
||||||
|
var blankChart;
|
||||||
|
var self = this;
|
||||||
|
// Console.log('Overloading...');
|
||||||
|
// Call the parent displayForm first...
|
||||||
|
|
||||||
|
this.superClass_.insertFrame.call(self);
|
||||||
|
|
||||||
|
var temp = this.frameID + '-t';
|
||||||
|
var amb = this.frameID + '-a';
|
||||||
|
var row = $('<div />', {class: 'mui-row'});
|
||||||
|
|
||||||
|
$('<div />',
|
||||||
|
{class: 'mui-col-xs-3 mui--text-accent', text: 'Temp:'}).appendTo(row);
|
||||||
|
|
||||||
|
$('<div />',
|
||||||
|
{class: 'mui-col-xs-3 mui--text-dark', id: temp}).appendTo(row);
|
||||||
|
$('<div />',
|
||||||
|
{
|
||||||
|
class: 'mui-col-xs-3 mui--text-accent',
|
||||||
|
text: 'Ambient:'
|
||||||
|
}).appendTo(row);
|
||||||
|
|
||||||
|
$('<div />',
|
||||||
|
{class: 'mui-col-xs-3 mui--text-dark', id: amb}).appendTo(row);
|
||||||
|
|
||||||
|
this.$id.append(row);
|
||||||
|
|
||||||
|
var tabBody = $('<ul>',{class: 'mui-tabs__bar mui-tabs__bar--justified'});
|
||||||
|
$('<li>',{class: 'mui--is-active tabOnWhite'}).append($('<a>',{ text: 'Temperature','data-mui-toggle': 'tab', 'data-mui-controls': (temp + '-pane')})).appendTo(tabBody);
|
||||||
|
$('<li>', {class: 'tabOnWhite'}).append($('<a>',{ text: 'Ambient','data-mui-toggle': 'tab', 'data-mui-controls': (amb + '-pane')})).appendTo(tabBody);
|
||||||
|
|
||||||
|
this.$id.append(tabBody);
|
||||||
|
|
||||||
|
blankChart = this.generateBlankGraph('temp');
|
||||||
|
|
||||||
|
this.$id.append($('<div>',{class: 'mui-tabs__pane mui--is-active',id: (temp + '-pane')}).append(blankChart));
|
||||||
|
|
||||||
|
blankChart = this.generateBlankGraph('ambient');
|
||||||
|
|
||||||
|
this.$id.append($('<div>',{class: 'mui-tabs__pane',id: (amb + '-pane')}).append(blankChart));
|
||||||
|
|
||||||
|
this.$result.temp = $('#' + temp);
|
||||||
|
this.$result.ambient = $('#' + amb);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
inheritsFrom(CC2650_TMP, CAPABILITY);
|
||||||
|
|
||||||
|
capabilityManager.register({id: 'F000AA00-0451-4000-B000-000000000000', module: CC2650_TMP});
|
69
platforms/android/assets/www/js/mandecoder.js
Normal file
69
platforms/android/assets/www/js/mandecoder.js
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* User: Martin Donnelly
|
||||||
|
* Date: 2016-05-24
|
||||||
|
* Time: 14:21
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
var MANUFACTUREDECODER = function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
this.getManID = function(data) {
|
||||||
|
return ('0000' + ((data[1] << 8) | data[0]).toString(16)).slice(-4).toUpperCase();
|
||||||
|
},
|
||||||
|
this.decodeIbeacon = function(data) {
|
||||||
|
|
||||||
|
// Not decoding anything yet.
|
||||||
|
// https://support.kontakt.io/hc/en-gb/articles/201492492-iBeacon-advertising-packet-structure
|
||||||
|
var bin = data;
|
||||||
|
var obj = { msg: '(iBeacon)'};
|
||||||
|
// obj.manID = ('0000' + ((bin[1] << 8) | bin[0]).toString(16)).slice(-4);
|
||||||
|
obj.manID = this.getManID(bin);
|
||||||
|
var uuid = [];
|
||||||
|
uuid.push(bin[4].toString(16) + bin[5].toString(16) + bin[6].toString(16) + bin[7].toString(16)) ;
|
||||||
|
|
||||||
|
uuid.push(bin[8].toString(16) + bin[9].toString(16)) ;
|
||||||
|
uuid.push(bin[10].toString(16) + bin[11].toString(16)) ;
|
||||||
|
uuid.push(bin[12].toString(16) + bin[13].toString(16)) ;
|
||||||
|
|
||||||
|
uuid.push(bin[14].toString(16) + bin[15].toString(16) + bin[16].toString(16) + bin[17].toString(16) + bin[18].toString(16) + bin[19].toString(16)) ;
|
||||||
|
|
||||||
|
obj.uuid = uuid.join('-');
|
||||||
|
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
};
|
||||||
|
this.decodeSiliconLabsSensorPuck = function(data) {
|
||||||
|
var bin = data;
|
||||||
|
var obj = {data:{}};
|
||||||
|
//obj.manID = ('0000' + ((bin[1] << 8) | bin[0]).toString(16)).slice(-4);
|
||||||
|
obj.manID = this.getManID(bin);
|
||||||
|
obj.a = (bin[3] << 8) | bin[2];
|
||||||
|
obj.b = (bin[5] << 8) | bin[4];
|
||||||
|
obj.data.humidity = (bin[7] << 8) | bin[6];
|
||||||
|
obj.data.temp = (bin[9] << 8) | bin[8];
|
||||||
|
obj.c = (bin[11] << 8) | bin[10];
|
||||||
|
obj.d = (bin[13] << 8) | bin[12];
|
||||||
|
|
||||||
|
obj.msg = 'Humidity: ' + (obj.data.humidity / 10) + ', temp: ' + (obj.data.temp / 10);
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
this.decodeSansible = function(data) {
|
||||||
|
var bin = data;
|
||||||
|
var obj = {data:{}};
|
||||||
|
// obj.manID = ('0000' + ((bin[1] << 8) | bin[0]).toString(16)).slice(-4);
|
||||||
|
obj.manID = this.getManID(bin);
|
||||||
|
|
||||||
|
obj.data.p1 = ((bin[2] << 16) | bin[3] << 8 | bin[4]);
|
||||||
|
obj.data.p2 = ((bin[5] << 16) | bin[6] << 8 | bin[7]);
|
||||||
|
|
||||||
|
obj.msg = 'Left: ' + (obj.data.p1 / 100) + ' hPa, Right: ' + (obj.data.p2 / 100) + ' hPa';
|
||||||
|
return obj;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
};
|
@ -53,9 +53,9 @@ var BATTERY = function() {
|
|||||||
this.onError);
|
this.onError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inheritsFrom(BATTERY, CAPABILITY);
|
inheritsFrom(BATTERY, CAPABILITY);
|
||||||
|
capabilityManager.register({id: '180F', module: BATTERY});
|
||||||
|
File diff suppressed because it is too large
Load Diff
15
platforms/android/assets/www/js/standards/gadget.js
Normal file
15
platforms/android/assets/www/js/standards/gadget.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* User: Martin Donnelly
|
||||||
|
* Date: 2016-06-01
|
||||||
|
* Time: 13:30
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
var GADGET = function(p) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
|
||||||
|
this._gadget = p;
|
||||||
|
|
||||||
|
};
|
803
platforms/android/assets/www/libs/smoothie.js
Normal file
803
platforms/android/assets/www/libs/smoothie.js
Normal file
@ -0,0 +1,803 @@
|
|||||||
|
// MIT License:
|
||||||
|
//
|
||||||
|
// Copyright (c) 2010-2013, Joe Walnes
|
||||||
|
// 2013-2014, Drew Noakes
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Smoothie Charts - http://smoothiecharts.org/
|
||||||
|
* (c) 2010-2013, Joe Walnes
|
||||||
|
* 2013-2014, Drew Noakes
|
||||||
|
*
|
||||||
|
* v1.0: Main charting library, by Joe Walnes
|
||||||
|
* v1.1: Auto scaling of axis, by Neil Dunn
|
||||||
|
* v1.2: fps (frames per second) option, by Mathias Petterson
|
||||||
|
* v1.3: Fix for divide by zero, by Paul Nikitochkin
|
||||||
|
* v1.4: Set minimum, top-scale padding, remove timeseries, add optional timer to reset bounds, by Kelley Reynolds
|
||||||
|
* v1.5: Set default frames per second to 50... smoother.
|
||||||
|
* .start(), .stop() methods for conserving CPU, by Dmitry Vyal
|
||||||
|
* options.interpolation = 'bezier' or 'line', by Dmitry Vyal
|
||||||
|
* options.maxValue to fix scale, by Dmitry Vyal
|
||||||
|
* v1.6: minValue/maxValue will always get converted to floats, by Przemek Matylla
|
||||||
|
* v1.7: options.grid.fillStyle may be a transparent color, by Dmitry A. Shashkin
|
||||||
|
* Smooth rescaling, by Kostas Michalopoulos
|
||||||
|
* v1.8: Set max length to customize number of live points in the dataset with options.maxDataSetLength, by Krishna Narni
|
||||||
|
* v1.9: Display timestamps along the bottom, by Nick and Stev-io
|
||||||
|
* (https://groups.google.com/forum/?fromgroups#!topic/smoothie-charts/-Ywse8FCpKI%5B1-25%5D)
|
||||||
|
* Refactored by Krishna Narni, to support timestamp formatting function
|
||||||
|
* v1.10: Switch to requestAnimationFrame, removed the now obsoleted options.fps, by Gergely Imreh
|
||||||
|
* v1.11: options.grid.sharpLines option added, by @drewnoakes
|
||||||
|
* Addressed warning seen in Firefox when seriesOption.fillStyle undefined, by @drewnoakes
|
||||||
|
* v1.12: Support for horizontalLines added, by @drewnoakes
|
||||||
|
* Support for yRangeFunction callback added, by @drewnoakes
|
||||||
|
* v1.13: Fixed typo (#32), by @alnikitich
|
||||||
|
* v1.14: Timer cleared when last TimeSeries removed (#23), by @davidgaleano
|
||||||
|
* Fixed diagonal line on chart at start/end of data stream, by @drewnoakes
|
||||||
|
* v1.15: Support for npm package (#18), by @dominictarr
|
||||||
|
* Fixed broken removeTimeSeries function (#24) by @davidgaleano
|
||||||
|
* Minor performance and tidying, by @drewnoakes
|
||||||
|
* v1.16: Bug fix introduced in v1.14 relating to timer creation/clearance (#23), by @drewnoakes
|
||||||
|
* TimeSeries.append now deals with out-of-order timestamps, and can merge duplicates, by @zacwitte (#12)
|
||||||
|
* Documentation and some local variable renaming for clarity, by @drewnoakes
|
||||||
|
* v1.17: Allow control over font size (#10), by @drewnoakes
|
||||||
|
* Timestamp text won't overlap, by @drewnoakes
|
||||||
|
* v1.18: Allow control of max/min label precision, by @drewnoakes
|
||||||
|
* Added 'borderVisible' chart option, by @drewnoakes
|
||||||
|
* Allow drawing series with fill but no stroke (line), by @drewnoakes
|
||||||
|
* v1.19: Avoid unnecessary repaints, and fixed flicker in old browsers having multiple charts in document (#40), by @asbai
|
||||||
|
* v1.20: Add SmoothieChart.getTimeSeriesOptions and SmoothieChart.bringToFront functions, by @drewnoakes
|
||||||
|
* v1.21: Add 'step' interpolation mode, by @drewnoakes
|
||||||
|
* v1.22: Add support for different pixel ratios. Also add optional y limit formatters, by @copacetic
|
||||||
|
* v1.23: Fix bug introduced in v1.22 (#44), by @drewnoakes
|
||||||
|
* v1.24: Fix bug introduced in v1.23, re-adding parseFloat to y-axis formatter defaults, by @siggy_sf
|
||||||
|
* v1.25: Fix bug seen when adding a data point to TimeSeries which is older than the current data, by @Nking92
|
||||||
|
* Draw time labels on top of series, by @comolosabia
|
||||||
|
* Add TimeSeries.clear function, by @drewnoakes
|
||||||
|
* v1.26: Add support for resizing on high device pixel ratio screens, by @copacetic
|
||||||
|
* v1.27: Fix bug introduced in v1.26 for non whole number devicePixelRatio values, by @zmbush
|
||||||
|
* v1.28: Add 'minValueScale' option, by @megawac
|
||||||
|
*/
|
||||||
|
|
||||||
|
;(function(exports) {
|
||||||
|
|
||||||
|
var Util = {
|
||||||
|
extend: function() {
|
||||||
|
arguments[0] = arguments[0] || {};
|
||||||
|
for (var i = 1; i < arguments.length; i++)
|
||||||
|
{
|
||||||
|
for (var key in arguments[i])
|
||||||
|
{
|
||||||
|
if (arguments[i].hasOwnProperty(key))
|
||||||
|
{
|
||||||
|
if (typeof(arguments[i][key]) === 'object') {
|
||||||
|
if (arguments[i][key] instanceof Array) {
|
||||||
|
arguments[0][key] = arguments[i][key];
|
||||||
|
} else {
|
||||||
|
arguments[0][key] = Util.extend(arguments[0][key], arguments[i][key]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
arguments[0][key] = arguments[i][key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arguments[0];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialises a new <code>TimeSeries</code> with optional data options.
|
||||||
|
*
|
||||||
|
* Options are of the form (defaults shown):
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* {
|
||||||
|
* resetBounds: true, // enables/disables automatic scaling of the y-axis
|
||||||
|
* resetBoundsInterval: 3000 // the period between scaling calculations, in millis
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* Presentation options for TimeSeries are specified as an argument to <code>SmoothieChart.addTimeSeries</code>.
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function TimeSeries(options) {
|
||||||
|
this.options = Util.extend({}, TimeSeries.defaultOptions, options);
|
||||||
|
this.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeSeries.defaultOptions = {
|
||||||
|
resetBoundsInterval: 3000,
|
||||||
|
resetBounds: true
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all data and state from this TimeSeries object.
|
||||||
|
*/
|
||||||
|
TimeSeries.prototype.clear = function() {
|
||||||
|
this.data = [];
|
||||||
|
this.maxValue = Number.NaN; // The maximum value ever seen in this TimeSeries.
|
||||||
|
this.minValue = Number.NaN; // The minimum value ever seen in this TimeSeries.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recalculate the min/max values for this <code>TimeSeries</code> object.
|
||||||
|
*
|
||||||
|
* This causes the graph to scale itself in the y-axis.
|
||||||
|
*/
|
||||||
|
TimeSeries.prototype.resetBounds = function() {
|
||||||
|
if (this.data.length) {
|
||||||
|
// Walk through all data points, finding the min/max value
|
||||||
|
this.maxValue = this.data[0][1];
|
||||||
|
this.minValue = this.data[0][1];
|
||||||
|
for (var i = 1; i < this.data.length; i++) {
|
||||||
|
var value = this.data[i][1];
|
||||||
|
if (value > this.maxValue) {
|
||||||
|
this.maxValue = value;
|
||||||
|
}
|
||||||
|
if (value < this.minValue) {
|
||||||
|
this.minValue = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No data exists, so set min/max to NaN
|
||||||
|
this.maxValue = Number.NaN;
|
||||||
|
this.minValue = Number.NaN;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new data point to the <code>TimeSeries</code>, preserving chronological order.
|
||||||
|
*
|
||||||
|
* @param timestamp the position, in time, of this data point
|
||||||
|
* @param value the value of this data point
|
||||||
|
* @param sumRepeatedTimeStampValues if <code>timestamp</code> has an exact match in the series, this flag controls
|
||||||
|
* whether it is replaced, or the values summed (defaults to false.)
|
||||||
|
*/
|
||||||
|
TimeSeries.prototype.append = function(timestamp, value, sumRepeatedTimeStampValues) {
|
||||||
|
// Rewind until we hit an older timestamp
|
||||||
|
var i = this.data.length - 1;
|
||||||
|
while (i >= 0 && this.data[i][0] > timestamp) {
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i === -1) {
|
||||||
|
// This new item is the oldest data
|
||||||
|
this.data.splice(0, 0, [timestamp, value]);
|
||||||
|
} else if (this.data.length > 0 && this.data[i][0] === timestamp) {
|
||||||
|
// Update existing values in the array
|
||||||
|
if (sumRepeatedTimeStampValues) {
|
||||||
|
// Sum this value into the existing 'bucket'
|
||||||
|
this.data[i][1] += value;
|
||||||
|
value = this.data[i][1];
|
||||||
|
} else {
|
||||||
|
// Replace the previous value
|
||||||
|
this.data[i][1] = value;
|
||||||
|
}
|
||||||
|
} else if (i < this.data.length - 1) {
|
||||||
|
// Splice into the correct position to keep timestamps in order
|
||||||
|
this.data.splice(i + 1, 0, [timestamp, value]);
|
||||||
|
} else {
|
||||||
|
// Add to the end of the array
|
||||||
|
this.data.push([timestamp, value]);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.maxValue = isNaN(this.maxValue) ? value : Math.max(this.maxValue, value);
|
||||||
|
this.minValue = isNaN(this.minValue) ? value : Math.min(this.minValue, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
TimeSeries.prototype.dropOldData = function(oldestValidTime, maxDataSetLength) {
|
||||||
|
// We must always keep one expired data point as we need this to draw the
|
||||||
|
// line that comes into the chart from the left, but any points prior to that can be removed.
|
||||||
|
var removeCount = 0;
|
||||||
|
while (this.data.length - removeCount >= maxDataSetLength && this.data[removeCount + 1][0] < oldestValidTime) {
|
||||||
|
removeCount++;
|
||||||
|
}
|
||||||
|
if (removeCount !== 0) {
|
||||||
|
this.data.splice(0, removeCount);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialises a new <code>SmoothieChart</code>.
|
||||||
|
*
|
||||||
|
* Options are optional, and should be of the form below. Just specify the values you
|
||||||
|
* need and the rest will be given sensible defaults as shown:
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* {
|
||||||
|
* minValue: undefined, // specify to clamp the lower y-axis to a given value
|
||||||
|
* maxValue: undefined, // specify to clamp the upper y-axis to a given value
|
||||||
|
* maxValueScale: 1, // allows proportional padding to be added above the chart. for 10% padding, specify 1.1.
|
||||||
|
* minValueScale: 1, // allows proportional padding to be added below the chart. for 10% padding, specify 1.1.
|
||||||
|
* yRangeFunction: undefined, // function({min: , max: }) { return {min: , max: }; }
|
||||||
|
* scaleSmoothing: 0.125, // controls the rate at which y-value zoom animation occurs
|
||||||
|
* millisPerPixel: 20, // sets the speed at which the chart pans by
|
||||||
|
* enableDpiScaling: true, // support rendering at different DPI depending on the device
|
||||||
|
* yMinFormatter: function(min, precision) { // callback function that formats the min y value label
|
||||||
|
* return parseFloat(min).toFixed(precision);
|
||||||
|
* },
|
||||||
|
* yMaxFormatter: function(max, precision) { // callback function that formats the max y value label
|
||||||
|
* return parseFloat(max).toFixed(precision);
|
||||||
|
* },
|
||||||
|
* maxDataSetLength: 2,
|
||||||
|
* interpolation: 'bezier' // one of 'bezier', 'linear', or 'step'
|
||||||
|
* timestampFormatter: null, // optional function to format time stamps for bottom of chart
|
||||||
|
* // you may use SmoothieChart.timeFormatter, or your own: function(date) { return ''; }
|
||||||
|
* scrollBackwards: false, // reverse the scroll direction of the chart
|
||||||
|
* horizontalLines: [], // [ { value: 0, color: '#ffffff', lineWidth: 1 } ]
|
||||||
|
* grid:
|
||||||
|
* {
|
||||||
|
* fillStyle: '#000000', // the background colour of the chart
|
||||||
|
* lineWidth: 1, // the pixel width of grid lines
|
||||||
|
* strokeStyle: '#777777', // colour of grid lines
|
||||||
|
* millisPerLine: 1000, // distance between vertical grid lines
|
||||||
|
* sharpLines: false, // controls whether grid lines are 1px sharp, or softened
|
||||||
|
* verticalSections: 2, // number of vertical sections marked out by horizontal grid lines
|
||||||
|
* borderVisible: true // whether the grid lines trace the border of the chart or not
|
||||||
|
* },
|
||||||
|
* labels
|
||||||
|
* {
|
||||||
|
* disabled: false, // enables/disables labels showing the min/max values
|
||||||
|
* fillStyle: '#ffffff', // colour for text of labels,
|
||||||
|
* fontSize: 15,
|
||||||
|
* fontFamily: 'sans-serif',
|
||||||
|
* precision: 2
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function SmoothieChart(options) {
|
||||||
|
this.options = Util.extend({}, SmoothieChart.defaultChartOptions, options);
|
||||||
|
this.seriesSet = [];
|
||||||
|
this.currentValueRange = 1;
|
||||||
|
this.currentVisMinValue = 0;
|
||||||
|
this.lastRenderTimeMillis = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SmoothieChart.defaultChartOptions = {
|
||||||
|
millisPerPixel: 20,
|
||||||
|
enableDpiScaling: true,
|
||||||
|
yMinFormatter: function(min, precision) {
|
||||||
|
return parseFloat(min).toFixed(precision);
|
||||||
|
},
|
||||||
|
yMaxFormatter: function(max, precision) {
|
||||||
|
return parseFloat(max).toFixed(precision);
|
||||||
|
},
|
||||||
|
maxValueScale: 1,
|
||||||
|
minValueScale: 1,
|
||||||
|
interpolation: 'bezier',
|
||||||
|
scaleSmoothing: 0.125,
|
||||||
|
maxDataSetLength: 2,
|
||||||
|
scrollBackwards: false,
|
||||||
|
grid: {
|
||||||
|
fillStyle: '#000000',
|
||||||
|
strokeStyle: '#777777',
|
||||||
|
lineWidth: 1,
|
||||||
|
sharpLines: false,
|
||||||
|
millisPerLine: 1000,
|
||||||
|
verticalSections: 2,
|
||||||
|
borderVisible: true
|
||||||
|
},
|
||||||
|
labels: {
|
||||||
|
fillStyle: '#ffffff',
|
||||||
|
disabled: false,
|
||||||
|
fontSize: 10,
|
||||||
|
fontFamily: 'monospace',
|
||||||
|
precision: 2
|
||||||
|
},
|
||||||
|
horizontalLines: []
|
||||||
|
};
|
||||||
|
|
||||||
|
// Based on http://inspirit.github.com/jsfeat/js/compatibility.js
|
||||||
|
SmoothieChart.AnimateCompatibility = (function() {
|
||||||
|
var requestAnimationFrame = function(callback, element) {
|
||||||
|
var requestAnimationFrame =
|
||||||
|
window.requestAnimationFrame ||
|
||||||
|
window.webkitRequestAnimationFrame ||
|
||||||
|
window.mozRequestAnimationFrame ||
|
||||||
|
window.oRequestAnimationFrame ||
|
||||||
|
window.msRequestAnimationFrame ||
|
||||||
|
function(callback) {
|
||||||
|
return window.setTimeout(function() {
|
||||||
|
callback(new Date().getTime());
|
||||||
|
}, 16);
|
||||||
|
};
|
||||||
|
return requestAnimationFrame.call(window, callback, element);
|
||||||
|
},
|
||||||
|
cancelAnimationFrame = function(id) {
|
||||||
|
var cancelAnimationFrame =
|
||||||
|
window.cancelAnimationFrame ||
|
||||||
|
function(id) {
|
||||||
|
clearTimeout(id);
|
||||||
|
};
|
||||||
|
return cancelAnimationFrame.call(window, id);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
requestAnimationFrame: requestAnimationFrame,
|
||||||
|
cancelAnimationFrame: cancelAnimationFrame
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
SmoothieChart.defaultSeriesPresentationOptions = {
|
||||||
|
lineWidth: 1,
|
||||||
|
strokeStyle: '#ffffff'
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a <code>TimeSeries</code> to this chart, with optional presentation options.
|
||||||
|
*
|
||||||
|
* Presentation options should be of the form (defaults shown):
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* {
|
||||||
|
* lineWidth: 1,
|
||||||
|
* strokeStyle: '#ffffff',
|
||||||
|
* fillStyle: undefined
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
SmoothieChart.prototype.addTimeSeries = function(timeSeries, options) {
|
||||||
|
this.seriesSet.push({timeSeries: timeSeries, options: Util.extend({}, SmoothieChart.defaultSeriesPresentationOptions, options)});
|
||||||
|
if (timeSeries.options.resetBounds && timeSeries.options.resetBoundsInterval > 0) {
|
||||||
|
timeSeries.resetBoundsTimerId = setInterval(
|
||||||
|
function() {
|
||||||
|
timeSeries.resetBounds();
|
||||||
|
},
|
||||||
|
timeSeries.options.resetBoundsInterval
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the specified <code>TimeSeries</code> from the chart.
|
||||||
|
*/
|
||||||
|
SmoothieChart.prototype.removeTimeSeries = function(timeSeries) {
|
||||||
|
// Find the correct timeseries to remove, and remove it
|
||||||
|
var numSeries = this.seriesSet.length;
|
||||||
|
for (var i = 0; i < numSeries; i++) {
|
||||||
|
if (this.seriesSet[i].timeSeries === timeSeries) {
|
||||||
|
this.seriesSet.splice(i, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If a timer was operating for that timeseries, remove it
|
||||||
|
if (timeSeries.resetBoundsTimerId) {
|
||||||
|
// Stop resetting the bounds, if we were
|
||||||
|
clearInterval(timeSeries.resetBoundsTimerId);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets render options for the specified <code>TimeSeries</code>.
|
||||||
|
*
|
||||||
|
* As you may use a single <code>TimeSeries</code> in multiple charts with different formatting in each usage,
|
||||||
|
* these settings are stored in the chart.
|
||||||
|
*/
|
||||||
|
SmoothieChart.prototype.getTimeSeriesOptions = function(timeSeries) {
|
||||||
|
// Find the correct timeseries to remove, and remove it
|
||||||
|
var numSeries = this.seriesSet.length;
|
||||||
|
for (var i = 0; i < numSeries; i++) {
|
||||||
|
if (this.seriesSet[i].timeSeries === timeSeries) {
|
||||||
|
return this.seriesSet[i].options;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Brings the specified <code>TimeSeries</code> to the top of the chart. It will be rendered last.
|
||||||
|
*/
|
||||||
|
SmoothieChart.prototype.bringToFront = function(timeSeries) {
|
||||||
|
// Find the correct timeseries to remove, and remove it
|
||||||
|
var numSeries = this.seriesSet.length;
|
||||||
|
for (var i = 0; i < numSeries; i++) {
|
||||||
|
if (this.seriesSet[i].timeSeries === timeSeries) {
|
||||||
|
var set = this.seriesSet.splice(i, 1);
|
||||||
|
this.seriesSet.push(set[0]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instructs the <code>SmoothieChart</code> to start rendering to the provided canvas, with specified delay.
|
||||||
|
*
|
||||||
|
* @param canvas the target canvas element
|
||||||
|
* @param delayMillis an amount of time to wait before a data point is shown. This can prevent the end of the series
|
||||||
|
* from appearing on screen, with new values flashing into view, at the expense of some latency.
|
||||||
|
*/
|
||||||
|
SmoothieChart.prototype.streamTo = function(canvas, delayMillis) {
|
||||||
|
this.canvas = canvas;
|
||||||
|
this.delay = delayMillis;
|
||||||
|
this.start();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make sure the canvas has the optimal resolution for the device's pixel ratio.
|
||||||
|
*/
|
||||||
|
SmoothieChart.prototype.resize = function() {
|
||||||
|
// TODO this function doesn't handle the value of enableDpiScaling changing during execution
|
||||||
|
if (!this.options.enableDpiScaling || !window || window.devicePixelRatio === 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var dpr = window.devicePixelRatio;
|
||||||
|
var width = parseInt(this.canvas.getAttribute('width'));
|
||||||
|
var height = parseInt(this.canvas.getAttribute('height'));
|
||||||
|
|
||||||
|
if (!this.originalWidth || (Math.floor(this.originalWidth * dpr) !== width)) {
|
||||||
|
this.originalWidth = width;
|
||||||
|
this.canvas.setAttribute('width', (Math.floor(width * dpr)).toString());
|
||||||
|
this.canvas.style.width = width + 'px';
|
||||||
|
this.canvas.getContext('2d').scale(dpr, dpr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.originalHeight || (Math.floor(this.originalHeight * dpr) !== height)) {
|
||||||
|
this.originalHeight = height;
|
||||||
|
this.canvas.setAttribute('height', (Math.floor(height * dpr)).toString());
|
||||||
|
this.canvas.style.height = height + 'px';
|
||||||
|
this.canvas.getContext('2d').scale(dpr, dpr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the animation of this chart.
|
||||||
|
*/
|
||||||
|
SmoothieChart.prototype.start = function() {
|
||||||
|
if (this.frame) {
|
||||||
|
// We're already running, so just return
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Renders a frame, and queues the next frame for later rendering
|
||||||
|
var animate = function() {
|
||||||
|
this.frame = SmoothieChart.AnimateCompatibility.requestAnimationFrame(function() {
|
||||||
|
this.render();
|
||||||
|
animate();
|
||||||
|
}.bind(this));
|
||||||
|
}.bind(this);
|
||||||
|
|
||||||
|
animate();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops the animation of this chart.
|
||||||
|
*/
|
||||||
|
SmoothieChart.prototype.stop = function() {
|
||||||
|
if (this.frame) {
|
||||||
|
SmoothieChart.AnimateCompatibility.cancelAnimationFrame(this.frame);
|
||||||
|
delete this.frame;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SmoothieChart.prototype.updateValueRange = function() {
|
||||||
|
// Calculate the current scale of the chart, from all time series.
|
||||||
|
var chartOptions = this.options,
|
||||||
|
chartMaxValue = Number.NaN,
|
||||||
|
chartMinValue = Number.NaN;
|
||||||
|
|
||||||
|
for (var d = 0; d < this.seriesSet.length; d++) {
|
||||||
|
// TODO(ndunn): We could calculate / track these values as they stream in.
|
||||||
|
var timeSeries = this.seriesSet[d].timeSeries;
|
||||||
|
if (!isNaN(timeSeries.maxValue)) {
|
||||||
|
chartMaxValue = !isNaN(chartMaxValue) ? Math.max(chartMaxValue, timeSeries.maxValue) : timeSeries.maxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isNaN(timeSeries.minValue)) {
|
||||||
|
chartMinValue = !isNaN(chartMinValue) ? Math.min(chartMinValue, timeSeries.minValue) : timeSeries.minValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scale the chartMaxValue to add padding at the top if required
|
||||||
|
if (chartOptions.maxValue != null) {
|
||||||
|
chartMaxValue = chartOptions.maxValue;
|
||||||
|
} else {
|
||||||
|
chartMaxValue *= chartOptions.maxValueScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the minimum if we've specified one
|
||||||
|
if (chartOptions.minValue != null) {
|
||||||
|
chartMinValue = chartOptions.minValue;
|
||||||
|
} else {
|
||||||
|
chartMinValue -= Math.abs(chartMinValue * chartOptions.minValueScale - chartMinValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a custom range function is set, call it
|
||||||
|
if (this.options.yRangeFunction) {
|
||||||
|
var range = this.options.yRangeFunction({min: chartMinValue, max: chartMaxValue});
|
||||||
|
chartMinValue = range.min;
|
||||||
|
chartMaxValue = range.max;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isNaN(chartMaxValue) && !isNaN(chartMinValue)) {
|
||||||
|
var targetValueRange = chartMaxValue - chartMinValue;
|
||||||
|
var valueRangeDiff = (targetValueRange - this.currentValueRange);
|
||||||
|
var minValueDiff = (chartMinValue - this.currentVisMinValue);
|
||||||
|
this.isAnimatingScale = Math.abs(valueRangeDiff) > 0.1 || Math.abs(minValueDiff) > 0.1;
|
||||||
|
this.currentValueRange += chartOptions.scaleSmoothing * valueRangeDiff;
|
||||||
|
this.currentVisMinValue += chartOptions.scaleSmoothing * minValueDiff;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.valueRange = { min: chartMinValue, max: chartMaxValue };
|
||||||
|
};
|
||||||
|
|
||||||
|
SmoothieChart.prototype.render = function(canvas, time) {
|
||||||
|
var nowMillis = new Date().getTime();
|
||||||
|
|
||||||
|
if (!this.isAnimatingScale) {
|
||||||
|
// We're not animating. We can use the last render time and the scroll speed to work out whether
|
||||||
|
// we actually need to paint anything yet. If not, we can return immediately.
|
||||||
|
|
||||||
|
// Render at least every 1/6th of a second. The canvas may be resized, which there is
|
||||||
|
// no reliable way to detect.
|
||||||
|
var maxIdleMillis = Math.min(1000/6, this.options.millisPerPixel);
|
||||||
|
|
||||||
|
if (nowMillis - this.lastRenderTimeMillis < maxIdleMillis) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.resize();
|
||||||
|
|
||||||
|
this.lastRenderTimeMillis = nowMillis;
|
||||||
|
|
||||||
|
canvas = canvas || this.canvas;
|
||||||
|
time = time || nowMillis - (this.delay || 0);
|
||||||
|
|
||||||
|
// Round time down to pixel granularity, so motion appears smoother.
|
||||||
|
time -= time % this.options.millisPerPixel;
|
||||||
|
|
||||||
|
var context = canvas.getContext('2d'),
|
||||||
|
chartOptions = this.options,
|
||||||
|
dimensions = { top: 0, left: 0, width: canvas.clientWidth, height: canvas.clientHeight },
|
||||||
|
// Calculate the threshold time for the oldest data points.
|
||||||
|
oldestValidTime = time - (dimensions.width * chartOptions.millisPerPixel),
|
||||||
|
valueToYPixel = function(value) {
|
||||||
|
var offset = value - this.currentVisMinValue;
|
||||||
|
return this.currentValueRange === 0
|
||||||
|
? dimensions.height
|
||||||
|
: dimensions.height - (Math.round((offset / this.currentValueRange) * dimensions.height));
|
||||||
|
}.bind(this),
|
||||||
|
timeToXPixel = function(t) {
|
||||||
|
if(chartOptions.scrollBackwards) {
|
||||||
|
return Math.round((time - t) / chartOptions.millisPerPixel);
|
||||||
|
}
|
||||||
|
return Math.round(dimensions.width - ((time - t) / chartOptions.millisPerPixel));
|
||||||
|
};
|
||||||
|
|
||||||
|
this.updateValueRange();
|
||||||
|
|
||||||
|
context.font = chartOptions.labels.fontSize + 'px ' + chartOptions.labels.fontFamily;
|
||||||
|
|
||||||
|
// Save the state of the canvas context, any transformations applied in this method
|
||||||
|
// will get removed from the stack at the end of this method when .restore() is called.
|
||||||
|
context.save();
|
||||||
|
|
||||||
|
// Move the origin.
|
||||||
|
context.translate(dimensions.left, dimensions.top);
|
||||||
|
|
||||||
|
// Create a clipped rectangle - anything we draw will be constrained to this rectangle.
|
||||||
|
// This prevents the occasional pixels from curves near the edges overrunning and creating
|
||||||
|
// screen cheese (that phrase should need no explanation).
|
||||||
|
context.beginPath();
|
||||||
|
context.rect(0, 0, dimensions.width, dimensions.height);
|
||||||
|
context.clip();
|
||||||
|
|
||||||
|
// Clear the working area.
|
||||||
|
context.save();
|
||||||
|
context.fillStyle = chartOptions.grid.fillStyle;
|
||||||
|
context.clearRect(0, 0, dimensions.width, dimensions.height);
|
||||||
|
context.fillRect(0, 0, dimensions.width, dimensions.height);
|
||||||
|
context.restore();
|
||||||
|
|
||||||
|
// Grid lines...
|
||||||
|
context.save();
|
||||||
|
context.lineWidth = chartOptions.grid.lineWidth;
|
||||||
|
context.strokeStyle = chartOptions.grid.strokeStyle;
|
||||||
|
// Vertical (time) dividers.
|
||||||
|
if (chartOptions.grid.millisPerLine > 0) {
|
||||||
|
context.beginPath();
|
||||||
|
for (var t = time - (time % chartOptions.grid.millisPerLine);
|
||||||
|
t >= oldestValidTime;
|
||||||
|
t -= chartOptions.grid.millisPerLine) {
|
||||||
|
var gx = timeToXPixel(t);
|
||||||
|
if (chartOptions.grid.sharpLines) {
|
||||||
|
gx -= 0.5;
|
||||||
|
}
|
||||||
|
context.moveTo(gx, 0);
|
||||||
|
context.lineTo(gx, dimensions.height);
|
||||||
|
}
|
||||||
|
context.stroke();
|
||||||
|
context.closePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Horizontal (value) dividers.
|
||||||
|
for (var v = 1; v < chartOptions.grid.verticalSections; v++) {
|
||||||
|
var gy = Math.round(v * dimensions.height / chartOptions.grid.verticalSections);
|
||||||
|
if (chartOptions.grid.sharpLines) {
|
||||||
|
gy -= 0.5;
|
||||||
|
}
|
||||||
|
context.beginPath();
|
||||||
|
context.moveTo(0, gy);
|
||||||
|
context.lineTo(dimensions.width, gy);
|
||||||
|
context.stroke();
|
||||||
|
context.closePath();
|
||||||
|
}
|
||||||
|
// Bounding rectangle.
|
||||||
|
if (chartOptions.grid.borderVisible) {
|
||||||
|
context.beginPath();
|
||||||
|
context.strokeRect(0, 0, dimensions.width, dimensions.height);
|
||||||
|
context.closePath();
|
||||||
|
}
|
||||||
|
context.restore();
|
||||||
|
|
||||||
|
// Draw any horizontal lines...
|
||||||
|
if (chartOptions.horizontalLines && chartOptions.horizontalLines.length) {
|
||||||
|
for (var hl = 0; hl < chartOptions.horizontalLines.length; hl++) {
|
||||||
|
var line = chartOptions.horizontalLines[hl],
|
||||||
|
hly = Math.round(valueToYPixel(line.value)) - 0.5;
|
||||||
|
context.strokeStyle = line.color || '#ffffff';
|
||||||
|
context.lineWidth = line.lineWidth || 1;
|
||||||
|
context.beginPath();
|
||||||
|
context.moveTo(0, hly);
|
||||||
|
context.lineTo(dimensions.width, hly);
|
||||||
|
context.stroke();
|
||||||
|
context.closePath();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For each data set...
|
||||||
|
for (var d = 0; d < this.seriesSet.length; d++) {
|
||||||
|
context.save();
|
||||||
|
var timeSeries = this.seriesSet[d].timeSeries,
|
||||||
|
dataSet = timeSeries.data,
|
||||||
|
seriesOptions = this.seriesSet[d].options;
|
||||||
|
|
||||||
|
// Delete old data that's moved off the left of the chart.
|
||||||
|
timeSeries.dropOldData(oldestValidTime, chartOptions.maxDataSetLength);
|
||||||
|
|
||||||
|
// Set style for this dataSet.
|
||||||
|
context.lineWidth = seriesOptions.lineWidth;
|
||||||
|
context.strokeStyle = seriesOptions.strokeStyle;
|
||||||
|
// Draw the line...
|
||||||
|
context.beginPath();
|
||||||
|
// Retain lastX, lastY for calculating the control points of bezier curves.
|
||||||
|
var firstX = 0, lastX = 0, lastY = 0;
|
||||||
|
for (var i = 0; i < dataSet.length && dataSet.length !== 1; i++) {
|
||||||
|
var x = timeToXPixel(dataSet[i][0]),
|
||||||
|
y = valueToYPixel(dataSet[i][1]);
|
||||||
|
|
||||||
|
if (i === 0) {
|
||||||
|
firstX = x;
|
||||||
|
context.moveTo(x, y);
|
||||||
|
} else {
|
||||||
|
switch (chartOptions.interpolation) {
|
||||||
|
case "linear":
|
||||||
|
case "line": {
|
||||||
|
context.lineTo(x,y);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "bezier":
|
||||||
|
default: {
|
||||||
|
// Great explanation of Bezier curves: http://en.wikipedia.org/wiki/Bezier_curve#Quadratic_curves
|
||||||
|
//
|
||||||
|
// Assuming A was the last point in the line plotted and B is the new point,
|
||||||
|
// we draw a curve with control points P and Q as below.
|
||||||
|
//
|
||||||
|
// A---P
|
||||||
|
// |
|
||||||
|
// |
|
||||||
|
// |
|
||||||
|
// Q---B
|
||||||
|
//
|
||||||
|
// Importantly, A and P are at the same y coordinate, as are B and Q. This is
|
||||||
|
// so adjacent curves appear to flow as one.
|
||||||
|
//
|
||||||
|
context.bezierCurveTo( // startPoint (A) is implicit from last iteration of loop
|
||||||
|
Math.round((lastX + x) / 2), lastY, // controlPoint1 (P)
|
||||||
|
Math.round((lastX + x)) / 2, y, // controlPoint2 (Q)
|
||||||
|
x, y); // endPoint (B)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "step": {
|
||||||
|
context.lineTo(x,lastY);
|
||||||
|
context.lineTo(x,y);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lastX = x; lastY = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataSet.length > 1) {
|
||||||
|
if (seriesOptions.fillStyle) {
|
||||||
|
// Close up the fill region.
|
||||||
|
context.lineTo(dimensions.width + seriesOptions.lineWidth + 1, lastY);
|
||||||
|
context.lineTo(dimensions.width + seriesOptions.lineWidth + 1, dimensions.height + seriesOptions.lineWidth + 1);
|
||||||
|
context.lineTo(firstX, dimensions.height + seriesOptions.lineWidth);
|
||||||
|
context.fillStyle = seriesOptions.fillStyle;
|
||||||
|
context.fill();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seriesOptions.strokeStyle && seriesOptions.strokeStyle !== 'none') {
|
||||||
|
context.stroke();
|
||||||
|
}
|
||||||
|
context.closePath();
|
||||||
|
}
|
||||||
|
context.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the axis values on the chart.
|
||||||
|
if (!chartOptions.labels.disabled && !isNaN(this.valueRange.min) && !isNaN(this.valueRange.max)) {
|
||||||
|
var maxValueString = chartOptions.yMaxFormatter(this.valueRange.max, chartOptions.labels.precision),
|
||||||
|
minValueString = chartOptions.yMinFormatter(this.valueRange.min, chartOptions.labels.precision),
|
||||||
|
labelPos = chartOptions.scrollBackwards ? 0 : dimensions.width - context.measureText(maxValueString).width - 2;
|
||||||
|
context.fillStyle = chartOptions.labels.fillStyle;
|
||||||
|
context.fillText(maxValueString, labelPos, chartOptions.labels.fontSize);
|
||||||
|
context.fillText(minValueString, labelPos, dimensions.height - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display timestamps along x-axis at the bottom of the chart.
|
||||||
|
if (chartOptions.timestampFormatter && chartOptions.grid.millisPerLine > 0) {
|
||||||
|
var textUntilX = chartOptions.scrollBackwards
|
||||||
|
? context.measureText(minValueString).width
|
||||||
|
: dimensions.width - context.measureText(minValueString).width + 4;
|
||||||
|
for (var t = time - (time % chartOptions.grid.millisPerLine);
|
||||||
|
t >= oldestValidTime;
|
||||||
|
t -= chartOptions.grid.millisPerLine) {
|
||||||
|
var gx = timeToXPixel(t);
|
||||||
|
// Only draw the timestamp if it won't overlap with the previously drawn one.
|
||||||
|
if ((!chartOptions.scrollBackwards && gx < textUntilX) || (chartOptions.scrollBackwards && gx > textUntilX)) {
|
||||||
|
// Formats the timestamp based on user specified formatting function
|
||||||
|
// SmoothieChart.timeFormatter function above is one such formatting option
|
||||||
|
var tx = new Date(t),
|
||||||
|
ts = chartOptions.timestampFormatter(tx),
|
||||||
|
tsWidth = context.measureText(ts).width;
|
||||||
|
|
||||||
|
textUntilX = chartOptions.scrollBackwards
|
||||||
|
? gx + tsWidth + 2
|
||||||
|
: gx - tsWidth - 2;
|
||||||
|
|
||||||
|
context.fillStyle = chartOptions.labels.fillStyle;
|
||||||
|
if(chartOptions.scrollBackwards) {
|
||||||
|
context.fillText(ts, gx, dimensions.height - 2);
|
||||||
|
} else {
|
||||||
|
context.fillText(ts, gx - tsWidth, dimensions.height - 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context.restore(); // See .save() above.
|
||||||
|
};
|
||||||
|
|
||||||
|
// Sample timestamp formatting function
|
||||||
|
SmoothieChart.timeFormatter = function(date) {
|
||||||
|
function pad2(number) { return (number < 10 ? '0' : '') + number }
|
||||||
|
return pad2(date.getHours()) + ':' + pad2(date.getMinutes()) + ':' + pad2(date.getSeconds());
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.TimeSeries = TimeSeries;
|
||||||
|
exports.SmoothieChart = SmoothieChart;
|
||||||
|
|
||||||
|
})(typeof exports === 'undefined' ? this : exports);
|
120
platforms/android/assets/www/plugins/cordova-plugin-file/www/DirectoryEntry.js
vendored
Normal file
120
platforms/android/assets/www/plugins/cordova-plugin-file/www/DirectoryEntry.js
vendored
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
cordova.define("cordova-plugin-file.DirectoryEntry", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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 argscheck = require('cordova/argscheck'),
|
||||||
|
utils = require('cordova/utils'),
|
||||||
|
exec = require('cordova/exec'),
|
||||||
|
Entry = require('./Entry'),
|
||||||
|
FileError = require('./FileError'),
|
||||||
|
DirectoryReader = require('./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)
|
||||||
|
* {FileSystem} filesystem on which the directory resides (readonly)
|
||||||
|
*/
|
||||||
|
var DirectoryEntry = function(name, fullPath, fileSystem, nativeURL) {
|
||||||
|
|
||||||
|
// add trailing slash if it is missing
|
||||||
|
if ((fullPath) && !/\/$/.test(fullPath)) {
|
||||||
|
fullPath += "/";
|
||||||
|
}
|
||||||
|
// add trailing slash if it is missing
|
||||||
|
if (nativeURL && !/\/$/.test(nativeURL)) {
|
||||||
|
nativeURL += "/";
|
||||||
|
}
|
||||||
|
DirectoryEntry.__super__.constructor.call(this, false, true, name, fullPath, fileSystem, nativeURL);
|
||||||
|
};
|
||||||
|
|
||||||
|
utils.extend(DirectoryEntry, Entry);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new DirectoryReader to read entries from this directory
|
||||||
|
*/
|
||||||
|
DirectoryEntry.prototype.createReader = function() {
|
||||||
|
return new DirectoryReader(this.toInternalURL());
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 fs = this.filesystem;
|
||||||
|
var win = successCallback && function(result) {
|
||||||
|
var entry = new DirectoryEntry(result.name, result.fullPath, fs, result.nativeURL);
|
||||||
|
successCallback(entry);
|
||||||
|
};
|
||||||
|
var fail = errorCallback && function(code) {
|
||||||
|
errorCallback(new FileError(code));
|
||||||
|
};
|
||||||
|
exec(win, fail, "File", "getDirectory", [this.toInternalURL(), 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.toInternalURL()]);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 fs = this.filesystem;
|
||||||
|
var win = successCallback && function(result) {
|
||||||
|
var FileEntry = require('./FileEntry');
|
||||||
|
var entry = new FileEntry(result.name, result.fullPath, fs, result.nativeURL);
|
||||||
|
successCallback(entry);
|
||||||
|
};
|
||||||
|
var fail = errorCallback && function(code) {
|
||||||
|
errorCallback(new FileError(code));
|
||||||
|
};
|
||||||
|
exec(win, fail, "File", "getFile", [this.toInternalURL(), path, options]);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = DirectoryEntry;
|
||||||
|
|
||||||
|
});
|
76
platforms/android/assets/www/plugins/cordova-plugin-file/www/DirectoryReader.js
vendored
Normal file
76
platforms/android/assets/www/plugins/cordova-plugin-file/www/DirectoryReader.js
vendored
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
cordova.define("cordova-plugin-file.DirectoryReader", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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 exec = require('cordova/exec'),
|
||||||
|
FileError = require('./FileError') ;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface that lists the files and directories in a directory.
|
||||||
|
*/
|
||||||
|
function DirectoryReader(localURL) {
|
||||||
|
this.localURL = localURL || null;
|
||||||
|
this.hasReadEntries = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
||||||
|
// If we've already read and passed on this directory's entries, return an empty list.
|
||||||
|
if (this.hasReadEntries) {
|
||||||
|
successCallback([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var reader = this;
|
||||||
|
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('./DirectoryEntry'))();
|
||||||
|
}
|
||||||
|
else if (result[i].isFile) {
|
||||||
|
entry = new (require('./FileEntry'))();
|
||||||
|
}
|
||||||
|
entry.isDirectory = result[i].isDirectory;
|
||||||
|
entry.isFile = result[i].isFile;
|
||||||
|
entry.name = result[i].name;
|
||||||
|
entry.fullPath = result[i].fullPath;
|
||||||
|
entry.filesystem = new (require('./FileSystem'))(result[i].filesystemName);
|
||||||
|
entry.nativeURL = result[i].nativeURL;
|
||||||
|
retVal.push(entry);
|
||||||
|
}
|
||||||
|
reader.hasReadEntries = true;
|
||||||
|
successCallback(retVal);
|
||||||
|
};
|
||||||
|
var fail = typeof errorCallback !== 'function' ? null : function(code) {
|
||||||
|
errorCallback(new FileError(code));
|
||||||
|
};
|
||||||
|
exec(win, fail, "File", "readEntries", [this.localURL]);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = DirectoryReader;
|
||||||
|
|
||||||
|
});
|
265
platforms/android/assets/www/plugins/cordova-plugin-file/www/Entry.js
vendored
Normal file
265
platforms/android/assets/www/plugins/cordova-plugin-file/www/Entry.js
vendored
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
cordova.define("cordova-plugin-file.Entry", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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 argscheck = require('cordova/argscheck'),
|
||||||
|
exec = require('cordova/exec'),
|
||||||
|
FileError = require('./FileError'),
|
||||||
|
Metadata = require('./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)
|
||||||
|
* @param fileSystem
|
||||||
|
* {FileSystem} the filesystem on which this entry resides
|
||||||
|
* (readonly)
|
||||||
|
* @param nativeURL
|
||||||
|
* {DOMString} an alternate URL which can be used by native
|
||||||
|
* webview controls, for example media players.
|
||||||
|
* (optional, readonly)
|
||||||
|
*/
|
||||||
|
function Entry(isFile, isDirectory, name, fullPath, fileSystem, nativeURL) {
|
||||||
|
this.isFile = !!isFile;
|
||||||
|
this.isDirectory = !!isDirectory;
|
||||||
|
this.name = name || '';
|
||||||
|
this.fullPath = fullPath || '';
|
||||||
|
this.filesystem = fileSystem || null;
|
||||||
|
this.nativeURL = nativeURL || 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(entryMetadata) {
|
||||||
|
var metadata = new Metadata({
|
||||||
|
size: entryMetadata.size,
|
||||||
|
modificationTime: entryMetadata.lastModifiedDate
|
||||||
|
});
|
||||||
|
successCallback(metadata);
|
||||||
|
};
|
||||||
|
var fail = errorCallback && function(code) {
|
||||||
|
errorCallback(new FileError(code));
|
||||||
|
};
|
||||||
|
exec(success, fail, "File", "getFileMetadata", [this.toInternalURL()]);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.toInternalURL(), 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));
|
||||||
|
};
|
||||||
|
var srcURL = this.toInternalURL(),
|
||||||
|
// entry name
|
||||||
|
name = newName || this.name,
|
||||||
|
success = function(entry) {
|
||||||
|
if (entry) {
|
||||||
|
if (successCallback) {
|
||||||
|
// create appropriate Entry object
|
||||||
|
var newFSName = entry.filesystemName || (entry.filesystem && entry.filesystem.name);
|
||||||
|
var fs = newFSName ? new FileSystem(newFSName, { name: "", fullPath: "/" }) : new FileSystem(parent.filesystem.name, { name: "", fullPath: "/" });
|
||||||
|
var result = (entry.isDirectory) ? new (require('./DirectoryEntry'))(entry.name, entry.fullPath, fs, entry.nativeURL) : new (require('cordova-plugin-file.FileEntry'))(entry.name, entry.fullPath, fs, entry.nativeURL);
|
||||||
|
successCallback(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// no Entry object returned
|
||||||
|
if (fail) {
|
||||||
|
fail(FileError.NOT_FOUND_ERR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// copy
|
||||||
|
exec(success, fail, "File", "moveTo", [srcURL, parent.toInternalURL(), 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));
|
||||||
|
};
|
||||||
|
var srcURL = this.toInternalURL(),
|
||||||
|
// entry name
|
||||||
|
name = newName || this.name,
|
||||||
|
// success callback
|
||||||
|
success = function(entry) {
|
||||||
|
if (entry) {
|
||||||
|
if (successCallback) {
|
||||||
|
// create appropriate Entry object
|
||||||
|
var newFSName = entry.filesystemName || (entry.filesystem && entry.filesystem.name);
|
||||||
|
var fs = newFSName ? new FileSystem(newFSName, { name: "", fullPath: "/" }) : new FileSystem(parent.filesystem.name, { name: "", fullPath: "/" });
|
||||||
|
var result = (entry.isDirectory) ? new (require('./DirectoryEntry'))(entry.name, entry.fullPath, fs, entry.nativeURL) : new (require('cordova-plugin-file.FileEntry'))(entry.name, entry.fullPath, fs, entry.nativeURL);
|
||||||
|
successCallback(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// no Entry object returned
|
||||||
|
if (fail) {
|
||||||
|
fail(FileError.NOT_FOUND_ERR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// copy
|
||||||
|
exec(success, fail, "File", "copyTo", [srcURL, parent.toInternalURL(), name]);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a URL that can be passed across the bridge to identify this entry.
|
||||||
|
*/
|
||||||
|
Entry.prototype.toInternalURL = function() {
|
||||||
|
if (this.filesystem && this.filesystem.__format__) {
|
||||||
|
return this.filesystem.__format__(this.fullPath, this.nativeURL);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a URL that can be used to identify this entry.
|
||||||
|
* Use a URL that can be used to as the src attribute of a <video> or
|
||||||
|
* <audio> tag. If that is not possible, construct a cdvfile:// URL.
|
||||||
|
*/
|
||||||
|
Entry.prototype.toURL = function() {
|
||||||
|
if (this.nativeURL) {
|
||||||
|
return this.nativeURL;
|
||||||
|
}
|
||||||
|
// fullPath attribute may contain the full URL in the case that
|
||||||
|
// toInternalURL fails.
|
||||||
|
return this.toInternalURL() || "file://localhost" + this.fullPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Backwards-compatibility: In v1.0.0 - 1.0.2, .toURL would only return a
|
||||||
|
* cdvfile:// URL, and this method was necessary to obtain URLs usable by the
|
||||||
|
* webview.
|
||||||
|
* See CB-6051, CB-6106, CB-6117, CB-6152, CB-6199, CB-6201, CB-6243, CB-6249,
|
||||||
|
* and CB-6300.
|
||||||
|
*/
|
||||||
|
Entry.prototype.toNativeURL = function() {
|
||||||
|
console.log("DEPRECATED: Update your code to use 'toURL'");
|
||||||
|
return this.toURL();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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'");
|
||||||
|
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.toInternalURL()]);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 fs = this.filesystem;
|
||||||
|
var win = successCallback && function(result) {
|
||||||
|
var DirectoryEntry = require('./DirectoryEntry');
|
||||||
|
var entry = new DirectoryEntry(result.name, result.fullPath, fs, result.nativeURL);
|
||||||
|
successCallback(entry);
|
||||||
|
};
|
||||||
|
var fail = errorCallback && function(code) {
|
||||||
|
errorCallback(new FileError(code));
|
||||||
|
};
|
||||||
|
exec(win, fail, "File", "getParent", [this.toInternalURL()]);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = Entry;
|
||||||
|
|
||||||
|
});
|
82
platforms/android/assets/www/plugins/cordova-plugin-file/www/File.js
vendored
Normal file
82
platforms/android/assets/www/plugins/cordova-plugin-file/www/File.js
vendored
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
cordova.define("cordova-plugin-file.File", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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, localURL, type, lastModifiedDate, size){
|
||||||
|
this.name = name || '';
|
||||||
|
this.localURL = localURL || null;
|
||||||
|
this.type = type || null;
|
||||||
|
this.lastModified = lastModifiedDate || null;
|
||||||
|
// For backwards compatibility, store the timestamp in lastModifiedDate as well
|
||||||
|
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.localURL, this.type, this.lastModified, this.size);
|
||||||
|
newFile.start = this.start + newStart;
|
||||||
|
newFile.end = this.start + newEnd;
|
||||||
|
return newFile;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = File;
|
||||||
|
|
||||||
|
});
|
96
platforms/android/assets/www/plugins/cordova-plugin-file/www/FileEntry.js
vendored
Normal file
96
platforms/android/assets/www/plugins/cordova-plugin-file/www/FileEntry.js
vendored
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
cordova.define("cordova-plugin-file.FileEntry", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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 utils = require('cordova/utils'),
|
||||||
|
exec = require('cordova/exec'),
|
||||||
|
Entry = require('./Entry'),
|
||||||
|
FileWriter = require('./FileWriter'),
|
||||||
|
File = require('./File'),
|
||||||
|
FileError = require('./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, fileSystem, nativeURL) {
|
||||||
|
// remove trailing slash if it is present
|
||||||
|
if (fullPath && /\/$/.test(fullPath)) {
|
||||||
|
fullPath = fullPath.substring(0, fullPath.length - 1);
|
||||||
|
}
|
||||||
|
if (nativeURL && /\/$/.test(nativeURL)) {
|
||||||
|
nativeURL = nativeURL.substring(0, nativeURL.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileEntry.__super__.constructor.apply(this, [true, false, name, fullPath, fileSystem, nativeURL]);
|
||||||
|
};
|
||||||
|
|
||||||
|
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.localURL === null || writer.localURL === "") {
|
||||||
|
if (errorCallback) {
|
||||||
|
errorCallback(new FileError(FileError.INVALID_STATE_ERR));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (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 localURL = this.toInternalURL();
|
||||||
|
var win = successCallback && function(f) {
|
||||||
|
var file = new File(f.name, localURL, f.type, f.lastModifiedDate, f.size);
|
||||||
|
successCallback(file);
|
||||||
|
};
|
||||||
|
var fail = errorCallback && function(code) {
|
||||||
|
errorCallback(new FileError(code));
|
||||||
|
};
|
||||||
|
exec(win, fail, "File", "getFileMetadata", [localURL]);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = FileEntry;
|
||||||
|
|
||||||
|
});
|
49
platforms/android/assets/www/plugins/cordova-plugin-file/www/FileError.js
vendored
Normal file
49
platforms/android/assets/www/plugins/cordova-plugin-file/www/FileError.js
vendored
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
cordova.define("cordova-plugin-file.FileError", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
});
|
292
platforms/android/assets/www/plugins/cordova-plugin-file/www/FileReader.js
vendored
Normal file
292
platforms/android/assets/www/plugins/cordova-plugin-file/www/FileReader.js
vendored
Normal file
@ -0,0 +1,292 @@
|
|||||||
|
cordova.define("cordova-plugin-file.FileReader", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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 exec = require('cordova/exec'),
|
||||||
|
modulemapper = require('cordova/modulemapper'),
|
||||||
|
utils = require('cordova/utils'),
|
||||||
|
FileError = require('./FileError'),
|
||||||
|
ProgressEvent = require('./ProgressEvent'),
|
||||||
|
origFileReader = modulemapper.getOriginalSymbol(window, '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._progress = null;
|
||||||
|
this._localURL = '';
|
||||||
|
this._realReader = origFileReader ? new origFileReader() : {};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the maximum size to read at a time via the native API. The default value is a compromise between
|
||||||
|
* minimizing the overhead of many exec() calls while still reporting progress frequently enough for large files.
|
||||||
|
* (Note attempts to allocate more than a few MB of contiguous memory on the native side are likely to cause
|
||||||
|
* OOM exceptions, while the JS engine seems to have fewer problems managing large strings or ArrayBuffers.)
|
||||||
|
*/
|
||||||
|
FileReader.READ_CHUNK_SIZE = 256*1024;
|
||||||
|
|
||||||
|
// States
|
||||||
|
FileReader.EMPTY = 0;
|
||||||
|
FileReader.LOADING = 1;
|
||||||
|
FileReader.DONE = 2;
|
||||||
|
|
||||||
|
utils.defineGetter(FileReader.prototype, 'readyState', function() {
|
||||||
|
return this._localURL ? this._readyState : this._realReader.readyState;
|
||||||
|
});
|
||||||
|
|
||||||
|
utils.defineGetter(FileReader.prototype, 'error', function() {
|
||||||
|
return this._localURL ? this._error: this._realReader.error;
|
||||||
|
});
|
||||||
|
|
||||||
|
utils.defineGetter(FileReader.prototype, 'result', function() {
|
||||||
|
return this._localURL ? 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._progress = 0;
|
||||||
|
reader._readyState = FileReader.LOADING;
|
||||||
|
|
||||||
|
if (typeof file.localURL == 'string') {
|
||||||
|
reader._localURL = file.localURL;
|
||||||
|
} else {
|
||||||
|
reader._localURL = '';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reader.onloadstart) {
|
||||||
|
reader.onloadstart(new ProgressEvent("loadstart", {target:reader}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback used by the following read* functions to handle incremental or final success.
|
||||||
|
* Must be bound to the FileReader's this along with all but the last parameter,
|
||||||
|
* e.g. readSuccessCallback.bind(this, "readAsText", "UTF-8", offset, totalSize, accumulate)
|
||||||
|
* @param readType The name of the read function to call.
|
||||||
|
* @param encoding Text encoding, or null if this is not a text type read.
|
||||||
|
* @param offset Starting offset of the read.
|
||||||
|
* @param totalSize Total number of bytes or chars to read.
|
||||||
|
* @param accumulate A function that takes the callback result and accumulates it in this._result.
|
||||||
|
* @param r Callback result returned by the last read exec() call, or null to begin reading.
|
||||||
|
*/
|
||||||
|
function readSuccessCallback(readType, encoding, offset, totalSize, accumulate, r) {
|
||||||
|
if (this._readyState === FileReader.DONE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof r !== "undefined") {
|
||||||
|
accumulate(r);
|
||||||
|
this._progress = Math.min(this._progress + FileReader.READ_CHUNK_SIZE, totalSize);
|
||||||
|
|
||||||
|
if (typeof this.onprogress === "function") {
|
||||||
|
this.onprogress(new ProgressEvent("progress", {loaded:this._progress, total:totalSize}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof r === "undefined" || this._progress < totalSize) {
|
||||||
|
var execArgs = [
|
||||||
|
this._localURL,
|
||||||
|
offset + this._progress,
|
||||||
|
offset + this._progress + Math.min(totalSize - this._progress, FileReader.READ_CHUNK_SIZE)];
|
||||||
|
if (encoding) {
|
||||||
|
execArgs.splice(1, 0, encoding);
|
||||||
|
}
|
||||||
|
exec(
|
||||||
|
readSuccessCallback.bind(this, readType, encoding, offset, totalSize, accumulate),
|
||||||
|
readFailureCallback.bind(this),
|
||||||
|
"File", readType, execArgs);
|
||||||
|
} else {
|
||||||
|
this._readyState = FileReader.DONE;
|
||||||
|
|
||||||
|
if (typeof this.onload === "function") {
|
||||||
|
this.onload(new ProgressEvent("load", {target:this}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof this.onloadend === "function") {
|
||||||
|
this.onloadend(new ProgressEvent("loadend", {target:this}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback used by the following read* functions to handle errors.
|
||||||
|
* Must be bound to the FileReader's this, e.g. readFailureCallback.bind(this)
|
||||||
|
*/
|
||||||
|
function readFailureCallback(e) {
|
||||||
|
if (this._readyState === FileReader.DONE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._readyState = FileReader.DONE;
|
||||||
|
this._result = null;
|
||||||
|
this._error = new FileError(e);
|
||||||
|
|
||||||
|
if (typeof this.onerror === "function") {
|
||||||
|
this.onerror(new ProgressEvent("error", {target:this}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof this.onloadend === "function") {
|
||||||
|
this.onloadend(new ProgressEvent("loadend", {target:this}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abort reading file.
|
||||||
|
*/
|
||||||
|
FileReader.prototype.abort = function() {
|
||||||
|
if (origFileReader && !this._localURL) {
|
||||||
|
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 totalSize = file.end - file.start;
|
||||||
|
readSuccessCallback.bind(this)("readAsText", enc, file.start, totalSize, function(r) {
|
||||||
|
if (this._progress === 0) {
|
||||||
|
this._result = "";
|
||||||
|
}
|
||||||
|
this._result += r;
|
||||||
|
}.bind(this));
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 totalSize = file.end - file.start;
|
||||||
|
readSuccessCallback.bind(this)("readAsDataURL", null, file.start, totalSize, function(r) {
|
||||||
|
var commaIndex = r.indexOf(',');
|
||||||
|
if (this._progress === 0) {
|
||||||
|
this._result = r;
|
||||||
|
} else {
|
||||||
|
this._result += r.substring(commaIndex + 1);
|
||||||
|
}
|
||||||
|
}.bind(this));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 totalSize = file.end - file.start;
|
||||||
|
readSuccessCallback.bind(this)("readAsBinaryString", null, file.start, totalSize, function(r) {
|
||||||
|
if (this._progress === 0) {
|
||||||
|
this._result = "";
|
||||||
|
}
|
||||||
|
this._result += r;
|
||||||
|
}.bind(this));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 totalSize = file.end - file.start;
|
||||||
|
readSuccessCallback.bind(this)("readAsArrayBuffer", null, file.start, totalSize, function(r) {
|
||||||
|
var resultArray = (this._progress === 0 ? new Uint8Array(totalSize) : new Uint8Array(this._result));
|
||||||
|
resultArray.set(new Uint8Array(r), this._progress);
|
||||||
|
this._result = resultArray.buffer;
|
||||||
|
}.bind(this));
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = FileReader;
|
||||||
|
|
||||||
|
});
|
58
platforms/android/assets/www/plugins/cordova-plugin-file/www/FileSystem.js
vendored
Normal file
58
platforms/android/assets/www/plugins/cordova-plugin-file/www/FileSystem.js
vendored
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
cordova.define("cordova-plugin-file.FileSystem", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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 DirectoryEntry = require('./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;
|
||||||
|
if (root) {
|
||||||
|
this.root = new DirectoryEntry(root.name, root.fullPath, this, root.nativeURL);
|
||||||
|
} else {
|
||||||
|
this.root = new DirectoryEntry(this.name, '/', this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
FileSystem.prototype.__format__ = function(fullPath, nativeUrl) {
|
||||||
|
return fullPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
FileSystem.prototype.toJSON = function() {
|
||||||
|
return "<FileSystem: " + this.name + ">";
|
||||||
|
};
|
||||||
|
|
||||||
|
// Use instead of encodeURI() when encoding just the path part of a URI rather than an entire URI.
|
||||||
|
FileSystem.encodeURIPath = function(path) {
|
||||||
|
// Because # is a valid filename character, it must be encoded to prevent part of the
|
||||||
|
// path from being parsed as a URI fragment.
|
||||||
|
return encodeURI(path).replace(/#/g, '%23');
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = FileSystem;
|
||||||
|
|
||||||
|
});
|
44
platforms/android/assets/www/plugins/cordova-plugin-file/www/FileUploadOptions.js
vendored
Normal file
44
platforms/android/assets/www/plugins/cordova-plugin-file/www/FileUploadOptions.js
vendored
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
cordova.define("cordova-plugin-file.FileUploadOptions", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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, httpMethod) {
|
||||||
|
this.fileKey = fileKey || null;
|
||||||
|
this.fileName = fileName || null;
|
||||||
|
this.mimeType = mimeType || null;
|
||||||
|
this.params = params || null;
|
||||||
|
this.headers = headers || null;
|
||||||
|
this.httpMethod = httpMethod || null;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = FileUploadOptions;
|
||||||
|
|
||||||
|
});
|
32
platforms/android/assets/www/plugins/cordova-plugin-file/www/FileUploadResult.js
vendored
Normal file
32
platforms/android/assets/www/plugins/cordova-plugin-file/www/FileUploadResult.js
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
cordova.define("cordova-plugin-file.FileUploadResult", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FileUploadResult
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
module.exports = function FileUploadResult(size, code, content) {
|
||||||
|
this.bytesSent = size;
|
||||||
|
this.responseCode = code;
|
||||||
|
this.response = content;
|
||||||
|
};
|
||||||
|
});
|
327
platforms/android/assets/www/plugins/cordova-plugin-file/www/FileWriter.js
vendored
Normal file
327
platforms/android/assets/www/plugins/cordova-plugin-file/www/FileWriter.js
vendored
Normal file
@ -0,0 +1,327 @@
|
|||||||
|
cordova.define("cordova-plugin-file.FileWriter", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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 exec = require('cordova/exec'),
|
||||||
|
FileError = require('./FileError'),
|
||||||
|
ProgressEvent = require('./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.localURL = file.localURL || 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.onerror = null; // When the write has failed (see errors).
|
||||||
|
};
|
||||||
|
|
||||||
|
// States
|
||||||
|
FileWriter.INIT = 0;
|
||||||
|
FileWriter.WRITING = 1;
|
||||||
|
FileWriter.DONE = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abort writing file.
|
||||||
|
*/
|
||||||
|
FileWriter.prototype.abort = function() {
|
||||||
|
// check for invalid state
|
||||||
|
if (this.readyState === FileWriter.DONE || this.readyState === FileWriter.INIT) {
|
||||||
|
throw new FileError(FileError.INVALID_STATE_ERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set error
|
||||||
|
this.error = new FileError(FileError.ABORT_ERR);
|
||||||
|
|
||||||
|
this.readyState = FileWriter.DONE;
|
||||||
|
|
||||||
|
// If abort callback
|
||||||
|
if (typeof this.onabort === "function") {
|
||||||
|
this.onabort(new ProgressEvent("abort", {"target":this}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If write end callback
|
||||||
|
if (typeof this.onwriteend === "function") {
|
||||||
|
this.onwriteend(new ProgressEvent("writeend", {"target":this}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes data to the file
|
||||||
|
*
|
||||||
|
* @param data text or blob to be written
|
||||||
|
* @param isPendingBlobReadResult {Boolean} true if the data is the pending blob read operation result
|
||||||
|
*/
|
||||||
|
FileWriter.prototype.write = function(data, isPendingBlobReadResult) {
|
||||||
|
|
||||||
|
var that=this;
|
||||||
|
var supportsBinary = (typeof window.Blob !== 'undefined' && typeof window.ArrayBuffer !== 'undefined');
|
||||||
|
var isProxySupportBlobNatively = (cordova.platformId === "windows8" || cordova.platformId === "windows");
|
||||||
|
var isBinary;
|
||||||
|
|
||||||
|
// Check to see if the incoming data is a blob
|
||||||
|
if (data instanceof File || (!isProxySupportBlobNatively && supportsBinary && data instanceof Blob)) {
|
||||||
|
var fileReader = new FileReader();
|
||||||
|
fileReader.onload = function() {
|
||||||
|
// Call this method again, with the arraybuffer as argument
|
||||||
|
FileWriter.prototype.write.call(that, this.result, true /* isPendingBlobReadResult */);
|
||||||
|
};
|
||||||
|
fileReader.onerror = function () {
|
||||||
|
// DONE state
|
||||||
|
that.readyState = FileWriter.DONE;
|
||||||
|
|
||||||
|
// Save error
|
||||||
|
that.error = this.error;
|
||||||
|
|
||||||
|
// If onerror callback
|
||||||
|
if (typeof that.onerror === "function") {
|
||||||
|
that.onerror(new ProgressEvent("error", {"target":that}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If onwriteend callback
|
||||||
|
if (typeof that.onwriteend === "function") {
|
||||||
|
that.onwriteend(new ProgressEvent("writeend", {"target":that}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// WRITING state
|
||||||
|
this.readyState = FileWriter.WRITING;
|
||||||
|
|
||||||
|
if (supportsBinary) {
|
||||||
|
fileReader.readAsArrayBuffer(data);
|
||||||
|
} else {
|
||||||
|
fileReader.readAsText(data);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark data type for safer transport over the binary bridge
|
||||||
|
isBinary = supportsBinary && (data instanceof ArrayBuffer);
|
||||||
|
if (isBinary && cordova.platformId === "windowsphone") {
|
||||||
|
// create a plain array, using the keys from the Uint8Array view so that we can serialize it
|
||||||
|
data = Array.apply(null, new Uint8Array(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Throw an exception if we are already writing a file
|
||||||
|
if (this.readyState === FileWriter.WRITING && !isPendingBlobReadResult) {
|
||||||
|
throw new FileError(FileError.INVALID_STATE_ERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// WRITING state
|
||||||
|
this.readyState = FileWriter.WRITING;
|
||||||
|
|
||||||
|
var me = this;
|
||||||
|
|
||||||
|
// If onwritestart callback
|
||||||
|
if (typeof me.onwritestart === "function") {
|
||||||
|
me.onwritestart(new ProgressEvent("writestart", {"target":me}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write file
|
||||||
|
exec(
|
||||||
|
// Success callback
|
||||||
|
function(r) {
|
||||||
|
// If DONE (cancelled), then don't do anything
|
||||||
|
if (me.readyState === FileWriter.DONE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// position always increases by bytes written because file would be extended
|
||||||
|
me.position += r;
|
||||||
|
// The length of the file is now where we are done writing.
|
||||||
|
|
||||||
|
me.length = me.position;
|
||||||
|
|
||||||
|
// DONE state
|
||||||
|
me.readyState = FileWriter.DONE;
|
||||||
|
|
||||||
|
// If onwrite callback
|
||||||
|
if (typeof me.onwrite === "function") {
|
||||||
|
me.onwrite(new ProgressEvent("write", {"target":me}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If onwriteend callback
|
||||||
|
if (typeof me.onwriteend === "function") {
|
||||||
|
me.onwriteend(new ProgressEvent("writeend", {"target":me}));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Error callback
|
||||||
|
function(e) {
|
||||||
|
// If DONE (cancelled), then don't do anything
|
||||||
|
if (me.readyState === FileWriter.DONE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DONE state
|
||||||
|
me.readyState = FileWriter.DONE;
|
||||||
|
|
||||||
|
// Save error
|
||||||
|
me.error = new FileError(e);
|
||||||
|
|
||||||
|
// If onerror callback
|
||||||
|
if (typeof me.onerror === "function") {
|
||||||
|
me.onerror(new ProgressEvent("error", {"target":me}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If onwriteend callback
|
||||||
|
if (typeof me.onwriteend === "function") {
|
||||||
|
me.onwriteend(new ProgressEvent("writeend", {"target":me}));
|
||||||
|
}
|
||||||
|
}, "File", "write", [this.localURL, data, this.position, isBinary]);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the file pointer to the location specified.
|
||||||
|
*
|
||||||
|
* If the offset is a negative number the position of the file
|
||||||
|
* pointer is rewound. If the offset is greater than the file
|
||||||
|
* size the position is set to the end of the file.
|
||||||
|
*
|
||||||
|
* @param offset is the location to move the file pointer to.
|
||||||
|
*/
|
||||||
|
FileWriter.prototype.seek = function(offset) {
|
||||||
|
// Throw an exception if we are already writing a file
|
||||||
|
if (this.readyState === FileWriter.WRITING) {
|
||||||
|
throw new FileError(FileError.INVALID_STATE_ERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!offset && offset !== 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// See back from end of file.
|
||||||
|
if (offset < 0) {
|
||||||
|
this.position = Math.max(offset + this.length, 0);
|
||||||
|
}
|
||||||
|
// Offset is bigger than file size so set position
|
||||||
|
// to the end of the file.
|
||||||
|
else if (offset > this.length) {
|
||||||
|
this.position = this.length;
|
||||||
|
}
|
||||||
|
// Offset is between 0 and file size so set the position
|
||||||
|
// to start writing.
|
||||||
|
else {
|
||||||
|
this.position = offset;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Truncates the file to the size specified.
|
||||||
|
*
|
||||||
|
* @param size to chop the file at.
|
||||||
|
*/
|
||||||
|
FileWriter.prototype.truncate = function(size) {
|
||||||
|
// Throw an exception if we are already writing a file
|
||||||
|
if (this.readyState === FileWriter.WRITING) {
|
||||||
|
throw new FileError(FileError.INVALID_STATE_ERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// WRITING state
|
||||||
|
this.readyState = FileWriter.WRITING;
|
||||||
|
|
||||||
|
var me = this;
|
||||||
|
|
||||||
|
// If onwritestart callback
|
||||||
|
if (typeof me.onwritestart === "function") {
|
||||||
|
me.onwritestart(new ProgressEvent("writestart", {"target":this}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write file
|
||||||
|
exec(
|
||||||
|
// Success callback
|
||||||
|
function(r) {
|
||||||
|
// If DONE (cancelled), then don't do anything
|
||||||
|
if (me.readyState === FileWriter.DONE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DONE state
|
||||||
|
me.readyState = FileWriter.DONE;
|
||||||
|
|
||||||
|
// Update the length of the file
|
||||||
|
me.length = r;
|
||||||
|
me.position = Math.min(me.position, r);
|
||||||
|
|
||||||
|
// If onwrite callback
|
||||||
|
if (typeof me.onwrite === "function") {
|
||||||
|
me.onwrite(new ProgressEvent("write", {"target":me}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If onwriteend callback
|
||||||
|
if (typeof me.onwriteend === "function") {
|
||||||
|
me.onwriteend(new ProgressEvent("writeend", {"target":me}));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Error callback
|
||||||
|
function(e) {
|
||||||
|
// If DONE (cancelled), then don't do anything
|
||||||
|
if (me.readyState === FileWriter.DONE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DONE state
|
||||||
|
me.readyState = FileWriter.DONE;
|
||||||
|
|
||||||
|
// Save error
|
||||||
|
me.error = new FileError(e);
|
||||||
|
|
||||||
|
// If onerror callback
|
||||||
|
if (typeof me.onerror === "function") {
|
||||||
|
me.onerror(new ProgressEvent("error", {"target":me}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If onwriteend callback
|
||||||
|
if (typeof me.onwriteend === "function") {
|
||||||
|
me.onwriteend(new ProgressEvent("writeend", {"target":me}));
|
||||||
|
}
|
||||||
|
}, "File", "truncate", [this.localURL, size]);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = FileWriter;
|
||||||
|
|
||||||
|
});
|
39
platforms/android/assets/www/plugins/cordova-plugin-file/www/Flags.js
vendored
Normal file
39
platforms/android/assets/www/plugins/cordova-plugin-file/www/Flags.js
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
cordova.define("cordova-plugin-file.Flags", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supplies arguments to methods that lookup or create files and directories.
|
||||||
|
*
|
||||||
|
* @param create
|
||||||
|
* {boolean} file or directory if it doesn't exist
|
||||||
|
* @param exclusive
|
||||||
|
* {boolean} used with create; if true the command will fail if
|
||||||
|
* target path exists
|
||||||
|
*/
|
||||||
|
function Flags(create, exclusive) {
|
||||||
|
this.create = create || false;
|
||||||
|
this.exclusive = exclusive || false;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Flags;
|
||||||
|
|
||||||
|
});
|
26
platforms/android/assets/www/plugins/cordova-plugin-file/www/LocalFileSystem.js
vendored
Normal file
26
platforms/android/assets/www/plugins/cordova-plugin-file/www/LocalFileSystem.js
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
cordova.define("cordova-plugin-file.LocalFileSystem", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.TEMPORARY = 0;
|
||||||
|
exports.PERSISTENT = 1;
|
||||||
|
|
||||||
|
});
|
43
platforms/android/assets/www/plugins/cordova-plugin-file/www/Metadata.js
vendored
Normal file
43
platforms/android/assets/www/plugins/cordova-plugin-file/www/Metadata.js
vendored
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
cordova.define("cordova-plugin-file.Metadata", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about the state of the file or directory
|
||||||
|
*
|
||||||
|
* {Date} modificationTime (readonly)
|
||||||
|
*/
|
||||||
|
var Metadata = function(metadata) {
|
||||||
|
if (typeof metadata == "object") {
|
||||||
|
this.modificationTime = new Date(metadata.modificationTime);
|
||||||
|
this.size = metadata.size || 0;
|
||||||
|
} else if (typeof metadata == "undefined") {
|
||||||
|
this.modificationTime = null;
|
||||||
|
this.size = 0;
|
||||||
|
} else {
|
||||||
|
/* Backwards compatiblity with platforms that only return a timestamp */
|
||||||
|
this.modificationTime = new Date(metadata);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = Metadata;
|
||||||
|
|
||||||
|
});
|
70
platforms/android/assets/www/plugins/cordova-plugin-file/www/ProgressEvent.js
vendored
Normal file
70
platforms/android/assets/www/plugins/cordova-plugin-file/www/ProgressEvent.js
vendored
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
cordova.define("cordova-plugin-file.ProgressEvent", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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 ProgressEvent exists in global context, use it already, otherwise use our own polyfill
|
||||||
|
// Feature test: See if we can instantiate a native ProgressEvent;
|
||||||
|
// if so, use that approach,
|
||||||
|
// otherwise fill-in with our own implementation.
|
||||||
|
//
|
||||||
|
// NOTE: right now we always fill in with our own. Down the road would be nice if we can use whatever is native in the webview.
|
||||||
|
var ProgressEvent = (function() {
|
||||||
|
/*
|
||||||
|
var createEvent = function(data) {
|
||||||
|
var event = document.createEvent('Events');
|
||||||
|
event.initEvent('ProgressEvent', false, false);
|
||||||
|
if (data) {
|
||||||
|
for (var i in data) {
|
||||||
|
if (data.hasOwnProperty(i)) {
|
||||||
|
event[i] = data[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (data.target) {
|
||||||
|
// TODO: cannot call <some_custom_object>.dispatchEvent
|
||||||
|
// need to first figure out how to implement EventTarget
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return event;
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
var ev = createEvent({type:"abort",target:document});
|
||||||
|
return function ProgressEvent(type, data) {
|
||||||
|
data.type = type;
|
||||||
|
return createEvent(data);
|
||||||
|
};
|
||||||
|
} catch(e){
|
||||||
|
*/
|
||||||
|
return function ProgressEvent(type, dict) {
|
||||||
|
this.type = type;
|
||||||
|
this.bubbles = false;
|
||||||
|
this.cancelBubble = false;
|
||||||
|
this.cancelable = false;
|
||||||
|
this.lengthComputable = false;
|
||||||
|
this.loaded = dict && dict.loaded ? dict.loaded : 0;
|
||||||
|
this.total = dict && dict.total ? dict.total : 0;
|
||||||
|
this.target = dict && dict.target ? dict.target : null;
|
||||||
|
};
|
||||||
|
//}
|
||||||
|
})();
|
||||||
|
|
||||||
|
module.exports = ProgressEvent;
|
||||||
|
|
||||||
|
});
|
52
platforms/android/assets/www/plugins/cordova-plugin-file/www/android/FileSystem.js
vendored
Normal file
52
platforms/android/assets/www/plugins/cordova-plugin-file/www/android/FileSystem.js
vendored
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
cordova.define("cordova-plugin-file.androidFileSystem", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
FILESYSTEM_PROTOCOL = "cdvfile";
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
__format__: function(fullPath, nativeUrl) {
|
||||||
|
var path;
|
||||||
|
var contentUrlMatch = /^content:\/\//.exec(nativeUrl);
|
||||||
|
if (contentUrlMatch) {
|
||||||
|
// When available, use the path from a native content URL, which was already encoded by Android.
|
||||||
|
// This is necessary because JavaScript's encodeURI() does not encode as many characters as
|
||||||
|
// Android, which can result in permission exceptions when the encoding of a content URI
|
||||||
|
// doesn't match the string for which permission was originally granted.
|
||||||
|
path = nativeUrl.substring(contentUrlMatch[0].length - 1);
|
||||||
|
} else {
|
||||||
|
path = FileSystem.encodeURIPath(fullPath);
|
||||||
|
if (!/^\//.test(path)) {
|
||||||
|
path = '/' + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
var m = /\?.*/.exec(nativeUrl);
|
||||||
|
if (m) {
|
||||||
|
path += m[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FILESYSTEM_PROTOCOL + '://localhost/' + this.name + path;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
});
|
29
platforms/android/assets/www/plugins/cordova-plugin-file/www/browser/isChrome.js
vendored
Normal file
29
platforms/android/assets/www/plugins/cordova-plugin-file/www/browser/isChrome.js
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
cordova.define("cordova-plugin-file.isChrome", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = function () {
|
||||||
|
// window.webkitRequestFileSystem and window.webkitResolveLocalFileSystemURL are available only in Chrome and
|
||||||
|
// possibly a good flag to indicate that we're running in Chrome
|
||||||
|
return window.webkitRequestFileSystem && window.webkitResolveLocalFileSystemURL;
|
||||||
|
};
|
||||||
|
|
||||||
|
});
|
66
platforms/android/assets/www/plugins/cordova-plugin-file/www/fileSystemPaths.js
vendored
Normal file
66
platforms/android/assets/www/plugins/cordova-plugin-file/www/fileSystemPaths.js
vendored
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
cordova.define("cordova-plugin-file.fileSystemPaths", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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 exec = require('cordova/exec');
|
||||||
|
var channel = require('cordova/channel');
|
||||||
|
|
||||||
|
exports.file = {
|
||||||
|
// Read-only directory where the application is installed.
|
||||||
|
applicationDirectory: null,
|
||||||
|
// Root of app's private writable storage
|
||||||
|
applicationStorageDirectory: null,
|
||||||
|
// Where to put app-specific data files.
|
||||||
|
dataDirectory: null,
|
||||||
|
// Cached files that should survive app restarts.
|
||||||
|
// Apps should not rely on the OS to delete files in here.
|
||||||
|
cacheDirectory: null,
|
||||||
|
// Android: the application space on external storage.
|
||||||
|
externalApplicationStorageDirectory: null,
|
||||||
|
// Android: Where to put app-specific data files on external storage.
|
||||||
|
externalDataDirectory: null,
|
||||||
|
// Android: the application cache on external storage.
|
||||||
|
externalCacheDirectory: null,
|
||||||
|
// Android: the external storage (SD card) root.
|
||||||
|
externalRootDirectory: null,
|
||||||
|
// iOS: Temp directory that the OS can clear at will.
|
||||||
|
tempDirectory: null,
|
||||||
|
// iOS: Holds app-specific files that should be synced (e.g. to iCloud).
|
||||||
|
syncedDataDirectory: null,
|
||||||
|
// iOS: Files private to the app, but that are meaningful to other applications (e.g. Office files)
|
||||||
|
documentsDirectory: null,
|
||||||
|
// BlackBerry10: Files globally available to all apps
|
||||||
|
sharedDirectory: null
|
||||||
|
};
|
||||||
|
|
||||||
|
channel.waitForInitialization('onFileSystemPathsReady');
|
||||||
|
channel.onCordovaReady.subscribe(function() {
|
||||||
|
function after(paths) {
|
||||||
|
for (var k in paths) {
|
||||||
|
exports.file[k] = paths[k];
|
||||||
|
}
|
||||||
|
channel.initializationComplete('onFileSystemPathsReady');
|
||||||
|
}
|
||||||
|
exec(after, null, 'File', 'requestAllPaths', []);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
});
|
48
platforms/android/assets/www/plugins/cordova-plugin-file/www/fileSystems-roots.js
vendored
Normal file
48
platforms/android/assets/www/plugins/cordova-plugin-file/www/fileSystems-roots.js
vendored
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
cordova.define("cordova-plugin-file.fileSystems-roots", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Map of fsName -> FileSystem.
|
||||||
|
var fsMap = null;
|
||||||
|
var FileSystem = require('./FileSystem');
|
||||||
|
var exec = require('cordova/exec');
|
||||||
|
|
||||||
|
// Overridden by Android, BlackBerry 10 and iOS to populate fsMap.
|
||||||
|
require('./fileSystems').getFs = function(name, callback) {
|
||||||
|
function success(response) {
|
||||||
|
fsMap = {};
|
||||||
|
for (var i = 0; i < response.length; ++i) {
|
||||||
|
var fsRoot = response[i];
|
||||||
|
var fs = new FileSystem(fsRoot.filesystemName, fsRoot);
|
||||||
|
fsMap[fs.name] = fs;
|
||||||
|
}
|
||||||
|
callback(fsMap[name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fsMap) {
|
||||||
|
callback(fsMap[name]);
|
||||||
|
} else {
|
||||||
|
exec(success, null, "File", "requestAllFileSystems", []);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
});
|
28
platforms/android/assets/www/plugins/cordova-plugin-file/www/fileSystems.js
vendored
Normal file
28
platforms/android/assets/www/plugins/cordova-plugin-file/www/fileSystems.js
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
cordova.define("cordova-plugin-file.fileSystems", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Overridden by Android, BlackBerry 10 and iOS to populate fsMap.
|
||||||
|
module.exports.getFs = function(name, callback) {
|
||||||
|
callback(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
});
|
85
platforms/android/assets/www/plugins/cordova-plugin-file/www/requestFileSystem.js
vendored
Normal file
85
platforms/android/assets/www/plugins/cordova-plugin-file/www/requestFileSystem.js
vendored
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
cordova.define("cordova-plugin-file.requestFileSystem", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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() {
|
||||||
|
//For browser platform: not all browsers use this file.
|
||||||
|
function checkBrowser() {
|
||||||
|
if (cordova.platformId === "browser" && require('./isChrome')()) {
|
||||||
|
module.exports = window.requestFileSystem || window.webkitRequestFileSystem;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (checkBrowser()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var argscheck = require('cordova/argscheck'),
|
||||||
|
FileError = require('./FileError'),
|
||||||
|
FileSystem = require('./FileSystem'),
|
||||||
|
exec = require('cordova/exec');
|
||||||
|
var fileSystems = require('./fileSystems');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request a file system in which to store application data.
|
||||||
|
* @param type local file system type
|
||||||
|
* @param size indicates how much storage space, in bytes, the application expects to need
|
||||||
|
* @param successCallback invoked with a FileSystem object
|
||||||
|
* @param errorCallback invoked if error occurs retrieving file system
|
||||||
|
*/
|
||||||
|
var requestFileSystem = function(type, size, successCallback, errorCallback) {
|
||||||
|
argscheck.checkArgs('nnFF', 'requestFileSystem', arguments);
|
||||||
|
var fail = function(code) {
|
||||||
|
if (errorCallback) {
|
||||||
|
errorCallback(new FileError(code));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (type < 0) {
|
||||||
|
fail(FileError.SYNTAX_ERR);
|
||||||
|
} else {
|
||||||
|
// if successful, return a FileSystem object
|
||||||
|
var success = function(file_system) {
|
||||||
|
if (file_system) {
|
||||||
|
if (successCallback) {
|
||||||
|
fileSystems.getFs(file_system.name, function(fs) {
|
||||||
|
// This should happen only on platforms that haven't implemented requestAllFileSystems (windows)
|
||||||
|
if (!fs) {
|
||||||
|
fs = new FileSystem(file_system.name, file_system.root);
|
||||||
|
}
|
||||||
|
successCallback(fs);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// no FileSystem object returned
|
||||||
|
fail(FileError.NOT_FOUND_ERR);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
exec(success, fail, "File", "requestFileSystem", [type, size]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = requestFileSystem;
|
||||||
|
})();
|
||||||
|
|
||||||
|
});
|
95
platforms/android/assets/www/plugins/cordova-plugin-file/www/resolveLocalFileSystemURI.js
vendored
Normal file
95
platforms/android/assets/www/plugins/cordova-plugin-file/www/resolveLocalFileSystemURI.js
vendored
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
cordova.define("cordova-plugin-file.resolveLocalFileSystemURI", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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() {
|
||||||
|
//For browser platform: not all browsers use overrided `resolveLocalFileSystemURL`.
|
||||||
|
function checkBrowser() {
|
||||||
|
if (cordova.platformId === "browser" && require('./isChrome')()) {
|
||||||
|
module.exports.resolveLocalFileSystemURL = window.resolveLocalFileSystemURL || window.webkitResolveLocalFileSystemURL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (checkBrowser()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var argscheck = require('cordova/argscheck'),
|
||||||
|
DirectoryEntry = require('./DirectoryEntry'),
|
||||||
|
FileEntry = require('./FileEntry'),
|
||||||
|
FileError = require('./FileError'),
|
||||||
|
exec = require('cordova/exec');
|
||||||
|
var fileSystems = require('./fileSystems');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Look up file system Entry referred to by local URI.
|
||||||
|
* @param {DOMString} uri URI referring to a local file or directory
|
||||||
|
* @param successCallback invoked with Entry object corresponding to URI
|
||||||
|
* @param errorCallback invoked if error occurs retrieving file system entry
|
||||||
|
*/
|
||||||
|
module.exports.resolveLocalFileSystemURL = module.exports.resolveLocalFileSystemURL || function(uri, successCallback, errorCallback) {
|
||||||
|
argscheck.checkArgs('sFF', 'resolveLocalFileSystemURI', arguments);
|
||||||
|
// error callback
|
||||||
|
var fail = function(error) {
|
||||||
|
if (errorCallback) {
|
||||||
|
errorCallback(new FileError(error));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// sanity check for 'not:valid:filename' or '/not:valid:filename'
|
||||||
|
// file.spec.12 window.resolveLocalFileSystemURI should error (ENCODING_ERR) when resolving invalid URI with leading /.
|
||||||
|
if(!uri || uri.split(":").length > 2) {
|
||||||
|
setTimeout( function() {
|
||||||
|
fail(FileError.ENCODING_ERR);
|
||||||
|
},0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// if successful, return either a file or directory entry
|
||||||
|
var success = function(entry) {
|
||||||
|
if (entry) {
|
||||||
|
if (successCallback) {
|
||||||
|
// create appropriate Entry object
|
||||||
|
var fsName = entry.filesystemName || (entry.filesystem && entry.filesystem.name) || (entry.filesystem == window.PERSISTENT ? 'persistent' : 'temporary');
|
||||||
|
fileSystems.getFs(fsName, function(fs) {
|
||||||
|
// This should happen only on platforms that haven't implemented requestAllFileSystems (windows)
|
||||||
|
if (!fs) {
|
||||||
|
fs = new FileSystem(fsName, {name:"", fullPath:"/"});
|
||||||
|
}
|
||||||
|
var result = (entry.isDirectory) ? new DirectoryEntry(entry.name, entry.fullPath, fs, entry.nativeURL) : new FileEntry(entry.name, entry.fullPath, fs, entry.nativeURL);
|
||||||
|
successCallback(result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// no Entry object returned
|
||||||
|
fail(FileError.NOT_FOUND_ERR);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exec(success, fail, "File", "resolveLocalFileSystemURI", [uri]);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.resolveLocalFileSystemURI = function() {
|
||||||
|
console.log("resolveLocalFileSystemURI is deprecated. Please call resolveLocalFileSystemURL instead.");
|
||||||
|
module.exports.resolveLocalFileSystemURL.apply(this, arguments);
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
});
|
120
platforms/android/platform_www/plugins/cordova-plugin-file/www/DirectoryEntry.js
vendored
Normal file
120
platforms/android/platform_www/plugins/cordova-plugin-file/www/DirectoryEntry.js
vendored
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
cordova.define("cordova-plugin-file.DirectoryEntry", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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 argscheck = require('cordova/argscheck'),
|
||||||
|
utils = require('cordova/utils'),
|
||||||
|
exec = require('cordova/exec'),
|
||||||
|
Entry = require('./Entry'),
|
||||||
|
FileError = require('./FileError'),
|
||||||
|
DirectoryReader = require('./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)
|
||||||
|
* {FileSystem} filesystem on which the directory resides (readonly)
|
||||||
|
*/
|
||||||
|
var DirectoryEntry = function(name, fullPath, fileSystem, nativeURL) {
|
||||||
|
|
||||||
|
// add trailing slash if it is missing
|
||||||
|
if ((fullPath) && !/\/$/.test(fullPath)) {
|
||||||
|
fullPath += "/";
|
||||||
|
}
|
||||||
|
// add trailing slash if it is missing
|
||||||
|
if (nativeURL && !/\/$/.test(nativeURL)) {
|
||||||
|
nativeURL += "/";
|
||||||
|
}
|
||||||
|
DirectoryEntry.__super__.constructor.call(this, false, true, name, fullPath, fileSystem, nativeURL);
|
||||||
|
};
|
||||||
|
|
||||||
|
utils.extend(DirectoryEntry, Entry);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new DirectoryReader to read entries from this directory
|
||||||
|
*/
|
||||||
|
DirectoryEntry.prototype.createReader = function() {
|
||||||
|
return new DirectoryReader(this.toInternalURL());
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 fs = this.filesystem;
|
||||||
|
var win = successCallback && function(result) {
|
||||||
|
var entry = new DirectoryEntry(result.name, result.fullPath, fs, result.nativeURL);
|
||||||
|
successCallback(entry);
|
||||||
|
};
|
||||||
|
var fail = errorCallback && function(code) {
|
||||||
|
errorCallback(new FileError(code));
|
||||||
|
};
|
||||||
|
exec(win, fail, "File", "getDirectory", [this.toInternalURL(), 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.toInternalURL()]);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 fs = this.filesystem;
|
||||||
|
var win = successCallback && function(result) {
|
||||||
|
var FileEntry = require('./FileEntry');
|
||||||
|
var entry = new FileEntry(result.name, result.fullPath, fs, result.nativeURL);
|
||||||
|
successCallback(entry);
|
||||||
|
};
|
||||||
|
var fail = errorCallback && function(code) {
|
||||||
|
errorCallback(new FileError(code));
|
||||||
|
};
|
||||||
|
exec(win, fail, "File", "getFile", [this.toInternalURL(), path, options]);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = DirectoryEntry;
|
||||||
|
|
||||||
|
});
|
76
platforms/android/platform_www/plugins/cordova-plugin-file/www/DirectoryReader.js
vendored
Normal file
76
platforms/android/platform_www/plugins/cordova-plugin-file/www/DirectoryReader.js
vendored
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
cordova.define("cordova-plugin-file.DirectoryReader", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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 exec = require('cordova/exec'),
|
||||||
|
FileError = require('./FileError') ;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface that lists the files and directories in a directory.
|
||||||
|
*/
|
||||||
|
function DirectoryReader(localURL) {
|
||||||
|
this.localURL = localURL || null;
|
||||||
|
this.hasReadEntries = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
||||||
|
// If we've already read and passed on this directory's entries, return an empty list.
|
||||||
|
if (this.hasReadEntries) {
|
||||||
|
successCallback([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var reader = this;
|
||||||
|
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('./DirectoryEntry'))();
|
||||||
|
}
|
||||||
|
else if (result[i].isFile) {
|
||||||
|
entry = new (require('./FileEntry'))();
|
||||||
|
}
|
||||||
|
entry.isDirectory = result[i].isDirectory;
|
||||||
|
entry.isFile = result[i].isFile;
|
||||||
|
entry.name = result[i].name;
|
||||||
|
entry.fullPath = result[i].fullPath;
|
||||||
|
entry.filesystem = new (require('./FileSystem'))(result[i].filesystemName);
|
||||||
|
entry.nativeURL = result[i].nativeURL;
|
||||||
|
retVal.push(entry);
|
||||||
|
}
|
||||||
|
reader.hasReadEntries = true;
|
||||||
|
successCallback(retVal);
|
||||||
|
};
|
||||||
|
var fail = typeof errorCallback !== 'function' ? null : function(code) {
|
||||||
|
errorCallback(new FileError(code));
|
||||||
|
};
|
||||||
|
exec(win, fail, "File", "readEntries", [this.localURL]);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = DirectoryReader;
|
||||||
|
|
||||||
|
});
|
265
platforms/android/platform_www/plugins/cordova-plugin-file/www/Entry.js
vendored
Normal file
265
platforms/android/platform_www/plugins/cordova-plugin-file/www/Entry.js
vendored
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
cordova.define("cordova-plugin-file.Entry", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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 argscheck = require('cordova/argscheck'),
|
||||||
|
exec = require('cordova/exec'),
|
||||||
|
FileError = require('./FileError'),
|
||||||
|
Metadata = require('./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)
|
||||||
|
* @param fileSystem
|
||||||
|
* {FileSystem} the filesystem on which this entry resides
|
||||||
|
* (readonly)
|
||||||
|
* @param nativeURL
|
||||||
|
* {DOMString} an alternate URL which can be used by native
|
||||||
|
* webview controls, for example media players.
|
||||||
|
* (optional, readonly)
|
||||||
|
*/
|
||||||
|
function Entry(isFile, isDirectory, name, fullPath, fileSystem, nativeURL) {
|
||||||
|
this.isFile = !!isFile;
|
||||||
|
this.isDirectory = !!isDirectory;
|
||||||
|
this.name = name || '';
|
||||||
|
this.fullPath = fullPath || '';
|
||||||
|
this.filesystem = fileSystem || null;
|
||||||
|
this.nativeURL = nativeURL || 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(entryMetadata) {
|
||||||
|
var metadata = new Metadata({
|
||||||
|
size: entryMetadata.size,
|
||||||
|
modificationTime: entryMetadata.lastModifiedDate
|
||||||
|
});
|
||||||
|
successCallback(metadata);
|
||||||
|
};
|
||||||
|
var fail = errorCallback && function(code) {
|
||||||
|
errorCallback(new FileError(code));
|
||||||
|
};
|
||||||
|
exec(success, fail, "File", "getFileMetadata", [this.toInternalURL()]);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.toInternalURL(), 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));
|
||||||
|
};
|
||||||
|
var srcURL = this.toInternalURL(),
|
||||||
|
// entry name
|
||||||
|
name = newName || this.name,
|
||||||
|
success = function(entry) {
|
||||||
|
if (entry) {
|
||||||
|
if (successCallback) {
|
||||||
|
// create appropriate Entry object
|
||||||
|
var newFSName = entry.filesystemName || (entry.filesystem && entry.filesystem.name);
|
||||||
|
var fs = newFSName ? new FileSystem(newFSName, { name: "", fullPath: "/" }) : new FileSystem(parent.filesystem.name, { name: "", fullPath: "/" });
|
||||||
|
var result = (entry.isDirectory) ? new (require('./DirectoryEntry'))(entry.name, entry.fullPath, fs, entry.nativeURL) : new (require('cordova-plugin-file.FileEntry'))(entry.name, entry.fullPath, fs, entry.nativeURL);
|
||||||
|
successCallback(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// no Entry object returned
|
||||||
|
if (fail) {
|
||||||
|
fail(FileError.NOT_FOUND_ERR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// copy
|
||||||
|
exec(success, fail, "File", "moveTo", [srcURL, parent.toInternalURL(), 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));
|
||||||
|
};
|
||||||
|
var srcURL = this.toInternalURL(),
|
||||||
|
// entry name
|
||||||
|
name = newName || this.name,
|
||||||
|
// success callback
|
||||||
|
success = function(entry) {
|
||||||
|
if (entry) {
|
||||||
|
if (successCallback) {
|
||||||
|
// create appropriate Entry object
|
||||||
|
var newFSName = entry.filesystemName || (entry.filesystem && entry.filesystem.name);
|
||||||
|
var fs = newFSName ? new FileSystem(newFSName, { name: "", fullPath: "/" }) : new FileSystem(parent.filesystem.name, { name: "", fullPath: "/" });
|
||||||
|
var result = (entry.isDirectory) ? new (require('./DirectoryEntry'))(entry.name, entry.fullPath, fs, entry.nativeURL) : new (require('cordova-plugin-file.FileEntry'))(entry.name, entry.fullPath, fs, entry.nativeURL);
|
||||||
|
successCallback(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// no Entry object returned
|
||||||
|
if (fail) {
|
||||||
|
fail(FileError.NOT_FOUND_ERR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// copy
|
||||||
|
exec(success, fail, "File", "copyTo", [srcURL, parent.toInternalURL(), name]);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a URL that can be passed across the bridge to identify this entry.
|
||||||
|
*/
|
||||||
|
Entry.prototype.toInternalURL = function() {
|
||||||
|
if (this.filesystem && this.filesystem.__format__) {
|
||||||
|
return this.filesystem.__format__(this.fullPath, this.nativeURL);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a URL that can be used to identify this entry.
|
||||||
|
* Use a URL that can be used to as the src attribute of a <video> or
|
||||||
|
* <audio> tag. If that is not possible, construct a cdvfile:// URL.
|
||||||
|
*/
|
||||||
|
Entry.prototype.toURL = function() {
|
||||||
|
if (this.nativeURL) {
|
||||||
|
return this.nativeURL;
|
||||||
|
}
|
||||||
|
// fullPath attribute may contain the full URL in the case that
|
||||||
|
// toInternalURL fails.
|
||||||
|
return this.toInternalURL() || "file://localhost" + this.fullPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Backwards-compatibility: In v1.0.0 - 1.0.2, .toURL would only return a
|
||||||
|
* cdvfile:// URL, and this method was necessary to obtain URLs usable by the
|
||||||
|
* webview.
|
||||||
|
* See CB-6051, CB-6106, CB-6117, CB-6152, CB-6199, CB-6201, CB-6243, CB-6249,
|
||||||
|
* and CB-6300.
|
||||||
|
*/
|
||||||
|
Entry.prototype.toNativeURL = function() {
|
||||||
|
console.log("DEPRECATED: Update your code to use 'toURL'");
|
||||||
|
return this.toURL();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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'");
|
||||||
|
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.toInternalURL()]);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 fs = this.filesystem;
|
||||||
|
var win = successCallback && function(result) {
|
||||||
|
var DirectoryEntry = require('./DirectoryEntry');
|
||||||
|
var entry = new DirectoryEntry(result.name, result.fullPath, fs, result.nativeURL);
|
||||||
|
successCallback(entry);
|
||||||
|
};
|
||||||
|
var fail = errorCallback && function(code) {
|
||||||
|
errorCallback(new FileError(code));
|
||||||
|
};
|
||||||
|
exec(win, fail, "File", "getParent", [this.toInternalURL()]);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = Entry;
|
||||||
|
|
||||||
|
});
|
82
platforms/android/platform_www/plugins/cordova-plugin-file/www/File.js
vendored
Normal file
82
platforms/android/platform_www/plugins/cordova-plugin-file/www/File.js
vendored
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
cordova.define("cordova-plugin-file.File", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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, localURL, type, lastModifiedDate, size){
|
||||||
|
this.name = name || '';
|
||||||
|
this.localURL = localURL || null;
|
||||||
|
this.type = type || null;
|
||||||
|
this.lastModified = lastModifiedDate || null;
|
||||||
|
// For backwards compatibility, store the timestamp in lastModifiedDate as well
|
||||||
|
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.localURL, this.type, this.lastModified, this.size);
|
||||||
|
newFile.start = this.start + newStart;
|
||||||
|
newFile.end = this.start + newEnd;
|
||||||
|
return newFile;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = File;
|
||||||
|
|
||||||
|
});
|
96
platforms/android/platform_www/plugins/cordova-plugin-file/www/FileEntry.js
vendored
Normal file
96
platforms/android/platform_www/plugins/cordova-plugin-file/www/FileEntry.js
vendored
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
cordova.define("cordova-plugin-file.FileEntry", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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 utils = require('cordova/utils'),
|
||||||
|
exec = require('cordova/exec'),
|
||||||
|
Entry = require('./Entry'),
|
||||||
|
FileWriter = require('./FileWriter'),
|
||||||
|
File = require('./File'),
|
||||||
|
FileError = require('./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, fileSystem, nativeURL) {
|
||||||
|
// remove trailing slash if it is present
|
||||||
|
if (fullPath && /\/$/.test(fullPath)) {
|
||||||
|
fullPath = fullPath.substring(0, fullPath.length - 1);
|
||||||
|
}
|
||||||
|
if (nativeURL && /\/$/.test(nativeURL)) {
|
||||||
|
nativeURL = nativeURL.substring(0, nativeURL.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileEntry.__super__.constructor.apply(this, [true, false, name, fullPath, fileSystem, nativeURL]);
|
||||||
|
};
|
||||||
|
|
||||||
|
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.localURL === null || writer.localURL === "") {
|
||||||
|
if (errorCallback) {
|
||||||
|
errorCallback(new FileError(FileError.INVALID_STATE_ERR));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (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 localURL = this.toInternalURL();
|
||||||
|
var win = successCallback && function(f) {
|
||||||
|
var file = new File(f.name, localURL, f.type, f.lastModifiedDate, f.size);
|
||||||
|
successCallback(file);
|
||||||
|
};
|
||||||
|
var fail = errorCallback && function(code) {
|
||||||
|
errorCallback(new FileError(code));
|
||||||
|
};
|
||||||
|
exec(win, fail, "File", "getFileMetadata", [localURL]);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = FileEntry;
|
||||||
|
|
||||||
|
});
|
49
platforms/android/platform_www/plugins/cordova-plugin-file/www/FileError.js
vendored
Normal file
49
platforms/android/platform_www/plugins/cordova-plugin-file/www/FileError.js
vendored
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
cordova.define("cordova-plugin-file.FileError", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
});
|
292
platforms/android/platform_www/plugins/cordova-plugin-file/www/FileReader.js
vendored
Normal file
292
platforms/android/platform_www/plugins/cordova-plugin-file/www/FileReader.js
vendored
Normal file
@ -0,0 +1,292 @@
|
|||||||
|
cordova.define("cordova-plugin-file.FileReader", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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 exec = require('cordova/exec'),
|
||||||
|
modulemapper = require('cordova/modulemapper'),
|
||||||
|
utils = require('cordova/utils'),
|
||||||
|
FileError = require('./FileError'),
|
||||||
|
ProgressEvent = require('./ProgressEvent'),
|
||||||
|
origFileReader = modulemapper.getOriginalSymbol(window, '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._progress = null;
|
||||||
|
this._localURL = '';
|
||||||
|
this._realReader = origFileReader ? new origFileReader() : {};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the maximum size to read at a time via the native API. The default value is a compromise between
|
||||||
|
* minimizing the overhead of many exec() calls while still reporting progress frequently enough for large files.
|
||||||
|
* (Note attempts to allocate more than a few MB of contiguous memory on the native side are likely to cause
|
||||||
|
* OOM exceptions, while the JS engine seems to have fewer problems managing large strings or ArrayBuffers.)
|
||||||
|
*/
|
||||||
|
FileReader.READ_CHUNK_SIZE = 256*1024;
|
||||||
|
|
||||||
|
// States
|
||||||
|
FileReader.EMPTY = 0;
|
||||||
|
FileReader.LOADING = 1;
|
||||||
|
FileReader.DONE = 2;
|
||||||
|
|
||||||
|
utils.defineGetter(FileReader.prototype, 'readyState', function() {
|
||||||
|
return this._localURL ? this._readyState : this._realReader.readyState;
|
||||||
|
});
|
||||||
|
|
||||||
|
utils.defineGetter(FileReader.prototype, 'error', function() {
|
||||||
|
return this._localURL ? this._error: this._realReader.error;
|
||||||
|
});
|
||||||
|
|
||||||
|
utils.defineGetter(FileReader.prototype, 'result', function() {
|
||||||
|
return this._localURL ? 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._progress = 0;
|
||||||
|
reader._readyState = FileReader.LOADING;
|
||||||
|
|
||||||
|
if (typeof file.localURL == 'string') {
|
||||||
|
reader._localURL = file.localURL;
|
||||||
|
} else {
|
||||||
|
reader._localURL = '';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reader.onloadstart) {
|
||||||
|
reader.onloadstart(new ProgressEvent("loadstart", {target:reader}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback used by the following read* functions to handle incremental or final success.
|
||||||
|
* Must be bound to the FileReader's this along with all but the last parameter,
|
||||||
|
* e.g. readSuccessCallback.bind(this, "readAsText", "UTF-8", offset, totalSize, accumulate)
|
||||||
|
* @param readType The name of the read function to call.
|
||||||
|
* @param encoding Text encoding, or null if this is not a text type read.
|
||||||
|
* @param offset Starting offset of the read.
|
||||||
|
* @param totalSize Total number of bytes or chars to read.
|
||||||
|
* @param accumulate A function that takes the callback result and accumulates it in this._result.
|
||||||
|
* @param r Callback result returned by the last read exec() call, or null to begin reading.
|
||||||
|
*/
|
||||||
|
function readSuccessCallback(readType, encoding, offset, totalSize, accumulate, r) {
|
||||||
|
if (this._readyState === FileReader.DONE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof r !== "undefined") {
|
||||||
|
accumulate(r);
|
||||||
|
this._progress = Math.min(this._progress + FileReader.READ_CHUNK_SIZE, totalSize);
|
||||||
|
|
||||||
|
if (typeof this.onprogress === "function") {
|
||||||
|
this.onprogress(new ProgressEvent("progress", {loaded:this._progress, total:totalSize}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof r === "undefined" || this._progress < totalSize) {
|
||||||
|
var execArgs = [
|
||||||
|
this._localURL,
|
||||||
|
offset + this._progress,
|
||||||
|
offset + this._progress + Math.min(totalSize - this._progress, FileReader.READ_CHUNK_SIZE)];
|
||||||
|
if (encoding) {
|
||||||
|
execArgs.splice(1, 0, encoding);
|
||||||
|
}
|
||||||
|
exec(
|
||||||
|
readSuccessCallback.bind(this, readType, encoding, offset, totalSize, accumulate),
|
||||||
|
readFailureCallback.bind(this),
|
||||||
|
"File", readType, execArgs);
|
||||||
|
} else {
|
||||||
|
this._readyState = FileReader.DONE;
|
||||||
|
|
||||||
|
if (typeof this.onload === "function") {
|
||||||
|
this.onload(new ProgressEvent("load", {target:this}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof this.onloadend === "function") {
|
||||||
|
this.onloadend(new ProgressEvent("loadend", {target:this}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback used by the following read* functions to handle errors.
|
||||||
|
* Must be bound to the FileReader's this, e.g. readFailureCallback.bind(this)
|
||||||
|
*/
|
||||||
|
function readFailureCallback(e) {
|
||||||
|
if (this._readyState === FileReader.DONE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._readyState = FileReader.DONE;
|
||||||
|
this._result = null;
|
||||||
|
this._error = new FileError(e);
|
||||||
|
|
||||||
|
if (typeof this.onerror === "function") {
|
||||||
|
this.onerror(new ProgressEvent("error", {target:this}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof this.onloadend === "function") {
|
||||||
|
this.onloadend(new ProgressEvent("loadend", {target:this}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abort reading file.
|
||||||
|
*/
|
||||||
|
FileReader.prototype.abort = function() {
|
||||||
|
if (origFileReader && !this._localURL) {
|
||||||
|
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 totalSize = file.end - file.start;
|
||||||
|
readSuccessCallback.bind(this)("readAsText", enc, file.start, totalSize, function(r) {
|
||||||
|
if (this._progress === 0) {
|
||||||
|
this._result = "";
|
||||||
|
}
|
||||||
|
this._result += r;
|
||||||
|
}.bind(this));
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 totalSize = file.end - file.start;
|
||||||
|
readSuccessCallback.bind(this)("readAsDataURL", null, file.start, totalSize, function(r) {
|
||||||
|
var commaIndex = r.indexOf(',');
|
||||||
|
if (this._progress === 0) {
|
||||||
|
this._result = r;
|
||||||
|
} else {
|
||||||
|
this._result += r.substring(commaIndex + 1);
|
||||||
|
}
|
||||||
|
}.bind(this));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 totalSize = file.end - file.start;
|
||||||
|
readSuccessCallback.bind(this)("readAsBinaryString", null, file.start, totalSize, function(r) {
|
||||||
|
if (this._progress === 0) {
|
||||||
|
this._result = "";
|
||||||
|
}
|
||||||
|
this._result += r;
|
||||||
|
}.bind(this));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 totalSize = file.end - file.start;
|
||||||
|
readSuccessCallback.bind(this)("readAsArrayBuffer", null, file.start, totalSize, function(r) {
|
||||||
|
var resultArray = (this._progress === 0 ? new Uint8Array(totalSize) : new Uint8Array(this._result));
|
||||||
|
resultArray.set(new Uint8Array(r), this._progress);
|
||||||
|
this._result = resultArray.buffer;
|
||||||
|
}.bind(this));
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = FileReader;
|
||||||
|
|
||||||
|
});
|
58
platforms/android/platform_www/plugins/cordova-plugin-file/www/FileSystem.js
vendored
Normal file
58
platforms/android/platform_www/plugins/cordova-plugin-file/www/FileSystem.js
vendored
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
cordova.define("cordova-plugin-file.FileSystem", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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 DirectoryEntry = require('./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;
|
||||||
|
if (root) {
|
||||||
|
this.root = new DirectoryEntry(root.name, root.fullPath, this, root.nativeURL);
|
||||||
|
} else {
|
||||||
|
this.root = new DirectoryEntry(this.name, '/', this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
FileSystem.prototype.__format__ = function(fullPath, nativeUrl) {
|
||||||
|
return fullPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
FileSystem.prototype.toJSON = function() {
|
||||||
|
return "<FileSystem: " + this.name + ">";
|
||||||
|
};
|
||||||
|
|
||||||
|
// Use instead of encodeURI() when encoding just the path part of a URI rather than an entire URI.
|
||||||
|
FileSystem.encodeURIPath = function(path) {
|
||||||
|
// Because # is a valid filename character, it must be encoded to prevent part of the
|
||||||
|
// path from being parsed as a URI fragment.
|
||||||
|
return encodeURI(path).replace(/#/g, '%23');
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = FileSystem;
|
||||||
|
|
||||||
|
});
|
44
platforms/android/platform_www/plugins/cordova-plugin-file/www/FileUploadOptions.js
vendored
Normal file
44
platforms/android/platform_www/plugins/cordova-plugin-file/www/FileUploadOptions.js
vendored
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
cordova.define("cordova-plugin-file.FileUploadOptions", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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, httpMethod) {
|
||||||
|
this.fileKey = fileKey || null;
|
||||||
|
this.fileName = fileName || null;
|
||||||
|
this.mimeType = mimeType || null;
|
||||||
|
this.params = params || null;
|
||||||
|
this.headers = headers || null;
|
||||||
|
this.httpMethod = httpMethod || null;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = FileUploadOptions;
|
||||||
|
|
||||||
|
});
|
32
platforms/android/platform_www/plugins/cordova-plugin-file/www/FileUploadResult.js
vendored
Normal file
32
platforms/android/platform_www/plugins/cordova-plugin-file/www/FileUploadResult.js
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
cordova.define("cordova-plugin-file.FileUploadResult", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FileUploadResult
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
module.exports = function FileUploadResult(size, code, content) {
|
||||||
|
this.bytesSent = size;
|
||||||
|
this.responseCode = code;
|
||||||
|
this.response = content;
|
||||||
|
};
|
||||||
|
});
|
327
platforms/android/platform_www/plugins/cordova-plugin-file/www/FileWriter.js
vendored
Normal file
327
platforms/android/platform_www/plugins/cordova-plugin-file/www/FileWriter.js
vendored
Normal file
@ -0,0 +1,327 @@
|
|||||||
|
cordova.define("cordova-plugin-file.FileWriter", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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 exec = require('cordova/exec'),
|
||||||
|
FileError = require('./FileError'),
|
||||||
|
ProgressEvent = require('./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.localURL = file.localURL || 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.onerror = null; // When the write has failed (see errors).
|
||||||
|
};
|
||||||
|
|
||||||
|
// States
|
||||||
|
FileWriter.INIT = 0;
|
||||||
|
FileWriter.WRITING = 1;
|
||||||
|
FileWriter.DONE = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abort writing file.
|
||||||
|
*/
|
||||||
|
FileWriter.prototype.abort = function() {
|
||||||
|
// check for invalid state
|
||||||
|
if (this.readyState === FileWriter.DONE || this.readyState === FileWriter.INIT) {
|
||||||
|
throw new FileError(FileError.INVALID_STATE_ERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set error
|
||||||
|
this.error = new FileError(FileError.ABORT_ERR);
|
||||||
|
|
||||||
|
this.readyState = FileWriter.DONE;
|
||||||
|
|
||||||
|
// If abort callback
|
||||||
|
if (typeof this.onabort === "function") {
|
||||||
|
this.onabort(new ProgressEvent("abort", {"target":this}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If write end callback
|
||||||
|
if (typeof this.onwriteend === "function") {
|
||||||
|
this.onwriteend(new ProgressEvent("writeend", {"target":this}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes data to the file
|
||||||
|
*
|
||||||
|
* @param data text or blob to be written
|
||||||
|
* @param isPendingBlobReadResult {Boolean} true if the data is the pending blob read operation result
|
||||||
|
*/
|
||||||
|
FileWriter.prototype.write = function(data, isPendingBlobReadResult) {
|
||||||
|
|
||||||
|
var that=this;
|
||||||
|
var supportsBinary = (typeof window.Blob !== 'undefined' && typeof window.ArrayBuffer !== 'undefined');
|
||||||
|
var isProxySupportBlobNatively = (cordova.platformId === "windows8" || cordova.platformId === "windows");
|
||||||
|
var isBinary;
|
||||||
|
|
||||||
|
// Check to see if the incoming data is a blob
|
||||||
|
if (data instanceof File || (!isProxySupportBlobNatively && supportsBinary && data instanceof Blob)) {
|
||||||
|
var fileReader = new FileReader();
|
||||||
|
fileReader.onload = function() {
|
||||||
|
// Call this method again, with the arraybuffer as argument
|
||||||
|
FileWriter.prototype.write.call(that, this.result, true /* isPendingBlobReadResult */);
|
||||||
|
};
|
||||||
|
fileReader.onerror = function () {
|
||||||
|
// DONE state
|
||||||
|
that.readyState = FileWriter.DONE;
|
||||||
|
|
||||||
|
// Save error
|
||||||
|
that.error = this.error;
|
||||||
|
|
||||||
|
// If onerror callback
|
||||||
|
if (typeof that.onerror === "function") {
|
||||||
|
that.onerror(new ProgressEvent("error", {"target":that}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If onwriteend callback
|
||||||
|
if (typeof that.onwriteend === "function") {
|
||||||
|
that.onwriteend(new ProgressEvent("writeend", {"target":that}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// WRITING state
|
||||||
|
this.readyState = FileWriter.WRITING;
|
||||||
|
|
||||||
|
if (supportsBinary) {
|
||||||
|
fileReader.readAsArrayBuffer(data);
|
||||||
|
} else {
|
||||||
|
fileReader.readAsText(data);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark data type for safer transport over the binary bridge
|
||||||
|
isBinary = supportsBinary && (data instanceof ArrayBuffer);
|
||||||
|
if (isBinary && cordova.platformId === "windowsphone") {
|
||||||
|
// create a plain array, using the keys from the Uint8Array view so that we can serialize it
|
||||||
|
data = Array.apply(null, new Uint8Array(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Throw an exception if we are already writing a file
|
||||||
|
if (this.readyState === FileWriter.WRITING && !isPendingBlobReadResult) {
|
||||||
|
throw new FileError(FileError.INVALID_STATE_ERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// WRITING state
|
||||||
|
this.readyState = FileWriter.WRITING;
|
||||||
|
|
||||||
|
var me = this;
|
||||||
|
|
||||||
|
// If onwritestart callback
|
||||||
|
if (typeof me.onwritestart === "function") {
|
||||||
|
me.onwritestart(new ProgressEvent("writestart", {"target":me}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write file
|
||||||
|
exec(
|
||||||
|
// Success callback
|
||||||
|
function(r) {
|
||||||
|
// If DONE (cancelled), then don't do anything
|
||||||
|
if (me.readyState === FileWriter.DONE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// position always increases by bytes written because file would be extended
|
||||||
|
me.position += r;
|
||||||
|
// The length of the file is now where we are done writing.
|
||||||
|
|
||||||
|
me.length = me.position;
|
||||||
|
|
||||||
|
// DONE state
|
||||||
|
me.readyState = FileWriter.DONE;
|
||||||
|
|
||||||
|
// If onwrite callback
|
||||||
|
if (typeof me.onwrite === "function") {
|
||||||
|
me.onwrite(new ProgressEvent("write", {"target":me}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If onwriteend callback
|
||||||
|
if (typeof me.onwriteend === "function") {
|
||||||
|
me.onwriteend(new ProgressEvent("writeend", {"target":me}));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Error callback
|
||||||
|
function(e) {
|
||||||
|
// If DONE (cancelled), then don't do anything
|
||||||
|
if (me.readyState === FileWriter.DONE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DONE state
|
||||||
|
me.readyState = FileWriter.DONE;
|
||||||
|
|
||||||
|
// Save error
|
||||||
|
me.error = new FileError(e);
|
||||||
|
|
||||||
|
// If onerror callback
|
||||||
|
if (typeof me.onerror === "function") {
|
||||||
|
me.onerror(new ProgressEvent("error", {"target":me}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If onwriteend callback
|
||||||
|
if (typeof me.onwriteend === "function") {
|
||||||
|
me.onwriteend(new ProgressEvent("writeend", {"target":me}));
|
||||||
|
}
|
||||||
|
}, "File", "write", [this.localURL, data, this.position, isBinary]);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the file pointer to the location specified.
|
||||||
|
*
|
||||||
|
* If the offset is a negative number the position of the file
|
||||||
|
* pointer is rewound. If the offset is greater than the file
|
||||||
|
* size the position is set to the end of the file.
|
||||||
|
*
|
||||||
|
* @param offset is the location to move the file pointer to.
|
||||||
|
*/
|
||||||
|
FileWriter.prototype.seek = function(offset) {
|
||||||
|
// Throw an exception if we are already writing a file
|
||||||
|
if (this.readyState === FileWriter.WRITING) {
|
||||||
|
throw new FileError(FileError.INVALID_STATE_ERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!offset && offset !== 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// See back from end of file.
|
||||||
|
if (offset < 0) {
|
||||||
|
this.position = Math.max(offset + this.length, 0);
|
||||||
|
}
|
||||||
|
// Offset is bigger than file size so set position
|
||||||
|
// to the end of the file.
|
||||||
|
else if (offset > this.length) {
|
||||||
|
this.position = this.length;
|
||||||
|
}
|
||||||
|
// Offset is between 0 and file size so set the position
|
||||||
|
// to start writing.
|
||||||
|
else {
|
||||||
|
this.position = offset;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Truncates the file to the size specified.
|
||||||
|
*
|
||||||
|
* @param size to chop the file at.
|
||||||
|
*/
|
||||||
|
FileWriter.prototype.truncate = function(size) {
|
||||||
|
// Throw an exception if we are already writing a file
|
||||||
|
if (this.readyState === FileWriter.WRITING) {
|
||||||
|
throw new FileError(FileError.INVALID_STATE_ERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// WRITING state
|
||||||
|
this.readyState = FileWriter.WRITING;
|
||||||
|
|
||||||
|
var me = this;
|
||||||
|
|
||||||
|
// If onwritestart callback
|
||||||
|
if (typeof me.onwritestart === "function") {
|
||||||
|
me.onwritestart(new ProgressEvent("writestart", {"target":this}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write file
|
||||||
|
exec(
|
||||||
|
// Success callback
|
||||||
|
function(r) {
|
||||||
|
// If DONE (cancelled), then don't do anything
|
||||||
|
if (me.readyState === FileWriter.DONE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DONE state
|
||||||
|
me.readyState = FileWriter.DONE;
|
||||||
|
|
||||||
|
// Update the length of the file
|
||||||
|
me.length = r;
|
||||||
|
me.position = Math.min(me.position, r);
|
||||||
|
|
||||||
|
// If onwrite callback
|
||||||
|
if (typeof me.onwrite === "function") {
|
||||||
|
me.onwrite(new ProgressEvent("write", {"target":me}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If onwriteend callback
|
||||||
|
if (typeof me.onwriteend === "function") {
|
||||||
|
me.onwriteend(new ProgressEvent("writeend", {"target":me}));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Error callback
|
||||||
|
function(e) {
|
||||||
|
// If DONE (cancelled), then don't do anything
|
||||||
|
if (me.readyState === FileWriter.DONE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DONE state
|
||||||
|
me.readyState = FileWriter.DONE;
|
||||||
|
|
||||||
|
// Save error
|
||||||
|
me.error = new FileError(e);
|
||||||
|
|
||||||
|
// If onerror callback
|
||||||
|
if (typeof me.onerror === "function") {
|
||||||
|
me.onerror(new ProgressEvent("error", {"target":me}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If onwriteend callback
|
||||||
|
if (typeof me.onwriteend === "function") {
|
||||||
|
me.onwriteend(new ProgressEvent("writeend", {"target":me}));
|
||||||
|
}
|
||||||
|
}, "File", "truncate", [this.localURL, size]);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = FileWriter;
|
||||||
|
|
||||||
|
});
|
39
platforms/android/platform_www/plugins/cordova-plugin-file/www/Flags.js
vendored
Normal file
39
platforms/android/platform_www/plugins/cordova-plugin-file/www/Flags.js
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
cordova.define("cordova-plugin-file.Flags", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supplies arguments to methods that lookup or create files and directories.
|
||||||
|
*
|
||||||
|
* @param create
|
||||||
|
* {boolean} file or directory if it doesn't exist
|
||||||
|
* @param exclusive
|
||||||
|
* {boolean} used with create; if true the command will fail if
|
||||||
|
* target path exists
|
||||||
|
*/
|
||||||
|
function Flags(create, exclusive) {
|
||||||
|
this.create = create || false;
|
||||||
|
this.exclusive = exclusive || false;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Flags;
|
||||||
|
|
||||||
|
});
|
26
platforms/android/platform_www/plugins/cordova-plugin-file/www/LocalFileSystem.js
vendored
Normal file
26
platforms/android/platform_www/plugins/cordova-plugin-file/www/LocalFileSystem.js
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
cordova.define("cordova-plugin-file.LocalFileSystem", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.TEMPORARY = 0;
|
||||||
|
exports.PERSISTENT = 1;
|
||||||
|
|
||||||
|
});
|
43
platforms/android/platform_www/plugins/cordova-plugin-file/www/Metadata.js
vendored
Normal file
43
platforms/android/platform_www/plugins/cordova-plugin-file/www/Metadata.js
vendored
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
cordova.define("cordova-plugin-file.Metadata", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about the state of the file or directory
|
||||||
|
*
|
||||||
|
* {Date} modificationTime (readonly)
|
||||||
|
*/
|
||||||
|
var Metadata = function(metadata) {
|
||||||
|
if (typeof metadata == "object") {
|
||||||
|
this.modificationTime = new Date(metadata.modificationTime);
|
||||||
|
this.size = metadata.size || 0;
|
||||||
|
} else if (typeof metadata == "undefined") {
|
||||||
|
this.modificationTime = null;
|
||||||
|
this.size = 0;
|
||||||
|
} else {
|
||||||
|
/* Backwards compatiblity with platforms that only return a timestamp */
|
||||||
|
this.modificationTime = new Date(metadata);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = Metadata;
|
||||||
|
|
||||||
|
});
|
70
platforms/android/platform_www/plugins/cordova-plugin-file/www/ProgressEvent.js
vendored
Normal file
70
platforms/android/platform_www/plugins/cordova-plugin-file/www/ProgressEvent.js
vendored
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
cordova.define("cordova-plugin-file.ProgressEvent", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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 ProgressEvent exists in global context, use it already, otherwise use our own polyfill
|
||||||
|
// Feature test: See if we can instantiate a native ProgressEvent;
|
||||||
|
// if so, use that approach,
|
||||||
|
// otherwise fill-in with our own implementation.
|
||||||
|
//
|
||||||
|
// NOTE: right now we always fill in with our own. Down the road would be nice if we can use whatever is native in the webview.
|
||||||
|
var ProgressEvent = (function() {
|
||||||
|
/*
|
||||||
|
var createEvent = function(data) {
|
||||||
|
var event = document.createEvent('Events');
|
||||||
|
event.initEvent('ProgressEvent', false, false);
|
||||||
|
if (data) {
|
||||||
|
for (var i in data) {
|
||||||
|
if (data.hasOwnProperty(i)) {
|
||||||
|
event[i] = data[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (data.target) {
|
||||||
|
// TODO: cannot call <some_custom_object>.dispatchEvent
|
||||||
|
// need to first figure out how to implement EventTarget
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return event;
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
var ev = createEvent({type:"abort",target:document});
|
||||||
|
return function ProgressEvent(type, data) {
|
||||||
|
data.type = type;
|
||||||
|
return createEvent(data);
|
||||||
|
};
|
||||||
|
} catch(e){
|
||||||
|
*/
|
||||||
|
return function ProgressEvent(type, dict) {
|
||||||
|
this.type = type;
|
||||||
|
this.bubbles = false;
|
||||||
|
this.cancelBubble = false;
|
||||||
|
this.cancelable = false;
|
||||||
|
this.lengthComputable = false;
|
||||||
|
this.loaded = dict && dict.loaded ? dict.loaded : 0;
|
||||||
|
this.total = dict && dict.total ? dict.total : 0;
|
||||||
|
this.target = dict && dict.target ? dict.target : null;
|
||||||
|
};
|
||||||
|
//}
|
||||||
|
})();
|
||||||
|
|
||||||
|
module.exports = ProgressEvent;
|
||||||
|
|
||||||
|
});
|
52
platforms/android/platform_www/plugins/cordova-plugin-file/www/android/FileSystem.js
vendored
Normal file
52
platforms/android/platform_www/plugins/cordova-plugin-file/www/android/FileSystem.js
vendored
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
cordova.define("cordova-plugin-file.androidFileSystem", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
FILESYSTEM_PROTOCOL = "cdvfile";
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
__format__: function(fullPath, nativeUrl) {
|
||||||
|
var path;
|
||||||
|
var contentUrlMatch = /^content:\/\//.exec(nativeUrl);
|
||||||
|
if (contentUrlMatch) {
|
||||||
|
// When available, use the path from a native content URL, which was already encoded by Android.
|
||||||
|
// This is necessary because JavaScript's encodeURI() does not encode as many characters as
|
||||||
|
// Android, which can result in permission exceptions when the encoding of a content URI
|
||||||
|
// doesn't match the string for which permission was originally granted.
|
||||||
|
path = nativeUrl.substring(contentUrlMatch[0].length - 1);
|
||||||
|
} else {
|
||||||
|
path = FileSystem.encodeURIPath(fullPath);
|
||||||
|
if (!/^\//.test(path)) {
|
||||||
|
path = '/' + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
var m = /\?.*/.exec(nativeUrl);
|
||||||
|
if (m) {
|
||||||
|
path += m[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FILESYSTEM_PROTOCOL + '://localhost/' + this.name + path;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
});
|
29
platforms/android/platform_www/plugins/cordova-plugin-file/www/browser/isChrome.js
vendored
Normal file
29
platforms/android/platform_www/plugins/cordova-plugin-file/www/browser/isChrome.js
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
cordova.define("cordova-plugin-file.isChrome", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = function () {
|
||||||
|
// window.webkitRequestFileSystem and window.webkitResolveLocalFileSystemURL are available only in Chrome and
|
||||||
|
// possibly a good flag to indicate that we're running in Chrome
|
||||||
|
return window.webkitRequestFileSystem && window.webkitResolveLocalFileSystemURL;
|
||||||
|
};
|
||||||
|
|
||||||
|
});
|
66
platforms/android/platform_www/plugins/cordova-plugin-file/www/fileSystemPaths.js
vendored
Normal file
66
platforms/android/platform_www/plugins/cordova-plugin-file/www/fileSystemPaths.js
vendored
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
cordova.define("cordova-plugin-file.fileSystemPaths", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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 exec = require('cordova/exec');
|
||||||
|
var channel = require('cordova/channel');
|
||||||
|
|
||||||
|
exports.file = {
|
||||||
|
// Read-only directory where the application is installed.
|
||||||
|
applicationDirectory: null,
|
||||||
|
// Root of app's private writable storage
|
||||||
|
applicationStorageDirectory: null,
|
||||||
|
// Where to put app-specific data files.
|
||||||
|
dataDirectory: null,
|
||||||
|
// Cached files that should survive app restarts.
|
||||||
|
// Apps should not rely on the OS to delete files in here.
|
||||||
|
cacheDirectory: null,
|
||||||
|
// Android: the application space on external storage.
|
||||||
|
externalApplicationStorageDirectory: null,
|
||||||
|
// Android: Where to put app-specific data files on external storage.
|
||||||
|
externalDataDirectory: null,
|
||||||
|
// Android: the application cache on external storage.
|
||||||
|
externalCacheDirectory: null,
|
||||||
|
// Android: the external storage (SD card) root.
|
||||||
|
externalRootDirectory: null,
|
||||||
|
// iOS: Temp directory that the OS can clear at will.
|
||||||
|
tempDirectory: null,
|
||||||
|
// iOS: Holds app-specific files that should be synced (e.g. to iCloud).
|
||||||
|
syncedDataDirectory: null,
|
||||||
|
// iOS: Files private to the app, but that are meaningful to other applications (e.g. Office files)
|
||||||
|
documentsDirectory: null,
|
||||||
|
// BlackBerry10: Files globally available to all apps
|
||||||
|
sharedDirectory: null
|
||||||
|
};
|
||||||
|
|
||||||
|
channel.waitForInitialization('onFileSystemPathsReady');
|
||||||
|
channel.onCordovaReady.subscribe(function() {
|
||||||
|
function after(paths) {
|
||||||
|
for (var k in paths) {
|
||||||
|
exports.file[k] = paths[k];
|
||||||
|
}
|
||||||
|
channel.initializationComplete('onFileSystemPathsReady');
|
||||||
|
}
|
||||||
|
exec(after, null, 'File', 'requestAllPaths', []);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
});
|
48
platforms/android/platform_www/plugins/cordova-plugin-file/www/fileSystems-roots.js
vendored
Normal file
48
platforms/android/platform_www/plugins/cordova-plugin-file/www/fileSystems-roots.js
vendored
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
cordova.define("cordova-plugin-file.fileSystems-roots", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Map of fsName -> FileSystem.
|
||||||
|
var fsMap = null;
|
||||||
|
var FileSystem = require('./FileSystem');
|
||||||
|
var exec = require('cordova/exec');
|
||||||
|
|
||||||
|
// Overridden by Android, BlackBerry 10 and iOS to populate fsMap.
|
||||||
|
require('./fileSystems').getFs = function(name, callback) {
|
||||||
|
function success(response) {
|
||||||
|
fsMap = {};
|
||||||
|
for (var i = 0; i < response.length; ++i) {
|
||||||
|
var fsRoot = response[i];
|
||||||
|
var fs = new FileSystem(fsRoot.filesystemName, fsRoot);
|
||||||
|
fsMap[fs.name] = fs;
|
||||||
|
}
|
||||||
|
callback(fsMap[name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fsMap) {
|
||||||
|
callback(fsMap[name]);
|
||||||
|
} else {
|
||||||
|
exec(success, null, "File", "requestAllFileSystems", []);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
});
|
28
platforms/android/platform_www/plugins/cordova-plugin-file/www/fileSystems.js
vendored
Normal file
28
platforms/android/platform_www/plugins/cordova-plugin-file/www/fileSystems.js
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
cordova.define("cordova-plugin-file.fileSystems", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Overridden by Android, BlackBerry 10 and iOS to populate fsMap.
|
||||||
|
module.exports.getFs = function(name, callback) {
|
||||||
|
callback(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
});
|
85
platforms/android/platform_www/plugins/cordova-plugin-file/www/requestFileSystem.js
vendored
Normal file
85
platforms/android/platform_www/plugins/cordova-plugin-file/www/requestFileSystem.js
vendored
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
cordova.define("cordova-plugin-file.requestFileSystem", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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() {
|
||||||
|
//For browser platform: not all browsers use this file.
|
||||||
|
function checkBrowser() {
|
||||||
|
if (cordova.platformId === "browser" && require('./isChrome')()) {
|
||||||
|
module.exports = window.requestFileSystem || window.webkitRequestFileSystem;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (checkBrowser()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var argscheck = require('cordova/argscheck'),
|
||||||
|
FileError = require('./FileError'),
|
||||||
|
FileSystem = require('./FileSystem'),
|
||||||
|
exec = require('cordova/exec');
|
||||||
|
var fileSystems = require('./fileSystems');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request a file system in which to store application data.
|
||||||
|
* @param type local file system type
|
||||||
|
* @param size indicates how much storage space, in bytes, the application expects to need
|
||||||
|
* @param successCallback invoked with a FileSystem object
|
||||||
|
* @param errorCallback invoked if error occurs retrieving file system
|
||||||
|
*/
|
||||||
|
var requestFileSystem = function(type, size, successCallback, errorCallback) {
|
||||||
|
argscheck.checkArgs('nnFF', 'requestFileSystem', arguments);
|
||||||
|
var fail = function(code) {
|
||||||
|
if (errorCallback) {
|
||||||
|
errorCallback(new FileError(code));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (type < 0) {
|
||||||
|
fail(FileError.SYNTAX_ERR);
|
||||||
|
} else {
|
||||||
|
// if successful, return a FileSystem object
|
||||||
|
var success = function(file_system) {
|
||||||
|
if (file_system) {
|
||||||
|
if (successCallback) {
|
||||||
|
fileSystems.getFs(file_system.name, function(fs) {
|
||||||
|
// This should happen only on platforms that haven't implemented requestAllFileSystems (windows)
|
||||||
|
if (!fs) {
|
||||||
|
fs = new FileSystem(file_system.name, file_system.root);
|
||||||
|
}
|
||||||
|
successCallback(fs);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// no FileSystem object returned
|
||||||
|
fail(FileError.NOT_FOUND_ERR);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
exec(success, fail, "File", "requestFileSystem", [type, size]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = requestFileSystem;
|
||||||
|
})();
|
||||||
|
|
||||||
|
});
|
95
platforms/android/platform_www/plugins/cordova-plugin-file/www/resolveLocalFileSystemURI.js
vendored
Normal file
95
platforms/android/platform_www/plugins/cordova-plugin-file/www/resolveLocalFileSystemURI.js
vendored
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
cordova.define("cordova-plugin-file.resolveLocalFileSystemURI", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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() {
|
||||||
|
//For browser platform: not all browsers use overrided `resolveLocalFileSystemURL`.
|
||||||
|
function checkBrowser() {
|
||||||
|
if (cordova.platformId === "browser" && require('./isChrome')()) {
|
||||||
|
module.exports.resolveLocalFileSystemURL = window.resolveLocalFileSystemURL || window.webkitResolveLocalFileSystemURL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (checkBrowser()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var argscheck = require('cordova/argscheck'),
|
||||||
|
DirectoryEntry = require('./DirectoryEntry'),
|
||||||
|
FileEntry = require('./FileEntry'),
|
||||||
|
FileError = require('./FileError'),
|
||||||
|
exec = require('cordova/exec');
|
||||||
|
var fileSystems = require('./fileSystems');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Look up file system Entry referred to by local URI.
|
||||||
|
* @param {DOMString} uri URI referring to a local file or directory
|
||||||
|
* @param successCallback invoked with Entry object corresponding to URI
|
||||||
|
* @param errorCallback invoked if error occurs retrieving file system entry
|
||||||
|
*/
|
||||||
|
module.exports.resolveLocalFileSystemURL = module.exports.resolveLocalFileSystemURL || function(uri, successCallback, errorCallback) {
|
||||||
|
argscheck.checkArgs('sFF', 'resolveLocalFileSystemURI', arguments);
|
||||||
|
// error callback
|
||||||
|
var fail = function(error) {
|
||||||
|
if (errorCallback) {
|
||||||
|
errorCallback(new FileError(error));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// sanity check for 'not:valid:filename' or '/not:valid:filename'
|
||||||
|
// file.spec.12 window.resolveLocalFileSystemURI should error (ENCODING_ERR) when resolving invalid URI with leading /.
|
||||||
|
if(!uri || uri.split(":").length > 2) {
|
||||||
|
setTimeout( function() {
|
||||||
|
fail(FileError.ENCODING_ERR);
|
||||||
|
},0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// if successful, return either a file or directory entry
|
||||||
|
var success = function(entry) {
|
||||||
|
if (entry) {
|
||||||
|
if (successCallback) {
|
||||||
|
// create appropriate Entry object
|
||||||
|
var fsName = entry.filesystemName || (entry.filesystem && entry.filesystem.name) || (entry.filesystem == window.PERSISTENT ? 'persistent' : 'temporary');
|
||||||
|
fileSystems.getFs(fsName, function(fs) {
|
||||||
|
// This should happen only on platforms that haven't implemented requestAllFileSystems (windows)
|
||||||
|
if (!fs) {
|
||||||
|
fs = new FileSystem(fsName, {name:"", fullPath:"/"});
|
||||||
|
}
|
||||||
|
var result = (entry.isDirectory) ? new DirectoryEntry(entry.name, entry.fullPath, fs, entry.nativeURL) : new FileEntry(entry.name, entry.fullPath, fs, entry.nativeURL);
|
||||||
|
successCallback(result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// no Entry object returned
|
||||||
|
fail(FileError.NOT_FOUND_ERR);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exec(success, fail, "File", "resolveLocalFileSystemURI", [uri]);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.resolveLocalFileSystemURI = function() {
|
||||||
|
console.log("resolveLocalFileSystemURI is deprecated. Please call resolveLocalFileSystemURL instead.");
|
||||||
|
module.exports.resolveLocalFileSystemURL.apply(this, arguments);
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
});
|
BIN
platforms/android/res/drawable-xxhdpi/icon.png
Normal file
BIN
platforms/android/res/drawable-xxhdpi/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.3 KiB |
BIN
platforms/android/res/drawable-xxxhdpi/icon.png
Normal file
BIN
platforms/android/res/drawable-xxxhdpi/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.2 KiB |
@ -0,0 +1,286 @@
|
|||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
package org.apache.cordova.file;
|
||||||
|
|
||||||
|
import android.content.res.AssetManager;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import org.apache.cordova.CordovaResourceApi;
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class AssetFilesystem extends Filesystem {
|
||||||
|
|
||||||
|
private final AssetManager assetManager;
|
||||||
|
|
||||||
|
// A custom gradle hook creates the cdvasset.manifest file, which speeds up asset listing a tonne.
|
||||||
|
// See: http://stackoverflow.com/questions/16911558/android-assetmanager-list-incredibly-slow
|
||||||
|
private static Object listCacheLock = new Object();
|
||||||
|
private static boolean listCacheFromFile;
|
||||||
|
private static Map<String, String[]> listCache;
|
||||||
|
private static Map<String, Long> lengthCache;
|
||||||
|
|
||||||
|
private void lazyInitCaches() {
|
||||||
|
synchronized (listCacheLock) {
|
||||||
|
if (listCache == null) {
|
||||||
|
ObjectInputStream ois = null;
|
||||||
|
try {
|
||||||
|
ois = new ObjectInputStream(assetManager.open("cdvasset.manifest"));
|
||||||
|
listCache = (Map<String, String[]>) ois.readObject();
|
||||||
|
lengthCache = (Map<String, Long>) ois.readObject();
|
||||||
|
listCacheFromFile = true;
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// Asset manifest won't exist if the gradle hook isn't set up correctly.
|
||||||
|
} finally {
|
||||||
|
if (ois != null) {
|
||||||
|
try {
|
||||||
|
ois.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (listCache == null) {
|
||||||
|
Log.w("AssetFilesystem", "Asset manifest not found. Recursive copies and directory listing will be slow.");
|
||||||
|
listCache = new HashMap<String, String[]>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] listAssets(String assetPath) throws IOException {
|
||||||
|
if (assetPath.startsWith("/")) {
|
||||||
|
assetPath = assetPath.substring(1);
|
||||||
|
}
|
||||||
|
if (assetPath.endsWith("/")) {
|
||||||
|
assetPath = assetPath.substring(0, assetPath.length() - 1);
|
||||||
|
}
|
||||||
|
lazyInitCaches();
|
||||||
|
String[] ret = listCache.get(assetPath);
|
||||||
|
if (ret == null) {
|
||||||
|
if (listCacheFromFile) {
|
||||||
|
ret = new String[0];
|
||||||
|
} else {
|
||||||
|
ret = assetManager.list(assetPath);
|
||||||
|
listCache.put(assetPath, ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long getAssetSize(String assetPath) throws FileNotFoundException {
|
||||||
|
if (assetPath.startsWith("/")) {
|
||||||
|
assetPath = assetPath.substring(1);
|
||||||
|
}
|
||||||
|
lazyInitCaches();
|
||||||
|
if (lengthCache != null) {
|
||||||
|
Long ret = lengthCache.get(assetPath);
|
||||||
|
if (ret == null) {
|
||||||
|
throw new FileNotFoundException("Asset not found: " + assetPath);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
CordovaResourceApi.OpenForReadResult offr = null;
|
||||||
|
try {
|
||||||
|
offr = resourceApi.openForRead(nativeUriForFullPath(assetPath));
|
||||||
|
long length = offr.length;
|
||||||
|
if (length < 0) {
|
||||||
|
// available() doesn't always yield the file size, but for assets it does.
|
||||||
|
length = offr.inputStream.available();
|
||||||
|
}
|
||||||
|
return length;
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new FileNotFoundException("File not found: " + assetPath);
|
||||||
|
} finally {
|
||||||
|
if (offr != null) {
|
||||||
|
try {
|
||||||
|
offr.inputStream.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public AssetFilesystem(AssetManager assetManager, CordovaResourceApi resourceApi) {
|
||||||
|
super(Uri.parse("file:///android_asset/"), "assets", resourceApi);
|
||||||
|
this.assetManager = assetManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri toNativeUri(LocalFilesystemURL inputURL) {
|
||||||
|
return nativeUriForFullPath(inputURL.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LocalFilesystemURL toLocalUri(Uri inputURL) {
|
||||||
|
if (!"file".equals(inputURL.getScheme())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
File f = new File(inputURL.getPath());
|
||||||
|
// Removes and duplicate /s (e.g. file:///a//b/c)
|
||||||
|
Uri resolvedUri = Uri.fromFile(f);
|
||||||
|
String rootUriNoTrailingSlash = rootUri.getEncodedPath();
|
||||||
|
rootUriNoTrailingSlash = rootUriNoTrailingSlash.substring(0, rootUriNoTrailingSlash.length() - 1);
|
||||||
|
if (!resolvedUri.getEncodedPath().startsWith(rootUriNoTrailingSlash)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String subPath = resolvedUri.getEncodedPath().substring(rootUriNoTrailingSlash.length());
|
||||||
|
// Strip leading slash
|
||||||
|
if (!subPath.isEmpty()) {
|
||||||
|
subPath = subPath.substring(1);
|
||||||
|
}
|
||||||
|
Uri.Builder b = new Uri.Builder()
|
||||||
|
.scheme(LocalFilesystemURL.FILESYSTEM_PROTOCOL)
|
||||||
|
.authority("localhost")
|
||||||
|
.path(name);
|
||||||
|
if (!subPath.isEmpty()) {
|
||||||
|
b.appendEncodedPath(subPath);
|
||||||
|
}
|
||||||
|
if (isDirectory(subPath) || inputURL.getPath().endsWith("/")) {
|
||||||
|
// Add trailing / for directories.
|
||||||
|
b.appendEncodedPath("");
|
||||||
|
}
|
||||||
|
return LocalFilesystemURL.parse(b.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isDirectory(String assetPath) {
|
||||||
|
try {
|
||||||
|
return listAssets(assetPath).length != 0;
|
||||||
|
} catch (IOException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LocalFilesystemURL[] listChildren(LocalFilesystemURL inputURL) throws FileNotFoundException {
|
||||||
|
String pathNoSlashes = inputURL.path.substring(1);
|
||||||
|
if (pathNoSlashes.endsWith("/")) {
|
||||||
|
pathNoSlashes = pathNoSlashes.substring(0, pathNoSlashes.length() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] files;
|
||||||
|
try {
|
||||||
|
files = listAssets(pathNoSlashes);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new FileNotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalFilesystemURL[] entries = new LocalFilesystemURL[files.length];
|
||||||
|
for (int i = 0; i < files.length; ++i) {
|
||||||
|
entries[i] = localUrlforFullPath(new File(inputURL.path, files[i]).getPath());
|
||||||
|
}
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject getFileForLocalURL(LocalFilesystemURL inputURL,
|
||||||
|
String path, JSONObject options, boolean directory)
|
||||||
|
throws FileExistsException, IOException, TypeMismatchException, EncodingException, JSONException {
|
||||||
|
if (options != null && options.optBoolean("create")) {
|
||||||
|
throw new UnsupportedOperationException("Assets are read-only");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check whether the supplied path is absolute or relative
|
||||||
|
if (directory && !path.endsWith("/")) {
|
||||||
|
path += "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalFilesystemURL requestedURL;
|
||||||
|
if (path.startsWith("/")) {
|
||||||
|
requestedURL = localUrlforFullPath(normalizePath(path));
|
||||||
|
} else {
|
||||||
|
requestedURL = localUrlforFullPath(normalizePath(inputURL.path + "/" + path));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Throws a FileNotFoundException if it doesn't exist.
|
||||||
|
getFileMetadataForLocalURL(requestedURL);
|
||||||
|
|
||||||
|
boolean isDir = isDirectory(requestedURL.path);
|
||||||
|
if (directory && !isDir) {
|
||||||
|
throw new TypeMismatchException("path doesn't exist or is file");
|
||||||
|
} else if (!directory && isDir) {
|
||||||
|
throw new TypeMismatchException("path doesn't exist or is directory");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the directory
|
||||||
|
return makeEntryForURL(requestedURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject getFileMetadataForLocalURL(LocalFilesystemURL inputURL) throws FileNotFoundException {
|
||||||
|
JSONObject metadata = new JSONObject();
|
||||||
|
long size = inputURL.isDirectory ? 0 : getAssetSize(inputURL.path);
|
||||||
|
try {
|
||||||
|
metadata.put("size", size);
|
||||||
|
metadata.put("type", inputURL.isDirectory ? "text/directory" : resourceApi.getMimeType(toNativeUri(inputURL)));
|
||||||
|
metadata.put("name", new File(inputURL.path).getName());
|
||||||
|
metadata.put("fullPath", inputURL.path);
|
||||||
|
metadata.put("lastModifiedDate", 0);
|
||||||
|
} catch (JSONException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canRemoveFileAtLocalURL(LocalFilesystemURL inputURL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
long writeToFileAtURL(LocalFilesystemURL inputURL, String data, int offset, boolean isBinary) throws NoModificationAllowedException, IOException {
|
||||||
|
throw new NoModificationAllowedException("Assets are read-only");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
long truncateFileAtURL(LocalFilesystemURL inputURL, long size) throws IOException, NoModificationAllowedException {
|
||||||
|
throw new NoModificationAllowedException("Assets are read-only");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String filesystemPathForURL(LocalFilesystemURL url) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
LocalFilesystemURL URLforFilesystemPath(String path) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean removeFileAtLocalURL(LocalFilesystemURL inputURL) throws InvalidModificationException, NoModificationAllowedException {
|
||||||
|
throw new NoModificationAllowedException("Assets are read-only");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean recursiveRemoveFileAtLocalURL(LocalFilesystemURL inputURL) throws NoModificationAllowedException {
|
||||||
|
throw new NoModificationAllowedException("Assets are read-only");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,216 @@
|
|||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
package org.apache.cordova.file;
|
||||||
|
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.provider.DocumentsContract;
|
||||||
|
import android.provider.MediaStore;
|
||||||
|
import android.provider.OpenableColumns;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import org.apache.cordova.CordovaResourceApi;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
public class ContentFilesystem extends Filesystem {
|
||||||
|
|
||||||
|
private final Context context;
|
||||||
|
|
||||||
|
public ContentFilesystem(Context context, CordovaResourceApi resourceApi) {
|
||||||
|
super(Uri.parse("content://"), "content", resourceApi);
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri toNativeUri(LocalFilesystemURL inputURL) {
|
||||||
|
String authorityAndPath = inputURL.uri.getEncodedPath().substring(this.name.length() + 2);
|
||||||
|
if (authorityAndPath.length() < 2) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String ret = "content://" + authorityAndPath;
|
||||||
|
String query = inputURL.uri.getEncodedQuery();
|
||||||
|
if (query != null) {
|
||||||
|
ret += '?' + query;
|
||||||
|
}
|
||||||
|
String frag = inputURL.uri.getEncodedFragment();
|
||||||
|
if (frag != null) {
|
||||||
|
ret += '#' + frag;
|
||||||
|
}
|
||||||
|
return Uri.parse(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LocalFilesystemURL toLocalUri(Uri inputURL) {
|
||||||
|
if (!"content".equals(inputURL.getScheme())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String subPath = inputURL.getEncodedPath();
|
||||||
|
if (subPath.length() > 0) {
|
||||||
|
subPath = subPath.substring(1);
|
||||||
|
}
|
||||||
|
Uri.Builder b = new Uri.Builder()
|
||||||
|
.scheme(LocalFilesystemURL.FILESYSTEM_PROTOCOL)
|
||||||
|
.authority("localhost")
|
||||||
|
.path(name)
|
||||||
|
.appendPath(inputURL.getAuthority());
|
||||||
|
if (subPath.length() > 0) {
|
||||||
|
b.appendEncodedPath(subPath);
|
||||||
|
}
|
||||||
|
Uri localUri = b.encodedQuery(inputURL.getEncodedQuery())
|
||||||
|
.encodedFragment(inputURL.getEncodedFragment())
|
||||||
|
.build();
|
||||||
|
return LocalFilesystemURL.parse(localUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject getFileForLocalURL(LocalFilesystemURL inputURL,
|
||||||
|
String fileName, JSONObject options, boolean directory) throws IOException, TypeMismatchException, JSONException {
|
||||||
|
throw new UnsupportedOperationException("getFile() not supported for content:. Use resolveLocalFileSystemURL instead.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean removeFileAtLocalURL(LocalFilesystemURL inputURL)
|
||||||
|
throws NoModificationAllowedException {
|
||||||
|
Uri contentUri = toNativeUri(inputURL);
|
||||||
|
try {
|
||||||
|
context.getContentResolver().delete(contentUri, null, null);
|
||||||
|
} catch (UnsupportedOperationException t) {
|
||||||
|
// Was seeing this on the File mobile-spec tests on 4.0.3 x86 emulator.
|
||||||
|
// The ContentResolver applies only when the file was registered in the
|
||||||
|
// first case, which is generally only the case with images.
|
||||||
|
throw new NoModificationAllowedException("Deleting not supported for content uri: " + contentUri);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean recursiveRemoveFileAtLocalURL(LocalFilesystemURL inputURL)
|
||||||
|
throws NoModificationAllowedException {
|
||||||
|
throw new NoModificationAllowedException("Cannot remove content url");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LocalFilesystemURL[] listChildren(LocalFilesystemURL inputURL) throws FileNotFoundException {
|
||||||
|
throw new UnsupportedOperationException("readEntriesAtLocalURL() not supported for content:. Use resolveLocalFileSystemURL instead.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject getFileMetadataForLocalURL(LocalFilesystemURL inputURL) throws FileNotFoundException {
|
||||||
|
long size = -1;
|
||||||
|
long lastModified = 0;
|
||||||
|
Uri nativeUri = toNativeUri(inputURL);
|
||||||
|
String mimeType = resourceApi.getMimeType(nativeUri);
|
||||||
|
Cursor cursor = openCursorForURL(nativeUri);
|
||||||
|
try {
|
||||||
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
|
size = resourceSizeForCursor(cursor);
|
||||||
|
Long modified = lastModifiedDateForCursor(cursor);
|
||||||
|
if (modified != null)
|
||||||
|
lastModified = modified.longValue();
|
||||||
|
} else {
|
||||||
|
// Some content providers don't support cursors at all!
|
||||||
|
CordovaResourceApi.OpenForReadResult offr = resourceApi.openForRead(nativeUri);
|
||||||
|
size = offr.length;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new FileNotFoundException();
|
||||||
|
} finally {
|
||||||
|
if (cursor != null)
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject metadata = new JSONObject();
|
||||||
|
try {
|
||||||
|
metadata.put("size", size);
|
||||||
|
metadata.put("type", mimeType);
|
||||||
|
metadata.put("name", name);
|
||||||
|
metadata.put("fullPath", inputURL.path);
|
||||||
|
metadata.put("lastModifiedDate", lastModified);
|
||||||
|
} catch (JSONException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long writeToFileAtURL(LocalFilesystemURL inputURL, String data,
|
||||||
|
int offset, boolean isBinary) throws NoModificationAllowedException {
|
||||||
|
throw new NoModificationAllowedException("Couldn't write to file given its content URI");
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public long truncateFileAtURL(LocalFilesystemURL inputURL, long size)
|
||||||
|
throws NoModificationAllowedException {
|
||||||
|
throw new NoModificationAllowedException("Couldn't truncate file given its content URI");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Cursor openCursorForURL(Uri nativeUri) {
|
||||||
|
ContentResolver contentResolver = context.getContentResolver();
|
||||||
|
try {
|
||||||
|
return contentResolver.query(nativeUri, null, null, null, null);
|
||||||
|
} catch (UnsupportedOperationException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Long resourceSizeForCursor(Cursor cursor) {
|
||||||
|
int columnIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
|
||||||
|
if (columnIndex != -1) {
|
||||||
|
String sizeStr = cursor.getString(columnIndex);
|
||||||
|
if (sizeStr != null) {
|
||||||
|
return Long.parseLong(sizeStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Long lastModifiedDateForCursor(Cursor cursor) {
|
||||||
|
int columnIndex = cursor.getColumnIndex(MediaStore.MediaColumns.DATE_MODIFIED);
|
||||||
|
if (columnIndex == -1) {
|
||||||
|
columnIndex = cursor.getColumnIndex(DocumentsContract.Document.COLUMN_LAST_MODIFIED);
|
||||||
|
}
|
||||||
|
if (columnIndex != -1) {
|
||||||
|
String dateStr = cursor.getString(columnIndex);
|
||||||
|
if (dateStr != null) {
|
||||||
|
return Long.parseLong(dateStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String filesystemPathForURL(LocalFilesystemURL url) {
|
||||||
|
File f = resourceApi.mapUriToFile(toNativeUri(url));
|
||||||
|
return f == null ? null : f.getAbsolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LocalFilesystemURL URLforFilesystemPath(String path) {
|
||||||
|
// Returns null as we don't support reverse mapping back to content:// URLs
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canRemoveFileAtLocalURL(LocalFilesystemURL inputURL) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
package org.apache.cordova.file;
|
||||||
|
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.os.StatFs;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class provides file directory utilities.
|
||||||
|
* All file operations are performed on the SD card.
|
||||||
|
*
|
||||||
|
* It is used by the FileUtils class.
|
||||||
|
*/
|
||||||
|
public class DirectoryManager {
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private static final String LOG_TAG = "DirectoryManager";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if a file or directory exists.
|
||||||
|
* @param name The name of the file to check.
|
||||||
|
* @return T=exists, F=not found
|
||||||
|
*/
|
||||||
|
public static boolean testFileExists(String name) {
|
||||||
|
boolean status;
|
||||||
|
|
||||||
|
// If SD card exists
|
||||||
|
if ((testSaveLocationExists()) && (!name.equals(""))) {
|
||||||
|
File path = Environment.getExternalStorageDirectory();
|
||||||
|
File newPath = constructFilePaths(path.toString(), name);
|
||||||
|
status = newPath.exists();
|
||||||
|
}
|
||||||
|
// If no SD card
|
||||||
|
else {
|
||||||
|
status = false;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the free space in external storage
|
||||||
|
*
|
||||||
|
* @return Size in KB or -1 if not available
|
||||||
|
*/
|
||||||
|
public static long getFreeExternalStorageSpace() {
|
||||||
|
String status = Environment.getExternalStorageState();
|
||||||
|
long freeSpaceInBytes = 0;
|
||||||
|
|
||||||
|
// Check if external storage exists
|
||||||
|
if (status.equals(Environment.MEDIA_MOUNTED)) {
|
||||||
|
freeSpaceInBytes = getFreeSpaceInBytes(Environment.getExternalStorageDirectory().getPath());
|
||||||
|
} else {
|
||||||
|
// If no external storage then return -1
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return freeSpaceInBytes / 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a path return the number of free bytes in the filesystem containing the path.
|
||||||
|
*
|
||||||
|
* @param path to the file system
|
||||||
|
* @return free space in bytes
|
||||||
|
*/
|
||||||
|
public static long getFreeSpaceInBytes(String path) {
|
||||||
|
try {
|
||||||
|
StatFs stat = new StatFs(path);
|
||||||
|
long blockSize = stat.getBlockSize();
|
||||||
|
long availableBlocks = stat.getAvailableBlocks();
|
||||||
|
return availableBlocks * blockSize;
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
// The path was invalid. Just return 0 free bytes.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if SD card exists.
|
||||||
|
*
|
||||||
|
* @return T=exists, F=not found
|
||||||
|
*/
|
||||||
|
public static boolean testSaveLocationExists() {
|
||||||
|
String sDCardStatus = Environment.getExternalStorageState();
|
||||||
|
boolean status;
|
||||||
|
|
||||||
|
// If SD card is mounted
|
||||||
|
if (sDCardStatus.equals(Environment.MEDIA_MOUNTED)) {
|
||||||
|
status = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no SD card
|
||||||
|
else {
|
||||||
|
status = false;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new file object from two file paths.
|
||||||
|
*
|
||||||
|
* @param file1 Base file path
|
||||||
|
* @param file2 Remaining file path
|
||||||
|
* @return File object
|
||||||
|
*/
|
||||||
|
private static File constructFilePaths (String file1, String file2) {
|
||||||
|
File newPath;
|
||||||
|
if (file2.startsWith(file1)) {
|
||||||
|
newPath = new File(file2);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
newPath = new File(file1 + "/" + file2);
|
||||||
|
}
|
||||||
|
return newPath;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.cordova.file;
|
||||||
|
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
public class EncodingException extends Exception {
|
||||||
|
|
||||||
|
public EncodingException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.cordova.file;
|
||||||
|
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
public class FileExistsException extends Exception {
|
||||||
|
|
||||||
|
public FileExistsException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
1196
platforms/android/src/org/apache/cordova/file/FileUtils.java
Normal file
1196
platforms/android/src/org/apache/cordova/file/FileUtils.java
Normal file
File diff suppressed because it is too large
Load Diff
331
platforms/android/src/org/apache/cordova/file/Filesystem.java
Normal file
331
platforms/android/src/org/apache/cordova/file/Filesystem.java
Normal file
@ -0,0 +1,331 @@
|
|||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
package org.apache.cordova.file;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FilterInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import org.apache.cordova.CordovaResourceApi;
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
public abstract class Filesystem {
|
||||||
|
|
||||||
|
protected final Uri rootUri;
|
||||||
|
protected final CordovaResourceApi resourceApi;
|
||||||
|
public final String name;
|
||||||
|
private JSONObject rootEntry;
|
||||||
|
|
||||||
|
public Filesystem(Uri rootUri, String name, CordovaResourceApi resourceApi) {
|
||||||
|
this.rootUri = rootUri;
|
||||||
|
this.name = name;
|
||||||
|
this.resourceApi = resourceApi;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ReadFileCallback {
|
||||||
|
public void handleData(InputStream inputStream, String contentType) throws IOException;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JSONObject makeEntryForURL(LocalFilesystemURL inputURL, Uri nativeURL) {
|
||||||
|
try {
|
||||||
|
String path = inputURL.path;
|
||||||
|
int end = path.endsWith("/") ? 1 : 0;
|
||||||
|
String[] parts = path.substring(0, path.length() - end).split("/+");
|
||||||
|
String fileName = parts[parts.length - 1];
|
||||||
|
|
||||||
|
JSONObject entry = new JSONObject();
|
||||||
|
entry.put("isFile", !inputURL.isDirectory);
|
||||||
|
entry.put("isDirectory", inputURL.isDirectory);
|
||||||
|
entry.put("name", fileName);
|
||||||
|
entry.put("fullPath", path);
|
||||||
|
// The file system can't be specified, as it would lead to an infinite loop,
|
||||||
|
// but the filesystem name can be.
|
||||||
|
entry.put("filesystemName", inputURL.fsName);
|
||||||
|
// Backwards compatibility
|
||||||
|
entry.put("filesystem", "temporary".equals(inputURL.fsName) ? 0 : 1);
|
||||||
|
|
||||||
|
String nativeUrlStr = nativeURL.toString();
|
||||||
|
if (inputURL.isDirectory && !nativeUrlStr.endsWith("/")) {
|
||||||
|
nativeUrlStr += "/";
|
||||||
|
}
|
||||||
|
entry.put("nativeURL", nativeUrlStr);
|
||||||
|
return entry;
|
||||||
|
} catch (JSONException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public JSONObject makeEntryForURL(LocalFilesystemURL inputURL) {
|
||||||
|
Uri nativeUri = toNativeUri(inputURL);
|
||||||
|
return nativeUri == null ? null : makeEntryForURL(inputURL, nativeUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JSONObject makeEntryForNativeUri(Uri nativeUri) {
|
||||||
|
LocalFilesystemURL inputUrl = toLocalUri(nativeUri);
|
||||||
|
return inputUrl == null ? null : makeEntryForURL(inputUrl, nativeUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JSONObject getEntryForLocalURL(LocalFilesystemURL inputURL) throws IOException {
|
||||||
|
return makeEntryForURL(inputURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JSONObject makeEntryForFile(File file) {
|
||||||
|
return makeEntryForNativeUri(Uri.fromFile(file));
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract JSONObject getFileForLocalURL(LocalFilesystemURL inputURL, String path,
|
||||||
|
JSONObject options, boolean directory) throws FileExistsException, IOException, TypeMismatchException, EncodingException, JSONException;
|
||||||
|
|
||||||
|
abstract boolean removeFileAtLocalURL(LocalFilesystemURL inputURL) throws InvalidModificationException, NoModificationAllowedException;
|
||||||
|
|
||||||
|
abstract boolean recursiveRemoveFileAtLocalURL(LocalFilesystemURL inputURL) throws FileExistsException, NoModificationAllowedException;
|
||||||
|
|
||||||
|
abstract LocalFilesystemURL[] listChildren(LocalFilesystemURL inputURL) throws FileNotFoundException;
|
||||||
|
|
||||||
|
public final JSONArray readEntriesAtLocalURL(LocalFilesystemURL inputURL) throws FileNotFoundException {
|
||||||
|
LocalFilesystemURL[] children = listChildren(inputURL);
|
||||||
|
JSONArray entries = new JSONArray();
|
||||||
|
if (children != null) {
|
||||||
|
for (LocalFilesystemURL url : children) {
|
||||||
|
entries.put(makeEntryForURL(url));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract JSONObject getFileMetadataForLocalURL(LocalFilesystemURL inputURL) throws FileNotFoundException;
|
||||||
|
|
||||||
|
public Uri getRootUri() {
|
||||||
|
return rootUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean exists(LocalFilesystemURL inputURL) {
|
||||||
|
try {
|
||||||
|
getFileMetadataForLocalURL(inputURL);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Uri nativeUriForFullPath(String fullPath) {
|
||||||
|
Uri ret = null;
|
||||||
|
if (fullPath != null) {
|
||||||
|
String encodedPath = Uri.fromFile(new File(fullPath)).getEncodedPath();
|
||||||
|
if (encodedPath.startsWith("/")) {
|
||||||
|
encodedPath = encodedPath.substring(1);
|
||||||
|
}
|
||||||
|
ret = rootUri.buildUpon().appendEncodedPath(encodedPath).build();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalFilesystemURL localUrlforFullPath(String fullPath) {
|
||||||
|
Uri nativeUri = nativeUriForFullPath(fullPath);
|
||||||
|
if (nativeUri != null) {
|
||||||
|
return toLocalUri(nativeUri);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes multiple repeated //s, and collapses processes ../s.
|
||||||
|
*/
|
||||||
|
protected static String normalizePath(String rawPath) {
|
||||||
|
// If this is an absolute path, trim the leading "/" and replace it later
|
||||||
|
boolean isAbsolutePath = rawPath.startsWith("/");
|
||||||
|
if (isAbsolutePath) {
|
||||||
|
rawPath = rawPath.replaceFirst("/+", "");
|
||||||
|
}
|
||||||
|
ArrayList<String> components = new ArrayList<String>(Arrays.asList(rawPath.split("/+")));
|
||||||
|
for (int index = 0; index < components.size(); ++index) {
|
||||||
|
if (components.get(index).equals("..")) {
|
||||||
|
components.remove(index);
|
||||||
|
if (index > 0) {
|
||||||
|
components.remove(index-1);
|
||||||
|
--index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
StringBuilder normalizedPath = new StringBuilder();
|
||||||
|
for(String component: components) {
|
||||||
|
normalizedPath.append("/");
|
||||||
|
normalizedPath.append(component);
|
||||||
|
}
|
||||||
|
if (isAbsolutePath) {
|
||||||
|
return normalizedPath.toString();
|
||||||
|
} else {
|
||||||
|
return normalizedPath.toString().substring(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the free space in bytes available on this filesystem.
|
||||||
|
* Subclasses may override this method to return nonzero free space.
|
||||||
|
*/
|
||||||
|
public long getFreeSpaceInBytes() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Uri toNativeUri(LocalFilesystemURL inputURL);
|
||||||
|
public abstract LocalFilesystemURL toLocalUri(Uri inputURL);
|
||||||
|
|
||||||
|
public JSONObject getRootEntry() {
|
||||||
|
if (rootEntry == null) {
|
||||||
|
rootEntry = makeEntryForNativeUri(rootUri);
|
||||||
|
}
|
||||||
|
return rootEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JSONObject getParentForLocalURL(LocalFilesystemURL inputURL) throws IOException {
|
||||||
|
Uri parentUri = inputURL.uri;
|
||||||
|
String parentPath = new File(inputURL.uri.getPath()).getParent();
|
||||||
|
if (!"/".equals(parentPath)) {
|
||||||
|
parentUri = inputURL.uri.buildUpon().path(parentPath + '/').build();
|
||||||
|
}
|
||||||
|
return getEntryForLocalURL(LocalFilesystemURL.parse(parentUri));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected LocalFilesystemURL makeDestinationURL(String newName, LocalFilesystemURL srcURL, LocalFilesystemURL destURL, boolean isDirectory) {
|
||||||
|
// I know this looks weird but it is to work around a JSON bug.
|
||||||
|
if ("null".equals(newName) || "".equals(newName)) {
|
||||||
|
newName = srcURL.uri.getLastPathSegment();;
|
||||||
|
}
|
||||||
|
|
||||||
|
String newDest = destURL.uri.toString();
|
||||||
|
if (newDest.endsWith("/")) {
|
||||||
|
newDest = newDest + newName;
|
||||||
|
} else {
|
||||||
|
newDest = newDest + "/" + newName;
|
||||||
|
}
|
||||||
|
if (isDirectory) {
|
||||||
|
newDest += '/';
|
||||||
|
}
|
||||||
|
return LocalFilesystemURL.parse(newDest);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read a source URL (possibly from a different filesystem, srcFs,) and copy it to
|
||||||
|
* the destination URL on this filesystem, optionally with a new filename.
|
||||||
|
* If move is true, then this method should either perform an atomic move operation
|
||||||
|
* or remove the source file when finished.
|
||||||
|
*/
|
||||||
|
public JSONObject copyFileToURL(LocalFilesystemURL destURL, String newName,
|
||||||
|
Filesystem srcFs, LocalFilesystemURL srcURL, boolean move) throws IOException, InvalidModificationException, JSONException, NoModificationAllowedException, FileExistsException {
|
||||||
|
// First, check to see that we can do it
|
||||||
|
if (move && !srcFs.canRemoveFileAtLocalURL(srcURL)) {
|
||||||
|
throw new NoModificationAllowedException("Cannot move file at source URL");
|
||||||
|
}
|
||||||
|
final LocalFilesystemURL destination = makeDestinationURL(newName, srcURL, destURL, srcURL.isDirectory);
|
||||||
|
|
||||||
|
Uri srcNativeUri = srcFs.toNativeUri(srcURL);
|
||||||
|
|
||||||
|
CordovaResourceApi.OpenForReadResult ofrr = resourceApi.openForRead(srcNativeUri);
|
||||||
|
OutputStream os = null;
|
||||||
|
try {
|
||||||
|
os = getOutputStreamForURL(destination);
|
||||||
|
} catch (IOException e) {
|
||||||
|
ofrr.inputStream.close();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
// Closes streams.
|
||||||
|
resourceApi.copyResource(ofrr, os);
|
||||||
|
|
||||||
|
if (move) {
|
||||||
|
srcFs.removeFileAtLocalURL(srcURL);
|
||||||
|
}
|
||||||
|
return getEntryForLocalURL(destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OutputStream getOutputStreamForURL(LocalFilesystemURL inputURL) throws IOException {
|
||||||
|
return resourceApi.openOutputStream(toNativeUri(inputURL));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readFileAtURL(LocalFilesystemURL inputURL, long start, long end,
|
||||||
|
ReadFileCallback readFileCallback) throws IOException {
|
||||||
|
CordovaResourceApi.OpenForReadResult ofrr = resourceApi.openForRead(toNativeUri(inputURL));
|
||||||
|
if (end < 0) {
|
||||||
|
end = ofrr.length;
|
||||||
|
}
|
||||||
|
long numBytesToRead = end - start;
|
||||||
|
try {
|
||||||
|
if (start > 0) {
|
||||||
|
ofrr.inputStream.skip(start);
|
||||||
|
}
|
||||||
|
InputStream inputStream = ofrr.inputStream;
|
||||||
|
if (end < ofrr.length) {
|
||||||
|
inputStream = new LimitedInputStream(inputStream, numBytesToRead);
|
||||||
|
}
|
||||||
|
readFileCallback.handleData(inputStream, ofrr.mimeType);
|
||||||
|
} finally {
|
||||||
|
ofrr.inputStream.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract long writeToFileAtURL(LocalFilesystemURL inputURL, String data, int offset,
|
||||||
|
boolean isBinary) throws NoModificationAllowedException, IOException;
|
||||||
|
|
||||||
|
abstract long truncateFileAtURL(LocalFilesystemURL inputURL, long size)
|
||||||
|
throws IOException, NoModificationAllowedException;
|
||||||
|
|
||||||
|
// This method should return null if filesystem urls cannot be mapped to paths
|
||||||
|
abstract String filesystemPathForURL(LocalFilesystemURL url);
|
||||||
|
|
||||||
|
abstract LocalFilesystemURL URLforFilesystemPath(String path);
|
||||||
|
|
||||||
|
abstract boolean canRemoveFileAtLocalURL(LocalFilesystemURL inputURL);
|
||||||
|
|
||||||
|
protected class LimitedInputStream extends FilterInputStream {
|
||||||
|
long numBytesToRead;
|
||||||
|
public LimitedInputStream(InputStream in, long numBytesToRead) {
|
||||||
|
super(in);
|
||||||
|
this.numBytesToRead = numBytesToRead;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public int read() throws IOException {
|
||||||
|
if (numBytesToRead <= 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
numBytesToRead--;
|
||||||
|
return in.read();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {
|
||||||
|
if (numBytesToRead <= 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int bytesToRead = byteCount;
|
||||||
|
if (byteCount > numBytesToRead) {
|
||||||
|
bytesToRead = (int)numBytesToRead; // Cast okay; long is less than int here.
|
||||||
|
}
|
||||||
|
int numBytesRead = in.read(buffer, byteOffset, bytesToRead);
|
||||||
|
numBytesToRead -= numBytesRead;
|
||||||
|
return numBytesRead;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package org.apache.cordova.file;
|
||||||
|
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
public class InvalidModificationException extends Exception {
|
||||||
|
|
||||||
|
public InvalidModificationException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,510 @@
|
|||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
package org.apache.cordova.file;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.RandomAccessFile;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
|
import org.apache.cordova.CordovaResourceApi;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.util.Base64;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
|
||||||
|
public class LocalFilesystem extends Filesystem {
|
||||||
|
private final Context context;
|
||||||
|
|
||||||
|
public LocalFilesystem(String name, Context context, CordovaResourceApi resourceApi, File fsRoot) {
|
||||||
|
super(Uri.fromFile(fsRoot).buildUpon().appendEncodedPath("").build(), name, resourceApi);
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String filesystemPathForFullPath(String fullPath) {
|
||||||
|
return new File(rootUri.getPath(), fullPath).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String filesystemPathForURL(LocalFilesystemURL url) {
|
||||||
|
return filesystemPathForFullPath(url.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String fullPathForFilesystemPath(String absolutePath) {
|
||||||
|
if (absolutePath != null && absolutePath.startsWith(rootUri.getPath())) {
|
||||||
|
return absolutePath.substring(rootUri.getPath().length() - 1);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri toNativeUri(LocalFilesystemURL inputURL) {
|
||||||
|
return nativeUriForFullPath(inputURL.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LocalFilesystemURL toLocalUri(Uri inputURL) {
|
||||||
|
if (!"file".equals(inputURL.getScheme())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
File f = new File(inputURL.getPath());
|
||||||
|
// Removes and duplicate /s (e.g. file:///a//b/c)
|
||||||
|
Uri resolvedUri = Uri.fromFile(f);
|
||||||
|
String rootUriNoTrailingSlash = rootUri.getEncodedPath();
|
||||||
|
rootUriNoTrailingSlash = rootUriNoTrailingSlash.substring(0, rootUriNoTrailingSlash.length() - 1);
|
||||||
|
if (!resolvedUri.getEncodedPath().startsWith(rootUriNoTrailingSlash)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String subPath = resolvedUri.getEncodedPath().substring(rootUriNoTrailingSlash.length());
|
||||||
|
// Strip leading slash
|
||||||
|
if (!subPath.isEmpty()) {
|
||||||
|
subPath = subPath.substring(1);
|
||||||
|
}
|
||||||
|
Uri.Builder b = new Uri.Builder()
|
||||||
|
.scheme(LocalFilesystemURL.FILESYSTEM_PROTOCOL)
|
||||||
|
.authority("localhost")
|
||||||
|
.path(name);
|
||||||
|
if (!subPath.isEmpty()) {
|
||||||
|
b.appendEncodedPath(subPath);
|
||||||
|
}
|
||||||
|
if (f.isDirectory()) {
|
||||||
|
// Add trailing / for directories.
|
||||||
|
b.appendEncodedPath("");
|
||||||
|
}
|
||||||
|
return LocalFilesystemURL.parse(b.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LocalFilesystemURL URLforFilesystemPath(String path) {
|
||||||
|
return localUrlforFullPath(fullPathForFilesystemPath(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject getFileForLocalURL(LocalFilesystemURL inputURL,
|
||||||
|
String path, JSONObject options, boolean directory) throws FileExistsException, IOException, TypeMismatchException, EncodingException, JSONException {
|
||||||
|
boolean create = false;
|
||||||
|
boolean exclusive = false;
|
||||||
|
|
||||||
|
if (options != null) {
|
||||||
|
create = options.optBoolean("create");
|
||||||
|
if (create) {
|
||||||
|
exclusive = options.optBoolean("exclusive");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for a ":" character in the file to line up with BB and iOS
|
||||||
|
if (path.contains(":")) {
|
||||||
|
throw new EncodingException("This path has an invalid \":\" in it.");
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalFilesystemURL requestedURL;
|
||||||
|
|
||||||
|
// Check whether the supplied path is absolute or relative
|
||||||
|
if (directory && !path.endsWith("/")) {
|
||||||
|
path += "/";
|
||||||
|
}
|
||||||
|
if (path.startsWith("/")) {
|
||||||
|
requestedURL = localUrlforFullPath(normalizePath(path));
|
||||||
|
} else {
|
||||||
|
requestedURL = localUrlforFullPath(normalizePath(inputURL.path + "/" + path));
|
||||||
|
}
|
||||||
|
|
||||||
|
File fp = new File(this.filesystemPathForURL(requestedURL));
|
||||||
|
|
||||||
|
if (create) {
|
||||||
|
if (exclusive && fp.exists()) {
|
||||||
|
throw new FileExistsException("create/exclusive fails");
|
||||||
|
}
|
||||||
|
if (directory) {
|
||||||
|
fp.mkdir();
|
||||||
|
} else {
|
||||||
|
fp.createNewFile();
|
||||||
|
}
|
||||||
|
if (!fp.exists()) {
|
||||||
|
throw new FileExistsException("create fails");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!fp.exists()) {
|
||||||
|
throw new FileNotFoundException("path does not exist");
|
||||||
|
}
|
||||||
|
if (directory) {
|
||||||
|
if (fp.isFile()) {
|
||||||
|
throw new TypeMismatchException("path doesn't exist or is file");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (fp.isDirectory()) {
|
||||||
|
throw new TypeMismatchException("path doesn't exist or is directory");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the directory
|
||||||
|
return makeEntryForURL(requestedURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean removeFileAtLocalURL(LocalFilesystemURL inputURL) throws InvalidModificationException {
|
||||||
|
|
||||||
|
File fp = new File(filesystemPathForURL(inputURL));
|
||||||
|
|
||||||
|
// You can't delete a directory that is not empty
|
||||||
|
if (fp.isDirectory() && fp.list().length > 0) {
|
||||||
|
throw new InvalidModificationException("You can't delete a directory that is not empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return fp.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean exists(LocalFilesystemURL inputURL) {
|
||||||
|
File fp = new File(filesystemPathForURL(inputURL));
|
||||||
|
return fp.exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getFreeSpaceInBytes() {
|
||||||
|
return DirectoryManager.getFreeSpaceInBytes(rootUri.getPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean recursiveRemoveFileAtLocalURL(LocalFilesystemURL inputURL) throws FileExistsException {
|
||||||
|
File directory = new File(filesystemPathForURL(inputURL));
|
||||||
|
return removeDirRecursively(directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean removeDirRecursively(File directory) throws FileExistsException {
|
||||||
|
if (directory.isDirectory()) {
|
||||||
|
for (File file : directory.listFiles()) {
|
||||||
|
removeDirRecursively(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!directory.delete()) {
|
||||||
|
throw new FileExistsException("could not delete: " + directory.getName());
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LocalFilesystemURL[] listChildren(LocalFilesystemURL inputURL) throws FileNotFoundException {
|
||||||
|
File fp = new File(filesystemPathForURL(inputURL));
|
||||||
|
|
||||||
|
if (!fp.exists()) {
|
||||||
|
// The directory we are listing doesn't exist so we should fail.
|
||||||
|
throw new FileNotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
File[] files = fp.listFiles();
|
||||||
|
if (files == null) {
|
||||||
|
// inputURL is a directory
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
LocalFilesystemURL[] entries = new LocalFilesystemURL[files.length];
|
||||||
|
for (int i = 0; i < files.length; i++) {
|
||||||
|
entries[i] = URLforFilesystemPath(files[i].getPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject getFileMetadataForLocalURL(LocalFilesystemURL inputURL) throws FileNotFoundException {
|
||||||
|
File file = new File(filesystemPathForURL(inputURL));
|
||||||
|
|
||||||
|
if (!file.exists()) {
|
||||||
|
throw new FileNotFoundException("File at " + inputURL.uri + " does not exist.");
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject metadata = new JSONObject();
|
||||||
|
try {
|
||||||
|
// Ensure that directories report a size of 0
|
||||||
|
metadata.put("size", file.isDirectory() ? 0 : file.length());
|
||||||
|
metadata.put("type", resourceApi.getMimeType(Uri.fromFile(file)));
|
||||||
|
metadata.put("name", file.getName());
|
||||||
|
metadata.put("fullPath", inputURL.path);
|
||||||
|
metadata.put("lastModifiedDate", file.lastModified());
|
||||||
|
} catch (JSONException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copyFile(Filesystem srcFs, LocalFilesystemURL srcURL, File destFile, boolean move) throws IOException, InvalidModificationException, NoModificationAllowedException {
|
||||||
|
if (move) {
|
||||||
|
String realSrcPath = srcFs.filesystemPathForURL(srcURL);
|
||||||
|
if (realSrcPath != null) {
|
||||||
|
File srcFile = new File(realSrcPath);
|
||||||
|
if (srcFile.renameTo(destFile)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Trying to rename the file failed. Possibly because we moved across file system on the device.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CordovaResourceApi.OpenForReadResult offr = resourceApi.openForRead(srcFs.toNativeUri(srcURL));
|
||||||
|
copyResource(offr, new FileOutputStream(destFile));
|
||||||
|
|
||||||
|
if (move) {
|
||||||
|
srcFs.removeFileAtLocalURL(srcURL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copyDirectory(Filesystem srcFs, LocalFilesystemURL srcURL, File dstDir, boolean move) throws IOException, NoModificationAllowedException, InvalidModificationException, FileExistsException {
|
||||||
|
if (move) {
|
||||||
|
String realSrcPath = srcFs.filesystemPathForURL(srcURL);
|
||||||
|
if (realSrcPath != null) {
|
||||||
|
File srcDir = new File(realSrcPath);
|
||||||
|
// If the destination directory already exists and is empty then delete it. This is according to spec.
|
||||||
|
if (dstDir.exists()) {
|
||||||
|
if (dstDir.list().length > 0) {
|
||||||
|
throw new InvalidModificationException("directory is not empty");
|
||||||
|
}
|
||||||
|
dstDir.delete();
|
||||||
|
}
|
||||||
|
// Try to rename the directory
|
||||||
|
if (srcDir.renameTo(dstDir)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Trying to rename the file failed. Possibly because we moved across file system on the device.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dstDir.exists()) {
|
||||||
|
if (dstDir.list().length > 0) {
|
||||||
|
throw new InvalidModificationException("directory is not empty");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!dstDir.mkdir()) {
|
||||||
|
// If we can't create the directory then fail
|
||||||
|
throw new NoModificationAllowedException("Couldn't create the destination directory");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalFilesystemURL[] children = srcFs.listChildren(srcURL);
|
||||||
|
for (LocalFilesystemURL childLocalUrl : children) {
|
||||||
|
File target = new File(dstDir, new File(childLocalUrl.path).getName());
|
||||||
|
if (childLocalUrl.isDirectory) {
|
||||||
|
copyDirectory(srcFs, childLocalUrl, target, false);
|
||||||
|
} else {
|
||||||
|
copyFile(srcFs, childLocalUrl, target, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (move) {
|
||||||
|
srcFs.recursiveRemoveFileAtLocalURL(srcURL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSONObject copyFileToURL(LocalFilesystemURL destURL, String newName,
|
||||||
|
Filesystem srcFs, LocalFilesystemURL srcURL, boolean move) throws IOException, InvalidModificationException, JSONException, NoModificationAllowedException, FileExistsException {
|
||||||
|
|
||||||
|
// Check to see if the destination directory exists
|
||||||
|
String newParent = this.filesystemPathForURL(destURL);
|
||||||
|
File destinationDir = new File(newParent);
|
||||||
|
if (!destinationDir.exists()) {
|
||||||
|
// The destination does not exist so we should fail.
|
||||||
|
throw new FileNotFoundException("The source does not exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Figure out where we should be copying to
|
||||||
|
final LocalFilesystemURL destinationURL = makeDestinationURL(newName, srcURL, destURL, srcURL.isDirectory);
|
||||||
|
|
||||||
|
Uri dstNativeUri = toNativeUri(destinationURL);
|
||||||
|
Uri srcNativeUri = srcFs.toNativeUri(srcURL);
|
||||||
|
// Check to see if source and destination are the same file
|
||||||
|
if (dstNativeUri.equals(srcNativeUri)) {
|
||||||
|
throw new InvalidModificationException("Can't copy onto itself");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (move && !srcFs.canRemoveFileAtLocalURL(srcURL)) {
|
||||||
|
throw new InvalidModificationException("Source URL is read-only (cannot move)");
|
||||||
|
}
|
||||||
|
|
||||||
|
File destFile = new File(dstNativeUri.getPath());
|
||||||
|
if (destFile.exists()) {
|
||||||
|
if (!srcURL.isDirectory && destFile.isDirectory()) {
|
||||||
|
throw new InvalidModificationException("Can't copy/move a file to an existing directory");
|
||||||
|
} else if (srcURL.isDirectory && destFile.isFile()) {
|
||||||
|
throw new InvalidModificationException("Can't copy/move a directory to an existing file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (srcURL.isDirectory) {
|
||||||
|
// E.g. Copy /sdcard/myDir to /sdcard/myDir/backup
|
||||||
|
if (dstNativeUri.toString().startsWith(srcNativeUri.toString() + '/')) {
|
||||||
|
throw new InvalidModificationException("Can't copy directory into itself");
|
||||||
|
}
|
||||||
|
copyDirectory(srcFs, srcURL, destFile, move);
|
||||||
|
} else {
|
||||||
|
copyFile(srcFs, srcURL, destFile, move);
|
||||||
|
}
|
||||||
|
return makeEntryForURL(destinationURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long writeToFileAtURL(LocalFilesystemURL inputURL, String data,
|
||||||
|
int offset, boolean isBinary) throws IOException, NoModificationAllowedException {
|
||||||
|
|
||||||
|
boolean append = false;
|
||||||
|
if (offset > 0) {
|
||||||
|
this.truncateFileAtURL(inputURL, offset);
|
||||||
|
append = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] rawData;
|
||||||
|
if (isBinary) {
|
||||||
|
rawData = Base64.decode(data, Base64.DEFAULT);
|
||||||
|
} else {
|
||||||
|
rawData = data.getBytes();
|
||||||
|
}
|
||||||
|
ByteArrayInputStream in = new ByteArrayInputStream(rawData);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
byte buff[] = new byte[rawData.length];
|
||||||
|
String absolutePath = filesystemPathForURL(inputURL);
|
||||||
|
FileOutputStream out = new FileOutputStream(absolutePath, append);
|
||||||
|
try {
|
||||||
|
in.read(buff, 0, buff.length);
|
||||||
|
out.write(buff, 0, rawData.length);
|
||||||
|
out.flush();
|
||||||
|
} finally {
|
||||||
|
// Always close the output
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
if (isPublicDirectory(absolutePath)) {
|
||||||
|
broadcastNewFile(Uri.fromFile(new File(absolutePath)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (NullPointerException e)
|
||||||
|
{
|
||||||
|
// This is a bug in the Android implementation of the Java Stack
|
||||||
|
NoModificationAllowedException realException = new NoModificationAllowedException(inputURL.toString());
|
||||||
|
throw realException;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rawData.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isPublicDirectory(String absolutePath) {
|
||||||
|
// TODO: should expose a way to scan app's private files (maybe via a flag).
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
// Lollipop has a bug where SD cards are null.
|
||||||
|
for (File f : context.getExternalMediaDirs()) {
|
||||||
|
if(f != null && absolutePath.startsWith(f.getAbsolutePath())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String extPath = Environment.getExternalStorageDirectory().getAbsolutePath();
|
||||||
|
return absolutePath.startsWith(extPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send broadcast of new file so files appear over MTP
|
||||||
|
*/
|
||||||
|
private void broadcastNewFile(Uri nativeUri) {
|
||||||
|
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, nativeUri);
|
||||||
|
context.sendBroadcast(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long truncateFileAtURL(LocalFilesystemURL inputURL, long size) throws IOException {
|
||||||
|
File file = new File(filesystemPathForURL(inputURL));
|
||||||
|
|
||||||
|
if (!file.exists()) {
|
||||||
|
throw new FileNotFoundException("File at " + inputURL.uri + " does not exist.");
|
||||||
|
}
|
||||||
|
|
||||||
|
RandomAccessFile raf = new RandomAccessFile(filesystemPathForURL(inputURL), "rw");
|
||||||
|
try {
|
||||||
|
if (raf.length() >= size) {
|
||||||
|
FileChannel channel = raf.getChannel();
|
||||||
|
channel.truncate(size);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return raf.length();
|
||||||
|
} finally {
|
||||||
|
raf.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canRemoveFileAtLocalURL(LocalFilesystemURL inputURL) {
|
||||||
|
String path = filesystemPathForURL(inputURL);
|
||||||
|
File file = new File(path);
|
||||||
|
return file.exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a copy & paste from CordovaResource API that is required since CordovaResourceApi
|
||||||
|
// has a bug pre-4.0.0.
|
||||||
|
// TODO: Once cordova-android@4.0.0 is released, delete this copy and make the plugin depend on
|
||||||
|
// 4.0.0 with an engine tag.
|
||||||
|
private static void copyResource(CordovaResourceApi.OpenForReadResult input, OutputStream outputStream) throws IOException {
|
||||||
|
try {
|
||||||
|
InputStream inputStream = input.inputStream;
|
||||||
|
if (inputStream instanceof FileInputStream && outputStream instanceof FileOutputStream) {
|
||||||
|
FileChannel inChannel = ((FileInputStream)input.inputStream).getChannel();
|
||||||
|
FileChannel outChannel = ((FileOutputStream)outputStream).getChannel();
|
||||||
|
long offset = 0;
|
||||||
|
long length = input.length;
|
||||||
|
if (input.assetFd != null) {
|
||||||
|
offset = input.assetFd.getStartOffset();
|
||||||
|
}
|
||||||
|
// transferFrom()'s 2nd arg is a relative position. Need to set the absolute
|
||||||
|
// position first.
|
||||||
|
inChannel.position(offset);
|
||||||
|
outChannel.transferFrom(inChannel, 0, length);
|
||||||
|
} else {
|
||||||
|
final int BUFFER_SIZE = 8192;
|
||||||
|
byte[] buffer = new byte[BUFFER_SIZE];
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
int bytesRead = inputStream.read(buffer, 0, BUFFER_SIZE);
|
||||||
|
|
||||||
|
if (bytesRead <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
outputStream.write(buffer, 0, bytesRead);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
input.inputStream.close();
|
||||||
|
if (outputStream != null) {
|
||||||
|
outputStream.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
package org.apache.cordova.file;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
public class LocalFilesystemURL {
|
||||||
|
|
||||||
|
public static final String FILESYSTEM_PROTOCOL = "cdvfile";
|
||||||
|
|
||||||
|
public final Uri uri;
|
||||||
|
public final String fsName;
|
||||||
|
public final String path;
|
||||||
|
public final boolean isDirectory;
|
||||||
|
|
||||||
|
private LocalFilesystemURL(Uri uri, String fsName, String fsPath, boolean isDirectory) {
|
||||||
|
this.uri = uri;
|
||||||
|
this.fsName = fsName;
|
||||||
|
this.path = fsPath;
|
||||||
|
this.isDirectory = isDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LocalFilesystemURL parse(Uri uri) {
|
||||||
|
if (!FILESYSTEM_PROTOCOL.equals(uri.getScheme())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String path = uri.getPath();
|
||||||
|
if (path.length() < 1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int firstSlashIdx = path.indexOf('/', 1);
|
||||||
|
if (firstSlashIdx < 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String fsName = path.substring(1, firstSlashIdx);
|
||||||
|
path = path.substring(firstSlashIdx);
|
||||||
|
boolean isDirectory = path.charAt(path.length() - 1) == '/';
|
||||||
|
return new LocalFilesystemURL(uri, fsName, path, isDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LocalFilesystemURL parse(String uri) {
|
||||||
|
return parse(Uri.parse(uri));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return uri.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.cordova.file;
|
||||||
|
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
public class NoModificationAllowedException extends Exception {
|
||||||
|
|
||||||
|
public NoModificationAllowedException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
package org.apache.cordova.file;
|
||||||
|
|
||||||
|
import android.util.SparseArray;
|
||||||
|
|
||||||
|
import org.apache.cordova.CallbackContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds pending runtime permission requests
|
||||||
|
*/
|
||||||
|
class PendingRequests {
|
||||||
|
private int currentReqId = 0;
|
||||||
|
private SparseArray<Request> requests = new SparseArray<Request>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a request and adds it to the array of pending requests. Each created request gets a
|
||||||
|
* unique result code for use with requestPermission()
|
||||||
|
* @param rawArgs The raw arguments passed to the plugin
|
||||||
|
* @param action The action this request corresponds to (get file, etc.)
|
||||||
|
* @param callbackContext The CallbackContext for this plugin call
|
||||||
|
* @return The request code that can be used to retrieve the Request object
|
||||||
|
*/
|
||||||
|
public synchronized int createRequest(String rawArgs, int action, CallbackContext callbackContext) {
|
||||||
|
Request req = new Request(rawArgs, action, callbackContext);
|
||||||
|
requests.put(req.requestCode, req);
|
||||||
|
return req.requestCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the request corresponding to this request code and removes it from the pending requests
|
||||||
|
* @param requestCode The request code for the desired request
|
||||||
|
* @return The request corresponding to the given request code or null if such a
|
||||||
|
* request is not found
|
||||||
|
*/
|
||||||
|
public synchronized Request getAndRemove(int requestCode) {
|
||||||
|
Request result = requests.get(requestCode);
|
||||||
|
requests.remove(requestCode);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds the options and CallbackContext for a call made to the plugin.
|
||||||
|
*/
|
||||||
|
public class Request {
|
||||||
|
|
||||||
|
// Unique int used to identify this request in any Android permission callback
|
||||||
|
private int requestCode;
|
||||||
|
|
||||||
|
// Action to be performed after permission request result
|
||||||
|
private int action;
|
||||||
|
|
||||||
|
// Raw arguments passed to plugin
|
||||||
|
private String rawArgs;
|
||||||
|
|
||||||
|
// The callback context for this plugin request
|
||||||
|
private CallbackContext callbackContext;
|
||||||
|
|
||||||
|
private Request(String rawArgs, int action, CallbackContext callbackContext) {
|
||||||
|
this.rawArgs = rawArgs;
|
||||||
|
this.action = action;
|
||||||
|
this.callbackContext = callbackContext;
|
||||||
|
this.requestCode = currentReqId ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAction() {
|
||||||
|
return this.action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRawArgs() {
|
||||||
|
return rawArgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CallbackContext getCallbackContext() {
|
||||||
|
return callbackContext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package org.apache.cordova.file;
|
||||||
|
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
public class TypeMismatchException extends Exception {
|
||||||
|
|
||||||
|
public TypeMismatchException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "CDVFile.h"
|
||||||
|
|
||||||
|
extern NSString* const kCDVAssetsLibraryPrefix;
|
||||||
|
extern NSString* const kCDVAssetsLibraryScheme;
|
||||||
|
|
||||||
|
@interface CDVAssetLibraryFilesystem : NSObject<CDVFileSystem> {
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) initWithName:(NSString *)name;
|
||||||
|
|
||||||
|
@end
|
@ -0,0 +1,253 @@
|
|||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "CDVFile.h"
|
||||||
|
#import "CDVAssetLibraryFilesystem.h"
|
||||||
|
#import <Cordova/CDV.h>
|
||||||
|
#import <AssetsLibrary/ALAsset.h>
|
||||||
|
#import <AssetsLibrary/ALAssetRepresentation.h>
|
||||||
|
#import <AssetsLibrary/ALAssetsLibrary.h>
|
||||||
|
#import <MobileCoreServices/MobileCoreServices.h>
|
||||||
|
|
||||||
|
NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
|
||||||
|
NSString* const kCDVAssetsLibraryScheme = @"assets-library";
|
||||||
|
|
||||||
|
@implementation CDVAssetLibraryFilesystem
|
||||||
|
@synthesize name=_name, urlTransformer;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
The CDVAssetLibraryFilesystem works with resources which are identified
|
||||||
|
by iOS as
|
||||||
|
asset-library://<path>
|
||||||
|
and represents them internally as URLs of the form
|
||||||
|
cdvfile://localhost/assets-library/<path>
|
||||||
|
*/
|
||||||
|
|
||||||
|
- (NSURL *)assetLibraryURLForLocalURL:(CDVFilesystemURL *)url
|
||||||
|
{
|
||||||
|
if ([url.url.scheme isEqualToString:kCDVFilesystemURLPrefix]) {
|
||||||
|
NSString *path = [[url.url absoluteString] substringFromIndex:[@"cdvfile://localhost/assets-library" length]];
|
||||||
|
return [NSURL URLWithString:[NSString stringWithFormat:@"assets-library:/%@", path]];
|
||||||
|
}
|
||||||
|
return url.url;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CDVPluginResult *)entryForLocalURI:(CDVFilesystemURL *)url
|
||||||
|
{
|
||||||
|
NSDictionary* entry = [self makeEntryForLocalURL:url];
|
||||||
|
return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:entry];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSDictionary *)makeEntryForLocalURL:(CDVFilesystemURL *)url {
|
||||||
|
return [self makeEntryForPath:url.fullPath isDirectory:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSDictionary*)makeEntryForPath:(NSString*)fullPath isDirectory:(BOOL)isDir
|
||||||
|
{
|
||||||
|
NSMutableDictionary* dirEntry = [NSMutableDictionary dictionaryWithCapacity:5];
|
||||||
|
NSString* lastPart = [fullPath lastPathComponent];
|
||||||
|
if (isDir && ![fullPath hasSuffix:@"/"]) {
|
||||||
|
fullPath = [fullPath stringByAppendingString:@"/"];
|
||||||
|
}
|
||||||
|
[dirEntry setObject:[NSNumber numberWithBool:!isDir] forKey:@"isFile"];
|
||||||
|
[dirEntry setObject:[NSNumber numberWithBool:isDir] forKey:@"isDirectory"];
|
||||||
|
[dirEntry setObject:fullPath forKey:@"fullPath"];
|
||||||
|
[dirEntry setObject:lastPart forKey:@"name"];
|
||||||
|
[dirEntry setObject:self.name forKey: @"filesystemName"];
|
||||||
|
|
||||||
|
NSURL* nativeURL = [NSURL URLWithString:[NSString stringWithFormat:@"assets-library:/%@",fullPath]];
|
||||||
|
if (self.urlTransformer) {
|
||||||
|
nativeURL = self.urlTransformer(nativeURL);
|
||||||
|
}
|
||||||
|
dirEntry[@"nativeURL"] = [nativeURL absoluteString];
|
||||||
|
|
||||||
|
return dirEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* helper function to get the mimeType from the file extension
|
||||||
|
* IN:
|
||||||
|
* NSString* fullPath - filename (may include path)
|
||||||
|
* OUT:
|
||||||
|
* NSString* the mime type as type/subtype. nil if not able to determine
|
||||||
|
*/
|
||||||
|
+ (NSString*)getMimeTypeFromPath:(NSString*)fullPath
|
||||||
|
{
|
||||||
|
NSString* mimeType = nil;
|
||||||
|
|
||||||
|
if (fullPath) {
|
||||||
|
CFStringRef typeId = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)[fullPath pathExtension], NULL);
|
||||||
|
if (typeId) {
|
||||||
|
mimeType = (__bridge_transfer NSString*)UTTypeCopyPreferredTagWithClass(typeId, kUTTagClassMIMEType);
|
||||||
|
if (!mimeType) {
|
||||||
|
// special case for m4a
|
||||||
|
if ([(__bridge NSString*)typeId rangeOfString : @"m4a-audio"].location != NSNotFound) {
|
||||||
|
mimeType = @"audio/mp4";
|
||||||
|
} else if ([[fullPath pathExtension] rangeOfString:@"wav"].location != NSNotFound) {
|
||||||
|
mimeType = @"audio/wav";
|
||||||
|
} else if ([[fullPath pathExtension] rangeOfString:@"css"].location != NSNotFound) {
|
||||||
|
mimeType = @"text/css";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CFRelease(typeId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mimeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithName:(NSString *)name
|
||||||
|
{
|
||||||
|
if (self) {
|
||||||
|
self.name = name;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CDVPluginResult *)getFileForURL:(CDVFilesystemURL *)baseURI requestedPath:(NSString *)requestedPath options:(NSDictionary *)options
|
||||||
|
{
|
||||||
|
// return unsupported result for assets-library URLs
|
||||||
|
return [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"getFile not supported for assets-library URLs."];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CDVPluginResult*)getParentForURL:(CDVFilesystemURL *)localURI
|
||||||
|
{
|
||||||
|
// we don't (yet?) support getting the parent of an asset
|
||||||
|
return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_READABLE_ERR];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CDVPluginResult*)setMetadataForURL:(CDVFilesystemURL *)localURI withObject:(NSDictionary *)options
|
||||||
|
{
|
||||||
|
// setMetadata doesn't make sense for asset library files
|
||||||
|
return [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CDVPluginResult *)removeFileAtURL:(CDVFilesystemURL *)localURI
|
||||||
|
{
|
||||||
|
// return error for assets-library URLs
|
||||||
|
return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:INVALID_MODIFICATION_ERR];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CDVPluginResult *)recursiveRemoveFileAtURL:(CDVFilesystemURL *)localURI
|
||||||
|
{
|
||||||
|
// return error for assets-library URLs
|
||||||
|
return [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"removeRecursively not supported for assets-library URLs."];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CDVPluginResult *)readEntriesAtURL:(CDVFilesystemURL *)localURI
|
||||||
|
{
|
||||||
|
// return unsupported result for assets-library URLs
|
||||||
|
return [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"readEntries not supported for assets-library URLs."];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CDVPluginResult *)truncateFileAtURL:(CDVFilesystemURL *)localURI atPosition:(unsigned long long)pos
|
||||||
|
{
|
||||||
|
// assets-library files can't be truncated
|
||||||
|
return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NO_MODIFICATION_ALLOWED_ERR];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CDVPluginResult *)writeToFileAtURL:(CDVFilesystemURL *)localURL withData:(NSData*)encData append:(BOOL)shouldAppend
|
||||||
|
{
|
||||||
|
// text can't be written into assets-library files
|
||||||
|
return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NO_MODIFICATION_ALLOWED_ERR];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)copyFileToURL:(CDVFilesystemURL *)destURL withName:(NSString *)newName fromFileSystem:(NSObject<CDVFileSystem> *)srcFs atURL:(CDVFilesystemURL *)srcURL copy:(BOOL)bCopy callback:(void (^)(CDVPluginResult *))callback
|
||||||
|
{
|
||||||
|
// Copying to an assets library file is not doable, since we can't write it.
|
||||||
|
CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:INVALID_MODIFICATION_ERR];
|
||||||
|
callback(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)filesystemPathForURL:(CDVFilesystemURL *)url
|
||||||
|
{
|
||||||
|
NSString *path = nil;
|
||||||
|
if ([[url.url scheme] isEqualToString:kCDVAssetsLibraryScheme]) {
|
||||||
|
path = [url.url path];
|
||||||
|
} else {
|
||||||
|
path = url.fullPath;
|
||||||
|
}
|
||||||
|
if ([path hasSuffix:@"/"]) {
|
||||||
|
path = [path substringToIndex:([path length]-1)];
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)readFileAtURL:(CDVFilesystemURL *)localURL start:(NSInteger)start end:(NSInteger)end callback:(void (^)(NSData*, NSString* mimeType, CDVFileError))callback
|
||||||
|
{
|
||||||
|
ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
|
||||||
|
if (asset) {
|
||||||
|
// We have the asset! Get the data and send it off.
|
||||||
|
ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation];
|
||||||
|
NSUInteger size = (end > start) ? (end - start) : [assetRepresentation size];
|
||||||
|
Byte* buffer = (Byte*)malloc(size);
|
||||||
|
NSUInteger bufferSize = [assetRepresentation getBytes:buffer fromOffset:start length:size error:nil];
|
||||||
|
NSData* data = [NSData dataWithBytesNoCopy:buffer length:bufferSize freeWhenDone:YES];
|
||||||
|
NSString* MIMEType = (__bridge_transfer NSString*)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)[assetRepresentation UTI], kUTTagClassMIMEType);
|
||||||
|
|
||||||
|
callback(data, MIMEType, NO_ERROR);
|
||||||
|
} else {
|
||||||
|
callback(nil, nil, NOT_FOUND_ERR);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) {
|
||||||
|
// Retrieving the asset failed for some reason. Send the appropriate error.
|
||||||
|
NSLog(@"Error: %@", error);
|
||||||
|
callback(nil, nil, SECURITY_ERR);
|
||||||
|
};
|
||||||
|
|
||||||
|
ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
|
||||||
|
[assetsLibrary assetForURL:[self assetLibraryURLForLocalURL:localURL] resultBlock:resultBlock failureBlock:failureBlock];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)getFileMetadataForURL:(CDVFilesystemURL *)localURL callback:(void (^)(CDVPluginResult *))callback
|
||||||
|
{
|
||||||
|
// In this case, we need to use an asynchronous method to retrieve the file.
|
||||||
|
// Because of this, we can't just assign to `result` and send it at the end of the method.
|
||||||
|
// Instead, we return after calling the asynchronous method and send `result` in each of the blocks.
|
||||||
|
ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
|
||||||
|
if (asset) {
|
||||||
|
// We have the asset! Populate the dictionary and send it off.
|
||||||
|
NSMutableDictionary* fileInfo = [NSMutableDictionary dictionaryWithCapacity:5];
|
||||||
|
ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation];
|
||||||
|
[fileInfo setObject:[NSNumber numberWithUnsignedLongLong:[assetRepresentation size]] forKey:@"size"];
|
||||||
|
[fileInfo setObject:localURL.fullPath forKey:@"fullPath"];
|
||||||
|
NSString* filename = [assetRepresentation filename];
|
||||||
|
[fileInfo setObject:filename forKey:@"name"];
|
||||||
|
[fileInfo setObject:[CDVAssetLibraryFilesystem getMimeTypeFromPath:filename] forKey:@"type"];
|
||||||
|
NSDate* creationDate = [asset valueForProperty:ALAssetPropertyDate];
|
||||||
|
NSNumber* msDate = [NSNumber numberWithDouble:[creationDate timeIntervalSince1970] * 1000];
|
||||||
|
[fileInfo setObject:msDate forKey:@"lastModifiedDate"];
|
||||||
|
|
||||||
|
callback([CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileInfo]);
|
||||||
|
} else {
|
||||||
|
// We couldn't find the asset. Send the appropriate error.
|
||||||
|
callback([CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) {
|
||||||
|
// Retrieving the asset failed for some reason. Send the appropriate error.
|
||||||
|
callback([CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]]);
|
||||||
|
};
|
||||||
|
|
||||||
|
ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
|
||||||
|
[assetsLibrary assetForURL:[self assetLibraryURLForLocalURL:localURL] resultBlock:resultBlock failureBlock:failureBlock];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
@end
|
157
platforms/ios/Sensortoy/Plugins/cordova-plugin-file/CDVFile.h
Normal file
157
platforms/ios/Sensortoy/Plugins/cordova-plugin-file/CDVFile.h
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <Cordova/CDVPlugin.h>
|
||||||
|
|
||||||
|
NSString* const kCDVAssetsLibraryPrefix;
|
||||||
|
NSString* const kCDVFilesystemURLPrefix;
|
||||||
|
|
||||||
|
enum CDVFileError {
|
||||||
|
NO_ERROR = 0,
|
||||||
|
NOT_FOUND_ERR = 1,
|
||||||
|
SECURITY_ERR = 2,
|
||||||
|
ABORT_ERR = 3,
|
||||||
|
NOT_READABLE_ERR = 4,
|
||||||
|
ENCODING_ERR = 5,
|
||||||
|
NO_MODIFICATION_ALLOWED_ERR = 6,
|
||||||
|
INVALID_STATE_ERR = 7,
|
||||||
|
SYNTAX_ERR = 8,
|
||||||
|
INVALID_MODIFICATION_ERR = 9,
|
||||||
|
QUOTA_EXCEEDED_ERR = 10,
|
||||||
|
TYPE_MISMATCH_ERR = 11,
|
||||||
|
PATH_EXISTS_ERR = 12
|
||||||
|
};
|
||||||
|
typedef int CDVFileError;
|
||||||
|
|
||||||
|
@interface CDVFilesystemURL : NSObject {
|
||||||
|
NSURL *_url;
|
||||||
|
NSString *_fileSystemName;
|
||||||
|
NSString *_fullPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) initWithString:(NSString*)strURL;
|
||||||
|
- (id) initWithURL:(NSURL*)URL;
|
||||||
|
+ (CDVFilesystemURL *)fileSystemURLWithString:(NSString *)strURL;
|
||||||
|
+ (CDVFilesystemURL *)fileSystemURLWithURL:(NSURL *)URL;
|
||||||
|
|
||||||
|
- (NSString *)absoluteURL;
|
||||||
|
|
||||||
|
@property (atomic) NSURL *url;
|
||||||
|
@property (atomic) NSString *fileSystemName;
|
||||||
|
@property (atomic) NSString *fullPath;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface CDVFilesystemURLProtocol : NSURLProtocol
|
||||||
|
@end
|
||||||
|
|
||||||
|
@protocol CDVFileSystem
|
||||||
|
- (CDVPluginResult *)entryForLocalURI:(CDVFilesystemURL *)url;
|
||||||
|
- (CDVPluginResult *)getFileForURL:(CDVFilesystemURL *)baseURI requestedPath:(NSString *)requestedPath options:(NSDictionary *)options;
|
||||||
|
- (CDVPluginResult *)getParentForURL:(CDVFilesystemURL *)localURI;
|
||||||
|
- (CDVPluginResult *)setMetadataForURL:(CDVFilesystemURL *)localURI withObject:(NSDictionary *)options;
|
||||||
|
- (CDVPluginResult *)removeFileAtURL:(CDVFilesystemURL *)localURI;
|
||||||
|
- (CDVPluginResult *)recursiveRemoveFileAtURL:(CDVFilesystemURL *)localURI;
|
||||||
|
- (CDVPluginResult *)readEntriesAtURL:(CDVFilesystemURL *)localURI;
|
||||||
|
- (CDVPluginResult *)truncateFileAtURL:(CDVFilesystemURL *)localURI atPosition:(unsigned long long)pos;
|
||||||
|
- (CDVPluginResult *)writeToFileAtURL:(CDVFilesystemURL *)localURL withData:(NSData*)encData append:(BOOL)shouldAppend;
|
||||||
|
- (void)copyFileToURL:(CDVFilesystemURL *)destURL withName:(NSString *)newName fromFileSystem:(NSObject<CDVFileSystem> *)srcFs atURL:(CDVFilesystemURL *)srcURL copy:(BOOL)bCopy callback:(void (^)(CDVPluginResult *))callback;
|
||||||
|
- (void)readFileAtURL:(CDVFilesystemURL *)localURL start:(NSInteger)start end:(NSInteger)end callback:(void (^)(NSData*, NSString* mimeType, CDVFileError))callback;
|
||||||
|
- (void)getFileMetadataForURL:(CDVFilesystemURL *)localURL callback:(void (^)(CDVPluginResult *))callback;
|
||||||
|
|
||||||
|
- (NSDictionary *)makeEntryForLocalURL:(CDVFilesystemURL *)url;
|
||||||
|
- (NSDictionary*)makeEntryForPath:(NSString*)fullPath isDirectory:(BOOL)isDir;
|
||||||
|
|
||||||
|
@property (nonatomic,strong) NSString *name;
|
||||||
|
@property (nonatomic, copy) NSURL*(^urlTransformer)(NSURL*);
|
||||||
|
|
||||||
|
@optional
|
||||||
|
- (NSString *)filesystemPathForURL:(CDVFilesystemURL *)localURI;
|
||||||
|
- (CDVFilesystemURL *)URLforFilesystemPath:(NSString *)path;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface CDVFile : CDVPlugin {
|
||||||
|
NSString* rootDocsPath;
|
||||||
|
NSString* appDocsPath;
|
||||||
|
NSString* appLibraryPath;
|
||||||
|
NSString* appTempPath;
|
||||||
|
|
||||||
|
NSMutableArray* fileSystems_;
|
||||||
|
BOOL userHasAllowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSNumber*)checkFreeDiskSpace:(NSString*)appPath;
|
||||||
|
- (NSDictionary*)makeEntryForPath:(NSString*)fullPath fileSystemName:(NSString *)fsName isDirectory:(BOOL)isDir;
|
||||||
|
- (NSDictionary *)makeEntryForURL:(NSURL *)URL;
|
||||||
|
- (CDVFilesystemURL *)fileSystemURLforLocalPath:(NSString *)localPath;
|
||||||
|
|
||||||
|
- (NSObject<CDVFileSystem> *)filesystemForURL:(CDVFilesystemURL *)localURL;
|
||||||
|
|
||||||
|
/* Native Registration API */
|
||||||
|
- (void)registerFilesystem:(NSObject<CDVFileSystem> *)fs;
|
||||||
|
- (NSObject<CDVFileSystem> *)fileSystemByName:(NSString *)fsName;
|
||||||
|
|
||||||
|
/* Exec API */
|
||||||
|
- (void)requestFileSystem:(CDVInvokedUrlCommand*)command;
|
||||||
|
- (void)resolveLocalFileSystemURI:(CDVInvokedUrlCommand*)command;
|
||||||
|
- (void)getDirectory:(CDVInvokedUrlCommand*)command;
|
||||||
|
- (void)getFile:(CDVInvokedUrlCommand*)command;
|
||||||
|
- (void)getParent:(CDVInvokedUrlCommand*)command;
|
||||||
|
- (void)removeRecursively:(CDVInvokedUrlCommand*)command;
|
||||||
|
- (void)remove:(CDVInvokedUrlCommand*)command;
|
||||||
|
- (void)copyTo:(CDVInvokedUrlCommand*)command;
|
||||||
|
- (void)moveTo:(CDVInvokedUrlCommand*)command;
|
||||||
|
- (void)getFileMetadata:(CDVInvokedUrlCommand*)command;
|
||||||
|
- (void)readEntries:(CDVInvokedUrlCommand*)command;
|
||||||
|
- (void)readAsText:(CDVInvokedUrlCommand*)command;
|
||||||
|
- (void)readAsDataURL:(CDVInvokedUrlCommand*)command;
|
||||||
|
- (void)readAsArrayBuffer:(CDVInvokedUrlCommand*)command;
|
||||||
|
- (void)write:(CDVInvokedUrlCommand*)command;
|
||||||
|
- (void)testFileExists:(CDVInvokedUrlCommand*)command;
|
||||||
|
- (void)testDirectoryExists:(CDVInvokedUrlCommand*)command;
|
||||||
|
- (void)getFreeDiskSpace:(CDVInvokedUrlCommand*)command;
|
||||||
|
- (void)truncate:(CDVInvokedUrlCommand*)command;
|
||||||
|
- (void)doCopyMove:(CDVInvokedUrlCommand*)command isCopy:(BOOL)bCopy;
|
||||||
|
|
||||||
|
/* Compatibilty with older File API */
|
||||||
|
- (NSString*)getMimeTypeFromPath:(NSString*)fullPath;
|
||||||
|
- (NSDictionary *)getDirectoryEntry:(NSString *)target isDirectory:(BOOL)bDirRequest;
|
||||||
|
|
||||||
|
/* Conversion between filesystem paths and URLs */
|
||||||
|
- (NSString *)filesystemPathForURL:(CDVFilesystemURL *)URL;
|
||||||
|
|
||||||
|
/* Internal methods for testing */
|
||||||
|
- (void)_getLocalFilesystemPath:(CDVInvokedUrlCommand*)command;
|
||||||
|
|
||||||
|
@property (nonatomic, strong) NSString* rootDocsPath;
|
||||||
|
@property (nonatomic, strong) NSString* appDocsPath;
|
||||||
|
@property (nonatomic, strong) NSString* appLibraryPath;
|
||||||
|
@property (nonatomic, strong) NSString* appTempPath;
|
||||||
|
@property (nonatomic, strong) NSString* persistentPath;
|
||||||
|
@property (nonatomic, strong) NSString* temporaryPath;
|
||||||
|
@property (nonatomic, strong) NSMutableArray* fileSystems;
|
||||||
|
|
||||||
|
@property BOOL userHasAllowed;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#define kW3FileTemporary @"temporary"
|
||||||
|
#define kW3FilePersistent @"persistent"
|
1117
platforms/ios/Sensortoy/Plugins/cordova-plugin-file/CDVFile.m
Normal file
1117
platforms/ios/Sensortoy/Plugins/cordova-plugin-file/CDVFile.m
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "CDVFile.h"
|
||||||
|
|
||||||
|
@interface CDVLocalFilesystem : NSObject<CDVFileSystem> {
|
||||||
|
NSString *_name;
|
||||||
|
NSString *_fsRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) initWithName:(NSString *)name root:(NSString *)fsRoot;
|
||||||
|
+ (NSString*)getMimeTypeFromPath:(NSString*)fullPath;
|
||||||
|
|
||||||
|
@property (nonatomic,strong) NSString *fsRoot;
|
||||||
|
|
||||||
|
@end
|
@ -0,0 +1,734 @@
|
|||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "CDVFile.h"
|
||||||
|
#import "CDVLocalFilesystem.h"
|
||||||
|
#import <Cordova/CDV.h>
|
||||||
|
#import <MobileCoreServices/MobileCoreServices.h>
|
||||||
|
#import <sys/xattr.h>
|
||||||
|
|
||||||
|
@implementation CDVLocalFilesystem
|
||||||
|
@synthesize name=_name, fsRoot=_fsRoot, urlTransformer;
|
||||||
|
|
||||||
|
- (id) initWithName:(NSString *)name root:(NSString *)fsRoot
|
||||||
|
{
|
||||||
|
if (self) {
|
||||||
|
self.name = name;
|
||||||
|
self.fsRoot = fsRoot;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IN
|
||||||
|
* NSString localURI
|
||||||
|
* OUT
|
||||||
|
* CDVPluginResult result containing a file or directoryEntry for the localURI, or an error if the
|
||||||
|
* URI represents a non-existent path, or is unrecognized or otherwise malformed.
|
||||||
|
*/
|
||||||
|
- (CDVPluginResult *)entryForLocalURI:(CDVFilesystemURL *)url
|
||||||
|
{
|
||||||
|
CDVPluginResult* result = nil;
|
||||||
|
NSDictionary* entry = [self makeEntryForLocalURL:url];
|
||||||
|
if (entry) {
|
||||||
|
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:entry];
|
||||||
|
} else {
|
||||||
|
// return NOT_FOUND_ERR
|
||||||
|
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
- (NSDictionary *)makeEntryForLocalURL:(CDVFilesystemURL *)url {
|
||||||
|
NSString *path = [self filesystemPathForURL:url];
|
||||||
|
NSFileManager* fileMgr = [[NSFileManager alloc] init];
|
||||||
|
BOOL isDir = NO;
|
||||||
|
// see if exists and is file or dir
|
||||||
|
BOOL bExists = [fileMgr fileExistsAtPath:path isDirectory:&isDir];
|
||||||
|
if (bExists) {
|
||||||
|
return [self makeEntryForPath:url.fullPath isDirectory:isDir];
|
||||||
|
} else {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- (NSDictionary*)makeEntryForPath:(NSString*)fullPath isDirectory:(BOOL)isDir
|
||||||
|
{
|
||||||
|
NSMutableDictionary* dirEntry = [NSMutableDictionary dictionaryWithCapacity:5];
|
||||||
|
NSString* lastPart = [[self stripQueryParametersFromPath:fullPath] lastPathComponent];
|
||||||
|
if (isDir && ![fullPath hasSuffix:@"/"]) {
|
||||||
|
fullPath = [fullPath stringByAppendingString:@"/"];
|
||||||
|
}
|
||||||
|
[dirEntry setObject:[NSNumber numberWithBool:!isDir] forKey:@"isFile"];
|
||||||
|
[dirEntry setObject:[NSNumber numberWithBool:isDir] forKey:@"isDirectory"];
|
||||||
|
[dirEntry setObject:fullPath forKey:@"fullPath"];
|
||||||
|
[dirEntry setObject:lastPart forKey:@"name"];
|
||||||
|
[dirEntry setObject:self.name forKey: @"filesystemName"];
|
||||||
|
|
||||||
|
NSURL* nativeURL = [NSURL fileURLWithPath:[self filesystemPathForFullPath:fullPath]];
|
||||||
|
if (self.urlTransformer) {
|
||||||
|
nativeURL = self.urlTransformer(nativeURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
dirEntry[@"nativeURL"] = [nativeURL absoluteString];
|
||||||
|
|
||||||
|
return dirEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)stripQueryParametersFromPath:(NSString *)fullPath
|
||||||
|
{
|
||||||
|
NSRange questionMark = [fullPath rangeOfString:@"?"];
|
||||||
|
if (questionMark.location != NSNotFound) {
|
||||||
|
return [fullPath substringWithRange:NSMakeRange(0,questionMark.location)];
|
||||||
|
}
|
||||||
|
return fullPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)filesystemPathForFullPath:(NSString *)fullPath
|
||||||
|
{
|
||||||
|
NSString *path = nil;
|
||||||
|
NSString *strippedFullPath = [self stripQueryParametersFromPath:fullPath];
|
||||||
|
path = [NSString stringWithFormat:@"%@%@", self.fsRoot, strippedFullPath];
|
||||||
|
if ([path length] > 1 && [path hasSuffix:@"/"]) {
|
||||||
|
path = [path substringToIndex:([path length]-1)];
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* IN
|
||||||
|
* NSString localURI
|
||||||
|
* OUT
|
||||||
|
* NSString full local filesystem path for the represented file or directory, or nil if no such path is possible
|
||||||
|
* The file or directory does not necessarily have to exist. nil is returned if the filesystem type is not recognized,
|
||||||
|
* or if the URL is malformed.
|
||||||
|
* The incoming URI should be properly escaped (no raw spaces, etc. URI percent-encoding is expected).
|
||||||
|
*/
|
||||||
|
- (NSString *)filesystemPathForURL:(CDVFilesystemURL *)url
|
||||||
|
{
|
||||||
|
return [self filesystemPathForFullPath:url.fullPath];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CDVFilesystemURL *)URLforFullPath:(NSString *)fullPath
|
||||||
|
{
|
||||||
|
if (fullPath) {
|
||||||
|
NSString* escapedPath = [fullPath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
|
||||||
|
if ([fullPath hasPrefix:@"/"]) {
|
||||||
|
return [CDVFilesystemURL fileSystemURLWithString:[NSString stringWithFormat:@"%@://localhost/%@%@", kCDVFilesystemURLPrefix, self.name, escapedPath]];
|
||||||
|
}
|
||||||
|
return [CDVFilesystemURL fileSystemURLWithString:[NSString stringWithFormat:@"%@://localhost/%@/%@", kCDVFilesystemURLPrefix, self.name, escapedPath]];
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CDVFilesystemURL *)URLforFilesystemPath:(NSString *)path
|
||||||
|
{
|
||||||
|
return [self URLforFullPath:[self fullPathForFileSystemPath:path]];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)normalizePath:(NSString *)rawPath
|
||||||
|
{
|
||||||
|
// If this is an absolute path, the first path component will be '/'. Skip it if that's the case
|
||||||
|
BOOL isAbsolutePath = [rawPath hasPrefix:@"/"];
|
||||||
|
if (isAbsolutePath) {
|
||||||
|
rawPath = [rawPath substringFromIndex:1];
|
||||||
|
}
|
||||||
|
NSMutableArray *components = [NSMutableArray arrayWithArray:[rawPath pathComponents]];
|
||||||
|
for (int index = 0; index < [components count]; ++index) {
|
||||||
|
if ([[components objectAtIndex:index] isEqualToString:@".."]) {
|
||||||
|
[components removeObjectAtIndex:index];
|
||||||
|
if (index > 0) {
|
||||||
|
[components removeObjectAtIndex:index-1];
|
||||||
|
--index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAbsolutePath) {
|
||||||
|
return [NSString stringWithFormat:@"/%@", [components componentsJoinedByString:@"/"]];
|
||||||
|
} else {
|
||||||
|
return [components componentsJoinedByString:@"/"];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)valueForKeyIsNumber:(NSDictionary*)dict key:(NSString*)key
|
||||||
|
{
|
||||||
|
BOOL bNumber = NO;
|
||||||
|
NSObject* value = dict[key];
|
||||||
|
if (value) {
|
||||||
|
bNumber = [value isKindOfClass:[NSNumber class]];
|
||||||
|
}
|
||||||
|
return bNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CDVPluginResult *)getFileForURL:(CDVFilesystemURL *)baseURI requestedPath:(NSString *)requestedPath options:(NSDictionary *)options
|
||||||
|
{
|
||||||
|
CDVPluginResult* result = nil;
|
||||||
|
BOOL bDirRequest = NO;
|
||||||
|
BOOL create = NO;
|
||||||
|
BOOL exclusive = NO;
|
||||||
|
int errorCode = 0; // !!! risky - no error code currently defined for 0
|
||||||
|
|
||||||
|
if ([self valueForKeyIsNumber:options key:@"create"]) {
|
||||||
|
create = [(NSNumber*)[options valueForKey:@"create"] boolValue];
|
||||||
|
}
|
||||||
|
if ([self valueForKeyIsNumber:options key:@"exclusive"]) {
|
||||||
|
exclusive = [(NSNumber*)[options valueForKey:@"exclusive"] boolValue];
|
||||||
|
}
|
||||||
|
if ([self valueForKeyIsNumber:options key:@"getDir"]) {
|
||||||
|
// this will not exist for calls directly to getFile but will have been set by getDirectory before calling this method
|
||||||
|
bDirRequest = [(NSNumber*)[options valueForKey:@"getDir"] boolValue];
|
||||||
|
}
|
||||||
|
// see if the requested path has invalid characters - should we be checking for more than just ":"?
|
||||||
|
if ([requestedPath rangeOfString:@":"].location != NSNotFound) {
|
||||||
|
errorCode = ENCODING_ERR;
|
||||||
|
} else {
|
||||||
|
// Build new fullPath for the requested resource.
|
||||||
|
// We concatenate the two paths together, and then scan the resulting string to remove
|
||||||
|
// parent ("..") references. Any parent references at the beginning of the string are
|
||||||
|
// silently removed.
|
||||||
|
NSString *combinedPath = [baseURI.fullPath stringByAppendingPathComponent:requestedPath];
|
||||||
|
combinedPath = [self normalizePath:combinedPath];
|
||||||
|
CDVFilesystemURL* requestedURL = [self URLforFullPath:combinedPath];
|
||||||
|
|
||||||
|
NSFileManager* fileMgr = [[NSFileManager alloc] init];
|
||||||
|
BOOL bIsDir;
|
||||||
|
BOOL bExists = [fileMgr fileExistsAtPath:[self filesystemPathForURL:requestedURL] isDirectory:&bIsDir];
|
||||||
|
if (bExists && (create == NO) && (bIsDir == !bDirRequest)) {
|
||||||
|
// path exists and is not of requested type - return TYPE_MISMATCH_ERR
|
||||||
|
errorCode = TYPE_MISMATCH_ERR;
|
||||||
|
} else if (!bExists && (create == NO)) {
|
||||||
|
// path does not exist and create is false - return NOT_FOUND_ERR
|
||||||
|
errorCode = NOT_FOUND_ERR;
|
||||||
|
} else if (bExists && (create == YES) && (exclusive == YES)) {
|
||||||
|
// file/dir already exists and exclusive and create are both true - return PATH_EXISTS_ERR
|
||||||
|
errorCode = PATH_EXISTS_ERR;
|
||||||
|
} else {
|
||||||
|
// if bExists and create == YES - just return data
|
||||||
|
// if bExists and create == NO - just return data
|
||||||
|
// if !bExists and create == YES - create and return data
|
||||||
|
BOOL bSuccess = YES;
|
||||||
|
NSError __autoreleasing* pError = nil;
|
||||||
|
if (!bExists && (create == YES)) {
|
||||||
|
if (bDirRequest) {
|
||||||
|
// create the dir
|
||||||
|
bSuccess = [fileMgr createDirectoryAtPath:[self filesystemPathForURL:requestedURL] withIntermediateDirectories:NO attributes:nil error:&pError];
|
||||||
|
} else {
|
||||||
|
// create the empty file
|
||||||
|
bSuccess = [fileMgr createFileAtPath:[self filesystemPathForURL:requestedURL] contents:nil attributes:nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!bSuccess) {
|
||||||
|
errorCode = ABORT_ERR;
|
||||||
|
if (pError) {
|
||||||
|
NSLog(@"error creating directory: %@", [pError localizedDescription]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// NSLog(@"newly created file/dir (%@) exists: %d", reqFullPath, [fileMgr fileExistsAtPath:reqFullPath]);
|
||||||
|
// file existed or was created
|
||||||
|
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[self makeEntryForPath:requestedURL.fullPath isDirectory:bDirRequest]];
|
||||||
|
}
|
||||||
|
} // are all possible conditions met?
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errorCode > 0) {
|
||||||
|
// create error callback
|
||||||
|
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CDVPluginResult*)getParentForURL:(CDVFilesystemURL *)localURI
|
||||||
|
{
|
||||||
|
CDVPluginResult* result = nil;
|
||||||
|
CDVFilesystemURL *newURI = nil;
|
||||||
|
if ([localURI.fullPath isEqualToString:@""]) {
|
||||||
|
// return self
|
||||||
|
newURI = localURI;
|
||||||
|
} else {
|
||||||
|
newURI = [CDVFilesystemURL fileSystemURLWithURL:[localURI.url URLByDeletingLastPathComponent]]; /* TODO: UGLY - FIX */
|
||||||
|
}
|
||||||
|
NSFileManager* fileMgr = [[NSFileManager alloc] init];
|
||||||
|
BOOL bIsDir;
|
||||||
|
BOOL bExists = [fileMgr fileExistsAtPath:[self filesystemPathForURL:newURI] isDirectory:&bIsDir];
|
||||||
|
if (bExists) {
|
||||||
|
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[self makeEntryForPath:newURI.fullPath isDirectory:bIsDir]];
|
||||||
|
} else {
|
||||||
|
// invalid path or file does not exist
|
||||||
|
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CDVPluginResult*)setMetadataForURL:(CDVFilesystemURL *)localURI withObject:(NSDictionary *)options
|
||||||
|
{
|
||||||
|
BOOL ok = NO;
|
||||||
|
|
||||||
|
NSString* filePath = [self filesystemPathForURL:localURI];
|
||||||
|
// we only care about this iCloud key for now.
|
||||||
|
// set to 1/true to skip backup, set to 0/false to back it up (effectively removing the attribute)
|
||||||
|
NSString* iCloudBackupExtendedAttributeKey = @"com.apple.MobileBackup";
|
||||||
|
id iCloudBackupExtendedAttributeValue = [options objectForKey:iCloudBackupExtendedAttributeKey];
|
||||||
|
|
||||||
|
if ((iCloudBackupExtendedAttributeValue != nil) && [iCloudBackupExtendedAttributeValue isKindOfClass:[NSNumber class]]) {
|
||||||
|
if (IsAtLeastiOSVersion(@"5.1")) {
|
||||||
|
NSURL* url = [NSURL fileURLWithPath:filePath];
|
||||||
|
NSError* __autoreleasing error = nil;
|
||||||
|
|
||||||
|
ok = [url setResourceValue:[NSNumber numberWithBool:[iCloudBackupExtendedAttributeValue boolValue]] forKey:NSURLIsExcludedFromBackupKey error:&error];
|
||||||
|
} else { // below 5.1 (deprecated - only really supported in 5.01)
|
||||||
|
u_int8_t value = [iCloudBackupExtendedAttributeValue intValue];
|
||||||
|
if (value == 0) { // remove the attribute (allow backup, the default)
|
||||||
|
ok = (removexattr([filePath fileSystemRepresentation], [iCloudBackupExtendedAttributeKey cStringUsingEncoding:NSUTF8StringEncoding], 0) == 0);
|
||||||
|
} else { // set the attribute (skip backup)
|
||||||
|
ok = (setxattr([filePath fileSystemRepresentation], [iCloudBackupExtendedAttributeKey cStringUsingEncoding:NSUTF8StringEncoding], &value, sizeof(value), 0, 0) == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok) {
|
||||||
|
return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
|
||||||
|
} else {
|
||||||
|
return [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remove the file or directory (recursively)
|
||||||
|
* IN:
|
||||||
|
* NSString* fullPath - the full path to the file or directory to be removed
|
||||||
|
* NSString* callbackId
|
||||||
|
* called from remove and removeRecursively - check all pubic api specific error conditions (dir not empty, etc) before calling
|
||||||
|
*/
|
||||||
|
|
||||||
|
- (CDVPluginResult*)doRemove:(NSString*)fullPath
|
||||||
|
{
|
||||||
|
CDVPluginResult* result = nil;
|
||||||
|
BOOL bSuccess = NO;
|
||||||
|
NSError* __autoreleasing pError = nil;
|
||||||
|
NSFileManager* fileMgr = [[NSFileManager alloc] init];
|
||||||
|
|
||||||
|
@try {
|
||||||
|
bSuccess = [fileMgr removeItemAtPath:fullPath error:&pError];
|
||||||
|
if (bSuccess) {
|
||||||
|
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
|
||||||
|
} else {
|
||||||
|
// see if we can give a useful error
|
||||||
|
CDVFileError errorCode = ABORT_ERR;
|
||||||
|
NSLog(@"error removing filesystem entry at %@: %@", fullPath, [pError localizedDescription]);
|
||||||
|
if ([pError code] == NSFileNoSuchFileError) {
|
||||||
|
errorCode = NOT_FOUND_ERR;
|
||||||
|
} else if ([pError code] == NSFileWriteNoPermissionError) {
|
||||||
|
errorCode = NO_MODIFICATION_ALLOWED_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode];
|
||||||
|
}
|
||||||
|
} @catch(NSException* e) { // NSInvalidArgumentException if path is . or ..
|
||||||
|
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:SYNTAX_ERR];
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CDVPluginResult *)removeFileAtURL:(CDVFilesystemURL *)localURI
|
||||||
|
{
|
||||||
|
NSString *fileSystemPath = [self filesystemPathForURL:localURI];
|
||||||
|
|
||||||
|
NSFileManager* fileMgr = [[NSFileManager alloc] init];
|
||||||
|
BOOL bIsDir = NO;
|
||||||
|
BOOL bExists = [fileMgr fileExistsAtPath:fileSystemPath isDirectory:&bIsDir];
|
||||||
|
if (!bExists) {
|
||||||
|
return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
|
||||||
|
}
|
||||||
|
if (bIsDir && ([[fileMgr contentsOfDirectoryAtPath:fileSystemPath error:nil] count] != 0)) {
|
||||||
|
// dir is not empty
|
||||||
|
return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:INVALID_MODIFICATION_ERR];
|
||||||
|
}
|
||||||
|
return [self doRemove:fileSystemPath];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CDVPluginResult *)recursiveRemoveFileAtURL:(CDVFilesystemURL *)localURI
|
||||||
|
{
|
||||||
|
NSString *fileSystemPath = [self filesystemPathForURL:localURI];
|
||||||
|
return [self doRemove:fileSystemPath];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IN
|
||||||
|
* NSString localURI
|
||||||
|
* OUT
|
||||||
|
* NSString full local filesystem path for the represented file or directory, or nil if no such path is possible
|
||||||
|
* The file or directory does not necessarily have to exist. nil is returned if the filesystem type is not recognized,
|
||||||
|
* or if the URL is malformed.
|
||||||
|
* The incoming URI should be properly escaped (no raw spaces, etc. URI percent-encoding is expected).
|
||||||
|
*/
|
||||||
|
- (NSString *)fullPathForFileSystemPath:(NSString *)fsPath
|
||||||
|
{
|
||||||
|
if ([fsPath hasPrefix:self.fsRoot]) {
|
||||||
|
return [fsPath substringFromIndex:[self.fsRoot length]];
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (CDVPluginResult *)readEntriesAtURL:(CDVFilesystemURL *)localURI
|
||||||
|
{
|
||||||
|
NSFileManager* fileMgr = [[NSFileManager alloc] init];
|
||||||
|
NSError* __autoreleasing error = nil;
|
||||||
|
NSString *fileSystemPath = [self filesystemPathForURL:localURI];
|
||||||
|
|
||||||
|
NSArray* contents = [fileMgr contentsOfDirectoryAtPath:fileSystemPath error:&error];
|
||||||
|
|
||||||
|
if (contents) {
|
||||||
|
NSMutableArray* entries = [NSMutableArray arrayWithCapacity:1];
|
||||||
|
if ([contents count] > 0) {
|
||||||
|
// create an Entry (as JSON) for each file/dir
|
||||||
|
for (NSString* name in contents) {
|
||||||
|
// see if is dir or file
|
||||||
|
NSString* entryPath = [fileSystemPath stringByAppendingPathComponent:name];
|
||||||
|
BOOL bIsDir = NO;
|
||||||
|
[fileMgr fileExistsAtPath:entryPath isDirectory:&bIsDir];
|
||||||
|
NSDictionary* entryDict = [self makeEntryForPath:[self fullPathForFileSystemPath:entryPath] isDirectory:bIsDir];
|
||||||
|
[entries addObject:entryDict];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:entries];
|
||||||
|
} else {
|
||||||
|
// assume not found but could check error for more specific error conditions
|
||||||
|
return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (unsigned long long)truncateFile:(NSString*)filePath atPosition:(unsigned long long)pos
|
||||||
|
{
|
||||||
|
unsigned long long newPos = 0UL;
|
||||||
|
|
||||||
|
NSFileHandle* file = [NSFileHandle fileHandleForWritingAtPath:filePath];
|
||||||
|
|
||||||
|
if (file) {
|
||||||
|
[file truncateFileAtOffset:(unsigned long long)pos];
|
||||||
|
newPos = [file offsetInFile];
|
||||||
|
[file synchronizeFile];
|
||||||
|
[file closeFile];
|
||||||
|
}
|
||||||
|
return newPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CDVPluginResult *)truncateFileAtURL:(CDVFilesystemURL *)localURI atPosition:(unsigned long long)pos
|
||||||
|
{
|
||||||
|
unsigned long long newPos = [self truncateFile:[self filesystemPathForURL:localURI] atPosition:pos];
|
||||||
|
return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:(int)newPos];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CDVPluginResult *)writeToFileAtURL:(CDVFilesystemURL *)localURL withData:(NSData*)encData append:(BOOL)shouldAppend
|
||||||
|
{
|
||||||
|
NSString *filePath = [self filesystemPathForURL:localURL];
|
||||||
|
|
||||||
|
CDVPluginResult* result = nil;
|
||||||
|
CDVFileError errCode = INVALID_MODIFICATION_ERR;
|
||||||
|
int bytesWritten = 0;
|
||||||
|
|
||||||
|
if (filePath) {
|
||||||
|
NSOutputStream* fileStream = [NSOutputStream outputStreamToFileAtPath:filePath append:shouldAppend];
|
||||||
|
if (fileStream) {
|
||||||
|
NSUInteger len = [encData length];
|
||||||
|
if (len == 0) {
|
||||||
|
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDouble:(double)len];
|
||||||
|
} else {
|
||||||
|
[fileStream open];
|
||||||
|
|
||||||
|
bytesWritten = (int)[fileStream write:[encData bytes] maxLength:len];
|
||||||
|
|
||||||
|
[fileStream close];
|
||||||
|
if (bytesWritten > 0) {
|
||||||
|
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:bytesWritten];
|
||||||
|
// } else {
|
||||||
|
// can probably get more detailed error info via [fileStream streamError]
|
||||||
|
// errCode already set to INVALID_MODIFICATION_ERR;
|
||||||
|
// bytesWritten = 0; // may be set to -1 on error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // else fileStream not created return INVALID_MODIFICATION_ERR
|
||||||
|
} else {
|
||||||
|
// invalid filePath
|
||||||
|
errCode = NOT_FOUND_ERR;
|
||||||
|
}
|
||||||
|
if (!result) {
|
||||||
|
// was an error
|
||||||
|
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errCode];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to check to see if the user attempted to copy an entry into its parent without changing its name,
|
||||||
|
* or attempted to copy a directory into a directory that it contains directly or indirectly.
|
||||||
|
*
|
||||||
|
* IN:
|
||||||
|
* NSString* srcDir
|
||||||
|
* NSString* destinationDir
|
||||||
|
* OUT:
|
||||||
|
* YES copy/ move is allows
|
||||||
|
* NO move is onto itself
|
||||||
|
*/
|
||||||
|
- (BOOL)canCopyMoveSrc:(NSString*)src ToDestination:(NSString*)dest
|
||||||
|
{
|
||||||
|
// This weird test is to determine if we are copying or moving a directory into itself.
|
||||||
|
// Copy /Documents/myDir to /Documents/myDir-backup is okay but
|
||||||
|
// Copy /Documents/myDir to /Documents/myDir/backup not okay
|
||||||
|
BOOL copyOK = YES;
|
||||||
|
NSRange range = [dest rangeOfString:src];
|
||||||
|
|
||||||
|
if (range.location != NSNotFound) {
|
||||||
|
NSRange testRange = {range.length - 1, ([dest length] - range.length)};
|
||||||
|
NSRange resultRange = [dest rangeOfString:@"/" options:0 range:testRange];
|
||||||
|
if (resultRange.location != NSNotFound) {
|
||||||
|
copyOK = NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return copyOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)copyFileToURL:(CDVFilesystemURL *)destURL withName:(NSString *)newName fromFileSystem:(NSObject<CDVFileSystem> *)srcFs atURL:(CDVFilesystemURL *)srcURL copy:(BOOL)bCopy callback:(void (^)(CDVPluginResult *))callback
|
||||||
|
{
|
||||||
|
NSFileManager *fileMgr = [[NSFileManager alloc] init];
|
||||||
|
NSString *destRootPath = [self filesystemPathForURL:destURL];
|
||||||
|
BOOL bDestIsDir = NO;
|
||||||
|
BOOL bDestExists = [fileMgr fileExistsAtPath:destRootPath isDirectory:&bDestIsDir];
|
||||||
|
|
||||||
|
NSString *newFileSystemPath = [destRootPath stringByAppendingPathComponent:newName];
|
||||||
|
NSString *newFullPath = [self fullPathForFileSystemPath:newFileSystemPath];
|
||||||
|
|
||||||
|
BOOL bNewIsDir = NO;
|
||||||
|
BOOL bNewExists = [fileMgr fileExistsAtPath:newFileSystemPath isDirectory:&bNewIsDir];
|
||||||
|
|
||||||
|
CDVPluginResult *result = nil;
|
||||||
|
int errCode = 0;
|
||||||
|
|
||||||
|
if (!bDestExists) {
|
||||||
|
// the destination root does not exist
|
||||||
|
errCode = NOT_FOUND_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ([srcFs isKindOfClass:[CDVLocalFilesystem class]]) {
|
||||||
|
/* Same FS, we can shortcut with NSFileManager operations */
|
||||||
|
NSString *srcFullPath = [srcFs filesystemPathForURL:srcURL];
|
||||||
|
|
||||||
|
BOOL bSrcIsDir = NO;
|
||||||
|
BOOL bSrcExists = [fileMgr fileExistsAtPath:srcFullPath isDirectory:&bSrcIsDir];
|
||||||
|
|
||||||
|
if (!bSrcExists) {
|
||||||
|
// the source does not exist
|
||||||
|
errCode = NOT_FOUND_ERR;
|
||||||
|
} else if ([newFileSystemPath isEqualToString:srcFullPath]) {
|
||||||
|
// source and destination can not be the same
|
||||||
|
errCode = INVALID_MODIFICATION_ERR;
|
||||||
|
} else if (bSrcIsDir && (bNewExists && !bNewIsDir)) {
|
||||||
|
// can't copy/move dir to file
|
||||||
|
errCode = INVALID_MODIFICATION_ERR;
|
||||||
|
} else { // no errors yet
|
||||||
|
NSError* __autoreleasing error = nil;
|
||||||
|
BOOL bSuccess = NO;
|
||||||
|
if (bCopy) {
|
||||||
|
if (bSrcIsDir && ![self canCopyMoveSrc:srcFullPath ToDestination:newFileSystemPath]) {
|
||||||
|
// can't copy dir into self
|
||||||
|
errCode = INVALID_MODIFICATION_ERR;
|
||||||
|
} else if (bNewExists) {
|
||||||
|
// the full destination should NOT already exist if a copy
|
||||||
|
errCode = PATH_EXISTS_ERR;
|
||||||
|
} else {
|
||||||
|
bSuccess = [fileMgr copyItemAtPath:srcFullPath toPath:newFileSystemPath error:&error];
|
||||||
|
}
|
||||||
|
} else { // move
|
||||||
|
// iOS requires that destination must not exist before calling moveTo
|
||||||
|
// is W3C INVALID_MODIFICATION_ERR error if destination dir exists and has contents
|
||||||
|
//
|
||||||
|
if (!bSrcIsDir && (bNewExists && bNewIsDir)) {
|
||||||
|
// can't move a file to directory
|
||||||
|
errCode = INVALID_MODIFICATION_ERR;
|
||||||
|
} else if (bSrcIsDir && ![self canCopyMoveSrc:srcFullPath ToDestination:newFileSystemPath]) {
|
||||||
|
// can't move a dir into itself
|
||||||
|
errCode = INVALID_MODIFICATION_ERR;
|
||||||
|
} else if (bNewExists) {
|
||||||
|
if (bNewIsDir && ([[fileMgr contentsOfDirectoryAtPath:newFileSystemPath error:NULL] count] != 0)) {
|
||||||
|
// can't move dir to a dir that is not empty
|
||||||
|
errCode = INVALID_MODIFICATION_ERR;
|
||||||
|
newFileSystemPath = nil; // so we won't try to move
|
||||||
|
} else {
|
||||||
|
// remove destination so can perform the moveItemAtPath
|
||||||
|
bSuccess = [fileMgr removeItemAtPath:newFileSystemPath error:NULL];
|
||||||
|
if (!bSuccess) {
|
||||||
|
errCode = INVALID_MODIFICATION_ERR; // is this the correct error?
|
||||||
|
newFileSystemPath = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (bNewIsDir && [newFileSystemPath hasPrefix:srcFullPath]) {
|
||||||
|
// can't move a directory inside itself or to any child at any depth;
|
||||||
|
errCode = INVALID_MODIFICATION_ERR;
|
||||||
|
newFileSystemPath = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newFileSystemPath != nil) {
|
||||||
|
bSuccess = [fileMgr moveItemAtPath:srcFullPath toPath:newFileSystemPath error:&error];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bSuccess) {
|
||||||
|
// should verify it is there and of the correct type???
|
||||||
|
NSDictionary* newEntry = [self makeEntryForPath:newFullPath isDirectory:bSrcIsDir];
|
||||||
|
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:newEntry];
|
||||||
|
} else {
|
||||||
|
if (error) {
|
||||||
|
if (([error code] == NSFileReadUnknownError) || ([error code] == NSFileReadTooLargeError)) {
|
||||||
|
errCode = NOT_READABLE_ERR;
|
||||||
|
} else if ([error code] == NSFileWriteOutOfSpaceError) {
|
||||||
|
errCode = QUOTA_EXCEEDED_ERR;
|
||||||
|
} else if ([error code] == NSFileWriteNoPermissionError) {
|
||||||
|
errCode = NO_MODIFICATION_ALLOWED_ERR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Need to copy the hard way
|
||||||
|
[srcFs readFileAtURL:srcURL start:0 end:-1 callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) {
|
||||||
|
CDVPluginResult* result = nil;
|
||||||
|
if (data != nil) {
|
||||||
|
BOOL bSuccess = [data writeToFile:newFileSystemPath atomically:YES];
|
||||||
|
if (bSuccess) {
|
||||||
|
// should verify it is there and of the correct type???
|
||||||
|
NSDictionary* newEntry = [self makeEntryForPath:newFullPath isDirectory:NO];
|
||||||
|
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:newEntry];
|
||||||
|
} else {
|
||||||
|
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:ABORT_ERR];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode];
|
||||||
|
}
|
||||||
|
callback(result);
|
||||||
|
}];
|
||||||
|
return; // Async IO; return without callback.
|
||||||
|
}
|
||||||
|
if (result == nil) {
|
||||||
|
if (!errCode) {
|
||||||
|
errCode = INVALID_MODIFICATION_ERR; // Catch-all default
|
||||||
|
}
|
||||||
|
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errCode];
|
||||||
|
}
|
||||||
|
callback(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* helper function to get the mimeType from the file extension
|
||||||
|
* IN:
|
||||||
|
* NSString* fullPath - filename (may include path)
|
||||||
|
* OUT:
|
||||||
|
* NSString* the mime type as type/subtype. nil if not able to determine
|
||||||
|
*/
|
||||||
|
+ (NSString*)getMimeTypeFromPath:(NSString*)fullPath
|
||||||
|
{
|
||||||
|
NSString* mimeType = nil;
|
||||||
|
|
||||||
|
if (fullPath) {
|
||||||
|
CFStringRef typeId = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)[fullPath pathExtension], NULL);
|
||||||
|
if (typeId) {
|
||||||
|
mimeType = (__bridge_transfer NSString*)UTTypeCopyPreferredTagWithClass(typeId, kUTTagClassMIMEType);
|
||||||
|
if (!mimeType) {
|
||||||
|
// special case for m4a
|
||||||
|
if ([(__bridge NSString*)typeId rangeOfString : @"m4a-audio"].location != NSNotFound) {
|
||||||
|
mimeType = @"audio/mp4";
|
||||||
|
} else if ([[fullPath pathExtension] rangeOfString:@"wav"].location != NSNotFound) {
|
||||||
|
mimeType = @"audio/wav";
|
||||||
|
} else if ([[fullPath pathExtension] rangeOfString:@"css"].location != NSNotFound) {
|
||||||
|
mimeType = @"text/css";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CFRelease(typeId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mimeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)readFileAtURL:(CDVFilesystemURL *)localURL start:(NSInteger)start end:(NSInteger)end callback:(void (^)(NSData*, NSString* mimeType, CDVFileError))callback
|
||||||
|
{
|
||||||
|
NSString *path = [self filesystemPathForURL:localURL];
|
||||||
|
|
||||||
|
NSString* mimeType = [CDVLocalFilesystem getMimeTypeFromPath:path];
|
||||||
|
if (mimeType == nil) {
|
||||||
|
mimeType = @"*/*";
|
||||||
|
}
|
||||||
|
NSFileHandle* file = [NSFileHandle fileHandleForReadingAtPath:path];
|
||||||
|
if (start > 0) {
|
||||||
|
[file seekToFileOffset:start];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSData* readData;
|
||||||
|
if (end < 0) {
|
||||||
|
readData = [file readDataToEndOfFile];
|
||||||
|
} else {
|
||||||
|
readData = [file readDataOfLength:(end - start)];
|
||||||
|
}
|
||||||
|
[file closeFile];
|
||||||
|
|
||||||
|
callback(readData, mimeType, readData != nil ? NO_ERROR : NOT_FOUND_ERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)getFileMetadataForURL:(CDVFilesystemURL *)localURL callback:(void (^)(CDVPluginResult *))callback
|
||||||
|
{
|
||||||
|
NSString *path = [self filesystemPathForURL:localURL];
|
||||||
|
CDVPluginResult *result;
|
||||||
|
NSFileManager* fileMgr = [[NSFileManager alloc] init];
|
||||||
|
|
||||||
|
NSError* __autoreleasing error = nil;
|
||||||
|
NSDictionary* fileAttrs = [fileMgr attributesOfItemAtPath:path error:&error];
|
||||||
|
|
||||||
|
if (fileAttrs) {
|
||||||
|
|
||||||
|
// create dictionary of file info
|
||||||
|
NSMutableDictionary* fileInfo = [NSMutableDictionary dictionaryWithCapacity:5];
|
||||||
|
|
||||||
|
[fileInfo setObject:localURL.fullPath forKey:@"fullPath"];
|
||||||
|
[fileInfo setObject:@"" forKey:@"type"]; // can't easily get the mimetype unless create URL, send request and read response so skipping
|
||||||
|
[fileInfo setObject:[path lastPathComponent] forKey:@"name"];
|
||||||
|
|
||||||
|
// Ensure that directories (and other non-regular files) report size of 0
|
||||||
|
unsigned long long size = ([fileAttrs fileType] == NSFileTypeRegular ? [fileAttrs fileSize] : 0);
|
||||||
|
[fileInfo setObject:[NSNumber numberWithUnsignedLongLong:size] forKey:@"size"];
|
||||||
|
|
||||||
|
NSDate* modDate = [fileAttrs fileModificationDate];
|
||||||
|
if (modDate) {
|
||||||
|
[fileInfo setObject:[NSNumber numberWithDouble:[modDate timeIntervalSince1970] * 1000] forKey:@"lastModifiedDate"];
|
||||||
|
}
|
||||||
|
|
||||||
|
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileInfo];
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// didn't get fileAttribs
|
||||||
|
CDVFileError errorCode = ABORT_ERR;
|
||||||
|
NSLog(@"error getting metadata: %@", [error localizedDescription]);
|
||||||
|
if ([error code] == NSFileNoSuchFileError || [error code] == NSFileReadNoSuchFileError) {
|
||||||
|
errorCode = NOT_FOUND_ERR;
|
||||||
|
}
|
||||||
|
// log [NSNumber numberWithDouble: theMessage] objCtype to see what it returns
|
||||||
|
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errorCode];
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
120
platforms/ios/platform_www/plugins/cordova-plugin-file/www/DirectoryEntry.js
vendored
Normal file
120
platforms/ios/platform_www/plugins/cordova-plugin-file/www/DirectoryEntry.js
vendored
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
cordova.define("cordova-plugin-file.DirectoryEntry", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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 argscheck = require('cordova/argscheck'),
|
||||||
|
utils = require('cordova/utils'),
|
||||||
|
exec = require('cordova/exec'),
|
||||||
|
Entry = require('./Entry'),
|
||||||
|
FileError = require('./FileError'),
|
||||||
|
DirectoryReader = require('./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)
|
||||||
|
* {FileSystem} filesystem on which the directory resides (readonly)
|
||||||
|
*/
|
||||||
|
var DirectoryEntry = function(name, fullPath, fileSystem, nativeURL) {
|
||||||
|
|
||||||
|
// add trailing slash if it is missing
|
||||||
|
if ((fullPath) && !/\/$/.test(fullPath)) {
|
||||||
|
fullPath += "/";
|
||||||
|
}
|
||||||
|
// add trailing slash if it is missing
|
||||||
|
if (nativeURL && !/\/$/.test(nativeURL)) {
|
||||||
|
nativeURL += "/";
|
||||||
|
}
|
||||||
|
DirectoryEntry.__super__.constructor.call(this, false, true, name, fullPath, fileSystem, nativeURL);
|
||||||
|
};
|
||||||
|
|
||||||
|
utils.extend(DirectoryEntry, Entry);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new DirectoryReader to read entries from this directory
|
||||||
|
*/
|
||||||
|
DirectoryEntry.prototype.createReader = function() {
|
||||||
|
return new DirectoryReader(this.toInternalURL());
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 fs = this.filesystem;
|
||||||
|
var win = successCallback && function(result) {
|
||||||
|
var entry = new DirectoryEntry(result.name, result.fullPath, fs, result.nativeURL);
|
||||||
|
successCallback(entry);
|
||||||
|
};
|
||||||
|
var fail = errorCallback && function(code) {
|
||||||
|
errorCallback(new FileError(code));
|
||||||
|
};
|
||||||
|
exec(win, fail, "File", "getDirectory", [this.toInternalURL(), 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.toInternalURL()]);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 fs = this.filesystem;
|
||||||
|
var win = successCallback && function(result) {
|
||||||
|
var FileEntry = require('./FileEntry');
|
||||||
|
var entry = new FileEntry(result.name, result.fullPath, fs, result.nativeURL);
|
||||||
|
successCallback(entry);
|
||||||
|
};
|
||||||
|
var fail = errorCallback && function(code) {
|
||||||
|
errorCallback(new FileError(code));
|
||||||
|
};
|
||||||
|
exec(win, fail, "File", "getFile", [this.toInternalURL(), path, options]);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = DirectoryEntry;
|
||||||
|
|
||||||
|
});
|
76
platforms/ios/platform_www/plugins/cordova-plugin-file/www/DirectoryReader.js
vendored
Normal file
76
platforms/ios/platform_www/plugins/cordova-plugin-file/www/DirectoryReader.js
vendored
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
cordova.define("cordova-plugin-file.DirectoryReader", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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 exec = require('cordova/exec'),
|
||||||
|
FileError = require('./FileError') ;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface that lists the files and directories in a directory.
|
||||||
|
*/
|
||||||
|
function DirectoryReader(localURL) {
|
||||||
|
this.localURL = localURL || null;
|
||||||
|
this.hasReadEntries = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
||||||
|
// If we've already read and passed on this directory's entries, return an empty list.
|
||||||
|
if (this.hasReadEntries) {
|
||||||
|
successCallback([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var reader = this;
|
||||||
|
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('./DirectoryEntry'))();
|
||||||
|
}
|
||||||
|
else if (result[i].isFile) {
|
||||||
|
entry = new (require('./FileEntry'))();
|
||||||
|
}
|
||||||
|
entry.isDirectory = result[i].isDirectory;
|
||||||
|
entry.isFile = result[i].isFile;
|
||||||
|
entry.name = result[i].name;
|
||||||
|
entry.fullPath = result[i].fullPath;
|
||||||
|
entry.filesystem = new (require('./FileSystem'))(result[i].filesystemName);
|
||||||
|
entry.nativeURL = result[i].nativeURL;
|
||||||
|
retVal.push(entry);
|
||||||
|
}
|
||||||
|
reader.hasReadEntries = true;
|
||||||
|
successCallback(retVal);
|
||||||
|
};
|
||||||
|
var fail = typeof errorCallback !== 'function' ? null : function(code) {
|
||||||
|
errorCallback(new FileError(code));
|
||||||
|
};
|
||||||
|
exec(win, fail, "File", "readEntries", [this.localURL]);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = DirectoryReader;
|
||||||
|
|
||||||
|
});
|
265
platforms/ios/platform_www/plugins/cordova-plugin-file/www/Entry.js
vendored
Normal file
265
platforms/ios/platform_www/plugins/cordova-plugin-file/www/Entry.js
vendored
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
cordova.define("cordova-plugin-file.Entry", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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 argscheck = require('cordova/argscheck'),
|
||||||
|
exec = require('cordova/exec'),
|
||||||
|
FileError = require('./FileError'),
|
||||||
|
Metadata = require('./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)
|
||||||
|
* @param fileSystem
|
||||||
|
* {FileSystem} the filesystem on which this entry resides
|
||||||
|
* (readonly)
|
||||||
|
* @param nativeURL
|
||||||
|
* {DOMString} an alternate URL which can be used by native
|
||||||
|
* webview controls, for example media players.
|
||||||
|
* (optional, readonly)
|
||||||
|
*/
|
||||||
|
function Entry(isFile, isDirectory, name, fullPath, fileSystem, nativeURL) {
|
||||||
|
this.isFile = !!isFile;
|
||||||
|
this.isDirectory = !!isDirectory;
|
||||||
|
this.name = name || '';
|
||||||
|
this.fullPath = fullPath || '';
|
||||||
|
this.filesystem = fileSystem || null;
|
||||||
|
this.nativeURL = nativeURL || 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(entryMetadata) {
|
||||||
|
var metadata = new Metadata({
|
||||||
|
size: entryMetadata.size,
|
||||||
|
modificationTime: entryMetadata.lastModifiedDate
|
||||||
|
});
|
||||||
|
successCallback(metadata);
|
||||||
|
};
|
||||||
|
var fail = errorCallback && function(code) {
|
||||||
|
errorCallback(new FileError(code));
|
||||||
|
};
|
||||||
|
exec(success, fail, "File", "getFileMetadata", [this.toInternalURL()]);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.toInternalURL(), 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));
|
||||||
|
};
|
||||||
|
var srcURL = this.toInternalURL(),
|
||||||
|
// entry name
|
||||||
|
name = newName || this.name,
|
||||||
|
success = function(entry) {
|
||||||
|
if (entry) {
|
||||||
|
if (successCallback) {
|
||||||
|
// create appropriate Entry object
|
||||||
|
var newFSName = entry.filesystemName || (entry.filesystem && entry.filesystem.name);
|
||||||
|
var fs = newFSName ? new FileSystem(newFSName, { name: "", fullPath: "/" }) : new FileSystem(parent.filesystem.name, { name: "", fullPath: "/" });
|
||||||
|
var result = (entry.isDirectory) ? new (require('./DirectoryEntry'))(entry.name, entry.fullPath, fs, entry.nativeURL) : new (require('cordova-plugin-file.FileEntry'))(entry.name, entry.fullPath, fs, entry.nativeURL);
|
||||||
|
successCallback(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// no Entry object returned
|
||||||
|
if (fail) {
|
||||||
|
fail(FileError.NOT_FOUND_ERR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// copy
|
||||||
|
exec(success, fail, "File", "moveTo", [srcURL, parent.toInternalURL(), 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));
|
||||||
|
};
|
||||||
|
var srcURL = this.toInternalURL(),
|
||||||
|
// entry name
|
||||||
|
name = newName || this.name,
|
||||||
|
// success callback
|
||||||
|
success = function(entry) {
|
||||||
|
if (entry) {
|
||||||
|
if (successCallback) {
|
||||||
|
// create appropriate Entry object
|
||||||
|
var newFSName = entry.filesystemName || (entry.filesystem && entry.filesystem.name);
|
||||||
|
var fs = newFSName ? new FileSystem(newFSName, { name: "", fullPath: "/" }) : new FileSystem(parent.filesystem.name, { name: "", fullPath: "/" });
|
||||||
|
var result = (entry.isDirectory) ? new (require('./DirectoryEntry'))(entry.name, entry.fullPath, fs, entry.nativeURL) : new (require('cordova-plugin-file.FileEntry'))(entry.name, entry.fullPath, fs, entry.nativeURL);
|
||||||
|
successCallback(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// no Entry object returned
|
||||||
|
if (fail) {
|
||||||
|
fail(FileError.NOT_FOUND_ERR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// copy
|
||||||
|
exec(success, fail, "File", "copyTo", [srcURL, parent.toInternalURL(), name]);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a URL that can be passed across the bridge to identify this entry.
|
||||||
|
*/
|
||||||
|
Entry.prototype.toInternalURL = function() {
|
||||||
|
if (this.filesystem && this.filesystem.__format__) {
|
||||||
|
return this.filesystem.__format__(this.fullPath, this.nativeURL);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a URL that can be used to identify this entry.
|
||||||
|
* Use a URL that can be used to as the src attribute of a <video> or
|
||||||
|
* <audio> tag. If that is not possible, construct a cdvfile:// URL.
|
||||||
|
*/
|
||||||
|
Entry.prototype.toURL = function() {
|
||||||
|
if (this.nativeURL) {
|
||||||
|
return this.nativeURL;
|
||||||
|
}
|
||||||
|
// fullPath attribute may contain the full URL in the case that
|
||||||
|
// toInternalURL fails.
|
||||||
|
return this.toInternalURL() || "file://localhost" + this.fullPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Backwards-compatibility: In v1.0.0 - 1.0.2, .toURL would only return a
|
||||||
|
* cdvfile:// URL, and this method was necessary to obtain URLs usable by the
|
||||||
|
* webview.
|
||||||
|
* See CB-6051, CB-6106, CB-6117, CB-6152, CB-6199, CB-6201, CB-6243, CB-6249,
|
||||||
|
* and CB-6300.
|
||||||
|
*/
|
||||||
|
Entry.prototype.toNativeURL = function() {
|
||||||
|
console.log("DEPRECATED: Update your code to use 'toURL'");
|
||||||
|
return this.toURL();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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'");
|
||||||
|
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.toInternalURL()]);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 fs = this.filesystem;
|
||||||
|
var win = successCallback && function(result) {
|
||||||
|
var DirectoryEntry = require('./DirectoryEntry');
|
||||||
|
var entry = new DirectoryEntry(result.name, result.fullPath, fs, result.nativeURL);
|
||||||
|
successCallback(entry);
|
||||||
|
};
|
||||||
|
var fail = errorCallback && function(code) {
|
||||||
|
errorCallback(new FileError(code));
|
||||||
|
};
|
||||||
|
exec(win, fail, "File", "getParent", [this.toInternalURL()]);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = Entry;
|
||||||
|
|
||||||
|
});
|
82
platforms/ios/platform_www/plugins/cordova-plugin-file/www/File.js
vendored
Normal file
82
platforms/ios/platform_www/plugins/cordova-plugin-file/www/File.js
vendored
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
cordova.define("cordova-plugin-file.File", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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, localURL, type, lastModifiedDate, size){
|
||||||
|
this.name = name || '';
|
||||||
|
this.localURL = localURL || null;
|
||||||
|
this.type = type || null;
|
||||||
|
this.lastModified = lastModifiedDate || null;
|
||||||
|
// For backwards compatibility, store the timestamp in lastModifiedDate as well
|
||||||
|
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.localURL, this.type, this.lastModified, this.size);
|
||||||
|
newFile.start = this.start + newStart;
|
||||||
|
newFile.end = this.start + newEnd;
|
||||||
|
return newFile;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = File;
|
||||||
|
|
||||||
|
});
|
96
platforms/ios/platform_www/plugins/cordova-plugin-file/www/FileEntry.js
vendored
Normal file
96
platforms/ios/platform_www/plugins/cordova-plugin-file/www/FileEntry.js
vendored
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
cordova.define("cordova-plugin-file.FileEntry", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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 utils = require('cordova/utils'),
|
||||||
|
exec = require('cordova/exec'),
|
||||||
|
Entry = require('./Entry'),
|
||||||
|
FileWriter = require('./FileWriter'),
|
||||||
|
File = require('./File'),
|
||||||
|
FileError = require('./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, fileSystem, nativeURL) {
|
||||||
|
// remove trailing slash if it is present
|
||||||
|
if (fullPath && /\/$/.test(fullPath)) {
|
||||||
|
fullPath = fullPath.substring(0, fullPath.length - 1);
|
||||||
|
}
|
||||||
|
if (nativeURL && /\/$/.test(nativeURL)) {
|
||||||
|
nativeURL = nativeURL.substring(0, nativeURL.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileEntry.__super__.constructor.apply(this, [true, false, name, fullPath, fileSystem, nativeURL]);
|
||||||
|
};
|
||||||
|
|
||||||
|
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.localURL === null || writer.localURL === "") {
|
||||||
|
if (errorCallback) {
|
||||||
|
errorCallback(new FileError(FileError.INVALID_STATE_ERR));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (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 localURL = this.toInternalURL();
|
||||||
|
var win = successCallback && function(f) {
|
||||||
|
var file = new File(f.name, localURL, f.type, f.lastModifiedDate, f.size);
|
||||||
|
successCallback(file);
|
||||||
|
};
|
||||||
|
var fail = errorCallback && function(code) {
|
||||||
|
errorCallback(new FileError(code));
|
||||||
|
};
|
||||||
|
exec(win, fail, "File", "getFileMetadata", [localURL]);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = FileEntry;
|
||||||
|
|
||||||
|
});
|
49
platforms/ios/platform_www/plugins/cordova-plugin-file/www/FileError.js
vendored
Normal file
49
platforms/ios/platform_www/plugins/cordova-plugin-file/www/FileError.js
vendored
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
cordova.define("cordova-plugin-file.FileError", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
});
|
292
platforms/ios/platform_www/plugins/cordova-plugin-file/www/FileReader.js
vendored
Normal file
292
platforms/ios/platform_www/plugins/cordova-plugin-file/www/FileReader.js
vendored
Normal file
@ -0,0 +1,292 @@
|
|||||||
|
cordova.define("cordova-plugin-file.FileReader", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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 exec = require('cordova/exec'),
|
||||||
|
modulemapper = require('cordova/modulemapper'),
|
||||||
|
utils = require('cordova/utils'),
|
||||||
|
FileError = require('./FileError'),
|
||||||
|
ProgressEvent = require('./ProgressEvent'),
|
||||||
|
origFileReader = modulemapper.getOriginalSymbol(window, '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._progress = null;
|
||||||
|
this._localURL = '';
|
||||||
|
this._realReader = origFileReader ? new origFileReader() : {};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the maximum size to read at a time via the native API. The default value is a compromise between
|
||||||
|
* minimizing the overhead of many exec() calls while still reporting progress frequently enough for large files.
|
||||||
|
* (Note attempts to allocate more than a few MB of contiguous memory on the native side are likely to cause
|
||||||
|
* OOM exceptions, while the JS engine seems to have fewer problems managing large strings or ArrayBuffers.)
|
||||||
|
*/
|
||||||
|
FileReader.READ_CHUNK_SIZE = 256*1024;
|
||||||
|
|
||||||
|
// States
|
||||||
|
FileReader.EMPTY = 0;
|
||||||
|
FileReader.LOADING = 1;
|
||||||
|
FileReader.DONE = 2;
|
||||||
|
|
||||||
|
utils.defineGetter(FileReader.prototype, 'readyState', function() {
|
||||||
|
return this._localURL ? this._readyState : this._realReader.readyState;
|
||||||
|
});
|
||||||
|
|
||||||
|
utils.defineGetter(FileReader.prototype, 'error', function() {
|
||||||
|
return this._localURL ? this._error: this._realReader.error;
|
||||||
|
});
|
||||||
|
|
||||||
|
utils.defineGetter(FileReader.prototype, 'result', function() {
|
||||||
|
return this._localURL ? 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._progress = 0;
|
||||||
|
reader._readyState = FileReader.LOADING;
|
||||||
|
|
||||||
|
if (typeof file.localURL == 'string') {
|
||||||
|
reader._localURL = file.localURL;
|
||||||
|
} else {
|
||||||
|
reader._localURL = '';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reader.onloadstart) {
|
||||||
|
reader.onloadstart(new ProgressEvent("loadstart", {target:reader}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback used by the following read* functions to handle incremental or final success.
|
||||||
|
* Must be bound to the FileReader's this along with all but the last parameter,
|
||||||
|
* e.g. readSuccessCallback.bind(this, "readAsText", "UTF-8", offset, totalSize, accumulate)
|
||||||
|
* @param readType The name of the read function to call.
|
||||||
|
* @param encoding Text encoding, or null if this is not a text type read.
|
||||||
|
* @param offset Starting offset of the read.
|
||||||
|
* @param totalSize Total number of bytes or chars to read.
|
||||||
|
* @param accumulate A function that takes the callback result and accumulates it in this._result.
|
||||||
|
* @param r Callback result returned by the last read exec() call, or null to begin reading.
|
||||||
|
*/
|
||||||
|
function readSuccessCallback(readType, encoding, offset, totalSize, accumulate, r) {
|
||||||
|
if (this._readyState === FileReader.DONE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof r !== "undefined") {
|
||||||
|
accumulate(r);
|
||||||
|
this._progress = Math.min(this._progress + FileReader.READ_CHUNK_SIZE, totalSize);
|
||||||
|
|
||||||
|
if (typeof this.onprogress === "function") {
|
||||||
|
this.onprogress(new ProgressEvent("progress", {loaded:this._progress, total:totalSize}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof r === "undefined" || this._progress < totalSize) {
|
||||||
|
var execArgs = [
|
||||||
|
this._localURL,
|
||||||
|
offset + this._progress,
|
||||||
|
offset + this._progress + Math.min(totalSize - this._progress, FileReader.READ_CHUNK_SIZE)];
|
||||||
|
if (encoding) {
|
||||||
|
execArgs.splice(1, 0, encoding);
|
||||||
|
}
|
||||||
|
exec(
|
||||||
|
readSuccessCallback.bind(this, readType, encoding, offset, totalSize, accumulate),
|
||||||
|
readFailureCallback.bind(this),
|
||||||
|
"File", readType, execArgs);
|
||||||
|
} else {
|
||||||
|
this._readyState = FileReader.DONE;
|
||||||
|
|
||||||
|
if (typeof this.onload === "function") {
|
||||||
|
this.onload(new ProgressEvent("load", {target:this}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof this.onloadend === "function") {
|
||||||
|
this.onloadend(new ProgressEvent("loadend", {target:this}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback used by the following read* functions to handle errors.
|
||||||
|
* Must be bound to the FileReader's this, e.g. readFailureCallback.bind(this)
|
||||||
|
*/
|
||||||
|
function readFailureCallback(e) {
|
||||||
|
if (this._readyState === FileReader.DONE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._readyState = FileReader.DONE;
|
||||||
|
this._result = null;
|
||||||
|
this._error = new FileError(e);
|
||||||
|
|
||||||
|
if (typeof this.onerror === "function") {
|
||||||
|
this.onerror(new ProgressEvent("error", {target:this}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof this.onloadend === "function") {
|
||||||
|
this.onloadend(new ProgressEvent("loadend", {target:this}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abort reading file.
|
||||||
|
*/
|
||||||
|
FileReader.prototype.abort = function() {
|
||||||
|
if (origFileReader && !this._localURL) {
|
||||||
|
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 totalSize = file.end - file.start;
|
||||||
|
readSuccessCallback.bind(this)("readAsText", enc, file.start, totalSize, function(r) {
|
||||||
|
if (this._progress === 0) {
|
||||||
|
this._result = "";
|
||||||
|
}
|
||||||
|
this._result += r;
|
||||||
|
}.bind(this));
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 totalSize = file.end - file.start;
|
||||||
|
readSuccessCallback.bind(this)("readAsDataURL", null, file.start, totalSize, function(r) {
|
||||||
|
var commaIndex = r.indexOf(',');
|
||||||
|
if (this._progress === 0) {
|
||||||
|
this._result = r;
|
||||||
|
} else {
|
||||||
|
this._result += r.substring(commaIndex + 1);
|
||||||
|
}
|
||||||
|
}.bind(this));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 totalSize = file.end - file.start;
|
||||||
|
readSuccessCallback.bind(this)("readAsBinaryString", null, file.start, totalSize, function(r) {
|
||||||
|
if (this._progress === 0) {
|
||||||
|
this._result = "";
|
||||||
|
}
|
||||||
|
this._result += r;
|
||||||
|
}.bind(this));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 totalSize = file.end - file.start;
|
||||||
|
readSuccessCallback.bind(this)("readAsArrayBuffer", null, file.start, totalSize, function(r) {
|
||||||
|
var resultArray = (this._progress === 0 ? new Uint8Array(totalSize) : new Uint8Array(this._result));
|
||||||
|
resultArray.set(new Uint8Array(r), this._progress);
|
||||||
|
this._result = resultArray.buffer;
|
||||||
|
}.bind(this));
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = FileReader;
|
||||||
|
|
||||||
|
});
|
58
platforms/ios/platform_www/plugins/cordova-plugin-file/www/FileSystem.js
vendored
Normal file
58
platforms/ios/platform_www/plugins/cordova-plugin-file/www/FileSystem.js
vendored
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
cordova.define("cordova-plugin-file.FileSystem", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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 DirectoryEntry = require('./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;
|
||||||
|
if (root) {
|
||||||
|
this.root = new DirectoryEntry(root.name, root.fullPath, this, root.nativeURL);
|
||||||
|
} else {
|
||||||
|
this.root = new DirectoryEntry(this.name, '/', this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
FileSystem.prototype.__format__ = function(fullPath, nativeUrl) {
|
||||||
|
return fullPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
FileSystem.prototype.toJSON = function() {
|
||||||
|
return "<FileSystem: " + this.name + ">";
|
||||||
|
};
|
||||||
|
|
||||||
|
// Use instead of encodeURI() when encoding just the path part of a URI rather than an entire URI.
|
||||||
|
FileSystem.encodeURIPath = function(path) {
|
||||||
|
// Because # is a valid filename character, it must be encoded to prevent part of the
|
||||||
|
// path from being parsed as a URI fragment.
|
||||||
|
return encodeURI(path).replace(/#/g, '%23');
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = FileSystem;
|
||||||
|
|
||||||
|
});
|
44
platforms/ios/platform_www/plugins/cordova-plugin-file/www/FileUploadOptions.js
vendored
Normal file
44
platforms/ios/platform_www/plugins/cordova-plugin-file/www/FileUploadOptions.js
vendored
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
cordova.define("cordova-plugin-file.FileUploadOptions", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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, httpMethod) {
|
||||||
|
this.fileKey = fileKey || null;
|
||||||
|
this.fileName = fileName || null;
|
||||||
|
this.mimeType = mimeType || null;
|
||||||
|
this.params = params || null;
|
||||||
|
this.headers = headers || null;
|
||||||
|
this.httpMethod = httpMethod || null;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = FileUploadOptions;
|
||||||
|
|
||||||
|
});
|
32
platforms/ios/platform_www/plugins/cordova-plugin-file/www/FileUploadResult.js
vendored
Normal file
32
platforms/ios/platform_www/plugins/cordova-plugin-file/www/FileUploadResult.js
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
cordova.define("cordova-plugin-file.FileUploadResult", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FileUploadResult
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
module.exports = function FileUploadResult(size, code, content) {
|
||||||
|
this.bytesSent = size;
|
||||||
|
this.responseCode = code;
|
||||||
|
this.response = content;
|
||||||
|
};
|
||||||
|
});
|
327
platforms/ios/platform_www/plugins/cordova-plugin-file/www/FileWriter.js
vendored
Normal file
327
platforms/ios/platform_www/plugins/cordova-plugin-file/www/FileWriter.js
vendored
Normal file
@ -0,0 +1,327 @@
|
|||||||
|
cordova.define("cordova-plugin-file.FileWriter", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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 exec = require('cordova/exec'),
|
||||||
|
FileError = require('./FileError'),
|
||||||
|
ProgressEvent = require('./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.localURL = file.localURL || 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.onerror = null; // When the write has failed (see errors).
|
||||||
|
};
|
||||||
|
|
||||||
|
// States
|
||||||
|
FileWriter.INIT = 0;
|
||||||
|
FileWriter.WRITING = 1;
|
||||||
|
FileWriter.DONE = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abort writing file.
|
||||||
|
*/
|
||||||
|
FileWriter.prototype.abort = function() {
|
||||||
|
// check for invalid state
|
||||||
|
if (this.readyState === FileWriter.DONE || this.readyState === FileWriter.INIT) {
|
||||||
|
throw new FileError(FileError.INVALID_STATE_ERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set error
|
||||||
|
this.error = new FileError(FileError.ABORT_ERR);
|
||||||
|
|
||||||
|
this.readyState = FileWriter.DONE;
|
||||||
|
|
||||||
|
// If abort callback
|
||||||
|
if (typeof this.onabort === "function") {
|
||||||
|
this.onabort(new ProgressEvent("abort", {"target":this}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If write end callback
|
||||||
|
if (typeof this.onwriteend === "function") {
|
||||||
|
this.onwriteend(new ProgressEvent("writeend", {"target":this}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes data to the file
|
||||||
|
*
|
||||||
|
* @param data text or blob to be written
|
||||||
|
* @param isPendingBlobReadResult {Boolean} true if the data is the pending blob read operation result
|
||||||
|
*/
|
||||||
|
FileWriter.prototype.write = function(data, isPendingBlobReadResult) {
|
||||||
|
|
||||||
|
var that=this;
|
||||||
|
var supportsBinary = (typeof window.Blob !== 'undefined' && typeof window.ArrayBuffer !== 'undefined');
|
||||||
|
var isProxySupportBlobNatively = (cordova.platformId === "windows8" || cordova.platformId === "windows");
|
||||||
|
var isBinary;
|
||||||
|
|
||||||
|
// Check to see if the incoming data is a blob
|
||||||
|
if (data instanceof File || (!isProxySupportBlobNatively && supportsBinary && data instanceof Blob)) {
|
||||||
|
var fileReader = new FileReader();
|
||||||
|
fileReader.onload = function() {
|
||||||
|
// Call this method again, with the arraybuffer as argument
|
||||||
|
FileWriter.prototype.write.call(that, this.result, true /* isPendingBlobReadResult */);
|
||||||
|
};
|
||||||
|
fileReader.onerror = function () {
|
||||||
|
// DONE state
|
||||||
|
that.readyState = FileWriter.DONE;
|
||||||
|
|
||||||
|
// Save error
|
||||||
|
that.error = this.error;
|
||||||
|
|
||||||
|
// If onerror callback
|
||||||
|
if (typeof that.onerror === "function") {
|
||||||
|
that.onerror(new ProgressEvent("error", {"target":that}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If onwriteend callback
|
||||||
|
if (typeof that.onwriteend === "function") {
|
||||||
|
that.onwriteend(new ProgressEvent("writeend", {"target":that}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// WRITING state
|
||||||
|
this.readyState = FileWriter.WRITING;
|
||||||
|
|
||||||
|
if (supportsBinary) {
|
||||||
|
fileReader.readAsArrayBuffer(data);
|
||||||
|
} else {
|
||||||
|
fileReader.readAsText(data);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark data type for safer transport over the binary bridge
|
||||||
|
isBinary = supportsBinary && (data instanceof ArrayBuffer);
|
||||||
|
if (isBinary && cordova.platformId === "windowsphone") {
|
||||||
|
// create a plain array, using the keys from the Uint8Array view so that we can serialize it
|
||||||
|
data = Array.apply(null, new Uint8Array(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Throw an exception if we are already writing a file
|
||||||
|
if (this.readyState === FileWriter.WRITING && !isPendingBlobReadResult) {
|
||||||
|
throw new FileError(FileError.INVALID_STATE_ERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// WRITING state
|
||||||
|
this.readyState = FileWriter.WRITING;
|
||||||
|
|
||||||
|
var me = this;
|
||||||
|
|
||||||
|
// If onwritestart callback
|
||||||
|
if (typeof me.onwritestart === "function") {
|
||||||
|
me.onwritestart(new ProgressEvent("writestart", {"target":me}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write file
|
||||||
|
exec(
|
||||||
|
// Success callback
|
||||||
|
function(r) {
|
||||||
|
// If DONE (cancelled), then don't do anything
|
||||||
|
if (me.readyState === FileWriter.DONE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// position always increases by bytes written because file would be extended
|
||||||
|
me.position += r;
|
||||||
|
// The length of the file is now where we are done writing.
|
||||||
|
|
||||||
|
me.length = me.position;
|
||||||
|
|
||||||
|
// DONE state
|
||||||
|
me.readyState = FileWriter.DONE;
|
||||||
|
|
||||||
|
// If onwrite callback
|
||||||
|
if (typeof me.onwrite === "function") {
|
||||||
|
me.onwrite(new ProgressEvent("write", {"target":me}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If onwriteend callback
|
||||||
|
if (typeof me.onwriteend === "function") {
|
||||||
|
me.onwriteend(new ProgressEvent("writeend", {"target":me}));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Error callback
|
||||||
|
function(e) {
|
||||||
|
// If DONE (cancelled), then don't do anything
|
||||||
|
if (me.readyState === FileWriter.DONE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DONE state
|
||||||
|
me.readyState = FileWriter.DONE;
|
||||||
|
|
||||||
|
// Save error
|
||||||
|
me.error = new FileError(e);
|
||||||
|
|
||||||
|
// If onerror callback
|
||||||
|
if (typeof me.onerror === "function") {
|
||||||
|
me.onerror(new ProgressEvent("error", {"target":me}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If onwriteend callback
|
||||||
|
if (typeof me.onwriteend === "function") {
|
||||||
|
me.onwriteend(new ProgressEvent("writeend", {"target":me}));
|
||||||
|
}
|
||||||
|
}, "File", "write", [this.localURL, data, this.position, isBinary]);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the file pointer to the location specified.
|
||||||
|
*
|
||||||
|
* If the offset is a negative number the position of the file
|
||||||
|
* pointer is rewound. If the offset is greater than the file
|
||||||
|
* size the position is set to the end of the file.
|
||||||
|
*
|
||||||
|
* @param offset is the location to move the file pointer to.
|
||||||
|
*/
|
||||||
|
FileWriter.prototype.seek = function(offset) {
|
||||||
|
// Throw an exception if we are already writing a file
|
||||||
|
if (this.readyState === FileWriter.WRITING) {
|
||||||
|
throw new FileError(FileError.INVALID_STATE_ERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!offset && offset !== 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// See back from end of file.
|
||||||
|
if (offset < 0) {
|
||||||
|
this.position = Math.max(offset + this.length, 0);
|
||||||
|
}
|
||||||
|
// Offset is bigger than file size so set position
|
||||||
|
// to the end of the file.
|
||||||
|
else if (offset > this.length) {
|
||||||
|
this.position = this.length;
|
||||||
|
}
|
||||||
|
// Offset is between 0 and file size so set the position
|
||||||
|
// to start writing.
|
||||||
|
else {
|
||||||
|
this.position = offset;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Truncates the file to the size specified.
|
||||||
|
*
|
||||||
|
* @param size to chop the file at.
|
||||||
|
*/
|
||||||
|
FileWriter.prototype.truncate = function(size) {
|
||||||
|
// Throw an exception if we are already writing a file
|
||||||
|
if (this.readyState === FileWriter.WRITING) {
|
||||||
|
throw new FileError(FileError.INVALID_STATE_ERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// WRITING state
|
||||||
|
this.readyState = FileWriter.WRITING;
|
||||||
|
|
||||||
|
var me = this;
|
||||||
|
|
||||||
|
// If onwritestart callback
|
||||||
|
if (typeof me.onwritestart === "function") {
|
||||||
|
me.onwritestart(new ProgressEvent("writestart", {"target":this}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write file
|
||||||
|
exec(
|
||||||
|
// Success callback
|
||||||
|
function(r) {
|
||||||
|
// If DONE (cancelled), then don't do anything
|
||||||
|
if (me.readyState === FileWriter.DONE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DONE state
|
||||||
|
me.readyState = FileWriter.DONE;
|
||||||
|
|
||||||
|
// Update the length of the file
|
||||||
|
me.length = r;
|
||||||
|
me.position = Math.min(me.position, r);
|
||||||
|
|
||||||
|
// If onwrite callback
|
||||||
|
if (typeof me.onwrite === "function") {
|
||||||
|
me.onwrite(new ProgressEvent("write", {"target":me}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If onwriteend callback
|
||||||
|
if (typeof me.onwriteend === "function") {
|
||||||
|
me.onwriteend(new ProgressEvent("writeend", {"target":me}));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Error callback
|
||||||
|
function(e) {
|
||||||
|
// If DONE (cancelled), then don't do anything
|
||||||
|
if (me.readyState === FileWriter.DONE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DONE state
|
||||||
|
me.readyState = FileWriter.DONE;
|
||||||
|
|
||||||
|
// Save error
|
||||||
|
me.error = new FileError(e);
|
||||||
|
|
||||||
|
// If onerror callback
|
||||||
|
if (typeof me.onerror === "function") {
|
||||||
|
me.onerror(new ProgressEvent("error", {"target":me}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If onwriteend callback
|
||||||
|
if (typeof me.onwriteend === "function") {
|
||||||
|
me.onwriteend(new ProgressEvent("writeend", {"target":me}));
|
||||||
|
}
|
||||||
|
}, "File", "truncate", [this.localURL, size]);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = FileWriter;
|
||||||
|
|
||||||
|
});
|
39
platforms/ios/platform_www/plugins/cordova-plugin-file/www/Flags.js
vendored
Normal file
39
platforms/ios/platform_www/plugins/cordova-plugin-file/www/Flags.js
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
cordova.define("cordova-plugin-file.Flags", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supplies arguments to methods that lookup or create files and directories.
|
||||||
|
*
|
||||||
|
* @param create
|
||||||
|
* {boolean} file or directory if it doesn't exist
|
||||||
|
* @param exclusive
|
||||||
|
* {boolean} used with create; if true the command will fail if
|
||||||
|
* target path exists
|
||||||
|
*/
|
||||||
|
function Flags(create, exclusive) {
|
||||||
|
this.create = create || false;
|
||||||
|
this.exclusive = exclusive || false;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Flags;
|
||||||
|
|
||||||
|
});
|
26
platforms/ios/platform_www/plugins/cordova-plugin-file/www/LocalFileSystem.js
vendored
Normal file
26
platforms/ios/platform_www/plugins/cordova-plugin-file/www/LocalFileSystem.js
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
cordova.define("cordova-plugin-file.LocalFileSystem", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.TEMPORARY = 0;
|
||||||
|
exports.PERSISTENT = 1;
|
||||||
|
|
||||||
|
});
|
43
platforms/ios/platform_www/plugins/cordova-plugin-file/www/Metadata.js
vendored
Normal file
43
platforms/ios/platform_www/plugins/cordova-plugin-file/www/Metadata.js
vendored
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
cordova.define("cordova-plugin-file.Metadata", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about the state of the file or directory
|
||||||
|
*
|
||||||
|
* {Date} modificationTime (readonly)
|
||||||
|
*/
|
||||||
|
var Metadata = function(metadata) {
|
||||||
|
if (typeof metadata == "object") {
|
||||||
|
this.modificationTime = new Date(metadata.modificationTime);
|
||||||
|
this.size = metadata.size || 0;
|
||||||
|
} else if (typeof metadata == "undefined") {
|
||||||
|
this.modificationTime = null;
|
||||||
|
this.size = 0;
|
||||||
|
} else {
|
||||||
|
/* Backwards compatiblity with platforms that only return a timestamp */
|
||||||
|
this.modificationTime = new Date(metadata);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = Metadata;
|
||||||
|
|
||||||
|
});
|
70
platforms/ios/platform_www/plugins/cordova-plugin-file/www/ProgressEvent.js
vendored
Normal file
70
platforms/ios/platform_www/plugins/cordova-plugin-file/www/ProgressEvent.js
vendored
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
cordova.define("cordova-plugin-file.ProgressEvent", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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 ProgressEvent exists in global context, use it already, otherwise use our own polyfill
|
||||||
|
// Feature test: See if we can instantiate a native ProgressEvent;
|
||||||
|
// if so, use that approach,
|
||||||
|
// otherwise fill-in with our own implementation.
|
||||||
|
//
|
||||||
|
// NOTE: right now we always fill in with our own. Down the road would be nice if we can use whatever is native in the webview.
|
||||||
|
var ProgressEvent = (function() {
|
||||||
|
/*
|
||||||
|
var createEvent = function(data) {
|
||||||
|
var event = document.createEvent('Events');
|
||||||
|
event.initEvent('ProgressEvent', false, false);
|
||||||
|
if (data) {
|
||||||
|
for (var i in data) {
|
||||||
|
if (data.hasOwnProperty(i)) {
|
||||||
|
event[i] = data[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (data.target) {
|
||||||
|
// TODO: cannot call <some_custom_object>.dispatchEvent
|
||||||
|
// need to first figure out how to implement EventTarget
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return event;
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
var ev = createEvent({type:"abort",target:document});
|
||||||
|
return function ProgressEvent(type, data) {
|
||||||
|
data.type = type;
|
||||||
|
return createEvent(data);
|
||||||
|
};
|
||||||
|
} catch(e){
|
||||||
|
*/
|
||||||
|
return function ProgressEvent(type, dict) {
|
||||||
|
this.type = type;
|
||||||
|
this.bubbles = false;
|
||||||
|
this.cancelBubble = false;
|
||||||
|
this.cancelable = false;
|
||||||
|
this.lengthComputable = false;
|
||||||
|
this.loaded = dict && dict.loaded ? dict.loaded : 0;
|
||||||
|
this.total = dict && dict.total ? dict.total : 0;
|
||||||
|
this.target = dict && dict.target ? dict.target : null;
|
||||||
|
};
|
||||||
|
//}
|
||||||
|
})();
|
||||||
|
|
||||||
|
module.exports = ProgressEvent;
|
||||||
|
|
||||||
|
});
|
29
platforms/ios/platform_www/plugins/cordova-plugin-file/www/browser/isChrome.js
vendored
Normal file
29
platforms/ios/platform_www/plugins/cordova-plugin-file/www/browser/isChrome.js
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
cordova.define("cordova-plugin-file.isChrome", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = function () {
|
||||||
|
// window.webkitRequestFileSystem and window.webkitResolveLocalFileSystemURL are available only in Chrome and
|
||||||
|
// possibly a good flag to indicate that we're running in Chrome
|
||||||
|
return window.webkitRequestFileSystem && window.webkitResolveLocalFileSystemURL;
|
||||||
|
};
|
||||||
|
|
||||||
|
});
|
66
platforms/ios/platform_www/plugins/cordova-plugin-file/www/fileSystemPaths.js
vendored
Normal file
66
platforms/ios/platform_www/plugins/cordova-plugin-file/www/fileSystemPaths.js
vendored
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
cordova.define("cordova-plugin-file.fileSystemPaths", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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 exec = require('cordova/exec');
|
||||||
|
var channel = require('cordova/channel');
|
||||||
|
|
||||||
|
exports.file = {
|
||||||
|
// Read-only directory where the application is installed.
|
||||||
|
applicationDirectory: null,
|
||||||
|
// Root of app's private writable storage
|
||||||
|
applicationStorageDirectory: null,
|
||||||
|
// Where to put app-specific data files.
|
||||||
|
dataDirectory: null,
|
||||||
|
// Cached files that should survive app restarts.
|
||||||
|
// Apps should not rely on the OS to delete files in here.
|
||||||
|
cacheDirectory: null,
|
||||||
|
// Android: the application space on external storage.
|
||||||
|
externalApplicationStorageDirectory: null,
|
||||||
|
// Android: Where to put app-specific data files on external storage.
|
||||||
|
externalDataDirectory: null,
|
||||||
|
// Android: the application cache on external storage.
|
||||||
|
externalCacheDirectory: null,
|
||||||
|
// Android: the external storage (SD card) root.
|
||||||
|
externalRootDirectory: null,
|
||||||
|
// iOS: Temp directory that the OS can clear at will.
|
||||||
|
tempDirectory: null,
|
||||||
|
// iOS: Holds app-specific files that should be synced (e.g. to iCloud).
|
||||||
|
syncedDataDirectory: null,
|
||||||
|
// iOS: Files private to the app, but that are meaningful to other applications (e.g. Office files)
|
||||||
|
documentsDirectory: null,
|
||||||
|
// BlackBerry10: Files globally available to all apps
|
||||||
|
sharedDirectory: null
|
||||||
|
};
|
||||||
|
|
||||||
|
channel.waitForInitialization('onFileSystemPathsReady');
|
||||||
|
channel.onCordovaReady.subscribe(function() {
|
||||||
|
function after(paths) {
|
||||||
|
for (var k in paths) {
|
||||||
|
exports.file[k] = paths[k];
|
||||||
|
}
|
||||||
|
channel.initializationComplete('onFileSystemPathsReady');
|
||||||
|
}
|
||||||
|
exec(after, null, 'File', 'requestAllPaths', []);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
});
|
48
platforms/ios/platform_www/plugins/cordova-plugin-file/www/fileSystems-roots.js
vendored
Normal file
48
platforms/ios/platform_www/plugins/cordova-plugin-file/www/fileSystems-roots.js
vendored
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
cordova.define("cordova-plugin-file.fileSystems-roots", function(require, exports, module) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Map of fsName -> FileSystem.
|
||||||
|
var fsMap = null;
|
||||||
|
var FileSystem = require('./FileSystem');
|
||||||
|
var exec = require('cordova/exec');
|
||||||
|
|
||||||
|
// Overridden by Android, BlackBerry 10 and iOS to populate fsMap.
|
||||||
|
require('./fileSystems').getFs = function(name, callback) {
|
||||||
|
function success(response) {
|
||||||
|
fsMap = {};
|
||||||
|
for (var i = 0; i < response.length; ++i) {
|
||||||
|
var fsRoot = response[i];
|
||||||
|
var fs = new FileSystem(fsRoot.filesystemName, fsRoot);
|
||||||
|
fsMap[fs.name] = fs;
|
||||||
|
}
|
||||||
|
callback(fsMap[name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fsMap) {
|
||||||
|
callback(fsMap[name]);
|
||||||
|
} else {
|
||||||
|
exec(success, null, "File", "requestAllFileSystems", []);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
});
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user