Merge pull request #871 from marcelklehr/feature/nice-chat-bubble
Use Tinycon to display chat mentions in favicon.pull/877/merge
commit
84cf741acf
|
@ -23,11 +23,12 @@
|
||||||
var padutils = require('./pad_utils').padutils;
|
var padutils = require('./pad_utils').padutils;
|
||||||
var padcookie = require('./pad_cookie').padcookie;
|
var padcookie = require('./pad_cookie').padcookie;
|
||||||
|
|
||||||
|
require('./tinycon');
|
||||||
|
|
||||||
var chat = (function()
|
var chat = (function()
|
||||||
{
|
{
|
||||||
var isStuck = false;
|
var isStuck = false;
|
||||||
var chatMentions = 0;
|
var chatMentions = 0;
|
||||||
var title = document.title;
|
|
||||||
var self = {
|
var self = {
|
||||||
show: function ()
|
show: function ()
|
||||||
{
|
{
|
||||||
|
@ -35,7 +36,7 @@ var chat = (function()
|
||||||
$("#chatbox").show();
|
$("#chatbox").show();
|
||||||
self.scrollDown();
|
self.scrollDown();
|
||||||
chatMentions = 0;
|
chatMentions = 0;
|
||||||
document.title = title;
|
Tinycon.setBubble(0);
|
||||||
},
|
},
|
||||||
stickToScreen: function(fromInitialCall) // Make chat stick to right hand side of screen
|
stickToScreen: function(fromInitialCall) // Make chat stick to right hand side of screen
|
||||||
{
|
{
|
||||||
|
@ -126,12 +127,9 @@ var chat = (function()
|
||||||
// chat throb stuff -- Just make it throw for twice as long
|
// chat throb stuff -- Just make it throw for twice as long
|
||||||
if(wasMentioned && !alreadyFocused)
|
if(wasMentioned && !alreadyFocused)
|
||||||
{ // If the user was mentioned show for twice as long and flash the browser window
|
{ // If the user was mentioned show for twice as long and flash the browser window
|
||||||
if (chatMentions == 0){
|
|
||||||
title = document.title;
|
|
||||||
}
|
|
||||||
$('#chatthrob').html("<b>"+authorName+"</b>" + ": " + text).show().delay(4000).hide(400);
|
$('#chatthrob').html("<b>"+authorName+"</b>" + ": " + text).show().delay(4000).hide(400);
|
||||||
chatMentions++;
|
chatMentions++;
|
||||||
document.title = "("+chatMentions+") " + title;
|
Tinycon.setBubble(chatMentions);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -141,7 +139,7 @@ var chat = (function()
|
||||||
// Clear the chat mentions when the user clicks on the chat input box
|
// Clear the chat mentions when the user clicks on the chat input box
|
||||||
$('#chatinput').click(function(){
|
$('#chatinput').click(function(){
|
||||||
chatMentions = 0;
|
chatMentions = 0;
|
||||||
document.title = title;
|
Tinycon.setBubble(0);
|
||||||
});
|
});
|
||||||
self.scrollDown();
|
self.scrollDown();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,237 @@
|
||||||
|
/*!
|
||||||
|
* Tinycon - A small library for manipulating the Favicon
|
||||||
|
* Tom Moor, http://tommoor.com
|
||||||
|
* Copyright (c) 2012 Tom Moor
|
||||||
|
* MIT Licensed
|
||||||
|
* @version 0.2.6
|
||||||
|
*/
|
||||||
|
|
||||||
|
(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
|
||||||
|
};
|
||||||
|
|
||||||
|
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('msie'),
|
||||||
|
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/)) {
|
||||||
|
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') === 'icon') {
|
||||||
|
head.removeChild(links[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var getCurrentFavicon = function(){
|
||||||
|
|
||||||
|
if (!originalFavicon || !currentFavicon) {
|
||||||
|
var tag = getFaviconTag();
|
||||||
|
originalFavicon = currentFavicon = tag ? tag.getAttribute('href') : '/favicon.ico';
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentFavicon;
|
||||||
|
};
|
||||||
|
|
||||||
|
var getCanvas = function (){
|
||||||
|
|
||||||
|
if (!canvas) {
|
||||||
|
canvas = document.createElement("canvas");
|
||||||
|
canvas.width = 16;
|
||||||
|
canvas.height = 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
return canvas;
|
||||||
|
};
|
||||||
|
|
||||||
|
var setFaviconTag = function(url){
|
||||||
|
removeFaviconTag();
|
||||||
|
|
||||||
|
var link = document.createElement('link');
|
||||||
|
link.type = 'image/x-icon';
|
||||||
|
link.rel = 'icon';
|
||||||
|
link.href = url;
|
||||||
|
document.getElementsByTagName('head')[0].appendChild(link);
|
||||||
|
};
|
||||||
|
|
||||||
|
var log = function(message){
|
||||||
|
if (window.console) window.console.log(message);
|
||||||
|
};
|
||||||
|
|
||||||
|
var drawFavicon = function(num, colour) {
|
||||||
|
|
||||||
|
// fallback to updating the browser title if unsupported
|
||||||
|
if (!getCanvas().getContext || browser.ie || browser.safari || options.fallback === 'force') {
|
||||||
|
return updateTitle(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
var context = getCanvas().getContext("2d");
|
||||||
|
var colour = colour || '#000000';
|
||||||
|
var num = num || 0;
|
||||||
|
var src = getCurrentFavicon();
|
||||||
|
|
||||||
|
faviconImage = new Image();
|
||||||
|
faviconImage.onload = function() {
|
||||||
|
|
||||||
|
// clear canvas
|
||||||
|
context.clearRect(0, 0, 16, 16);
|
||||||
|
|
||||||
|
// draw original favicon
|
||||||
|
context.drawImage(faviconImage, 0, 0, faviconImage.width, faviconImage.height, 0, 0, 16, 16);
|
||||||
|
|
||||||
|
// draw bubble over the top
|
||||||
|
if (num > 0) drawBubble(context, num, 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/)) {
|
||||||
|
faviconImage.crossOrigin = 'anonymous';
|
||||||
|
}
|
||||||
|
|
||||||
|
faviconImage.src = src;
|
||||||
|
};
|
||||||
|
|
||||||
|
var updateTitle = function(num) {
|
||||||
|
|
||||||
|
if (options.fallback) {
|
||||||
|
if (num > 0) {
|
||||||
|
document.title = '('+num+') ' + originalTitle;
|
||||||
|
} else {
|
||||||
|
document.title = originalTitle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var drawBubble = function(context, num, colour) {
|
||||||
|
|
||||||
|
// bubble needs to be larger for double digits
|
||||||
|
var len = (num+"").length-1;
|
||||||
|
var width = options.width + (6*len);
|
||||||
|
var w = 16-width;
|
||||||
|
var h = 16-options.height;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// bubble
|
||||||
|
context.fillRect(w,h,width-1,options.height);
|
||||||
|
|
||||||
|
// rounded left
|
||||||
|
context.beginPath();
|
||||||
|
context.moveTo(w-0.5,h+1);
|
||||||
|
context.lineTo(w-0.5,15);
|
||||||
|
context.stroke();
|
||||||
|
|
||||||
|
// rounded right
|
||||||
|
context.beginPath();
|
||||||
|
context.moveTo(15.5,h+1);
|
||||||
|
context.lineTo(15.5,15);
|
||||||
|
context.stroke();
|
||||||
|
|
||||||
|
// bottom shadow
|
||||||
|
context.beginPath();
|
||||||
|
context.strokeStyle = "rgba(0,0,0,0.3)";
|
||||||
|
context.moveTo(w,16);
|
||||||
|
context.lineTo(15,16);
|
||||||
|
context.stroke();
|
||||||
|
|
||||||
|
// number
|
||||||
|
context.fillStyle = options.colour;
|
||||||
|
context.textAlign = "right";
|
||||||
|
context.textBaseline = "top";
|
||||||
|
|
||||||
|
// unfortunately webkit/mozilla are a pixel different in text positioning
|
||||||
|
context.fillText(num, 15, browser.mozilla ? 7 : 6);
|
||||||
|
};
|
||||||
|
|
||||||
|
var refreshFavicon = function(){
|
||||||
|
// check support
|
||||||
|
if (!getCanvas().getContext) return;
|
||||||
|
|
||||||
|
setFaviconTag(getCanvas().toDataURL());
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// 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(num, colour){
|
||||||
|
|
||||||
|
// validate
|
||||||
|
if(isNaN(parseFloat(num)) || !isFinite(num)) return log('Bubble must be a number');
|
||||||
|
|
||||||
|
drawFavicon(num, colour);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
Tinycon.reset = function(){
|
||||||
|
Tinycon.setImage(originalFavicon);
|
||||||
|
};
|
||||||
|
|
||||||
|
Tinycon.setOptions(defaults);
|
||||||
|
window.Tinycon = Tinycon;
|
||||||
|
})();
|
Loading…
Reference in New Issue