From 017a3c1cbd3e64d7d4d25453ef705f1c5f7ad1c1 Mon Sep 17 00:00:00 2001 From: Eduardo de Matos Silva Date: Sat, 5 Jan 2013 13:52:45 -0200 Subject: [PATCH 01/41] add AMD support --- tinycon.js | 5 +++++ tinycon.min.js | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/tinycon.js b/tinycon.js index 9b8d75a..0838312 100644 --- a/tinycon.js +++ b/tinycon.js @@ -257,4 +257,9 @@ Tinycon.setOptions(defaults); window.Tinycon = Tinycon; + + if(typeof define === 'function' && define.amd) { + define(Tinycon); + } + })(); diff --git a/tinycon.min.js b/tinycon.min.js index 1a9403c..620ddad 100644 --- a/tinycon.min.js +++ b/tinycon.min.js @@ -5,4 +5,8 @@ MIT Licensed @version 0.5 */ -(function(){var Tinycon={};var currentFavicon=null;var originalFavicon=null;var originalTitle=document.title;var faviconImage=null;var canvas=null;var options={};var defaults={width:7,height:9,font:'10px arial',colour:'#ffffff',background:'#F03D25',fallback:true,abbreviate:true};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,len=links.length;i0)drawBubble(context,label,colour);refreshFavicon()};if(!src.match(/^data/)){faviconImage.crossOrigin='anonymous'}faviconImage.src=src};var updateTitle=function(label){if(options.fallback){if((label+'').length>0){document.title='('+label+') '+originalTitle}else{document.title=originalTitle}}};var drawBubble=function(context,label,colour){if(typeof label=='number'&&label>99&&options.abbreviate){label=abbreviateNumber(label)}var len=(label+'').length-1;var width=options.width+(6*len);var w=16-width;var h=16-options.height;context.font=(browser.webkit?'bold ':'')+options.font;context.fillStyle=options.background;context.strokeStyle=options.background;context.lineWidth=1;context.fillRect(w,h,width-1,options.height);context.beginPath();context.moveTo(w-0.5,h+1);context.lineTo(w-0.5,15);context.stroke();context.beginPath();context.moveTo(15.5,h+1);context.lineTo(15.5,15);context.stroke();context.beginPath();context.strokeStyle="rgba(0,0,0,0.3)";context.moveTo(w,16);context.lineTo(15,16);context.stroke();context.fillStyle=options.colour;context.textAlign="right";context.textBaseline="top";context.fillText(label,15,browser.mozilla?7:6)};var refreshFavicon=function(){if(!getCanvas().getContext)return;setFaviconTag(getCanvas().toDataURL())};var abbreviateNumber=function(label){var metricPrefixes=[['G',1000000000],['M',1000000],['k',1000]];for(var i=0;i=metricPrefixes[i][1]){label=round(label/metricPrefixes[i][1])+metricPrefixes[i][0];break}}return label};var round=function(value,precision){var number=new Number(value);return number.toFixed(precision)};Tinycon.setOptions=function(custom){options={};for(var key in defaults){options[key]=custom.hasOwnProperty(key)?custom[key]:defaults[key]}return this};Tinycon.setImage=function(url){currentFavicon=url;refreshFavicon();return this};Tinycon.setBubble=function(label,colour){label=label||'';drawFavicon(label,colour);return this};Tinycon.reset=function(){setFaviconTag(originalFavicon)};Tinycon.setOptions(defaults);window.Tinycon=Tinycon})(); \ No newline at end of file +(function(){var f={},l=null,m=null,q=document.title,h=null,k=null,e={},n={width:7,height:9,font:"10px arial",colour:"#ffffff",background:"#F03D25",fallback:!0,abbreviate:!0},c,r=navigator.userAgent.toLowerCase();c=function(a){return-1!==r.indexOf(a)};var s=c("msie");c("chrome");var t=c("chrome")||c("safari"),u=c("safari")&&!c("chrome"),v=c("mozilla")&&!c("chrome")&&!c("safari"),j=function(){k||(k=document.createElement("canvas"),k.width=16,k.height=16);return k},p=function(a){for(var d=document.getElementsByTagName("link"), +b=document.getElementsByTagName("head")[0],e=0,c=d.length;e=c[g][1]){a=(new Number(a/c[g][1])).toFixed(void 0)+c[g][0];break}var c=e.width+6*((a+"").length-1),g=16-c,f=16-e.height;b.font=(t?"bold ":"")+e.font;b.fillStyle=e.background;b.strokeStyle=e.background;b.lineWidth=1;b.fillRect(g,f,c-1,e.height);b.beginPath();b.moveTo(g-0.5,f+1);b.lineTo(g-0.5,15);b.stroke();b.beginPath();b.moveTo(15.5,f+1);b.lineTo(15.5,15);b.stroke();b.beginPath();b.strokeStyle="rgba(0,0,0,0.3)";b.moveTo(g, +16);b.lineTo(15,16);b.stroke();b.fillStyle=e.colour;b.textAlign="right";b.textBaseline="top";b.fillText(a,15,v?7:6)}j().getContext&&p(j().toDataURL())};a.match(/^data/)||(h.crossOrigin="anonymous");h.src=a}return this};f.reset=function(){p(m)};f.setOptions(n);window.Tinycon=f;"function"===typeof define&&define.amd&&define(f)})(); \ No newline at end of file From 7e77fe4bb87ea4c5ff88fbed6bcf7cc852c8a519 Mon Sep 17 00:00:00 2001 From: Eduardo de Matos Silva Date: Sat, 5 Jan 2013 13:53:47 -0200 Subject: [PATCH 02/41] create example of AMD usage --- examples/index-amd.html | 17 +++++++++++++++++ examples/require.js | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 examples/index-amd.html create mode 100644 examples/require.js diff --git a/examples/index-amd.html b/examples/index-amd.html new file mode 100644 index 0000000..34eef1f --- /dev/null +++ b/examples/index-amd.html @@ -0,0 +1,17 @@ + + + + Tinycon + + + + + + + \ No newline at end of file diff --git a/examples/require.js b/examples/require.js new file mode 100644 index 0000000..d08afe4 --- /dev/null +++ b/examples/require.js @@ -0,0 +1,35 @@ +/* + RequireJS 2.1.2 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + Available via the MIT or new BSD license. + see: http://github.com/jrburke/requirejs for details +*/ +var requirejs,require,define; +(function(Y){function H(b){return"[object Function]"===L.call(b)}function I(b){return"[object Array]"===L.call(b)}function x(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(H(n)){if(this.events.error)try{e=j.execCb(c,n,b,e)}catch(d){a=d}else e=j.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=[this.map.id],a.requireType="define",C(this.error=a)}else e=n;this.exports=e;if(this.map.isDefine&& +!this.ignore&&(p[c]=e,l.onResourceLoad))l.onResourceLoad(j,this.map,this.depMaps);delete k[c];this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=h(a.prefix);this.depMaps.push(d);s(d,"defined",t(this,function(e){var n,d;d=this.map.name;var v=this.map.parentMap?this.map.parentMap.name:null,f=j.makeRequire(a.parentMap,{enableBuildCallback:!0, +skipMap:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,v,!0)})||""),e=h(a.prefix+"!"+d,this.map.parentMap),s(e,"defined",t(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=i(k,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",t(this,function(a){this.emit("error",a)}));d.enable()}}else n=t(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=t(this,function(a){this.inited=!0;this.error= +a;a.requireModules=[b];E(k,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&delete k[a.map.id]});C(a)}),n.fromText=t(this,function(e,c){var d=a.name,u=h(d),v=O;c&&(e=c);v&&(O=!1);q(u);r(m.config,b)&&(m.config[d]=m.config[b]);try{l.exec(e)}catch(k){throw Error("fromText eval for "+d+" failed: "+k);}v&&(O=!0);this.depMaps.push(u);j.completeLoad(d);f([d],n)}),e.load(a.name,f,n,m)}));j.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){this.enabling=this.enabled=!0;x(this.depMaps,t(this,function(a, +b){var c,e;if("string"===typeof a){a=h(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=i(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;s(a,"defined",t(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&s(a,"error",this.errback)}c=a.id;e=k[c];!r(N,c)&&(e&&!e.enabled)&&j.enable(a,this)}));E(this.pluginMaps,t(this,function(a){var b=i(k,a.id);b&&!b.enabled&&j.enable(a,this)}));this.enabling=!1;this.check()},on:function(a,b){var c= +this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){x(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};j={config:m,contextName:b,registry:k,defined:p,urlFetched:S,defQueue:F,Module:W,makeModuleMap:h,nextTick:l.nextTick,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=m.pkgs,c=m.shim,e={paths:!0,config:!0,map:!0};E(a,function(a,b){e[b]?"map"===b?Q(m[b],a,!0,!0):Q(m[b],a,!0):m[b]=a});a.shim&&(E(a.shim,function(a, +b){I(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=j.makeShimExports(a);c[b]=a}),m.shim=c);a.packages&&(x(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ga,"").replace(aa,"")}}),m.pkgs=b);E(k,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=h(b))});if(a.deps||a.callback)j.require(a.deps||[],a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(Y,arguments)); +return b||a.exports&&Z(a.exports)}},makeRequire:function(a,d){function f(e,c,u){var i,m;d.enableBuildCallback&&(c&&H(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(H(c))return C(J("requireargs","Invalid require call"),u);if(a&&r(N,e))return N[e](k[a.id]);if(l.get)return l.get(j,e,a);i=h(e,a,!1,!0);i=i.id;return!r(p,i)?C(J("notloaded",'Module name "'+i+'" has not been loaded yet for context: '+b+(a?"":". Use require([])"))):p[i]}K();j.nextTick(function(){K();m=q(h(null,a));m.skipMap=d.skipMap; +m.init(e,c,u,{enabled:!0});B()});return f}d=d||{};Q(f,{isBrowser:z,toUrl:function(b){var d=b.lastIndexOf("."),g=null;-1!==d&&(g=b.substring(d,b.length),b=b.substring(0,d));return j.nameToUrl(c(b,a&&a.id,!0),g)},defined:function(b){return r(p,h(b,a,!1,!0).id)},specified:function(b){b=h(b,a,!1,!0).id;return r(p,b)||r(k,b)}});a||(f.undef=function(b){w();var c=h(b,a,!0),d=i(k,b);delete p[b];delete S[c.url];delete X[b];d&&(d.events.defined&&(X[b]=d.events),delete k[b])});return f},enable:function(a){i(k, +a.id)&&q(a).enable()},completeLoad:function(a){var b,c,d=i(m.shim,a)||{},h=d.exports;for(w();F.length;){c=F.shift();if(null===c[0]){c[0]=a;if(b)break;b=!0}else c[0]===a&&(b=!0);D(c)}c=i(k,a);if(!b&&!r(p,a)&&c&&!c.inited){if(m.enforceDefine&&(!h||!Z(h)))return y(a)?void 0:C(J("nodefine","No define call for "+a,null,[a]));D([a,d.deps||[],d.exportsFn])}B()},nameToUrl:function(a,b){var c,d,h,f,j,k;if(l.jsExtRegExp.test(a))f=a+(b||"");else{c=m.paths;d=m.pkgs;f=a.split("/");for(j=f.length;0f.attachEvent.toString().indexOf("[native code"))&&!V?(O=!0,f.attachEvent("onreadystatechange", +b.onScriptLoad)):(f.addEventListener("load",b.onScriptLoad,!1),f.addEventListener("error",b.onScriptError,!1)),f.src=d,K=f,D?A.insertBefore(f,D):A.appendChild(f),K=null,f;$&&(importScripts(d),b.completeLoad(c))};z&&M(document.getElementsByTagName("script"),function(b){A||(A=b.parentNode);if(s=b.getAttribute("data-main"))return q.baseUrl||(G=s.split("/"),ba=G.pop(),ca=G.length?G.join("/")+"/":"./",q.baseUrl=ca,s=ba),s=s.replace(aa,""),q.deps=q.deps?q.deps.concat(s):[s],!0});define=function(b,c,d){var i, +f;"string"!==typeof b&&(d=c,c=b,b=null);I(c)||(d=c,c=[]);!c.length&&H(d)&&d.length&&(d.toString().replace(ia,"").replace(ja,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c));if(O){if(!(i=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),function(b){if("interactive"===b.readyState)return P=b}),i=P;i&&(b||(b=i.getAttribute("data-requiremodule")),f=B[i.getAttribute("data-requirecontext")])}(f?f.defQueue:R).push([b,c,d])};define.amd= +{jQuery:!0};l.exec=function(b){return eval(b)};l(q)}})(this); \ No newline at end of file From af1a41cfc32cb36417fd739261a6e298e95c3e8c Mon Sep 17 00:00:00 2001 From: Eduardo de Matos Silva Date: Sat, 5 Jan 2013 14:01:16 -0200 Subject: [PATCH 03/41] update documentation to reflect AMD support --- README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/README.md b/README.md index 4066577..80dac26 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,29 @@ Tinycon.setOptions({ }); ``` +### AMD support + +Tinycon can also be used as an asynchronous module. + +```javascript +require([ + 'tinycon.js' +], function (T) { + + T.setOptions({ + width: 7, + height: 9, + font: '10px arial', + colour: '#ffffff', + background: '#549A2F', + fallback: true + }); + + T.setBubble(7); + +}); +``` + ## Browser Support Tinycon has been tested to work completely in the following browsers. Older versions may be supported, but haven't been tested: From 49d9776bcc0f4e54827eee7b4e8f563d85812d15 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Mon, 2 Sep 2013 14:54:32 -0700 Subject: [PATCH 04/41] Create LICENSE --- LICENSE | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..fdb4f08 --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2013 Tom Moor + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. From 2f08444ba5e8e0823d0817b2b221f5b42b6ac265 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferenczy=20P=C3=A9ter?= Date: Sat, 7 Sep 2013 05:40:53 +0200 Subject: [PATCH 05/41] Added Retina support --- tinycon.js | 58 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/tinycon.js b/tinycon.js index 9b8d75a..4161eb2 100644 --- a/tinycon.js +++ b/tinycon.js @@ -4,7 +4,7 @@ * Copyright (c) 2012 Tom Moor * MIT Licensed * @version 0.5 -*/ + */ (function(){ @@ -15,10 +15,12 @@ var faviconImage = null; var canvas = null; var options = {}; + var r = window.devicePixelRatio || 1; + var size = 16 * r; var defaults = { width: 7, height: 9, - font: '10px arial', + font: 10 * r + 'px arial', colour: '#ffffff', background: '#F03D25', fallback: true, @@ -82,8 +84,8 @@ if (!canvas) { canvas = document.createElement("canvas"); - canvas.width = 16; - canvas.height = 16; + canvas.width = size; + canvas.height = size; } return canvas; @@ -114,14 +116,16 @@ var colour = colour || '#000000'; var src = getCurrentFavicon(); + var clipped = browser.mozilla ? 16 : size; + faviconImage = new Image(); faviconImage.onload = function() { // clear canvas - context.clearRect(0, 0, 16, 16); + context.clearRect(0, 0, size, size); // draw original favicon - context.drawImage(faviconImage, 0, 0, faviconImage.width, faviconImage.height, 0, 0, 16, 16); + context.drawImage(faviconImage, 0, 0, clipped, clipped, 0, 0, size, size); // draw bubble over the top if ((label + '').length > 0) drawBubble(context, label, colour); @@ -159,36 +163,40 @@ // bubble needs to be larger for double digits var len = (label + '').length-1; - var width = options.width + (6*len); - var w = 16-width; - var h = 16-options.height; + + var width = options.width * r + (6 * r * len), + height = options.height * r; + + var top = size - height, + left = size - width - r, + bottom = 16 * r, + right = 16 * r, + radius = 2 * r; // webkit seems to render fonts lighter than firefox context.font = (browser.webkit ? 'bold ' : '') + options.font; context.fillStyle = options.background; context.strokeStyle = options.background; - context.lineWidth = 1; + context.lineWidth = r; // 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(); + context.moveTo(left + radius, top); + context.quadraticCurveTo(left, top, left, top + radius); + context.lineTo(left, bottom - radius); + context.quadraticCurveTo(left, bottom, left + radius, bottom); + context.lineTo(right - radius, bottom); + context.quadraticCurveTo(right, bottom, right, bottom - radius); + context.lineTo(right, top + radius); + context.quadraticCurveTo(right, top, right - radius, top); + context.closePath(); + context.fill(); // bottom shadow context.beginPath(); context.strokeStyle = "rgba(0,0,0,0.3)"; - context.moveTo(w,16); - context.lineTo(15,16); + context.moveTo(left + radius / 2.0, bottom); + context.lineTo(right - radius / 2.0, bottom); context.stroke(); // label @@ -197,7 +205,7 @@ context.textBaseline = "top"; // unfortunately webkit/mozilla are a pixel different in text positioning - context.fillText(label, 15, browser.mozilla ? 7 : 6); + context.fillText(label, r === 2 ? 29 : 15, browser.mozilla ? 7*r : 6*r); }; var refreshFavicon = function(){ From c4909a18c45201ec61fb2266b7228804a634eae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferenczy=20P=C3=A9ter?= Date: Sat, 7 Sep 2013 05:49:19 +0200 Subject: [PATCH 06/41] Reminified script --- tinycon.min.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tinycon.min.js b/tinycon.min.js index 1a9403c..597abd0 100644 --- a/tinycon.min.js +++ b/tinycon.min.js @@ -5,4 +5,4 @@ MIT Licensed @version 0.5 */ -(function(){var Tinycon={};var currentFavicon=null;var originalFavicon=null;var originalTitle=document.title;var faviconImage=null;var canvas=null;var options={};var defaults={width:7,height:9,font:'10px arial',colour:'#ffffff',background:'#F03D25',fallback:true,abbreviate:true};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,len=links.length;i0)drawBubble(context,label,colour);refreshFavicon()};if(!src.match(/^data/)){faviconImage.crossOrigin='anonymous'}faviconImage.src=src};var updateTitle=function(label){if(options.fallback){if((label+'').length>0){document.title='('+label+') '+originalTitle}else{document.title=originalTitle}}};var drawBubble=function(context,label,colour){if(typeof label=='number'&&label>99&&options.abbreviate){label=abbreviateNumber(label)}var len=(label+'').length-1;var width=options.width+(6*len);var w=16-width;var h=16-options.height;context.font=(browser.webkit?'bold ':'')+options.font;context.fillStyle=options.background;context.strokeStyle=options.background;context.lineWidth=1;context.fillRect(w,h,width-1,options.height);context.beginPath();context.moveTo(w-0.5,h+1);context.lineTo(w-0.5,15);context.stroke();context.beginPath();context.moveTo(15.5,h+1);context.lineTo(15.5,15);context.stroke();context.beginPath();context.strokeStyle="rgba(0,0,0,0.3)";context.moveTo(w,16);context.lineTo(15,16);context.stroke();context.fillStyle=options.colour;context.textAlign="right";context.textBaseline="top";context.fillText(label,15,browser.mozilla?7:6)};var refreshFavicon=function(){if(!getCanvas().getContext)return;setFaviconTag(getCanvas().toDataURL())};var abbreviateNumber=function(label){var metricPrefixes=[['G',1000000000],['M',1000000],['k',1000]];for(var i=0;i=metricPrefixes[i][1]){label=round(label/metricPrefixes[i][1])+metricPrefixes[i][0];break}}return label};var round=function(value,precision){var number=new Number(value);return number.toFixed(precision)};Tinycon.setOptions=function(custom){options={};for(var key in defaults){options[key]=custom.hasOwnProperty(key)?custom[key]:defaults[key]}return this};Tinycon.setImage=function(url){currentFavicon=url;refreshFavicon();return this};Tinycon.setBubble=function(label,colour){label=label||'';drawFavicon(label,colour);return this};Tinycon.reset=function(){setFaviconTag(originalFavicon)};Tinycon.setOptions(defaults);window.Tinycon=Tinycon})(); \ No newline at end of file +(function(){var e={};var t=null;var n=null;var r=document.title;var i=null;var s=null;var o={};var u=window.devicePixelRatio||1;var a=16*u;var f={width:7,height:9,font:10*u+"px arial",colour:"#ffffff",background:"#F03D25",fallback:true,abbreviate:true};var l=function(){var e=navigator.userAgent.toLowerCase();return function(t){return e.indexOf(t)!==-1}}();var c={ie:l("msie"),chrome:l("chrome"),webkit:l("chrome")||l("safari"),safari:l("safari")&&!l("chrome"),mozilla:l("mozilla")&&!l("chrome")&&!l("safari")};var h=function(){var e=document.getElementsByTagName("link");for(var t=0,n=e.length;t0)w(n,e,t);E()};if(!r.match(/^data/)){i.crossOrigin="anonymous"}i.src=r};var b=function(e){if(o.fallback){if((e+"").length>0){document.title="("+e+") "+r}else{document.title=r}}};var w=function(e,t,n){if(typeof t=="number"&&t>99&&o.abbreviate){t=S(t)}var r=(t+"").length-1;var i=o.width*u+6*u*r,s=o.height*u;var f=a-s,l=a-i-u,h=16*u,p=16*u,d=2*u;e.font=(c.webkit?"bold ":"")+o.font;e.fillStyle=o.background;e.strokeStyle=o.background;e.lineWidth=u;e.beginPath();e.moveTo(l+d,f);e.quadraticCurveTo(l,f,l,f+d);e.lineTo(l,h-d);e.quadraticCurveTo(l,h,l+d,h);e.lineTo(p-d,h);e.quadraticCurveTo(p,h,p,h-d);e.lineTo(p,f+d);e.quadraticCurveTo(p,f,p-d,f);e.closePath();e.fill();e.beginPath();e.strokeStyle="rgba(0,0,0,0.3)";e.moveTo(l+d/2,h);e.lineTo(p-d/2,h);e.stroke();e.fillStyle=o.colour;e.textAlign="right";e.textBaseline="top";e.fillText(t,u===2?29:15,c.mozilla?7*u:6*u)};var E=function(){if(!v().getContext)return;m(v().toDataURL())};var S=function(e){var t=[["G",1e9],["M",1e6],["k",1e3]];for(var n=0;n=t[n][1]){e=x(e/t[n][1])+t[n][0];break}}return e};var x=function(e,t){var n=new Number(e);return n.toFixed(t)};e.setOptions=function(e){o={};for(var t in f){o[t]=e.hasOwnProperty(t)?e[t]:f[t]}return this};e.setImage=function(e){t=e;E();return this};e.setBubble=function(e,t){e=e||"";y(e,t);return this};e.reset=function(){m(n)};e.setOptions(f);window.Tinycon=e})() \ No newline at end of file From d44364c466f679414c9231dc08e0b356a0932ed8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferenczy=20P=C3=A9ter?= Date: Sat, 7 Sep 2013 06:52:07 +0200 Subject: [PATCH 07/41] Fallback to 16px image if no high-res present --- tinycon.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tinycon.js b/tinycon.js index 4161eb2..63562b4 100644 --- a/tinycon.js +++ b/tinycon.js @@ -116,16 +116,15 @@ var colour = colour || '#000000'; var src = getCurrentFavicon(); - var clipped = browser.mozilla ? 16 : size; - faviconImage = new Image(); faviconImage.onload = function() { // clear canvas context.clearRect(0, 0, size, size); - // draw original favicon - context.drawImage(faviconImage, 0, 0, clipped, clipped, 0, 0, size, size); + // draw original favicon fallback to 16x16, then overwrite with 32x32 if possible + context.drawImage(faviconImage, 0, 0, 16, 16, 0, 0, size, size); + if (!browser.mozilla) context.drawImage(faviconImage, 0, 0, 32, 32, 0, 0, size, size); // draw bubble over the top if ((label + '').length > 0) drawBubble(context, label, colour); From 6daff2b481763ef57e51ea815e18ced0646d6aec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferenczy=20P=C3=A9ter?= Date: Sat, 7 Sep 2013 06:53:13 +0200 Subject: [PATCH 08/41] Reminified script --- tinycon.min.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tinycon.min.js b/tinycon.min.js index 597abd0..b1accb2 100644 --- a/tinycon.min.js +++ b/tinycon.min.js @@ -5,4 +5,4 @@ MIT Licensed @version 0.5 */ -(function(){var e={};var t=null;var n=null;var r=document.title;var i=null;var s=null;var o={};var u=window.devicePixelRatio||1;var a=16*u;var f={width:7,height:9,font:10*u+"px arial",colour:"#ffffff",background:"#F03D25",fallback:true,abbreviate:true};var l=function(){var e=navigator.userAgent.toLowerCase();return function(t){return e.indexOf(t)!==-1}}();var c={ie:l("msie"),chrome:l("chrome"),webkit:l("chrome")||l("safari"),safari:l("safari")&&!l("chrome"),mozilla:l("mozilla")&&!l("chrome")&&!l("safari")};var h=function(){var e=document.getElementsByTagName("link");for(var t=0,n=e.length;t0)w(n,e,t);E()};if(!r.match(/^data/)){i.crossOrigin="anonymous"}i.src=r};var b=function(e){if(o.fallback){if((e+"").length>0){document.title="("+e+") "+r}else{document.title=r}}};var w=function(e,t,n){if(typeof t=="number"&&t>99&&o.abbreviate){t=S(t)}var r=(t+"").length-1;var i=o.width*u+6*u*r,s=o.height*u;var f=a-s,l=a-i-u,h=16*u,p=16*u,d=2*u;e.font=(c.webkit?"bold ":"")+o.font;e.fillStyle=o.background;e.strokeStyle=o.background;e.lineWidth=u;e.beginPath();e.moveTo(l+d,f);e.quadraticCurveTo(l,f,l,f+d);e.lineTo(l,h-d);e.quadraticCurveTo(l,h,l+d,h);e.lineTo(p-d,h);e.quadraticCurveTo(p,h,p,h-d);e.lineTo(p,f+d);e.quadraticCurveTo(p,f,p-d,f);e.closePath();e.fill();e.beginPath();e.strokeStyle="rgba(0,0,0,0.3)";e.moveTo(l+d/2,h);e.lineTo(p-d/2,h);e.stroke();e.fillStyle=o.colour;e.textAlign="right";e.textBaseline="top";e.fillText(t,u===2?29:15,c.mozilla?7*u:6*u)};var E=function(){if(!v().getContext)return;m(v().toDataURL())};var S=function(e){var t=[["G",1e9],["M",1e6],["k",1e3]];for(var n=0;n=t[n][1]){e=x(e/t[n][1])+t[n][0];break}}return e};var x=function(e,t){var n=new Number(e);return n.toFixed(t)};e.setOptions=function(e){o={};for(var t in f){o[t]=e.hasOwnProperty(t)?e[t]:f[t]}return this};e.setImage=function(e){t=e;E();return this};e.setBubble=function(e,t){e=e||"";y(e,t);return this};e.reset=function(){m(n)};e.setOptions(f);window.Tinycon=e})() \ No newline at end of file +(function(){var e={};var t=null;var n=null;var r=document.title;var i=null;var s=null;var o={};var u=window.devicePixelRatio||1;var a=16*u;var f={width:7,height:9,font:10*u+"px arial",colour:"#ffffff",background:"#F03D25",fallback:true,abbreviate:true};var l=function(){var e=navigator.userAgent.toLowerCase();return function(t){return e.indexOf(t)!==-1}}();var c={ie:l("msie"),chrome:l("chrome"),webkit:l("chrome")||l("safari"),safari:l("safari")&&!l("chrome"),mozilla:l("mozilla")&&!l("chrome")&&!l("safari")};var h=function(){var e=document.getElementsByTagName("link");for(var t=0,n=e.length;t0)w(n,e,t);E()};if(!r.match(/^data/)){i.crossOrigin="anonymous"}i.src=r};var b=function(e){if(o.fallback){if((e+"").length>0){document.title="("+e+") "+r}else{document.title=r}}};var w=function(e,t,n){if(typeof t=="number"&&t>99&&o.abbreviate){t=S(t)}var r=(t+"").length-1;var i=o.width*u+6*u*r,s=o.height*u;var f=a-s,l=a-i-u,h=16*u,p=16*u,d=2*u;e.font=(c.webkit?"bold ":"")+o.font;e.fillStyle=o.background;e.strokeStyle=o.background;e.lineWidth=u;e.beginPath();e.moveTo(l+d,f);e.quadraticCurveTo(l,f,l,f+d);e.lineTo(l,h-d);e.quadraticCurveTo(l,h,l+d,h);e.lineTo(p-d,h);e.quadraticCurveTo(p,h,p,h-d);e.lineTo(p,f+d);e.quadraticCurveTo(p,f,p-d,f);e.closePath();e.fill();e.beginPath();e.strokeStyle="rgba(0,0,0,0.3)";e.moveTo(l+d/2,h);e.lineTo(p-d/2,h);e.stroke();e.fillStyle=o.colour;e.textAlign="right";e.textBaseline="top";e.fillText(t,u===2?29:15,c.mozilla?7*u:6*u)};var E=function(){if(!v().getContext)return;m(v().toDataURL())};var S=function(e){var t=[["G",1e9],["M",1e6],["k",1e3]];for(var n=0;n=t[n][1]){e=x(e/t[n][1])+t[n][0];break}}return e};var x=function(e,t){var n=new Number(e);return n.toFixed(t)};e.setOptions=function(e){o={};for(var t in f){o[t]=e.hasOwnProperty(t)?e[t]:f[t]}return this};e.setImage=function(e){t=e;E();return this};e.setBubble=function(e,t){e=e||"";y(e,t);return this};e.reset=function(){m(n)};e.setOptions(f);window.Tinycon=e})() \ No newline at end of file From 8f6f3018c837297ff1ef515661d668e9605243c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferenczy=20P=C3=A9ter?= Date: Sat, 7 Sep 2013 08:05:50 +0200 Subject: [PATCH 09/41] Workaround for Chrome bug --- tinycon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tinycon.js b/tinycon.js index 63562b4..3e93b99 100644 --- a/tinycon.js +++ b/tinycon.js @@ -116,7 +116,7 @@ var colour = colour || '#000000'; var src = getCurrentFavicon(); - faviconImage = new Image(); + faviconImage = document.createElement('img'); faviconImage.onload = function() { // clear canvas From 4e5d216ea43b5c4942464ef0b985e126621cb0e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferenczy=20P=C3=A9ter?= Date: Sat, 7 Sep 2013 08:06:59 +0200 Subject: [PATCH 10/41] Reminified script --- tinycon.min.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tinycon.min.js b/tinycon.min.js index b1accb2..44c3528 100644 --- a/tinycon.min.js +++ b/tinycon.min.js @@ -5,4 +5,4 @@ MIT Licensed @version 0.5 */ -(function(){var e={};var t=null;var n=null;var r=document.title;var i=null;var s=null;var o={};var u=window.devicePixelRatio||1;var a=16*u;var f={width:7,height:9,font:10*u+"px arial",colour:"#ffffff",background:"#F03D25",fallback:true,abbreviate:true};var l=function(){var e=navigator.userAgent.toLowerCase();return function(t){return e.indexOf(t)!==-1}}();var c={ie:l("msie"),chrome:l("chrome"),webkit:l("chrome")||l("safari"),safari:l("safari")&&!l("chrome"),mozilla:l("mozilla")&&!l("chrome")&&!l("safari")};var h=function(){var e=document.getElementsByTagName("link");for(var t=0,n=e.length;t0)w(n,e,t);E()};if(!r.match(/^data/)){i.crossOrigin="anonymous"}i.src=r};var b=function(e){if(o.fallback){if((e+"").length>0){document.title="("+e+") "+r}else{document.title=r}}};var w=function(e,t,n){if(typeof t=="number"&&t>99&&o.abbreviate){t=S(t)}var r=(t+"").length-1;var i=o.width*u+6*u*r,s=o.height*u;var f=a-s,l=a-i-u,h=16*u,p=16*u,d=2*u;e.font=(c.webkit?"bold ":"")+o.font;e.fillStyle=o.background;e.strokeStyle=o.background;e.lineWidth=u;e.beginPath();e.moveTo(l+d,f);e.quadraticCurveTo(l,f,l,f+d);e.lineTo(l,h-d);e.quadraticCurveTo(l,h,l+d,h);e.lineTo(p-d,h);e.quadraticCurveTo(p,h,p,h-d);e.lineTo(p,f+d);e.quadraticCurveTo(p,f,p-d,f);e.closePath();e.fill();e.beginPath();e.strokeStyle="rgba(0,0,0,0.3)";e.moveTo(l+d/2,h);e.lineTo(p-d/2,h);e.stroke();e.fillStyle=o.colour;e.textAlign="right";e.textBaseline="top";e.fillText(t,u===2?29:15,c.mozilla?7*u:6*u)};var E=function(){if(!v().getContext)return;m(v().toDataURL())};var S=function(e){var t=[["G",1e9],["M",1e6],["k",1e3]];for(var n=0;n=t[n][1]){e=x(e/t[n][1])+t[n][0];break}}return e};var x=function(e,t){var n=new Number(e);return n.toFixed(t)};e.setOptions=function(e){o={};for(var t in f){o[t]=e.hasOwnProperty(t)?e[t]:f[t]}return this};e.setImage=function(e){t=e;E();return this};e.setBubble=function(e,t){e=e||"";y(e,t);return this};e.reset=function(){m(n)};e.setOptions(f);window.Tinycon=e})() \ No newline at end of file +(function(){var e={};var t=null;var n=null;var r=document.title;var i=null;var s=null;var o={};var u=window.devicePixelRatio||1;var a=16*u;var f={width:7,height:9,font:10*u+"px arial",colour:"#ffffff",background:"#F03D25",fallback:true,abbreviate:true};var l=function(){var e=navigator.userAgent.toLowerCase();return function(t){return e.indexOf(t)!==-1}}();var c={ie:l("msie"),chrome:l("chrome"),webkit:l("chrome")||l("safari"),safari:l("safari")&&!l("chrome"),mozilla:l("mozilla")&&!l("chrome")&&!l("safari")};var h=function(){var e=document.getElementsByTagName("link");for(var t=0,n=e.length;t0)w(n,e,t);E()};if(!r.match(/^data/)){i.crossOrigin="anonymous"}i.src=r};var b=function(e){if(o.fallback){if((e+"").length>0){document.title="("+e+") "+r}else{document.title=r}}};var w=function(e,t,n){if(typeof t=="number"&&t>99&&o.abbreviate){t=S(t)}var r=(t+"").length-1;var i=o.width*u+6*u*r,s=o.height*u;var f=a-s,l=a-i-u,h=16*u,p=16*u,d=2*u;e.font=(c.webkit?"bold ":"")+o.font;e.fillStyle=o.background;e.strokeStyle=o.background;e.lineWidth=u;e.beginPath();e.moveTo(l+d,f);e.quadraticCurveTo(l,f,l,f+d);e.lineTo(l,h-d);e.quadraticCurveTo(l,h,l+d,h);e.lineTo(p-d,h);e.quadraticCurveTo(p,h,p,h-d);e.lineTo(p,f+d);e.quadraticCurveTo(p,f,p-d,f);e.closePath();e.fill();e.beginPath();e.strokeStyle="rgba(0,0,0,0.3)";e.moveTo(l+d/2,h);e.lineTo(p-d/2,h);e.stroke();e.fillStyle=o.colour;e.textAlign="right";e.textBaseline="top";e.fillText(t,u===2?29:15,c.mozilla?7*u:6*u)};var E=function(){if(!v().getContext)return;m(v().toDataURL())};var S=function(e){var t=[["G",1e9],["M",1e6],["k",1e3]];for(var n=0;n=t[n][1]){e=x(e/t[n][1])+t[n][0];break}}return e};var x=function(e,t){var n=new Number(e);return n.toFixed(t)};e.setOptions=function(e){o={};for(var t in f){o[t]=e.hasOwnProperty(t)?e[t]:f[t]}return this};e.setImage=function(e){t=e;E();return this};e.setBubble=function(e,t){e=e||"";y(e,t);return this};e.reset=function(){m(n)};e.setOptions(f);window.Tinycon=e})() \ No newline at end of file From 353f493722d0b1736e14ef295c6f6a577b1e7827 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Fri, 20 Sep 2013 23:05:10 +0100 Subject: [PATCH 11/41] Upped version to 0.6 --- tinycon.js | 2 +- tinycon.min.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tinycon.js b/tinycon.js index 3e93b99..7a5aa9c 100644 --- a/tinycon.js +++ b/tinycon.js @@ -3,7 +3,7 @@ * Tom Moor, http://tommoor.com * Copyright (c) 2012 Tom Moor * MIT Licensed - * @version 0.5 + * @version 0.6 */ (function(){ diff --git a/tinycon.min.js b/tinycon.min.js index 44c3528..cb2a3d2 100644 --- a/tinycon.min.js +++ b/tinycon.min.js @@ -3,6 +3,6 @@ Tom Moor, http://tommoor.com Copyright (c) 2012 Tom Moor MIT Licensed - @version 0.5 + @version 0.6 */ (function(){var e={};var t=null;var n=null;var r=document.title;var i=null;var s=null;var o={};var u=window.devicePixelRatio||1;var a=16*u;var f={width:7,height:9,font:10*u+"px arial",colour:"#ffffff",background:"#F03D25",fallback:true,abbreviate:true};var l=function(){var e=navigator.userAgent.toLowerCase();return function(t){return e.indexOf(t)!==-1}}();var c={ie:l("msie"),chrome:l("chrome"),webkit:l("chrome")||l("safari"),safari:l("safari")&&!l("chrome"),mozilla:l("mozilla")&&!l("chrome")&&!l("safari")};var h=function(){var e=document.getElementsByTagName("link");for(var t=0,n=e.length;t0)w(n,e,t);E()};if(!r.match(/^data/)){i.crossOrigin="anonymous"}i.src=r};var b=function(e){if(o.fallback){if((e+"").length>0){document.title="("+e+") "+r}else{document.title=r}}};var w=function(e,t,n){if(typeof t=="number"&&t>99&&o.abbreviate){t=S(t)}var r=(t+"").length-1;var i=o.width*u+6*u*r,s=o.height*u;var f=a-s,l=a-i-u,h=16*u,p=16*u,d=2*u;e.font=(c.webkit?"bold ":"")+o.font;e.fillStyle=o.background;e.strokeStyle=o.background;e.lineWidth=u;e.beginPath();e.moveTo(l+d,f);e.quadraticCurveTo(l,f,l,f+d);e.lineTo(l,h-d);e.quadraticCurveTo(l,h,l+d,h);e.lineTo(p-d,h);e.quadraticCurveTo(p,h,p,h-d);e.lineTo(p,f+d);e.quadraticCurveTo(p,f,p-d,f);e.closePath();e.fill();e.beginPath();e.strokeStyle="rgba(0,0,0,0.3)";e.moveTo(l+d/2,h);e.lineTo(p-d/2,h);e.stroke();e.fillStyle=o.colour;e.textAlign="right";e.textBaseline="top";e.fillText(t,u===2?29:15,c.mozilla?7*u:6*u)};var E=function(){if(!v().getContext)return;m(v().toDataURL())};var S=function(e){var t=[["G",1e9],["M",1e6],["k",1e3]];for(var n=0;n=t[n][1]){e=x(e/t[n][1])+t[n][0];break}}return e};var x=function(e,t){var n=new Number(e);return n.toFixed(t)};e.setOptions=function(e){o={};for(var t in f){o[t]=e.hasOwnProperty(t)?e[t]:f[t]}return this};e.setImage=function(e){t=e;E();return this};e.setBubble=function(e,t){e=e||"";y(e,t);return this};e.reset=function(){m(n)};e.setOptions(f);window.Tinycon=e})() \ No newline at end of file From fc93ec303b8530ef47851acdd122d47cc7ce7af9 Mon Sep 17 00:00:00 2001 From: Maxim Colls Date: Fri, 11 Oct 2013 13:24:27 +0200 Subject: [PATCH 12/41] Fixed double-printing the favicon --- tinycon.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tinycon.js b/tinycon.js index 7a5aa9c..4922824 100644 --- a/tinycon.js +++ b/tinycon.js @@ -122,9 +122,8 @@ // clear canvas context.clearRect(0, 0, size, size); - // draw original favicon fallback to 16x16, then overwrite with 32x32 if possible - context.drawImage(faviconImage, 0, 0, 16, 16, 0, 0, size, size); - if (!browser.mozilla) context.drawImage(faviconImage, 0, 0, 32, 32, 0, 0, size, size); + // draw the favicon + context.drawImage(faviconImage, 0, 0, faviconImage.width, faviconImage.height, 0, 0, size, size); // draw bubble over the top if ((label + '').length > 0) drawBubble(context, label, colour); From 4c42db44300baea9b083ece109d042d1a7f057c8 Mon Sep 17 00:00:00 2001 From: Phil Harnish Date: Fri, 11 Oct 2013 13:42:29 -0700 Subject: [PATCH 13/41] Optionally set crossOrigin = 'anonymous' crossOrigin = 'anonymous' will not send cookies with requests. This can, for example, cause a login redirect which results in the cross origin error the code tried to avoid in the first place. --- tinycon.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tinycon.js b/tinycon.js index 7a5aa9c..4106f7a 100644 --- a/tinycon.js +++ b/tinycon.js @@ -24,6 +24,7 @@ colour: '#ffffff', background: '#F03D25', fallback: true, + crossOrigin: true, abbreviate: true }; @@ -135,7 +136,7 @@ // allow cross origin resource requests if the image is not a data:uri // as detailed here: https://github.com/mrdoob/three.js/issues/1305 - if (!src.match(/^data/)) { + if (!src.match(/^data/) && options.crossOrigin) { faviconImage.crossOrigin = 'anonymous'; } From d8dd9566f320e53a2596ed583d011592cb6b2efd Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Sat, 12 Oct 2013 00:19:22 +0200 Subject: [PATCH 14/41] Upped to 0.6.1, minified --- tinycon.js | 2 +- tinycon.min.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tinycon.js b/tinycon.js index b324ee2..f81624e 100644 --- a/tinycon.js +++ b/tinycon.js @@ -3,7 +3,7 @@ * Tom Moor, http://tommoor.com * Copyright (c) 2012 Tom Moor * MIT Licensed - * @version 0.6 + * @version 0.6.1 */ (function(){ diff --git a/tinycon.min.js b/tinycon.min.js index cb2a3d2..129600e 100644 --- a/tinycon.min.js +++ b/tinycon.min.js @@ -3,6 +3,6 @@ Tom Moor, http://tommoor.com Copyright (c) 2012 Tom Moor MIT Licensed - @version 0.6 + @version 0.6.1 */ -(function(){var e={};var t=null;var n=null;var r=document.title;var i=null;var s=null;var o={};var u=window.devicePixelRatio||1;var a=16*u;var f={width:7,height:9,font:10*u+"px arial",colour:"#ffffff",background:"#F03D25",fallback:true,abbreviate:true};var l=function(){var e=navigator.userAgent.toLowerCase();return function(t){return e.indexOf(t)!==-1}}();var c={ie:l("msie"),chrome:l("chrome"),webkit:l("chrome")||l("safari"),safari:l("safari")&&!l("chrome"),mozilla:l("mozilla")&&!l("chrome")&&!l("safari")};var h=function(){var e=document.getElementsByTagName("link");for(var t=0,n=e.length;t0)w(n,e,t);E()};if(!r.match(/^data/)){i.crossOrigin="anonymous"}i.src=r};var b=function(e){if(o.fallback){if((e+"").length>0){document.title="("+e+") "+r}else{document.title=r}}};var w=function(e,t,n){if(typeof t=="number"&&t>99&&o.abbreviate){t=S(t)}var r=(t+"").length-1;var i=o.width*u+6*u*r,s=o.height*u;var f=a-s,l=a-i-u,h=16*u,p=16*u,d=2*u;e.font=(c.webkit?"bold ":"")+o.font;e.fillStyle=o.background;e.strokeStyle=o.background;e.lineWidth=u;e.beginPath();e.moveTo(l+d,f);e.quadraticCurveTo(l,f,l,f+d);e.lineTo(l,h-d);e.quadraticCurveTo(l,h,l+d,h);e.lineTo(p-d,h);e.quadraticCurveTo(p,h,p,h-d);e.lineTo(p,f+d);e.quadraticCurveTo(p,f,p-d,f);e.closePath();e.fill();e.beginPath();e.strokeStyle="rgba(0,0,0,0.3)";e.moveTo(l+d/2,h);e.lineTo(p-d/2,h);e.stroke();e.fillStyle=o.colour;e.textAlign="right";e.textBaseline="top";e.fillText(t,u===2?29:15,c.mozilla?7*u:6*u)};var E=function(){if(!v().getContext)return;m(v().toDataURL())};var S=function(e){var t=[["G",1e9],["M",1e6],["k",1e3]];for(var n=0;n=t[n][1]){e=x(e/t[n][1])+t[n][0];break}}return e};var x=function(e,t){var n=new Number(e);return n.toFixed(t)};e.setOptions=function(e){o={};for(var t in f){o[t]=e.hasOwnProperty(t)?e[t]:f[t]}return this};e.setImage=function(e){t=e;E();return this};e.setBubble=function(e,t){e=e||"";y(e,t);return this};e.reset=function(){m(n)};e.setOptions(f);window.Tinycon=e})() \ No newline at end of file +!function(){var a={},b=null,c=null,d=document.title,e=null,f=null,g={},h=window.devicePixelRatio||1,i=16*h,j={width:7,height:9,font:10*h+"px arial",colour:"#ffffff",background:"#F03D25",fallback:!0,crossOrigin:!0,abbreviate:!0},k=function(){var a=navigator.userAgent.toLowerCase();return function(b){return-1!==a.indexOf(b)}}(),l={ie:k("msie"),chrome:k("chrome"),webkit:k("chrome")||k("safari"),safari:k("safari")&&!k("chrome"),mozilla:k("mozilla")&&!k("chrome")&&!k("safari")},m=function(){for(var a=document.getElementsByTagName("link"),b=0,c=a.length;c>b;b++)if((a[b].getAttribute("rel")||"").match(/\bicon\b/))return a[b];return!1},n=function(){for(var a=document.getElementsByTagName("link"),b=document.getElementsByTagName("head")[0],c=0,d=a.length;d>c;c++){var e="undefined"!=typeof a[c];e&&(a[c].getAttribute("rel")||"").match(/\bicon\b/)&&b.removeChild(a[c])}},o=function(){if(!c||!b){var a=m();c=b=a?a.getAttribute("href"):"/favicon.ico"}return b},p=function(){return f||(f=document.createElement("canvas"),f.width=i,f.height=i),f},q=function(a){n();var b=document.createElement("link");b.type="image/x-icon",b.rel="icon",b.href=a,document.getElementsByTagName("head")[0].appendChild(b)},s=function(a,b){if(!p().getContext||l.ie||l.safari||"force"===g.fallback)return t(a);var c=p().getContext("2d"),b=b||"#000000",d=o();e=document.createElement("img"),e.onload=function(){c.clearRect(0,0,i,i),c.drawImage(e,0,0,e.width,e.height,0,0,i,i),(a+"").length>0&&u(c,a,b),v()},!d.match(/^data/)&&g.crossOrigin&&(e.crossOrigin="anonymous"),e.src=d},t=function(a){g.fallback&&(document.title=(a+"").length>0?"("+a+") "+d:d)},u=function(a,b){"number"==typeof b&&b>99&&g.abbreviate&&(b=w(b));var d=(b+"").length-1,e=g.width*h+6*h*d,f=g.height*h,j=i-f,k=i-e-h,m=16*h,n=16*h,o=2*h;a.font=(l.webkit?"bold ":"")+g.font,a.fillStyle=g.background,a.strokeStyle=g.background,a.lineWidth=h,a.beginPath(),a.moveTo(k+o,j),a.quadraticCurveTo(k,j,k,j+o),a.lineTo(k,m-o),a.quadraticCurveTo(k,m,k+o,m),a.lineTo(n-o,m),a.quadraticCurveTo(n,m,n,m-o),a.lineTo(n,j+o),a.quadraticCurveTo(n,j,n-o,j),a.closePath(),a.fill(),a.beginPath(),a.strokeStyle="rgba(0,0,0,0.3)",a.moveTo(k+o/2,m),a.lineTo(n-o/2,m),a.stroke(),a.fillStyle=g.colour,a.textAlign="right",a.textBaseline="top",a.fillText(b,2===h?29:15,l.mozilla?7*h:6*h)},v=function(){p().getContext&&q(p().toDataURL())},w=function(a){for(var b=[["G",1e9],["M",1e6],["k",1e3]],c=0;c=b[c][1]){a=x(a/b[c][1])+b[c][0];break}return a},x=function(a,b){var c=new Number(a);return c.toFixed(b)};a.setOptions=function(a){g={};for(var b in j)g[b]=a.hasOwnProperty(b)?a[b]:j[b];return this},a.setImage=function(a){return b=a,v(),this},a.setBubble=function(a,b){return a=a||"",s(a,b),this},a.reset=function(){q(c)},a.setOptions(j),window.Tinycon=a}(); \ No newline at end of file From 9d5d8bf69fcac3e081e51a753b9466657f36d062 Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Fri, 6 Dec 2013 22:13:29 +0900 Subject: [PATCH 15/41] Add license markup to header comment Closure compiler keeps the header comments containing `@license` or `@preserve`. * https://developers.google.com/closure/compiler/docs/js-for-compiler#tag-license --- tinycon.js | 2 +- tinycon.min.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tinycon.js b/tinycon.js index f81624e..5ef491a 100644 --- a/tinycon.js +++ b/tinycon.js @@ -2,7 +2,7 @@ * Tinycon - A small library for manipulating the Favicon * Tom Moor, http://tommoor.com * Copyright (c) 2012 Tom Moor - * MIT Licensed + * @license MIT Licensed * @version 0.6.1 */ diff --git a/tinycon.min.js b/tinycon.min.js index 129600e..59d39e1 100644 --- a/tinycon.min.js +++ b/tinycon.min.js @@ -2,7 +2,7 @@ Tinycon - A small library for manipulating the Favicon Tom Moor, http://tommoor.com Copyright (c) 2012 Tom Moor - MIT Licensed + @license MIT Licensed @version 0.6.1 */ !function(){var a={},b=null,c=null,d=document.title,e=null,f=null,g={},h=window.devicePixelRatio||1,i=16*h,j={width:7,height:9,font:10*h+"px arial",colour:"#ffffff",background:"#F03D25",fallback:!0,crossOrigin:!0,abbreviate:!0},k=function(){var a=navigator.userAgent.toLowerCase();return function(b){return-1!==a.indexOf(b)}}(),l={ie:k("msie"),chrome:k("chrome"),webkit:k("chrome")||k("safari"),safari:k("safari")&&!k("chrome"),mozilla:k("mozilla")&&!k("chrome")&&!k("safari")},m=function(){for(var a=document.getElementsByTagName("link"),b=0,c=a.length;c>b;b++)if((a[b].getAttribute("rel")||"").match(/\bicon\b/))return a[b];return!1},n=function(){for(var a=document.getElementsByTagName("link"),b=document.getElementsByTagName("head")[0],c=0,d=a.length;d>c;c++){var e="undefined"!=typeof a[c];e&&(a[c].getAttribute("rel")||"").match(/\bicon\b/)&&b.removeChild(a[c])}},o=function(){if(!c||!b){var a=m();c=b=a?a.getAttribute("href"):"/favicon.ico"}return b},p=function(){return f||(f=document.createElement("canvas"),f.width=i,f.height=i),f},q=function(a){n();var b=document.createElement("link");b.type="image/x-icon",b.rel="icon",b.href=a,document.getElementsByTagName("head")[0].appendChild(b)},s=function(a,b){if(!p().getContext||l.ie||l.safari||"force"===g.fallback)return t(a);var c=p().getContext("2d"),b=b||"#000000",d=o();e=document.createElement("img"),e.onload=function(){c.clearRect(0,0,i,i),c.drawImage(e,0,0,e.width,e.height,0,0,i,i),(a+"").length>0&&u(c,a,b),v()},!d.match(/^data/)&&g.crossOrigin&&(e.crossOrigin="anonymous"),e.src=d},t=function(a){g.fallback&&(document.title=(a+"").length>0?"("+a+") "+d:d)},u=function(a,b){"number"==typeof b&&b>99&&g.abbreviate&&(b=w(b));var d=(b+"").length-1,e=g.width*h+6*h*d,f=g.height*h,j=i-f,k=i-e-h,m=16*h,n=16*h,o=2*h;a.font=(l.webkit?"bold ":"")+g.font,a.fillStyle=g.background,a.strokeStyle=g.background,a.lineWidth=h,a.beginPath(),a.moveTo(k+o,j),a.quadraticCurveTo(k,j,k,j+o),a.lineTo(k,m-o),a.quadraticCurveTo(k,m,k+o,m),a.lineTo(n-o,m),a.quadraticCurveTo(n,m,n,m-o),a.lineTo(n,j+o),a.quadraticCurveTo(n,j,n-o,j),a.closePath(),a.fill(),a.beginPath(),a.strokeStyle="rgba(0,0,0,0.3)",a.moveTo(k+o/2,m),a.lineTo(n-o/2,m),a.stroke(),a.fillStyle=g.colour,a.textAlign="right",a.textBaseline="top",a.fillText(b,2===h?29:15,l.mozilla?7*h:6*h)},v=function(){p().getContext&&q(p().toDataURL())},w=function(a){for(var b=[["G",1e9],["M",1e6],["k",1e3]],c=0;c=b[c][1]){a=x(a/b[c][1])+b[c][0];break}return a},x=function(a,b){var c=new Number(a);return c.toFixed(b)};a.setOptions=function(a){g={};for(var b in j)g[b]=a.hasOwnProperty(b)?a[b]:j[b];return this},a.setImage=function(a){return b=a,v(),this},a.setBubble=function(a,b){return a=a||"",s(a,b),this},a.reset=function(){q(c)},a.setOptions(j),window.Tinycon=a}(); \ No newline at end of file From 9cc67d64281720092e905cd22a490e0e79c20f5d Mon Sep 17 00:00:00 2001 From: Simon Gaeremynck Date: Tue, 21 Jan 2014 21:04:32 +0000 Subject: [PATCH 16/41] #19 - bugfix for handling dynamic document titles --- tinycon.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tinycon.js b/tinycon.js index 5ef491a..3ef9e54 100644 --- a/tinycon.js +++ b/tinycon.js @@ -11,7 +11,6 @@ var Tinycon = {}; var currentFavicon = null; var originalFavicon = null; - var originalTitle = document.title; var faviconImage = null; var canvas = null; var options = {}; @@ -145,6 +144,14 @@ var updateTitle = function(label) { if (options.fallback) { + // Grab the current title that we can prefix with the label + var originalTitle = document.title; + + // Strip out the old label if there is one + if (originalTitle[0] === '(') { + originalTitle = originalTitle.slice(originalTitle.indexOf(' ')); + } + if ((label + '').length > 0) { document.title = '(' + label + ') ' + originalTitle; } else { From 40cf574a6a0fdd3cc59183c6d66ba09ac88a9b67 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Sun, 9 Feb 2014 16:06:46 -0800 Subject: [PATCH 17/41] Repack, version upped --- tinycon.js | 2 +- tinycon.min.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tinycon.js b/tinycon.js index 3ef9e54..81a6fbb 100644 --- a/tinycon.js +++ b/tinycon.js @@ -3,7 +3,7 @@ * Tom Moor, http://tommoor.com * Copyright (c) 2012 Tom Moor * @license MIT Licensed - * @version 0.6.1 + * @version 0.6.2 */ (function(){ diff --git a/tinycon.min.js b/tinycon.min.js index 59d39e1..a167207 100644 --- a/tinycon.min.js +++ b/tinycon.min.js @@ -3,6 +3,6 @@ Tom Moor, http://tommoor.com Copyright (c) 2012 Tom Moor @license MIT Licensed - @version 0.6.1 + @version 0.6.2 */ -!function(){var a={},b=null,c=null,d=document.title,e=null,f=null,g={},h=window.devicePixelRatio||1,i=16*h,j={width:7,height:9,font:10*h+"px arial",colour:"#ffffff",background:"#F03D25",fallback:!0,crossOrigin:!0,abbreviate:!0},k=function(){var a=navigator.userAgent.toLowerCase();return function(b){return-1!==a.indexOf(b)}}(),l={ie:k("msie"),chrome:k("chrome"),webkit:k("chrome")||k("safari"),safari:k("safari")&&!k("chrome"),mozilla:k("mozilla")&&!k("chrome")&&!k("safari")},m=function(){for(var a=document.getElementsByTagName("link"),b=0,c=a.length;c>b;b++)if((a[b].getAttribute("rel")||"").match(/\bicon\b/))return a[b];return!1},n=function(){for(var a=document.getElementsByTagName("link"),b=document.getElementsByTagName("head")[0],c=0,d=a.length;d>c;c++){var e="undefined"!=typeof a[c];e&&(a[c].getAttribute("rel")||"").match(/\bicon\b/)&&b.removeChild(a[c])}},o=function(){if(!c||!b){var a=m();c=b=a?a.getAttribute("href"):"/favicon.ico"}return b},p=function(){return f||(f=document.createElement("canvas"),f.width=i,f.height=i),f},q=function(a){n();var b=document.createElement("link");b.type="image/x-icon",b.rel="icon",b.href=a,document.getElementsByTagName("head")[0].appendChild(b)},s=function(a,b){if(!p().getContext||l.ie||l.safari||"force"===g.fallback)return t(a);var c=p().getContext("2d"),b=b||"#000000",d=o();e=document.createElement("img"),e.onload=function(){c.clearRect(0,0,i,i),c.drawImage(e,0,0,e.width,e.height,0,0,i,i),(a+"").length>0&&u(c,a,b),v()},!d.match(/^data/)&&g.crossOrigin&&(e.crossOrigin="anonymous"),e.src=d},t=function(a){g.fallback&&(document.title=(a+"").length>0?"("+a+") "+d:d)},u=function(a,b){"number"==typeof b&&b>99&&g.abbreviate&&(b=w(b));var d=(b+"").length-1,e=g.width*h+6*h*d,f=g.height*h,j=i-f,k=i-e-h,m=16*h,n=16*h,o=2*h;a.font=(l.webkit?"bold ":"")+g.font,a.fillStyle=g.background,a.strokeStyle=g.background,a.lineWidth=h,a.beginPath(),a.moveTo(k+o,j),a.quadraticCurveTo(k,j,k,j+o),a.lineTo(k,m-o),a.quadraticCurveTo(k,m,k+o,m),a.lineTo(n-o,m),a.quadraticCurveTo(n,m,n,m-o),a.lineTo(n,j+o),a.quadraticCurveTo(n,j,n-o,j),a.closePath(),a.fill(),a.beginPath(),a.strokeStyle="rgba(0,0,0,0.3)",a.moveTo(k+o/2,m),a.lineTo(n-o/2,m),a.stroke(),a.fillStyle=g.colour,a.textAlign="right",a.textBaseline="top",a.fillText(b,2===h?29:15,l.mozilla?7*h:6*h)},v=function(){p().getContext&&q(p().toDataURL())},w=function(a){for(var b=[["G",1e9],["M",1e6],["k",1e3]],c=0;c=b[c][1]){a=x(a/b[c][1])+b[c][0];break}return a},x=function(a,b){var c=new Number(a);return c.toFixed(b)};a.setOptions=function(a){g={};for(var b in j)g[b]=a.hasOwnProperty(b)?a[b]:j[b];return this},a.setImage=function(a){return b=a,v(),this},a.setBubble=function(a,b){return a=a||"",s(a,b),this},a.reset=function(){q(c)},a.setOptions(j),window.Tinycon=a}(); \ No newline at end of file +(function(){var Tinycon={};var currentFavicon=null;var originalFavicon=null;var faviconImage=null;var canvas=null;var options={};var r=window.devicePixelRatio||1;var size=16*r;var defaults={width:7,height:9,font:10*r+'px arial',colour:'#ffffff',background:'#F03D25',fallback:true,crossOrigin:true,abbreviate:true};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,len=links.length;i0)drawBubble(context,label,colour);refreshFavicon()};if(!src.match(/^data/)&&options.crossOrigin){faviconImage.crossOrigin='anonymous'}faviconImage.src=src};var updateTitle=function(label){if(options.fallback){var originalTitle=document.title;if(originalTitle[0]==='('){originalTitle=originalTitle.slice(originalTitle.indexOf(' '))}if((label+'').length>0){document.title='('+label+') '+originalTitle}else{document.title=originalTitle}}};var drawBubble=function(context,label,colour){if(typeof label=='number'&&label>99&&options.abbreviate){label=abbreviateNumber(label)}var len=(label+'').length-1;var width=options.width*r+(6*r*len),height=options.height*r;var top=size-height,left=size-width-r,bottom=16*r,right=16*r,radius=2*r;context.font=(browser.webkit?'bold ':'')+options.font;context.fillStyle=options.background;context.strokeStyle=options.background;context.lineWidth=r;context.beginPath();context.moveTo(left+radius,top);context.quadraticCurveTo(left,top,left,top+radius);context.lineTo(left,bottom-radius);context.quadraticCurveTo(left,bottom,left+radius,bottom);context.lineTo(right-radius,bottom);context.quadraticCurveTo(right,bottom,right,bottom-radius);context.lineTo(right,top+radius);context.quadraticCurveTo(right,top,right-radius,top);context.closePath();context.fill();context.beginPath();context.strokeStyle="rgba(0,0,0,0.3)";context.moveTo(left+radius/2.0,bottom);context.lineTo(right-radius/2.0,bottom);context.stroke();context.fillStyle=options.colour;context.textAlign="right";context.textBaseline="top";context.fillText(label,r===2?29:15,browser.mozilla?7*r:6*r)};var refreshFavicon=function(){if(!getCanvas().getContext)return;setFaviconTag(getCanvas().toDataURL())};var abbreviateNumber=function(label){var metricPrefixes=[['G',1000000000],['M',1000000],['k',1000]];for(var i=0;i=metricPrefixes[i][1]){label=round(label/metricPrefixes[i][1])+metricPrefixes[i][0];break}}return label};var round=function(value,precision){var number=new Number(value);return number.toFixed(precision)};Tinycon.setOptions=function(custom){options={};for(var key in defaults){options[key]=custom.hasOwnProperty(key)?custom[key]:defaults[key]}return this};Tinycon.setImage=function(url){currentFavicon=url;refreshFavicon();return this};Tinycon.setBubble=function(label,colour){label=label||'';drawFavicon(label,colour);return this};Tinycon.reset=function(){setFaviconTag(originalFavicon)};Tinycon.setOptions(defaults);window.Tinycon=Tinycon})(); \ No newline at end of file From 94f32ea2d37c0e366f1041a99aed897473dbe3d7 Mon Sep 17 00:00:00 2001 From: Evan Hahn Date: Tue, 26 May 2015 07:49:35 -0700 Subject: [PATCH 18/41] Add CommonJS support This lets tools like Browserify and Webpack use Tinycon. --- tinycon.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tinycon.js b/tinycon.js index 3955fb3..d3bad4a 100644 --- a/tinycon.js +++ b/tinycon.js @@ -270,10 +270,13 @@ }; Tinycon.setOptions(defaults); - window.Tinycon = Tinycon; if(typeof define === 'function' && define.amd) { define(Tinycon); + } else if (typeof module !== 'undefined') { + module.exports = Tinycon; + } else { + window.Tinycon = Tinycon; } })(); From 3b5dd1bfb7a7907bd48213adb258d7c4f06b3976 Mon Sep 17 00:00:00 2001 From: Chris Barr Date: Thu, 18 Jun 2015 11:42:10 -0400 Subject: [PATCH 19/41] Ensure we have a URL to set before setting it Without this, I ran into an error where my code tried to call `Tinycon.reset()` before Tinycon had save the `orginalFavicon` which caused it to try and set the favicon URL to `null` --- tinycon.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/tinycon.js b/tinycon.js index 3955fb3..78b593f 100644 --- a/tinycon.js +++ b/tinycon.js @@ -92,13 +92,15 @@ }; 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); + if(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){ From f667cdd9858468a8b9341e2fe9197c68206e8f19 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Sun, 19 Jul 2015 12:00:08 -0700 Subject: [PATCH 20/41] Added: package.json for NPM support Added grunt script to uglify --- .gitignore | 3 ++- Gruntfile.js | 16 ++++++++++++++++ LICENSE | 2 +- package.json | 14 ++++++++++++++ tinycon.js | 4 ++-- tinycon.min.js | 14 +++++++------- 6 files changed, 42 insertions(+), 11 deletions(-) create mode 100644 Gruntfile.js create mode 100644 package.json diff --git a/.gitignore b/.gitignore index 496ee2c..646ac51 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -.DS_Store \ No newline at end of file +.DS_Store +node_modules/ diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 0000000..33bd7e4 --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,16 @@ +module.exports = function(grunt) { + grunt.loadNpmTasks('grunt-contrib-uglify'); + + grunt.initConfig({ + uglify: { + all: { + options: { + preserveComments: 'some' + }, + files: { + 'tinycon.min.js': ['tinycon.js'] + } + }, + }, + }); +}; \ No newline at end of file diff --git a/LICENSE b/LICENSE index fdb4f08..e8a657b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2013 Tom Moor +Copyright (c) 2015 Tom Moor Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/package.json b/package.json new file mode 100644 index 0000000..a2dc761 --- /dev/null +++ b/package.json @@ -0,0 +1,14 @@ +{ + "name": "tinycon", + "version": "0.6.4", + "description": "Add notification bubbles in the favicon", + "author": "Tom Moor (http://tommoor.com)", + "main" : "./tinycon.js", + "repository" : { + "type": "git", + "url": "git://github.com/tommoor/tinycon.git" + }, + "devDependencies": { + "grunt": "~0.4.5", + } +} \ No newline at end of file diff --git a/tinycon.js b/tinycon.js index ede6203..2b5795f 100644 --- a/tinycon.js +++ b/tinycon.js @@ -1,9 +1,9 @@ /*! * Tinycon - A small library for manipulating the Favicon * Tom Moor, http://tommoor.com - * Copyright (c) 2012 Tom Moor + * Copyright (c) 2015 Tom Moor * @license MIT Licensed - * @version 0.6.3 + * @version 0.6.4 */ (function(){ diff --git a/tinycon.min.js b/tinycon.min.js index 283f511..9536565 100644 --- a/tinycon.min.js +++ b/tinycon.min.js @@ -1,8 +1,8 @@ /*! - Tinycon - A small library for manipulating the Favicon - Tom Moor, http://tommoor.com - Copyright (c) 2012 Tom Moor - @license MIT Licensed - @version 0.6.3 -*/ -(function(){var Tinycon={};var currentFavicon=null;var originalFavicon=null;var faviconImage=null;var canvas=null;var options={};var r=window.devicePixelRatio||1;var size=16*r;var defaults={width:7,height:9,font:10*r+'px arial',colour:'#ffffff',background:'#F03D25',fallback:true,crossOrigin:true,abbreviate:true};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,len=links.length;i0)drawBubble(context,label,colour);refreshFavicon()};if(!src.match(/^data/)&&options.crossOrigin){faviconImage.crossOrigin='anonymous'}faviconImage.src=src};var updateTitle=function(label){if(options.fallback){var originalTitle=document.title;if(originalTitle[0]==='('){originalTitle=originalTitle.slice(originalTitle.indexOf(' '))}if((label+'').length>0){document.title='('+label+') '+originalTitle}else{document.title=originalTitle}}};var drawBubble=function(context,label,colour){if(typeof label=='number'&&label>99&&options.abbreviate){label=abbreviateNumber(label)}var len=(label+'').length-1;var width=options.width*r+(6*r*len),height=options.height*r;var top=size-height,left=size-width-r,bottom=16*r,right=16*r,radius=2*r;context.font=(browser.webkit?'bold ':'')+options.font;context.fillStyle=options.background;context.strokeStyle=options.background;context.lineWidth=r;context.beginPath();context.moveTo(left+radius,top);context.quadraticCurveTo(left,top,left,top+radius);context.lineTo(left,bottom-radius);context.quadraticCurveTo(left,bottom,left+radius,bottom);context.lineTo(right-radius,bottom);context.quadraticCurveTo(right,bottom,right,bottom-radius);context.lineTo(right,top+radius);context.quadraticCurveTo(right,top,right-radius,top);context.closePath();context.fill();context.beginPath();context.strokeStyle="rgba(0,0,0,0.3)";context.moveTo(left+radius/2.0,bottom);context.lineTo(right-radius/2.0,bottom);context.stroke();context.fillStyle=options.colour;context.textAlign="right";context.textBaseline="top";context.fillText(label,r===2?29:15,browser.mozilla?7*r:6*r)};var refreshFavicon=function(){if(!getCanvas().getContext)return;setFaviconTag(getCanvas().toDataURL())};var abbreviateNumber=function(label){var metricPrefixes=[['G',1000000000],['M',1000000],['k',1000]];for(var i=0;i=metricPrefixes[i][1]){label=round(label/metricPrefixes[i][1])+metricPrefixes[i][0];break}}return label};var round=function(value,precision){var number=new Number(value);return number.toFixed(precision)};Tinycon.setOptions=function(custom){options={};for(var key in defaults){options[key]=custom.hasOwnProperty(key)?custom[key]:defaults[key]}return this};Tinycon.setImage=function(url){currentFavicon=url;refreshFavicon();return this};Tinycon.setBubble=function(label,colour){label=label||'';drawFavicon(label,colour);return this};Tinycon.reset=function(){setFaviconTag(originalFavicon)};Tinycon.setOptions(defaults);window.Tinycon=Tinycon;if(typeof define==='function'&&define.amd){define(Tinycon)}})(); \ No newline at end of file + * Tinycon - A small library for manipulating the Favicon + * Tom Moor, http://tommoor.com + * Copyright (c) 2015 Tom Moor + * @license MIT Licensed + * @version 0.6.4 + */ +!function(){var a={},b=null,c=null,d=null,e=null,f={},g=window.devicePixelRatio||1,h=16*g,i={width:7,height:9,font:10*g+"px arial",colour:"#ffffff",background:"#F03D25",fallback:!0,crossOrigin:!0,abbreviate:!0},j=function(){var a=navigator.userAgent.toLowerCase();return function(b){return-1!==a.indexOf(b)}}(),k={ie:j("msie"),chrome:j("chrome"),webkit:j("chrome")||j("safari"),safari:j("safari")&&!j("chrome"),mozilla:j("mozilla")&&!j("chrome")&&!j("safari")},l=function(){for(var a=document.getElementsByTagName("link"),b=0,c=a.length;c>b;b++)if((a[b].getAttribute("rel")||"").match(/\bicon\b/))return a[b];return!1},m=function(){for(var a=document.getElementsByTagName("link"),b=document.getElementsByTagName("head")[0],c=0,d=a.length;d>c;c++){var e="undefined"!=typeof a[c];e&&(a[c].getAttribute("rel")||"").match(/\bicon\b/)&&b.removeChild(a[c])}},n=function(){if(!c||!b){var a=l();c=b=a?a.getAttribute("href"):"/favicon.ico"}return b},o=function(){return e||(e=document.createElement("canvas"),e.width=h,e.height=h),e},p=function(a){if(a){m();var b=document.createElement("link");b.type="image/x-icon",b.rel="icon",b.href=a,document.getElementsByTagName("head")[0].appendChild(b)}},q=function(a,b){if(!o().getContext||k.ie||k.safari||"force"===f.fallback)return r(a);var c=o().getContext("2d"),b=b||"#000000",e=n();d=document.createElement("img"),d.onload=function(){c.clearRect(0,0,h,h),c.drawImage(d,0,0,d.width,d.height,0,0,h,h),(a+"").length>0&&s(c,a,b),t()},!e.match(/^data/)&&f.crossOrigin&&(d.crossOrigin="anonymous"),d.src=e},r=function(a){if(f.fallback){var b=document.title;"("===b[0]&&(b=b.slice(b.indexOf(" "))),(a+"").length>0?document.title="("+a+") "+b:document.title=b}},s=function(a,b,c){"number"==typeof b&&b>99&&f.abbreviate&&(b=u(b));var d=(b+"").length-1,e=f.width*g+6*g*d,i=f.height*g,j=h-i,l=h-e-g,m=16*g,n=16*g,o=2*g;a.font=(k.webkit?"bold ":"")+f.font,a.fillStyle=f.background,a.strokeStyle=f.background,a.lineWidth=g,a.beginPath(),a.moveTo(l+o,j),a.quadraticCurveTo(l,j,l,j+o),a.lineTo(l,m-o),a.quadraticCurveTo(l,m,l+o,m),a.lineTo(n-o,m),a.quadraticCurveTo(n,m,n,m-o),a.lineTo(n,j+o),a.quadraticCurveTo(n,j,n-o,j),a.closePath(),a.fill(),a.beginPath(),a.strokeStyle="rgba(0,0,0,0.3)",a.moveTo(l+o/2,m),a.lineTo(n-o/2,m),a.stroke(),a.fillStyle=f.colour,a.textAlign="right",a.textBaseline="top",a.fillText(b,2===g?29:15,k.mozilla?7*g:6*g)},t=function(){o().getContext&&p(o().toDataURL())},u=function(a){for(var b=[["G",1e9],["M",1e6],["k",1e3]],c=0;c=b[c][1]){a=v(a/b[c][1])+b[c][0];break}return a},v=function(a,b){var c=new Number(a);return c.toFixed(b)};a.setOptions=function(a){f={};for(var b in i)f[b]=a.hasOwnProperty(b)?a[b]:i[b];return this},a.setImage=function(a){return b=a,t(),this},a.setBubble=function(a,b){return a=a||"",q(a,b),this},a.reset=function(){p(c)},a.setOptions(i),"function"==typeof define&&define.amd?define(a):"undefined"!=typeof module?module.exports=a:window.Tinycon=a}(); \ No newline at end of file From 30361a32b43025fb08cfd00498f62f7290164977 Mon Sep 17 00:00:00 2001 From: Karim El-Husseiny Date: Wed, 30 Sep 2015 17:49:14 +0200 Subject: [PATCH 21/41] Fix Syntax Error in package.json --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index a2dc761..93d1e34 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,6 @@ "url": "git://github.com/tommoor/tinycon.git" }, "devDependencies": { - "grunt": "~0.4.5", + "grunt": "~0.4.5" } -} \ No newline at end of file +} From 64f8fca212251020375f30b9a3d751e9e297b4f6 Mon Sep 17 00:00:00 2001 From: waschmittel Date: Mon, 5 Oct 2015 16:40:37 +0200 Subject: [PATCH 22/41] Restore the original Favicon on reset I suppose it's intended that way. Why else would there be a currentFavicon AND an originalFavicon variable? --- tinycon.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tinycon.js b/tinycon.js index 2b5795f..1cce0ac 100644 --- a/tinycon.js +++ b/tinycon.js @@ -74,7 +74,10 @@ if (!originalFavicon || !currentFavicon) { var tag = getFaviconTag(); - originalFavicon = currentFavicon = tag ? tag.getAttribute('href') : '/favicon.ico'; + currentFavicon = tag ? tag.getAttribute('href') : '/favicon.ico'; + if (!originalFavicon) { + originalFavicon = currentFavicon; + } } return currentFavicon; From fbecd431c085cbd6a67124e59436af17393c6820 Mon Sep 17 00:00:00 2001 From: waschmittel Date: Mon, 5 Oct 2015 17:01:48 +0200 Subject: [PATCH 23/41] Update tinycon.js --- tinycon.js | 1 + 1 file changed, 1 insertion(+) diff --git a/tinycon.js b/tinycon.js index 1cce0ac..3967712 100644 --- a/tinycon.js +++ b/tinycon.js @@ -271,6 +271,7 @@ }; Tinycon.reset = function(){ + currentFavicon = originalFavicon; setFaviconTag(originalFavicon); }; From 6830a69eaf5ac30bc1f94afd8c6e98f9d98f15e6 Mon Sep 17 00:00:00 2001 From: Justin Wiblin Date: Wed, 21 Oct 2015 09:36:09 +0100 Subject: [PATCH 24/41] Update tinycon.js --- tinycon.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tinycon.js b/tinycon.js index 2b5795f..090147b 100644 --- a/tinycon.js +++ b/tinycon.js @@ -49,7 +49,7 @@ var links = document.getElementsByTagName('link'); for(var i=0, len=links.length; i < len; i++) { - if ((links[i].getAttribute('rel') || '').match(/\bicon\b/)) { + if ((links[i].getAttribute('rel') || '').match(/\bicon\b/i)) { return links[i]; } } @@ -64,7 +64,7 @@ for(var i=0, len=links.length; i < len; i++) { var exists = (typeof(links[i]) !== 'undefined'); - if (exists && (links[i].getAttribute('rel') || '').match(/\bicon\b/)) { + if (exists && (links[i].getAttribute('rel') || '').match(/\bicon\b/i)) { head.removeChild(links[i]); } } From 47f390bbae7dd797178f7c7ae11018e715d3b98a Mon Sep 17 00:00:00 2001 From: Justin Wiblin Date: Wed, 21 Oct 2015 10:16:08 +0100 Subject: [PATCH 25/41] Update tinycon.js --- tinycon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tinycon.js b/tinycon.js index 2b5795f..68ad2c6 100644 --- a/tinycon.js +++ b/tinycon.js @@ -36,7 +36,7 @@ }()); var browser = { - ie: ua('msie'), + ie: ua('trident'), chrome: ua('chrome'), webkit: ua('chrome') || ua('safari'), safari: ua('safari') && !ua('chrome'), From 6a4e131cff0ba08ea863af34ce19cb9b1490468a Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Sat, 9 Apr 2016 10:29:21 -0700 Subject: [PATCH 26/41] Colour > color Tabs to spaces --- tinycon.js | 519 +++++++++++++++++++++++++++-------------------------- 1 file changed, 262 insertions(+), 257 deletions(-) diff --git a/tinycon.js b/tinycon.js index 6d7d13e..19d2245 100644 --- a/tinycon.js +++ b/tinycon.js @@ -8,193 +8,193 @@ (function(){ - var Tinycon = {}; - var currentFavicon = null; - var originalFavicon = null; - var faviconImage = null; - var canvas = null; - var options = {}; - var r = window.devicePixelRatio || 1; - var size = 16 * r; - var defaults = { - width: 7, - height: 9, - font: 10 * r + 'px arial', - colour: '#ffffff', - background: '#F03D25', - fallback: true, - crossOrigin: true, - abbreviate: true - }; - - var ua = (function () { - var agent = navigator.userAgent.toLowerCase(); - // New function has access to 'agent' via closure - return function (browser) { - return agent.indexOf(browser) !== -1; - }; - }()); - - var browser = { - ie: ua('trident'), - chrome: ua('chrome'), - webkit: ua('chrome') || ua('safari'), - safari: ua('safari') && !ua('chrome'), - mozilla: ua('mozilla') && !ua('chrome') && !ua('safari') - }; - - // private methods - var getFaviconTag = function(){ - - var links = document.getElementsByTagName('link'); - - for(var i=0, len=links.length; i < len; i++) { - if ((links[i].getAttribute('rel') || '').match(/\bicon\b/i)) { - return links[i]; - } - } - - return false; - }; - - var removeFaviconTag = function(){ - - var links = document.getElementsByTagName('link'); - var head = document.getElementsByTagName('head')[0]; - - for(var i=0, len=links.length; i < len; i++) { - var exists = (typeof(links[i]) !== 'undefined'); - if (exists && (links[i].getAttribute('rel') || '').match(/\bicon\b/i)) { - head.removeChild(links[i]); - } - } - }; - - var getCurrentFavicon = function(){ - - if (!originalFavicon || !currentFavicon) { - var tag = getFaviconTag(); - currentFavicon = tag ? tag.getAttribute('href') : '/favicon.ico'; - if (!originalFavicon) { - originalFavicon = currentFavicon; - } - } - - return currentFavicon; - }; - - var getCanvas = function (){ - - if (!canvas) { - canvas = document.createElement("canvas"); - canvas.width = size; - canvas.height = size; - } - - return canvas; - }; - - var setFaviconTag = function(url){ - if(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) window.console.log(message); - }; - - var drawFavicon = function(label, colour) { - - // fallback to updating the browser title if unsupported - if (!getCanvas().getContext || browser.ie || browser.safari || options.fallback === 'force') { - return updateTitle(label); - } - - var context = getCanvas().getContext("2d"); - var colour = colour || '#000000'; - var src = getCurrentFavicon(); - - faviconImage = document.createElement('img'); - faviconImage.onload = function() { - - // clear canvas - context.clearRect(0, 0, size, size); - - // draw the favicon - context.drawImage(faviconImage, 0, 0, faviconImage.width, faviconImage.height, 0, 0, size, size); - - // draw bubble over the top - if ((label + '').length > 0) drawBubble(context, label, colour); - - // refresh tag in page - refreshFavicon(); - }; - - // allow cross origin resource requests if the image is not a data:uri - // as detailed here: https://github.com/mrdoob/three.js/issues/1305 - if (!src.match(/^data/) && options.crossOrigin) { - faviconImage.crossOrigin = 'anonymous'; - } + var Tinycon = {}; + var currentFavicon = null; + var originalFavicon = null; + var faviconImage = null; + var canvas = null; + var options = {}; + var r = window.devicePixelRatio || 1; + var size = 16 * r; + var defaults = { + width: 7, + height: 9, + font: 10 * r + 'px arial', + color: '#ffffff', + background: '#F03D25', + fallback: true, + crossOrigin: true, + abbreviate: true + }; + + var ua = (function () { + var agent = navigator.userAgent.toLowerCase(); + // New function has access to 'agent' via closure + return function (browser) { + return agent.indexOf(browser) !== -1; + }; + }()); + + var browser = { + ie: ua('trident'), + chrome: ua('chrome'), + webkit: ua('chrome') || ua('safari'), + safari: ua('safari') && !ua('chrome'), + mozilla: ua('mozilla') && !ua('chrome') && !ua('safari') + }; + + // private methods + var getFaviconTag = function(){ + + var links = document.getElementsByTagName('link'); + + for(var i=0, len=links.length; i < len; i++) { + if ((links[i].getAttribute('rel') || '').match(/\bicon\b/i)) { + return links[i]; + } + } + + return false; + }; + + var removeFaviconTag = function(){ + + var links = document.getElementsByTagName('link'); + var head = document.getElementsByTagName('head')[0]; + + for(var i=0, len=links.length; i < len; i++) { + var exists = (typeof(links[i]) !== 'undefined'); + if (exists && (links[i].getAttribute('rel') || '').match(/\bicon\b/i)) { + head.removeChild(links[i]); + } + } + }; + + var getCurrentFavicon = function(){ + + if (!originalFavicon || !currentFavicon) { + var tag = getFaviconTag(); + currentFavicon = tag ? tag.getAttribute('href') : '/favicon.ico'; + if (!originalFavicon) { + originalFavicon = currentFavicon; + } + } + + return currentFavicon; + }; + + var getCanvas = function (){ + + if (!canvas) { + canvas = document.createElement("canvas"); + canvas.width = size; + canvas.height = size; + } + + return canvas; + }; + + var setFaviconTag = function(url){ + if(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) window.console.log(message); + }; + + var drawFavicon = function(label, color) { + + // fallback to updating the browser title if unsupported + if (!getCanvas().getContext || browser.ie || browser.safari || options.fallback === 'force') { + return updateTitle(label); + } + + var context = getCanvas().getContext("2d"); + var color = color || '#000000'; + var src = getCurrentFavicon(); + + faviconImage = document.createElement('img'); + faviconImage.onload = function() { + + // clear canvas + context.clearRect(0, 0, size, size); + + // draw the favicon + context.drawImage(faviconImage, 0, 0, faviconImage.width, faviconImage.height, 0, 0, size, size); + + // draw bubble over the top + if ((label + '').length > 0) drawBubble(context, label, color); - faviconImage.src = src; - }; + // refresh tag in page + refreshFavicon(); + }; - var updateTitle = function(label) { - - if (options.fallback) { - // Grab the current title that we can prefix with the label - var originalTitle = document.title; - - // Strip out the old label if there is one - if (originalTitle[0] === '(') { - originalTitle = originalTitle.slice(originalTitle.indexOf(' ')); - } + // allow cross origin resource requests if the image is not a data:uri + // as detailed here: https://github.com/mrdoob/three.js/issues/1305 + if (!src.match(/^data/) && options.crossOrigin) { + faviconImage.crossOrigin = 'anonymous'; + } - if ((label + '').length > 0) { - document.title = '(' + label + ') ' + originalTitle; - } else { - document.title = originalTitle; - } - } - }; - - var drawBubble = function(context, label, colour) { - - // automatic abbreviation for long (>2 digits) numbers - if (typeof label == 'number' && label > 99 && options.abbreviate) { - label = abbreviateNumber(label); - } - - // bubble needs to be larger for double digits - var len = (label + '').length-1; - - var width = options.width * r + (6 * r * len), - height = options.height * r; + faviconImage.src = src; + }; - var top = size - height, + var updateTitle = function(label) { + + if (options.fallback) { + // Grab the current title that we can prefix with the label + var originalTitle = document.title; + + // Strip out the old label if there is one + if (originalTitle[0] === '(') { + originalTitle = originalTitle.slice(originalTitle.indexOf(' ')); + } + + if ((label + '').length > 0) { + document.title = '(' + label + ') ' + originalTitle; + } else { + document.title = originalTitle; + } + } + }; + + var drawBubble = function(context, label, color) { + + // automatic abbreviation for long (>2 digits) numbers + if (typeof label == 'number' && label > 99 && options.abbreviate) { + label = abbreviateNumber(label); + } + + // bubble needs to be larger for double digits + var len = (label + '').length-1; + + var width = options.width * r + (6 * r * len), + height = options.height * r; + + var top = size - height, left = size - width - r, bottom = 16 * r, right = 16 * r, radius = 2 * r; - // webkit seems to render fonts lighter than firefox - context.font = (browser.webkit ? 'bold ' : '') + options.font; - context.fillStyle = options.background; - context.strokeStyle = options.background; - context.lineWidth = r; + // webkit seems to render fonts lighter than firefox + context.font = (browser.webkit ? 'bold ' : '') + options.font; + context.fillStyle = options.background; + context.strokeStyle = options.background; + context.lineWidth = r; - // bubble - context.beginPath(); + // bubble + context.beginPath(); context.moveTo(left + radius, top); - context.quadraticCurveTo(left, top, left, top + radius); - context.lineTo(left, bottom - radius); + context.quadraticCurveTo(left, top, left, top + radius); + context.lineTo(left, bottom - radius); context.quadraticCurveTo(left, bottom, left + radius, bottom); context.lineTo(right - radius, bottom); context.quadraticCurveTo(right, bottom, right, bottom - radius); @@ -203,86 +203,91 @@ context.closePath(); context.fill(); - // bottom shadow - context.beginPath(); - context.strokeStyle = "rgba(0,0,0,0.3)"; - context.moveTo(left + radius / 2.0, bottom); - context.lineTo(right - radius / 2.0, bottom); - context.stroke(); - - // label - context.fillStyle = options.colour; - context.textAlign = "right"; - context.textBaseline = "top"; - - // unfortunately webkit/mozilla are a pixel different in text positioning - context.fillText(label, r === 2 ? 29 : 15, browser.mozilla ? 7*r : 6*r); - }; - - var refreshFavicon = function(){ - // check support - if (!getCanvas().getContext) return; - - setFaviconTag(getCanvas().toDataURL()); - }; - - var abbreviateNumber = function(label) { - var metricPrefixes = [ - ['G', 1000000000], - ['M', 1000000], - ['k', 1000] - ]; - - for(var i = 0; i < metricPrefixes.length; ++i) { - if (label >= metricPrefixes[i][1]) { - label = round(label / metricPrefixes[i][1]) + metricPrefixes[i][0]; - break; - } - } - - return label; - }; - - var round = function (value, precision) { - var number = new Number(value); - return number.toFixed(precision); - }; - - // public methods - Tinycon.setOptions = function(custom){ - options = {}; - - for(var key in defaults){ - options[key] = custom.hasOwnProperty(key) ? custom[key] : defaults[key]; - } - return this; - }; - - Tinycon.setImage = function(url){ - currentFavicon = url; - refreshFavicon(); - return this; - }; - - Tinycon.setBubble = function(label, colour) { - label = label || ''; - drawFavicon(label, colour); - return this; - }; - - Tinycon.reset = function(){ - currentFavicon = originalFavicon; - setFaviconTag(originalFavicon); - }; - - Tinycon.setOptions(defaults); - - if(typeof define === 'function' && define.amd) { - define(Tinycon); - } else if (typeof module !== 'undefined') { - module.exports = Tinycon; - } else { - window.Tinycon = Tinycon; - } + // bottom shadow + context.beginPath(); + context.strokeStyle = "rgba(0,0,0,0.3)"; + context.moveTo(left + radius / 2.0, bottom); + context.lineTo(right - radius / 2.0, bottom); + context.stroke(); + + // label + context.fillStyle = options.color; + context.textAlign = "right"; + context.textBaseline = "top"; + + // unfortunately webkit/mozilla are a pixel different in text positioning + context.fillText(label, r === 2 ? 29 : 15, browser.mozilla ? 7*r : 6*r); + }; + + var refreshFavicon = function(){ + // check support + if (!getCanvas().getContext) return; + + setFaviconTag(getCanvas().toDataURL()); + }; + + var abbreviateNumber = function(label) { + var metricPrefixes = [ + ['G', 1000000000], + ['M', 1000000], + ['k', 1000] + ]; + + for(var i = 0; i < metricPrefixes.length; ++i) { + if (label >= metricPrefixes[i][1]) { + label = round(label / metricPrefixes[i][1]) + metricPrefixes[i][0]; + break; + } + } + + return label; + }; + + var round = function (value, precision) { + var number = new Number(value); + return number.toFixed(precision); + }; + + // public methods + Tinycon.setOptions = function(custom){ + options = {}; + + // account for deprecated UK English spelling + if (custom.colour) { + custom.color = custom.colour; + } + + for(var key in defaults){ + options[key] = custom.hasOwnProperty(key) ? custom[key] : defaults[key]; + } + return this; + }; + + Tinycon.setImage = function(url){ + currentFavicon = url; + refreshFavicon(); + return this; + }; + + Tinycon.setBubble = function(label, color) { + label = label || ''; + drawFavicon(label, color); + return this; + }; + + Tinycon.reset = function(){ + currentFavicon = originalFavicon; + setFaviconTag(originalFavicon); + }; + + Tinycon.setOptions(defaults); + + if(typeof define === 'function' && define.amd) { + define(Tinycon); + } else if (typeof module !== 'undefined') { + module.exports = Tinycon; + } else { + window.Tinycon = Tinycon; + } })(); From ea8e815cb7bc0cb12b1944e865ebd8323b3523dc Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Sat, 9 Apr 2016 10:34:52 -0700 Subject: [PATCH 27/41] Updated documentation Added note on installing from github Fixed spelling mistakes Reminified --- README.md | 21 +++++++++++++++------ tinycon.min.js | 2 +- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 80dac26..e78ddcf 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Tinycon -A small library for manipulating the favicon, in particular adding alert bubbles and changing images. Tinycon gracefully falls back to a number in title approach for browers that don't support canvas or dynamic favicons. +A small library for manipulating the favicon, in particular adding alert bubbles and changing images. Tinycon gracefully falls back to a number in title approach for browsers that don't support canvas or dynamic favicons. @@ -8,7 +8,16 @@ A small library for manipulating the favicon, in particular adding alert bubbles ## Documentation -Tinycon adds a single object to the global namespace and does not require initialisation. +Tinycon adds a single object to the global namespace and does not require initialisation. + +### Installation + +There are several versions of Tinycon published on NPM, unfortunately they are not controlled by me and do not track HEAD. The best idea is to install from github +directly and cut out the middleman! + +``` +npm install tommoor/tinycon --save +``` ### Basic Usage @@ -23,8 +32,8 @@ 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 +* color: the foreground font color +* background: the alert bubble background color * fallback: should we fallback to a number in brackets for browsers that don't support canvas/dynamic favicons? Boolean, or use the string 'force' to ensure a title update even in supported browsers. * abbreviate: should tinycon shrink large numbers such as 1000 to an abbreviated version (1k). Boolean, defaults to true @@ -33,7 +42,7 @@ Tinycon.setOptions({ width: 7, height: 9, font: '10px arial', - colour: '#ffffff', + color: '#ffffff', background: '#549A2F', fallback: true }); @@ -52,7 +61,7 @@ require([ width: 7, height: 9, font: '10px arial', - colour: '#ffffff', + color: '#ffffff', background: '#549A2F', fallback: true }); diff --git a/tinycon.min.js b/tinycon.min.js index 9536565..dc796a3 100644 --- a/tinycon.min.js +++ b/tinycon.min.js @@ -5,4 +5,4 @@ * @license MIT Licensed * @version 0.6.4 */ -!function(){var a={},b=null,c=null,d=null,e=null,f={},g=window.devicePixelRatio||1,h=16*g,i={width:7,height:9,font:10*g+"px arial",colour:"#ffffff",background:"#F03D25",fallback:!0,crossOrigin:!0,abbreviate:!0},j=function(){var a=navigator.userAgent.toLowerCase();return function(b){return-1!==a.indexOf(b)}}(),k={ie:j("msie"),chrome:j("chrome"),webkit:j("chrome")||j("safari"),safari:j("safari")&&!j("chrome"),mozilla:j("mozilla")&&!j("chrome")&&!j("safari")},l=function(){for(var a=document.getElementsByTagName("link"),b=0,c=a.length;c>b;b++)if((a[b].getAttribute("rel")||"").match(/\bicon\b/))return a[b];return!1},m=function(){for(var a=document.getElementsByTagName("link"),b=document.getElementsByTagName("head")[0],c=0,d=a.length;d>c;c++){var e="undefined"!=typeof a[c];e&&(a[c].getAttribute("rel")||"").match(/\bicon\b/)&&b.removeChild(a[c])}},n=function(){if(!c||!b){var a=l();c=b=a?a.getAttribute("href"):"/favicon.ico"}return b},o=function(){return e||(e=document.createElement("canvas"),e.width=h,e.height=h),e},p=function(a){if(a){m();var b=document.createElement("link");b.type="image/x-icon",b.rel="icon",b.href=a,document.getElementsByTagName("head")[0].appendChild(b)}},q=function(a,b){if(!o().getContext||k.ie||k.safari||"force"===f.fallback)return r(a);var c=o().getContext("2d"),b=b||"#000000",e=n();d=document.createElement("img"),d.onload=function(){c.clearRect(0,0,h,h),c.drawImage(d,0,0,d.width,d.height,0,0,h,h),(a+"").length>0&&s(c,a,b),t()},!e.match(/^data/)&&f.crossOrigin&&(d.crossOrigin="anonymous"),d.src=e},r=function(a){if(f.fallback){var b=document.title;"("===b[0]&&(b=b.slice(b.indexOf(" "))),(a+"").length>0?document.title="("+a+") "+b:document.title=b}},s=function(a,b,c){"number"==typeof b&&b>99&&f.abbreviate&&(b=u(b));var d=(b+"").length-1,e=f.width*g+6*g*d,i=f.height*g,j=h-i,l=h-e-g,m=16*g,n=16*g,o=2*g;a.font=(k.webkit?"bold ":"")+f.font,a.fillStyle=f.background,a.strokeStyle=f.background,a.lineWidth=g,a.beginPath(),a.moveTo(l+o,j),a.quadraticCurveTo(l,j,l,j+o),a.lineTo(l,m-o),a.quadraticCurveTo(l,m,l+o,m),a.lineTo(n-o,m),a.quadraticCurveTo(n,m,n,m-o),a.lineTo(n,j+o),a.quadraticCurveTo(n,j,n-o,j),a.closePath(),a.fill(),a.beginPath(),a.strokeStyle="rgba(0,0,0,0.3)",a.moveTo(l+o/2,m),a.lineTo(n-o/2,m),a.stroke(),a.fillStyle=f.colour,a.textAlign="right",a.textBaseline="top",a.fillText(b,2===g?29:15,k.mozilla?7*g:6*g)},t=function(){o().getContext&&p(o().toDataURL())},u=function(a){for(var b=[["G",1e9],["M",1e6],["k",1e3]],c=0;c=b[c][1]){a=v(a/b[c][1])+b[c][0];break}return a},v=function(a,b){var c=new Number(a);return c.toFixed(b)};a.setOptions=function(a){f={};for(var b in i)f[b]=a.hasOwnProperty(b)?a[b]:i[b];return this},a.setImage=function(a){return b=a,t(),this},a.setBubble=function(a,b){return a=a||"",q(a,b),this},a.reset=function(){p(c)},a.setOptions(i),"function"==typeof define&&define.amd?define(a):"undefined"!=typeof module?module.exports=a:window.Tinycon=a}(); \ No newline at end of file +!function(){var a={},b=null,c=null,d=null,e=null,f={},g=window.devicePixelRatio||1,h=16*g,i={width:7,height:9,font:10*g+"px arial",color:"#ffffff",background:"#F03D25",fallback:!0,crossOrigin:!0,abbreviate:!0},j=function(){var a=navigator.userAgent.toLowerCase();return function(b){return-1!==a.indexOf(b)}}(),k={ie:j("trident"),chrome:j("chrome"),webkit:j("chrome")||j("safari"),safari:j("safari")&&!j("chrome"),mozilla:j("mozilla")&&!j("chrome")&&!j("safari")},l=function(){for(var a=document.getElementsByTagName("link"),b=0,c=a.length;c>b;b++)if((a[b].getAttribute("rel")||"").match(/\bicon\b/i))return a[b];return!1},m=function(){for(var a=document.getElementsByTagName("link"),b=document.getElementsByTagName("head")[0],c=0,d=a.length;d>c;c++){var e="undefined"!=typeof a[c];e&&(a[c].getAttribute("rel")||"").match(/\bicon\b/i)&&b.removeChild(a[c])}},n=function(){if(!c||!b){var a=l();b=a?a.getAttribute("href"):"/favicon.ico",c||(c=b)}return b},o=function(){return e||(e=document.createElement("canvas"),e.width=h,e.height=h),e},p=function(a){if(a){m();var b=document.createElement("link");b.type="image/x-icon",b.rel="icon",b.href=a,document.getElementsByTagName("head")[0].appendChild(b)}},q=function(a,b){if(!o().getContext||k.ie||k.safari||"force"===f.fallback)return r(a);var c=o().getContext("2d"),b=b||"#000000",e=n();d=document.createElement("img"),d.onload=function(){c.clearRect(0,0,h,h),c.drawImage(d,0,0,d.width,d.height,0,0,h,h),(a+"").length>0&&s(c,a,b),t()},!e.match(/^data/)&&f.crossOrigin&&(d.crossOrigin="anonymous"),d.src=e},r=function(a){if(f.fallback){var b=document.title;"("===b[0]&&(b=b.slice(b.indexOf(" "))),(a+"").length>0?document.title="("+a+") "+b:document.title=b}},s=function(a,b,c){"number"==typeof b&&b>99&&f.abbreviate&&(b=u(b));var d=(b+"").length-1,e=f.width*g+6*g*d,i=f.height*g,j=h-i,l=h-e-g,m=16*g,n=16*g,o=2*g;a.font=(k.webkit?"bold ":"")+f.font,a.fillStyle=f.background,a.strokeStyle=f.background,a.lineWidth=g,a.beginPath(),a.moveTo(l+o,j),a.quadraticCurveTo(l,j,l,j+o),a.lineTo(l,m-o),a.quadraticCurveTo(l,m,l+o,m),a.lineTo(n-o,m),a.quadraticCurveTo(n,m,n,m-o),a.lineTo(n,j+o),a.quadraticCurveTo(n,j,n-o,j),a.closePath(),a.fill(),a.beginPath(),a.strokeStyle="rgba(0,0,0,0.3)",a.moveTo(l+o/2,m),a.lineTo(n-o/2,m),a.stroke(),a.fillStyle=f.color,a.textAlign="right",a.textBaseline="top",a.fillText(b,2===g?29:15,k.mozilla?7*g:6*g)},t=function(){o().getContext&&p(o().toDataURL())},u=function(a){for(var b=[["G",1e9],["M",1e6],["k",1e3]],c=0;c=b[c][1]){a=v(a/b[c][1])+b[c][0];break}return a},v=function(a,b){var c=new Number(a);return c.toFixed(b)};a.setOptions=function(a){f={},a.colour&&(a.color=a.colour);for(var b in i)f[b]=a.hasOwnProperty(b)?a[b]:i[b];return this},a.setImage=function(a){return b=a,t(),this},a.setBubble=function(a,b){return a=a||"",q(a,b),this},a.reset=function(){b=c,p(c)},a.setOptions(i),"function"==typeof define&&define.amd?define(a):"undefined"!=typeof module?module.exports=a:window.Tinycon=a}(); \ No newline at end of file From 5fdc1dd8229de0427ee1a03d058bdc62b30c7b4b Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Sat, 9 Apr 2016 10:35:37 -0700 Subject: [PATCH 28/41] Bump 0.6.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 93d1e34..5a26e98 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tinycon", - "version": "0.6.4", + "version": "0.6.5", "description": "Add notification bubbles in the favicon", "author": "Tom Moor (http://tommoor.com)", "main" : "./tinycon.js", From 36179d92aa9c0d3bdef22f31feb7399216cfd587 Mon Sep 17 00:00:00 2001 From: Mikael Korpela Date: Wed, 11 May 2016 18:46:40 +0300 Subject: [PATCH 29/41] Add bower.json Basic Bower json as per spec: https://github.com/bower/spec/blob/master/json.md --- bower.json | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 bower.json diff --git a/bower.json b/bower.json new file mode 100644 index 0000000..23e091a --- /dev/null +++ b/bower.json @@ -0,0 +1,30 @@ +{ + "name": "tinycon", + "description": "A small library for manipulating the favicon, in particular adding alert bubbles and changing images.", + "homepage": "http://blog.tommoor.com/tinycon/", + "repository": { + "type": "git", + "url": "https://github.com/tommoor/tinycon.git" + }, + "moduleType": [ + "globals", + "amd" + ], + "keywords": [ + "favicon", + "notification" + ], + "main": [ + "tinycon.js" + ], + "ignore": [ + "examples", + "Gruntfile.js", + ".gitignore", + "*.md", + "LICENSE", + "package.json" + ], + "private": false, + "license": "MIT" +} From 06fa31a2c1a3a4f899402d116e1c8214f98d7cf0 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 6 Jul 2016 14:13:52 -0400 Subject: [PATCH 30/41] Added license property to package.json --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 5a26e98..8876c09 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "0.6.5", "description": "Add notification bubbles in the favicon", "author": "Tom Moor (http://tommoor.com)", + "license": "MIT", "main" : "./tinycon.js", "repository" : { "type": "git", From 75baba2b33f97e98da1ff9778438b114cea033bc Mon Sep 17 00:00:00 2001 From: Phil Harnish Date: Fri, 12 Sep 2014 08:51:55 -0700 Subject: [PATCH 31/41] Chrome browsers with nonstandard zoom report fractional devicePixelRatio. Fractional pixel values cause drawing artifacts with text. Tested on a retina display (rounds up to 2) and a standard display (stays at 1). --- tinycon.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/tinycon.js b/tinycon.js index 19d2245..85a9a63 100644 --- a/tinycon.js +++ b/tinycon.js @@ -14,7 +14,8 @@ var faviconImage = null; var canvas = null; var options = {}; - var r = window.devicePixelRatio || 1; + // Chrome browsers with nonstandard zoom report fractional devicePixelRatio. + var r = Math.ceil(window.devicePixelRatio) || 1; var size = 16 * r; var defaults = { width: 7, @@ -192,16 +193,16 @@ // bubble context.beginPath(); - context.moveTo(left + radius, top); + context.moveTo(left + radius, top); context.quadraticCurveTo(left, top, left, top + radius); context.lineTo(left, bottom - radius); - context.quadraticCurveTo(left, bottom, left + radius, bottom); - context.lineTo(right - radius, bottom); - context.quadraticCurveTo(right, bottom, right, bottom - radius); - context.lineTo(right, top + radius); - context.quadraticCurveTo(right, top, right - radius, top); - context.closePath(); - context.fill(); + context.quadraticCurveTo(left, bottom, left + radius, bottom); + context.lineTo(right - radius, bottom); + context.quadraticCurveTo(right, bottom, right, bottom - radius); + context.lineTo(right, top + radius); + context.quadraticCurveTo(right, top, right - radius, top); + context.closePath(); + context.fill(); // bottom shadow context.beginPath(); From 38ab833ff6eef5b8f0cce61dedc2bbe39182f3de Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Sat, 13 Aug 2016 15:38:39 -0700 Subject: [PATCH 32/41] Added minified file and README note --- README.md | 5 +++++ tinycon.min.js | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e78ddcf..bd23897 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,11 @@ Currently the library degrades to title update: * Safari 5 +## Development + +To produce the minified file run `grunt uglify` + + ## License / Credits Tinycon is released under the MIT license. It is simple and easy to understand and places almost no restrictions on what you can do with Tinycon. diff --git a/tinycon.min.js b/tinycon.min.js index dc796a3..b39f400 100644 --- a/tinycon.min.js +++ b/tinycon.min.js @@ -5,4 +5,4 @@ * @license MIT Licensed * @version 0.6.4 */ -!function(){var a={},b=null,c=null,d=null,e=null,f={},g=window.devicePixelRatio||1,h=16*g,i={width:7,height:9,font:10*g+"px arial",color:"#ffffff",background:"#F03D25",fallback:!0,crossOrigin:!0,abbreviate:!0},j=function(){var a=navigator.userAgent.toLowerCase();return function(b){return-1!==a.indexOf(b)}}(),k={ie:j("trident"),chrome:j("chrome"),webkit:j("chrome")||j("safari"),safari:j("safari")&&!j("chrome"),mozilla:j("mozilla")&&!j("chrome")&&!j("safari")},l=function(){for(var a=document.getElementsByTagName("link"),b=0,c=a.length;c>b;b++)if((a[b].getAttribute("rel")||"").match(/\bicon\b/i))return a[b];return!1},m=function(){for(var a=document.getElementsByTagName("link"),b=document.getElementsByTagName("head")[0],c=0,d=a.length;d>c;c++){var e="undefined"!=typeof a[c];e&&(a[c].getAttribute("rel")||"").match(/\bicon\b/i)&&b.removeChild(a[c])}},n=function(){if(!c||!b){var a=l();b=a?a.getAttribute("href"):"/favicon.ico",c||(c=b)}return b},o=function(){return e||(e=document.createElement("canvas"),e.width=h,e.height=h),e},p=function(a){if(a){m();var b=document.createElement("link");b.type="image/x-icon",b.rel="icon",b.href=a,document.getElementsByTagName("head")[0].appendChild(b)}},q=function(a,b){if(!o().getContext||k.ie||k.safari||"force"===f.fallback)return r(a);var c=o().getContext("2d"),b=b||"#000000",e=n();d=document.createElement("img"),d.onload=function(){c.clearRect(0,0,h,h),c.drawImage(d,0,0,d.width,d.height,0,0,h,h),(a+"").length>0&&s(c,a,b),t()},!e.match(/^data/)&&f.crossOrigin&&(d.crossOrigin="anonymous"),d.src=e},r=function(a){if(f.fallback){var b=document.title;"("===b[0]&&(b=b.slice(b.indexOf(" "))),(a+"").length>0?document.title="("+a+") "+b:document.title=b}},s=function(a,b,c){"number"==typeof b&&b>99&&f.abbreviate&&(b=u(b));var d=(b+"").length-1,e=f.width*g+6*g*d,i=f.height*g,j=h-i,l=h-e-g,m=16*g,n=16*g,o=2*g;a.font=(k.webkit?"bold ":"")+f.font,a.fillStyle=f.background,a.strokeStyle=f.background,a.lineWidth=g,a.beginPath(),a.moveTo(l+o,j),a.quadraticCurveTo(l,j,l,j+o),a.lineTo(l,m-o),a.quadraticCurveTo(l,m,l+o,m),a.lineTo(n-o,m),a.quadraticCurveTo(n,m,n,m-o),a.lineTo(n,j+o),a.quadraticCurveTo(n,j,n-o,j),a.closePath(),a.fill(),a.beginPath(),a.strokeStyle="rgba(0,0,0,0.3)",a.moveTo(l+o/2,m),a.lineTo(n-o/2,m),a.stroke(),a.fillStyle=f.color,a.textAlign="right",a.textBaseline="top",a.fillText(b,2===g?29:15,k.mozilla?7*g:6*g)},t=function(){o().getContext&&p(o().toDataURL())},u=function(a){for(var b=[["G",1e9],["M",1e6],["k",1e3]],c=0;c=b[c][1]){a=v(a/b[c][1])+b[c][0];break}return a},v=function(a,b){var c=new Number(a);return c.toFixed(b)};a.setOptions=function(a){f={},a.colour&&(a.color=a.colour);for(var b in i)f[b]=a.hasOwnProperty(b)?a[b]:i[b];return this},a.setImage=function(a){return b=a,t(),this},a.setBubble=function(a,b){return a=a||"",q(a,b),this},a.reset=function(){b=c,p(c)},a.setOptions(i),"function"==typeof define&&define.amd?define(a):"undefined"!=typeof module?module.exports=a:window.Tinycon=a}(); \ No newline at end of file +!function(){var a={},b=null,c=null,d=null,e=null,f={},g=Math.ceil(window.devicePixelRatio)||1,h=16*g,i={width:7,height:9,font:10*g+"px arial",color:"#ffffff",background:"#F03D25",fallback:!0,crossOrigin:!0,abbreviate:!0},j=function(){var a=navigator.userAgent.toLowerCase();return function(b){return-1!==a.indexOf(b)}}(),k={ie:j("trident"),chrome:j("chrome"),webkit:j("chrome")||j("safari"),safari:j("safari")&&!j("chrome"),mozilla:j("mozilla")&&!j("chrome")&&!j("safari")},l=function(){for(var a=document.getElementsByTagName("link"),b=0,c=a.length;c>b;b++)if((a[b].getAttribute("rel")||"").match(/\bicon\b/i))return a[b];return!1},m=function(){for(var a=document.getElementsByTagName("link"),b=document.getElementsByTagName("head")[0],c=0,d=a.length;d>c;c++){var e="undefined"!=typeof a[c];e&&(a[c].getAttribute("rel")||"").match(/\bicon\b/i)&&b.removeChild(a[c])}},n=function(){if(!c||!b){var a=l();b=a?a.getAttribute("href"):"/favicon.ico",c||(c=b)}return b},o=function(){return e||(e=document.createElement("canvas"),e.width=h,e.height=h),e},p=function(a){if(a){m();var b=document.createElement("link");b.type="image/x-icon",b.rel="icon",b.href=a,document.getElementsByTagName("head")[0].appendChild(b)}},q=function(a,b){if(!o().getContext||k.ie||k.safari||"force"===f.fallback)return r(a);var c=o().getContext("2d"),b=b||"#000000",e=n();d=document.createElement("img"),d.onload=function(){c.clearRect(0,0,h,h),c.drawImage(d,0,0,d.width,d.height,0,0,h,h),(a+"").length>0&&s(c,a,b),t()},!e.match(/^data/)&&f.crossOrigin&&(d.crossOrigin="anonymous"),d.src=e},r=function(a){if(f.fallback){var b=document.title;"("===b[0]&&(b=b.slice(b.indexOf(" "))),(a+"").length>0?document.title="("+a+") "+b:document.title=b}},s=function(a,b,c){"number"==typeof b&&b>99&&f.abbreviate&&(b=u(b));var d=(b+"").length-1,e=f.width*g+6*g*d,i=f.height*g,j=h-i,l=h-e-g,m=16*g,n=16*g,o=2*g;a.font=(k.webkit?"bold ":"")+f.font,a.fillStyle=f.background,a.strokeStyle=f.background,a.lineWidth=g,a.beginPath(),a.moveTo(l+o,j),a.quadraticCurveTo(l,j,l,j+o),a.lineTo(l,m-o),a.quadraticCurveTo(l,m,l+o,m),a.lineTo(n-o,m),a.quadraticCurveTo(n,m,n,m-o),a.lineTo(n,j+o),a.quadraticCurveTo(n,j,n-o,j),a.closePath(),a.fill(),a.beginPath(),a.strokeStyle="rgba(0,0,0,0.3)",a.moveTo(l+o/2,m),a.lineTo(n-o/2,m),a.stroke(),a.fillStyle=f.color,a.textAlign="right",a.textBaseline="top",a.fillText(b,2===g?29:15,k.mozilla?7*g:6*g)},t=function(){o().getContext&&p(o().toDataURL())},u=function(a){for(var b=[["G",1e9],["M",1e6],["k",1e3]],c=0;c=b[c][1]){a=v(a/b[c][1])+b[c][0];break}return a},v=function(a,b){var c=new Number(a);return c.toFixed(b)};a.setOptions=function(a){f={},a.colour&&(a.color=a.colour);for(var b in i)f[b]=a.hasOwnProperty(b)?a[b]:i[b];return this},a.setImage=function(a){return b=a,t(),this},a.setBubble=function(a,b){return a=a||"",q(a,b),this},a.reset=function(){b=c,p(c)},a.setOptions(i),"function"==typeof define&&define.amd?define(a):"undefined"!=typeof module?module.exports=a:window.Tinycon=a}(); \ No newline at end of file From cdb71d792b2438a167a014e20093c92c3cfa94ce Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Sat, 13 Aug 2016 15:38:44 -0700 Subject: [PATCH 33/41] 0.6.6 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8876c09..01e9844 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tinycon", - "version": "0.6.5", + "version": "0.6.6", "description": "Add notification bubbles in the favicon", "author": "Tom Moor (http://tommoor.com)", "license": "MIT", From 83e7ef5765f1b29e1abeee6262f9b5b3f9242c24 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Sat, 13 Aug 2016 15:42:43 -0700 Subject: [PATCH 34/41] Removed version note from comment, its in the package.json --- tinycon.js | 1 - tinycon.min.js | 1 - 2 files changed, 2 deletions(-) diff --git a/tinycon.js b/tinycon.js index 85a9a63..a694923 100644 --- a/tinycon.js +++ b/tinycon.js @@ -3,7 +3,6 @@ * Tom Moor, http://tommoor.com * Copyright (c) 2015 Tom Moor * @license MIT Licensed - * @version 0.6.4 */ (function(){ diff --git a/tinycon.min.js b/tinycon.min.js index b39f400..1e533d8 100644 --- a/tinycon.min.js +++ b/tinycon.min.js @@ -3,6 +3,5 @@ * Tom Moor, http://tommoor.com * Copyright (c) 2015 Tom Moor * @license MIT Licensed - * @version 0.6.4 */ !function(){var a={},b=null,c=null,d=null,e=null,f={},g=Math.ceil(window.devicePixelRatio)||1,h=16*g,i={width:7,height:9,font:10*g+"px arial",color:"#ffffff",background:"#F03D25",fallback:!0,crossOrigin:!0,abbreviate:!0},j=function(){var a=navigator.userAgent.toLowerCase();return function(b){return-1!==a.indexOf(b)}}(),k={ie:j("trident"),chrome:j("chrome"),webkit:j("chrome")||j("safari"),safari:j("safari")&&!j("chrome"),mozilla:j("mozilla")&&!j("chrome")&&!j("safari")},l=function(){for(var a=document.getElementsByTagName("link"),b=0,c=a.length;c>b;b++)if((a[b].getAttribute("rel")||"").match(/\bicon\b/i))return a[b];return!1},m=function(){for(var a=document.getElementsByTagName("link"),b=document.getElementsByTagName("head")[0],c=0,d=a.length;d>c;c++){var e="undefined"!=typeof a[c];e&&(a[c].getAttribute("rel")||"").match(/\bicon\b/i)&&b.removeChild(a[c])}},n=function(){if(!c||!b){var a=l();b=a?a.getAttribute("href"):"/favicon.ico",c||(c=b)}return b},o=function(){return e||(e=document.createElement("canvas"),e.width=h,e.height=h),e},p=function(a){if(a){m();var b=document.createElement("link");b.type="image/x-icon",b.rel="icon",b.href=a,document.getElementsByTagName("head")[0].appendChild(b)}},q=function(a,b){if(!o().getContext||k.ie||k.safari||"force"===f.fallback)return r(a);var c=o().getContext("2d"),b=b||"#000000",e=n();d=document.createElement("img"),d.onload=function(){c.clearRect(0,0,h,h),c.drawImage(d,0,0,d.width,d.height,0,0,h,h),(a+"").length>0&&s(c,a,b),t()},!e.match(/^data/)&&f.crossOrigin&&(d.crossOrigin="anonymous"),d.src=e},r=function(a){if(f.fallback){var b=document.title;"("===b[0]&&(b=b.slice(b.indexOf(" "))),(a+"").length>0?document.title="("+a+") "+b:document.title=b}},s=function(a,b,c){"number"==typeof b&&b>99&&f.abbreviate&&(b=u(b));var d=(b+"").length-1,e=f.width*g+6*g*d,i=f.height*g,j=h-i,l=h-e-g,m=16*g,n=16*g,o=2*g;a.font=(k.webkit?"bold ":"")+f.font,a.fillStyle=f.background,a.strokeStyle=f.background,a.lineWidth=g,a.beginPath(),a.moveTo(l+o,j),a.quadraticCurveTo(l,j,l,j+o),a.lineTo(l,m-o),a.quadraticCurveTo(l,m,l+o,m),a.lineTo(n-o,m),a.quadraticCurveTo(n,m,n,m-o),a.lineTo(n,j+o),a.quadraticCurveTo(n,j,n-o,j),a.closePath(),a.fill(),a.beginPath(),a.strokeStyle="rgba(0,0,0,0.3)",a.moveTo(l+o/2,m),a.lineTo(n-o/2,m),a.stroke(),a.fillStyle=f.color,a.textAlign="right",a.textBaseline="top",a.fillText(b,2===g?29:15,k.mozilla?7*g:6*g)},t=function(){o().getContext&&p(o().toDataURL())},u=function(a){for(var b=[["G",1e9],["M",1e6],["k",1e3]],c=0;c=b[c][1]){a=v(a/b[c][1])+b[c][0];break}return a},v=function(a,b){var c=new Number(a);return c.toFixed(b)};a.setOptions=function(a){f={},a.colour&&(a.color=a.colour);for(var b in i)f[b]=a.hasOwnProperty(b)?a[b]:i[b];return this},a.setImage=function(a){return b=a,t(),this},a.setBubble=function(a,b){return a=a||"",q(a,b),this},a.reset=function(){b=c,p(c)},a.setOptions(i),"function"==typeof define&&define.amd?define(a):"undefined"!=typeof module?module.exports=a:window.Tinycon=a}(); \ No newline at end of file From 729941a1ada19fbb59b807f808a6031ad0ff1cb8 Mon Sep 17 00:00:00 2001 From: David Palm Date: Mon, 20 Mar 2017 14:41:22 +0100 Subject: [PATCH 35/41] Do not assume tags are children of --- tinycon.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tinycon.js b/tinycon.js index a694923..0b77a73 100644 --- a/tinycon.js +++ b/tinycon.js @@ -60,12 +60,11 @@ var removeFaviconTag = function(){ var links = document.getElementsByTagName('link'); - var head = document.getElementsByTagName('head')[0]; for(var i=0, len=links.length; i < len; i++) { var exists = (typeof(links[i]) !== 'undefined'); if (exists && (links[i].getAttribute('rel') || '').match(/\bicon\b/i)) { - head.removeChild(links[i]); + links[i].parentNode.removeChild(links[i]); } } }; From b904b2568d7b326ea38d11aa7abe50ffd29d5b3e Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Sat, 1 Apr 2017 10:03:36 -0700 Subject: [PATCH 36/41] Add prepublish --- package.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 01e9844..8ab485e 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,14 @@ { - "name": "tinycon", + "name": "@tommoor/tinycon", "version": "0.6.6", "description": "Add notification bubbles in the favicon", "author": "Tom Moor (http://tommoor.com)", "license": "MIT", "main" : "./tinycon.js", + "scripts": { + "build": "grunt uglify", + "prepublish": "grunt uglify" + }, "repository" : { "type": "git", "url": "git://github.com/tommoor/tinycon.git" From 0001094646a6aafb0d69cfd1e7e51d6af58fb4fb Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Sat, 1 Apr 2017 10:03:39 -0700 Subject: [PATCH 37/41] 0.6.7 --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 8ab485e..cf83f77 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,15 @@ { "name": "@tommoor/tinycon", - "version": "0.6.6", + "version": "0.6.7", "description": "Add notification bubbles in the favicon", "author": "Tom Moor (http://tommoor.com)", "license": "MIT", - "main" : "./tinycon.js", + "main": "./tinycon.js", "scripts": { "build": "grunt uglify", "prepublish": "grunt uglify" }, - "repository" : { + "repository": { "type": "git", "url": "git://github.com/tommoor/tinycon.git" }, From 82accb1523cd96781cd943124a9698f6f072f342 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Sat, 1 Apr 2017 10:13:28 -0700 Subject: [PATCH 38/41] NPM publishable --- .gitignore | 1 + package.json | 5 +++-- tinycon.min.js | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 646ac51..6e984a3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .DS_Store +.log node_modules/ diff --git a/package.json b/package.json index cf83f77..de4f374 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "@tommoor/tinycon", + "name": "tinycon", "version": "0.6.7", "description": "Add notification bubbles in the favicon", "author": "Tom Moor (http://tommoor.com)", @@ -14,6 +14,7 @@ "url": "git://github.com/tommoor/tinycon.git" }, "devDependencies": { - "grunt": "~0.4.5" + "grunt": "~0.4.5", + "grunt-contrib-uglify": "^2.2.1" } } diff --git a/tinycon.min.js b/tinycon.min.js index 1e533d8..659c99a 100644 --- a/tinycon.min.js +++ b/tinycon.min.js @@ -4,4 +4,4 @@ * Copyright (c) 2015 Tom Moor * @license MIT Licensed */ -!function(){var a={},b=null,c=null,d=null,e=null,f={},g=Math.ceil(window.devicePixelRatio)||1,h=16*g,i={width:7,height:9,font:10*g+"px arial",color:"#ffffff",background:"#F03D25",fallback:!0,crossOrigin:!0,abbreviate:!0},j=function(){var a=navigator.userAgent.toLowerCase();return function(b){return-1!==a.indexOf(b)}}(),k={ie:j("trident"),chrome:j("chrome"),webkit:j("chrome")||j("safari"),safari:j("safari")&&!j("chrome"),mozilla:j("mozilla")&&!j("chrome")&&!j("safari")},l=function(){for(var a=document.getElementsByTagName("link"),b=0,c=a.length;c>b;b++)if((a[b].getAttribute("rel")||"").match(/\bicon\b/i))return a[b];return!1},m=function(){for(var a=document.getElementsByTagName("link"),b=document.getElementsByTagName("head")[0],c=0,d=a.length;d>c;c++){var e="undefined"!=typeof a[c];e&&(a[c].getAttribute("rel")||"").match(/\bicon\b/i)&&b.removeChild(a[c])}},n=function(){if(!c||!b){var a=l();b=a?a.getAttribute("href"):"/favicon.ico",c||(c=b)}return b},o=function(){return e||(e=document.createElement("canvas"),e.width=h,e.height=h),e},p=function(a){if(a){m();var b=document.createElement("link");b.type="image/x-icon",b.rel="icon",b.href=a,document.getElementsByTagName("head")[0].appendChild(b)}},q=function(a,b){if(!o().getContext||k.ie||k.safari||"force"===f.fallback)return r(a);var c=o().getContext("2d"),b=b||"#000000",e=n();d=document.createElement("img"),d.onload=function(){c.clearRect(0,0,h,h),c.drawImage(d,0,0,d.width,d.height,0,0,h,h),(a+"").length>0&&s(c,a,b),t()},!e.match(/^data/)&&f.crossOrigin&&(d.crossOrigin="anonymous"),d.src=e},r=function(a){if(f.fallback){var b=document.title;"("===b[0]&&(b=b.slice(b.indexOf(" "))),(a+"").length>0?document.title="("+a+") "+b:document.title=b}},s=function(a,b,c){"number"==typeof b&&b>99&&f.abbreviate&&(b=u(b));var d=(b+"").length-1,e=f.width*g+6*g*d,i=f.height*g,j=h-i,l=h-e-g,m=16*g,n=16*g,o=2*g;a.font=(k.webkit?"bold ":"")+f.font,a.fillStyle=f.background,a.strokeStyle=f.background,a.lineWidth=g,a.beginPath(),a.moveTo(l+o,j),a.quadraticCurveTo(l,j,l,j+o),a.lineTo(l,m-o),a.quadraticCurveTo(l,m,l+o,m),a.lineTo(n-o,m),a.quadraticCurveTo(n,m,n,m-o),a.lineTo(n,j+o),a.quadraticCurveTo(n,j,n-o,j),a.closePath(),a.fill(),a.beginPath(),a.strokeStyle="rgba(0,0,0,0.3)",a.moveTo(l+o/2,m),a.lineTo(n-o/2,m),a.stroke(),a.fillStyle=f.color,a.textAlign="right",a.textBaseline="top",a.fillText(b,2===g?29:15,k.mozilla?7*g:6*g)},t=function(){o().getContext&&p(o().toDataURL())},u=function(a){for(var b=[["G",1e9],["M",1e6],["k",1e3]],c=0;c=b[c][1]){a=v(a/b[c][1])+b[c][0];break}return a},v=function(a,b){var c=new Number(a);return c.toFixed(b)};a.setOptions=function(a){f={},a.colour&&(a.color=a.colour);for(var b in i)f[b]=a.hasOwnProperty(b)?a[b]:i[b];return this},a.setImage=function(a){return b=a,t(),this},a.setBubble=function(a,b){return a=a||"",q(a,b),this},a.reset=function(){b=c,p(c)},a.setOptions(i),"function"==typeof define&&define.amd?define(a):"undefined"!=typeof module?module.exports=a:window.Tinycon=a}(); \ No newline at end of file +!function(){var a={},b=null,c=null,d=null,e=null,f={},g=Math.ceil(window.devicePixelRatio)||1,h=16*g,i={width:7,height:9,font:10*g+"px arial",color:"#ffffff",background:"#F03D25",fallback:!0,crossOrigin:!0,abbreviate:!0},j=function(){var a=navigator.userAgent.toLowerCase();return function(b){return a.indexOf(b)!==-1}}(),k={ie:j("trident"),chrome:j("chrome"),webkit:j("chrome")||j("safari"),safari:j("safari")&&!j("chrome"),mozilla:j("mozilla")&&!j("chrome")&&!j("safari")},l=function(){for(var a=document.getElementsByTagName("link"),b=0,c=a.length;b0&&s(c,a,b),t()},!e.match(/^data/)&&f.crossOrigin&&(d.crossOrigin="anonymous"),d.src=e},r=function(a){if(f.fallback){var b=document.title;"("===b[0]&&(b=b.slice(b.indexOf(" "))),(a+"").length>0?document.title="("+a+") "+b:document.title=b}},s=function(a,b,c){"number"==typeof b&&b>99&&f.abbreviate&&(b=u(b));var d=(b+"").length-1,e=f.width*g+6*g*d,i=f.height*g,j=h-i,l=h-e-g,m=16*g,n=16*g,o=2*g;a.font=(k.webkit?"bold ":"")+f.font,a.fillStyle=f.background,a.strokeStyle=f.background,a.lineWidth=g,a.beginPath(),a.moveTo(l+o,j),a.quadraticCurveTo(l,j,l,j+o),a.lineTo(l,m-o),a.quadraticCurveTo(l,m,l+o,m),a.lineTo(n-o,m),a.quadraticCurveTo(n,m,n,m-o),a.lineTo(n,j+o),a.quadraticCurveTo(n,j,n-o,j),a.closePath(),a.fill(),a.beginPath(),a.strokeStyle="rgba(0,0,0,0.3)",a.moveTo(l+o/2,m),a.lineTo(n-o/2,m),a.stroke(),a.fillStyle=f.color,a.textAlign="right",a.textBaseline="top",a.fillText(b,2===g?29:15,k.mozilla?7*g:6*g)},t=function(){o().getContext&&p(o().toDataURL())},u=function(a){for(var b=[["G",1e9],["M",1e6],["k",1e3]],c=0;c=b[c][1]){a=v(a/b[c][1])+b[c][0];break}return a},v=function(a,b){return new Number(a).toFixed(b)};a.setOptions=function(a){f={},a.colour&&(a.color=a.colour);for(var b in i)f[b]=a.hasOwnProperty(b)?a[b]:i[b];return this},a.setImage=function(a){return b=a,t(),this},a.setBubble=function(a,b){return a=a||"",q(a,b),this},a.reset=function(){b=c,p(c)},a.setOptions(i),"function"==typeof define&&define.amd?define(a):"undefined"!=typeof module?module.exports=a:window.Tinycon=a}(); \ No newline at end of file From 8d62eee74e33c467efae331e697416a1c6371d32 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Sat, 1 Apr 2017 10:13:32 -0700 Subject: [PATCH 39/41] 0.6.8 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index de4f374..7797642 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tinycon", - "version": "0.6.7", + "version": "0.6.8", "description": "Add notification bubbles in the favicon", "author": "Tom Moor (http://tommoor.com)", "license": "MIT", From 83ed386e367d0bb6e27b496ec3b6240ce43f6a27 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Wed, 5 Apr 2017 10:27:32 -0700 Subject: [PATCH 40/41] Update install instructions --- README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index bd23897..1222618 100644 --- a/README.md +++ b/README.md @@ -8,15 +8,18 @@ A small library for manipulating the favicon, in particular adding alert bubbles ## Documentation -Tinycon adds a single object to the global namespace and does not require initialisation. +Tinycon adds a single object to the global namespace and does not require initialization. + ### Installation -There are several versions of Tinycon published on NPM, unfortunately they are not controlled by me and do not track HEAD. The best idea is to install from github -directly and cut out the middleman! +Install with your favorite package manager. ``` -npm install tommoor/tinycon --save +npm install tinycon --save +``` +``` +yarn add tinycon ``` ### Basic Usage @@ -27,7 +30,7 @@ Tinycon.setBubble(6); ### Options -Tinycon can take a range of options to customise the look +Tinycon can take a range of options to customize the look * width: the width of the alert bubble * height: the height of the alert bubble From 9c3fbfab8f07944af43bf1aaf93387446c3f54df Mon Sep 17 00:00:00 2001 From: lax1089 Date: Mon, 1 Jul 2019 00:38:04 -0400 Subject: [PATCH 41/41] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1222618..44da454 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ Tinycon has been tested to work completely in the following browsers. Older vers * Firefox 9+ * Opera 11+ -Currently the library degrades to title update: +Currently the library degrades to title update in the following browsers: * Internet Explorer 9 * Safari 5