Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
217
overrides/shared/js/contacts/import/utilities/sdcard.js
Normal file
217
overrides/shared/js/contacts/import/utilities/sdcard.js
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
'use strict';
|
||||
|
||||
var utils = window.utils || {};
|
||||
|
||||
if (!utils.sdcard) {
|
||||
var SdCard = utils.sdcard = {
|
||||
NOT_INITIALIZED: 0,
|
||||
NOT_AVAILABLE: 1,
|
||||
AVAILABLE: 2,
|
||||
SHARED: 3,
|
||||
observers: {}
|
||||
};
|
||||
|
||||
SdCard.status = SdCard.NOT_INITIALIZED;
|
||||
SdCard.deviceStorages = (navigator.getDeviceStorages ? navigator.getDeviceStorages('sdcard') : []);
|
||||
SdCard.deviceStorage = Array.isArray(SdCard.deviceStorages) &&
|
||||
SdCard.deviceStorages[0];
|
||||
|
||||
SdCard._toStatus = function toStatus(state) {
|
||||
switch (state) {
|
||||
case 'available':
|
||||
SdCard.status = SdCard.AVAILABLE;
|
||||
break;
|
||||
// NOTE: The 'SHARED' state is equivalent to NOT_AVAILABLE, since we
|
||||
// could have inconsistencies if we allow changing the sdcard content
|
||||
// meanwhile exporting/importing.
|
||||
// It's needed to have it's own state solely for showing the proper
|
||||
// message when needed
|
||||
case 'shared':
|
||||
SdCard.status = SdCard.SHARED;
|
||||
break;
|
||||
case 'unavailable':
|
||||
case 'deleted':
|
||||
SdCard.status = SdCard.NOT_AVAILABLE;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
SdCard.updateStorageState = function sd_updateStorageState(state) {
|
||||
SdCard._toStatus(state);
|
||||
|
||||
Object.keys(this.observers).forEach(function onObserver(name) {
|
||||
if (typeof(SdCard.observers[name]) === 'function') {
|
||||
SdCard.observers[name].call(null, state);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if (SdCard.deviceStorage) {
|
||||
SdCard.deviceStorage
|
||||
.addEventListener('change', function sd_deviceStorageChangeHandler(e) {
|
||||
SdCard.updateStorageState(e.reason);
|
||||
});
|
||||
|
||||
if (SdCard.status === SdCard.NOT_INITIALIZED) {
|
||||
SdCard.deviceStorage.available().onsuccess = (function(e) {
|
||||
SdCard.updateStorageState(e.target.result);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether there is a SD card inserted in the device.
|
||||
* @return {Boolean} true if sdcard available, false otherwise.
|
||||
*/
|
||||
SdCard.checkStorageCard = function sd_checkStorageCard() {
|
||||
return SdCard.status === SdCard.AVAILABLE;
|
||||
};
|
||||
|
||||
SdCard.getStatus = function(cb) {
|
||||
if (!SdCard.deviceStorage) {
|
||||
SdCard._toStatus('unavailable');
|
||||
cb(SdCard.status);
|
||||
return;
|
||||
}
|
||||
|
||||
var req = SdCard.deviceStorage.available();
|
||||
|
||||
req.onsuccess = function() {
|
||||
SdCard._toStatus(req.result);
|
||||
cb(SdCard.status);
|
||||
};
|
||||
req.onerror = function() {
|
||||
console.error('Error while determining SD Status', req.error.name);
|
||||
cb(SdCard.status);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves files that adjust to the kind specified in the
|
||||
* parameters from the SD card inserted in the device.
|
||||
*
|
||||
* @param {String[]} mimes Possible mime types of the files to be found.
|
||||
* @param {String[]} exts Possible file extensions of the files to be found.
|
||||
* @param {Function} cb Callback.
|
||||
*/
|
||||
SdCard.retrieveFiles = function retrieveFilesContent(mimes, exts, cb) {
|
||||
var fileArray = [];
|
||||
var forbiddenDirectories = ['.Trash'];
|
||||
|
||||
// getDeviceStorages('sdcard') can return more than one storage unit
|
||||
// in different order, depends on the default media storage setting,
|
||||
// so we need to iterate though them to be sure we checked the proper
|
||||
// SD Card
|
||||
var storages = (navigator.getDeviceStorages ? navigator.getDeviceStorages('sdcard') : []);
|
||||
var numberOfStorages = storages.length;
|
||||
var currentStorage = 0;
|
||||
|
||||
var cursorOnError = function() {
|
||||
cb(this.error.name);
|
||||
};
|
||||
|
||||
// RegExp that checks if a string contains any of the extensions.
|
||||
var reExt = new RegExp('.(' + exts.join('|') + ')$');
|
||||
|
||||
var cursorOnSuccess = function(e) {
|
||||
var file = e.target.result;
|
||||
// If we don't have any more files on the storage...
|
||||
if (!file) {
|
||||
// ... but we have more storages...
|
||||
if (++currentStorage < numberOfStorages) {
|
||||
// ... check the next one
|
||||
cursor = storages[currentStorage].enumerate();
|
||||
cursor.onsuccess = cursorOnSuccess;
|
||||
cursor.onerror = cursorOnError;
|
||||
} else {
|
||||
cb(null, fileArray);
|
||||
}
|
||||
} else {
|
||||
if ((mimes.indexOf(file.type) === -1) && !reExt.test(file.name)) {
|
||||
cursor.continue();
|
||||
} else {
|
||||
if (forbiddenDirectories.indexOf(file.name) === -1) {
|
||||
fileArray.push(file);
|
||||
cursor.continue();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var cursor = storages[currentStorage].enumerate();
|
||||
cursor.onsuccess = cursorOnSuccess;
|
||||
cursor.onerror = cursorOnError;
|
||||
};
|
||||
|
||||
/**
|
||||
* Incrementally extracts vcard text from a file.
|
||||
*
|
||||
* @param {Object} file File Object.
|
||||
* @param {Function} cb Function to call for each chunk of vcards retrieved
|
||||
* from the file.
|
||||
*/
|
||||
SdCard.getTextFromFile = function(file, cb) {
|
||||
if (!file) {
|
||||
return Promise.reject();
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
const END_VCARD = 'end:vcard';
|
||||
const CHUNK_SIZE = 1 * 1024 * 1024; // 1Mb
|
||||
|
||||
var fileReader = new FileReader();
|
||||
|
||||
var result = 0;
|
||||
|
||||
(function readChunk(offset, buffer) {
|
||||
if (offset >= file.size) {
|
||||
resolve(result);
|
||||
return;
|
||||
}
|
||||
var chunk = file.slice(offset, offset + CHUNK_SIZE);
|
||||
offset += CHUNK_SIZE;
|
||||
fileReader.readAsText(chunk);
|
||||
fileReader.onload = function() {
|
||||
buffer += fileReader.result;
|
||||
if (!buffer.match(/end:vcard/gi)) {
|
||||
readChunk(offset, buffer);
|
||||
return;
|
||||
}
|
||||
var lastContactInChunk =
|
||||
buffer.toLowerCase().lastIndexOf(END_VCARD) + END_VCARD.length;
|
||||
cb(buffer.substr(0, lastContactInChunk)).then(partialResult => {
|
||||
result += partialResult;
|
||||
readChunk(offset, buffer.substr(lastContactInChunk + 1));
|
||||
}).catch(error => {
|
||||
console.warn(error);
|
||||
});
|
||||
};
|
||||
})(0 /* initial offset */, '' /* initial empty buffer */);
|
||||
});
|
||||
};
|
||||
|
||||
// Subscribe a callback for sdcard changes. A name is needed
|
||||
// to refer to this observer.
|
||||
// @param {String} identifier for the observer
|
||||
// @param {Function} the callback to be invoqued on a change
|
||||
// @param {Boolean} if the callback exists, override it
|
||||
SdCard.subscribeToChanges = function(name, func, force) {
|
||||
if (this.observers[name] !== undefined && !force) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.observers[name] = func;
|
||||
return true;
|
||||
};
|
||||
|
||||
// Remove the subscription to listen to changes for the specific
|
||||
// identifier
|
||||
// @param {String} the identifier
|
||||
SdCard.unsubscribeToChanges = function(name) {
|
||||
if (this.observers[name]) {
|
||||
delete this.observers[name];
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
Loading…
Reference in a new issue