diff --git a/app/assets/images/default-favicon.ico b/app/assets/images/default-favicon.ico new file mode 100644 index 00000000000..d20ae8eeded Binary files /dev/null and b/app/assets/images/default-favicon.ico differ diff --git a/app/assets/javascripts/discourse.js b/app/assets/javascripts/discourse.js index 954d8ad1b37..33e1627ce39 100644 --- a/app/assets/javascripts/discourse.js +++ b/app/assets/javascripts/discourse.js @@ -85,6 +85,14 @@ Discourse = Ember.Application.createWithMixins({ }, 200); }.observes('title', 'hasFocus', 'notifyCount'), + faviconChanged: function() { + if(Discourse.SiteSettings.dynamic_favicon) { + $.faviconNotify( + Discourse.SiteSettings.favicon_url, this.get('notifyCount') + ); + } + }.observes('notifyCount'), + // The classes of buttons to show on a post postButtons: function() { return Discourse.SiteSettings.post_menu.split("|").map(function(i) { diff --git a/app/assets/javascripts/external/jquery.faviconNotify.js b/app/assets/javascripts/external/jquery.faviconNotify.js new file mode 100644 index 00000000000..2b071e30e7c --- /dev/null +++ b/app/assets/javascripts/external/jquery.faviconNotify.js @@ -0,0 +1,224 @@ +/** + * jQuery Favicon Notify + * + * Updates the favicon to notify the user of changes. In the original tests I + * had an embedded font collection to allow any charachers - I decided that the + * ~130Kb and added complexity was overkill. As such it now uses a manual glyph + * set meaning that only numerical notifications are possible. + * + * Dual licensed under the MIT and GPL licenses: + * + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + * @author David King + * @copyright Copyright (c) 2011 + + * @url oodavid.com + */ +(function($){ + var canvas; + var bg = '#000000'; + var fg = '#FFFFFF'; + var pos = 'br'; + $.faviconNotify = function(icon, num, myPos, myBg, myFg){ + // Default the positions + myPos = myPos || pos; + myFg = myFg || fg; + myBg = myBg || bg; + // Create a canvas if we need one + canvas = canvas || $('')[0]; + if(canvas.getContext){ + // Load the icon + $('').load(function(e){ + // Load the icon into the canvas + canvas.height = canvas.width = 16; + var ctx = canvas.getContext('2d'); + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.drawImage(this, 0, 0); + // We gots num? + if(num !== undefined){ + num = parseFloat(num, 10); + // Convert the num into a glyphs array + var myGlyphs = []; + if(num > 99){ + myGlyphs.push(glyphs['LOTS']); + } else { + num = num.toString().split(''); + $.each(num, function(k,v){ + myGlyphs.push(glyphs[v]); + }); + } + // Merge the glyphs together + var combined = []; + var glyphHeight = myGlyphs[0].length; + $.each(myGlyphs, function(k,v){ + for(y=0; y').attr('href', canvas.toDataURL('image/png'))); + }).attr('src', icon) + } + }; + var glyphs = { + '0': [ + ' --- ', + ' -@@@- ', + '-@---@-', + '-@- -@-', + '-@- -@-', + '-@- -@-', + '-@---@-', + ' -@@@- ', + ' --- ' ], + '1': [ + ' - ', + ' -@- ', + '-@@- ', + ' -@- ', + ' -@- ', + ' -@- ', + ' -@- ', + '-@@@-', + ' --- ' ], + '2': [ + ' --- ', + ' -@@@- ', + '-@---@-', + ' - --@-', + ' -@@- ', + ' -@-- ', + '-@---- ', + '-@@@@@-', + ' ----- ' ], + '3': [ + ' --- ', + ' -@@@- ', + '-@---@-', + ' - --@-', + ' -@@- ', + ' - --@-', + '-@---@-', + ' -@@@- ', + ' --- ' ], + '4': [ + ' -- ', + ' -@@-', + ' -@-@-', + ' -@--@-', + '-@---@-', + '-@@@@@-', + ' ----@-', + ' -@-', + ' - ' ], + '5': [ + ' ----- ', + '-@@@@@-', + '-@---- ', + '-@--- ', + '-@@@@- ', + ' ----@-', + '-@---@-', + ' -@@@- ', + ' --- ' ], + '6': [ + ' --- ', + ' -@@@- ', + '-@---@-', + '-@---- ', + '-@@@@- ', + '-@---@-', + '-@---@-', + ' -@@@- ', + ' --- ' ], + '7': [ + ' ----- ', + '-@@@@@-', + ' ----@-', + ' -@- ', + ' -@- ', + ' -@- ', + ' -@- ', + ' -@- ', + ' - ' ], + '8': [ + ' --- ', + ' -@@@- ', + '-@---@-', + '-@---@-', + ' -@@@- ', + '-@---@-', + '-@---@-', + ' -@@@- ', + ' --- ' ], + '9': [ + ' --- ', + ' -@@@- ', + '-@---@-', + '-@---@-', + ' -@@@@-', + ' ----@-', + '-@---@-', + ' -@@@- ', + ' --- ' ], + '!': [ + ' - ', + '-@-', + '-@-', + '-@-', + '-@-', + '-@-', + ' - ', + '-@-', + ' - ' ], + '.': [ + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' - ', + '-@-', + ' - ' ], + 'LOTS': [ + ' - -- --- -- ', + '-@- -@@-@@@--@@-', + '-@--@--@-@--@- ', + '-@--@--@-@--@- ', + '-@--@--@-@- -@- ', + '-@--@--@-@- -@-', + '-@--@--@-@----@-', + '-@@@-@@--@-@@@- ', + ' --- -- - --- ' + ] + }; +})(jQuery); diff --git a/app/models/site_setting.rb b/app/models/site_setting.rb index e5b99a92260..93fee5b34ba 100644 --- a/app/models/site_setting.rb +++ b/app/models/site_setting.rb @@ -79,7 +79,8 @@ class SiteSetting < ActiveRecord::Base setting(:invite_expiry_days, 14) setting(:active_user_rate_limit_secs, 60) setting(:previous_visit_timeout_hours, 1) - setting(:favicon_url, '/assets/default-favicon.png') + client_setting(:favicon_url, '/assets/default-favicon.ico') + client_setting(:dynamic_favicon, false) setting(:apple_touch_icon_url, '/assets/default-apple-touch-icon.png') setting(:ninja_edit_window, 5.minutes.to_i) diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 47f225f6e61..9e689872a53 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -460,6 +460,7 @@ en: logo_url: "The logo for your site eg: http://example.com/logo.png" logo_small_url: "The small logo for your site used when scrolling down on topics eg: http://example.com/logo-small.png" favicon_url: "A favicon for your site, see http://en.wikipedia.org/wiki/Favicon" + dynamic_favicon: "Show incoming message notifications on favicon" apple_touch_icon_url: "Icon used for Apple touch devices. Recommended size is 144px by 144px." notification_email: "The return email address used when sending system emails such as notifying users of lost passwords, new accounts etc"