Избранное | Русский | Войти

Руководство по гаджетам Google Wave

Изначально гаджеты развивались в качестве стандартного способа встраивания неподтвержденного кода в веб-приложения Google. В API Google Wave они представляют основной механизм изменения внешнего вида волн для сторонних разработчиков.

 

В этом руководстве описано создание гаджетов для Google Wave. Общая информация о создании гаджетов представлена в Руководстве разработчика по API гаджетов.

Содержание

  1. Гаджеты Google Wave: в чем отличие?
  2. Начало работы
    1. Запуск гаджета
  3. Общее состояние
    1. Разработка структуры гаджета Google Wave
  4. Гаджет аукциона
    1. Управление участниками
    2. Обработка предложений цены
    3. Объединение
  5. Роли
    1. Данные профилей

Гаджеты Google Wave: в чем отличие?

В Google Wave можно запускать большинство гаджетов, созданных для контейнеров, отличных от Google Wave. Однако эти гаджеты не могут применять все возможности многопользовательской среды, работающей в реальном времени, а именно Google Wave. Основное отличие гаджетов Google Wave от других гаджетов состоит в том, что Wave-гаджет существует в волне и может взаимодействовать с ней. Гаджеты, совместимые с Wave, могут:

  • получать доступ к управлению состоянием на более детальном уровне;
  • определять текущего зрителя и всех других участников волны;
  • гармонично работать с механизмом воспроизведения Wave.

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

Выполняемые в Google Wave гаджеты принадлежат волне, в которую они добавлены. В этом состоит отличие от контейнеров, подобных Orkut, где гаджеты, размещенные на странице профиля, принадлежат владельцу этой страницы. Следовательно, связанная с гаджетом информация, такая как пользовательские настройки, хранится на уровне волн (а именно в волне), а не на уровне пользователей. Информация о гаджете и его состояние доступны всем участникам волны. Обратите внимание: в отличие от обычных гаджетов, в гаджетах Google Wave не отображается название. Это позволяет отображать гаджет как часть обсуждения, а не показывать его в виде отдельного объекта.

Примечание. На данный момент Google Wave не поддерживает API OpenSocial, но поддерживает аналогичное определение ролей. Дополнительную информацию можно получить в разделе Роли.

Начало работы

По своей сути социальные гаджеты представляют собой XML-файлы, иногда называемые спецификациями гаджетов. Вот простой гаджет "Hello Wave" (hello.xml), в котором показаны базовые разделы спецификации:

<?xml version="1.0" encoding="UTF-8" ?>
<Module>
  <ModulePrefs title="Hello Wave">
<Require feature="wave-preview" /> </ModulePrefs>
<Content type="html">
<![CDATA[
Hello, Wave! ]]> </Content> </Module>

В примере "Hello Wave" представлен ряд разделов, которые управляют функциями и дизайном гаджета.

  • <Module> указывает, что в этом XML-файле содержится гаджет.
  • <ModulePrefs> содержит информацию о гаджете и его авторе.
  • <Require feature="wave-preview" /> указывает, что гаджет относится к API гаджетов Google Wave.
  • <Content type="html"> указывает, что тип содержания гаджета – HTML. Дополнительная информация представлена в Руководстве разработчика по API гаджетов.
  • <![ CDATA[…]]> включает основное содержание гаджета, в том числе весь код HTML, CSS и JavaScript (или ссылки на соответствующие файлы). Содержание этого раздела следует рассматривать как содержание тега body на обычной HTML-странице.

Запуск гаджета

Гаджет можно написать в любом текстовом редакторе. Создав гаджет, необходимо разместить его в общедоступном месте в Интернете (доступ к нему не должен быть ограничен брандмауэром). Варианты хостинга: GGE и SVN.

