Как стать автором
Обновить

Написание и публикация гаджета для Google Wave

Время на прочтение8 мин
Количество просмотров620
После открытия регистрации на Google Wave появилась возможность использовать его для организации рабочего процесса и общения с клиентами.

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

Добавление элементов в блипы («blip») волны делается с помощью гаджетов. Которые, в свою очередь, состоят всего из двух файлов:
installer.xml,
gadget.xml

installer.xml нужен, чтобы добавить кнопку на wysiwyg панель google wave. (так же гаджет можно добавить по ссылке, не устанавливая никаких расширений).
gadget.xml файл с настройками и кодом гаджета.

Installer.xml


<extension
  name="Progressbar"
  thumbnailUrl="http://adcirobot.appspot.com/assets/gadget.png"
  description="Insert a progress bar into your waves, and click it to indicate the current progress. ">
 <author name="Fedor Indutny"/>
 <menuHook location="toolbar" text="Add Project Progress"
   iconUrl="http://adcirobot.appspot.com/assets/gadget-small.png">
  <insertGadget url="http://adcirobot.appspot.com/assets/gadget.xml"/>
 </menuHook>
</extension>


* This source code was highlighted with Source Code Highlighter.

Это реальный пример взятый из опубликованного мною гаджета.

Google wave Gadget API это надстройка над Google Gadget API, поэтому структура файлов практически идентична.

Обязательно нужно указать имя расширения, имя автора и описание, т.к. оно будет отображаться в галерее. Так же
в файле есть menuHook запись, означающая добавление кнопки на панель редактирования блипа (думаю, смысл настроек понятен из их названия). insertGadget говорит нам, что при нажатии этой кнопки после курсора будет вставлен гаджет, указанный по ссылке.

Собственно, это все, что необходимо знать об installer.xml.

Gadget.xml


<?xml version="1.0" encoding="UTF-8"?>
<Module>
  <ModulePrefs  
    title="Progressbar"
    author="Fedor Indutny"
    author_email="fedor.indutny@gmail.com"
    screenshot="http://adcirobot.appspot.com/assets/gadget.png"
    thumbnail="http://adcirobot.appspot.com/assets/gadget.png"
  >
    <optional feature="shareable-prefs" />
    <Require feature="wave" />
    <Require feature="dynamic-height"/>
  </ModulePrefs>
  <Content type="html"><![CDATA[
      любой html-код
  ]]></Content>
</Module>


* This source code was highlighted with Source Code Highlighter.


Аттрибуты ModulePrefs тоже довольно логичны и берутся из Google Gadget API.
Стоит уделить внимание:
  • shareable-prefs — означает, что данные, которые хранит гаджет будут общими для всех пользователей (соответственно, обновляться динамически у всех подписчиков волны).
  • wave — подключает wave.js скрипт, который дает доступ к Wave API функционалу (нам нужно будет только изменение параметров и состояния).
  • dynamic-height — я думаю, объяснять не стоит.


В Content можно расположить свой код (он будет выполняться внутри iframe, поэтому разрешено писать все, что угодно), вот такой код написал я:
<script type="text/javascript" src="url_to_jquery.js"></script>
  
  <div id="A" style="-webkit-user-select:none;height: 10px;background:white;border:1px solid #bbb;margin:0;padding:0;" title="click to indicate current progress ">
    <div id="B" style="height:100%;width: 0%;background: transparent url(data:image/png;base64,большой base64 код) repeat-x 0 0">
      <div style="-webkit-user-select:none;height:100%;opacity:0.33;background:transparent url(data:image/gif;base64,большой base64 код) repeat 0 0;border: 0;margin:0;padding:0"></div>
    </div>
  </div>
<script type="text/javascript">
код будет приведен чуть ниже
</script>

* This source code was highlighted with Source Code Highlighter.

(Выношу js-код отдельно, чтобы была нормальная подсветка синтаксиса. jquery я подключал просто inline, поэтому здесь не привожу).

