mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-13 03:27:39 +03:00
Added Tinycon (Unread message tab's icon)
This commit is contained in:
parent
f1b3271b4d
commit
47bb848905
15 changed files with 426 additions and 17 deletions
|
|
@ -172,7 +172,7 @@
|
||||||
/**
|
/**
|
||||||
* @param {string} sTitle
|
* @param {string} sTitle
|
||||||
*/
|
*/
|
||||||
AbstractApp.prototype.setTitle = function (sTitle)
|
AbstractApp.prototype.setWindowTitle = function (sTitle)
|
||||||
{
|
{
|
||||||
sTitle = ((Utils.isNormal(sTitle) && 0 < sTitle.length) ? sTitle + ' - ' : '') +
|
sTitle = ((Utils.isNormal(sTitle) && 0 < sTitle.length) ? sTitle + ' - ' : '') +
|
||||||
Settings.settingsGet('Title') || '';
|
Settings.settingsGet('Title') || '';
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
$ = require('$'),
|
$ = require('$'),
|
||||||
moment = require('moment'),
|
moment = require('moment'),
|
||||||
SimplePace = require('SimplePace'),
|
SimplePace = require('SimplePace'),
|
||||||
|
Tinycon = require('Tinycon'),
|
||||||
|
|
||||||
Enums = require('Common/Enums'),
|
Enums = require('Common/Enums'),
|
||||||
Globals = require('Common/Globals'),
|
Globals = require('Common/Globals'),
|
||||||
|
|
@ -1342,7 +1343,7 @@
|
||||||
{
|
{
|
||||||
Globals.$html.addClass('rl-user-auth');
|
Globals.$html.addClass('rl-user-auth');
|
||||||
|
|
||||||
this.setTitle(Translator.i18n('TITLES/LOADING'));
|
this.setWindowTitle(Translator.i18n('TITLES/LOADING'));
|
||||||
|
|
||||||
//require.ensure([], function() { // require code splitting
|
//require.ensure([], function() { // require code splitting
|
||||||
|
|
||||||
|
|
@ -1479,6 +1480,17 @@
|
||||||
_.defer(function () {
|
_.defer(function () {
|
||||||
self.initVerticalLayoutResizer(Enums.ClientSideKeyName.FolderListSize);
|
self.initVerticalLayoutResizer(Enums.ClientSideKeyName.FolderListSize);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (Tinycon)
|
||||||
|
{
|
||||||
|
Tinycon.setOptions({
|
||||||
|
fallback: false
|
||||||
|
});
|
||||||
|
|
||||||
|
Events.sub('mailbox.inbox-unread-count', function (iCount) {
|
||||||
|
Tinycon.setBubble(0 < iCount ? (99 < iCount ? 99 : iCount) : 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
LoginAdminScreen.prototype.onShow = function ()
|
LoginAdminScreen.prototype.onShow = function ()
|
||||||
{
|
{
|
||||||
require('App/Admin').setTitle('');
|
require('App/Admin').setWindowTitle('');
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = LoginAdminScreen;
|
module.exports = LoginAdminScreen;
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@
|
||||||
|
|
||||||
SettingsAdminScreen.prototype.onShow = function ()
|
SettingsAdminScreen.prototype.onShow = function ()
|
||||||
{
|
{
|
||||||
require('App/Admin').setTitle('');
|
require('App/Admin').setWindowTitle('');
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = SettingsAdminScreen;
|
module.exports = SettingsAdminScreen;
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
AboutUserScreen.prototype.onShow = function ()
|
AboutUserScreen.prototype.onShow = function ()
|
||||||
{
|
{
|
||||||
require('App/User').setTitle('RainLoop');
|
require('App/User').setWindowTitle('RainLoop');
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = AboutUserScreen;
|
module.exports = AboutUserScreen;
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
LoginUserScreen.prototype.onShow = function ()
|
LoginUserScreen.prototype.onShow = function ()
|
||||||
{
|
{
|
||||||
require('App/User').setTitle('');
|
require('App/User').setWindowTitle('');
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = LoginUserScreen;
|
module.exports = LoginUserScreen;
|
||||||
|
|
|
||||||
|
|
@ -45,21 +45,21 @@
|
||||||
*/
|
*/
|
||||||
MailBoxUserScreen.prototype.oLastRoute = {};
|
MailBoxUserScreen.prototype.oLastRoute = {};
|
||||||
|
|
||||||
MailBoxUserScreen.prototype.setNewTitle = function ()
|
MailBoxUserScreen.prototype.updateWindowTitle = function ()
|
||||||
{
|
{
|
||||||
var
|
var
|
||||||
sEmail = AccountStore.email(),
|
sEmail = AccountStore.email(),
|
||||||
nFoldersInboxUnreadCount = FolderStore.foldersInboxUnreadCount()
|
nFoldersInboxUnreadCount = FolderStore.foldersInboxUnreadCount()
|
||||||
;
|
;
|
||||||
|
|
||||||
require('App/User').setTitle(('' === sEmail ? '' :
|
require('App/User').setWindowTitle(('' === sEmail ? '' : '' +
|
||||||
(0 < nFoldersInboxUnreadCount ? '(' + nFoldersInboxUnreadCount + ') ' : ' ') +
|
(0 < nFoldersInboxUnreadCount ? '(' + nFoldersInboxUnreadCount + ') ' : ' ') +
|
||||||
sEmail + ' - ') + Translator.i18n('TITLES/MAILBOX'));
|
sEmail + ' - ') + Translator.i18n('TITLES/MAILBOX'));
|
||||||
};
|
};
|
||||||
|
|
||||||
MailBoxUserScreen.prototype.onShow = function ()
|
MailBoxUserScreen.prototype.onShow = function ()
|
||||||
{
|
{
|
||||||
this.setNewTitle();
|
this.updateWindowTitle();
|
||||||
Globals.keyScope(Enums.KeyState.MessageList);
|
Globals.keyScope(Enums.KeyState.MessageList);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -112,7 +112,7 @@
|
||||||
SettingsStore.layout.valueHasMutated();
|
SettingsStore.layout.valueHasMutated();
|
||||||
}, 50);
|
}, 50);
|
||||||
|
|
||||||
Events.sub('mailbox.inbox-unread-count', function (iCount) {
|
Events.sub('mailbox.inbox-unread-count', _.bind(function (iCount) {
|
||||||
|
|
||||||
FolderStore.foldersInboxUnreadCount(iCount);
|
FolderStore.foldersInboxUnreadCount(iCount);
|
||||||
|
|
||||||
|
|
@ -124,12 +124,10 @@
|
||||||
oItem.count(iCount);
|
oItem.count(iCount);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
FolderStore.foldersInboxUnreadCount.subscribe(function () {
|
this.updateWindowTitle();
|
||||||
this.setNewTitle();
|
|
||||||
}, this);
|
|
||||||
|
|
||||||
|
}, this));
|
||||||
};
|
};
|
||||||
|
|
||||||
MailBoxUserScreen.prototype.onBuild = function ()
|
MailBoxUserScreen.prototype.onBuild = function ()
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,7 @@
|
||||||
|
|
||||||
SettingsUserScreen.prototype.setSettingsTitle = function ()
|
SettingsUserScreen.prototype.setSettingsTitle = function ()
|
||||||
{
|
{
|
||||||
require('App/User').setTitle(this.sSettingsTitle);
|
require('App/User').setWindowTitle(this.sSettingsTitle);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = SettingsUserScreen;
|
module.exports = SettingsUserScreen;
|
||||||
|
|
|
||||||
5
dev/bootstrap.js
vendored
5
dev/bootstrap.js
vendored
|
|
@ -54,7 +54,7 @@
|
||||||
|
|
||||||
window['__APP_BOOT'] = function (fCall) {
|
window['__APP_BOOT'] = function (fCall) {
|
||||||
|
|
||||||
$(function () {
|
$(_.delay(function () {
|
||||||
|
|
||||||
if (!$('#rl-content').is(':visible'))
|
if (!$('#rl-content').is(':visible'))
|
||||||
{
|
{
|
||||||
|
|
@ -82,7 +82,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
window['__APP_BOOT'] = null;
|
window['__APP_BOOT'] = null;
|
||||||
});
|
|
||||||
|
}, 10));
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -157,6 +157,7 @@ cfg.paths.js = {
|
||||||
'vendors/queue/queue.min.js',
|
'vendors/queue/queue.min.js',
|
||||||
'vendors/inputosaurus/inputosaurus.min.js',
|
'vendors/inputosaurus/inputosaurus.min.js',
|
||||||
'vendors/moment/min/moment.min.js ',
|
'vendors/moment/min/moment.min.js ',
|
||||||
|
'vendors/tinycon/tinycon.min.js ',
|
||||||
'vendors/routes/signals.min.js',
|
'vendors/routes/signals.min.js',
|
||||||
'vendors/routes/hasher.min.js',
|
'vendors/routes/hasher.min.js',
|
||||||
'vendors/routes/crossroads.min.js',
|
'vendors/routes/crossroads.min.js',
|
||||||
|
|
|
||||||
19
vendors/tinycon/LICENSE
vendored
Normal file
19
vendors/tinycon/LICENSE
vendored
Normal file
|
|
@ -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.
|
||||||
90
vendors/tinycon/README.md
vendored
Normal file
90
vendors/tinycon/README.md
vendored
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
<img src="https://github.com/tommoor/tinycon/blob/master/examples/screenshot.png?raw=true" />
|
||||||
|
|
||||||
|
<a href="http://tommoor.github.com/tinycon/">See the Live Demo here.</a>
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
Tinycon adds a single object to the global namespace and does not require initialisation.
|
||||||
|
|
||||||
|
### Basic Usage
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
Tinycon.setBubble(6);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
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
|
||||||
|
* 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
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
Tinycon.setOptions({
|
||||||
|
width: 7,
|
||||||
|
height: 9,
|
||||||
|
font: '10px arial',
|
||||||
|
colour: '#ffffff',
|
||||||
|
background: '#549A2F',
|
||||||
|
fallback: true
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 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:
|
||||||
|
|
||||||
|
* Chrome 15+
|
||||||
|
* Firefox 9+
|
||||||
|
* Opera 11+
|
||||||
|
|
||||||
|
Currently the library degrades to title update:
|
||||||
|
|
||||||
|
* Internet Explorer 9
|
||||||
|
* Safari 5
|
||||||
|
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
[More Information](http://en.wikipedia.org/wiki/MIT_License)
|
||||||
|
|
||||||
|
Tinycon was inspired by [Notificon](https://github.com/makeable/Notificon)
|
||||||
|
|
||||||
|
|
||||||
|
## Download
|
||||||
|
|
||||||
|
Releases are available for download from
|
||||||
|
[GitHub](http://github.com/tommoor/tinycon/downloads).
|
||||||
279
vendors/tinycon/tinycon.js
vendored
Normal file
279
vendors/tinycon/tinycon.js
vendored
Normal file
|
|
@ -0,0 +1,279 @@
|
||||||
|
/*!
|
||||||
|
* 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();
|
||||||
|
// 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') || '').match(/\bicon\b/)) {
|
||||||
|
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 = size;
|
||||||
|
canvas.height = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
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(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';
|
||||||
|
}
|
||||||
|
|
||||||
|
faviconImage.src = src;
|
||||||
|
};
|
||||||
|
|
||||||
|
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, 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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
// bubble
|
||||||
|
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();
|
||||||
|
|
||||||
|
// 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(){
|
||||||
|
setFaviconTag(originalFavicon);
|
||||||
|
};
|
||||||
|
|
||||||
|
Tinycon.setOptions(defaults);
|
||||||
|
window.Tinycon = Tinycon;
|
||||||
|
|
||||||
|
if(typeof define === 'function' && define.amd) {
|
||||||
|
define(Tinycon);
|
||||||
|
}
|
||||||
|
|
||||||
|
})();
|
||||||
8
vendors/tinycon/tinycon.min.js
vendored
Normal file
8
vendors/tinycon/tinycon.min.js
vendored
Normal file
|
|
@ -0,0 +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;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')||'').match(/\bicon\b/)){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=size;canvas.height=size}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(label,colour){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(){context.clearRect(0,0,size,size);context.drawImage(faviconImage,0,0,faviconImage.width,faviconImage.height,0,0,size,size);if((label+'').length>0)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.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)};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)}})();
|
||||||
|
|
@ -38,6 +38,7 @@ module.exports = {
|
||||||
'hasher': 'window.hasher',
|
'hasher': 'window.hasher',
|
||||||
'Jua': 'window.Jua',
|
'Jua': 'window.Jua',
|
||||||
'Autolinker': 'window.Autolinker',
|
'Autolinker': 'window.Autolinker',
|
||||||
|
'Tinycon': 'window.Tinycon',
|
||||||
'buzz': 'window.buzz',
|
'buzz': 'window.buzz',
|
||||||
'ssm': 'window.ssm',
|
'ssm': 'window.ssm',
|
||||||
'key': 'window.key',
|
'key': 'window.key',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue