Всем привет! Это продолжение статьи Пишем гаджет Windows 7. Теперь мы напишем более сложный гаджет, чем просто кнопка для запуска игры. Он будет отображать текущую температуру на улице с четырех разных сайтов. Результат можно увидеть на скриншоте в начале статьи.

Вступление

На самом деле, я терпеть не могу всевозможные виджеты для отображения погоды. Они кажутся мне бесполезными, потому что узнавать погоду мне требуется слишком редко, и я для этого просто выхожу на балкон. Но я не собираюсь пользоваться собственным произведением, написал его чисто ради интереса. (Because we can).

JavaScript - единственный из языков программирования, который оказался в программе первого семестра первого курса моей специальности в универе, так что мой гаджет работает именно на нем. Должен сказать, мне довольно нравится этот язык, потому что я люблю веб-дизайн и все с ним связанное, хоть и абсолютно не разбираюсь ни в джаваскрипте, ни в дизайне.

NB: это не мануал, я просто рассказываю о том, как решил задачу, поставленную в первом абзаце статьи. Более того, прошу высказывать ваши замечания и более элегантные решения в комментариях.

Брать температуру будем из XML-файлов, в которых погодные сайты отдают данные для разработчиков приложений. Это оказалось неожиданной проблемой - не так легко найти сайты, у которых можно скачать XML без регистрации бесплатно, я с трудом наскреб четыре штуки. Большинство для доступа к API требует оплату или регистрацию для получения индивидуального ключа доступа. Так что не удивляйтесь, что один из источников украинский :)

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

HTML

Сначала напишем внешнее оформление гаджета, чтобы потом сразу привязать к нему javascript-код. Я создал четыре блока с двумя абзацами в каждом: для температуры и источника данных:
<div id="container">
<div id="temp1">
<p id="digit1"></p>
<p id="name1">Яндекс</p>
</div>
<div id="temp2">
<p id="digit2"></p>
<p id="name2">Yahoo</p>
</div>
<div id="temp3">
<p id="digit3"></p>
<p id="name3">Accuweather</p>
</div>
<div id="temp4">
<p id="digit4"></p>
<p id="name4">weather.co.ua</p>
</div>
</div>

CSS

В файле CSS-стилей указываем размер и фон гаджета:
body { 
width: 260px;
height: 180px;
background-image: url("grass.jpg");
}
Вообще, указывать изображение для фона гаджета полагается с помощью специального элемента g:image, но у меня что-то не получилось.

Я попытался расположить эти четыре блока в сетку с помощью text-align: center у родительского блока, в браузере это сработало, а в самом гаджете блоки все равно встали вертикально друг за другом. Тогда я разозлился и прибил их гвоздями указал для них абсолютную позицию в углах гаджета:
#temp1, #temp2, #temp3, #temp4 {
position: absolute;
width: 130px;
height: 90px;
margin: 0px;
}
#temp1 {
top: 0px;
left: 0px;
}
#temp2 {
top: 0px;
right: 0px;
}
#temp3 {
bottom: 0px;
left: 0px;
}
#temp4 {
bottom: 0px;
right: 0px;
}
Весь CSS-код показывать не буду, больше ничего важного там нет.

JS

Создаем .js-файлик и первым делом записываем в переменные источники данных:
var url1 = 'http://export.yandex.ru/weather-ng/forecasts/27612.xml';
var url2 = 'http://xml.weather.yahoo.com/forecastrss?p=RSXX0063&u=c';
var url3 = 'http://rss.accuweather.com/rss/liveweather_rss.asp?metric=1&locCode=ASI|RU|RS052|MOSCOW';
var url4 = 'http://xml.weather.co.ua/1.2/forecast/27?dayf=1';
По этим ссылкам - погода в Москве, для других городов нужно изменить коды в URL.

