Page tree
Skip to end of metadata
Go to start of metadata

Задача

В качестве простого примера рассмотрим виджет для компании Offline Telecom, позволяющий встраивать в личный кабинет видео с YouTube.

Виджет добавляет на страницу локалезависимый заголовок и фрейм с видеоплеером. Ссылка на видео задаётся в конфигурационном файле.

Файловая структура

Пусть код компании – offline (указан в /etc/hydra/hupo_configuration.yml в ключе client). Виджет назовем videos.

Создадим директорию /etc/hydra/hupo/offline, в которой будем проводить разработку. Файловое дерево этой директории будет выглядеть следующим образом:

 Файловая структура
├── assets                                     Клиентские файлы
│   ├── javascripts                            Скрипты
│   │   ├── custom.js.coffee                   Скрипт инициализации
│   │   └── views                              Представления
│   │       ├── index.js.coffee                Представление главной страницы
│   │       ├── offline                        Пользовательские представления Offline Telecom
│   │       │   └── widgets.js.coffee          Скрипт определения пространства имен для виджетов Offline Telecom
│   │       └── widgets                        Представления виджетов
│   │           └── offline                    Представления виджетов Offline Telecom
│   │               └── videos.js.coffee       Представление виджета видео
│   └── templates                              Шаблоны	
│       └── widgets                            Шаблоны виджетов
│           └── videos.jst.hamlc               Шаблон виджета видео
├── engine                                     Серверные файлы
│   ├── app                                    Приложение
│   │   └── widgets                            Виджеты
│   │       └── offline                        Виджеты Offline Telecom
│   │           └── videos_widget.rb           Виджет видео
│   ├── hupo-vendor-engine.gemspec             Спецификация гема
│   └── lib                                    Служебные файлы
│       ├── hupo_vendor_engine
│       │   └── engine.rb
│       └── hupo_vendor_engine.rb
├── locales                                    Переводы
│   └── ru.widgets.yml                         Переводы виджетов
└── widgets                                    Конфигурация виджетов
    └── videos.yml                             Конфигурация виджета видео

Служебные файлы

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

engine/hupo-vendor-engine.gemspec
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
engine/lin/hupo_vendor_engine.rb
require 'hupo_vendor_engine/engine'
engine/lib/hupo_vendor_engine/engine.rb
module HupoVendor
  class Engine < Rails::Engine
    isolate_namespace HupoVendor
  end
end

Серверная часть

Виджет видео не взаимодействует с сервером, поэтому на сервере достаточно лишь объявить пустой класс виджета:

engine/app/widgets/offline/videos_widget.rb
module Offline
  class VideosWidget < HupoWidget::Base
  end
end

Конфигурация и переводы

Прежде, чем переходить к программированию клиентской части, удобно определить настройки:

widgets/videos.yml
offline:
  videos:
    # спецификации для виджета с кодом offline.videos
    cat_gone:
      # настройки спецификации
      link: "//www.youtube.com/embed/WxGS-2M6_5I"
    # другая спецификация
    copter_cat:
      link: "//www.youtube.com/embed/b6c5wLTaQi0"

Переводы имеют схожую структуру:

locales/ru.widgets.yml
ru:
  offline:
    videos:
      cat_gone:
        title: Кот ушел
      copter_cat:
        title: Кот-вертолет

Клиентская часть

Скрипты клиентской части программируются на языке CoffeeScript, который транслируется в JavaScript на этапе запуска приложения. Приложение использует фреймворк Backbone.js. В этом примере используется только та часть, которая касается представлений.

Шаблоны задаются на языке HAML с возможностью использования CoffeeScript. Шаблон также компилируется в JavaScript, который генерирует HTML. Возможности шаблонизатора описаны на странице проекта.

Клиентская часть работает следующим образом:

  1. При загрузке страницы выполняется файл assets/javascripts/custom.js.coffee, который подгружает остальные классы:

    assets/javascripts/custom.js.coffee
    #= require_self
    # Подключаем представления
    #= require_tree ./views
    # Подключаем шаблоны
    #= require_tree ../templates
    # Пространство имен для представлений Offline Telecom
    HupoApp.Views.Offline = {}
  2. В числе прочих подгрузится и класс представления виджета:

    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 = {}	
  3. Виджеты инициализируются в представлениях страниц или других блоков. В нашем случае мы хотим поместить их на главную страницу, следовательно используем представление главной страницы:

    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())
    
  4. При заходе пользователя на главную страницу приложение создаст новый объект класса представления. При этом вызовется метод initialize, который создаст представления виджетов. Затем при отрисовке страницы приложение вызовет у представления страницы метод render, который вызовет метод renderVideos, также вызывающий метод render для каждого виджета. В свою очередь рендеринг виджета вызывает рендеринг шаблона, который генерирует HTML и добавляет его на страницу.
    Шаблон имеет следующий вид:

    assets/templates/widgets/videos.yml
    - # заголовок
    %h1= @t('title')
    - # видео
    %iframe{width: 420, height: 315, src: @link, frameborder: 0, allowfullscreen: true}
    
    
  5. В результате на странице появится что-то такое:


Исходные коды примера доступны по ссылке: videos_widget.zip