Javascript


    // Функция, передаваемая в качестве аргумента будет вызвана в момент
    // полной загрузки гаджета
    gadgets.util.registerOnLoadHandler(function() {
      var
        // Этим мы будем блокировать редактирование значения гаджета
        lock = 0,
        // Инициализация (A - progressbar holder, B - progressbar)
        A = $("#A"), B = $("#B"), mousemove = 0, $procent = 0,
        // Кэшируем
        round = Math.round, A$offset = A.offset(),
        A$outerWidth = A.outerWidth();
      
      // Если вдруг этот гаджет решили выполнять
      // вне Google Wave - прекратить исполнение
      if (!wave || !wave.isInWaveContainer()) return;
      
      // Функция будет вызвана при изменении состояния(параметров) гаджета
      wave.setStateCallback(function() {
        // Используя системный объект wave получаем объект состояния:
        // getState()
        // А в нем есть функция get([attr-name]), её и используем
        var procent = wave.getState().get('procent') || 0;
        
        // Делаем всякие красивости с анимацией фона
        B.stop().animate({width: procent + "%", backgroundPosition: "(0px -" + procent + "px)"},function() {
          A[(procent >= 100) ? "addClass" : "removeClass"]("full");    
        });
      });
      
      // Функция будет вызвана при изменении режима
      // (редактирование, просмотр)
      wave.setModeCallback(function() {
                
        if (lock = wave.getMode() == wave.Mode.EDIT ? 0 : 1) {
          // Если в режиме чтения
          A.css({cursor: ""});
          B.css({cursor: ""});
          mousemove = 0;
        } else {
          // Если в режиме записи
          A.css({cursor: "pointer"});
          B.css({cursor: "pointer"});
        }
      });
      
      // На клик будем менять процент прогресса
      A.click(function(E) {
      
        E.preventDefault();
        
        // Если мы не в режиме чтения
        if (lock) return;
        
        // submitDelta - записывает значение в состояние
        // (Всем подписчикам будет разослано сообщение об изменении,
        // вызван setStateCallback )
        wave.getState().submitDelta({procent:
          E.ctrlKey ?
          (A.hasClass("full") ? 0 : 100)
          :
          round((100 * ( E.pageX - A$offset.left) / A$outerWidth))
        });
      }).mousedown(function(E){
        // Делаем Drag поведение
        E.preventDefault();
        mousemove = 1;
        changed = 0;
      });
      
      $(window).mousemove(function (E){
        // В принципе все тоже самое, только submitDelta
        // Будет вызван при отпускании мышки
        if (!mousemove || lock) return;
        
        changed = 1;
              
        B.css({
          width: ($procent = round((100 * ( E.pageX - A$offset.left) / A$outerWidth))) + "%",
          backgroundPosition: "0 -" + $procent + "px"
        },
        function() {
          A[($procent >= 100) ? "addClass" : "removeClass"]("full");    
        });
        
      })
      .mouseup(function(E) {
        mousemove = 0;
        if (!changed) return;
        
        wave.getState().submitDelta({procent: $procent});
        
      });
      
      // Устанавливаем высоту гаджета
      gadgets.window.adjustHeight(13);
    });


* This source code was highlighted with Source Code Highlighter.


Более подробно об функциях API можно узнать здесь.

Процесс публикации


Гаджет готов, заливаем файлы на любой хостинг (как правило, используется appspot) — можно приступать к публикации!

Для начала нужно установить расширение Submitty. После установки станет доступным создание нового типа волн — Extension Submission. Создаем волну, следуем инструкциям (заполняем данные анкеты и вводим путь к installer.xml) и нажимаем кнопку Share with Reviewers.
Теперь ваш гаджет отправился на рассмотрение командой Google Wave, через определенное время вам ответят и (если все нормально) пришлют ссылку на ваш гаджет в галерее.

А вот и мой гаджет.
Побаловаться с ним можно здесь.

Спасибо за чтение!

P.S.
Если есть интерес — могу рассказать про использование нового API при написании роботов для Google Wave.
Теги:
Хабы:
+35
Комментарии10

Публикации

Истории

Ближайшие события

Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн