Commit | Line | Data |
---|---|---|
0b7949de | 1 | _kiwi.view.Favicon = Backbone.View.extend({ |
bd85cbdb VC |
2 | initialize: function () { |
3 | var that = this, | |
4 | $win = $(window); | |
5 | ||
9e2e2fc5 | 6 | this.has_canvas_support = !!window.CanvasRenderingContext2D; |
bd85cbdb VC |
7 | this.has_focus = true; |
8 | this.highlight_count = 0; | |
9 | ||
10 | this.original_favicon = $('link[rel~="icon"]')[0].href; | |
11 | ||
12 | $win.on('focus', function () { | |
13 | that.has_focus = true; | |
14 | that._resetHighlights(); | |
15 | }); | |
16 | $win.on('blur', function () { | |
17 | that.has_focus = false; | |
18 | }); | |
19 | }, | |
20 | ||
21 | newHighlight: function () { | |
22 | var that = this; | |
23 | if (!this.has_focus) { | |
24 | this.highlight_count++; | |
9e2e2fc5 VC |
25 | if (this.has_canvas_support) { |
26 | this._drawFavicon(function(canvas) { | |
27 | var bubbleCanvas = that._drawBubble(that.highlight_count.toString(), canvas); | |
28 | that._refreshFavicon(bubbleCanvas.toDataURL()); | |
29 | }); | |
30 | } | |
bd85cbdb VC |
31 | } |
32 | }, | |
33 | ||
34 | _resetHighlights: function () { | |
35 | var that = this; | |
36 | this.highlight_count = 0; | |
37 | this._drawFavicon(function(canvas) { | |
38 | that._refreshFavicon(canvas.toDataURL()); | |
39 | }); | |
40 | }, | |
41 | ||
42 | _drawFavicon: function (callback) { | |
43 | var that = this, | |
44 | context = this._createCanvas().getContext('2d'), | |
45 | favicon_image = new Image(); | |
46 | ||
47 | // Allow cross origin resource requests | |
48 | favicon_image.crossOrigin = 'anonymous'; | |
49 | // Trigger the load event | |
50 | favicon_image.src = this.original_favicon; | |
51 | ||
52 | favicon_image.onload = function() { | |
53 | // Draw the favicon itself | |
54 | context.drawImage(favicon_image, 0, 0, favicon_image.width, favicon_image.height); | |
55 | callback(canvas); | |
56 | }; | |
57 | }, | |
58 | ||
59 | _drawBubble: function (label, canvas) { | |
60 | var letter_spacing = -1.5, | |
61 | text_width = 0, text_height = 0, | |
62 | context = test = canvas.getContext('2d'), | |
63 | canvas_width = canvas.width, | |
64 | canvas_height = canvas.height; | |
65 | ||
bd85cbdb VC |
66 | // Setup a test canvas to get text width |
67 | test.font = context.font = 'bold 10px Arial'; | |
68 | test.textAlign = 'right'; | |
9e2e2fc5 | 69 | this._renderText(test, label, 0, 0, letter_spacing); |
bd85cbdb VC |
70 | |
71 | // Calculate text width based on letter spacing and padding | |
72 | text_width = test.measureText(label).width + letter_spacing * (label.length - 1) + 2; | |
73 | text_height = 9; | |
74 | ||
75 | // Set bubble parameters | |
76 | bubbleX = canvas_width - text_width; | |
77 | bubbleY = canvas_height - text_height; | |
78 | ||
79 | // Draw bubble background | |
80 | context.fillStyle = 'red'; | |
81 | context.fillRect(bubbleX, bubbleY, text_width, text_height); | |
82 | ||
83 | // Draw the text | |
84 | context.fillStyle = 'white'; | |
9e2e2fc5 | 85 | this._renderText(context, label, canvas_width - 1, canvas_height - 1, letter_spacing); |
bd85cbdb VC |
86 | |
87 | return canvas; | |
88 | }, | |
89 | ||
90 | _refreshFavicon: function (url) { | |
91 | $('link[rel~="icon"]').remove(); | |
92 | $('<link rel="shortcut icon" href="' + url + '">').appendTo($('head')); | |
93 | }, | |
94 | ||
95 | _createCanvas: function () { | |
96 | canvas = document.createElement('canvas'); | |
97 | canvas.width = 16; | |
98 | canvas.height = 16; | |
99 | ||
100 | return canvas; | |
9e2e2fc5 VC |
101 | }, |
102 | ||
103 | _renderText: function (context, text, x, y, letter_spacing) { | |
104 | // A hacky solution for letter-spacing, but works well with small favicon text | |
105 | // Modified from http://jsfiddle.net/davidhong/hKbJ4/ | |
106 | var current, | |
107 | characters = text.split('').reverse(), | |
108 | index = 0, | |
109 | currentPosition = x; | |
110 | ||
111 | while (index < text.length) { | |
112 | current = characters[index++]; | |
113 | context.fillText(current, currentPosition, y); | |
114 | currentPosition += (-1 * (context.measureText(current).width + letter_spacing)); | |
115 | } | |
116 | ||
117 | return context; | |
bd85cbdb | 118 | } |
0b7949de | 119 | }); |