Статьи

Закрепление сайта: вращающиеся значки наложения для нескольких сервисных уведомлений

В своем последнем посте я рассказал о том, как использовать API закрепления сайтов в IE9 для реализации значков наложения для улучшения уведомлений пользователей. Демонстрация была посвящена тому, как отобразить числовой значок, чтобы указать, когда произошло определенное событие (например, сообщения в папке входящих сообщений).


Закрепленный сайт с наложенным значком

Это действительно отличный способ сообщить вашим пользователям, что для них есть ожидающая информация. Но что произойдет, если ваш сайт предлагает несколько типов уведомлений? В настоящее время веб-сайты предлагают такую ​​большую функциональность, что довольно часто они обслуживают различные типы уведомлений, от запросов друзей и напоминаний о событиях до новых сообщений и приглашений в игры.

Вращающиеся иконки нескольких оверлеев

Отличительной особенностью API Pinning сайта является то, что он очень гибкий и с помощью некоторого волшебства JavaScript вы можете легко отображать несколько значков наложения для различных служб, которые у вас есть. В этой демонстрации я хочу показать 3 различных наложенных значка, которые предупреждают пользователя об ожидающих сообщениях, запросах и действиях.

Как и прежде, мне пришлось проявить некоторые из моих художественных талантов, создав иконки наложения с помощью редактора x-icon . Я создал 5 каждого из них, и вот как выглядят первые три:

Код немного изменился по сравнению с последней демонстрацией, чтобы вместить несколько бит данных за выборку. Если раньше я выбирал только один фрагмент данных, то в этой демонстрации я возвращаю 3, по одному для каждого типа уведомлений:

myPin.init([{ "data" : [{ "label" : "Messages", "ntype" : "M", "num": 2 }, { "label" : "Requests", "ntype" : "R", "num": 1 }, { "label" : "Actions", "ntype" : "A", "num": 3 }] },
               { "data" : [{ "label" : "Messages", "ntype" : "M", "num": 1 }, { "label" : "Requests", "ntype" : "R", "num": 5 }, { "label" : "Actions", "ntype" : "A", "num": 2 }] },
               { "data" : [{ "label" : "Messages", "ntype" : "M", "num": 5 }, { "label" : "Requests", "ntype" : "R", "num": 1 }, { "label" : "Actions", "ntype" : "A", "num": 4 }] }
              ]);

Напоминаем, что метод getData () имитирует захват удаленных данных. Поэтому, если мы посмотрим на данные выше, мы можем смоделировать откат трех отдельных битов данных. Вот почему мы вызываем метод каждые 10 секунд, используя setInterval. Это позволяет нам увидеть, как уведомления могут выглядеть в течение определенного периода времени. 

setInterval(function () { myPin.getData() }, 10000);

Следующее, что изменилось, — это использование таймера, чтобы позволить небольшую задержку при рендеринге значков наложения. Использование setTimeout () обеспечивает достаточную задержку, чтобы отдельный значок наложения был виден пользователю перед переходом к следующему значку. Если бы у нас не было этой задержки, ротация была бы слишком быстрой, чтобы предоставить какое-либо полезное уведомление. Если мы посмотрим на следующее изображение, то увидим, как будет выглядеть уведомление:


Значок наложения, показывающий числовое уведомление

Это достигается с помощью следующего кода:

// Grab the current set of data...
currData = this.dataBin[this.currIndex++].data;    
         
/* We're going to display a new overlay every x number of seconds to display a new overlay icon so
   let's loop through the data elements for the current set of data... */
for (var i=0; i < currData.length; i++ ){
                     
    (function(idx) { setTimeout( function(){ myPin.dispOverlay( currData[idx] ); }, 1000 * idx); }( i ));                  
                     
}

Вот что происходит. В первой строке я беру текущий набор данных, который содержит всю информацию об уведомлениях (сообщения, запросы и действия). Эти данные выглядят так:

[{ "label" : "Messages", "ntype" : "M", "num": 2 },
{ "label" : "Requests", "ntype" : "R", "num": 1 },
{ "label" : "Actions", "ntype" : "A", "num": 3 }]

Я перебираю каждую группу данных и назначаю таймер с помощью setTimeout (), который будет вызывать dispOverlay () с интервалом ~ 1 секунда. Это магический код, который учитывает постепенную задержку рендеринга иконок, о которой я упоминал ранее. Ожидаемая функциональность заключается в том, что значок «сообщения» будет отображаться, за которым следует значок «запросы» через 1 секунду, а затем, наконец, значок «действия».

Теперь вам может быть интересно, почему у меня есть анонимная функция, обертывающая setTimeout () . Это потому, что у меня есть замыкание в setTimeout, которое может вызвать общую проблему с областью видимости, в которой переменная ‘i’, которую я использую для получения текущего индекса данных, будет обновлена ​​только до последнего значения индекса. У Джеймса Падолси есть отличное объяснение, и спасибо Джону Дэвиду Далтону за помощь в решении этой проблемы.

