Вы будете очень удивлены, узнав какое количество информации доступно в Интернете через RSS и ATOM каналы - поиск в твиттере, напоминания гугл, собственные и другие блоги и многое другое. Вам просто необходимо найти оранжевую иконку и Вы точно найдете массу полезной информации, которая так и ждет, чтобы быть задействованной.
Сегодня мы займемся созданием красивого виджета для чтения подобных лент. Он будет извлекать любую ленту и отображать ее в любом месте сайта. Вы можете настроить его таким образом, чтобы он отображал последние сообщения с разных категорий блога, или упоминания о Вас в твиттере, или все что угодно :).
Решение проблем
Прежде чем начать разработку, нам необходимо прояснить что именно мы хотим и какие проблемы реализации у нас могут возникнуть. И найти их решения, конечно же.
Проблема 1 - чтение лент
Виджет не содержит серверной части, поэтому нам необходимо найти способ считывать ленты с помощью JavaScript. Ajax великолепная технология, но она имеет ограничения безопасности и позволяет работать только в пределах одного домена. Это означает, что внешние ленты нам будут недоступны.
И тут нам поможет YQL. Этот сервис читает ленту и делает ее доступной нашему скрипту в качестве JSON объекта, который мы можем вывести на странице.
YQL - бесплатный API сервис от Yahoo, с помощью которого Вы можете делать намного больше, чем просто читать ленты. Он служит шлюзом между Вашим и любым другим АПИ и позволяет Вам манипулировать ими с помощью легкого синтаксиса по типу SQL. Больше информации можно найти тут.
Настройка YQL требует небольших усилий, однако (нам необходимо динамически включить тег <script> в шапку сайта). К счастью, jQuery способен на это - есть метод под названием getJSON.
Проблема 2 - Разные форматы лент
Существуют разные форматы лент - RSS1, RSS2 и ATOM. Они отличаются друг от друга. Наш код должен уметь считывать результаты, которые выдает YQL и выводить их на страницу.
Эту проблему мы решим с помощью отдельной функции с несколькими логическими или\или ( || ) в нашем коде.
Проблема 3 - Недостаточно места
Тут уже проблема разметки, но она не менее важна. Поскольку боковые панели у сайтов обычно маленькие нам необходимо вместить несколько лент в довольно маленькое место. Вкладки тут вряд ли помогут, а вот выпадающий список будет в самый раз.
Приступим к созданию...
Шаг 1 - XHTML
Первая часть урока содержит базовую разметку.
demo.html
<div id="feedWidget">
<div id="activeTab">
<!-- Название -->
</div>
<div class="line"></div>
<div id="tabContent">
<!-- Содержимое -->
</div>
</div>
Поскольку все в нашем виджете зависит от JavaScript его нет смысла показывать, при отключенном в браузере JS. И поэтому feedWidget спрятан с помощью display:none в стилях. А показывается он с помощью метода jQuery show().
Шаг 2 - CSS
styles.css - часть 1
#feedWidget{
background:url(img/bg.png) repeat-x #47525c;
border:2px solid #48535e;
margin:0 auto;
width:200px;
padding:5px;
position:relative;
/* при выключенном JS ничего не отображается: */
display:none;
z-index:20;
}
#activeTab.hover,.dropDownList{
background:url(img/drop_arrow.png) no-repeat 95% 50% #47525c;
border:1px solid #38434d;
margin:-1px;
cursor:pointer;
/* CSS3 скругленные углы: */
-moz-border-radius:5px;
-webkit-border-radius:5px;
border-radius:5px;
}
#activeTab,.dropDownList div{
color:white;
cursor:pointer;
font-size:20px;
margin:0 2px 0 0;
padding:5px;
text-shadow:0 1px 1px black;
}
.line{
height:1px;
overflow:hidden;
background-color:#2b353d;
border-bottom:1px solid #687581;
margin:10px 0;
}
Обратите внимание на то, что мы определяем специальный класс при наведении на слой #activeTab, вместо обычного :hover псевдокласса. Это сделано потому, что стиль при наведении должен быть применен только в случае наличия нескольких источников лент, что невозможно определить используя CSS. Это будет сделано с помощью JS.
styles.css - часть 2
.dropDownList{
background-image:none;
position:absolute;
border-top:none;
padding:5px;
-moz-border-radius-topleft: 0;
-moz-border-radius-topright: 0;
-webkit-border-top-left-radius: 0;
-webkit-border-top-right-radius: 0;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.dropDownList div:hover{
background-color:#505e6b;
}
#tabContent div{
/* тут будут сообщения с ленты */
background-color:#EEEEEE;
color:#555555;
font-size:10px;
margin-bottom:10px;
padding:5px;
position:relative;
-moz-border-radius:5px;
-webkit-border-radius:5px;
border-radius:5px;
/* CSS3 тень ячейки: */
-moz-box-shadow:0 1px 1px black;
-webkit-box-shadow:0 1px 1px black;
box-shadow:0 1px 1px black;
}
Тут мы оформляем внешний вид зоны, в которой будут выводиться сообщения.
Шаг 3- jQuery
После подключения фреймворка в шапке документа мы можем использовать методы для построения сложных взаимодействий.
script.js - часть 1
/* Настройки: */
var tabs = {
"@tutorialzine" : {
"feed" : "http://twitter.com/statuses/user_timeline/67315866.rss",
"function" : twitter
},
"Latest Tutorials": {
"feed" : "http://feeds.feedburner.com/Tutorialzine",
"function" : rss
},
"Smashing Mag": {
"feed" : "http://rss1.smashingmagazine.com/feed/",
"function" : rss
},
"Script & Style" : {
"feed" : "http://feeds2.feedburner.com/ScriptAndStyle",
"function" : rss
}
}
$(document).ready(function(){
/* Считаем количество источников: */
var totalTabs=0;
$.each(tabs,function(){totalTabs++;})
$('#feedWidget').show().mouseleave(function(){
/* Если курсор покинул виджет, спрятать выпадающий список: */
$('.dropDownList').remove();
$('#activeTab').removeClass('hover');
}).mouseenter(function(){
if(totalTabs>1) $('#activeTab').addClass('hover');
});
$('#activeTab').click(showDropDown);
/* используем метод LIVe */
$('.dropDownList div').live('click',function(){
/* Calling the showDropDown function, when the drop down is already shown, will hide it: */
showDropDown();
showTab($(this).text());
});
/* показываем один из источников после загрузки страницы: */
showTab('@tutorialzine');
});
Объект tabs содержит записи о разных источниках, которые мы будем использовать вместе с функцией, которая будет выводить ленты на страницу. В конце мы выводим один источник (в скобках функции showTab) для отображения сразу после загрузки страницы.
script.js - часть 2
function showTab(key)
{
var obj = tabs[key];
if(!obj) return false;
var stage = $('#tabContent');
/* формируем query: */
var query = "select * from feed where url='"+obj.feed+"' LIMIT 5";
/* Формируем URL lkz YQL: */
var url = "http://query.yahooapis.com/v1/public/yql?q="+encodeURIComponent(query)+"&format=json&callback=?";
$.getJSON(url,function(data){
stage.empty();
/* элемент существует в RSS и ATOM лентах: */
$.each(data.query.results.item || data.query.results.entry,function(){
try{
/* Пробуем вызвать функцию юзера, "this" остаток информации ленты: */
stage.append(obj['function'](this));
}
catch(e){
/* Информируем о возможных ошибках: */
var f_name =obj['function'].toString().match(/function\s+(\w+)\(/i);
if(f_name) f_name = f_name[1];
stage.append('<div>There is a problem with your '+f_name+ ' function</div>');
return false;
}
})
});
$('#activeTab').text(key);
}
function showDropDown()
{
if(totalTabs<2) return false;
if($('#feedWidget .dropDownList').length)
{
/* Если выпадающий список уже показан, спрятать его: */
$('.dropDownList').slideUp('fast',function(){ $(this).remove(); })
return false;
}
var activeTab = $('#activeTab');
var offsetTop = (activeTab.offset().top - $('#feedWidget').offset().top )+activeTab.outerHeight() - 5;
/* Создание выпадающего слоя на лету: */
var dropDown = $('<div>').addClass('dropDownList').css({
'top' : offsetTop,
'width' : activeTab.width()
}).hide().appendTo('#feedWidget')
$.each(tabs,function(j){
if(j==activeTab.text()) return true;
$('<div>').text(j).appendTo(dropDown);
})
dropDown.slideDown('fast');
}
Функция showTab берет название вкладки в качестве параметра и показывает ее в виджете, после формирования YQL URL, и чтения его с помощью метода getJSON. После этого, ответ проходит цикл с помощью $.each и вызывается функция.
script.js - часть 3
function twitter(item)
{
/* Форматируем твиты, превращая хештеги, упоминания в ссылках URLS в правильные гиперлинки: */
return $('<div>').html(
formatString(item.description || item.title)+
' <a href="'+(item.link || item.origLink)+'" target="_blank">[tweet]</a>'
);
}
function rss(item)
{
return $('<div>').html(
formatString(item.title.content || item.title)+
' <a href="'+(item.origLink || item.link[0].href || item.link)+'" target="_blank">[read]</a>'
);
}
function formatString(str)
{
str = str.replace(/<[^>]+>/ig,'');
str=' '+str;
str = str.replace(/((ftp|https?):\/\/([-\w\.]+)+(:\d+)?(\/([\w/_\.]*(\?\S+)?)?)?)/gm,'<a href="$1" target="_blank">$1</a>');
str = str.replace(/([^\w])\@([\w\-]+)/gm,'$1@<a href="http://twitter.com/$2" target="_blank">$2</a>');
str = str.replace(/([^\w])\#([\w\-]+)/gm,'$1<a href="http://twitter.com/search?q=%23$2" target="_blank">#$2</a>');
return str;
}
В последней части у нас 2 функции - twitter и rss. Они берут объект (переданный из $.each d showTab()) и находят путь к ссылке и названию элемента ленты.
Вот и все готово! Пользуйтесь! :)