Pull to refresh

Динамический favicon или отображаем карму, не обновляя страницу

Reading time5 min
Views11K
image
У каждого из нас, полагаю, в любимом браузере постоянно открыты несколько вкладок одновременно. Не раз бывают случаи, что и заголовка вкладки не видно — лишь favicon'ки. Но часто они информации, кроме как отображения логотипа сайта, не дают. И, наверное, зря. Но мы постараемся и здесь использовать это место (целых 16px*16px!) так, как хотим. По крайней мере, будем знать, как это можно сделать.

Даже не старайтесь менять <link[rel=«icon»]… />.


Кто-то, возможно, воскликнет: «Что ж тут сложного-то? Взял тег link и поменял в нем src!». Но не тут то было, товарищи. Этот код не будет работать:
  1. var oldicons = document.querySelectorAll( 'link[rel="icon"], link[rel="shortcut icon"]' );
  2. for (var i = 0; i < oldicons.length; i++ ) {
  3.   oldicons[i].setAttribute( "src", "/newicon.png" );
  4. }

Этот тоже:
  1. $('link[rel="shortcut icon"]').attr( "src", "/newicon.png" );

Почему так — не скажу (кто-то объяснит?), но это можно сделать вот так (на jQuery):
  1. $('link[rel$=icon]').remove();
  2. $('head').append( $('<link rel="shortcut icon" type="image/x-icon"/>' ).attr( 'href', "/newicon.png" ) );


То есть, сначала удаляем элемент, если есть, а потом добавляем его дочерним в тег head. Вместо remove() можно также применить replaceWith('').

Поскольку нам нужны динамические favicon'ки, будем их рисовать на canvas'е, а потом использовать его в качестве favicon'ки.

  1. var c = document.createElement('canvas');
  2. c.height = c.width = 16;
  3. var x = c.getContext('2d');
  4. x.font = '18px bold Calibri';
  5. x.fillStyle = '#000';
  6. if(m) {
  7.   x.fillText( parseInt( m[1] ) > 9 ? '9+' : m[1], 0, 16, 16);
  8. }


Используем __defineSetter__


В GMail кол-во новых сообщений отображается в заголовке:
Входящие (15) - v.pupkin@gmail.com - GMail
Давайте выдерем оттуда regexp'ом циферку и получим, количество новых сообщений.

Чтобы так не изврящаться, вы можете использовать Google XML/API, но к нему нужна авторизация, да и рассматривать этот способ я не буду, так как речь совсем не о GMail почте. А о том, как можно обрабатывать изменения заголовка окошка, не прибегая к разным window.setTimeOut. Для этого мы возьмем Gecko'вский метод __defineSetter__ (подробнее о нем — здесь).

Этот метод позволяет использовать обработчик события, когда данные какого-то элемента меняются (но еще не изменились):
  1. Object.prototype.__defineSetter__( 'Id', function( data ){
  2.     alert( "hooked data=" + data );
  3. });

В этом примере показано, что в момент изменения атрибута id элемента Object (а это может быть любой тег или глобальная переменная), нам будет показано уведомление alert(«hooked data=»+data);

А давайте повесим этот «обработчик» на document.title, после чего выполним все наши вышеперечисленные действия, тем самым подводя итог первой части статьи.
  1. document.__defineSetter__( 'title', function( v ){
  2.     delete document.title; //убираем старый "обработчик"
  3.     document.title = v; //перехватываем новые данные и кладем в переменную
  4.     document.__defineSetter__( 'title', arguments.callee); //и быстренько возвращаем обработчик на место
  5.     var m = /\(([0-9]+)\)/.exec( v ); // выкусываем регуляркой цыферки с кол-вом сообщений с переменной
  6.     var c = document.createElement( 'canvas' ); //начинаем canvas'ить. Создадим холст
  7.     c.height = c.width = 16; // и присвоим ему размеры
  8.     var x = c.getContext( '2d' ); //получим контекст
  9.     x.font = '18px bold Calibri'; //задаем стиль шрифта
  10.     x.fillStyle = '#000'; //и цвет заливки
  11.     if ( m ) {
  12.         x.fillText( parseInt(m[1] ) > 9 ? '9+' : m[1], 0, 16, 16); //Если кол-во > 9, тогда показываем «9+»
  13.     }
  14.     var o = document.querySelectorAll( 'link[rel="icon"], link[rel="shortcut icon"]' ); // найдем все возможные теги favicon'ок
  15.     for (var i=0; i < o.length; i++) {
  16.         o[i].parentNode.removeChild( o[i] ); // и грохнем их,
  17.     }
  18.     var n = document.createElement( 'link' ); // после чего создадим заново
  19.     n.setAttribute( 'rel', 'icon' ); // с нужными атрубутами
  20.     n.setAttribute( 'href', c.toDataURL() ); // c.toDataURL() получает готовую картинку на нашем холсте в виде текста "data:image/png;base64,......"/
  21.     document.querySelector( 'head' ).appendChild(n); //ну и, наконец, применяем свежесозданую favicon'ку к документу. Вуаля!
  22. });