Далее пишем функцию, которая будет загружать XML в переменную, используя ActiveX. Работать она будет только в Internet Explorer'е, но поддержка других браузеров нам не нужна, ибо гаджеты Windows работают именно через IE:
function loading(name, url) {
if (window.ActiveXObject) {
name = new ActiveXObject('Microsoft.XMLDOM');
}
name.async = false;
name.load(url);
return name;
}
Она проверяет, что браузер - IE, создает ActiveX-объект для XML и через метод .load загружает в него нужный файл. Вообще, обычно в подобных гаджетах это делают на jquery, но я написал все на чистом JS.

Теперь садимся и смотрим на каждый XML-файл. У Яндекса текущая температура хранится в fact → temperature. Теги <temperature></temperature> встречаются несколько раз, но нужный нам стоит первым сверху. Это все, что нужно было узнать, теперь можно писать код:
temp1_xml = loading(xmlYa, url1);
temp1 = temp1_xml.getElementsByTagName('temperature')
[0].childNodes[0].nodeValue;
output1 = document.getElementById('digit1');
output1.innerHTML = temp1 + '°';
Здесь мы с помощью специального метода .getElementsByTagName собираем коллекцию элементов с тегом temperature и берем значение первого из них, которое выводим в подобающее место нашего гаджета, прибавляя значок градуса, чтобы цифры не смотрелись слишком абстрактно.

В XML от Yahoo текущая температура хранится не в теге, а в атрибуте тега, вот так: <yweather:condition text="Light Snow" code="14" temp="-15" date="Mon, 21 Jan 2013 7:57 pm MSK"/>. Просто используем метод .getAttribute:
temp2_xml = loading(xmlYh, url2);
temp2 = temp2_xml.getElementsByTagName('yweather:condition')
[0].getAttribute('temp');
output2 = document.getElementById('digit2');
output2.innerHTML = temp2 + '°';
XML от accuweather.com оказался самым проблемным. Текущее состояние погоды хранится в первом сверху item → title, в строчке вида "Currently: Flurries: -13C". В зависимости от погоды второе слово может меняться, зато оба двоеточия будут всегда оставаться на месте (ну я надеюсь). Так что берем значение элемента как строку (метод .data) и обрезаем все до пробела после второго двоеточия, а также символ "C", он нам не нужен:
temp3_xml = loading(xmlAcw, url3);
var temp3_string = temp3_xml.getElementsByTagName('item')
[0].getElementsByTagName('title')[0].childNodes[0].data;
temp3 = temp3_string.substring
((temp3_string.lastIndexOf(': ')+2), (temp3_string.length-1));
output3 = document.getElementById('digit3');
output3.innerHTML = temp3 + '°';
Украинский сайт погоды сюрпризов не выдал, значение текущей температуры хранится в первом сверху теге <t>:
temp4_xml = loading(xmlUkr, url4);
temp4 = temp4_xml.getElementsByTagName('t')
[0].childNodes[0].nodeValue;
output4 = document.getElementById('digit4');
output4.innerHTML = temp4 + '°';
Осталось только сделать автообновление данных. Для этого я обернул весь вышеуказанный код вот так:
(function work() {
// весь код
setTimeout(work, 900000)
}) ();
Таким образом функция повторяет сама себя и данные обновляются каждые 15 минут. Где-то читал, что такой способ предпочтительнее, чем setInterval, а еще где-то вычитал, что оба этих метода в гаджетах Windows недопустимы, но ту статью я потерял :| Если есть лучший способ, прошу мне сообщить.

Завершение

Теперь можно собирать исходники в гаджет, об этом я рассказывал в предыдущей статье. Не забудьте создать файл gadget.xml. Полный исходный код можно посмотреть, распаковав файл гаджета архиватором (ссылка в конце поста).

Послесловие

Вообще, в этой статье я хотел доделать гаджет из предыдущей - выводить на кнопке количество часов, проведенных в игре. Я пытаюсь сделать это таким же способом - загрузка xml-данных своего профиля в Стиме методом .load, но в IE данные выводятся, а в гаджете - ни в какую. Я пока не разобрался, в чем проблема, так что ждите третьего поста на эту тему :) Задавайте вопросы в комментариях.

Скачать

Вы можете скачать то, что у меня получилось, если вам нужно:

Поиск