Files
piecon/piecon.js
Lukas Zboron 9b71591aab Fix TypeError on setProgress
If there are multiple link elements and favicon is not last,
first setProgress would cause "Cannot read property 'getAttribute' of undefined"

links is now Array instead of HTMLCollection, so that it does't change while for
loop iterates through it.

Closes #17
Closes #13
Closes #11
2015-11-18 20:04:40 +01:00

190 lines
5.5 KiB
JavaScript

//
// piecon.js
//
// https://github.com/lipka/piecon
//
// Copyright (c) 2015 Lukas Lipka <lukaslipka@gmail.com>. All rights reserved.
//
(function(){
var Piecon = {};
var currentFavicon = null;
var originalFavicon = null;
var originalTitle = null;
var canvas = null;
var options = {};
var defaults = {
color: '#ff0084',
background: '#bbb',
shadow: '#fff',
fallback: false
};
var isRetina = window.devicePixelRatio > 1;
var ua = (function () {
var agent = navigator.userAgent.toLowerCase();
return function (browser) {
return agent.indexOf(browser) !== -1;
};
}());
var browser = {
ie: ua('msie'),
chrome: ua('chrome'),
webkit: ua('chrome') || ua('safari'),
safari: ua('safari') && !ua('chrome'),
mozilla: ua('mozilla') && !ua('chrome') && !ua('safari')
};
var getFaviconTag = function() {
var links = document.getElementsByTagName('link');
for (var i = 0, l = links.length; i < l; i++) {
if (links[i].getAttribute('rel') === 'icon' || links[i].getAttribute('rel') === 'shortcut icon') {
return links[i];
}
}
return false;
};
var removeFaviconTag = function() {
var links = Array.prototype.slice.call(document.getElementsByTagName('link'), 0);
var head = document.getElementsByTagName('head')[0];
for (var i = 0, l = links.length; i < l; i++) {
if (links[i].getAttribute('rel') === 'icon' || links[i].getAttribute('rel') === 'shortcut icon') {
head.removeChild(links[i]);
}
}
};
var setFaviconTag = function(url) {
removeFaviconTag();
var link = document.createElement('link');
link.type = 'image/x-icon';
link.rel = 'icon';
link.href = url;
document.getElementsByTagName('head')[0].appendChild(link);
};
var getCanvas = function () {
if (!canvas) {
canvas = document.createElement("canvas");
if (isRetina) {
canvas.width = 32;
canvas.height = 32;
} else {
canvas.width = 16;
canvas.height = 16;
}
}
return canvas;
};
var drawFavicon = function(percentage) {
var canvas = getCanvas();
var context = canvas.getContext("2d");
percentage = percentage || 0;
if (context) {
context.clearRect(0, 0, canvas.width, canvas.height);
// Draw shadow
context.beginPath();
context.moveTo(canvas.width / 2, canvas.height / 2);
context.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2), 0, Math.PI * 2, false);
context.fillStyle = options.shadow;
context.fill();
// Draw background
context.beginPath();
context.moveTo(canvas.width / 2, canvas.height / 2);
context.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, 0, Math.PI * 2, false);
context.fillStyle = options.background;
context.fill();
// Draw pie
if (percentage > 0) {
context.beginPath();
context.moveTo(canvas.width / 2, canvas.height / 2);
context.arc(canvas.width / 2, canvas.height / 2, Math.min(canvas.width / 2, canvas.height / 2) - 2, (-0.5) * Math.PI, (-0.5 + 2 * percentage / 100) * Math.PI, false);
context.lineTo(canvas.width / 2, canvas.height / 2);
context.fillStyle = options.color;
context.fill();
}
setFaviconTag(canvas.toDataURL());
}
};
var updateTitle = function(percentage) {
if (percentage > 0) {
document.title = '(' + percentage + '%) ' + originalTitle;
} else {
document.title = originalTitle;
}
};
Piecon.setOptions = function(custom) {
options = {};
for (var key in defaults){
options[key] = custom.hasOwnProperty(key) ? custom[key] : defaults[key];
}
return this;
};
Piecon.setProgress = function(percentage) {
if (!originalTitle) {
originalTitle = document.title;
}
if (!originalFavicon || !currentFavicon) {
var tag = getFaviconTag();
originalFavicon = currentFavicon = tag ? tag.getAttribute('href') : '/favicon.ico';
}
if (!isNaN(parseFloat(percentage)) && isFinite(percentage)) {
if (!getCanvas().getContext || browser.ie || browser.safari || options.fallback === true) {
// Fallback to updating the browser title if unsupported
return updateTitle(percentage);
} else if (options.fallback === 'force') {
updateTitle(percentage);
}
return drawFavicon(percentage);
}
return false;
};
Piecon.reset = function() {
if (originalTitle) {
document.title = originalTitle;
}
if (originalFavicon) {
currentFavicon = originalFavicon;
setFaviconTag(currentFavicon);
}
};
Piecon.setOptions(defaults);
if(typeof define === 'function' && define.amd) {
define(Piecon);
} else if (typeof module !== 'undefined') {
module.exports = Piecon;
} else {
window.Piecon = Piecon;
}
})();