j1-template 2024.3.15 → 2024.3.16

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/assets/data/amplitude.html +7 -7
  3. data/assets/data/panel.html +4 -3
  4. data/assets/theme/j1/adapter/js/amplitude.js +100 -81
  5. data/assets/theme/j1/adapter/js/masonry.js +2 -2
  6. data/assets/theme/j1/adapter/js/videojs.js +212 -0
  7. data/assets/theme/j1/core/css/themes/unolight/bootstrap.css +7 -4
  8. data/assets/theme/j1/core/css/themes/unolight/bootstrap.css.map +1 -1
  9. data/assets/theme/j1/core/css/themes/unolight/bootstrap.min.css +1 -1
  10. data/assets/theme/j1/core/css/themes/unolight/bootstrap.min.css.map +1 -1
  11. data/assets/theme/j1/core/js/template.js +4 -0
  12. data/assets/theme/j1/core/js/template.min.js +2 -2
  13. data/assets/theme/j1/core/js/template.min.js.map +1 -1
  14. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/amplitude.css +81 -1
  15. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/amplitude.min.css +1 -1
  16. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/player/compact.css +3 -2
  17. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/player/compact.min.css +1 -1
  18. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/player/large.css +19 -4
  19. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/player/large.min.css +1 -1
  20. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/artist.svg +78 -0
  21. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/mute.svg +52 -20
  22. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/next.svg +20 -39
  23. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/now-playing.svg +24 -38
  24. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/playlist-hide.svg +85 -0
  25. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/playlist-music.svg +85 -0
  26. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/playlist-show.svg +85 -0
  27. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/playlist.svg +85 -0
  28. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/previous.svg +18 -37
  29. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/skip-backward.svg +33 -30
  30. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/skip-forward.svg +33 -29
  31. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/small/next.svg +55 -14
  32. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/small/previous.svg +56 -14
  33. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/volume.svg +38 -21
  34. data/assets/theme/j1/modules/amplitudejs/js/amplitude.map +20 -20
  35. data/assets/theme/j1/modules/amplitudejs/js/tech/youtube_example.js +211 -0
  36. data/assets/theme/j1/modules/lightGallery/js/plugins/lg-video.js +206 -122
  37. data/assets/theme/j1/modules/videojs/assets/icons/custom-icons/next.svg +82 -0
  38. data/assets/theme/j1/modules/videojs/css/font/README.md +151 -0
  39. data/assets/theme/j1/modules/videojs/css/font/VideoJS.svg +150 -0
  40. data/assets/theme/j1/modules/videojs/css/font/video-js-cdn.css +2012 -0
  41. data/assets/theme/j1/modules/videojs/css/plugins/controls/skipbuttons.0.css +32 -0
  42. data/assets/theme/j1/modules/videojs/css/plugins/controls/skipbuttons.1.css +31 -0
  43. data/assets/theme/j1/modules/videojs/css/plugins/controls/skipbuttons.css +31 -0
  44. data/assets/theme/j1/modules/videojs/css/plugins/controls/skipbuttons.min.css +21 -0
  45. data/assets/theme/j1/modules/videojs/css/themes/uno.css +14 -3
  46. data/assets/theme/j1/modules/videojs/css/themes/uno.min.css +1 -1
  47. data/assets/theme/j1/modules/videojs/css/videojs.css +1 -0
  48. data/assets/theme/j1/modules/videojs/js/plugins/controls/autocaption/LICENSE +13 -0
  49. data/assets/theme/j1/modules/videojs/js/plugins/controls/autocaption/README.md +75 -0
  50. data/assets/theme/j1/modules/videojs/js/plugins/controls/autocaption/autocaption.js +149 -0
  51. data/assets/theme/j1/modules/videojs/js/plugins/controls/autocaption/autocaption.min.js +21 -0
  52. data/assets/theme/j1/modules/videojs/js/plugins/controls/hotkeys/README.md +76 -30
  53. data/assets/theme/j1/modules/videojs/js/plugins/controls/hotkeys/hotkeys.js +64 -53
  54. data/assets/theme/j1/modules/videojs/js/plugins/controls/hotkeys/hotkeys.min.js +1 -1
  55. data/assets/theme/j1/modules/videojs/js/plugins/controls/skipbuttons/README.md +133 -0
  56. data/assets/theme/j1/modules/videojs/js/plugins/controls/skipbuttons/skipbuttons.js +137 -0
  57. data/assets/theme/j1/modules/videojs/js/plugins/controls/skipbuttons/skipbuttons.min.js +21 -0
  58. data/assets/theme/j1/modules/videojs/js/plugins/controls/zoom/zoom.js +15 -12
  59. data/assets/theme/j1/modules/videojs/js/plugins/players/yt/youtube.js +43 -16
  60. data/lib/j1/patches/rubygems/eventmachine-1.2.7-x64-mingw32/lib/3.3/fastfilereaderext.so +0 -0
  61. data/lib/j1/patches/rubygems/eventmachine-1.2.7-x64-mingw32/lib/3.3/rubyeventmachine.so +0 -0
  62. data/lib/j1/patches/rubygems/eventmachine-1.2.7-x64-mingw32/lib/3.4/fastfilereaderext.so +0 -0
  63. data/lib/j1/patches/rubygems/eventmachine-1.2.7-x64-mingw32/lib/3.4/rubyeventmachine.so +0 -0
  64. data/lib/j1/version.rb +1 -1
  65. data/lib/j1_app/j1_auth_manager/config.rb +0 -4
  66. data/lib/starter_web/Gemfile +45 -22
  67. data/lib/starter_web/README.md +5 -5
  68. data/lib/starter_web/_config.yml +4 -6
  69. data/lib/starter_web/_data/modules/amplitude.yml +9 -399
  70. data/lib/starter_web/_data/modules/defaults/gallery.yml +42 -0
  71. data/lib/starter_web/_data/modules/defaults/videojs.yml +107 -0
  72. data/lib/starter_web/_data/modules/gallery.yml +30 -14
  73. data/lib/starter_web/_data/modules/masonry.yml +15 -0
  74. data/lib/starter_web/_data/modules/videojs.yml +57 -0
  75. data/lib/starter_web/_data/resources.yml +9 -27
  76. data/lib/starter_web/_data/templates/feed.xml +1 -1
  77. data/lib/starter_web/_includes/tables/jekyll_variables.asciidoc +1 -0
  78. data/lib/starter_web/_plugins/asciidoctor/dailymotion-block.rb +4 -1
  79. data/lib/starter_web/_plugins/asciidoctor/videojs-block.rb +145 -24
  80. data/lib/starter_web/_plugins/asciidoctor/vimeo-block.rb +4 -1
  81. data/lib/starter_web/_plugins/asciidoctor/wistia-block.rb +313 -0
  82. data/lib/starter_web/_plugins/asciidoctor/youtube-block.rb +192 -17
  83. data/lib/starter_web/_plugins/index/lunr.rb +1 -1
  84. data/lib/starter_web/package.json +1 -1
  85. data/lib/starter_web/pages/public/amplitude_yt_tester.adoc +20 -7
  86. data/lib/starter_web/pages/public/manuals/integrations/amplitudejs/amplitudejs-api.adoc +1 -1
  87. data/lib/starter_web/pages/public/manuals/integrations/videojs/youtube-api.adoc +1638 -0
  88. data/lib/starter_web/pages/public/tools/previewer/preview_bootstrap_theme.adoc +5 -6
  89. data/lib/starter_web/pages/public/tools/previewer/preview_videojs.adoc +203 -0
  90. data/lib/starter_web/pages/{tour → public/tour}/play_audio.adoc +3 -10
  91. data/lib/starter_web/pages/{tour → public/tour}/play_video.adoc +49 -40
  92. metadata +61 -41
  93. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/_pause.svg +0 -19
  94. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/_play.svg +0 -18
  95. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/show-playlist.svg +0 -15
  96. data/assets/theme/j1/modules/jqueryScrollbar/LICENSE +0 -20
  97. data/assets/theme/j1/modules/jqueryScrollbar/README.md +0 -28
  98. data/assets/theme/j1/modules/jqueryScrollbar/css/scrollbar.css +0 -939
  99. data/assets/theme/j1/modules/jqueryScrollbar/css/scrollbar.min.css +0 -20
  100. data/assets/theme/j1/modules/jqueryScrollbar/js/scrollbar.js +0 -851
  101. data/assets/theme/j1/modules/jqueryScrollbar/js/scrollbar.min.js +0 -36
  102. data/assets/theme/j1/modules/jqueryScrollbar/sass/scrollbar.scss +0 -806
  103. data/assets/theme/j1/modules/lightGallery/js/plugins/lg-video.0.js +0 -794
  104. /data/lib/starter_web/pages/{tour → public/tour}/_includes/attributes.asciidoc +0 -0
  105. /data/lib/starter_web/pages/{tour → public/tour}/_includes/documents/100_gistblock.asciidoc +0 -0
  106. /data/lib/starter_web/pages/{tour → public/tour}/_includes/documents/410_bottom_info.asciidoc +0 -0
  107. /data/lib/starter_web/pages/{tour → public/tour}/_includes/documents/410_bottom_left_warning.asciidoc +0 -0
  108. /data/lib/starter_web/pages/{tour → public/tour}/_includes/documents/410_bottom_right_danger.asciidoc +0 -0
  109. /data/lib/starter_web/pages/{tour → public/tour}/_includes/documents/410_central_success.asciidoc +0 -0
  110. /data/lib/starter_web/pages/{tour → public/tour}/_includes/documents/410_full_height_left_info.asciidoc +0 -0
  111. /data/lib/starter_web/pages/{tour → public/tour}/_includes/documents/410_full_height_right_success.asciidoc +0 -0
  112. /data/lib/starter_web/pages/{tour → public/tour}/_includes/documents/410_table_bs_modal_examples.asciidoc +0 -0
  113. /data/lib/starter_web/pages/{tour → public/tour}/_includes/documents/410_top_info.asciidoc +0 -0
  114. /data/lib/starter_web/pages/{tour → public/tour}/_includes/documents/410_top_left_info.asciidoc +0 -0
  115. /data/lib/starter_web/pages/{tour → public/tour}/_includes/documents/410_top_right_success.asciidoc +0 -0
  116. /data/lib/starter_web/pages/{tour → public/tour}/_includes/documents/419_advanced_modals_demo.asciidoc +0 -0
  117. /data/lib/starter_web/pages/{tour → public/tour}/_includes/documents/tables/bs_modal_examples.asciidoc +0 -0
  118. /data/lib/starter_web/pages/{tour → public/tour}/_includes/documents/themes_bootstrap.asciidoc +0 -0
  119. /data/lib/starter_web/pages/{tour → public/tour}/_includes/documents/themes_rouge.asciidoc +0 -0
  120. /data/lib/starter_web/pages/{tour → public/tour}/asciidoc_extensions.adoc +0 -0
  121. /data/lib/starter_web/pages/{tour → public/tour}/bootstrap_themes.adoc +0 -0
  122. /data/lib/starter_web/pages/{tour → public/tour}/highlghter_rouge.adoc +0 -0
  123. /data/lib/starter_web/pages/{tour → public/tour}/icon_fonts.adoc +0 -0
  124. /data/lib/starter_web/pages/{tour → public/tour}/modal_extentions.adoc +0 -0
  125. /data/lib/starter_web/pages/{tour → public/tour}/present_images.adoc +0 -0
  126. /data/lib/starter_web/pages/{tour → public/tour}/quicksearch.adoc +0 -0
  127. /data/lib/starter_web/pages/{tour → public/tour}/responsive_tables.adoc +0 -0
  128. /data/lib/starter_web/pages/{tour → public/tour}/typography.adoc +0 -0
