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
149
gaia/apps/download/js/pick.js
Executable file
149
gaia/apps/download/js/pick.js
Executable file
|
|
@ -0,0 +1,149 @@
|
|||
'use strict';
|
||||
|
||||
/* global DownloadStore, DownloadFormatter, DownloadHelper, LazyLoader */
|
||||
|
||||
/*
|
||||
* This library implements a picker activity for downloaded files.
|
||||
*
|
||||
* How it works:
|
||||
*
|
||||
* var activity = new MozActivity({
|
||||
* name: 'pick',
|
||||
* data: {
|
||||
* type: 'application/*'
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* ... and returns an object like this:
|
||||
*
|
||||
* activity.onsuccess = function(e) {
|
||||
* console.log('Name of the file:', activity.result.name);
|
||||
* console.log('Mime type:', activity.result.type);
|
||||
* console.log('Binary content:', activity.result.blob);
|
||||
* console.log('File path:', activity.result.path);
|
||||
* console.log('File size in bytes:', activity.result.size);
|
||||
* };
|
||||
*/
|
||||
|
||||
(function(exports) {
|
||||
|
||||
const CHUNK_SIZE = 10;
|
||||
|
||||
function DownloadPicker() {
|
||||
this.header = document.querySelector('#header');
|
||||
this.list = document.querySelector('#downloads ul');
|
||||
// It holds download objects indexed by id.
|
||||
this.downloads = Object.create(null);
|
||||
|
||||
navigator.mozSetMessageHandler('activity', this.handleActivity.bind(this));
|
||||
}
|
||||
|
||||
DownloadPicker.prototype = {
|
||||
handleActivity: function(activity) {
|
||||
switch (activity.source.name) {
|
||||
case 'pick':
|
||||
this.activity = activity;
|
||||
this.attachActionHandlers();
|
||||
this.renderList();
|
||||
break;
|
||||
|
||||
default:
|
||||
activity.postError('name not supported');
|
||||
}
|
||||
},
|
||||
|
||||
renderList: function() {
|
||||
DownloadStore.getAll().onsuccess = (event) => {
|
||||
var result = event.target.result;
|
||||
if (!Array.isArray(result)) {
|
||||
result = [result];
|
||||
}
|
||||
// Painting downloads with reverse insertion order (the last the
|
||||
// most recent).
|
||||
var items = result.reverse();
|
||||
// If document.body.dataset.downloads === 0 the UI will show a message
|
||||
// telling user that there is not downloads.
|
||||
var total = document.body.dataset.downloads = items.length;
|
||||
this.renderFragment(items, 0, total);
|
||||
};
|
||||
},
|
||||
|
||||
renderFragment: function(items, from, total) {
|
||||
var target = document.createDocumentFragment();
|
||||
var idx = from;
|
||||
for (; idx < from + CHUNK_SIZE && idx < total; idx++) {
|
||||
this.appendDownload(items[idx], target);
|
||||
}
|
||||
|
||||
this.list.appendChild(target);
|
||||
(idx < total) && setTimeout(() => {
|
||||
this.renderFragment(items, idx, total);
|
||||
});
|
||||
},
|
||||
|
||||
appendDownload: function(download, target) {
|
||||
var id = download.id;
|
||||
if (this.downloads[id]) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.downloads[id] = download;
|
||||
|
||||
var item = document.createElement('li');
|
||||
// This parameter lets us know which item was clicked in the list
|
||||
item.dataset.id = id;
|
||||
|
||||
// File name
|
||||
var pFileName = document.createElement('p');
|
||||
pFileName.classList.add('fileName');
|
||||
pFileName.textContent = DownloadFormatter.getFileName(download);
|
||||
|
||||
// Additional information (start time and file size in bytes)
|
||||
var pInfo = document.createElement('p');
|
||||
pInfo.classList.add('info');
|
||||
DownloadFormatter.getDate(download, (date) => {
|
||||
DownloadFormatter.getTotalSize(download).then(totalSize => {
|
||||
navigator.mozL10n.setAttributes(pInfo, 'summary', {
|
||||
date: date,
|
||||
status: totalSize
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
item.appendChild(pFileName);
|
||||
item.appendChild(pInfo);
|
||||
target.appendChild(item);
|
||||
},
|
||||
|
||||
attachActionHandlers: function() {
|
||||
this.header.addEventListener('action', () => {
|
||||
// closing the picker activity
|
||||
this.activity.postError('cancelled');
|
||||
});
|
||||
|
||||
this.list.addEventListener('click', (event) => {
|
||||
var download = this.downloads[event.target.dataset.id];
|
||||
download && this.pick(download);
|
||||
});
|
||||
},
|
||||
|
||||
pick: function(download) {
|
||||
// download was selected by the user
|
||||
LazyLoader.load(['shared/js/mime_mapper.js',
|
||||
'shared/js/download/download_helper.js'], () => {
|
||||
var req = DownloadHelper.info(download);
|
||||
|
||||
req.onsuccess = (event) => {
|
||||
this.activity.postResult(event.target.result);
|
||||
};
|
||||
|
||||
req.onerror = (event) => {
|
||||
DownloadHelper.handlerError(req.error, download);
|
||||
};
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
exports.downloadPicker = new DownloadPicker();
|
||||
|
||||
}(window));
|
||||
18
gaia/apps/download/jsdoc.json
Executable file
18
gaia/apps/download/jsdoc.json
Executable file
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "download",
|
||||
"tags": {
|
||||
"dictionaries": ["jsdoc"]
|
||||
},
|
||||
"source": {
|
||||
"include": ["apps/download/js/**/*.js"]
|
||||
},
|
||||
"plugins": [
|
||||
"plugins/markdown",
|
||||
"plugins/summarize"
|
||||
],
|
||||
"opts": {
|
||||
"private": true,
|
||||
"recurse": true,
|
||||
"destination": "docs/download"
|
||||
}
|
||||
}
|
||||
1
gaia/apps/download/locales/download.en-US.properties
Executable file
1
gaia/apps/download/locales/download.en-US.properties
Executable file
|
|
@ -0,0 +1 @@
|
|||
select-download = Select download
|
||||
60
gaia/apps/download/manifest.webapp
Executable file
60
gaia/apps/download/manifest.webapp
Executable file
|
|
@ -0,0 +1,60 @@
|
|||
{
|
||||
"name": "Downloads",
|
||||
"description": "Gaia Download Picker",
|
||||
"type": "certified",
|
||||
"role": "system",
|
||||
"orientation": "default",
|
||||
"developer": {
|
||||
"name": "The Gaia Team",
|
||||
"url": "https://github.com/mozilla-b2g/gaia"
|
||||
},
|
||||
"permissions": {
|
||||
"device-storage:pictures": {
|
||||
"access": "readonly"
|
||||
},
|
||||
"device-storage:music": {
|
||||
"access": "readonly"
|
||||
},
|
||||
"device-storage:videos": {
|
||||
"access": "readonly"
|
||||
},
|
||||
"device-storage:sdcard": {
|
||||
"access": "readonly"
|
||||
},
|
||||
"moz-extremely-unstable-and-will-change-webcomponents": {}
|
||||
},
|
||||
"activities": {
|
||||
"pick": {
|
||||
"filters": {
|
||||
"type": "application/*"
|
||||
},
|
||||
"disposition": "inline",
|
||||
"returnValue": true,
|
||||
"href": "/pick.html"
|
||||
}
|
||||
},
|
||||
"datastores-access": {
|
||||
"download_store": {
|
||||
"readonly": true,
|
||||
"description": "Stores download finished"
|
||||
}
|
||||
},
|
||||
"icons": {
|
||||
"84": "/style/icons/download_84.png",
|
||||
"126": "/style/icons/download_126.png",
|
||||
"142": "/style/icons/download_142.png",
|
||||
"189": "/style/icons/download_189.png",
|
||||
"284": "/style/icons/download_284.png"
|
||||
},
|
||||
"locales": {
|
||||
"en-US": {
|
||||
"name": "Downloads",
|
||||
"description": "Gaia Download Picker"
|
||||
},
|
||||
"fr": {
|
||||
"name": "Téléchargements",
|
||||
"description": "Sélection de téléchargements de Gaia"
|
||||
}
|
||||
},
|
||||
"default_locale": "en-US"
|
||||
}
|
||||
10
gaia/apps/download/package.json
Executable file
10
gaia/apps/download/package.json
Executable file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"webide": {
|
||||
"prepackage": {
|
||||
"command": "make",
|
||||
"env": ["APP=download"],
|
||||
"cwd": "../.."
|
||||
},
|
||||
"packageDir": "../../build_stage/download/"
|
||||
}
|
||||
}
|
||||
61
gaia/apps/download/pick.html
Executable file
61
gaia/apps/download/pick.html
Executable file
|
|
@ -0,0 +1,61 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
|
||||
<meta charset="utf-8">
|
||||
<title>Download Picker</title>
|
||||
|
||||
<!-- Localization -->
|
||||
<meta name="defaultLanguage" content="en-US">
|
||||
<meta name="availableLanguages" content="en-US">
|
||||
<link rel="localization" href="shared/locales/date/date.{locale}.properties">
|
||||
<link rel="localization" href="shared/locales/download/download.{locale}.properties">
|
||||
<link rel="localization" href="shared/elements/gaia_menu/locales/gaia_menu.{locale}.properties">
|
||||
<link rel="localization" href="locales/download.{locale}.properties">
|
||||
<script type="text/javascript" src="shared/js/l10n.js"></script>
|
||||
<script defer type="text/javascript" src="shared/js/moz_intl.js"></script>
|
||||
|
||||
<!-- Web Components -->
|
||||
<script defer src="shared/elements/config.js"></script>
|
||||
<!-- <link rel="stylesheet" type="text/css" href="shared/elements/gaia-icons/gaia-icons.css" /> -->
|
||||
<link rel="stylesheet" type="text/css" href="shared/elements/gaia-theme/gaia-theme.css">
|
||||
<script defer src="shared/elements/gaia-header/dist/gaia-header.js"></script>
|
||||
<!-- <script defer src="shared/js/component_utils.js"></script> -->
|
||||
<!-- <script defer src="shared/elements/gaia_menu/script.js"></script> -->
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="shared/style/lists.css">
|
||||
<link rel="stylesheet" href="style/pick.css">
|
||||
|
||||
<script type="text/javascript" defer src="shared/js/lazy_loader.js"></script>
|
||||
<script type="text/javascript" defer src="shared/js/download/download_store.js"></script>
|
||||
<!-- <script type="text/javascript" defer src="shared/js/mime_mapper.js"></script> -->
|
||||
<!-- <script type="text/javascript" defer src="shared/js/download/download_ui.js"></script> -->
|
||||
<!-- <script type="text/javascript" defer src="shared/js/download/download_helper.js"></script> -->
|
||||
<script type="text/javascript" defer src="shared/js/download/download_formatter.js"></script>
|
||||
|
||||
<!-- Specific code -->
|
||||
<script type="text/javascript" defer src="js/pick.js"></script>
|
||||
|
||||
<!-- Error messages -->
|
||||
<link rel="stylesheet" type="text/css" href="shared/style/buttons.css">
|
||||
<link rel="stylesheet" type="text/css" href="shared/style/confirm.css">
|
||||
</head>
|
||||
|
||||
<body class="theme-media">
|
||||
<section role="region" class="skin-dark">
|
||||
<gaia-header ignore-dir id="header" action="close">
|
||||
<h1 data-l10n-id="select-download"></h1>
|
||||
</gaia-header>
|
||||
|
||||
<section id="no-downloads">
|
||||
<span></span>
|
||||
<span data-l10n-id="no-downloads"></span>
|
||||
</section>
|
||||
|
||||
<section id="downloads" data-type="list" class="active">
|
||||
<ul>
|
||||
</ul>
|
||||
</section>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
BIN
gaia/apps/download/style/icons/download_126.png
Executable file
BIN
gaia/apps/download/style/icons/download_126.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
BIN
gaia/apps/download/style/icons/download_142.png
Executable file
BIN
gaia/apps/download/style/icons/download_142.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 5.9 KiB |
BIN
gaia/apps/download/style/icons/download_189.png
Executable file
BIN
gaia/apps/download/style/icons/download_189.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 4.7 KiB |
BIN
gaia/apps/download/style/icons/download_284.png
Executable file
BIN
gaia/apps/download/style/icons/download_284.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 8.5 KiB |
BIN
gaia/apps/download/style/icons/download_84.png
Executable file
BIN
gaia/apps/download/style/icons/download_84.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 3.2 KiB |
63
gaia/apps/download/style/pick.css
Executable file
63
gaia/apps/download/style/pick.css
Executable file
|
|
@ -0,0 +1,63 @@
|
|||
html, body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
body > section {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* No downloads message */
|
||||
|
||||
#no-downloads {
|
||||
height: calc(100% - 5rem);
|
||||
text-align: center;
|
||||
display: none;
|
||||
}
|
||||
|
||||
body[data-downloads="0"] #no-downloads {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#no-downloads span:first-child {
|
||||
height: 100%;
|
||||
display: inline-block;
|
||||
width: 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
#no-downloads span:nth-child(2) {
|
||||
font-size: 1.8rem;
|
||||
color: #1CABCB;
|
||||
}
|
||||
|
||||
/* List of downloads */
|
||||
|
||||
#downloads {
|
||||
height: calc(100% - 5rem);
|
||||
font-weight: 400;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#downloads ul {
|
||||
overflow-y: auto;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* Only <li> elements are touchable */
|
||||
#downloads li p {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#downloads li .fileName {
|
||||
padding: 1rem 6rem 1rem 3.5rem;
|
||||
}
|
||||
|
||||
#downloads li .info {
|
||||
font-size: 1.2rem;
|
||||
padding: 0 6rem 0 3.5rem;
|
||||
}
|
||||
27
gaia/apps/download/test/build/integration/download_test.js
Executable file
27
gaia/apps/download/test/build/integration/download_test.js
Executable file
|
|
@ -0,0 +1,27 @@
|
|||
'use strict';
|
||||
|
||||
/* jshint node: true, mocha: true */
|
||||
/* global suiteSetup */
|
||||
|
||||
var helper = require('helper');
|
||||
|
||||
suite('Download tests', function() {
|
||||
suiteSetup(helper.cleanupWorkspace);
|
||||
teardown(helper.cleanupWorkspace);
|
||||
|
||||
test('APP=download make', function(done) {
|
||||
helper.exec('APP=download make', function(error, stdout, stderr) {
|
||||
helper.checkError(error, stdout, stderr);
|
||||
|
||||
var zipPath = process.cwd() +
|
||||
'/profile/webapps/download.gaiamobile.org/application.zip';
|
||||
var checkList = ['manifest.webapp'];
|
||||
|
||||
checkList.forEach(function(filePath) {
|
||||
helper.checkFilePathInZip(zipPath, filePath);
|
||||
});
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
165
gaia/apps/download/test/unit/pick_test.js
Executable file
165
gaia/apps/download/test/unit/pick_test.js
Executable file
|
|
@ -0,0 +1,165 @@
|
|||
'use strict';
|
||||
|
||||
/* global MockL10n, loadBodyHTML, DownloadStore, downloadPicker,
|
||||
DownloadFormatter, MockMozIntl */
|
||||
/* global require, requireApp, suite, suiteTeardown, suiteSetup, test, assert,
|
||||
MocksHelper, sinon */
|
||||
|
||||
require('/shared/test/unit/load_body_html_helper.js');
|
||||
require('/shared/js/download/download_store.js');
|
||||
require('/shared/js/download/download_formatter.js');
|
||||
require('/shared/test/unit/mocks/mock_navigator_moz_set_message_handler.js');
|
||||
require('/shared/test/unit/mocks/mock_l10n.js');
|
||||
require('/shared/test/unit/mocks/mock_moz_intl.js');
|
||||
require('/shared/test/unit/mocks/mock_lazy_loader.js');
|
||||
|
||||
var mocksHelperForDownloadPicker = new MocksHelper([
|
||||
'LazyLoader'
|
||||
]).init();
|
||||
|
||||
suite('pick.js >', function() {
|
||||
|
||||
var realSetMessageHandler = null;
|
||||
var realL10n = null;
|
||||
var realMozIntl = null;
|
||||
var downloads = [];
|
||||
|
||||
function createSource(name, type) {
|
||||
return {
|
||||
name: name,
|
||||
data: {
|
||||
type: type
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function runActivity(data) {
|
||||
navigator.mozSetMessageHandler.mMessageHandlers.activity(data);
|
||||
}
|
||||
|
||||
mocksHelperForDownloadPicker.attachTestHelpers();
|
||||
|
||||
suiteSetup(function(done) {
|
||||
realL10n = navigator.mozL10n;
|
||||
navigator.mozL10n = MockL10n;
|
||||
realMozIntl = window.mozIntl;
|
||||
window.mozIntl = MockMozIntl;
|
||||
realSetMessageHandler = navigator.mozSetMessageHandler;
|
||||
navigator.mozSetMessageHandler = window.MockNavigatormozSetMessageHandler;
|
||||
navigator.mozSetMessageHandler.mSetup();
|
||||
loadBodyHTML('/pick.html');
|
||||
sinon.stub(DownloadStore, 'getAll', function() {
|
||||
return {
|
||||
set onsuccess(cb) {
|
||||
cb({ target: { result: downloads }});
|
||||
}
|
||||
};
|
||||
});
|
||||
requireApp('download/js/pick.js', done);
|
||||
});
|
||||
|
||||
suiteTeardown(function() {
|
||||
navigator.mozL10n = realL10n;
|
||||
navigator.mozSetMessageHandler.mTeardown();
|
||||
navigator.mozSetMessageHandler = realSetMessageHandler;
|
||||
window.mozIntl = realMozIntl;
|
||||
DownloadStore.getAll.restore();
|
||||
});
|
||||
|
||||
suite('Initialization >', function() {
|
||||
test(' download picker ready ', function() {
|
||||
var handlers = navigator.mozSetMessageHandler.mMessageHandlers;
|
||||
assert.equal(Object.keys(handlers).length, 1);
|
||||
assert.isFunction(handlers.activity);
|
||||
});
|
||||
});
|
||||
|
||||
suite('No downloads >', function() {
|
||||
test(' document.body.dataset.downloads is 0', function() {
|
||||
runActivity({
|
||||
source: createSource('pick', 'application/*')
|
||||
});
|
||||
|
||||
assert.equal(document.body.dataset.downloads, 0);
|
||||
});
|
||||
});
|
||||
|
||||
suite('Downloads >', function() {
|
||||
|
||||
suiteSetup(function() {
|
||||
downloads = [
|
||||
{
|
||||
id: '1',
|
||||
startTime: new Date(),
|
||||
path: '/music.mp3'
|
||||
}, {
|
||||
id: '2',
|
||||
startTime: new Date(),
|
||||
path: '/image.gif'
|
||||
}
|
||||
];
|
||||
|
||||
runActivity({
|
||||
source: createSource('pick', 'application/*')
|
||||
});
|
||||
});
|
||||
|
||||
suiteTeardown(function() {
|
||||
downloadPicker.pick.restore();
|
||||
});
|
||||
|
||||
function checkItem(download) {
|
||||
var item = downloadPicker.list.querySelector('li[data-id="' +
|
||||
download.id + '"]');
|
||||
assert.equal(item.querySelector('.fileName').textContent,
|
||||
DownloadFormatter.getFileName(download));
|
||||
}
|
||||
|
||||
test(' rendered list', function() {
|
||||
assert.equal(document.body.dataset.downloads, downloads.length);
|
||||
assert.equal(downloadPicker.list.querySelectorAll('li').length,
|
||||
downloads.length);
|
||||
|
||||
checkItem(downloads[0]);
|
||||
checkItem(downloads[1]);
|
||||
});
|
||||
|
||||
test(' click an item', function() {
|
||||
var expectedDownload = downloads[0];
|
||||
sinon.stub(downloadPicker, 'pick', function(download) {
|
||||
assert.equal(download, expectedDownload);
|
||||
return {};
|
||||
});
|
||||
|
||||
var item = downloadPicker.list.querySelector('li[data-id="' +
|
||||
expectedDownload.id + '"]');
|
||||
item.click();
|
||||
});
|
||||
});
|
||||
|
||||
suite('Cancel action >', function() {
|
||||
test(' clicking on cross icon', function() {
|
||||
runActivity({
|
||||
source: createSource('pick', 'application/*'),
|
||||
postError: function(result) {
|
||||
assert.equal(result, 'cancelled');
|
||||
}
|
||||
});
|
||||
|
||||
downloadPicker.header.dispatchEvent(new CustomEvent('action'));
|
||||
});
|
||||
});
|
||||
|
||||
suite('Error >', function() {
|
||||
test(' name not supported', function() {
|
||||
// "share" activities are not supported
|
||||
runActivity({
|
||||
source: createSource('share', 'application/*'),
|
||||
postError: function(result) {
|
||||
assert.equal(result, 'name not supported');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
4
gaia/apps/download/test/unit/setup.js
Executable file
4
gaia/apps/download/test/unit/setup.js
Executable file
|
|
@ -0,0 +1,4 @@
|
|||
'use strict';
|
||||
|
||||
/* global require */
|
||||
require('/shared/test/unit/mocks/mocks_helper.js');
|
||||
Loading…
Reference in a new issue