Последнее изменение в dispOverlay (), в котором мне нужно определить, какой значок наложения нужно отобразить. Поскольку у меня теперь есть три разных типа уведомлений, мне нужен условный оператор, чтобы определить тип и построить правильное имя иконки:

if (theData.ntype == "M") {
    oImg = "images/messages-" + theData.num + ".ico";
} else if (theData.ntype == "R") {
    oImg = "images/requests-" + theData.num + ".ico";
} else if (theData.ntype == "A") {
    oImg = "images/actions-" + theData.num + ".ico";
}

Это проверяет тип и отображает правую иконку в зависимости от типа и количества уведомлений, ожидающих этого типа.

Демо и финальный код

Вы можете проверить демо, перейдя сюда в IE9:

http://reybango.com/demos/sprotate/index.html

Когда страница отобразится, перетащите вкладку на панель задач и закрепите ее. Вы должны увидеть новое окно с новым закрепленным сайтом. Далее вы увидите, что значки наложений появляются на панели задач, и они должны начинать циклически повторяться каждые 10 секунд.

Вот полный исходный код. Вы также можете скачать все здесь .

<!DOCTYPE html>
<html>
<head>
<title>Pinned Site - Rotating Overlay Icons</title>
<link rel="shortcut icon" type="image/ico" href="favicon.ico" />
<meta name="application-name" content="Pinned Site Test" />
<meta name="msapplication-starturl" content="http://reybango.com/demos/sprotate/index.html" />
<meta name="msapplication-navbutton-color" content="#3480C0" />
<meta name="msapplication-window" content="width=1024;height=768" />
<meta name="msapplication-tooltip" content="Testing the Pinned Site API" />
<style>
body {
    background: none repeat scroll 0 0 #4492CE;
    font: 440%/1.4em 'Segoe Light',Segoe,'Segoe UI','Meiryo Regular','Meiryo',sans-serif;  
    color: #EDEFF4;
}
 
</style>
 
</head>
 
<body>
 
<div>
<h1>Pinned Sites</h1>
<p>Rotating Overlay Icons</p>
</div>
 
<script>
 
    var myData = [];
 
    var myPin = {
 
        currIndex: 0,
        dataBin: [],
         
        getData: function () {
 
            var idx = 0, currData = [], cntr = 0, theData;
         
            // Determines whether the current page was launched as a pinned site...
            if (window.external.msIsSiteMode()) {
 
                // Grab the current set of data...
                currData = this.dataBin[this.currIndex++].data;    
         
                /* We're going to display a new overlay every x number of seconds to display a new overlay icon so
                   let's loop through the data elements for the current set of data... */
                for (var i=0; i < currData.length; i++ ){
                     
                    (function(idx) { setTimeout( function(){ myPin.dispOverlay( currData[idx] ); }, 1e3 * idx); }( i ));                   
                     
                }
                 
                if (this.currIndex > 2) { this.currIndex = 0 }
                 
            }
 
        },
 
        dispOverlay: function (theData) {
 
            var oImg = "";
 
            // Is there any data?
            if (theData) {
 
                // Clear any preexisting overlay icon
                window.external.msSiteModeClearIconOverlay();
 
                // Render the overlay icon based on the data returned...
                if (theData.ntype == "M") {
                    oImg = "images/messages-" + theData.num + ".ico";
                } else if (theData.ntype == "R") {
                    oImg = "images/requests-" + theData.num + ".ico";
                } else if (theData.ntype == "A") {
                    oImg = "images/actions-" + theData.num + ".ico";
                }              
 
                // Go ahead and create the overlay image and it's label...
                this.setOverlay(oImg, theData.label);
 
            }
 
        },
 
        setOverlay: function (icon, desc) {
 
            // Sets the overlay icons...
            window.external.msSiteModeSetIconOverlay(icon, desc);
            window.external.msSiteModeActivate();
 
        },
 
        init: function (myData) {
 
            this.dataBin = myData;
            this.getData();
             
        }
 
    };
 
    // This clears out any previously set overlay icons...
    window.external.msSiteModeClearIconOverlay();
     
    // Run it once to kick everything off...
    myPin.init([{ "data" : [{ "label" : "Messages", "ntype" : "M", "num": 2 }, { "label" : "Requests", "ntype" : "R", "num": 1 }, { "label" : "Actions", "ntype" : "A", "num": 3 }] },
                { "data" : [{ "label" : "Messages", "ntype" : "M", "num": 1 }, { "label" : "Requests", "ntype" : "R", "num": 5 }, { "label" : "Actions", "ntype" : "A", "num": 2 }] },
                { "data" : [{ "label" : "Messages", "ntype" : "M", "num": 5 }, { "label" : "Requests", "ntype" : "R", "num": 1 }, { "label" : "Actions", "ntype" : "A", "num": 4 }] }
               ]);
 
    // This is only here because I want to simulate pulling data on a regular interval...
    setInterval(function () { myPin.getData() }, 10000);
 
</script>
</body>
</html>