@@ -0,0 +1,313 @@
1
+ # ------------------------------------------------------------------------------
2
+ # ~/_plugins/asciidoctor-extensions/wistia-block.rb
3
+ # Asciidoctor extension for Vimeo Video
4
+ #
5
+ # Product/Info:
6
+ # https://jekyll.one
7
+ #
8
+ # Copyright (C) 2023, 2024 Juergen Adams
9
+ #
10
+ # J1 Template is licensed under the MIT License.
11
+ # See: https://github.com/jekyll-one-org/j1-template/blob/main/LICENSE
12
+ # ------------------------------------------------------------------------------
13
+ require 'asciidoctor/extensions' unless RUBY_ENGINE == 'opal'
14
+ include Asciidoctor
15
+
16
+ # ------------------------------------------------------------------------------
17
+ # A block macro that embeds a video from the Vimeo platform
18
+ # into the output document
19
+ #
20
+ # Usage:
21
+ #
22
+ # wistia::video_id[theme="vjs_theme_name" role="CSS classes"]
23
+ #
24
+ # Example:
25
+ #
26
+ # .Video title
27
+ # wistia::179528528[theme="city" role="mt-5 mb-5"]
28
+ #
29
+ # ------------------------------------------------------------------------------
30
+ # See:
31
+ # https://www.tutorialspoint.com/creating-a-responsive-video-player-using-video-js
32
+ # ------------------------------------------------------------------------------
33
+
34
+ Asciidoctor::Extensions.register do
35
+
36
+ class WistiaBlockMacro < Extensions::BlockMacroProcessor
37
+ use_dsl
38
+
39
+ named :wistia
40
+ name_positional_attributes 'caption', 'start','poster', 'theme', 'custom_buttons', 'role'
41
+ default_attrs 'caption' => 'true',
42
+ 'start' => '00:00:00',
43
+ 'poster' => '/assets/videos/poster/wistia/wistia-blue.jpg',
44
+ 'theme' => 'uno',
45
+ 'custom_buttons' => true,
46
+ 'role' => 'mt-3 mb-3'
47
+
48
+ def process parent, target, attributes
49
+
50
+ # ========================================================================
51
+ # load VideoJS configuration data
52
+ # ------------------------------------------------------------------------
53
+ # NOTE:
54
+ # Settings folder _data is NOT available in the website
55
+ #-------------------------------------------------------------------------
56
+ current_path = File.expand_path(Dir.getwd)
57
+ default_config_path = File.join(current_path, '/_data/modules/defaults')
58
+ user_config_path = File.join(current_path, '/_data/modules')
59
+
60
+ videojs_config_file_name = 'videojs.yml'
61
+ videojs_default_config_file = File.join(default_config_path, videojs_config_file_name)
62
+ videojs_user_config_file = File.join(user_config_path, videojs_config_file_name)
63
+
64
+ videojsDefaultSettings = YAML::load(File.open(videojs_default_config_file))
65
+ videojsUserSettings = YAML::load(File.open(videojs_user_config_file))
66
+ videojsDefaultSettingsJson = videojsDefaultSettings.to_json;
67
+ videojsUserSettingsJson = videojsUserSettings.to_json;
68
+
69
+ # ========================================================================
70
+ # set plugin specific data
71
+ # ------------------------------------------------------------------------
72
+ #
73
+ chars = [('a'..'z'), ('A'..'Z'), ('0'..'9')].map(&:to_a).flatten
74
+ video_id = (0...11).map { chars[rand(chars.length)] }.join
75
+
76
+ title_html = (attributes.has_key? 'title') ? %(<div class="video-title">#{attributes['title']}</div>\n) : nil
77
+ poster_image = (poster = attributes['poster']) ? %(#{poster}) : nil
78
+ theme_name = (theme = attributes['theme']) ? %(#{theme}) : nil
79
+ caption_enabled = (caption = attributes['caption']) ? true : false
80
+ custom_buttons = (custom_buttons = attributes['custom_buttons']) ? %(#{custom_buttons}) : nil
81
+ poster_attr = %(poster="#{poster_image}")
82
+
83
+ if attributes['poster'] == 'auto'
84
+ poster_attr = ''
85
+ end
86
+
87
+ html = %(
88
+ <div class="wistia-player #{attributes['role']}">
89
+ #{title_html}
90
+ <video
91
+ id="#{video_id}"
92
+ class="video-js vjs-theme-#{theme_name}"
93
+ width="640" height="360"
94
+ #{poster_attr}
95
+ aria-label="#{attributes['title']}"
96
+ data-setup='{
97
+ "fluid" : true,
98
+ "techOrder": [
99
+ "wistia", "html5"
100
+ ],
101
+ "sources": [{
102
+ "type": "video/wistia",
103
+ "src": "#{target}"
104
+ }],
105
+ "wistia": {
106
+ "playback_css_class": "wistia_embed wistia_async_29b0fbf547",
107
+ "autoplay": false
108
+ },
109
+ "controlBar": {
110
+ "pictureInPictureToggle": false,
111
+ "volumePanel": {
112
+ "inline": false
113
+ }
114
+ }
115
+ }'
116
+ > </video>
117
+ </div>
118
+
119
+ <script>
120
+ $(function() {
121
+
122
+ // =================================================================
123
+ // take over VideoJS configuration data (JSON data from Ruby)
124
+ // -----------------------------------------------------------------
125
+ var videojsDefaultConfigJson = '#{videojsDefaultSettingsJson}';
126
+ var videojsUserConfigJson = '#{videojsUserSettingsJson}';
127
+
128
+ // =================================================================
129
+ // create config objects from JSON data
130
+ // -----------------------------------------------------------------
131
+ var videojsDefaultSettings = JSON.parse(videojsDefaultConfigJson);
132
+ var videojsUserSettings = JSON.parse(videojsUserConfigJson);
133
+
134
+ // merge config objects (jQuery)
135
+ var videojsConfig = $.extend(true, {}, videojsDefaultSettings.defaults, videojsUserSettings.settings);
136
+
137
+ // =================================================================
138
+ // VideoJS player settings
139
+ // -----------------------------------------------------------------
140
+ const vjsPlayerType = 'ytp';
141
+ const vjsPlaybackRates = videojsConfig.playbackRates.values;
142
+
143
+ // =================================================================
144
+ // VideoJS plugin settings
145
+ // -----------------------------------------------------------------
146
+ const piAutoCaption = videojsConfig.plugins.autoCaption;
147
+ const piHotKeys = videojsConfig.plugins.hotKeys;
148
+ const piSkipButtons = videojsConfig.plugins.skipButtons;
149
+ const piZoomButtons = videojsConfig.plugins.zoomButtons;
150
+
151
+ // =================================================================
152
+ // helper functions
153
+ // -----------------------------------------------------------------
154
+ function addCaptionAfterImage(imageSrc) {
155
+ const image = document.querySelector(`img[src="${imageSrc}"]`);
156
+
157
+ if (image) {
158
+ // create div|caption container
159
+ const newDiv = document.createElement('div');
160
+ newDiv.classList.add('caption');
161
+ newDiv.textContent = '#{attributes['title']}';
162
+
163
+ // insert div|caption container AFTER the image
164
+ image.parentNode.insertBefore(newDiv, image.nextSibling);
165
+ } else {
166
+ console.error(`Kein Bild mit src="${imageSrc}" gefunden.`);
167
+ }
168
+ }
169
+
170
+ // =================================================================
171
+ // initialize the VideoJS player (on page ready)
172
+ // -----------------------------------------------------------------
173
+ var dependencies_met_page_ready = setInterval (function (options) {
174
+ var pageState = $('#content').css("display");
175
+ var pageVisible = (pageState == 'block') ? true : false;
176
+ var j1CoreFinished = (j1.getState() === 'finished') ? true : false;
177
+
178
+ if (j1CoreFinished && pageVisible) {
179
+ var vjs_player = document.getElementById("#{video_id}");
180
+
181
+ // add|skip captions (on poster image)
182
+ if ('#{caption_enabled}' === 'true') {
183
+ addCaptionAfterImage('#{poster_image}');
184
+ }
185
+
186
+ // scroll page to the players top position
187
+ // -------------------------------------------------------------
188
+ vjs_player.addEventListener('click', function(event) {
189
+ const targetDiv = document.getElementById("#{video_id}");
190
+ const targetDivPosition = targetDiv.offsetTop;
191
+ var scrollOffset = (window.innerWidth >= 720) ? -130 : -110;
192
+
193
+ // scroll player to top position
194
+ window.scrollTo(0, targetDivPosition + scrollOffset);
195
+ }); // END EventListener 'click'
196
+
197
+ clearInterval(dependencies_met_page_ready);
198
+ }
199
+ }, 10);
200
+
201
+ // customize the yt player (already) created
202
+ // -----------------------------------------------------------------
203
+ var dependencies_met_vjs_player_exist = setInterval (function (options) {
204
+ var vjsPlayerExist = document.getElementById("#{video_id}") ? true : false;
205
+ var vjsPlayerCustomButtons = ("#{custom_buttons}" === 'true') ? true : false;
206
+
207
+ if (vjsPlayerExist && vjsPlayerCustomButtons) {
208
+ // apply player customization on 'player ready'
209
+ videojs("#{video_id}").ready(function() {
210
+ var vjsPlayer = this;
211
+
212
+ // add|skip playbackRates
213
+ //
214
+ if (videojsConfig.playbackRates.enabled) {
215
+ vjsPlayer.playbackRates(vjsPlaybackRates);
216
+ }
217
+
218
+ // add|skip hotKeys plugin
219
+ //
220
+ if (piHotKeys.enabled) {
221
+ vjsPlayer.hotKeys({
222
+ volumeStep: piHotKeys.volumeStep,
223
+ seekStep: piHotKeys.seekStep,
224
+ enableMute: piHotKeys.enableMute,
225
+ enableFullscreen: piHotKeys.enableFullscreen,
226
+ enableNumbers: piHotKeys.enableNumbers,
227
+ enableVolumeScroll: piHotKeys.enableVolumeScroll,
228
+ enableHoverScroll: piHotKeys.enableHoverScroll,
229
+ alwaysCaptureHotkeys: piHotKeys.alwaysCaptureHotkeys,
230
+ captureDocumentHotkeys: piHotKeys.captureDocumentHotkeys,
231
+ documentHotkeysFocusElementFilter: e => e.tagName.toLowerCase() === "body",
232
+
233
+ // Mimic VLC seek behavior (default to: 15)
234
+ seekStep: function(e) {
235
+ if (e.ctrlKey && e.altKey) {
236
+ return 5*60;
237
+ } else if (e.ctrlKey) {
238
+ return 60;
239
+ } else if (e.altKey) {
240
+ return 10;
241
+ } else {
242
+ return 15;
243
+ }
244
+ },
245
+
246
+ // Enhance existing simple hotkey by complex hotkeys
247
+ fullscreenKey: function(e) {
248
+ // fullscreen with the F key or Ctrl+Enter
249
+ return ((e.which === 70) || (e.ctrlKey && e.which === 13));
250
+ },
251
+
252
+ }); // END VideoJS hotKeys plugin
253
+ }
254
+
255
+ // add|skip skipButtons plugin
256
+ if (piSkipButtons.enabled) {
257
+ var backwardIndex = piSkipButtons.backward;
258
+ var forwardIndex = piSkipButtons.forwardIndex;
259
+
260
+ // property 'surroundPlayButton' takes precendence
261
+ //
262
+ if (piSkipButtons.surroundPlayButton) {
263
+ var backwardIndex = 0;
264
+ var forwardIndex = 1;
265
+ }
266
+
267
+ vjsPlayer.skipButtons({
268
+ backwardIndex: backwardIndex,
269
+ forwardIndex: forwardIndex,
270
+ backward: piSkipButtons.backward,
271
+ forward: piSkipButtons.forward,
272
+ });
273
+ }
274
+
275
+ // add|skip zoomButtons plugin
276
+ if (piZoomButtons.enabled && vjsPlayerType === 'native') {
277
+ vjsPlayer.zoomButtons({
278
+ moveX: piZoomButtons.moveX,
279
+ moveY: piZoomButtons.moveY,
280
+ rotate: piZoomButtons.rotate,
281
+ zoom: piZoomButtons.zoom
282
+ });
283
+ }
284
+
285
+ // set start position of current video (on play)
286
+ // -----------------------------------------------------------
287
+ var appliedOnce = false;
288
+ vjsPlayer.on("play", function() {
289
+ var startFromSecond = new Date('1970-01-01T' + "#{attributes['start']}" + 'Z').getTime() / 1000;
290
+ if (!appliedOnce) {
291
+ vjsPlayer.currentTime(startFromSecond);
292
+ appliedOnce = true;
293
+ }
294
+ });
295
+
296
+ }); // END yt player ready (set custom controls)
297
+
298
+ clearInterval(dependencies_met_vjs_player_exist);
299
+ } // END if 'vjsPlayerExist'
300
+
301
+ }, 10); // END 'dependencies_met_vjs_player_exist'
302
+
303
+ }); // END 'document ready'
304
+
305
+ </script>
306
+ )
307
+
308
+ create_pass_block parent, html, attributes, subs: nil
309
+ end
310
+ end
311
+
312
+ block_macro WistiaBlockMacro
313
+ end
@@ -1,6 +1,6 @@
1
1
  # ------------------------------------------------------------------------------
2
2
  # ~/_plugins/asciidoctor-extensions/youtube-block.rb
3
- # Asciidoctor extension for YouTube Video
3
+ # Asciidoctor extension for YouTube Videos
4
4
  #
5
5
  # Product/Info:
6
6
  # https://jekyll.one
@@ -10,6 +10,9 @@
10
10
  # J1 Template is licensed under the MIT License.
11
11
  # See: https://github.com/jekyll-one-org/j1-template/blob/main/LICENSE
12
12
  # ------------------------------------------------------------------------------
13
+
14
+ # Require Asciidoctor Extensions
15
+ # ------------------------------------------------------------------------------
13
16
  require 'asciidoctor/extensions' unless RUBY_ENGINE == 'opal'
14
17
  include Asciidoctor
15
18
 
@@ -40,25 +43,55 @@ include Asciidoctor
40
43
  # See: https://www.datenschutz.org/youtube-nocookie/
41
44
  # ------------------------------------------------------------------------------
42
45
 
46
+ # Register the Asciidoctor Extension
47
+ # ------------------------------------------------------------------------------
43
48
  Asciidoctor::Extensions.register do
44
49
 
45
50
  class YouTubeBlockMacro < Extensions::BlockMacroProcessor
46
51
  use_dsl
47
52
 
48
53
  named :youtube
49
- name_positional_attributes 'poster', 'theme', 'role'
50
- default_attrs 'poster' => '/assets/image/icons/videojs/videojs-poster.png',
54
+ name_positional_attributes 'caption', 'start','poster', 'theme', 'custom_buttons', 'role'
55
+ default_attrs 'caption' => 'true',
56
+ 'start' => '00:00:00',
57
+ 'poster' => '/assets/image/icons/videojs/videojs-poster.png',
51
58
  'theme' => 'uno',
52
- 'role' => 'mt-3 mb-3'
59
+ 'custom_buttons' => true,
60
+ 'role' => 'mt-4 mb-5'
53
61
 
54
62
  def process parent, target, attributes
55
63
 
56
- chars = [('a'..'z'), ('A'..'Z'), ('0'..'9')].map(&:to_a).flatten
57
- video_id = (0...11).map { chars[rand(chars.length)] }.join
64
+ # ========================================================================
65
+ # load VideoJS configuration data
66
+ # ------------------------------------------------------------------------
67
+ # NOTE:
68
+ # Settings folder _data is NOT available in the website
69
+ #-------------------------------------------------------------------------
70
+ current_path = File.expand_path(Dir.getwd)
71
+ default_config_path = File.join(current_path, '/_data/modules/defaults')
72
+ user_config_path = File.join(current_path, '/_data/modules')
73
+
74
+ videojs_config_file_name = 'videojs.yml'
75
+ videojs_default_config_file = File.join(default_config_path, videojs_config_file_name)
76
+ videojs_user_config_file = File.join(user_config_path, videojs_config_file_name)
77
+
78
+ videojsDefaultSettings = YAML::load(File.open(videojs_default_config_file))
79
+ videojsUserSettings = YAML::load(File.open(videojs_user_config_file))
80
+ videojsDefaultSettingsJson = videojsDefaultSettings.to_json;
81
+ videojsUserSettingsJson = videojsUserSettings.to_json;
58
82
 
59
- title_html = (attributes.has_key? 'title') ? %(<div class="video-title"> <i class="mdib mdib-youtube-tv mdib-24px mr-2"></i> #{attributes['title']} </div>\n) : nil
60
- poster_image = (poster = attributes['poster']) ? %(#{poster}) : nil
61
- theme_name = (theme = attributes['theme']) ? %(#{theme}) : nil
83
+ # ========================================================================
84
+ # set plugin specific data
85
+ # ------------------------------------------------------------------------
86
+ #
87
+ chars = [('a'..'z'), ('A'..'Z'), ('0'..'9')].map(&:to_a).flatten
88
+ video_id = (0...11).map { chars[rand(chars.length)] }.join
89
+
90
+ title_html = (attributes.has_key? 'title') ? %(<div class="video-title"> <i class="mdib mdib-video mdib-24px mr-2"></i> #{attributes['title']} </div>\n) : nil
91
+ poster_image = (poster = attributes['poster']) ? %(#{poster}) : nil
92
+ theme_name = (theme = attributes['theme']) ? %(#{theme}) : nil
93
+ custom_buttons = (custom_buttons = attributes['custom_buttons']) ? %(#{custom_buttons}) : nil
94
+ caption_enabled = (caption = attributes['caption']) ? true : false
62
95
 
63
96
  html = %(
64
97
  <div class="youtube-player bottom #{attributes['role']}">
@@ -93,6 +126,38 @@ Asciidoctor::Extensions.register do
93
126
  <script>
94
127
  $(function() {
95
128
 
129
+ // =================================================================
130
+ // take over VideoJS configuration data (JSON data from Ruby)
131
+ // -----------------------------------------------------------------
132
+ var videojsDefaultConfigJson = '#{videojsDefaultSettingsJson}';
133
+ var videojsUserConfigJson = '#{videojsUserSettingsJson}';
134
+
135
+ // =================================================================
136
+ // create config objects from JSON data
137
+ // -----------------------------------------------------------------
138
+ var videojsDefaultSettings = JSON.parse(videojsDefaultConfigJson);
139
+ var videojsUserSettings = JSON.parse(videojsUserConfigJson);
140
+
141
+ // merge config objects (jQuery)
142
+ var videojsConfig = $.extend(true, {}, videojsDefaultSettings.defaults, videojsUserSettings.settings);
143
+
144
+ // =================================================================
145
+ // VideoJS player settings
146
+ // -----------------------------------------------------------------
147
+ const vjsPlayerType = 'ytp';
148
+ const vjsPlaybackRates = videojsConfig.playbackRates.values;
149
+
150
+ // =================================================================
151
+ // VideoJS plugin settings
152
+ // -----------------------------------------------------------------
153
+ const piAutoCaption = videojsConfig.plugins.autoCaption;
154
+ const piHotKeys = videojsConfig.plugins.hotKeys;
155
+ const piSkipButtons = videojsConfig.plugins.skipButtons;
156
+ const piZoomButtons = videojsConfig.plugins.zoomButtons;
157
+
158
+ // =================================================================
159
+ // helper functions
160
+ // -----------------------------------------------------------------
96
161
  function addCaptionAfterImage(imageSrc) {
97
162
  const image = document.querySelector(`img[src="${imageSrc}"]`);
98
163
 
@@ -109,31 +174,141 @@ Asciidoctor::Extensions.register do
109
174
  }
110
175
  }
111
176
 
177
+ // =================================================================
178
+ // initialize the VideoJS player (on page ready)
179
+ // -----------------------------------------------------------------
112
180
  var dependencies_met_page_ready = setInterval (function (options) {
113
181
  var pageState = $('#content').css("display");
114
182
  var pageVisible = (pageState == 'block') ? true : false;
115
183
  var j1CoreFinished = (j1.getState() === 'finished') ? true : false;
116
184
 
117
185
  if (j1CoreFinished && pageVisible) {
118
- addCaptionAfterImage('#{poster_image}');
186
+ var vjs_player = document.getElementById("#{video_id}");
119
187
 
120
- // scroll to player top position
121
- // -------------------------------------------------------------
122
- var vjs_player = document.getElementById("#{video_id}");
188
+ // add|skip captions (on poster image)
189
+ if ('#{caption_enabled}' === 'true') {
190
+ addCaptionAfterImage('#{poster_image}');
191
+ }
123
192
 
193
+ // scroll page to the players top position
194
+ // -------------------------------------------------------------
124
195
  vjs_player.addEventListener('click', function(event) {
125
- var scrollOffset = (window.innerWidth >= 720) ? -130 : -110;
126
-
127
- // scroll player to top position
128
196
  const targetDiv = document.getElementById("#{video_id}");
129
197
  const targetDivPosition = targetDiv.offsetTop;
198
+ var scrollOffset = (window.innerWidth >= 720) ? -130 : -110;
199
+
200
+ // scroll player to top position
130
201
  window.scrollTo(0, targetDivPosition + scrollOffset);
131
202
  }); // END EventListener 'click'
132
203
 
133
204
  clearInterval(dependencies_met_page_ready);
134
205
  }
135
206
  }, 10);
136
- });
207
+
208
+ // customize the yt player (already) created
209
+ // -----------------------------------------------------------------
210
+ var dependencies_met_vjs_player_exist = setInterval (function (options) {
211
+ var vjsPlayerExist = document.getElementById("#{video_id}") ? true : false;
212
+ var vjsPlayerCustomButtons = ("#{custom_buttons}" === 'true') ? true : false;
213
+
214
+ if (vjsPlayerExist && vjsPlayerCustomButtons) {
215
+ // apply player customization on 'player ready'
216
+ videojs("#{video_id}").ready(function() {
217
+ var vjsPlayer = this;
218
+
219
+ // add|skip playbackRates
220
+ //
221
+ if (videojsConfig.playbackRates.enabled) {
222
+ vjsPlayer.playbackRates(vjsPlaybackRates);
223
+ }
224
+
225
+ // add|skip hotKeys plugin
226
+ //
227
+ if (piHotKeys.enabled) {
228
+ vjsPlayer.hotKeys({
229
+ volumeStep: piHotKeys.volumeStep,
230
+ seekStep: piHotKeys.seekStep,
231
+ enableMute: piHotKeys.enableMute,
232
+ enableFullscreen: piHotKeys.enableFullscreen,
233
+ enableNumbers: piHotKeys.enableNumbers,
234
+ enableVolumeScroll: piHotKeys.enableVolumeScroll,
235
+ enableHoverScroll: piHotKeys.enableHoverScroll,
236
+ alwaysCaptureHotkeys: piHotKeys.alwaysCaptureHotkeys,
237
+ captureDocumentHotkeys: piHotKeys.captureDocumentHotkeys,
238
+ documentHotkeysFocusElementFilter: e => e.tagName.toLowerCase() === "body",
239
+
240
+ // Mimic VLC seek behavior (default to: 15)
241
+ seekStep: function(e) {
242
+ if (e.ctrlKey && e.altKey) {
243
+ return 5*60;
244
+ } else if (e.ctrlKey) {
245
+ return 60;
246
+ } else if (e.altKey) {
247
+ return 10;
248
+ } else {
249
+ return 15;
250
+ }
251
+ },
252
+
253
+ // Enhance existing simple hotkey by complex hotkeys
254
+ fullscreenKey: function(e) {
255
+ // fullscreen with the F key or Ctrl+Enter
256
+ return ((e.which === 70) || (e.ctrlKey && e.which === 13));
257
+ },
258
+
259
+ }); // END VideoJS hotKeys plugin
260
+ }
261
+
262
+ // add|skip skipButtons plugin
263
+ if (piSkipButtons.enabled) {
264
+ var backwardIndex = piSkipButtons.backward;
265
+ var forwardIndex = piSkipButtons.forwardIndex;
266
+
267
+ // property 'surroundPlayButton' takes precendence
268
+ //
269
+ if (piSkipButtons.surroundPlayButton) {
270
+ var backwardIndex = 0;
271
+ var forwardIndex = 1;
272
+ }
273
+
274
+ vjsPlayer.skipButtons({
275
+ backwardIndex: backwardIndex,
276
+ forwardIndex: forwardIndex,
277
+ backward: piSkipButtons.backward,
278
+ forward: piSkipButtons.forward,
279
+ });
280
+ }
281
+
282
+ // add|skip zoomButtons plugin
283
+ if (piZoomButtons.enabled && vjsPlayerType === 'native') {
284
+ vjsPlayer.zoomButtons({
285
+ moveX: piZoomButtons.moveX,
286
+ moveY: piZoomButtons.moveY,
287
+ rotate: piZoomButtons.rotate,
288
+ zoom: piZoomButtons.zoom
289
+ });
290
+ }
291
+
292
+ // set start position of current video (on play)
293
+ // -----------------------------------------------------------
294
+ var appliedOnce = false;
295
+ vjsPlayer.on("play", function() {
296
+ var startFromSecond = new Date('1970-01-01T' + "#{attributes['start']}" + 'Z').getTime() / 1000;
297
+ if (!appliedOnce) {
298
+ vjsPlayer.currentTime(startFromSecond);
299
+ appliedOnce = true;
300
+ }
301
+ });
302
+
303
+ }); // END yt player ready (set custom controls)
304
+
305
+ clearInterval(dependencies_met_vjs_player_exist);
306
+ } // END if 'vjsPlayerExist'
307
+
308
+ }, 10); // END 'dependencies_met_vjs_player_exist'
309
+
310
+ }); // END 'document ready'
311
+
137
312
  </script>
138
313
  )
139
314
 
@@ -394,6 +394,6 @@ end
394
394
 
395
395
  module Jekyll
396
396
  module J1LunrSearch
397
- VERSION = '2024.3.15'
397
+ VERSION = '2024.3.16'
398
398
  end
399
399
  end
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": true,
3
3
  "name": "j1",
4
- "version": "2024.3.15",
4
+ "version": "2024.3.16",
5
5
  "description": "J1 Template",
6
6
  "homepage": "https://your.site",
7
7
  "author": {