workarea-product_videos 1.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.editorconfig +16 -0
- data/.eslintrc +27 -0
- data/.gitignore +19 -0
- data/.rails-rubocop.yml +119 -0
- data/.rubocop.yml +7 -0
- data/.scss-lint.yml +192 -0
- data/CHANGELOG.md +92 -0
- data/Gemfile +16 -0
- data/README.md +87 -0
- data/Rakefile +60 -0
- data/app/assets/images/workarea/admin/icons/video.svg +1 -0
- data/app/assets/images/workarea/storefront/icons/video_play.svg +1 -0
- data/app/assets/javascripts/workarea/storefront/product_videos/modules/vimeo_api.js +81 -0
- data/app/assets/javascripts/workarea/storefront/product_videos/modules/youtube_api.js +124 -0
- data/app/assets/stylesheets/workarea/storefront/product_videos/components/_product_video.scss +37 -0
- data/app/controllers/workarea/admin/catalog_product_videos_controller.rb +52 -0
- data/app/controllers/workarea/storefront/products_controller.decorator +19 -0
- data/app/models/workarea/catalog/product.decorator +7 -0
- data/app/models/workarea/catalog/product_video.rb +32 -0
- data/app/services/workarea/video_embed_parser.rb +54 -0
- data/app/view_models/workarea/storefront/product_video_view_model.rb +84 -0
- data/app/view_models/workarea/storefront/product_view_model.decorator +9 -0
- data/app/views/workarea/admin/catalog_product_videos/edit.html.haml +76 -0
- data/app/views/workarea/admin/catalog_product_videos/index.html.haml +46 -0
- data/app/views/workarea/admin/catalog_product_videos/new.html.haml +57 -0
- data/app/views/workarea/admin/catalog_products/_product_videos_card.html.haml +21 -0
- data/app/views/workarea/storefront/products/_video_link.html.haml +8 -0
- data/app/views/workarea/storefront/products/_video_thumbnail.html.haml +12 -0
- data/app/views/workarea/storefront/products/video.html.haml +3 -0
- data/bin/rails +20 -0
- data/config/initializers/appends.rb +37 -0
- data/config/initializers/product_videos.rb +5 -0
- data/config/initializers/workarea.rb +3 -0
- data/config/locales/en.yml +41 -0
- data/config/routes.rb +15 -0
- data/lib/workarea/product_videos/engine.rb +8 -0
- data/lib/workarea/product_videos/version.rb +5 -0
- data/lib/workarea/product_videos.rb +11 -0
- data/script/admin_ci +9 -0
- data/script/ci +11 -0
- data/script/core_ci +9 -0
- data/script/plugins_ci +9 -0
- data/script/storefront_ci +9 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/config/manifest.js +4 -0
- data/test/dummy/app/assets/images/.keep +0 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/controllers/concerns/.keep +0 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/jobs/application_job.rb +2 -0
- data/test/dummy/app/mailers/application_mailer.rb +4 -0
- data/test/dummy/app/models/concerns/.keep +0 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
- data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +38 -0
- data/test/dummy/bin/update +29 -0
- data/test/dummy/bin/yarn +11 -0
- data/test/dummy/config/application.rb +29 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/cable.yml +10 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +54 -0
- data/test/dummy/config/environments/production.rb +91 -0
- data/test/dummy/config/environments/test.rb +44 -0
- data/test/dummy/config/initializers/application_controller_renderer.rb +8 -0
- data/test/dummy/config/initializers/assets.rb +14 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/new_framework_defaults.rb +23 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/workarea.rb +5 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +33 -0
- data/test/dummy/config/puma.rb +56 -0
- data/test/dummy/config/routes.rb +5 -0
- data/test/dummy/config/secrets.yml +32 -0
- data/test/dummy/config/spring.rb +6 -0
- data/test/dummy/config.ru +5 -0
- data/test/dummy/db/seeds.rb +2 -0
- data/test/dummy/lib/assets/.keep +0 -0
- data/test/dummy/log/.keep +0 -0
- data/test/dummy/package.json +5 -0
- data/test/factories/embed_codes.rb +15 -0
- data/test/integration/workarea/admin/product_videos_integration_test.rb +59 -0
- data/test/integration/workarea/storefront/product_videos_integration_test.rb +30 -0
- data/test/services/workarea/video_embedder_test.rb +27 -0
- data/test/system/workarea/admin/product_videos_system_test.rb +58 -0
- data/test/system/workarea/storefront/product_videos_system_test.rb +60 -0
- data/test/teaspoon_env.rb +6 -0
- data/test/test_helper.rb +10 -0
- data/test/view_models/workarea/storefront/product_video_view_model_test.rb +46 -0
- data/workarea-product_videos.gemspec +19 -0
- 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,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,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'
|