workarea-product_videos 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +16 -0
  3. data/.eslintrc +27 -0
  4. data/.gitignore +19 -0
  5. data/.rails-rubocop.yml +119 -0
  6. data/.rubocop.yml +7 -0
  7. data/.scss-lint.yml +192 -0
  8. data/CHANGELOG.md +92 -0
  9. data/Gemfile +16 -0
  10. data/README.md +87 -0
  11. data/Rakefile +60 -0
  12. data/app/assets/images/workarea/admin/icons/video.svg +1 -0
  13. data/app/assets/images/workarea/storefront/icons/video_play.svg +1 -0
  14. data/app/assets/javascripts/workarea/storefront/product_videos/modules/vimeo_api.js +81 -0
  15. data/app/assets/javascripts/workarea/storefront/product_videos/modules/youtube_api.js +124 -0
  16. data/app/assets/stylesheets/workarea/storefront/product_videos/components/_product_video.scss +37 -0
  17. data/app/controllers/workarea/admin/catalog_product_videos_controller.rb +52 -0
  18. data/app/controllers/workarea/storefront/products_controller.decorator +19 -0
  19. data/app/models/workarea/catalog/product.decorator +7 -0
  20. data/app/models/workarea/catalog/product_video.rb +32 -0
  21. data/app/services/workarea/video_embed_parser.rb +54 -0
  22. data/app/view_models/workarea/storefront/product_video_view_model.rb +84 -0
  23. data/app/view_models/workarea/storefront/product_view_model.decorator +9 -0
  24. data/app/views/workarea/admin/catalog_product_videos/edit.html.haml +76 -0
  25. data/app/views/workarea/admin/catalog_product_videos/index.html.haml +46 -0
  26. data/app/views/workarea/admin/catalog_product_videos/new.html.haml +57 -0
  27. data/app/views/workarea/admin/catalog_products/_product_videos_card.html.haml +21 -0
  28. data/app/views/workarea/storefront/products/_video_link.html.haml +8 -0
  29. data/app/views/workarea/storefront/products/_video_thumbnail.html.haml +12 -0
  30. data/app/views/workarea/storefront/products/video.html.haml +3 -0
  31. data/bin/rails +20 -0
  32. data/config/initializers/appends.rb +37 -0
  33. data/config/initializers/product_videos.rb +5 -0
  34. data/config/initializers/workarea.rb +3 -0
  35. data/config/locales/en.yml +41 -0
  36. data/config/routes.rb +15 -0
  37. data/lib/workarea/product_videos/engine.rb +8 -0
  38. data/lib/workarea/product_videos/version.rb +5 -0
  39. data/lib/workarea/product_videos.rb +11 -0
  40. data/script/admin_ci +9 -0
  41. data/script/ci +11 -0
  42. data/script/core_ci +9 -0
  43. data/script/plugins_ci +9 -0
  44. data/script/storefront_ci +9 -0
  45. data/test/dummy/Rakefile +6 -0
  46. data/test/dummy/app/assets/config/manifest.js +4 -0
  47. data/test/dummy/app/assets/images/.keep +0 -0
  48. data/test/dummy/app/assets/javascripts/application.js +13 -0
  49. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  50. data/test/dummy/app/controllers/application_controller.rb +3 -0
  51. data/test/dummy/app/controllers/concerns/.keep +0 -0
  52. data/test/dummy/app/helpers/application_helper.rb +2 -0
  53. data/test/dummy/app/jobs/application_job.rb +2 -0
  54. data/test/dummy/app/mailers/application_mailer.rb +4 -0
  55. data/test/dummy/app/models/concerns/.keep +0 -0
  56. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  57. data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
  58. data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
  59. data/test/dummy/bin/bundle +3 -0
  60. data/test/dummy/bin/rails +4 -0
  61. data/test/dummy/bin/rake +4 -0
  62. data/test/dummy/bin/setup +38 -0
  63. data/test/dummy/bin/update +29 -0
  64. data/test/dummy/bin/yarn +11 -0
  65. data/test/dummy/config/application.rb +29 -0
  66. data/test/dummy/config/boot.rb +5 -0
  67. data/test/dummy/config/cable.yml +10 -0
  68. data/test/dummy/config/environment.rb +5 -0
  69. data/test/dummy/config/environments/development.rb +54 -0
  70. data/test/dummy/config/environments/production.rb +91 -0
  71. data/test/dummy/config/environments/test.rb +44 -0
  72. data/test/dummy/config/initializers/application_controller_renderer.rb +8 -0
  73. data/test/dummy/config/initializers/assets.rb +14 -0
  74. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  75. data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
  76. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  77. data/test/dummy/config/initializers/inflections.rb +16 -0
  78. data/test/dummy/config/initializers/mime_types.rb +4 -0
  79. data/test/dummy/config/initializers/new_framework_defaults.rb +23 -0
  80. data/test/dummy/config/initializers/session_store.rb +3 -0
  81. data/test/dummy/config/initializers/workarea.rb +5 -0
  82. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  83. data/test/dummy/config/locales/en.yml +33 -0
  84. data/test/dummy/config/puma.rb +56 -0
  85. data/test/dummy/config/routes.rb +5 -0
  86. data/test/dummy/config/secrets.yml +32 -0
  87. data/test/dummy/config/spring.rb +6 -0
  88. data/test/dummy/config.ru +5 -0
  89. data/test/dummy/db/seeds.rb +2 -0
  90. data/test/dummy/lib/assets/.keep +0 -0
  91. data/test/dummy/log/.keep +0 -0
  92. data/test/dummy/package.json +5 -0
  93. data/test/factories/embed_codes.rb +15 -0
  94. data/test/integration/workarea/admin/product_videos_integration_test.rb +59 -0
  95. data/test/integration/workarea/storefront/product_videos_integration_test.rb +30 -0
  96. data/test/services/workarea/video_embedder_test.rb +27 -0
  97. data/test/system/workarea/admin/product_videos_system_test.rb +58 -0
  98. data/test/system/workarea/storefront/product_videos_system_test.rb +60 -0
  99. data/test/teaspoon_env.rb +6 -0
  100. data/test/test_helper.rb +10 -0
  101. data/test/view_models/workarea/storefront/product_video_view_model_test.rb +46 -0
  102. data/workarea-product_videos.gemspec +19 -0
  103. metadata +157 -0
