1 _kiwi
.view
.Favicon
= Backbone
.View
.extend({
2 initialize: function () {
7 this.highlight_count
= 0;
8 // Check for html5 canvas support
9 this.has_canvas_support
= !!window
.CanvasRenderingContext2D
;
11 // Store the original favicon
12 this.original_favicon
= $('link[rel~="icon"]')[0].href
;
14 // Create our favicon canvas
17 // Reset favicon notifications when user focuses window
18 $win
.on('focus', function () {
19 that
.has_focus
= true;
20 that
._resetHighlights();
22 $win
.on('blur', function () {
23 that
.has_focus
= false;
27 newHighlight: function () {
29 if (!this.has_focus
) {
30 this.highlight_count
++;
31 if (this.has_canvas_support
) {
32 this._drawFavicon(function() {
33 that
._drawBubble(that
.highlight_count
.toString());
34 that
._refreshFavicon(that
.canvas
.toDataURL());
40 _resetHighlights: function () {
42 this.highlight_count
= 0;
43 this._refreshFavicon(this.original_favicon
);
46 _drawFavicon: function (callback
) {
49 context
= canvas
.getContext('2d'),
50 favicon_image
= new Image();
52 // Allow cross origin resource requests
53 favicon_image
.crossOrigin
= 'anonymous';
54 // Trigger the load event
55 favicon_image
.src
= this.original_favicon
;
57 favicon_image
.onload = function() {
58 // Clear canvas from prevous iteration
59 context
.clearRect(0, 0, canvas
.width
, canvas
.height
);
60 // Draw the favicon itself
61 context
.drawImage(favicon_image
, 0, 0, canvas
.width
, canvas
.height
);
66 _drawBubble: function (label
) {
68 bubble_width
= 0, bubble_height
= 0,
70 context
= test_context
= canvas
.getContext('2d'),
71 canvas_width
= canvas
.width
,
72 canvas_height
= canvas
.height
;
74 // Different letter spacing for MacOS
75 if (navigator
.appVersion
.indexOf("Mac") !== -1) {
76 letter_spacing
= -1.5;
82 // Setup a test canvas to get text width
83 test_context
.font
= context
.font
= 'bold 10px Arial';
84 test_context
.textAlign
= 'right';
85 this._renderText(test_context
, label
, 0, 0, letter_spacing
);
87 // Calculate bubble width based on letter spacing and padding
88 bubble_width
= test_context
.measureText(label
).width
+ letter_spacing
* (label
.length
- 1) + 2;
89 // Canvas does not have any way of measuring text height, so we just do it manually and add 1px top/bottom padding
92 // Set bubble coordinates
93 bubbleX
= canvas_width
- bubble_width
;
94 bubbleY
= canvas_height
- bubble_height
;
96 // Draw bubble background
97 context
.fillStyle
= 'red';
98 context
.fillRect(bubbleX
, bubbleY
, bubble_width
, bubble_height
);
101 context
.fillStyle
= 'white';
102 this._renderText(context
, label
, canvas_width
- 1, canvas_height
- 1, letter_spacing
);
105 _refreshFavicon: function (url
) {
106 $('link[rel~="icon"]').remove();
107 $('<link rel="shortcut icon" href="' + url
+ '">').appendTo($('head'));
110 _createCanvas: function () {
111 var canvas
= document
.createElement('canvas');
115 this.canvas
= canvas
;
118 _renderText: function (context
, text
, x
, y
, letter_spacing
) {
119 // A hacky solution for letter-spacing, but works well with small favicon text
120 // Modified from http://jsfiddle.net/davidhong/hKbJ4/
122 characters
= text
.split('').reverse(),
126 while (index
< text
.length
) {
127 current
= characters
[index
++];
128 context
.fillText(current
, currentPosition
, y
);
129 currentPosition
+= (-1 * (context
.measureText(current
).width
+ letter_spacing
));