Files
qt5-legatus-legacy/Lts/Tools/TimelineOverview/views/static/libarys/favicon/favloader.min.js
T
2026-08-13 18:33:10 +02:00

299 lines
11 KiB
JavaScript
Executable File

/**@license
*
* favloader v. 0.4.4
*
* Vanilla JavaScript library for loading animation in favicon
*
* Copyright (c) 2018-2019 Jakub T. Jankiewicz <https://jcubic.pl/me>
* Released under the MIT license
*
* Build: Sat, 22 May 2021 11:37:31 +0000
*/
/* global define, module, global, Worker, Blob, BlobBuilder, setTimeout, parseGIF */
(function(factory) {
var root = typeof window !== 'undefined' ? window : global;
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
// istanbul ignore next
define([], factory);
} else if (typeof module === 'object' && module.exports) {
// Node/CommonJS
module.exports = factory();
} else {
// Browser
// istanbul ignore next
root.favloader = factory();
}
})(function(undefined) {
// we use web worker to trigger interval since browser main thread is limited
// when tab is not active
function fworker(fn) {
// ref: https://stackoverflow.com/a/10372280/387194
var str = '(' + fn.toString() + ')()';
var URL = window.URL || window.webkitURL;
var blob;
try {
blob = new Blob([str], {type: 'application/javascript'});
} catch (e) { // Backwards-compatibility
window.BlobBuilder = window.BlobBuilder ||
window.WebKitBlobBuilder ||
window.MozBlobBuilder;
blob = new BlobBuilder();
blob.append(str);
blob = blob.getBlob();
}
return new Worker(URL.createObjectURL(blob));
}
// ----------------------------------------------------------------------------------
var interval = (function() {
var worker = fworker(function() {
// rAF polyfil without setTimeout, ref: https://gist.github.com/paulirish/1579671
var vendors = ['ms', 'moz', 'webkit', 'o'];
for(var x = 0; x < vendors.length && !self.requestAnimationFrame; ++x) {
self.requestAnimationFrame = self[vendors[x]+'RequestAnimationFrame'];
self.cancelAnimationFrame = self[vendors[x]+'CancelAnimationFrame']
|| self[vendors[x]+'CancelRequestAnimationFrame'];
}
var raf = {};
self.addEventListener('message', function(response) {
var data = response.data;
var id = data.id;
if (data.type !== 'RPC' || id === null) {
return;
}
if (data.method == 'setInterval') {
var interval_id = data.params[0];
if (typeof interval_id === 'number') {
raf[interval_id] = self.setInterval(function() {
self.postMessage({ type: 'interval', id: interval_id });
}, data.params[1]);
self.postMessage({ type: 'RPC', id: id, result: interval_id });
} else {
self.postMessage({
type: 'RPC',
id: id,
result: null,
error: 'Invalid Argument, expected number'
});
}
} else if (data.method == 'clearInterval') {
self.clearInterval(raf[data.params[0]]);
delete raf[data.params[0]];
}
});
});
var callbacks = {};
var rpc = (function() {
var id = 0;
return function rpc(method, params) {
var _id = ++id;
return new Promise(function(resolve, reject) {
worker.addEventListener('message', function handler(response) {
var data = response.data;
if (data && data.type === 'RPC' && data.id === _id) {
if (data.error) {
reject(data.error);
} else {
resolve(data.result);
}
worker.removeEventListener('message', handler);
}
});
worker.postMessage({ type: 'RPC', method: method, id: _id, params: params });
});
};
})();
worker.addEventListener('message', function(response) {
var data = response.data;
if (data && data.type === 'interval' && callbacks[data.id]) {
callbacks[data.id]();
}
});
return {
set: function(fn, interval) {
var interval_id = Date.now();
callbacks[interval_id] = fn;
rpc('setInterval', [interval_id, interval]);
return interval_id;
},
clear: function(id) {
delete callbacks[id];
return rpc('clearInterval', [id]);
}
};
})();
// ----------------------------------------------------------------------------------
var hidden, visibilityChange;
if (typeof document.hidden !== "undefined") { // Opera 12.10 and Firefox 18 and later support
hidden = "hidden";
visibilityChange = "visibilitychange";
} else if (typeof document.msHidden !== "undefined") {
hidden = "msHidden";
visibilityChange = "msvisibilitychange";
} else if (typeof document.webkitHidden !== "undefined") {
hidden = "webkitHidden";
visibilityChange = "webkitvisibilitychange";
}
// ----------------------------------------------------------------------------------
function warn(message) {
if (console && console.warn) {
console.warn(message);
} else {
setTimeout(function() {
throw new Error(message);
}, 0);
}
}
// ----------------------------------------------------------------------------------
var ctx,
c,
link,
icon,
id,
progress = 0,
duration,
initialized,
settings,
gif,
type,
initial_turns = -.25,
interval_id,
step;
// ----------------------------------------------------------------------------------
function init(options) {
if (document.readyState !== "complete") {
setTimeout(init.bind(this, options), 100);
return;
}
settings = Object.assign({
size: 16,
radius: 6,
thickness: 2,
color: '#0F60A8',
duration: 5000
}, options);
if (!link) {
link = document.querySelector('link[rel*="icon"]');
if (!link) {
link = document.createElement('link');
link.setAttribute('rel', 'icon');
document.head.appendChild(link);
warn("No default icon found, restore state will not work");
} else {
icon = link.getAttribute('href');
type = link.getAttribute('type');
}
}
clear();
if (settings.gif) {
if (typeof parseGIF === 'undefined') {
throw new Error('parseGIF not defined, please include parseGIF.js file');
}
parseGIF(settings.gif).then(function(data) {
gif = data;
});
} else {
if (!c) {
c = document.createElement('canvas');
}
c.width = c.height = settings.size;
ctx = c.getContext('2d');
ctx.lineCap = "round";
ctx.lineWidth = settings.thickness;
ctx.strokeStyle = settings.color;
duration = settings.duration;
}
initialized = true;
}
// ----------------------------------------------------------------------------------
function clear() {
if (interval_id) {
interval.clear(interval_id);
interval_id = null;
}
}
// ----------------------------------------------------------------------------------
function restore() {
if (icon) {
link.setAttribute('href', icon + '?' + Date.now());
link.setAttribute('type', type);
} else if (link) {
link.parentNode.removeChild(link);
}
clear();
}
// ----------------------------------------------------------------------------------
function animate() {
if (!initialized) {
setTimeout(animate, 100);
return;
}
if (interval_id) {
return;
}
progress = 0;
if (settings.gif && parseGIF) {
if (!gif) {
setTimeout(animate, 100);
return;
}
interval_id = interval.set(animateGIF, 300);
} else {
interval_id = interval.set(draw, 300);
}
}
// ----------------------------------------------------------------------------------
function turn(x) {
return (x + initial_turns) * 2 * Math.PI;
}
// ----------------------------------------------------------------------------------
function animateGIF() {
progress++;
if (progress >= gif.uris.length) {
progress = 0;
}
update(gif.uris[progress]);
}
// ----------------------------------------------------------------------------------
function arcStart(pos) {
return turn(pos + initial_turns) + turn(Math.max(0, pos * 2 - 1));
}
// ----------------------------------------------------------------------------------
function arcEnd(pos) {
return turn(pos + initial_turns) + turn(Math.min(1, pos * 2));
}
// ----------------------------------------------------------------------------------
function update(dataURI) {
var newIcon, icon = document.querySelector('link[rel*="icon"]');
(newIcon = icon.cloneNode(true)).setAttribute('href', dataURI);
icon.parentNode.replaceChild(newIcon, icon);
link = newIcon;
}
// ----------------------------------------------------------------------------------
function draw() {
ctx.clearRect(0, 0, settings.size, settings.size);
if (typeof settings.frame === 'function') {
settings.frame(ctx);
} else {
var position = progress % duration / duration;
ctx.beginPath();
var center = Math.round(settings.size / 2);
ctx.arc(center, center, settings.radius, arcStart(position), arcEnd(position));
ctx.stroke();
}
update(ctx.canvas.toDataURL());
progress += duration / 100;
}
// ----------------------------------------------------------------------------------
return {
init: init,
start: animate,
stop: restore,
version: '0.4.4'
};
});