Разработчику, желающему воплотить более оригинальную идею, чем трансляция RSS-потока или демонстрация фотографий из Flickr, целесообразно воспользоваться онлайновым редактором, размещенным по адресу http://code.google.com/intl/en/apis/gadgets/docs/legacy/gs.html#GGE. Эта утилита, помимо базовых функций редактирования программного текста, содержит большой набор примеров – зачастую после их изучения можно обойтись даже без чтения документации; как уже говорилось, структура API вполне стройна и очевидна.
Обратите внимание: XML-файл должен предоставляться в кодировке UTF-8. Теоретически можно указать и другие кодировки, однако в этом случае API ядра системы управления гаджетами может работать некорректно (русские буквы просто преобразуются в спецсимволы HTML). При необходимости использовать русский язык в текстах (например, в диалогах) файл следует конвертировать в UTF-8 (а лучше использовать специальные функции подсистемы «интернационализации», но их мы рассмотрим в следующих обзорах). Самый наглядный способ – просто скопировать исходный текст гаджета в окно редактора и сохранить файл (он автоматически будет размещен на сервере Google).
Чрезвычайно полезная возможность, реализованная в редакторе, – предварительный просмотр. Разработчик может оперативно оценить внешний вид своей разработки и, что важнее, ее работоспособность. Кроме того, там же можно загрузить завершенную программу в глобальный каталог гаджетов Google.
Структура XML вполне очевидна, следует только отметить, если программный код разработки размещается в ее теле (используется тег <Content type='html'>), а не во внешнем файле, то его следует обрамлять сигнатурами <![CDATA[и]]>, указывающими XML-парсеру на то, что это – не часть структуры XML-файла, а данные, которые следует передать для обработки в неизменном виде (CDATA – это Character Data, стандартное XML-определение). Обычно в этом поле содержится не только HTML, но и JavaScript, который и обеспечивает прикладную функциональность гаджета.
Разработчик данного гаджета разместил исходный текст программы на собственном сайте, ссылка на который размещена в атрибуте href тега <Content>. Это позволяет эффективно отделить функциональную часть модуля от интерфейсной. Такой подход накладывает и несколько ограничений. В частности, необходимо в явном виде декларировать необходимые разделы API гаджетов и выполнять специальную обработку адресной строки, передавая параметры вызывающего модуля. Иными словами, роль iGoogle здесь практически сводится к выводу внешнего содержимого в заданном фрейме, ну и небольшой библиотеки полезных функций. Это не то, чего бы хотелось.
В то же время такая техника может быть полезна, если гаджет получается очень объемным и (или) его функциональность вынесена в модули, подготовленные с помощью Flash/Flex, Silverliht и др. (хороший пример: размещение в теле гаджета видеороликов, транслируемых с помощью внешнего Flash-плеера). Тег <ModulePrefs> описывает реквизиты разработки, к этому тегу мы еще вернемся.
Более сложный пример: гаджет, загружающий данные XML с внешнего (по отношению к iGoogle) сайта. Эта разработка была предоставлена проектом «Антивирусный дайджест» (www.antivirus-digest.net). Сайт (на нем размещается рейтинг антивирусов), формируемый, как заявляют создатели, «на основе реальных данных». На сервере размещается виртуальная машина, которая играет роль жертвы для вирусов, «троянов», червей, затем проверяется несколькими антивирусами, после чего формируется еженедельный дайджест успехов разных антивирусных программ в ловле всяческой «заразы». Данные рейтинга доступны в RSS, откуда их и извлекает гаджет.
Логика работы вполне прозрачна: загружается XML (посредством функции _IG_FetchXmlContent), формируется структура записей, откуда и извлекаются данные. Обратите внимание: второй параметр _IG_FetchXmlContent – функция, которая определяется по месту вызова; она содержит практически всю функциональность разработки, связанную с генерацией HTML. Функция _gel – просто короткий синоним для вызова JavaScript document.getElementById(), _IG_RegisterOnloadHandler более интересна – она позволяет зарегистрировать в системе функцию-обработчик события «загрузка гаджета».
API гаджетов разделен на две основные группы: ядро и расширения. Среди функций первой группы – средства и объекты для управления подсистемой хранения пользовательских данных, используемых для настройки параметров гаджета (_IG_Prefs()). Разработчику доступны инструменты для создания типизированных параметров (строка, целое число, булева переменная, массив). Кроме того, там же содержатся API общего назначения, такие, как загрузка текстового и XML-содержимого (что и использовано в листинге 3), средства для управления некоторыми событиями (_IG_RegisterOnloadHandler) и изображениями (_IG_GetImage, _IG_GetCachedUrl).
Листинг 3. Гаджет, извлекающий данные из RSS– или XML-потока
<Module>
<ModulePrefs title='Рейтинг antivirus-digest.net'
scrolling='true'
author_email='[email protected]'
author='[email protected]'
width='340' height='230'
description='Рейтинг антивирусов'
thumbnail='http://antivirus-digest.net/img/current_week_antivir.png'/>
<Content type='html'>
<div id='content_div'></div>
<script type='text/javascript'>
function displayRSSData() {
// Адрес RSS/XML-файла для загрузки
var url = 'http://antivirus-digest.net/rss.php';
//Загружаем данные, в случае ошибки сообщаем пользователю
_IG_FetchXmlContent(url, function (response) {
if (response == null || typeof(response)!= «object» || response.firstChild ==
null) {
_gel(«content_div»). innerHTML = «<i>Сбой при загрузке</i>»;
return;
}
// Начало формирования HTML-текста (часть неинформативных строк, связанных
// с оформлением, в листинге опущена)
var html = '';
//Разбираем полученный массив информации, извлекая ключи и их значения
var itemList = response.getElementsByTagName(«item»);
for (var i = 0; i < itemList.length; i++) {
var nodeList = itemList.item(i). childNodes;
for (var j = 0; j < nodeList.length; j++) {
var node = nodeList.item(j);
if (node.nodeName == «title») {
var name = node.firstChild.nodeValue;
}
if (node.nodeName == «description») {
if (node.firstChild.nodeName == «#cdata-section»)
var data = node.firstChild.nodeValue;
}
}
// В цикле добавляем значения переменных в переменную, содержащую HTML-код
html += name;
html += «<br>»;
html += data;
html += «<br>»;
}