Skip to content
This repository has been archived by the owner on Nov 3, 2021. It is now read-only.

Commit

Permalink
Merge pull request #16206 from borjasalguero/dm_strings
Browse files Browse the repository at this point in the history
Update DM Strings r=kaze, arcturus
  • Loading branch information
borjasalguero committed Feb 24, 2014
2 parents d26d283 + 1e6949e commit b7b2741
Show file tree
Hide file tree
Showing 5 changed files with 199 additions and 14 deletions.
10 changes: 10 additions & 0 deletions apps/settings/js/downloads/download_item.js
Expand Up @@ -75,6 +75,16 @@ var DownloadItem = (function DownloadItem() {
li.appendChild(pInfo);
li.appendChild(progress);

// Add timestamp for updating periodically
var timestamp;
try {
timestamp = download.startTime.getTime() || (new Date()).getTime();
} catch (ex) {
timestamp = (new Date()).getTime();
console.warn(ex);
}
li.dataset.timestamp = timestamp;

return update(li, download);
};

Expand Down
88 changes: 84 additions & 4 deletions apps/settings/js/downloads/downloads_list.js
Expand Up @@ -26,13 +26,17 @@
var numberOfDownloads = 0;
var numberOfCheckedDownloads = 0;

var visibilityObserver = null;
var updateTimeInfoScheduler = null;

function _checkEmptyList() {
if (!downloadsContainer) {
return;
}
var isEmpty = (downloadsContainer.children.length === 0);

if (isEmpty) {
_stopTimeInfoUpdater();
downloadsContainer.hidden = true;
emptyDownloadsContainer.hidden = false;
} else {
Expand All @@ -51,6 +55,79 @@
}
}

function _initVisibilityObserver() {
// Init observer if is the first rendering
if (!!visibilityObserver) {
return;
}
// We have 2 cases:
// 1.- Update when the panel is visible only
visibilityObserver = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (downloadsPanel.classList.contains('current')) {
_startTimeInfoUpdater(true);
} else {
_stopTimeInfoUpdater();
}
});
});

var options = {
'attributes': true,
'attributeOldValue': true,
'attributeFilter': ['class']
};

visibilityObserver.observe(downloadsPanel, options);

// 2.-If the app is not the one shown, removing also the timer
document.addEventListener('visibilitychange', function() {
if (document.hidden) {
_stopTimeInfoUpdater();
} else {
_startTimeInfoUpdater(true);
}
});
}

function _updateTimeHeader(elem) {
var date = new Date(+elem.dataset.timestamp);
var status = elem.dataset.state;
var infoNode = elem.querySelector('.info');
LazyLoader.load(['shared/js/l10n_date.js'], function onload() {
var prettyDate = navigator.mozL10n.DateTimeFormat().fromNow(date, true);
navigator.mozL10n.localize(infoNode, 'summary', {
date: prettyDate,
status: status
});
});
}

function _updateTimeInfo() {
// Retrieve elements
var elements = downloadsContainer.querySelectorAll('[data-state]');
// Only elements which are not 'downloading' shows the date
for (var i = 0, length = elements.length; i < length; i++) {
if (elements[i].dataset.state != 'downloading') {
_updateTimeHeader(elements[i]);
}
}
}

function _startTimeInfoUpdater(forceUpdate) {
// Update first of all the time info nodes
if (typeof forceUpdate === 'boolean' && forceUpdate) {
_updateTimeInfo();
}

// Activate the scheduler
updateTimeInfoScheduler = setInterval(_updateTimeInfo, 60000);
}

function _stopTimeInfoUpdater() {
clearInterval(updateTimeInfoScheduler);
}

function _render(downloads, oncomplete) {
if (!downloadsContainer) {
return;
Expand All @@ -64,7 +141,10 @@
downloadsContainer.innerHTML = '';
// Render
downloads.forEach(_append);

// Start time updaters & observer
_initVisibilityObserver();
_startTimeInfoUpdater();
// Execute complete callback
oncomplete && oncomplete();
}

Expand All @@ -75,16 +155,16 @@

function _create(download) {
var li = DownloadItem.create(download);
if (download.state === 'downloading') {
download.onstatechange = _onDownloadStateChange;
}
download.onstatechange = _onDownloadStateChange;
li.addEventListener('click', _onDownloadAction);
return li;
}

function _prepend(download) {
if (downloadsContainer.children.length === 0) {
_append(download);
_initVisibilityObserver();
_startTimeInfoUpdater(true);
_checkEmptyList();
return;
}
Expand Down
6 changes: 5 additions & 1 deletion apps/settings/style/downloads.css
Expand Up @@ -192,7 +192,11 @@
}

#downloadList ul > li[data-state="stopped"] progress,
#downloadList ul > li[data-state="succeeded"] progress {
#downloadList ul > li[data-state="succeeded"] progress,
#downloadList ul > li[data-state="failed"] progress,
#downloadList ul > li[data-state="stopped"] progress:not([value]),
#downloadList ul > li[data-state="failed"] progress:not([value]),
#downloadList ul > li[data-state="succeeded"] progress:not([value]) {
display: none;
}