@@ -0,0 +1,81 @@
1
+ /**
2
+ * @namespace WORKAREA.vimeoApi
3
+ */
4
+ WORKAREA.registerModule('vimeoApi', (function () {
5
+ 'use strict';
6
+
7
+ var getAnalyticsLabel = function(iframe) {
8
+ var iframeSrc = iframe.attr('src').split('?')[0],
9
+ label = iframeSrc;
10
+
11
+ if (iframe.data('title')) {
12
+ label += ' (' + iframe.data('title') + ')';
13
+ } else if (iframe.attr('title')) {
14
+ label += ' (' + iframe.attr('title') + ')';
15
+ }
16
+
17
+ return label;
18
+ },
19
+
20
+ sendEvent = function (id, action) {
21
+ var iframe = $('#' + id),
22
+ label = getAnalyticsLabel(iframe);
23
+
24
+ WORKAREA.analytics.fireCallback(
25
+ 'vimeo',
26
+ {
27
+ 'eventCategory': 'Vimeo',
28
+ 'eventAction': action,
29
+ 'eventLabel': label,
30
+ 'eventValue': undefined
31
+ }
32
+ );
33
+ },
34
+
35
+ muteVideo = function (player) {
36
+ player.setVolume(0);
37
+ },
38
+
39
+ onPlay = function (playerData) {
40
+ sendEvent(playerData.player_id, 'Play Video');
41
+ },
42
+
43
+ onPause = function (playerData) {
44
+ sendEvent(playerData.player_id, 'Paused video');
45
+ },
46
+
47
+ onFinish = function (playerData) {
48
+ sendEvent(playerData.player_id, 'Completed video');
49
+ },
50
+
51
+ setupPlayer = function (index, iframe) {
52
+ var player = new Vimeo.Player(iframe),
53
+ playerData = $(iframe).data('vimeoApi');
54
+
55
+ if (playerData.mute === 'true') {
56
+ muteVideo(player);
57
+ }
58
+
59
+ player.on('play', _.partial(onPlay, playerData));
60
+ player.on('pause', _.partial(onPause, playerData));
61
+ player.on('finish', _.partial(onFinish, playerData));
62
+ },
63
+
64
+ injectSDK = _.once(function($vimeoIframes) {
65
+ $.getScript('https://player.vimeo.com/api/player.js', function() {
66
+ $vimeoIframes.each(setupPlayer);
67
+ });
68
+ }),
69
+
70
+ init = function ($scope) {
71
+ var $vimeoIframes = $('[data-vimeo-api]', $scope);
72
+
73
+ if (_.isEmpty($vimeoIframes)) { return; }
74
+
75
+ injectSDK($vimeoIframes);
76
+ };
77
+
78
+ return {
79
+ init: init
80
+ };
81
+ }()));
@@ -0,0 +1,124 @@
1
+ /**
2
+ * @namespace WORKAREA.youtubeApi
3
+ */
4
+ WORKAREA.registerModule('youtubeApi', (function () {
5
+ 'use strict';
6
+
7
+ var getAnalyticsLabel = function(iframe) {
8
+ var iframeSrc = iframe.attr('src').split('?')[0],
9
+ label = iframeSrc;
10
+
11
+ if (iframe.data('title')) {
12
+ label += ' (' + iframe.data('title') + ')';
13
+ } else if (iframe.attr('title')) {
14
+ label += ' (' + iframe.attr('title') + ')';
15
+ }
16
+
17
+ return label;
18
+ },
19
+
20
+ sendEvent = function (id, action) {
21
+ var iframe = $('#' + id),
22
+ label = getAnalyticsLabel(iframe);
23
+
24
+ WORKAREA.analytics.fireCallback(
25
+ 'youtube',
26
+ {
27
+ 'eventCategory': 'Youtube',
28
+ 'eventAction': action,
29
+ 'eventLabel': label,
30
+ 'eventValue': undefined
31
+ }
32
+ );
33
+ },
34
+
35
+ onPlay = function (playerId) {
36
+ sendEvent(playerId, 'Play Video');
37
+ },
38
+
39
+ onPause = function (playerId) {
40
+ sendEvent(playerId, 'Paused video');
41
+ },
42
+
43
+ onFinish = function (playerId) {
44
+ sendEvent(playerId, 'Completed video');
45
+ },
46
+
47
+ handlePlayerState = function(playerId, state) {
48
+ var stateMap = {
49
+ '-1': 'unstarted',
50
+ '0': 'ended',
51
+ '1': 'playing',
52
+ '2': 'paused',
53
+ '3': 'buffering',
54
+ '5': 'queued'
55
+ },
56
+ currentState = stateMap[state.data];
57
+
58
+ if (currentState === 'playing') {
59
+ onPlay(playerId);
60
+ } else if (currentState === 'paused') {
61
+ onPause(playerId);
62
+ } else if (currentState === 'ended') {
63
+ onFinish(playerId);
64
+ }
65
+ },
66
+
67
+ onPlayerReady = function (playerData, event) {
68
+ var player = event.target;
69
+
70
+ if (playerData.mute === 'true') {
71
+ player.mute();
72
+ }
73
+ },
74
+
75
+ setupPlayer = function (index, iframe) {
76
+ var playerData = $(iframe).data('youtubeApi'),
77
+ playerId = $(iframe).attr('id'),
78
+ player = new YT.Player(playerId, {
79
+ events: {
80
+ 'onReady': _.partial(onPlayerReady, playerData),
81
+ 'onStateChange': _.partial(handlePlayerState, playerId)
82
+ }
83
+ });
84
+
85
+ return player;
86
+ },
87
+
88
+ scriptLoaded = function ($scope) {
89
+ var $youtubeIframes = $('[data-youtube-api]', $scope);
90
+
91
+ $youtubeIframes.each(setupPlayer);
92
+ },
93
+
94
+ injectSDK = function () {
95
+ if ($('[data-youtube-api]').data('youtube-api-loaded')) {
96
+ return;
97
+ } else {
98
+ $.getScript('https://www.youtube.com/player_api');
99
+ }
100
+ },
101
+
102
+ init = function ($scope) {
103
+ var $youtubeIframes = $('[data-youtube-api]', $scope);
104
+
105
+ if (_.isEmpty($youtubeIframes)) { return; }
106
+
107
+ injectSDK();
108
+ };
109
+
110
+ return {
111
+ init: init,
112
+ scriptLoaded: scriptLoaded
113
+ };
114
+ }()));
115
+
116
+ /**
117
+ * onYouTubeIframeAPIReady is called by YouTube API
118
+ * This is executed when the API is ready to go.
119
+ */
120
+ /*eslint no-unused-vars: 0 */
121
+ function onYouTubeIframeAPIReady() {
122
+ $('[data-youtube-api]').data('youtube-api-loaded', true);
123
+ WORKAREA.youtubeApi.scriptLoaded($(document));
124
+ }
@@ -0,0 +1,37 @@
1
+ /*------------------------------------*\
2
+ #PRODUCT-VIDEO
3
+ \*------------------------------------*/
4
+
5
+
6
+ $product-video-padding: 56.25% !default; // 16:9 aspect
7
+ $product-video-width: 80vw !default;
8
+ $product-video-max-width: 1080px !default;
9
+
10
+
11
+ .product-video {
12
+ position: relative;
13
+ margin: 0 auto;
14
+ }
15
+
16
+ .product-video--thumbnail {}
17
+
18
+ .product-video__container {
19
+ position: relative;
20
+ padding-bottom: $product-video-padding;
21
+ width: $product-video-width;
22
+ max-width: $product-video-max-width;
23
+ }
24
+
25
+ .product-video__iframe {
26
+ position: absolute;
27
+ width: 100%;
28
+ height: 100%;
29
+ }
30
+
31
+ .product-video__dialog-link {}
32
+
33
+ .product-video__thumbnail-image {}
34
+
35
+ .product-video__play-icon {
36
+ @include center;
37
+ }
@@ -0,0 +1,52 @@
1
+ module Workarea
2
+ class Admin::CatalogProductVideosController < Admin::ApplicationController
3
+ required_permissions :catalog
4
+ before_action :find_product
5
+
6
+ def index
7
+ @videos = @product.videos
8
+ end
9
+
10
+ def new; end
11
+
12
+ def create
13
+ @video = @product.videos.build(params[:video])
14
+
15
+ if @video.save
16
+ flash[:success] = t("workarea.admin.catalog_product_videos.flash_messages.created")
17
+ redirect_to catalog_product_videos_path(@product)
18
+ else
19
+ render :index, status: :unprocessable_entity
20
+ end
21
+ end
22
+
23
+ def edit
24
+ @video = @product.videos.find(params[:id])
25
+ end
26
+
27
+ def update
28
+ @video = @product.videos.find(params[:id])
29
+
30
+ if @video.update_attributes(params[:video])
31
+ flash[:success] = t("workarea.admin.catalog_product_videos.flash_messages.updated")
32
+ else
33
+ flash[:error] = t("workarea.admin.catalog_product_videos.flash_messages.error")
34
+ end
35
+
36
+ redirect_to catalog_product_videos_path(@product)
37
+ end
38
+
39
+ def destroy
40
+ @product.videos.find(params[:id]).destroy
41
+ flash[:success] = t("workarea.admin.catalog_product_videos.flash_messages.deleted")
42
+ redirect_to catalog_product_videos_path(@product)
43
+ end
44
+
45
+ private
46
+
47
+ def find_product
48
+ model = Catalog::Product.find_by(slug: params[:catalog_product_id])
49
+ @product = Admin::ProductViewModel.wrap(model, view_model_options)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,19 @@
1
+ module Workarea
2
+ decorate Storefront::ProductsController, with: :product_videos do
3
+ def video
4
+ model = Catalog::Product.find_by(id: params[:product_id])
5
+ raise InvalidDisplay unless model.active? || current_user.try(:admin?)
6
+
7
+ @product = Storefront::ProductViewModel.wrap(
8
+ model,
9
+ view_model_options
10
+ )
11
+
12
+ video = @product.videos.detect{ |v| v.id.to_s == params[:video_id] }
13
+ @video = Storefront::ProductVideoViewModel.wrap(
14
+ video,
15
+ view_model_options
16
+ )
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,7 @@
1
+ module Workarea
2
+ decorate Catalog::Product, with: :product_videos do
3
+ decorated do
4
+ embeds_many :videos, class_name: 'Workarea::Catalog::ProductVideo'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,32 @@
1
+ module Workarea
2
+ module Catalog
3
+ class ProductVideo
4
+ include ApplicationDocument
5
+
6
+ field :embed_code, type: String
7
+ field :display_option, type: String, default: "dialog"
8
+ field :embed_id, type: String
9
+ field :url, type: String
10
+ field :host, type: String
11
+ field :aspect_ratio, type: String
12
+ field :thumbnail, type: String
13
+
14
+ embedded_in :product,
15
+ class_name: "Workarea::Catalog::Product",
16
+ inverse_of: :videos,
17
+ touch: true
18
+
19
+ validates :embed_code, presence: true
20
+ validates :display_option, presence: true
21
+ validates :embed_id, presence: true
22
+ validates :url, presence: true
23
+ validates :host, presence: true
24
+ validates :aspect_ratio, presence: true
25
+ before_validation :process_embed_code
26
+
27
+ def process_embed_code
28
+ VideoEmbedParser.new(self.embed_code).video_params.each { |key, value| self[key] = value }
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,54 @@
1
+ module Workarea
2
+ class VideoEmbedParser
3
+ def initialize(embed_code, options = {})
4
+ @parsed_embed_code = Nokogiri::HTML.fragment(embed_code).children.first
5
+ @options = options
6
+ end
7
+
8
+ def video_params
9
+ {
10
+ embed_id: embed_id,
11
+ url: url,
12
+ host: uri.host,
13
+ aspect_ratio: aspect_ratio
14
+ }
15
+ end
16
+
17
+ private
18
+
19
+ def vimeo?
20
+ /vimeo/.match?(host)
21
+ end
22
+
23
+ def youtube?
24
+ /youtube/.match(host)
25
+ end
26
+
27
+ def url
28
+ @url ||= @parsed_embed_code.attribute("src").value
29
+ end
30
+
31
+ def uri
32
+ URI.parse(url)
33
+ end
34
+
35
+ def host
36
+ uri.host
37
+ end
38
+
39
+ def embed_id
40
+ id = uri.path.split("/").last
41
+ if youtube?
42
+ id = "youtube-#{id}"
43
+ end
44
+ id
45
+ end
46
+
47
+ def aspect_ratio
48
+ height = @parsed_embed_code.attribute("height").value
49
+ width = @parsed_embed_code.attribute("width").value
50
+ ratio = (height.to_f / width.to_f) * 100
51
+ ratio.round(2)
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,84 @@
1
+ module Workarea
2
+ module Storefront
3
+ class ProductVideoViewModel < ApplicationViewModel
4
+ def iframe_attrs
5
+ attrs = {
6
+ id: model.embed_id,
7
+ frameborder: "0",
8
+ allowfullscreen: "",
9
+ container_style: "padding-bottom: #{model.aspect_ratio}%"
10
+ }
11
+
12
+ if vimeo?
13
+ attrs.merge(vimeo_attrs)
14
+ elsif youtube?
15
+ attrs.merge(youtube_attrs)
16
+ end
17
+ end
18
+
19
+ def thumbnail
20
+ return unless model.thumbnail.present?
21
+ @thumbnail ||= Workarea::Content::Asset.find_or_initialize_by(id: model.thumbnail)
22
+ end
23
+
24
+ private
25
+
26
+ def vimeo?
27
+ /vimeo/.match?(host)
28
+ end
29
+
30
+ def youtube?
31
+ /youtube/.match?(host)
32
+ end
33
+
34
+ def vimeo_attrs
35
+ {
36
+ src: "#{model.url}?#{vimeo_url_params}",
37
+ webkitallowfullscreen: "",
38
+ mozallowfullscreen: "",
39
+ data: {
40
+ vimeo_api: {
41
+ player_id: model.embed_id,
42
+ mute: @options[:mute]
43
+ }.to_json
44
+ }
45
+ }
46
+ end
47
+
48
+ def youtube_attrs
49
+ {
50
+ src: "#{url}?#{youtube_url_params}",
51
+ data: {
52
+ youtube_api: {
53
+ mute: @options[:mute]
54
+ }.to_json
55
+ }
56
+ }
57
+ end
58
+
59
+ def uri
60
+ URI.parse(model.url)
61
+ end
62
+
63
+ def vimeo_url_params
64
+ parsed_query = Rack::Utils.parse_query(uri.query)
65
+ parsed_query["api"] = 1
66
+ parsed_query["autoplay"] = @options[:autoplay]
67
+ parsed_query["loop"] = @options[:loop_playback]
68
+ parsed_query["player_id"] = model.embed_id
69
+
70
+ URI.encode_www_form(parsed_query)
71
+ end
72
+
73
+ def youtube_url_params
74
+ parsed_query = Rack::Utils.parse_query(uri.query)
75
+ parsed_query["enablejsapi"] = 1
76
+ parsed_query["autoplay"] = @options[:autoplay] ? 1 : 0
77
+ parsed_query["loop"] = @options[:loop_playback] ? 1 : 0
78
+ parsed_query["videoId"] = model.embed_id
79
+
80
+ URI.encode_www_form(parsed_query)
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,9 @@
1
+ module Workarea
2
+ decorate Storefront::ProductViewModel, with: :product_videos do
3
+ def videos
4
+ @videos ||= Storefront::ProductVideoViewModel.wrap(
5
+ model.videos
6
+ )
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,76 @@
1
+ - @page_title = t('workarea.admin.catalog_product_videos.edit.title', product: @product.name)
2
+
3
+ .product-images.view
4
+ .view__header
5
+ .grid.grid--middle
6
+ .grid__cell.grid__cell--25
7
+ = render 'workarea/admin/releases/select'
8
+ .grid__cell.grid__cell--50
9
+ .view__heading
10
+ = link_to_index_for(@product)
11
+ %h1= link_to @product.name, url_for(@product)
12
+ .grid__cell.grid__cell--25
13
+ = render_aux_navigation_for(@product)
14
+
15
+ .view__container
16
+ = render_cards_for(@product, :videos)
17
+
18
+ .section
19
+ %h2.view__heading= t('workarea.admin.catalog_product_videos.edit.heading')
20
+
21
+ %h3= t('workarea.admin.catalog_product_videos.edit.extracted_data')
22
+ %table
23
+ %thead
24
+ %tr
25
+ %th= t('workarea.admin.catalog_product_videos.fields.video_id')
26
+ %th= t('workarea.admin.catalog_product_videos.fields.host')
27
+ %th= t('workarea.admin.catalog_product_videos.fields.url')
28
+ %th= t('workarea.admin.catalog_product_videos.fields.aspect_ratio')
29
+ %tbody
30
+ %tr
31
+ %td= @video.embed_id
32
+ %td= @video.host
33
+ %td= link_to @video.url, @video.url, target: '_blank', rel: 'noopener'
34
+ %td= @video.aspect_ratio
35
+ .grid
36
+ .grid__cell.grid__cell--33
37
+ = form_tag catalog_product_video_path(@product, @video), method: :patch, class: 'product-videos__action-group-item' do
38
+ .property.property--required
39
+ = label_tag 'video_embed_code', class: 'property__name' do
40
+ %span.property__text= t('workarea.admin.catalog_product_videos.fields.embed_code')
41
+ = text_area_tag 'video[embed_code]', @video.embed_code, class: 'text-box text-box--i18n text-box--multi-line', required: true
42
+ .property.property--required
43
+ = label_tag 'video_display_option', class: 'property__name' do
44
+ %span.property__text= t('workarea.admin.catalog_product_videos.fields.display_type')
45
+ = link_to '#display-type-info', data: { tooltip: '' } do
46
+ = inline_svg('workarea/admin/icons/help.svg', class: 'svg-icon svg-icon--small svg-icon--blue', title: t('workarea.admin.catalog_product_videos.fields.display_type'))
47
+ #display-type-info.tooltip-content
48
+ %p= t('workarea.admin.catalog_product_videos.fields.display_type_info_html')
49
+ = select_tag 'video[display_option]', options_for_select(Workarea.config.product_videos[:display_options], @video.display_option), id: 'video_display_option', required: true
50
+
51
+ .property
52
+ = label_tag 'video_thumbnail', class: 'property__name' do
53
+ %span.property__text= t('workarea.admin.catalog_product_videos.fields.thumbnail')
54
+
55
+ .asset-picker-field{ data: { asset_picker_field: '' } }
56
+ .asset-picker-field__cell
57
+ = hidden_field_tag 'video[thumbnail]', @video.thumbnail, id: 'video_thumbnail', class: 'text-box text-box--i18n'
58
+
59
+ %span{ data: { asset_name: true } }
60
+ - asset = Workarea::Content::Asset.find_or_initialize_by(id: @video.thumbnail)
61
+ = asset.name.presence || t('workarea.admin.content_blocks.asset.name_missing')
62
+
63
+ .asset-picker-field__cell= link_to t('workarea.admin.content_blocks.asset.select_an_asset'), insert_content_assets_path(file_type: 'image'), class: 'text-button', data: { asset_picker_field_open: '', turbolinks: false }
64
+ - if asset.name.present?
65
+ .asset-picker-field__cell= button_tag t('workarea.admin.content_blocks.asset.clear_asset'), type: 'button', value: 'clear_asset', id: nil, class: 'text-button text-button--destroy', data: { asset_picker_field_clear: '' }
66
+
67
+
68
+ .workflow-bar
69
+ .grid.grid--right.grid--middle
70
+ .grid__cell.grid__cell--20
71
+ = link_to t('workarea.admin.form.cancel'), url_for(@product), class: 'workflow-bar__button workflow-bar__button--delete'
72
+
73
+ .grid__cell.grid__cell--80
74
+ .grid.grid--auto.grid--right.grid--middle
75
+ .grid__cell
76
+ = button_tag t('workarea.admin.catalog_product_videos.edit.update_button'), value: 'edit_video', class: 'workflow-bar__button workflow-bar__button--update'
@@ -0,0 +1,46 @@
1
+ - @page_title = t('workarea.admin.catalog_product_videos.index.title', product: @product.name)
2
+
3
+ .product-images.view
4
+ .view__header
5
+ .grid.grid--middle
6
+ .grid__cell.grid__cell--25
7
+ = render 'workarea/admin/releases/select'
8
+ .grid__cell.grid__cell--50
9
+ .view__heading
10
+ = link_to_index_for(@product)
11
+ %h1= link_to @product.name, url_for(@product)
12
+ .grid__cell.grid__cell--25
13
+ = render_aux_navigation_for(@product)
14
+
15
+ .view__container
16
+ = render_cards_for(@product, :videos)
17
+
18
+ .section
19
+ %h2.view__heading= t('workarea.admin.catalog_product_videos.index.heading')
20
+ %table.index-table
21
+ %thead
22
+ %tr
23
+ %th= t('workarea.admin.catalog_product_videos.fields.video_id')
24
+ %th= t('workarea.admin.catalog_product_videos.fields.host')
25
+ %th= t('workarea.admin.catalog_product_videos.fields.display_type')
26
+ %th
27
+ %tbody
28
+ - @product.videos.each do |video|
29
+ %tr.index-table__row
30
+ %td= link_to video[:embed_id], edit_catalog_product_video_path(@product, video)
31
+ %td= video[:host]
32
+ %td= video.display_option
33
+ %td
34
+ = form_tag catalog_product_video_path(@product, video), method: 'delete', class: 'text-button text-button--destroy' do
35
+ = button_tag value: 'delete_video', class: 'text-button text-button--destroy' do
36
+ = inline_svg('workarea/admin/icons/delete.svg', class: 'text-button__icon', title: t('workarea.admin.actions.delete'))
37
+
38
+ .workflow-bar
39
+ .grid.grid--right.grid--middle
40
+ .grid__cell.grid__cell--20
41
+ = link_to t('workarea.admin.form.cancel'), url_for(@product), class: 'workflow-bar__button workflow-bar__button--delete'
42
+
43
+ .grid__cell.grid__cell--80
44
+ .grid.grid--auto.grid--right.grid--middle
45
+ .grid__cell
46
+ = link_to t('workarea.admin.catalog_product_videos.index.add_new'), new_catalog_product_video_path(@product), class: 'workflow-bar__button workflow-bar__button--create'
@@ -0,0 +1,57 @@
1
+ - @page_title = t('workarea.admin.catalog_product_videos.new.title', product: @product.name)
2
+
3
+ .product-images.view
4
+ .view__header
5
+ .grid.grid--middle
6
+ .grid__cell.grid__cell--25
7
+ = render 'workarea/admin/releases/select'
8
+ .grid__cell.grid__cell--50
9
+ .view__heading
10
+ = link_to_index_for(@product)
11
+ %h1= link_to @product.name, url_for(@product)
12
+ .grid__cell.grid__cell--25
13
+ = render_aux_navigation_for(@product)
14
+
15
+ .view__container
16
+ = render_cards_for(@product, :videos)
17
+
18
+ .section
19
+ %h2.view__heading= t('workarea.admin.catalog_product_videos.new.heading')
20
+ .grid
21
+ .grid__cell.grid__cell--33
22
+ = form_tag catalog_product_videos_path(@product), method: 'post', multipart: true do
23
+ .property.property--required
24
+ = label_tag 'video_embed_code', class: 'property__name' do
25
+ %span.property__text= t('workarea.admin.catalog_product_videos.fields.embed_code')
26
+ = text_area_tag 'video[embed_code]', nil, class: 'text-box text-box--i18n text-box--multi-line', required: true
27
+ .property.property--required
28
+ = label_tag 'video_display_option', class: 'property__name' do
29
+ %span.property__text= t('workarea.admin.catalog_product_videos.fields.display_type')
30
+ = link_to '#display-type-info', data: { tooltip: '' } do
31
+ = inline_svg('workarea/admin/icons/help.svg', class: 'svg-icon svg-icon--small svg-icon--blue', title: t('workarea.admin.catalog_product_videos.fields.display_type'))
32
+ #display-type-info.tooltip-content
33
+ %p= t('workarea.admin.catalog_product_videos.fields.display_type_info_html')
34
+ .value= select_tag 'video[display_option]', options_for_select(Workarea.config.product_videos[:display_options]), id: 'video_display_option', required: true
35
+
36
+ .property
37
+ = label_tag 'video_thumbnail', class: 'property__name' do
38
+ %span.property__text= t('workarea.admin.catalog_product_videos.fields.thumbnail')
39
+
40
+ .asset-picker-field{ data: { asset_picker_field: '' } }
41
+ .asset-picker-field__cell
42
+ = hidden_field_tag 'video[thumbnail]', nil, id: 'video_thumbnail', class: 'text-box text-box--i18n'
43
+
44
+ %span{ data: { asset_name: true } }
45
+ = t('workarea.admin.content_blocks.asset.name_missing')
46
+
47
+ .asset-picker-field__cell= link_to t('workarea.admin.content_blocks.asset.select_an_asset'), insert_content_assets_path(file_type: 'image'), class: 'text-button', data: { asset_picker_field_open: '', turbolinks: false }
48
+
49
+ .workflow-bar
50
+ .grid.grid--right.grid--middle
51
+ .grid__cell.grid__cell--20
52
+ = link_to t('workarea.admin.form.cancel'), url_for(@product), class: 'workflow-bar__button workflow-bar__button--delete'
53
+
54
+ .grid__cell.grid__cell--80
55
+ .grid.grid--auto.grid--right.grid--middle
56
+ .grid__cell
57
+ = button_tag t('workarea.admin.catalog_product_videos.new.button'), value: 'create_video', class: 'workflow-bar__button workflow-bar__button--create'