Чтобы проверить, как это работает, зайдите на ссылку, а потом во входящие на GMail. При наличии новых сообщений вы увидите счетчик в качестве картинки favion'а. У меня работало на Опере и Firefox под Ubuntu. Хрому идея не понравилсь.

Где это можно применить?


Да где хотите. Например, дабы не заглядывать во вкладку, есть ли новые сообщения, можно применить сей способ. Хотя, для можно использовать штучки типа счетчика с Google Labs и gmail-notifier для FF.
Но, может быть, вам захочется информировать своих пользователей на вашем сайте о чем-либо.

Или даже наслаждаться тем, как на хабре растет или падает ваша карма :)

Последний случай и возьму как основу для еще одного примера.

В качестве «движка» для скрипта применил Greasemonkey. Можете использовать этот userscript.

Отображение будет работать только когда вы находитесь в хабрацентре (кстати, не только своем). Можно простенько прикрутить ajax и получать циферки не находясь в своем хабрацентре, это по своему усмотрению. При большом желании можно его привинтить к Google Chrome (написать расширение) или Опере (например, той же «javascript-закладкой»).

А вот и сам скрипт (upd: немного обновлен):
  1. var c = document.createElement( "canvas" ); // Используем тот же канвас
  2. c.height = c.width = 16;
  3. var cx = c.getContext( "2d" );
  4. cx.beginPath();// рисуем голубенький квадратик и черный текст на нем
  5. cx.rect( 0, 3, 18, 11 );// и помещаем их на канвас
  6. cx.fillStyle = "#6DA3BD";
  7. cx.fill();
  8.  
  9. cx.font = "10px Normal Tahoma";
  10. cx.fillStyle = "#fff";
  11.  
  12. var mark = document.querySelectorAll( ".mark span" ); // получаем циферки со странички
  13. cx.fillText( parseInt( mark[0].innerHTML ), 0, 12, 16 );
  14.  
  15. // применяем favicon
  16. var oldicons = document.querySelectorAll( 'link[rel="icon"], link[rel="shortcut icon"]' );
  17. for(var i = 0; i < oldicons.length; i++) {
  18.     oldicons[i].parentNode.removeChild( oldicons[i] );
  19. }
  20.  
  21. var newicon = document.createElement( "link" );
  22. newicon.setAttribute( "rel", "icon" );
  23. newicon.setAttribute( "href", c.toDataURL() );
  24. document.querySelector( "head" ).appendChild( newicon );
  25.  
  26. // обновляем страничку каждые 2 минуты
  27. window.setTimeout( function () {
  28.     window.clearTimeout();
  29.     window.location.reload();
  30. }, 120000 );
* This source code was highlighted with Source Code Highlighter.


Собственно вот и все. Если хоть какую-то часть поста вы сочли полезным для себя, пусть это даже не касается темы топика, то разрешите время считать потраченным не зря на его написание.
Если же вас заинтересовало динамическое изменение favicon, то вы можете воспользоваться готовым плагином для jQuery — там можно и анимировать favicon'ки (через тот же canvas).

Спасибо за внимание.
Tags:
Hubs:
Total votes 138: ↑133 and ↓5+128
Comments54

Articles