From 0335dbc98fc275ed71827894f468a2331d10bc6c Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Mon, 30 Jan 2012 10:18:32 +0800 Subject: [PATCH] First commit --- README.md | 36 +++++++++ examples/index.html | 16 ++++ tinycon.js | 191 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 243 insertions(+) create mode 100644 README.md create mode 100644 examples/index.html create mode 100644 tinycon.js diff --git a/README.md b/README.md new file mode 100644 index 0000000..a36ea8e --- /dev/null +++ b/README.md @@ -0,0 +1,36 @@ +# Tinycon + +A tiny library for manipulating the favicon, in particular adding alert bubbles and changing images. + + +## Documentation + +Tinycon adds a single object to the global namespace and does not require initialisation. + +### Basic Usage + + Tinycon.setBubble(6); + +### Options + +Tinycon can take a range of options to customise the look + +* width: the width of the alert bubble +* height: the height of the alert bubble +* font: a css string to use for the fontface (recommended to leave this) +* colour: the foreground font colour +* background: the alert bubble background colour + + Tinycon.setOptions({ + width: 7, + height: 9, + font: '10px arial', + colour: '#ffffff', + background: '#549A2F' + }); + + +## Download + +Releases are available for download from +[GitHub](http://github.com/tommoor/tinycon/downloads). diff --git a/examples/index.html b/examples/index.html new file mode 100644 index 0000000..df304a3 --- /dev/null +++ b/examples/index.html @@ -0,0 +1,16 @@ + + + + + + + + + + \ No newline at end of file diff --git a/tinycon.js b/tinycon.js new file mode 100644 index 0000000..5b362fa --- /dev/null +++ b/tinycon.js @@ -0,0 +1,191 @@ +/* + * Tinycon - A small library for manipulating the Favicon + * Tom Moor, http://tommoor.com + * Copyright (c) 2012 Tom Moor + * MIT Licensed + * @version 0.1 +*/ + +(function(){ + + var Tinycon = {}; + var originalFavicon = null; + var originalImage = null; + var canvas = null; + var options = {}; + var defaults = { + width: 7, + height: 9, + font: '10px arial', + colour: '#ffffff', + background: '#549A2F' + }; + + // private + var getFaviconTag = function(){ + + var links = document.getElementsByTagName('link'); + + for(var i=0; i < links.length; i++) { + if (links[i].getAttribute('rel') === 'icon') { + return links[i]; + } + } + + return false; + } + + var removeFaviconTag = function(){ + + var links = document.getElementsByTagName('link'); + var head = document.getElementsByTagName('head')[0]; + + for(var i=0; i < links.length; i++) { + if (links[i].getAttribute('rel') === 'icon') { + head.removeChild(links[i]); + } + } + } + + var getOriginalFavicon = function(){ + + if (!originalFavicon) { + var tag = getFaviconTag(); + originalFavicon = tag ? tag.getAttribute('href') : '/favicon.ico'; + } + + return originalFavicon; + } + + var getCanvas = function (){ + + if (!canvas) { + canvas = document.createElement("canvas"); + canvas.width = 16; + canvas.height = 16; + } + + return canvas; + } + + 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 log = function(message){ + if (window.console) console.log(message); + } + + var drawFavicon = function(num, colour) { + // check support + if (!getCanvas().getContext) return; + + var context = getCanvas().getContext("2d"); + var colour = colour || '#000000'; + var num = num || 0; + + originalImage = new Image(); + originalImage.onload = function() { + + // clear canvas + context.clearRect(0, 0, 16, 16); + + // draw original favicon + context.drawImage(originalImage, 0, 0); + + // draw bubble over the top + if (num > 0) drawBubble(context, num, colour); + + // refresh tag in page + refreshFavicon(); + } + originalImage.src = getOriginalFavicon(); + } + + var drawBubble = function(context, num, colour) { + + // bubble needs to be larger for double digits + var width = num > 9 ? options.width+6 : options.width; + var w = 16-width; + var h = 16-options.height; + + context.font = options.font; + context.fillStyle = options.background; + context.strokeStyle = options.background; + context.lineWidth = 1; + + // bubble + context.fillRect(w,h,width-1,options.height); + + // rounded left + context.beginPath(); + context.moveTo(w-0.5,h+1); + context.lineTo(w-0.5,15); + context.stroke(); + + // rounded right + context.beginPath(); + context.moveTo(15.5,h+1); + context.lineTo(15.5,15); + context.stroke(); + + // bottom shadow + context.beginPath(); + context.strokeStyle = "rgba(0,0,0,0.3)"; + context.moveTo(w,16); + context.lineTo(15,16); + context.stroke(); + + // number + context.fillStyle = options.colour; + context.textAlign = "right"; + context.textBaseline = "top"; + context.fillText(num,15,6); + } + + var refreshFavicon = function(){ + // check support + if (!getCanvas().getContext) return; + + setFaviconTag(getCanvas().toDataURL()); + } + + + // public + Tinycon.setOptions = function(custom){ + options = {}; + + for(var i in defaults){ + options[i] = custom[i] ? custom[i] : defaults[i]; + } + return this; + } + + Tinycon.setImage = function(url){ + originalFavicon = url; + refreshFavicon(); + return this; + } + + Tinycon.setBubble = function(num, colour){ + + // validate + if(isNaN(num)) return log('Bubble must be a number'); + + drawFavicon(num, colour); + return this; + } + + Tinycon.reset = function(){ + // todo + } + + Tinycon.setOptions(defaults); + window.Tinycon = Tinycon; +})(); \ No newline at end of file