Чтобы добавить гаджет в волну, выполните следующие действия:

  1. Поместите курсор в волну и выберите Отладка > Добавить гаджет.
  2. В диалоговом окне Галерея гаджетов в текстовом поле URL XML-модуля гаджета введите URL спецификации гаджетов (в данном примере – http://gadget-doc-examples.googlecode.com/svn/trunk/wave/hello.xml ).
  3. Нажмите Добавить как XML.

Установка пользовательских настроек

Как уже было сказано выше, состояние гаджета, в том числе пользовательские настройки, хранится на уровне волны. Владельцем гаджета является волна. Это означает, что для всех участников волны используются одни и те же пользовательские настройки. Об этом не стоит забывать при разработке гаджетов для Google Wave. Следует включать только пользовательские настройки, которые требуются для волны с несколькими участниками.

Пользовательские настройки гаджета можно указать в текстовом поле Пользовательские настройки (JSON) диалогового окна Галерея гаджетов. Их нужно указывать в виде пар ключ-значение в формате JSON. В качестве примера рассмотрим гаджет с пользовательскими настройками mycolor и myname. Чтобы указать их значения, нужно ввести в текстовом поле Пользовательские настройки (JSON) следующие данные:

{"mycolor" : "Orange", "myname" : "Trevor"} 

Общее состояние

Характерной чертой гаджетов Google Wave является их возможность задавать состояние и отвечать на его изменение. Состояние гаджета Google Wave называется общим, поскольку оно одинаково для всех участников волны.

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

Помимо того, что состояние гаджета Google Wave является общим для всех участников волны, следует учесть, что в общем случае его может изменить любой участник и в любое время. Если два пользователя изменяют значения для различных ключей в одно и то же время, волна обрабатывает эту ситуацию. Однако при изменении значения одного и того же ключа принимается только одно изменение.

Что это означает для разработчиков гаджетов Google Wave? При разработке гаджета не стоит забывать о следующем:

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

В следующей таблице перечислены методы создания гаджетов с отслеживанием изменений состояния:

Метод Описание
setStateCallback(callback, opt_context) Регистрирует "заинтересованность" гаджета в подписке на изменение состояния. Указывает функцию callback, которая вызывается при изменении объекта состояния гаджета. Дополнительно можно указать объект (opt_context), предназначенный для получения обратного вызова. Этот метод может встречаться в гаджете только один раз.
setParticipantCallback(callback, opt_context)

Регистрирует "заинтересованность" гаджета в подписке на изменение состава участников. Указывает функцию callback, которая вызывается при изменениях состава участников. Эти изменения включают загрузку участников при первом запуске гаджета, их вступление или выход из волны, а также изменение информации об участниках, например имени. Сюда не входит выполнение участниками действий в волне.

Дополнительно можно указать объект (opt_context), предназначенный для получения обратного вызова. Этот метод может встречаться в гаджете только один раз.

wave.getState() Возвращает объект состояния гаджета, представляющий собой таблицу пар ключ-значение. Получив этот объект, можно выполнять над ним операции, например запрос значений определенных ключей. Например, метод wave.getState().get('count') возвращает значение ключа count.
submitDelta(delta) Обновляет объект состояния, добавляя к нему таблицу пар ключ-значение delta, которая представляет обновление. Например, метод wave.getState().submitDelta({'count': 5}) задает для ключа count значение 5.
Пользовательские обратные вызовы Последним необходимым элементом являются пользовательские функции обратного вызова, выполняемые при изменении объекта состояния волны или участников. Эти функции указываются в качестве аргументов методов setStateCallback() и setParticipantCallback().

Разработка структуры гаджета Google Wave

Эффективность работы гаджета Google Wave определяется доступностью и актуальностью объектов состояния и участников в момент обращения к ним. Чтобы удостовериться в этом, при разработке структуры гаджета Google Wave рекомендуется следовать приведенным ниже принципам:

  • Не обращайтесь к объектам состояния или участников в функции init(). Большинство Wave-гаджетов содержат функцию инициализации, вызываемую при их загрузке. В примерах этого документа данная функция называется init(). Ее можно использовать, чтобы удостовериться в работе волны и зарегистрировать обратные вызовы. Не допускайте попыток обращения к объектам состояния или участников в функции init(). Объекты состояния и участников не имеют содержательных значений до выполнения соответствующих обратных вызовов (setParticipantCallback и setStateCallback).
  • Изменяйте объект состояния при отправке события элементом пользовательского интерфейса. Это не строгое правило, а лишь рекомендация по разработке. Однако при создании интерактивного гаджета вам наверняка потребуется элемент пользовательского интерфейса, например кнопка для ввода информации пользователя. При отправке этим элементом события следует изменить объект состояния в коде.
  • Размещайте программную логику в функциях обратного вызова. Изменив объект состояния, дождитесь уведомления об изменениях, прежде чем отображать их в интерфейсе гаджета. Другими словами, основная часть кода должна быть написана в функциях обратного вызова. Функции обратного вызова вызываются при изменении объекта состояния (setStateCallback) или участников волны (setParticipantCallback). Добавление кода в эти функции помогает удостовериться в получении последних изменений.

В этом простом примере показана структура гаджета Google Wave. У этого гаджета есть единственный ключ count. Функция обратного вызова stateUpdated() обновляет вид гаджета при каждом нажатии кнопки участником волны, которое приводит к увеличению значения ключа count.

Вот структура гаджета в примере:

  • gadgets.util.registerOnLoadHandler(init) обозначает функцию init(), которую нужно вызвать при первой загрузке гаджета. В этом примере она называется init(), но это название не является обязательным.
  • Функция init() просто подтверждает, что волна работает, и вызывает метод wave.setStateCallback(stateUpdated). Основная программная логика гаджета содержится в функции обратного вызова stateUpdated(). Пример использования метода setParticipantCallback() можно найти в разделе Гаджет аукциона.
  • Функция buttonClicked() вызывается, когда участник волны нажимает кнопку "Нажми меня" в гаджете. Именно в данной функции изменяется объект состояния.
  • Интерфейс гаджета не отражает изменений состояния в функции buttonClicked(). Он обновляется в функции обратного вызова stateChanged(). Помните, что функции обратного вызова вызываются только после изменения связанных с ними объектов. Это позволяет гарантировать, что при обновлении интерфейса используются новейшие изменения.

Вот пример гаджета. Помните, что если два участника попытаются увеличить счетчик одновременно, будет учтено только одно изменение (это описано ранее в разделе Общее состояние).

<?xml version="1.0" encoding="UTF-8" ?> 
<Module>
<ModulePrefs title="State Example" height="120">
<Require feature="wave-preview" />
</ModulePrefs>
<Content type="html">
<![CDATA[
<div id="content_div" style="height: 50px;"></div>
<script type="text/javascript"> var div = document.getElementById('content_div'); function buttonClicked() { var value = parseInt(wave.getState().get('count', '0')); wave.getState().submitDelta({'count': value + 1}); } function stateUpdated() { if(!wave.getState().get('count')) { div.innerHTML = "The count is 0." } else { div.innerHTML = "The count is " + wave.getState().get('count'); } } function init() { if (wave && wave.isInWaveContainer()) { wave.setStateCallback(stateUpdated); } } gadgets.util.registerOnLoadHandler(init); // Reset value of "count" to 0 function resetCounter(){ wave.getState().submitDelta({'count': '0'}); } </script> <input type=button value="Click Me!" id="butCount" onClick="buttonClicked()"> <input type=button value="Reset" id="butReset" onClick="resetCounter()"> ]]> </Content> </Module>

Гаджет аукциона

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

Управление участниками

Волны представляют собой управляемые обсуждения с несколькими участниками в реальном времени. Каждый участник может открывать волну как в одном, так и нескольких окнах. Экземпляр гаджета в волне создается при каждом ее открытии. Общее состояние обеспечивает одинаковый вид всех экземпляров гаджетов. Часто для гаджета имеют значение и сами участники. Гаджеты могут получать список всех участников волны (вне зависимости о того, открыт ли у них гаджет) и зрителя. Зритель является пользователем, в клиенте волны которого выполняется определенный экземпляр гаджета.

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

При предложении цены зрителем и нажатии кнопки отправки его идентификатор и цена сохраняются в виде пары ключ-значение. Таким образом, они становятся частью состояния гаджета:

function buttonClicked() {
  var viewerId = wave.getViewer().getId();
  var state = wave.getState();
  var bid = parseInt(document.getElementById('yourBid').value);
  var currentBid = parseInt(state.get(viewerId, '0'));
  if (bid > currentBid) {
    delta = {};
    delta[viewerId] = bid;
    state.submitDelta(delta);
  }
}

Обработка предложений цены

После отправки предложения его нужно сравнить с ценами, предложенными другими участниками. Гаджет аукциона обрабатывает список цен за позицию. Этот список состоит из цен и предложивших их пользователей. При каждом изменении состояния гаджету нужно пересчитать максимальную цену и обновить свой вид.

В функции init(), выполняемой при загрузке гаджета, указаны два вызова функции обратного вызова:

  • wave.setStateCallback() – устанавливает функцию обратного вызова для обновления состояния гаджета.
  • wave.setParticipantCallback() – устанавливает функцию обратного вызова для обновления участников. В этом примере она используется для отслеживания количества участников в волне.
function init() {
  if (wave && wave.isInWaveContainer()) {
    wave.setStateCallback(renderInfo);
    wave.setParticipantCallback(renderInfo);
  }
}
gadgets.util.registerOnLoadHandler(init);

Гаджет аукциона отслеживает состояние одной пары ключ-значение: идентификатора зрителя участника волны, предлагающего цену, и самой цены. Оба метода wave.setStateCallback() и wave.setParticipantCallback() вызывают одну и ту же функцию обратного вызова renderInfo(). Эта функция сравнивает все предложенные цены и определяет максимальную. Она отображает текущую максимальную цену и предложившего ее пользователя.

function renderInfo() {
  if (!wave.getState()) {
    return;
  }
  var highestBid = 0;
  var highestBidderId = null;
  var state = wave.getState();
  var keys = state.getKeys();
  for (var i = 0; i < keys.length; ++i) {
        var bidder = keys[i];
        var bid = parseInt(state.get(bidder));
        if (bid > highestBid) {
          highestBid = bid;
          highestBidderId = bidder;
        }
      }
  var bidderName = 'Nobody';
  var thumbNail = 'http://gadget-doc-examples.googlecode.com/svn/trunk/images/unknown.gif';
  if (highestBidderId) {
    bidderName = highestBidderId;
    var participants = wave.getParticipants();
    var numPeople = participants.length;
    if (participants) {
      for (var i = 0; i < participants.length; ++i) {
        if (participants[i].getId() == highestBidderId) {
          var highestBidder = participants[i];
          bidderName = highestBidder.getDisplayName();
          if (!bidderName) {
            bidderName = highestBidder.getId();
          }
          thumbNail = highestBidder.getThumbnailUrl();
        }
      }
    }
  }
  document.getElementById('bidderThumbnail').src = thumbNail; 
  document.getElementById('bidderName').firstChild.nodeValue = bidderName;
  document.getElementById('highestBid').firstChild.nodeValue = highestBid;
  document.getElementById('yourBid').value = highestBid;
  document.getElementById('participants').firstChild.nodeValue = numPeople;
}

Объединение

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

Для разработки гаджетов Google Wave могут пригодиться инструменты JQuery и Firebug.

На данный момент Google Wave не кэширует гаджеты, поэтому все изменения, внесенные в исходный код, отображаются в работающих версиях гаджета сразу после обновления волны. Чтобы обновить волну, можно просто нажать на другую волну, а затем вернуться в волну с гаджетом.

Роли

Для успешной разработки гаджета Google Wave важно понимать, какие роли применяются к гаджету, выполняемому в среде Google Wave.

Примечание. В настоящее время Google Wave не поддерживает API OpenSocial. Тем не менее, в нем поддерживаются аналогичные концепции, такие как владелец, зритель и друзья.

В этой таблице представлена общая информация о ролях в Google Wave:

Роль Вызов метода волны Описание
Владелец гаджета На данный момент программный доступ отсутствует. Владельцем гаджета является содержащая его волна, а не добавивший его пользователь.
Друзья владельца гаджета wave.getParticipants() Возвращает участников волны.
Зритель гаджета wave.getViewer() Возвращает объект, представляющий просматривающего волну пользователя.
Хост wave.getHost() Участник, добавивший этот гаджет во всплеск. Обратите внимание, что он может больше не являться участником волны.

Данные профилей

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

  • wave.Participant.getId()
  • wave.Participant.getDisplayName()
  • wave.Participant.getThumbnailUrl()

Дополнительная информация представлена в Справочном руководстве по API гаджетов Google Wave.