Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
298 lines
8.7 KiB
JavaScript
Executable file
298 lines
8.7 KiB
JavaScript
Executable file
'use strict';
|
|
|
|
/* global BaseView */
|
|
|
|
(function(exports) {
|
|
|
|
var LayoutItemView = function(list, layoutItem) {
|
|
BaseView.apply(this);
|
|
|
|
this._statusEl = null;
|
|
this._progressEl = null;
|
|
|
|
if (typeof layoutItem !== 'object') {
|
|
throw new Error('LayoutItemView: ' +
|
|
'LayoutItemView does not create a LayoutItem for itself, ' +
|
|
'please pass an approate instance as the model.');
|
|
}
|
|
|
|
this.list = list;
|
|
this._model = layoutItem;
|
|
};
|
|
|
|
LayoutItemView.prototype = Object.create(BaseView.prototype);
|
|
|
|
LayoutItemView.prototype.oninlistchange = null;
|
|
|
|
LayoutItemView.prototype.inList = undefined;
|
|
|
|
LayoutItemView.prototype.IN_LIST_INSTALLED = 0;
|
|
LayoutItemView.prototype.IN_LIST_INSTALLABLE = 1;
|
|
|
|
LayoutItemView.prototype.TEMPLATE_ID = 'installable-keyboard-list-item';
|
|
|
|
LayoutItemView.prototype.start = function() {
|
|
this._model.onerror = this._showError.bind(this);
|
|
this._model.onprogress = this._updateProgress.bind(this);
|
|
this._model.onstatechange = this._updateUI.bind(this);
|
|
this._model.oninstall = this._showEnableDialog.bind(this);
|
|
|
|
var template = document.getElementById(this.TEMPLATE_ID);
|
|
var el = this.container =
|
|
document.importNode(template.content, true).firstElementChild;
|
|
el.querySelector('.label').textContent = this._model.name;
|
|
if (this._model.nameL10nId) {
|
|
el.querySelector('.label').dataset.l10nId = this._model.nameL10nId;
|
|
}
|
|
el.addEventListener('click', this);
|
|
|
|
this._statusEl = el.querySelector('.status');
|
|
this._progressEl = el.querySelector('.progress');
|
|
|
|
this._updateUI();
|
|
};
|
|
|
|
LayoutItemView.prototype._updateProgress = function() {
|
|
var loadedSizeData = this._getHumanFileSize(this._model.downloadLoadedSize);
|
|
var totalSizeData = this._getHumanFileSize(this._model.downloadTotalSize);
|
|
this._progressEl.value = this._model.downloadLoadedSize;
|
|
this._progressEl.max = this._model.downloadTotalSize;
|
|
this._statusEl.dataset.l10nArgs =
|
|
JSON.stringify({
|
|
loadedSize: loadedSizeData.size,
|
|
loadedSizeUnit: loadedSizeData.localizedUnit,
|
|
totalSize: totalSizeData.size,
|
|
totalSizeUnit: totalSizeData.localizedUnit
|
|
});
|
|
};
|
|
|
|
LayoutItemView.prototype._updateUI = function() {
|
|
var fileSizeData;
|
|
var loadedSizeData;
|
|
var totalSizeData;
|
|
|
|
var item = this._model;
|
|
|
|
switch (item.state) {
|
|
case item.STATE_PRELOADED:
|
|
this.container.dataset.enabledAction = 'none';
|
|
this._statusEl.dataset.l10nId = 'preInstalledStatus';
|
|
fileSizeData = this._getHumanFileSize(item.fileSize);
|
|
this._statusEl.dataset.l10nArgs = JSON.stringify({
|
|
size: fileSizeData.size,
|
|
sizeUnit: fileSizeData.localizedUnit
|
|
});
|
|
this._progressEl.classList.add('hide');
|
|
this._updateList(this.IN_LIST_INSTALLED);
|
|
|
|
break;
|
|
|
|
case item.STATE_INSTALLABLE:
|
|
this.container.dataset.enabledAction = 'download';
|
|
this._statusEl.dataset.l10nId = 'installableStatus';
|
|
fileSizeData = this._getHumanFileSize(item.fileSize);
|
|
this._statusEl.dataset.l10nArgs = JSON.stringify({
|
|
size: fileSizeData.size,
|
|
sizeUnit: fileSizeData.localizedUnit
|
|
});
|
|
this._progressEl.classList.add('hide');
|
|
this._updateList(this.IN_LIST_INSTALLABLE);
|
|
|
|
break;
|
|
|
|
case item.STATE_INSTALLING_CANCELLABLE:
|
|
this.container.dataset.enabledAction = 'cancel-download';
|
|
this._statusEl.dataset.l10nId = 'downloadingStatus';
|
|
loadedSizeData = this._getHumanFileSize(item.downloadLoadedSize);
|
|
totalSizeData = this._getHumanFileSize(item.downloadTotalSize);
|
|
this._statusEl.dataset.l10nArgs =
|
|
JSON.stringify({
|
|
loadedSize: loadedSizeData.size,
|
|
loadedSizeUnit: loadedSizeData.localizedUnit,
|
|
totalSize: totalSizeData.size,
|
|
totalSizeUnit: totalSizeData.localizedUnit
|
|
});
|
|
this._progressEl.classList.remove('hide');
|
|
this._progressEl.value = item.downloadLoadedSize;
|
|
this._progressEl.max = item.downloadTotalSize;
|
|
this._updateList(this.IN_LIST_INSTALLABLE);
|
|
|
|
break;
|
|
|
|
case item.STATE_INSTALLING:
|
|
this.container.dataset.enabledAction = 'none';
|
|
this._statusEl.dataset.l10nId = 'downloadingStatus';
|
|
fileSizeData = this._getHumanFileSize(item.fileSize);
|
|
this._statusEl.dataset.l10nArgs =
|
|
JSON.stringify({
|
|
loadedSize: fileSizeData.size,
|
|
loadedSizeUnit: fileSizeData.localizedUnit,
|
|
totalSize: fileSizeData.size,
|
|
totalSizeUnit: fileSizeData.localizedUnit
|
|
});
|
|
this._progressEl.classList.remove('hide');
|
|
this._progressEl.value = this._progressEl.max = item.fileSize;
|
|
this._updateList(this.IN_LIST_INSTALLABLE);
|
|
|
|
break;
|
|
|
|
case item.STATE_INSTALLED:
|
|
this.container.dataset.enabledAction = 'remove';
|
|
this._statusEl.dataset.l10nId = 'installedStatus';
|
|
fileSizeData = this._getHumanFileSize(item.fileSize);
|
|
this._statusEl.dataset.l10nArgs = JSON.stringify({
|
|
size: fileSizeData.size,
|
|
sizeUnit: fileSizeData.localizedUnit
|
|
});
|
|
this._progressEl.classList.add('hide');
|
|
this._updateList(this.IN_LIST_INSTALLED);
|
|
|
|
break;
|
|
|
|
case item.STATE_REMOVING:
|
|
this.container.dataset.enabledAction = 'none';
|
|
this._statusEl.dataset.l10nId = 'removingStatus';
|
|
delete this._statusEl.dataset.l10nArgs;
|
|
this._progressEl.classList.add('hide');
|
|
this._updateList(this.IN_LIST_INSTALLED);
|
|
|
|
break;
|
|
}
|
|
};
|
|
|
|
LayoutItemView.prototype._showEnableDialog = function() {
|
|
this.list.confirmEnable(this._model.name).then(function(confirmed) {
|
|
if (confirmed) {
|
|
return this.list.enableLayout(this._model.id);
|
|
}
|
|
}.bind(this)).catch(function(e) {
|
|
e && console.error(e);
|
|
});
|
|
};
|
|
|
|
LayoutItemView.prototype._showError = function(errorInfo) {
|
|
switch (errorInfo.error) {
|
|
case errorInfo.ERROR_DOWNLOADERROR:
|
|
this.list.showDownloadErrorToast();
|
|
break;
|
|
|
|
case errorInfo.ERROR_INSTALLERROR:
|
|
console.error('LayoutItemView: layout installation error.');
|
|
break;
|
|
|
|
case errorInfo.ERROR_REMOVEERROR:
|
|
console.error('LayoutItemView: layout removal error.');
|
|
break;
|
|
|
|
default:
|
|
console.error('LayoutItemView: undefined onerror call,', errorInfo);
|
|
|
|
break;
|
|
}
|
|
};
|
|
|
|
LayoutItemView.prototype.handleEvent = function(evt) {
|
|
var el = evt.target;
|
|
|
|
// This is intentionally kept at minimum. We do not check if the currect state
|
|
// is applicable for certain action, nor we keep the returned promise and
|
|
// react on it.
|
|
// UI updates are all tie to state updates, and state updates only.
|
|
// We do, however, wire confirmation dialog here.
|
|
var p;
|
|
switch (el.dataset.action) {
|
|
case 'download':
|
|
p = this.list.confirmDownload().then(function(confirmed) {
|
|
if (confirmed) {
|
|
return this._model.install();
|
|
}
|
|
}.bind(this));
|
|
|
|
break;
|
|
|
|
case 'cancelDownload':
|
|
p = this._model.cancelInstall();
|
|
|
|
break;
|
|
|
|
case 'remove':
|
|
p = this.list.confirmRemoval(this._model.name).then(function(confirmed) {
|
|
if (!confirmed) {
|
|
return;
|
|
}
|
|
|
|
return this.list.disableLayout(this._model.id)
|
|
.then(function() {
|
|
return this._model.remove();
|
|
}.bind(this));
|
|
}.bind(this));
|
|
|
|
break;
|
|
}
|
|
|
|
if (p) {
|
|
p.catch(function(e) {
|
|
e && console.error(e);
|
|
});
|
|
}
|
|
};
|
|
|
|
LayoutItemView.prototype.stop = function() {
|
|
this._model.onprogress = null;
|
|
this._model.onstatechange = null;
|
|
|
|
this.container.removeEventListener('click', this);
|
|
this.container = null;
|
|
};
|
|
|
|
LayoutItemView.prototype._updateList = function(newListState) {
|
|
if (newListState === this.inList) {
|
|
return;
|
|
}
|
|
|
|
if (typeof this.inList === 'undefined') {
|
|
// First time set, don't trigger.
|
|
this.inList = newListState;
|
|
|
|
return;
|
|
}
|
|
|
|
this.inList = newListState;
|
|
if (typeof this.oninlistchange === 'function') {
|
|
this.oninlistchange();
|
|
}
|
|
};
|
|
|
|
LayoutItemView.prototype._getHumanFileSize = function(sizeInNumber) {
|
|
// XXX I actually don't know how not to use get() here.
|
|
var _ = navigator.mozL10n.get;
|
|
var sizeString = '';
|
|
var localizedUnit = '';
|
|
|
|
if (sizeInNumber > (1 << 30)) {
|
|
sizeString = (sizeInNumber / (1 << 30)).toFixed(2);
|
|
localizedUnit = _('byteUnit-GB');
|
|
} else if (sizeInNumber > (1 << 20)) {
|
|
sizeString = (sizeInNumber / (1 << 20)).toFixed(2);
|
|
localizedUnit = _('byteUnit-MB');
|
|
} else if (sizeInNumber > (1 << 10)) {
|
|
sizeString = (sizeInNumber / (1 << 10)).toFixed(2);
|
|
localizedUnit = _('byteUnit-KB');
|
|
} else {
|
|
sizeString = sizeInNumber.toFixed(2);
|
|
localizedUnit = _('byteUnit-B');
|
|
}
|
|
|
|
// Remove the zeros after decimal point,
|
|
// and the decimal point too if there isn't any thing left on the right side.
|
|
sizeString = sizeString.replace(/\.?0*$/, '');
|
|
|
|
return {
|
|
size: sizeString,
|
|
localizedUnit: localizedUnit
|
|
};
|
|
};
|
|
|
|
exports.LayoutItemView = LayoutItemView;
|
|
|
|
}(window));
|