VulpesOS/gaia/shared/js/homescreens/icon.js
OverSu b38dea0597 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.
2026-09-30 23:13:03 +02:00

137 lines
3.4 KiB
JavaScript
Executable file

'use strict';
/* global GridIconRenderer, devicePixelRatio, Promise */
(function(exports) {
const FETCH_XHR_TIMEOUT = 10000;
/**
* XHR wrapper for fetching blobs with timeout logic.
*
* @param {String} uri to fetch.
* @return {Promise[Blob]}
*/
function fetchBlob(uri) {
return new Promise(function(accept, reject) {
var xhr = new XMLHttpRequest({
mozAnon: true,
mozSystem: true
});
xhr.open('GET', uri, true);
xhr.responseType = 'blob';
xhr.timeout = FETCH_XHR_TIMEOUT;
xhr.send();
xhr.onload = function() {
var status = xhr.status;
if (status !== 0 && status !== 200) {
reject(
new Error('Got HTTP status ' + status + ' trying to load ' + uri)
);
return;
}
accept(xhr.response);
};
xhr.onerror = xhr.ontimeout = function() {
reject(new Error('Error while HTTP GET: ', uri));
};
});
}
/**
* Represents a generic icon.
*
* @param {DOMElement} The DOM element.
* @param {String} icon uri.
*/
function Icon(elem, uri) {
this.elem = elem;
this.uri = uri;
}
Icon.prototype = {
/**
* The size icon by default.
*/
get size() {
return this._size || 40;
},
set size(size) {
this._size = size || this.size;
var style = this.elem.style;
var sizeInRems = (this._size / 10) + 'rem';
style.backgroundSize = style.width = style.height = sizeInRems;
},
/**
* It renders the icon. If the URI of the icon is not defined or there is an
* error fetching this one, the icon by default will be displayed if it is
* defined in the stylesheet.
*
* @param {Object} It defines two optional parameters. "size" which defines
* the size of the icon and "type" that describes how the
* icon will be rendered ('clip', 'favicon' or 'standard').
* See GridIconRenderer.
*/
render: function render(options) {
options = options || {};
var uri = this.uri;
this.size = options.size;
if (!uri) {
return;
}
fetchBlob(uri).then(function(blob) {
this.renderBlob(blob, options);
}.bind(this));
},
renderBlob: function renderBlob(blob, options) {
options = options || {};
var style = this.elem.style;
this.size = options.size;
var img = new Image();
img.src = URL.createObjectURL(blob);
var size = this.size;
img.onload = () => {
var renderer = new GridIconRenderer({
grid: {
layout: {
get gridIconSize() {
return size;
},
get gridMaxIconSize() {
return size * devicePixelRatio;
}
}
}
});
var type = options.type || GridIconRenderer.TYPE.FAVICON;
renderer[type](img).then((blob) => {
var url = URL.createObjectURL(blob);
var imageUrl = 'url(' + url + ')';
style.backgroundImage = imageUrl;
if (options.onLoad) {
options.onLoad(blob);
}
});
URL.revokeObjectURL(img.src);
};
img.onerror = () => {
if (options.onerror) {
options.onerror();
}
};
}
};
exports.Icon = Icon;
}(window));