Задача
В качестве простого примера рассмотрим виджет для компании Offline Telecom, позволяющий встраивать в личный кабинет видео с YouTube.
Виджет добавляет на страницу локалезависимый заголовок и фрейм с видеоплеером. Ссылка на видео задаётся в конфигурационном файле.
Файловая структура
Пусть код компании – offline (указан в /etc/hydra/hupo_configuration.yml в ключе client). Виджет назовем videos.
Создадим директорию /etc/hydra/hupo/offline, в которой будем проводить разработку. Файловое дерево этой директории будет выглядеть следующим образом:
Служебные файлы
Для того, чтобы подключить наш код к приложению, нужно создать файлы со следующим содержанием:
Gem::Specification.new do |s| s.name = 'hupo-vendor-engine' s.version = '0.1' s.authors = ['Your Name'] s.email = %w(your@email.com) s.homepage = 'http://github.com/latera/hupo' s.summary = 'Offline Telecom HUPO extension.' s.description = 'Provides vendor extensions for Hupo.' s.files = Dir['lib/**/*'] s.require_paths = %w(lib) end
require 'hupo_vendor_engine/engine'
module HupoVendor class Engine < Rails::Engine isolate_namespace HupoVendor end end
Серверная часть
Виджет видео не взаимодействует с сервером, поэтому на сервере достаточно лишь объявить пустой класс виджета:
module Offline class VideosWidget < HupoWidget::Base end end
Конфигурация и переводы
Прежде, чем переходить к программированию клиентской части, удобно определить настройки:
offline: videos: # спецификации для виджета с кодом offline.videos cat_gone: # настройки спецификации link: "//www.youtube.com/embed/WxGS-2M6_5I" # другая спецификация copter_cat: link: "//www.youtube.com/embed/b6c5wLTaQi0"
Переводы имеют схожую структуру:
ru: offline: videos: cat_gone: title: Кот ушел copter_cat: title: Кот-вертолет
Клиентская часть
Скрипты клиентской части программируются на языке CoffeeScript, который транслируется в JavaScript на этапе запуска приложения. Приложение использует фреймворк Backbone.js. В этом примере используется только та часть, которая касается представлений.
Шаблоны задаются на языке HAML с возможностью использования CoffeeScript. Шаблон также компилируется в JavaScript, который генерирует HTML. Возможности шаблонизатора описаны на странице проекта.
Клиентская часть работает следующим образом:
При загрузке страницы выполняется файл assets/javascripts/custom.js.coffee, который подгружает остальные классы:
assets/javascripts/custom.js.coffee#= require_self # Подключаем представления #= require_tree ./views # Подключаем шаблоны #= require_tree ../templates # Пространство имен для представлений Offline Telecom HupoApp.Views.Offline = {}
В числе прочих подгрузится и класс представления виджета:
assets/javascripts/views/widgets/offline/videos.js.coffee#= require views/offline/widgets class HupoApp.Views.Offline.Widgets.Videos extends HupoApp.Views.Widgets # код виджета widgetCode: 'offline.videos' # функция отрисовки render: (options) => # вызов метода базового класса super(options) # устанавливаем содержимое блока виджета @$el.html(JST['widgets/videos'](t: @translator, link: @widgetOptions.link)) # показываем виджет @$el.show()
В первой строке этого файла указана зависимость от файла assets/javascripts/views/offline/widgets.js.coffee, определяющем имен HupoApp.Views.Offline.Widgets:
assets/javascripts/views/offline/widgets.js.coffee#= require views/widgets # объявляем пространство имен для виджетов Offline Telecom HupoApp.Views.Offline.Widgets = {}
Виджеты инициализируются в представлениях страниц или других блоков. В нашем случае мы хотим поместить их на главную страницу, следовательно используем представление главной страницы:
assets/javascripts/views/index.js.coffee# главная страница class HupoApp.Views.Index extends Backbone.View # список используемых спецификаций из конфигурации виджета videos: ['cat_gone', 'copter_cat'] initialize: => # инициализируем виджеты @videosWidgets = _.map @videos, (video) => new HupoApp.Views.Offline.Widgets.Videos(video) render: => # очищаем блок виджета @$el.empty() # рендерим виджет @renderVideos() # показываем блок виджета @$el.show() renderVideos: => # для каждого виджета for video in @videosWidgets # добавляем в блок результат рендеринга виджета @$el.append(video.render())
При заходе пользователя на главную страницу приложение создаст новый объект класса представления. При этом вызовется метод initialize, который создаст представления виджетов. Затем при отрисовке страницы приложение вызовет у представления страницы метод render, который вызовет метод renderVideos, также вызывающий метод render для каждого виджета. В свою очередь рендеринг виджета вызывает рендеринг шаблона, который генерирует HTML и добавляет его на страницу.
Шаблон имеет следующий вид:assets/templates/widgets/videos.yml- # заголовок %h1= @t('title') - # видео %iframe{width: 420, height: 315, src: @link, frameborder: 0, allowfullscreen: true}
- В результате на странице появится что-то такое:
Исходные коды примера доступны по ссылке: videos_widget.zip