Expand Down
91 changes: 89 additions & 2 deletions apps/settings/test/unit/downloads_list_test.js
Expand Up @@ -209,6 +209,95 @@ suite('DownloadList', function() {
});
});

suite(' > update time info', function() {

test(' > timestamp is in the structure as data', function(done) {
DownloadsList.init(function() {
var downloadsContainer = document.querySelector('#downloadList ul');
for (var i = 0; i < downloadsContainer.childNodes.length; i++) {
assert.ok(downloadsContainer.childNodes[i].dataset.timestamp);
}
done();
});
});

test(' > update periodically', function(done) {
DownloadsList.init(function() {
var clock = sinon.useFakeTimers(Date.now());
var downloadsContainer = document.querySelector('#downloadList ul');
// NOTE: "downloading" elements has no info related with time
var timestamps = [], newTimestamps = [];
// Create a visibility event change
var visibilityEvent = new CustomEvent('visibilitychange');
// Force a rendering of the time labels with an event
document.dispatchEvent(visibilityEvent);
// Retrieve current time info labels
for (var i = 0; i < downloadsContainer.children.length; i++) {
var downloadEl = downloadsContainer.children[i];
if (downloadEl.dataset.state != 'downloading') {
timestamps.push(downloadEl.querySelector('.info').textContent);
}
}
// Force 'setInterval' to be executed
clock.tick(100000);

// Retrieve new time info labels
for (var i = 0; i < downloadsContainer.children.length; i++) {
var downloadEl = downloadsContainer.children[i];
if (downloadEl.dataset.state != 'downloading') {
newTimestamps.push(downloadEl.querySelector('.info').textContent);
}
}

// Each label must change, due to the time between one event and another
for (var i = 0; i < timestamps.length; i++) {
assert.isFalse(timestamps[i] === newTimestamps[i]);
}
clock.restore();
done();
});
});

test(' > update with visibility event', function(done) {

DownloadsList.init(function() {
var clock = sinon.useFakeTimers(Date.now());
var downloadsContainer = document.querySelector('#downloadList ul');
// NOTE: "downloading" elements has no info related with time
var timestamps = [], newTimestamps = [];
// Create a visibility event change
var visibilityEvent = new CustomEvent('visibilitychange');
// Dispatch the first event
document.dispatchEvent(visibilityEvent);
// Retrieve current time info labels
for (var i = 0; i < downloadsContainer.children.length; i++) {
var downloadEl = downloadsContainer.children[i];
if (downloadEl.dataset.state != 'downloading') {
timestamps.push(downloadEl.querySelector('.info').textContent);
}
}
// Move 1 sec. to the future!
clock.tick(1000);

// New event of visibility
document.dispatchEvent(visibilityEvent);
// Retrieve new time info labels
for (var i = 0; i < downloadsContainer.children.length; i++) {
var downloadEl = downloadsContainer.children[i];
if (downloadEl.dataset.state != 'downloading') {
newTimestamps.push(downloadEl.querySelector('.info').textContent);
}
}
// Each label must change, due to the time between one event and another
for (var i = 0; i < timestamps.length; i++) {
assert.isFalse(timestamps[i] === newTimestamps[i]);
}
clock.restore();
done();
});
});
});

suite(' > methods', function() {
test(' > check render with empty datastore', function(done) {
DownloadsList.init(function() {
Expand Down Expand Up @@ -370,5 +459,3 @@ suite('DownloadList', function() {
});
});
});


18 changes: 11 additions & 7 deletions apps/settings/test/unit/mock_l10n.js
@@ -1,18 +1,22 @@
/* exported MockL10n*/

'use strict';

var MockL10n = {
get: function get(key, params) {
return key;
},
localize: function localize() {},
localize: function localize(elem, l10nKey, params) {
elem.textContent = JSON.stringify(params);
},
ready: function(callback) {
callback();
},
DateTimeFormat: function() {}
};

MockL10n.DateTimeFormat.prototype = {
localeFormat: function mockLocaleFormat(time, strFormat) {
return '' + time;
DateTimeFormat: function(date) {
return {
fromNow: function(date) {
return Date.now();
}
};
}
};

0 comments on commit b7b2741

Please sign in to comment.