Завдання комунікації між вкладками і виявлення активної вкладки

Наочний приклад завдання — сайт vk.com. Кожен раз коли ви відтворюйте музику або відео в одній вкладці — в інших вкладках відтворення зупиняється. І якщо ви звернетеся в інтернет за допомогою у вирішенні даної задачі, то напевно знайдете опис Storage Events або Page Visibility API або навіть готові рішення, наприклад Visibility.js.
На хабре вже був огляд цих речей, наприклад ось і .



Я пройшов цим шляхом, але не одне з рішень мене не влаштувало. Мені хотілося чогось простого, легкого і не вимагає глибокого вивчення деталей.


Рішення, яке вийшло в результаті, отримало назву DuelJS (просто рандомное унікальна назва) і нижче я спробую порівняти його з Visibility.js щоб уникнути зайвої критики в свою сторону.

Активна вкладка

Зручна кросбраузерна обгортка для простого відображення стану «ця вкладка зараз активна», visibility.js буде виглядати наступним чином:

if ('visible' == Visibility.state()) {
// ця вкладки
}

У вкладки Visibility є 3 стани: visible, hidden та prerender.

Перевагою Visibility також є callbacks, які ви можете вішати на безліч подій, таких як активізація вкладки, setInterval в активному вікні тощо.

Філософія DuelJS дещо спрощено:
1. Всі вкладки мають лише 2 стану — Master та Slave
2. Майстер вкладка це вкладка, в якій ведеться робота — нічого зайвого, все решта є Slave.

При такому підході досить лише однієї функції: window.isMaster() — перевірити чи є вкладка майстром.

if (window.isMaster()) {
// ця вкладки
}

Комунікації між вкладками

Тепер перейдемо до комунікацій між вкладками. Найбільш підходящим рішенням мені здалося використання Storage Events, хоча вони і не без проблем. До речі знаходив я в гуглі ще такі варіанти як використання postMessage API або WebSockets.

Основна проблема Storage Events полягає в їхній поганій підтримці деякими MSIE, хоча до недавнього часу і в інших браузерів теж могли виникати з цим проблеми.

Так як Visibility.js є по суті обгорткою над Page Visibility API — робота зі Storage Events в ній відсутня.

У DuejJS існує кросбраузерна обгортка над Storage Events, яка виражається в наступної філософії:
1. Комунікації між вкладками здійснюються за допомогою каналів
2. Усередині каналу вкладки можуть запускати події, на які можуть реагувати інші вкладки в цьому каналі

Створити канал досить просто:

var ch = duel.channel('channel_name'); // channel_name - ім'я каналу

Тепер визначимо поведінку при виклику події qwerty:

ch.on('qwerty', function (a, b, c, ...) {})

Метод on у каналу визначає його поведінку. У функції, що передається другим параметром може бути скільки завгодно аргументів, або не бути зовсім.

Запустити подія так само легко. Слово on тепер замінимо на broadcast, а передаються аргументи вставимо після назви події:

ch.broadcast('qwerty', a, b, c, ...)


Створення плеєра з поведінкою як на vk.com

Для нетерплячих читачів відразу даю посилання на робочий приклад.

Основна суть програми полягає у трьох рядках:
1. var player = duel.channel('player'); (визначення каналу)
2. player.on('stop', function () {… (визначення поведінки при події stop)
3. player.broadcast('stop'); (запуск події stop)

Повний код сторінки виглядає наступним чином:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Зупинено</title>
<!-- Заголовок (title) сторінки відображає стан відтворення. -->

<script type="text/javascript" src="duel.min.js"></script>
<link rel="stylesheet" type="text/css" href="pretty.css">
</head>
<body>
<!-- div #preview представляє з себе клікабельну картинку, при кліці по якій ініціалізується iframe з роликом на youtube -->
<div id="preview"><div>PLAY</div></div>
<a href="index.html" target="_blank">Відкрити нову вкладку</a>
<script type="text/javascript">
/** відкриваємо канал з ім'ям player */
var player = duel.channel('player');

/** превью для відео-ролика */
var previewDiv = document.getElementById('preview');

/**
* Реєструємо нову подію каналу player
*/
player.on('stop', function () {
/**
* Видаляємо iframe
*/
var frame = document.getElementsByTagName('iframe')[0];
frame.parentNode.removeChild(frame);

/**
* Показуємо превью
*/
previewDiv.style.display = 'block';

/**
* Оновлюємо заголовок вкладки
*/
document.title = 'Зупинено';
});

previewDiv.onclick = function () {
/**
* Посилаємо сигнал stop в канал player
*/
player.broadcast('stop');

/**
* Створюємо новий елемент iframe з відео з youtube
*/
var frame = document.createElement("iframe");
frame.width = '859';
frame.height = '480';
frame.src = '//www.youtube.com/embed/xsV8TrF4gN0?rel=0&autoplay=1';
frame.frameborder = '0';

/**
* Вбудовуємо його під превью і приховуємо превью
*/
previewDiv.parentNode.insertBefore(frame, previewDiv.nextSibling);
previewDiv.style.display = 'none';

/**
* Оновлюємо заголовок вкладки
*/
document.title = 'Граємо...';
}
</script>
</body>
</html>



Висновок

Буду дуже радий якщо вам допоможе дане рішення і використовувати його в своїх проектах. Я відкритий до ідей по поліпшенню. Ліба — кросбраузерна і працює в тому числі і в IE, за рахунок вбудованих хаків.



Корисні посилання

Коротка документація DuelJS на сайті
Репозиторій DuelJS на GitHub
Ще одна демка DuelJS

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.