j1-template 2024.3.15 → 2024.3.17

Sign up to get free protection for your applications and to get access to all the features.
Files changed (211) hide show
  1. checksums.yaml +4 -4
  2. data/assets/data/amplitude.html +139 -68
  3. data/assets/data/banner.html +1 -1
  4. data/assets/data/cookieconsent.html +1 -1
  5. data/assets/data/docsearch.html +1 -1
  6. data/assets/data/fab.html +1 -1
  7. data/assets/data/footer.html +1 -1
  8. data/assets/data/galeries.html +1 -1
  9. data/assets/data/gallery_customizer.html +1 -1
  10. data/assets/data/gemini-ui.html +1 -1
  11. data/assets/data/iframes.html +1 -1
  12. data/assets/data/masonry.html +1 -1
  13. data/assets/data/masterslider.html +1 -1
  14. data/assets/data/menu.html +1 -1
  15. data/assets/data/mmenu.html +1 -1
  16. data/assets/data/mmenu_sidebar.html +1 -1
  17. data/assets/data/mmenu_toc.html +1 -1
  18. data/assets/data/panel.html +5 -4
  19. data/assets/data/quicklinks.html +1 -1
  20. data/assets/data/rtext_resizer.html +1 -1
  21. data/assets/data/slick.html +1 -1
  22. data/assets/data/speak2me.html +1 -1
  23. data/assets/data/swiper.html +313 -0
  24. data/assets/theme/j1/adapter/js/amplitude.30.js +1177 -0
  25. data/assets/theme/j1/adapter/js/amplitude.js +241 -191
  26. data/assets/theme/j1/adapter/js/j1.js +3 -3
  27. data/assets/theme/j1/adapter/js/masonry.js +2 -2
  28. data/assets/theme/j1/adapter/js/masterslider.js +2 -1
  29. data/assets/theme/j1/adapter/js/swiper.js +231 -0
  30. data/assets/theme/j1/adapter/js/videojs.js +212 -0
  31. data/assets/theme/j1/core/css/themes/unolight/bootstrap.css +7 -4
  32. data/assets/theme/j1/core/css/themes/unolight/bootstrap.css.map +1 -1
  33. data/assets/theme/j1/core/css/themes/unolight/bootstrap.min.css +1 -1
  34. data/assets/theme/j1/core/css/themes/unolight/bootstrap.min.css.map +1 -1
  35. data/assets/theme/j1/core/js/template.js +4 -0
  36. data/assets/theme/j1/core/js/template.min.js +2 -2
  37. data/assets/theme/j1/core/js/template.min.js.map +1 -1
  38. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/amplitude.css +94 -4
  39. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/amplitude.min.css +1 -1
  40. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/player/compact.css +3 -2
  41. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/player/compact.min.css +1 -1
  42. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/player/large.css +72 -10
  43. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/player/large.min.css +2 -1
  44. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/artist.svg +78 -0
  45. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/mute.svg +52 -20
  46. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/next.svg +20 -39
  47. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/now-playing.svg +24 -38
  48. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/playlist-hide.svg +85 -0
  49. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/playlist-music.svg +85 -0
  50. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/playlist-show.svg +85 -0
  51. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/playlist.svg +85 -0
  52. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/previous.svg +18 -37
  53. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/skip-backward.svg +33 -30
  54. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/skip-forward.svg +33 -29
  55. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/small/next.svg +55 -14
  56. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/small/previous.svg +56 -14
  57. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/volume.svg +38 -21
  58. data/assets/theme/j1/modules/amplitudejs/js/amplitude.map +20 -20
  59. data/assets/theme/j1/modules/amplitudejs/js/tech/ytp.15.js +1594 -0
  60. data/assets/theme/j1/modules/amplitudejs/js/tech/ytp.js +1617 -89
  61. data/assets/theme/j1/modules/amplitudejs/js/visualizations/bar.js +1 -1
  62. data/assets/theme/j1/modules/amplitudejs/js/visualizations/circular-equalizer.js +31 -1
  63. data/assets/theme/j1/modules/amplitudejs/js/visualizations/frequency-analyzer.js +1 -1
  64. data/assets/theme/j1/modules/amplitudejs/js/visualizations/michael-bromley.js +1 -1
  65. data/assets/theme/j1/modules/amplitudejs/js/visualizations/template.js +1 -1
  66. data/assets/theme/j1/modules/lightGallery/js/plugins/lg-video.js +206 -122
  67. data/assets/theme/j1/modules/photoswipe/.version_5.4.4 +6 -0
  68. data/assets/theme/j1/modules/photoswipe/LICENSE +21 -0
  69. data/assets/theme/j1/modules/photoswipe/README.md +32 -0
  70. data/assets/theme/j1/modules/photoswipe/css/org/photoswipe-dynamic-caption-plugin.umd.min.js +5 -0
  71. data/assets/theme/j1/modules/photoswipe/css/org/photoswipe.css +420 -0
  72. data/assets/theme/j1/modules/photoswipe/css/photoswipe-caption-plugin.css +67 -0
  73. data/assets/theme/j1/modules/photoswipe/css/photoswipe-caption-plugin.min.css +16 -0
  74. data/assets/theme/j1/modules/photoswipe/css/photoswipe.css +376 -0
  75. data/assets/theme/j1/modules/photoswipe/css/photoswipe.min.css +17 -0
  76. data/assets/theme/j1/modules/photoswipe/css/scss/photoswipe.scss +427 -0
  77. data/assets/theme/j1/modules/photoswipe/example/photoswipe-caption-plugin.html +237 -0
  78. data/assets/theme/j1/modules/photoswipe/example/test-gallery.html +36 -0
  79. data/assets/theme/j1/modules/photoswipe/js/README.md +43 -0
  80. data/assets/theme/j1/modules/photoswipe/js/photoswipe-caption-plugin.min.js +5 -0
  81. data/assets/theme/j1/modules/photoswipe/js/photoswipe-core.min.js +18 -0
  82. data/assets/theme/j1/modules/photoswipe/js/photoswipe-lightbox.min.js +18 -0
  83. data/assets/theme/j1/modules/swiper/.version_1.2.0 +15 -0
  84. data/assets/theme/j1/modules/swiper/LICENSE +20 -0
  85. data/assets/theme/j1/modules/swiper/README.md +95 -0
  86. data/assets/theme/j1/modules/swiper/css/swiper-bundle.css +740 -0
  87. data/assets/theme/j1/modules/swiper/css/swiper-bundle.min..css +17 -0
  88. data/assets/theme/j1/modules/swiper/css/theme/uno.css +249 -0
  89. data/assets/theme/j1/modules/swiper/css/theme/uno.min.css +154 -0
  90. data/assets/theme/j1/modules/swiper/js/swiper-bundle.js +9785 -0
  91. data/assets/theme/j1/modules/swiper/js/swiper-bundle.min.js +17 -0
  92. data/assets/theme/j1/modules/swiper/swiperjs.com-demos.url +2 -0
  93. data/assets/theme/j1/modules/videojs/assets/icons/custom-icons/next.svg +82 -0
  94. data/assets/theme/j1/modules/videojs/css/font/README.md +151 -0
  95. data/assets/theme/j1/modules/videojs/css/font/VideoJS.svg +150 -0
  96. data/assets/theme/j1/modules/videojs/css/font/video-js-cdn.css +2012 -0
  97. data/assets/theme/j1/modules/videojs/css/plugins/controls/skipbuttons.0.css +32 -0
  98. data/assets/theme/j1/modules/videojs/css/plugins/controls/skipbuttons.1.css +31 -0
  99. data/assets/theme/j1/modules/videojs/css/plugins/controls/skipbuttons.css +31 -0
  100. data/assets/theme/j1/modules/videojs/css/plugins/controls/skipbuttons.min.css +21 -0
  101. data/assets/theme/j1/modules/videojs/css/themes/uno.css +14 -3
  102. data/assets/theme/j1/modules/videojs/css/themes/uno.min.css +1 -1
  103. data/assets/theme/j1/modules/videojs/css/videojs.css +1 -0
  104. data/assets/theme/j1/modules/videojs/js/plugins/controls/autocaption/LICENSE +13 -0
  105. data/assets/theme/j1/modules/videojs/js/plugins/controls/autocaption/README.md +75 -0
  106. data/assets/theme/j1/modules/videojs/js/plugins/controls/autocaption/autocaption.js +149 -0
  107. data/assets/theme/j1/modules/videojs/js/plugins/controls/autocaption/autocaption.min.js +21 -0
  108. data/assets/theme/j1/modules/videojs/js/plugins/controls/hotkeys/README.md +76 -30
  109. data/assets/theme/j1/modules/videojs/js/plugins/controls/hotkeys/hotkeys.js +64 -53
  110. data/assets/theme/j1/modules/videojs/js/plugins/controls/hotkeys/hotkeys.min.js +1 -1
  111. data/assets/theme/j1/modules/videojs/js/plugins/controls/skipbuttons/README.md +133 -0
  112. data/assets/theme/j1/modules/videojs/js/plugins/controls/skipbuttons/skipbuttons.js +137 -0
  113. data/assets/theme/j1/modules/videojs/js/plugins/controls/skipbuttons/skipbuttons.min.js +21 -0
  114. data/assets/theme/j1/modules/videojs/js/plugins/controls/zoom/zoom.js +15 -12
  115. data/assets/theme/j1/modules/videojs/js/plugins/players/yt/youtube.js +43 -16
  116. data/lib/j1/patches/rubygems/eventmachine-1.2.7-x64-mingw32/lib/3.3/fastfilereaderext.so +0 -0
  117. data/lib/j1/patches/rubygems/eventmachine-1.2.7-x64-mingw32/lib/3.3/rubyeventmachine.so +0 -0
  118. data/lib/j1/patches/rubygems/eventmachine-1.2.7-x64-mingw32/lib/3.4/fastfilereaderext.so +0 -0
  119. data/lib/j1/patches/rubygems/eventmachine-1.2.7-x64-mingw32/lib/3.4/rubyeventmachine.so +0 -0
  120. data/lib/j1/version.rb +1 -1
  121. data/lib/j1_app/j1_auth_manager/config.rb +0 -4
  122. data/lib/starter_web/Gemfile +45 -22
  123. data/lib/starter_web/README.md +5 -5
  124. data/lib/starter_web/_config.yml +4 -6
  125. data/lib/starter_web/_data/modules/amplitude.yml +308 -363
  126. data/lib/starter_web/_data/modules/defaults/amplitude.yml +60 -35
  127. data/lib/starter_web/_data/modules/defaults/gallery.yml +42 -0
  128. data/lib/starter_web/_data/modules/defaults/slick.yml +1 -1
  129. data/lib/starter_web/_data/modules/defaults/swiper.yml +515 -0
  130. data/lib/starter_web/_data/modules/defaults/videojs.yml +107 -0
  131. data/lib/starter_web/_data/modules/gallery.yml +30 -14
  132. data/lib/starter_web/_data/modules/masonry.yml +15 -0
  133. data/lib/starter_web/_data/modules/swiper.yml +227 -0
  134. data/lib/starter_web/_data/modules/videojs.yml +57 -0
  135. data/lib/starter_web/_data/resources.yml +50 -16
  136. data/lib/starter_web/_data/templates/feed.xml +1 -1
  137. data/lib/starter_web/_includes/tables/jekyll_variables.asciidoc +1 -0
  138. data/lib/starter_web/_plugins/asciidoctor/amplitude-block.rb +1 -0
  139. data/lib/starter_web/_plugins/asciidoctor/dailymotion-block.rb +4 -1
  140. data/lib/starter_web/_plugins/asciidoctor/videojs-block.rb +141 -24
  141. data/lib/starter_web/_plugins/asciidoctor/vimeo-block.rb +4 -1
  142. data/lib/starter_web/_plugins/asciidoctor/wistia-block.rb +313 -0
  143. data/lib/starter_web/_plugins/asciidoctor/youtube-block.rb +192 -17
  144. data/lib/starter_web/_plugins/index/lunr.rb +1 -1
  145. data/lib/starter_web/assets/video/poster/youtube/faelle_des_bnd/der_unverzichtbare_feind.jpg +0 -0
  146. data/lib/starter_web/assets/video/poster/youtube/faelle_des_bnd/ein_diener_vieler_herren.jpg +0 -0
  147. data/lib/starter_web/assets/video/poster/youtube/the_piano/the-piano.jpg +0 -0
  148. data/lib/starter_web/package.json +1 -1
  149. data/lib/starter_web/pages/public/_includes/attributes.asciidoc +45 -0
  150. data/lib/starter_web/pages/public/_includes/documents/photoswipe/200_photoswipe_parameters.asciidoc +510 -0
  151. data/lib/starter_web/pages/public/_includes/documents/photoswipe/210_photoswipe_lightbox_parameters.asciidoc +98 -0
  152. data/lib/starter_web/pages/public/_includes/documents/photoswipe/300_caption_plugin_for_photoSwipe.asciidoc +327 -0
  153. data/lib/starter_web/pages/public/_includes/documents/swiper/100_swiper_features.asciidoc +50 -0
  154. data/lib/starter_web/pages/public/_includes/documents/swiper/100_swiper_html_layout.asciidoc +122 -0
  155. data/lib/starter_web/pages/public/_includes/documents/swiper/100_swiper_initialization.asciidoc +53 -0
  156. data/lib/starter_web/pages/public/_includes/documents/swiper/110_swiper_common_options.asciidoc +43 -0
  157. data/lib/starter_web/pages/public/_includes/documents/swiper/200_swiper_parameters_a_k.asciidoc +994 -0
  158. data/lib/starter_web/pages/public/_includes/documents/swiper/200_swiper_parameters_l_o.asciidoc +473 -0
  159. data/lib/starter_web/pages/public/_includes/documents/swiper/200_swiper_parameters_p_s.asciidoc +700 -0
  160. data/lib/starter_web/pages/public/_includes/documents/swiper/200_swiper_parameters_t_z.asciidoc +413 -0
  161. data/lib/starter_web/pages/public/_includes/documents/swiper/300_swiper_instance_properties.asciidoc +873 -0
  162. data/lib/starter_web/pages/public/_includes/documents/swiper/400_swiper_modules.asciidoc +2514 -0
  163. data/lib/starter_web/pages/public/_includes/documents/swiper/500_swiper_methods.asciidoc +989 -0
  164. data/lib/starter_web/pages/public/_includes/documents/swiper/600_swiper_events.asciidoc +1534 -0
  165. data/lib/starter_web/pages/public/amplitude_yt_tester.adoc +89 -62
  166. data/lib/starter_web/pages/public/manuals/integrations/amplitudejs/amplitudejs-api.adoc +1 -1
  167. data/lib/starter_web/pages/public/manuals/integrations/videojs/youtube-api.adoc +1638 -0
  168. data/lib/starter_web/pages/public/photoswipe_api.adoc +150 -0
  169. data/lib/starter_web/pages/public/swiper_api.adoc +128 -0
  170. data/lib/starter_web/pages/public/swiper_tester.adoc +973 -0
  171. data/lib/starter_web/pages/public/tools/previewer/preview_bootstrap_theme.adoc +5 -6
  172. data/lib/starter_web/pages/public/tools/previewer/preview_videojs.adoc +203 -0
  173. data/lib/starter_web/pages/{tour → public/tour}/modal_extentions.adoc +12 -5
  174. data/lib/starter_web/pages/{tour → public/tour}/play_audio.adoc +63 -15
  175. data/lib/starter_web/pages/{tour → public/tour}/play_video.adoc +79 -40
  176. data/lib/starter_web/pages/{tour → public/tour}/present_images.adoc +5 -5
  177. metadata +114 -41
  178. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/_pause.svg +0 -19
  179. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/_play.svg +0 -18
  180. data/assets/theme/j1/modules/amplitudejs/icons/player/dark/show-playlist.svg +0 -15
  181. data/assets/theme/j1/modules/jqueryScrollbar/LICENSE +0 -20
  182. data/assets/theme/j1/modules/jqueryScrollbar/README.md +0 -28
  183. data/assets/theme/j1/modules/jqueryScrollbar/css/scrollbar.css +0 -939
  184. data/assets/theme/j1/modules/jqueryScrollbar/css/scrollbar.min.css +0 -20
  185. data/assets/theme/j1/modules/jqueryScrollbar/js/scrollbar.js +0 -851
  186. data/assets/theme/j1/modules/jqueryScrollbar/js/scrollbar.min.js +0 -36
  187. data/assets/theme/j1/modules/jqueryScrollbar/sass/scrollbar.scss +0 -806
  188. data/assets/theme/j1/modules/lightGallery/js/plugins/lg-video.0.js +0 -794
  189. /data/lib/starter_web/pages/{tour → public/tour}/_includes/attributes.asciidoc +0 -0
  190. /data/lib/starter_web/pages/{tour → public/tour}/_includes/documents/100_gistblock.asciidoc +0 -0
  191. /data/lib/starter_web/pages/{tour → public/tour}/_includes/documents/410_bottom_info.asciidoc +0 -0
  192. /data/lib/starter_web/pages/{tour → public/tour}/_includes/documents/410_bottom_left_warning.asciidoc +0 -0
  193. /data/lib/starter_web/pages/{tour → public/tour}/_includes/documents/410_bottom_right_danger.asciidoc +0 -0
  194. /data/lib/starter_web/pages/{tour → public/tour}/_includes/documents/410_central_success.asciidoc +0 -0
  195. /data/lib/starter_web/pages/{tour → public/tour}/_includes/documents/410_full_height_left_info.asciidoc +0 -0
  196. /data/lib/starter_web/pages/{tour → public/tour}/_includes/documents/410_full_height_right_success.asciidoc +0 -0
  197. /data/lib/starter_web/pages/{tour → public/tour}/_includes/documents/410_table_bs_modal_examples.asciidoc +0 -0
  198. /data/lib/starter_web/pages/{tour → public/tour}/_includes/documents/410_top_info.asciidoc +0 -0
  199. /data/lib/starter_web/pages/{tour → public/tour}/_includes/documents/410_top_left_info.asciidoc +0 -0
  200. /data/lib/starter_web/pages/{tour → public/tour}/_includes/documents/410_top_right_success.asciidoc +0 -0
  201. /data/lib/starter_web/pages/{tour → public/tour}/_includes/documents/419_advanced_modals_demo.asciidoc +0 -0
  202. /data/lib/starter_web/pages/{tour → public/tour}/_includes/documents/tables/bs_modal_examples.asciidoc +0 -0
  203. /data/lib/starter_web/pages/{tour → public/tour}/_includes/documents/themes_bootstrap.asciidoc +0 -0
  204. /data/lib/starter_web/pages/{tour → public/tour}/_includes/documents/themes_rouge.asciidoc +0 -0
  205. /data/lib/starter_web/pages/{tour → public/tour}/asciidoc_extensions.adoc +0 -0
  206. /data/lib/starter_web/pages/{tour → public/tour}/bootstrap_themes.adoc +0 -0
  207. /data/lib/starter_web/pages/{tour → public/tour}/highlghter_rouge.adoc +0 -0
  208. /data/lib/starter_web/pages/{tour → public/tour}/icon_fonts.adoc +0 -0
  209. /data/lib/starter_web/pages/{tour → public/tour}/quicksearch.adoc +0 -0
  210. /data/lib/starter_web/pages/{tour → public/tour}/responsive_tables.adoc +0 -0
  211. /data/lib/starter_web/pages/{tour → public/tour}/typography.adoc +0 -0
@@ -1,6 +1,64 @@
1
+ ---
2
+ regenerate: true
3
+ ---
4
+
5
+ {%- capture cache -%}
6
+
7
+ {% comment %}
8
+ # -----------------------------------------------------------------------------
9
+ # ~/assets/theme/j1/modules/amplitudejs/js/plugins/tech/ytp.js
10
+ # AmplitudeJS V5 Plugin|Tech for J1 Template
11
+ #
12
+ # Product/Info:
13
+ # https://jekyll.one
14
+ #
15
+ # Copyright (C) 2023, 2024 Juergen Adams
16
+ #
17
+ # J1 Template is licensed under the MIT License.
18
+ # See: https://github.com/jekyll-one-org/j1-template/blob/main/LICENSE
19
+ # -----------------------------------------------------------------------------
20
+ # Test data:
21
+ # {{ liquid_var | debug }}
22
+ # amplitude_options: {{ amplitude_options | debug }}
23
+ # -----------------------------------------------------------------------------
24
+ {% endcomment %}
25
+
26
+ {% comment %} Liquid procedures
27
+ -------------------------------------------------------------------------------- {% endcomment %}
28
+
29
+ {% comment %} Set global settings
30
+ -------------------------------------------------------------------------------- {% endcomment %}
31
+ {% assign environment = site.environment %}
32
+ {% assign asset_path = "/assets/theme/j1" %}
33
+
34
+ {% comment %} Process YML config data
35
+ ================================================================================ {% endcomment %}
36
+
37
+ {% comment %} Set config files
38
+ -------------------------------------------------------------------------------- {% endcomment %}
39
+ {% assign template_config = site.data.j1_config %}
40
+ {% assign blocks = site.data.blocks %}
41
+ {% assign modules = site.data.modules %}
42
+
43
+ {% comment %} Set config data (settings only)
44
+ -------------------------------------------------------------------------------- {% endcomment %}
45
+ {% assign amplitude_defaults = modules.defaults.amplitude.defaults %}
46
+ {% assign amplitude_settings = modules.amplitude.settings %}
47
+
48
+ {% comment %} Set config options (settings only)
49
+ -------------------------------------------------------------------------------- {% endcomment %}
50
+ {% assign amplitude_options = amplitude_defaults | merge: amplitude_settings %}
51
+
52
+ {% comment %} Detect prod mode
53
+ -------------------------------------------------------------------------------- {% endcomment %}
54
+ {% assign production = false %}
55
+ {% if environment == 'prod' or environment == 'production' %}
56
+ {% assign production = true %}
57
+ {% endif %}
58
+
1
59
  /*
2
60
  # -----------------------------------------------------------------------------
3
- # ~/assets/theme/j1/modules/amplitudejs/js/plugins/tech/youtube.js
61
+ # ~/assets/theme/j1/modules/amplitudejs/js/plugins/tech/ytp.js
4
62
  # AmplitudeJS V5 Plugin|Tech for J1 Template
5
63
  #
6
64
  # Product/Info:
@@ -14,100 +72,1570 @@
14
72
  */
15
73
  "use strict";
16
74
 
17
- var ytPlayer;
18
- var ytPlayerReady = false;
19
- var ytApiIReady = false;
20
- var logger = log4javascript.getLogger('j1.adapter.amplitude.tech');
21
- var ytpSettings = {
22
- ytpVideoID: "qEhzpBJpUq0",
23
- ytpAutoPlay: 0,
24
- ytpLoop: 1
25
- };
26
-
27
75
  // date|time monitoring
28
- //---------------------
76
+ //------------------------------------------------------------------------------
29
77
  var startTime;
30
78
  var endTime;
31
79
  var startTimeModule;
32
80
  var endTimeModule;
33
81
  var timeSeconds;
34
82
 
35
- startTimeModule = Date.now();
36
-
37
- logger.info('\n' + 'Initialize YouTube IframeAPI: started');
83
+ // YT API settings
84
+ // -----------------------------------------------------------------------------
85
+ // const YT_PLAYER_STATE = {
86
+ var YT_PLAYER_STATE = {
87
+ UNSTARTED: -1,
88
+ ENDED: 0,
89
+ PLAYING: 1,
90
+ PAUSED: 2,
91
+ BUFFERING: 3,
92
+ CUED: 5
93
+ };
38
94
 
39
- // load the IFrame Player API code asynchronously
40
- //
41
95
  var firstScriptTag;
42
- var tag = document.createElement('script');
43
- tag.id = 'iframe_api';
44
- tag.src = '//youtube.com/iframe_api';
45
- firstScriptTag = document.getElementsByTagName('script')[0];
46
-
47
- firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
48
-
49
- // Create an <iframe> (and the YouTube player) after the YT API code
50
- // has been downloaded
51
- function onYouTubeytApiIReady() {
52
- ytApiIReady = true;
53
-
54
- // logger.info('\n' + 'AJS YouTube IframeAPI: ready');
55
-
56
- // var ytCtrl = document.getElementById("youtube_player_container");
57
- // ytCtrl.innerHTML = '<img id="youtube-icon1 src=""/> <div id="ytPlayer"></div>';
58
- // ytCtrl.style.cssText = 'width:150px;margin:2em auto;cursor:pointer;cursor:hand;display:none';
59
- // ytCtrl.onclick = toggleAudio1;
60
-
61
- ytPlayer = new YT.Player('ytPlayer', {
62
- height: 0,
63
- width: 0,
64
- videoId: ytpSettings.ytpVideoID,
65
- playerVars: {
66
- autoplay: ytpSettings.ytpAutoPlay,
67
- loop: ytpSettings.ytpLoop
68
- },
69
- events: {
70
- onReady: onPlayerReady,
71
- onStateChange: onPlayerStateChange
72
- }
73
- });
74
-
75
- // save player reference for later use
76
- j1.adapter.amplitude['ytPlayer'] = ytPlayer;
77
- j1.adapter.amplitude['ytApiIReady'] = ytApiIReady;
78
-
79
- logger.info('\n' + 'Initialize YouTube API: finished');
80
- endTimeModule = Date.now();
81
- logger.info('\n' + 'YouTube API initializing time: ' + (endTimeModule-startTimeModule) + 'ms');
82
-
83
- } // END onYouTubeytApiIReady
84
-
85
- function onPlayerReady(event) {
86
- logger.info('\n' + 'YouTube Player: ready');
87
- ytPlayer.setPlaybackQuality("small");
88
- j1.adapter.amplitude['ytPlayerReady'] = true;
89
-
90
- // document.getElementById("youtube-audio").style.display = "block";
91
- // togglePlayButton1(ytPlayer.getPlayerState() !== 5);
92
- } // END event onPlayerReady
93
-
94
- function onPlayerStateChange(event) {
95
- if (event.data === 0) {
96
- var bla = 'blupp'
97
- // togglePlayButton1(false);
98
- }
99
- } // END event onPlayerStateChange
100
-
101
- // Create a new div element
102
- const ytpContainer = document.createElement('div');
103
-
104
- // Set attributes for the div container
105
- ytpContainer.id = 'youtube_player_container';
106
- // ytpContainer.className = 'container';
107
- // ytpContainer.setAttribute("data-video", "WxcWO9O4DSM");
108
- // ytpContainer.setAttribute("data-autoplay", "0");
109
- // ytpContainer.setAttribute("data-loop", "1");
110
- // ytpContainer.innerHTML = 'data-video="WxcWO9O4DSM" data-autoplay="0" data-loop="1"';
111
-
112
- // Append the div container to the end of the body
113
- document.body.appendChild(ytpContainer);
96
+ var ytPlayer;
97
+ var ytPlayerReady = false;
98
+ var ytApiReady = false;
99
+ var logger = log4javascript.getLogger('j1.adapter.amplitude.tech');
100
+
101
+ // YT Player settings data (created dynamically)
102
+ // -----------------------------------------------------------------------------
103
+ // var ytPlayers = {};
104
+ // var ytPlayersMap = new Map();
105
+
106
+ // AmplitudeJS API settings
107
+ // -----------------------------------------------------------------------------
108
+
109
+ var dependency;
110
+ var playerCounter = 0;
111
+ var load_dependencies = {};
112
+
113
+ // set default song index to FIRST item
114
+ var songIndex = 0;
115
+ var ytpSongIndex = 0;
116
+
117
+ var ytpAutoPlay = false;
118
+ var ytpLoop = true;
119
+ var playLists = {};
120
+ var playersUILoaded = { state: false };
121
+ var apiInitialized = { state: false };
122
+ var amplitudeDefaults = $.extend({}, {{amplitude_defaults | replace: 'nil', 'null' | replace: '=>', ':' }});
123
+ var amplitudeSettings = $.extend({}, {{amplitude_settings | replace: 'nil', 'null' | replace: '=>', ':' }});
124
+ var amplitudeOptions = $.extend(true, {}, amplitudeDefaults, amplitudeSettings);
125
+
126
+ var playerExistsInPage = false;
127
+ var ytpContainer = null;
128
+ var playerProperties = {};
129
+ var playList;
130
+ var playerProperties;
131
+ var playerID;
132
+ var playerType;
133
+ var playListTitle;
134
+ var playListName;
135
+ var amplitudePlayerState;
136
+ var ytPlayer;
137
+ var ytpPlaybackRate
138
+
139
+ var songs;
140
+ var songMetaData;
141
+ var songURL;
142
+
143
+ var progress;
144
+
145
+ // ---------------------------------------------------------------------------
146
+ // Base YT functions and events
147
+ // ---------------------------------------------------------------------------
148
+
149
+ // Recursive function to MERGE objects
150
+ var mergeObject = function() {
151
+ mergeObject = Object.assign || function mergeObject(t) {
152
+ for (var s, i=1, n=arguments.length; i<n; i++) {
153
+ s = arguments[i];
154
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
155
+ }
156
+ return t;
157
+ };
158
+ return mergeObject.apply(this, arguments);
159
+ };
160
+
161
+ // Add property path dynamically to an existing object
162
+ // Example: addNestedProperty(j1.adapter.amplitude.data, 'playlist.profile.name', 'Max Mustermann')
163
+ function addNestedProperty(obj, path, value) {
164
+ let current = obj;
165
+ const properties = path.split('.');
166
+
167
+ properties.forEach((property, index) => {
168
+ if (index === properties.length - 1) {
169
+ current[property] = value;
170
+ } else {
171
+ if (!current[property]) {
172
+ current[property] = {};
173
+ }
174
+ current = current[property];
175
+ }
176
+ });
177
+ }
178
+
179
+ function setNestedProperty(obj, path, value) {
180
+ const keys = path.split('.');
181
+
182
+ // Basisfall: Wenn nur noch ein Schlüssel übrig ist, setzen wir den Wert direkt
183
+ if (keys.length === 1) {
184
+ obj[keys[0]] = value;
185
+ return;
186
+ }
187
+
188
+ // Rekursiver Fall: Wir erstellen das Objekt für den nächsten Schlüssel, falls es noch nicht existiert
189
+ let current = obj[keys[0]];
190
+ if (typeof current !== 'object') {
191
+ current = obj[keys[0]] = {};
192
+ }
193
+
194
+ // Rekursiver Aufruf für den Rest des Pfades
195
+ setNestedProperty(current, keys.slice(1).join('.'), value);
196
+ }
197
+
198
+ // Add (nested) object dynamically to an existing object
199
+ // Example: createNestedObject(myObject, ['level1', 'arrayProperty', 0], 'element1');
200
+ function addNestedObject(obj, path, value) {
201
+ const lastKey = path[path.length - 1];
202
+ let current = obj;
203
+
204
+ path.slice(0, -1).forEach(key => {
205
+ current[key] = current[key] || {};
206
+ current = current[key];
207
+ });
208
+
209
+ current[lastKey] = value;
210
+ }
211
+
212
+ // load YT Iframe player API
213
+ function initYtAPI() {
214
+ startTimeModule = Date.now();
215
+
216
+ logger.info('\n' + 'Initialize plugin|tech (ytp) : started');
217
+
218
+ // Load YT IFrame Player API asynchronously
219
+ // -------------------------------------------------------------------------
220
+ var tag = document.createElement('script');
221
+ tag.src = "//youtube.com/iframe_api";
222
+ firstScriptTag = document.getElementsByTagName('script')[0];
223
+
224
+ firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
225
+ }
226
+
227
+ // setup YTPlayerUiEvents for AJS players
228
+ function initUiEventsForAJS() {
229
+
230
+ var dependencies_ytp_ready = setInterval (() => {
231
+ var ytApiReady = (j1.adapter.amplitude.data.ytpGlobals['ytApiReady'] !== undefined) ? j1.adapter.amplitude.data.ytpGlobals['ytApiReady'] : false;
232
+ var ytPlayerReady = (j1.adapter.amplitude.data.ytpGlobals['ytPlayerReady'] !== undefined) ? j1.adapter.amplitude.data.ytpGlobals['ytPlayerReady'] : false;
233
+
234
+ if (ytApiReady && ytPlayerReady) {
235
+
236
+ {% for player in amplitude_settings.players %}{% if player.enabled %}
237
+
238
+ {% if player.source == empty %}
239
+ {% assign player_source = amplitude_defaults.player.source %}
240
+ {% else %}
241
+ {% assign player_source = player.source %}
242
+ {% endif %}
243
+
244
+ {% if player_source == 'video' %}
245
+ var playerID = '{{player.id}}';
246
+ mimikYTPlayerUiEventsForAJS(playerID);
247
+ {% endif %}
248
+
249
+ {% endif %}{% endfor %}
250
+
251
+ clearInterval(dependencies_ytp_ready);
252
+ logger.info('\n' + 'Initialize APIPlayers : ready');
253
+ } // END if ready
254
+
255
+ }, 10); // END dependencies_ytp_ready
256
+ } // END initUiEventsForAJS()
257
+
258
+ // Create a player after Iframe player API is ready to use
259
+ // ---------------------------------------------------------------------------
260
+ function onYouTubeIframeAPIReady() {
261
+ // var currentOptions;
262
+ var playerSource;
263
+
264
+ ytApiReady = true;
265
+ // currentOptions = $.extend({}, {{amplitude_options | replace: 'nil', 'null' | replace: '=>', ':' }});
266
+
267
+ {% for player in amplitude_options.players %}{% if player.enabled %}
268
+ {% capture xhr_container_id %}{{player.id}}_parent{% endcapture %}
269
+
270
+ playerSource = '{{player.source}}';
271
+
272
+ {% if player.source == empty %}
273
+ {% assign player_source = amplitude_defaults.player.source %}
274
+ {% else %}
275
+ {% assign player_source = player.source %}
276
+ {% endif %}
277
+
278
+ {% if player_source != 'video' %}
279
+ {% continue %}
280
+ {% else %}
281
+ // load players of type 'video' configured in current page
282
+ //
283
+ playerExistsInPage = ($('#' + '{{xhr_container_id}}')[0] !== undefined) ? true : false;
284
+ if (playerExistsInPage) {
285
+ var playerSettings = $.extend({}, {{player | replace: 'nil', 'null' | replace: '=>', ':' }});
286
+ var songs = Amplitude.getSongsStatePlaylist(playerSettings.playlist.name);
287
+ var activeSongMetadata = songs[0];
288
+ var playerType = playerSettings.type
289
+
290
+ // increase number of found players in page by one
291
+ playerCounter++;
292
+
293
+ // load individual player settings (to manage multiple players in page)
294
+ //
295
+ var ytpVideoID = activeSongMetadata.url.split('=')[1];
296
+ var ytpAutoPlay = ('{{player.yt_player.autoplay}}'.length > 0) ? '{{player.yt_player.autoplay}}' : '{{amplitude_defaults.player.yt_player.autoplay}}';
297
+ var ytpLoop = ('{{player.yt_player.loop}}'.length > 0) ? '{{player.yt_player.loop}}' : '{{amplitude_defaults.player.yt_player.loop}}';
298
+ var ytpHeight = ('{{player.yt_player.height}}'.length > 0) ? '{{player.yt_player.height}}' : '{{amplitude_defaults.player.yt_player.height}}';
299
+ var ytpWidth = ('{{player.yt_player.width}}'.length > 0) ? '{{player.yt_player.width}}' : '{{amplitude_defaults.player.yt_player.width}}';
300
+
301
+ logger.info('\n' + 'AJS YouTube iFrame API: ready');
302
+ logger.info('\n' + 'configure player on ID: #{{player.id}}');
303
+
304
+ // create a hidden YT Player iFrame container
305
+ //
306
+ ytpContainer = document.getElementById('{{player.id}}_video');
307
+ ytpContainer.innerHTML = '<div id="iframe_{{player.id}}"></div>';
308
+ ytpContainer.style.cssText = 'display:none';
309
+
310
+ ytPlayer = new YT.Player('iframe_{{player.id}}', {
311
+ height: ytpHeight,
312
+ width: ytpWidth,
313
+ videoId: ytpVideoID,
314
+ playerVars: {
315
+ autoplay: ytpAutoPlay,
316
+ loop: ytpLoop
317
+ },
318
+ events: {
319
+ 'onReady': {{player.id}}OnPlayerReady,
320
+ 'onStateChange': {{player.id}}OnPlayerStateChange
321
+ }
322
+ });
323
+
324
+ // remove EMPTY properties
325
+ delete playerSettings.player;
326
+
327
+ // save YT player properties for later use
328
+ playerProperties = {
329
+ "playerDefaults": amplitudeDefaults.player,
330
+ "playerSettings": playerSettings,
331
+ "player": ytPlayer,
332
+ "playerReady": false,
333
+ "playerType": playerType,
334
+ "playerID": "{{player.id}}",
335
+ "videoID": ytpVideoID,
336
+ "songs": songs,
337
+ "activeIndex": 0,
338
+ };
339
+
340
+ // store player properties for later use
341
+ addNestedProperty(j1.adapter.amplitude.data.ytPlayers, '{{player.id}}', playerProperties);
342
+
343
+ // save YT player data for later use (e.g. events)
344
+ // j1.adapter.amplitude.data.ytpGlobals['ytVideoID'] = ytpVideoID;
345
+ // j1.adapter.amplitude.data.ytpGlobals['ytPlayerDefaults'] = amplitudeDefaults.player;
346
+ // j1.adapter.amplitude.data.ytpGlobals['ytPlayerSettings'] = playerSettings;
347
+ j1.adapter.amplitude.data.ytpGlobals['ytApiReady'] = ytApiReady;
348
+
349
+
350
+ // reset current player
351
+ playerExistsInPage = false;
352
+
353
+ } // END if playerExistsInPage()
354
+
355
+ // run AJS YouTube Player initialization
356
+ // ---------------------------------------------------------------------
357
+ function {{player.id}}OnPlayerReady(event) {
358
+ var hours, minutes, seconds;
359
+ var ytPlayer = event.target;
360
+ var ytPlayerReady = true;
361
+
362
+ logger.info('\n' + 'AJS YouTube Player on ID {{player.id}}: ready');
363
+
364
+ // save YT player data for later use (e.g. events)
365
+ j1.adapter.amplitude.data.ytpGlobals['ytPlayerReady'] = ytPlayerReady;
366
+ j1.adapter.amplitude.data.ytPlayers.{{player.id}}.playerReady = ytPlayerReady;
367
+
368
+ // setInterval(updateCurrentTimeContainerYTP, 1000);
369
+ // setInterval(updateProgressBarsYTP, 1000)
370
+
371
+ // get duration hours (if configured)
372
+ if ({{player.display_hours}} ) {
373
+ hours = ytpGetDurationHours (ytPlayer);
374
+ }
375
+
376
+ // get duration minutes|seconds
377
+ minutes = ytpGetDurationMinutes (ytPlayer);
378
+ seconds = ytpGetDurationSeconds (ytPlayer);
379
+
380
+ // set duration time values for current video
381
+ // -------------------------------------------------------------------
382
+
383
+ // set duration|hours
384
+ if ({{player.display_hours}} ) {
385
+ var durationHours = document.getElementsByClassName("amplitude-duration-hours");
386
+ durationHours[0].innerHTML = hours;
387
+ }
388
+
389
+ // set duration|minutes
390
+ var durationMinutes = document.getElementsByClassName("amplitude-duration-minutes");
391
+ durationMinutes[0].innerHTML = minutes;
392
+
393
+ // set duration|seconds
394
+ var durationSeconds = document.getElementsByClassName("amplitude-duration-seconds");
395
+ durationSeconds[0].innerHTML = seconds;
396
+
397
+ // final message
398
+ // -------------------------------------------------------------------
399
+ endTimeModule = Date.now();
400
+
401
+ logger.info('\n' + 'Initialize plugin|tech (ytp) : finished');
402
+
403
+ if (playerCounter > 0) {
404
+ logger.info('\n' + 'Found players of type video (YTP) in page: ' + playerCounter);
405
+ } else {
406
+ logger.warn('\n' + 'Found NO players of type video (YTP) in page');
407
+ }
408
+
409
+ logger.info('\n' + 'plugin|tech initializing time: ' + (endTimeModule-startTimeModule) + 'ms');
410
+
411
+ } // END onPlayerReady()
412
+
413
+ // update YT player elements on state change (playing)
414
+ // ---------------------------------------------------------------------
415
+ function {{player.id}}OnPlayerStateChange(event) {
416
+ var playlist = j1.adapter.amplitude.data.ytPlayers.{{player.id}}.playerSettings.playlist.name;
417
+ var playerID = playlist + '_large';
418
+ var ytPlayer = j1.adapter.amplitude.data.ytPlayers.{{player.id}}.player;
419
+ var songs = j1.adapter.amplitude.data.ytPlayers.{{player.id}}.songs;
420
+ // var activeIndex = j1.adapter.amplitude.data.ytPlayers.{{player.id}}.activeIndex;
421
+
422
+ // set active ytPlayer
423
+ j1.adapter.amplitude.data.ytpGlobals['activePlayer'] = ytPlayer;
424
+
425
+ // save YT player data for later use (e.g. events)
426
+ // j1.adapter.amplitude.data.ytPlayers.{{player.id}}.player = ytPlayer;
427
+
428
+ resetCurrentTimeContainerYTP();
429
+ updateDurationTimeContainerYTP(ytPlayer);
430
+
431
+ // setInterval(updateCurrentTimeContainerYTP, 1000);
432
+ // setInterval(updateProgressBarsYTP('{{player.id}}'), 1000)
433
+
434
+ // Set the index of the active song (index starts by 0)
435
+ // ytpSetActiveIndex({{player.id}}, activeIndex);
436
+
437
+ if (event.data === YT_PLAYER_STATE.PLAYING || event.data === YT_PLAYER_STATE.BUFFERING) {
438
+ setInterval(updateCurrentTimeContainerYTP, 1000);
439
+ setInterval(updateProgressBarsYTP, 1000);
440
+
441
+ // j1.adapter.amplitude.data.ytpGlobals['activePlayer'] = ytPlayer;
442
+ }
443
+
444
+ // play next video
445
+ if (event.data === YT_PLAYER_STATE.ENDED) {
446
+
447
+ // var ytPlayer = j1.adapter.amplitude.data.ytpGlobals['ytPlayer'];
448
+ // var ytPlayer = j1.adapter.amplitude.data.ytPlayers.{{player.id}}.player;
449
+ // var songs = j1.adapter.amplitude.data.ytpGlobals['ytPlayerSongs'];
450
+ // var songIndex = parseInt(j1.adapter.amplitude.data.ytpGlobals['ytpSongIndex']) + 1;
451
+
452
+ var songIndex;
453
+ songIndex = ytpSongIndex;
454
+ songIndex++;
455
+ ytpSongIndex = songIndex;
456
+
457
+ // var songIndex = j1.adapter.amplitude.data.ytPlayers[playerID].activeIndex
458
+ // songIndex++
459
+
460
+ // update activeIndex
461
+ // j1.adapter.amplitude.data.ytPlayers[playerID].activeIndex = songIndex;
462
+
463
+ if (songIndex < songs.length) {
464
+ var songMetaData = songs[songIndex];
465
+ var songURL = songMetaData.url;
466
+ var ytpVideoID = songURL.split('=')[1];
467
+
468
+ // continue on next video
469
+ ytPlayer.loadVideoById(ytpVideoID);
470
+
471
+ // reset|update time settings
472
+ resetCurrentTimeContainerYTP();
473
+ updateDurationTimeContainerYTP(ytPlayer);
474
+
475
+ // update global song index for next video
476
+ ytpSongIndex = songIndex;
477
+ // ytpSetActiveIndex({{player.id}}, songIndex);
478
+
479
+ // save YT player data for later use (e.g. events)
480
+ // j1.adapter.amplitude.data.ytpGlobals['ytpSongIndex'] = ytpSongIndex;
481
+
482
+ // load cover image for next video
483
+ var coverImage;
484
+ var selector = ".cover-image-" + playlist;
485
+ coverImage = document.querySelector(selector);
486
+ coverImage.src = songMetaData.cover_art_url;
487
+
488
+ // replace song name in meta-containers for next video
489
+ var songName = document.getElementsByClassName("song-name");
490
+ songName[0].innerHTML = songMetaData.name; // player-bottom
491
+ songName[1].innerHTML = songMetaData.name; // playlist-screen-controls
492
+
493
+ // replace song rating (playlist-screen|meta-container)
494
+ var largetPlayerSongAudioRating = document.getElementsByClassName("audio-rating");
495
+ if (largetPlayerSongAudioRating.length) {
496
+ if (songMetaData.rating) {
497
+ largetPlayerSongAudioRating[0].innerHTML = songMetaData.rating + ' <i class="mdib mdib-star md-gray-400 mdib-18px"></i>';
498
+ } else {
499
+ largetPlayerSongAudioRating[0].innerHTML = '';
500
+ }
501
+ } // END if largetPlayerSongAudioRating
502
+
503
+ // replace artist name in meta-containers for next video
504
+ var artistName = document.getElementsByClassName("artist");
505
+ artistName[0].innerHTML = songMetaData.artist;
506
+
507
+ // replace album name in meta-containers for next video
508
+ var albumName = document.getElementsByClassName("album");
509
+ albumName[0].innerHTML = songMetaData.album;
510
+
511
+ // set song active in playlist
512
+ // setSongPlayed(songIndex);
513
+ setSongPlayed(playerID, songIndex);
514
+ } else {
515
+ // select FIRST video
516
+ songIndex = 0;
517
+ var songMetaData = songs[songIndex];
518
+ var songURL = songMetaData.url;
519
+ var ytpVideoID = songURL.split('=')[1];
520
+
521
+ // ytpSetActiveIndex({{player.id}}, songIndex);
522
+
523
+ // continue (paused) on FIRST video
524
+ ytPlayer.loadVideoById(ytpVideoID);
525
+ // wait some time to make sure video is loaded|active
526
+ setTimeout(() => {
527
+ ytPlayer.pauseVideo();
528
+ // reset|update time settings
529
+ resetCurrentTimeContainerYTP();
530
+ updateDurationTimeContainerYTP(ytPlayer);
531
+
532
+ // update AJS play_pause button
533
+ var largePlayerPlayPauseButton = document.getElementById('large_player_play_pause');
534
+ largePlayerPlayPauseButton.classList.remove('amplitude-playing');
535
+ largePlayerPlayPauseButton.classList.add('amplitude-paused');
536
+ }, 300);
537
+
538
+ // update global song index for first video
539
+ ytpSongIndex = songIndex;
540
+
541
+ // save YT player data for later use (e.g. events)
542
+ // j1.adapter.amplitude.data.ytpGlobals['ytpSongIndex'] = ytpSongIndex;
543
+
544
+ // load cover image for first video
545
+ var coverImage;
546
+ var selector = ".cover-image-" + playlist;
547
+ coverImage = document.querySelector(selector);
548
+ coverImage.src = songMetaData.cover_art_url;
549
+
550
+ // replace name in meta-containers for first video
551
+ var songName = document.getElementsByClassName("song-name");
552
+ songName[0].innerHTML = songMetaData.name; // player-bottom
553
+ songName[1].innerHTML = songMetaData.name; // playlist-screen-controls
554
+
555
+ // replace song rating (playlist-screen|meta-container)
556
+ var largetPlayerSongAudioRating = document.getElementsByClassName("audio-rating");
557
+ if (largetPlayerSongAudioRating.length) {
558
+ if (songMetaData.rating) {
559
+ largetPlayerSongAudioRating[0].innerHTML = songMetaData.rating + ' <i class="mdib mdib-star md-gray-400 mdib-18px"></i>';
560
+ } else {
561
+ largetPlayerSongAudioRating[0].innerHTML = '';
562
+ }
563
+ } // END if largetPlayerSongAudioRating
564
+
565
+ // replace artist name in meta-containers for next video
566
+ var artistName = document.getElementsByClassName("artist");
567
+ artistName.innerHTML = songMetaData.artist;
568
+
569
+ // replace album name in meta-containers for next video
570
+ var albumName = document.getElementsByClassName("album");
571
+ albumName.innerHTML = songMetaData.album;
572
+
573
+ // update AJS play_pause button
574
+ var largePlayerPlayPauseButton = document.getElementById('large_player_play_pause');
575
+ largePlayerPlayPauseButton.classList.remove('amplitude-playing');
576
+ largePlayerPlayPauseButton.classList.add('amplitude-paused');
577
+
578
+ // set song (video) active in playlist
579
+ // setSongPlayed(songIndex);
580
+ setSongPlayed(playerID, songIndex);
581
+ }
582
+ } // END if YT_PLAYER_STATE.ENDED
583
+
584
+ } // END {{player.id}}OnPlayerStateChange
585
+
586
+ {% endif %}
587
+ {% endif %}{% endfor %}
588
+
589
+ } // END onYouTubeIframeAPIReady ()
590
+
591
+
592
+ // ---------------------------------------------------------------------------
593
+ // main (plugin)
594
+ // ---------------------------------------------------------------------------
595
+ // load|initialize YT Iframe player API
596
+ //
597
+ initYtAPI();
598
+
599
+ // setup YTPlayerUiEvents for AJS players
600
+ //
601
+ initUiEventsForAJS();
602
+
603
+
604
+ // ---------------------------------------------------------------------------
605
+ // Base AJS Player functions
606
+ // ---------------------------------------------------------------------------
607
+
608
+ // ---------------------------------------------------------------------------
609
+ // Returns the index of the current video (song) in the songs array
610
+ // that is currently playing (starts by 0)
611
+ // ---------------------------------------------------------------------------
612
+ //
613
+ function getSongPlayed() {
614
+ var index = -1;
615
+ var songContainers = document.getElementsByClassName("amplitude-active-song-container");
616
+
617
+ if (songContainers.length) {
618
+ for (var i=0; i<songContainers.length; i++) {
619
+ index = parseInt(songContainers[i].getAttribute('data-amplitude-song-index'));
620
+ if (index >= 0) {
621
+ break;
622
+ }
623
+ }
624
+ }
625
+
626
+ return index;
627
+ } // END getSongPlayed
628
+
629
+ // ---------------------------------------------------------------------------
630
+ // Add class 'amplitude-active-song-container' to the element containing
631
+ // visual information for the active song.
632
+ //
633
+ // NOTE: We then don't care if shuffle is on or not.
634
+ // ---------------------------------------------------------------------------
635
+ //
636
+ function setSongPlayed(playerID, index) {
637
+ var direct;
638
+
639
+ // Specify if it was a (direct) click on the song container
640
+ direct = true;
641
+
642
+ // Get all song container elements
643
+ var songContainers = document.getElementsByClassName("amplitude-song-container");
644
+
645
+ // Clear all active song containrs
646
+ for (var i = 0; i < songContainers.length; i++) {
647
+ songContainers[i].classList.remove("amplitude-active-song-container");
648
+ }
649
+
650
+ // Find the active index and add the active song container to the element
651
+ // that represents the song at the index.
652
+ //
653
+ if (Amplitude.getActivePlaylist() == "" || Amplitude.getActivePlaylist() == null) {
654
+ var activeIndex = "";
655
+
656
+ // If we click directly on the song element, we ignore
657
+ // whether it's in shuffle or not.
658
+ //
659
+ if (direct) {
660
+ // activeIndex = Amplitude.getActiveIndex();
661
+ activeIndex = index;
662
+ } else {
663
+ if (Amplitude.getConfig().shuffle_on) {
664
+ // activeIndex = Amplitude.getConfig().shuffle_list[Amplitude.getActiveIndex()];
665
+ } else {
666
+ // activeIndex = Amplitude.getActiveIndex();
667
+ activeIndex = index;
668
+ }
669
+ }
670
+
671
+ // activate playlist container
672
+ if (document.querySelectorAll('.amplitude-song-container[data-amplitude-song-index="' + activeIndex + '"]')) {
673
+ var _songContainers = document.querySelectorAll('.amplitude-song-container[data-amplitude-song-index="' + activeIndex + '"]');
674
+ for (var _i = 0; _i < _songContainers.length; _i++) {
675
+ if (_songContainers[_i].hasAttribute("data-amplitude-playlist")) {
676
+ var _playerID = _songContainers[_i].getAttribute("data-amplitude-playlist") + '_large';
677
+ if (_playerID === playerID) {
678
+ _songContainers[_i].classList.add("amplitude-active-song-container");
679
+ }
680
+ }
681
+ }
682
+ }
683
+ } else {
684
+ // If we have an active playlist or the action took place directly on the
685
+ // song element, we ignore the shuffle.
686
+ //
687
+ if (Amplitude.getActivePlaylist() != null && Amplitude.getActivePlaylist() != "" || direct) {
688
+ var activePlaylistIndex = Amplitude.getActiveIndex();
689
+ } else {
690
+ var activePlaylistIndex = "";
691
+
692
+ if (Amplitude.getActivePlaylist().shuffle) {
693
+ activePlaylistIndex = Amplitude.getActiveIndex();
694
+ } else {
695
+ activePlaylistIndex = Amplitude.getActiveIndex();
696
+ }
697
+ } // END if
698
+ } // END if
699
+ } // END setSongPlayed
700
+
701
+ // Returns the position as a percentage the user clicked in player progressbar
702
+ // NOTE: The percentage is out of [0.00 .. 1.00]
703
+ // ---------------------------------------------------------------------------
704
+ function getProgressBarSelectedPositionPercentage (event, progessBar) {
705
+ var offset = progessBar.getBoundingClientRect();
706
+ var xpos = event.pageX - offset.left;
707
+ var percentage = (parseFloat(xpos) / parseFloat(progessBar.offsetWidth)).toFixed(2);
708
+
709
+ return percentage;
710
+ }
711
+
712
+ // Returns the time in seconds calculated from a percentage value
713
+ // NOTE: The percentage is out of [0.00 .. 1.00]
714
+ // ---------------------------------------------------------------------------
715
+ function getTimeFromPercentage (player, percentage) {
716
+ var videoDuration = ytpGetDuration(player);
717
+ var time = parseFloat((videoDuration * percentage).toFixed(2));
718
+
719
+ return time;
720
+ }
721
+
722
+ // Update YTP specific progress data
723
+ // ---------------------------------------------------------------------------
724
+ function updateProgressBarsYTP() {
725
+ var progress;
726
+ var activePlayer = j1.adapter.amplitude.data.ytpGlobals['activePlayer'];
727
+ var progressBars = document.getElementsByClassName("large-player-progress");
728
+
729
+ for (var i=0; i<progressBars.length; i++) {
730
+ if (activePlayer !== undefined) {
731
+ // calc procent value (float, 2 decimals [0.00 .. 1.00])
732
+ progress = parseFloat((activePlayer.getCurrentTime() / activePlayer.getDuration()).toFixed(2));
733
+
734
+ // set current progess value if valid
735
+ if (isFinite(progress)) {
736
+ progressBars[i].value = progress;
737
+ }
738
+ }
739
+ } // END for
740
+
741
+ // calc procent value (float, 2 decimals [0.00 .. 1.00])
742
+ // progress = parseFloat((ytPlayer.getCurrentTime() / ytPlayer.getDuration()).toFixed(2));
743
+
744
+ // // jadams, 2024-12-07: added check on finite value
745
+ // if (!isFinite(progress)) {
746
+ // // TODO: check why progress value may NOT finite
747
+ // progressBar.value = 0;
748
+ // } else if (progress === 1) {
749
+ // // reset progress value for next video
750
+ // progressBar.value = 0;
751
+ // } else {
752
+ // // calculate current progress
753
+ // progress = parseFloat((ytPlayer.getCurrentTime() / ytPlayer.getDuration()).toFixed(2));
754
+ // progressBar.value = progress;
755
+
756
+ // save YT player progress data for later use (e.g. events)
757
+ // j1.adapter.amplitude.data.ytpGlobals['ytPlayerProgress'] = progress;
758
+ //}
759
+ }
760
+
761
+ // Update YTP specific duration time data
762
+ // ---------------------------------------------------------------------------
763
+ function updateDurationTimeContainerYTP(player) {
764
+ var hours, minutes, seconds;
765
+ var durationHours, durationMinutes, durationSeconds;
766
+
767
+ // get current hours|minutes|seconds
768
+ hours = ytpGetDurationHours(player);
769
+ minutes = ytpGetDurationMinutes(player);
770
+ seconds = ytpGetDurationSeconds(player);
771
+
772
+ // update time container values for current video
773
+ // -------------------------------------------------------------------------
774
+
775
+ // update current duration|hours
776
+ durationHours = document.getElementsByClassName("amplitude-duration-hours");
777
+ if (!isNaN(hours)) {
778
+ durationHours[0].innerHTML = hours;
779
+ }
780
+
781
+ // update current duration|minutes
782
+ durationMinutes = document.getElementsByClassName("amplitude-duration-minutes");
783
+ if (!isNaN(minutes)) {
784
+ durationMinutes[0].innerHTML = minutes;
785
+ }
786
+
787
+ // update duration|seconds
788
+ durationSeconds = document.getElementsByClassName("amplitude-duration-seconds");
789
+ if (!isNaN(seconds)) {
790
+ durationSeconds[0].innerHTML = seconds;
791
+ }
792
+ }
793
+
794
+ // Update YTP specific CURRENT time data
795
+ // ---------------------------------------------------------------------------
796
+ function updateCurrentTimeContainerYTP() {
797
+ var hours, minutes, seconds;
798
+ var currentHours, currentMinutes, currentSeconds;
799
+
800
+ // get current hours|minutes|seconds
801
+ hours = ytpGetCurrentHours(ytPlayer);
802
+ minutes = ytpGetCurrentMinutes(ytPlayer);
803
+ seconds = ytpGetCurrentSeconds(ytPlayer);
804
+
805
+ // update time container values for current video
806
+ // -------------------------------------------------------------------------
807
+
808
+ // update current duration|hours
809
+ if (hours !== '00') {
810
+ currentHours = document.getElementsByClassName("amplitude-current-hours");
811
+ currentHours[0].innerHTML = hours;
812
+ }
813
+
814
+ // update current duration|minutes
815
+ currentMinutes = document.getElementsByClassName("amplitude-current-minutes");
816
+ currentMinutes[0].innerHTML = minutes;
817
+
818
+ // update duration|seconds
819
+ currentSeconds = document.getElementsByClassName("amplitude-current-seconds");
820
+ currentSeconds[0].innerHTML = seconds;
821
+ }
822
+
823
+ // Reset YTP specific progress data
824
+ // ---------------------------------------------------------------------------
825
+ function resetProgressBarYTP(playerID) {
826
+ if (playerID !== undefined) {
827
+ var progressBar = j1.adapter.amplitude.data.ytPlayers[playerID].progressBar;
828
+ progressBar.value = 0;
829
+ }
830
+ }
831
+
832
+ // Reset YTP specific CURRENT time data
833
+ // ---------------------------------------------------------------------------
834
+ function resetCurrentTimeContainerYTP() {
835
+
836
+ // reset duration|hours
837
+ var currentHours = document.getElementsByClassName("amplitude-current-hours");
838
+ if (currentHours.length) {
839
+ currentHours[0].innerHTML = '00';
840
+ }
841
+
842
+ // reset duration|minutes
843
+ var currentMinutes = document.getElementsByClassName("amplitude-current-minutes");
844
+ currentMinutes[0].innerHTML = '00';
845
+
846
+ // reset duration|seconds
847
+ var currentSeconds = document.getElementsByClassName("amplitude-current-seconds");
848
+ currentSeconds[0].innerHTML = '00';
849
+ }
850
+
851
+
852
+ // ---------------------------------------------------------------------------
853
+ // Mimik Base AJS API functions
854
+ // ---------------------------------------------------------------------------
855
+
856
+ // Seek (skip) video to time specified
857
+ // ---------------------------------------------------------------------------
858
+ function ytpSeekTo(player, time) {
859
+ player.seekTo(time, true);
860
+ } // END ytpSeekTo
861
+
862
+ // Returns the buffered percentage of the playing video
863
+ // ---------------------------------------------------------------------------
864
+ function ytpGetBuffered(player) {
865
+ // to be defined
866
+ }
867
+
868
+ // Returns the active song index (in the songs array, starts by 0)
869
+ // ---------------------------------------------------------------------------
870
+ function ytpGetActiveIndex(playerID) {
871
+ var activeIndex = -1;
872
+
873
+ if (j1.adapter.amplitude.data.ytPlayers[playerID].activeIndex !== undefined) {
874
+ activeIndex = parseInt(j1.adapter.amplitude.data.ytPlayers[playerID].activeIndex);
875
+ }
876
+
877
+ return activeIndex;
878
+ } // END ytpGetActiveIndex
879
+
880
+ // Set the index of the active song (index starts by 0)
881
+ // ---------------------------------------------------------------------------
882
+ function ytpSetActiveIndex(playerID, idx) {
883
+ var success = false;
884
+ var index = parseInt(idx);
885
+
886
+ if (j1.adapter.amplitude.data.ytPlayers[playerID].activeIndex !== undefined) {
887
+ j1.adapter.amplitude.data.ytPlayers[playerID].activeIndex = index;
888
+ success = true;
889
+ }
890
+
891
+ return success;
892
+ } // END ytpSetActiveIndex
893
+
894
+ // Returns the percentage of the video played
895
+ // ---------------------------------------------------------------------------
896
+ function ytpGetPlayedPercentage(player) {
897
+ // to be defined
898
+ }
899
+
900
+ // Returns the actual video element
901
+ // ---------------------------------------------------------------------------
902
+ function ytpGetAudio(player) {
903
+ // to be defined
904
+ }
905
+
906
+ // Returns available playback speeds for the player
907
+ // ---------------------------------------------------------------------------
908
+ function ytpGetPlaybackSpeeds(player) {
909
+ // to be defined
910
+ }
911
+
912
+ // Returns the current playback speed for the player
913
+ // ---------------------------------------------------------------------------
914
+ function ytpGetPlaybackSpeed(player) {
915
+ }
916
+
917
+ // Returns the current state of the player
918
+ // ---------------------------------------------------------------------------
919
+ function ytpGetPlayerState(player) {
920
+ // to be defined
921
+ }
922
+
923
+ // Returns the duration of the video
924
+ // ---------------------------------------------------------------------------
925
+ function ytpGetDuration(player) {
926
+ var playerState, duration;
927
+
928
+ playerState = player.getPlayerState();
929
+ if (playerState === YT_PLAYER_STATE.PLAYING || playerState === YT_PLAYER_STATE.BUFFERING || playerState === YT_PLAYER_STATE.PAUSED || playerState === YT_PLAYER_STATE.CUED) {
930
+ duration = player.getDuration();
931
+
932
+ return duration;
933
+ } else {
934
+ return 0;
935
+ }
936
+ } // END ytpGetDuration
937
+
938
+ // Returns the current time of the video played
939
+ // ---------------------------------------------------------------------------
940
+ function ytpGetCurrentTime(player) {
941
+ var currentTime, playerState;
942
+
943
+ if (player !== undefined && player.getPlayerState !== undefined) {
944
+ playerState = player.getPlayerState();
945
+ if (playerState === YT_PLAYER_STATE.PLAYING || playerState === YT_PLAYER_STATE.PAUSED || playerState === YT_PLAYER_STATE.CUED) {
946
+ currentTime = player.getCurrentTime();
947
+
948
+ return currentTime;
949
+ } else {
950
+ return 0;
951
+ }
952
+ }
953
+ } // END ytpGetCurrentTime
954
+
955
+ // Returns the duration hours of the video
956
+ // ---------------------------------------------------------------------------
957
+ function ytpGetDurationHours(player) {
958
+ var playerState, duration, hours, d, h;
959
+
960
+ if (player !== undefined && player.getPlayerState !== undefined) {
961
+ playerState = player.getPlayerState();
962
+ if (playerState === YT_PLAYER_STATE.PLAYING || playerState === YT_PLAYER_STATE.PAUSED || playerState === YT_PLAYER_STATE.CUED ) {
963
+ duration = ytpGetDuration(player);
964
+ d = Number(duration);
965
+ h = Math.floor(d / 3600);
966
+ hours = h.toString().padStart(2, '0');
967
+
968
+ return hours;
969
+ } else {
970
+ return '00';
971
+ }
972
+ }
973
+ } // END ytpGetDurationHours
974
+
975
+ // Returns the duration minutes of the video
976
+ // ---------------------------------------------------------------------------
977
+ function ytpGetDurationMinutes(player) {
978
+ var playerState, duration, minutes, d, m;
979
+
980
+ if (player !== undefined && player.getPlayerState !== undefined) {
981
+ playerState = player.getPlayerState();
982
+ if (playerState === YT_PLAYER_STATE.PLAYING || playerState === YT_PLAYER_STATE.PAUSED || playerState === YT_PLAYER_STATE.CUED) {
983
+ duration = ytpGetDuration(player);
984
+ d = Number(duration);
985
+ m = Math.floor(d % 3600 / 60);
986
+ minutes = m.toString().padStart(2, '0');
987
+
988
+ return minutes;
989
+ } else {
990
+ return '00';
991
+ }
992
+ }
993
+ } // END ytpGetDurationMinutes
994
+
995
+ // Returns the duration seconds of the video
996
+ // ---------------------------------------------------------------------------
997
+ function ytpGetDurationSeconds(player) {
998
+ var playerState, duration, seconds, d, s;
999
+
1000
+ if (player !== undefined && player.getPlayerState !== undefined) {
1001
+ playerState = player.getPlayerState();
1002
+ if (playerState === YT_PLAYER_STATE.PLAYING || playerState === YT_PLAYER_STATE.PAUSED || playerState === YT_PLAYER_STATE.CUED ) {
1003
+ duration = ytpGetDuration(player);
1004
+ d = Number(duration);
1005
+ s = Math.floor(d % 60);
1006
+ seconds = s.toString().padStart(2, '0');
1007
+
1008
+ return seconds;
1009
+ } else {
1010
+ return '00';
1011
+ }
1012
+ }
1013
+ } // END ytpGetDurationSeconds
1014
+
1015
+ // Returns the current hours the user is into the video
1016
+ // ---------------------------------------------------------------------------
1017
+ function ytpGetCurrentHours(player) {
1018
+ var playerState, currentTime, hours, d, h;
1019
+
1020
+ if (player !== undefined && player.getPlayerState !== undefined) {
1021
+ playerState = player.getPlayerState();
1022
+ if (playerState === YT_PLAYER_STATE.PLAYING || playerState === YT_PLAYER_STATE.PAUSED || playerState === YT_PLAYER_STATE.CUED) {
1023
+ currentTime = ytpGetCurrentTime(player);
1024
+ d = Number(currentTime);
1025
+ h = Math.floor(d / 3600);
1026
+ hours = h.toString().padStart(2, '0');
1027
+
1028
+ return hours;
1029
+ } else {
1030
+ return '00';
1031
+ }
1032
+ }
1033
+ } // END ytpGetCurrentHours
1034
+
1035
+ // Returns the current minutes the user is into the video
1036
+ // ---------------------------------------------------------------------------
1037
+ function ytpGetCurrentMinutes (player) {
1038
+ var playerState, currentTime, minutes, d, m;
1039
+
1040
+ if (player !== undefined && player.getPlayerState !== undefined) {
1041
+ playerState = player.getPlayerState();
1042
+ if (playerState === YT_PLAYER_STATE.PLAYING || playerState === YT_PLAYER_STATE.PAUSED || playerState === YT_PLAYER_STATE.CUED) {
1043
+ currentTime = ytpGetCurrentTime(player);
1044
+ d = Number(currentTime);
1045
+ m = Math.floor(d % 3600 / 60);
1046
+ minutes = m.toString().padStart(2, '0');
1047
+
1048
+ return minutes;
1049
+ } else {
1050
+ return '00';
1051
+ }
1052
+ }
1053
+ } // END ytpGetCurrentMinutes
1054
+
1055
+ // Returns the current seconds the user is into the video
1056
+ // ---------------------------------------------------------------------------
1057
+ function ytpGetCurrentSeconds(player) {
1058
+ var playerState, currentTime, seconds, d, s;
1059
+
1060
+ if (player !== undefined && player.getPlayerState !== undefined) {
1061
+ playerState = player.getPlayerState();
1062
+ if (playerState === YT_PLAYER_STATE.PLAYING || playerState === YT_PLAYER_STATE.PAUSED || playerState === YT_PLAYER_STATE.CUED ) {
1063
+ currentTime = ytpGetCurrentTime(player);
1064
+ d = Number(currentTime);
1065
+ s = Math.floor(d % 60);
1066
+ seconds = s.toString().padStart(2, '0');
1067
+
1068
+ return seconds;
1069
+ } else {
1070
+ return '00';
1071
+ }
1072
+ }
1073
+ } // END ytpGetCurrentSeconds
1074
+
1075
+ // ---------------------------------------------------------------------------
1076
+ // mimikYTPlayerUiEventsForAJS()
1077
+ // Mimik AJS button events for YT video
1078
+ // ---------------------------------------------------------------------------
1079
+ function mimikYTPlayerUiEventsForAJS(ytPlayerID) {
1080
+ if (j1.adapter.amplitude['data']['ytPlayers'][ytPlayerID] !== undefined) {
1081
+ var playerDefaults = j1.adapter.amplitude['data']['ytPlayers'][ytPlayerID].playerDefaults;
1082
+ var playerSettings = j1.adapter.amplitude['data']['ytPlayers'][ytPlayerID].playerSettings;
1083
+ var playerButton = `large-player-play-pause-${ytPlayerID}`;
1084
+
1085
+ // -----------------------------------------------------------------------
1086
+ // Large AJS players
1087
+ //
1088
+ if (j1.adapter.amplitude['data']['ytPlayers'][ytPlayerID].playerSettings.type === 'large') {
1089
+
1090
+ // Overload AJS play_pause button for YT
1091
+ //
1092
+ var largePlayerPlayPauseButton = document.getElementsByClassName(playerButton);
1093
+ for (var i=0; i<largePlayerPlayPauseButton.length; i++) {
1094
+ var classArray = [].slice.call(largePlayerPlayPauseButton[i].classList, 0);
1095
+ var classString = classArray.toString();
1096
+
1097
+ if (classString.includes(ytPlayerID)) {
1098
+ largePlayerPlayPauseButton[i].addEventListener('click', function(event) {
1099
+ var playlist = this.getAttribute("data-amplitude-playlist");
1100
+ var playerID = playlist + '_large';
1101
+ var ytPlayer = j1.adapter.amplitude['data']['ytPlayers'][playerID]['player'];
1102
+ var songs = j1.adapter.amplitude['data']['ytPlayers'][playerID]['songs'];
1103
+ var activeIndex = parseInt(j1.adapter.amplitude['data']['ytPlayers'][playerID]['activeIndex']);
1104
+ var songMetaData = songs[songIndex];
1105
+ var playPauseButton = `large-player-play-pause-${ytPlayerID}`;
1106
+
1107
+ // toggle YT play|pause video
1108
+ if (ytPlayer.getPlayerState() === YT_PLAYER_STATE.PLAYING || ytPlayer.getPlayerState() === YT_PLAYER_STATE.BUFFERING) {
1109
+ ytPlayer.pauseVideo();
1110
+ } else {
1111
+ ytPlayer.playVideo();
1112
+ }
1113
+
1114
+ // toggle AJS PlayPauseButton
1115
+ var largePlayerPlayPauseButton = document.getElementsByClassName(playPauseButton);
1116
+ if (largePlayerPlayPauseButton[0].classList.contains('amplitude-paused')) {
1117
+ largePlayerPlayPauseButton[0].classList.remove('amplitude-paused');
1118
+ largePlayerPlayPauseButton[0].classList.add('amplitude-playing');
1119
+ } else {
1120
+ largePlayerPlayPauseButton[0].classList.remove('amplitude-playing');
1121
+ largePlayerPlayPauseButton[0].classList.add('amplitude-paused');
1122
+ }
1123
+
1124
+ // don't activate playlist item on FIRST || LAST song
1125
+ // if (songIndex !== 0 && songIndex !== songs.length - 1) {
1126
+ if (songIndex !== songs.length - 1) {
1127
+ // set song active in playlist
1128
+ //setSongPlayed(songIndex);
1129
+ setSongPlayed(playerID, songIndex);
1130
+ }
1131
+
1132
+ // event.preventDefault();
1133
+ event.stopImmediatePropagation(); // deactivate AJS events
1134
+ }); // END EventListener largePlayerPlayPauseButton 'click'
1135
+ } // END if largePlayerPlayPauseButton
1136
+ } // END for largePlayerPlayPauseButton
1137
+
1138
+ // Overload AJS largePlayerSkipBackward button for YT
1139
+ //
1140
+ var largePlayerSkipForwardButtons = document.getElementsByClassName("large-player-skip-forward");
1141
+ for (var i=0; i<largePlayerSkipForwardButtons.length; i++) {
1142
+ var classArray = [].slice.call(largePlayerSkipForwardButtons[i].classList, 0);
1143
+ var classString = classArray.toString();
1144
+
1145
+ // load player settings
1146
+ var playerForwardBackwardSkipSeconds = (playerSettings.forward_backward_skip_seconds === undefined) ? playerDefaults.forward_backward_skip_seconds : playerSettings.forward_backward_skip_seconds;
1147
+
1148
+ // if (largePlayerSkipForwardButtons[i].id === 'skip-forward_' + ytPlayerID) {
1149
+ // if (classString.includes(ytPlayerID)) && largePlayerSkipForwardButtons[i].id === 'skip-forkward_' + ytPlayerID) {
1150
+ if (classString.includes(ytPlayerID)) {
1151
+ largePlayerSkipForwardButtons[i].addEventListener('click', function(event) {
1152
+ var currentTime, playerState, skipOffset, ytPlayer;
1153
+
1154
+ skipOffset = parseFloat(playerForwardBackwardSkipSeconds);
1155
+ ytPlayer = j1.adapter.amplitude['data']['ytPlayers'][ytPlayerID].player;
1156
+ playerState = ytPlayer.getPlayerState();
1157
+ currentTime = ytPlayer.getCurrentTime();
1158
+
1159
+ if (playerState === YT_PLAYER_STATE.PLAYING || playerState === YT_PLAYER_STATE.PAUSED) {
1160
+ ytPlayer.seekTo(currentTime + skipOffset, true);
1161
+ }
1162
+
1163
+ // deactivate AJS events (if any)
1164
+ event.stopImmediatePropagation();
1165
+ }); // END Listener 'click'
1166
+ } // END if skip-forward button
1167
+ } // END for
1168
+
1169
+ // Overload AJS largePlayerSkipBackward button for YT
1170
+ //
1171
+ var largePlayerSkipBackwardButtons = document.getElementsByClassName("large-player-skip-backward");
1172
+ for (var i=0; i<largePlayerSkipBackwardButtons.length; i++) {
1173
+ var classArray = [].slice.call(largePlayerSkipBackwardButtons[i].classList, 0);
1174
+ var classString = classArray.toString();
1175
+
1176
+ // load player settings
1177
+ var playerForwardBackwardSkipSeconds = (playerSettings.forward_backward_skip_seconds === undefined) ? playerDefaults.forward_backward_skip_seconds : playerSettings.forward_backward_skip_seconds;
1178
+
1179
+ if (classString.includes(ytPlayerID)) {
1180
+ largePlayerSkipBackwardButtons[i].addEventListener('click', function(event) {
1181
+ var currentTime, playerState, skipOffset, ytPlayer;
1182
+
1183
+ skipOffset = parseFloat(playerForwardBackwardSkipSeconds);
1184
+ ytPlayer = j1.adapter.amplitude['data']['ytPlayers'][ytPlayerID].player;
1185
+ playerState = ytPlayer.getPlayerState();
1186
+ currentTime = ytPlayer.getCurrentTime();
1187
+
1188
+ if (playerState === YT_PLAYER_STATE.PLAYING || playerState === YT_PLAYER_STATE.PAUSED) {
1189
+ ytPlayer.seekTo(currentTime - skipOffset, true);
1190
+ }
1191
+
1192
+ // deactivate AJS events (if any)
1193
+ event.stopImmediatePropagation();
1194
+ }); // END Listener 'click'
1195
+ } // END if skip-backward button
1196
+ } // END for
1197
+
1198
+ // click on (player) next button
1199
+ // TODO: Fix for multiple players in page
1200
+ // --------------------------------------------------------------------
1201
+
1202
+ // Overload AJS largePlayerNext button for YT
1203
+ //
1204
+ var largePlayerNextButton = document.getElementsByClassName("large-player-next");
1205
+ for (var i=0; i<largePlayerNextButton.length; i++) {
1206
+ var classArray = [].slice.call(largePlayerNextButton[i].classList, 0);
1207
+ var classString = classArray.toString();
1208
+
1209
+ if (classString.includes(ytPlayerID)) {
1210
+ largePlayerNextButton[i].addEventListener('click', function(event) {
1211
+ var ytpVideoID;
1212
+ var playlist = this.getAttribute("data-amplitude-playlist");
1213
+ var playerID = playlist + '_large';
1214
+ // var songIndex = parseInt(j1.adapter.amplitude.data.ytPlayers[playerID].activeIndex);
1215
+ var songIndex = ytpSongIndex;
1216
+ var songs = j1.adapter.amplitude.data.ytPlayers[playerID].songs;
1217
+ var ytPlayer = j1.adapter.amplitude.data.ytPlayers[playerID].player;
1218
+
1219
+ // var songs = j1.adapter.amplitude['data']['ytPlayers'][playerID].songs
1220
+ // var ytPlayer = j1.adapter.amplitude['data']['ytPlayers'][playerID].player;
1221
+
1222
+ // if (songIndex < songs.length) {
1223
+ if (songIndex < songs.length-1) {
1224
+ // set song on next item
1225
+ songIndex++;
1226
+ ytpSongIndex = songIndex;
1227
+
1228
+ // j1.adapter.amplitude.data.ytPlayers[playerID].activeIndex = songIndex;
1229
+ }
1230
+ // else {
1231
+ // songIndex--;
1232
+ // }
1233
+
1234
+ // collect (next) song data
1235
+ // if (songIndex < songs.length) {
1236
+ if (songIndex < songs.length-1) {
1237
+ songMetaData = songs[songIndex];
1238
+ songURL = songMetaData.url;
1239
+ ytpVideoID = songURL.split('=')[1];
1240
+ } else {
1241
+ songIndex = 0;
1242
+ // j1.adapter.amplitude.data.ytPlayers[playerID].activeIndex = songIndex;
1243
+ songMetaData = songs[songIndex];
1244
+ songURL = songMetaData.url;
1245
+ ytpVideoID = songURL.split('=')[1];
1246
+ }
1247
+
1248
+ // pause song (video) if FIRST item reached
1249
+ // TODO: handle on player|shuffle different (do play)
1250
+ if (songMetaData.index === 0) {
1251
+
1252
+ // continue (paused) on FIRST video
1253
+ if (ytPlayer !== undefined) {
1254
+ ytPlayer.loadVideoById(ytpVideoID);
1255
+
1256
+ // wait some time to make sure video is loaded|active
1257
+ setTimeout(() => {
1258
+ ytPlayer.pauseVideo();
1259
+ // reset|update time settings
1260
+ resetCurrentTimeContainerYTP();
1261
+ updateDurationTimeContainerYTP(ytPlayer);
1262
+ // resetProgressBarYTP(playerID);
1263
+
1264
+ // update AJS play_pause button
1265
+ var largePlayerPlayPauseButton = document.getElementById('large_player_play_pause');
1266
+ largePlayerPlayPauseButton.classList.remove('amplitude-playing');
1267
+ largePlayerPlayPauseButton.classList.add('amplitude-paused');
1268
+ }, 300);
1269
+ }
1270
+ } else {
1271
+ // load NEXT video if available
1272
+ if (ytPlayer !== undefined) {
1273
+ ytPlayer.loadVideoById(ytpVideoID);
1274
+
1275
+ // update AJS play_pause button (set playing)
1276
+ var largePlayerPlayPauseButton = document.getElementById('large_player_play_pause');
1277
+ largePlayerPlayPauseButton.classList.remove('amplitude-paused');
1278
+ largePlayerPlayPauseButton.classList.add('amplitude-playing');
1279
+ } else {
1280
+ // update AJS play_pause button (set paused)
1281
+ var largePlayerPlayPauseButton = document.getElementById('large_player_play_pause');
1282
+ largePlayerPlayPauseButton.classList.remove('amplitude-playing');
1283
+ largePlayerPlayPauseButton.classList.add('amplitude-paused');
1284
+ }
1285
+ }
1286
+
1287
+ // reset|update current time settings
1288
+ resetCurrentTimeContainerYTP();
1289
+ updateDurationTimeContainerYTP(ytPlayer);
1290
+
1291
+ // load cover image for next video
1292
+ var coverImage;
1293
+ var selector = ".cover-image-" + playlist;
1294
+ coverImage = document.querySelector(selector);
1295
+ coverImage.src = songMetaData.cover_art_url;
1296
+
1297
+ // replace new song name (meta-container)
1298
+ var songName = document.getElementsByClassName("song-name");
1299
+ songName[0].innerHTML = songMetaData.name; // player-bottom
1300
+ songName[1].innerHTML = songMetaData.name; // playlist-screen
1301
+
1302
+ // replace song rating (playlist-screen|meta-container)
1303
+ var largetPlayerSongAudioRating = document.getElementsByClassName("audio-rating");
1304
+ if (largetPlayerSongAudioRating.length) {
1305
+ if (songMetaData.rating) {
1306
+ largetPlayerSongAudioRating[0].innerHTML = songMetaData.rating + ' <i class="mdib mdib-star md-gray-400 mdib-18px"></i>';
1307
+ } else {
1308
+ largetPlayerSongAudioRating[0].innerHTML = '';
1309
+ }
1310
+ } // END if largetPlayerSongAudioRating
1311
+
1312
+ // replace artist name in meta-containers for next video
1313
+ var artistName = document.getElementsByClassName("artist");
1314
+ artistName[0].innerHTML = songMetaData.artist;
1315
+
1316
+ // replace album name in meta-containers for next video
1317
+ var albumName = document.getElementsByClassName("album");
1318
+ albumName[0].innerHTML = songMetaData.album;
1319
+
1320
+ // update AJS play_pause button
1321
+ var largePlayerPlayPauseButton = document.getElementById('large_player_play_pause');
1322
+ largePlayerPlayPauseButton.classList.remove('amplitude-paused');
1323
+ largePlayerPlayPauseButton.classList.add('amplitude-playing');
1324
+
1325
+ // if (songIndex < songs.length) {
1326
+ if (songIndex < songs.length-1) {
1327
+ // set song active in playlist
1328
+ // setSongPlayed(songIndex);
1329
+ setSongPlayed(playerID, songIndex);
1330
+ // j1.adapter.amplitude.data.ytPlayers[playerID].activeIndex = songIndex;
1331
+ }
1332
+
1333
+ // deactivate AJS events (if any)
1334
+ event.stopImmediatePropagation();
1335
+ }); // END EventListener 'click' next button
1336
+ } // END if
1337
+ } // END for largePlayerNextButton
1338
+
1339
+ // click on (player) previous button
1340
+ // TODO: Fix for multiple players in page
1341
+ // -----------------------------------------------------------------------
1342
+
1343
+ // Overload AJS largePlayerPrevious button for YT
1344
+ //
1345
+ var largePlayePreviousButton = document.getElementsByClassName("large-player-previous");
1346
+ for (var i=0; i<largePlayePreviousButton.length; i++) {
1347
+ var classArray = [].slice.call(largePlayerNextButton[i].classList, 0);
1348
+ var classString = classArray.toString();
1349
+
1350
+ if (classString.includes(ytPlayerID)) {
1351
+ largePlayePreviousButton[i].addEventListener('click', function(event) {
1352
+ var ytpVideoID;
1353
+ var playlist = this.getAttribute("data-amplitude-playlist");
1354
+ var playerID = playlist + '_large';
1355
+ // var songIndex = parseInt(j1.adapter.amplitude.data.ytPlayers[playerID].activeIndex);
1356
+ var songIndex = ytpSongIndex;
1357
+ var songs = j1.adapter.amplitude.data.ytPlayers[playerID].songs;
1358
+ var ytPlayer = j1.adapter.amplitude.data.ytPlayers[playerID].player;
1359
+
1360
+ if (songIndex < songs.length-1) {
1361
+ // set song on previous item
1362
+ songIndex--;
1363
+ ytpSongIndex = songIndex;
1364
+ // j1.adapter.amplitude.data.ytPlayers[playerID].activeIndex = songIndex;
1365
+ }
1366
+
1367
+ // collect (next) song data
1368
+ if (songIndex > 0 && songIndex < songs.length) {
1369
+ songMetaData = songs[songIndex];
1370
+ songIndex = songMetaData.index;
1371
+ songURL = songMetaData.url;
1372
+ ytpSongIndex = songMetaData.index;
1373
+ ytpVideoID = songURL.split('=')[1];
1374
+ } else {
1375
+ songIndex = 0;
1376
+ ytpSongIndex = 0;
1377
+ // j1.adapter.amplitude.data.ytPlayers[playerID].activeIndex = songIndex;
1378
+ songMetaData = songs[songIndex];
1379
+ songURL = songMetaData.url;
1380
+ ytpSongIndex = songIndex;
1381
+ ytpVideoID = songURL.split('=')[1];
1382
+ }
1383
+
1384
+ // save YT player data for later use (e.g. events)
1385
+ // j1.adapter.amplitude.data.ytpGlobals['ytpSongIndex'] = ytpSongIndex;
1386
+
1387
+ // pause song (video) if FIRST item reached
1388
+ // TODO: handle on player|shuffle different (do play)
1389
+ if (songMetaData.index === 0) {
1390
+ ytpSongIndex = 0;
1391
+
1392
+ // continue (paused) on FIRST video
1393
+ if (ytPlayer !== undefined) {
1394
+ ytPlayer.loadVideoById(ytpVideoID);
1395
+
1396
+ // wait some time to make sure video is loaded|active
1397
+ setTimeout(() => {
1398
+ ytPlayer.pauseVideo();
1399
+ // reset|update time settings
1400
+ resetCurrentTimeContainerYTP();
1401
+ updateDurationTimeContainerYTP(ytPlayer);
1402
+ resetProgressBarYTP(playerID);
1403
+
1404
+ // update AJS play_pause button
1405
+ var largePlayerPlayPauseButton = document.getElementById('large_player_play_pause');
1406
+ largePlayerPlayPauseButton.classList.remove('amplitude-playing');
1407
+ largePlayerPlayPauseButton.classList.add('amplitude-paused');
1408
+ }, 300);
1409
+ }
1410
+ } else {
1411
+ // load NEXT video if available
1412
+ if (ytPlayer !== undefined) {
1413
+ ytPlayer.loadVideoById(ytpVideoID);
1414
+
1415
+ // update AJS play_pause button (set playing)
1416
+ var largePlayerPlayPauseButton = document.getElementById('large_player_play_pause');
1417
+ largePlayerPlayPauseButton.classList.remove('amplitude-paused');
1418
+ largePlayerPlayPauseButton.classList.add('amplitude-playing');
1419
+ } else {
1420
+ // update AJS play_pause button (set paused)
1421
+ var largePlayerPlayPauseButton = document.getElementById('large_player_play_pause');
1422
+ largePlayerPlayPauseButton.classList.remove('amplitude-playing');
1423
+ largePlayerPlayPauseButton.classList.add('amplitude-paused');
1424
+ }
1425
+ }
1426
+
1427
+ // reset|update current time settings
1428
+ resetCurrentTimeContainerYTP();
1429
+ updateDurationTimeContainerYTP(ytPlayer);
1430
+
1431
+ // replace new song name (meta-container)
1432
+ var songName = document.getElementsByClassName("song-name");
1433
+ songName[0].innerHTML = songMetaData.name; // player-bottom
1434
+ songName[1].innerHTML = songMetaData.name; // playlist-screen
1435
+
1436
+ // load cover image for next video
1437
+ var coverImage;
1438
+ var selector = ".cover-image-" + playlist;
1439
+ coverImage = document.querySelector(selector);
1440
+ coverImage.src = songMetaData.cover_art_url;
1441
+
1442
+ // replace song rating (playlist-screen|meta-container)
1443
+ var largetPlayerSongAudioRating = document.getElementsByClassName("audio-rating");
1444
+ if (largetPlayerSongAudioRating.length) {
1445
+ if (songMetaData.rating) {
1446
+ largetPlayerSongAudioRating[0].innerHTML = songMetaData.rating + ' <i class="mdib mdib-star md-gray-400 mdib-18px"></i>';
1447
+ } else {
1448
+ largetPlayerSongAudioRating[0].innerHTML = '';
1449
+ }
1450
+ } // END if largetPlayerSongAudioRating
1451
+
1452
+ // replace artist name in meta-containers for next video
1453
+ var artistName = document.getElementsByClassName("artist");
1454
+ artistName[0].innerHTML = songMetaData.artist;
1455
+
1456
+ // replace album name in meta-containers for next video
1457
+ var albumName = document.getElementsByClassName("album");
1458
+ albumName[0].innerHTML = songMetaData.album;
1459
+
1460
+ // update AJS play_pause button
1461
+ var largePlayerPlayPauseButton = document.getElementById('large_player_play_pause');
1462
+ largePlayerPlayPauseButton.classList.remove('amplitude-paused');
1463
+ largePlayerPlayPauseButton.classList.add('amplitude-playing');
1464
+
1465
+ // on LAST item, don't activate item in playlist
1466
+ if (songIndex !== songs.length - 1) {
1467
+ // set song active in playlist
1468
+ // setSongPlayed(songIndex);
1469
+ setSongPlayed(playerID, songIndex);
1470
+ }
1471
+
1472
+ // set song active in playlist
1473
+ // setSongPlayed(songIndex);
1474
+ // setSongPlayed(playerID, songIndex);
1475
+
1476
+ // deactivate AJS events (if any)
1477
+ event.stopImmediatePropagation();
1478
+ }); // END EventListener 'click' previous button
1479
+ } // END if
1480
+ } // END for
1481
+
1482
+ // click on song container
1483
+ // TODO: Fix for multiple players in page
1484
+ // ---------------------------------------------------------------------
1485
+ var largetPlayerSongContainer = document.getElementsByClassName("amplitude-song-container");
1486
+ for (var i=0; i<largetPlayerSongContainer.length; i++) {
1487
+ var classArray = [].slice.call(largetPlayerSongContainer[i].classList, 0);
1488
+ var classString = classArray.toString();
1489
+
1490
+ if (classString.includes(ytPlayerID)) {
1491
+ largetPlayerSongContainer[i].addEventListener('click', function(event) {
1492
+ var ytpVideoID;
1493
+ var activeSongIndex;
1494
+ var success;
1495
+
1496
+ var playlist = this.getAttribute("data-amplitude-playlist");
1497
+ var playerID = playlist + '_large';
1498
+ // var ytpSongIndex = parseInt(this.getAttribute("data-amplitude-song-index"));
1499
+ var songs = j1.adapter.amplitude.data.ytPlayers[playerID].songs;
1500
+
1501
+ // update global song index
1502
+ ytpSongIndex = parseInt(this.getAttribute("data-amplitude-song-index"));
1503
+
1504
+ // get active song index if video (song) is playing
1505
+ activeSongIndex = getSongPlayed();
1506
+
1507
+ // if (activeSongIndex >= 0) {
1508
+ // success = ytpSetActiveIndex(playerID, activeSongIndex);
1509
+ // } else {
1510
+ // success = ytpSetActiveIndex(playerID, ytpSongIndex);
1511
+ // }
1512
+
1513
+ // save YT player data for later use (e.g. events)
1514
+ // j1.adapter.amplitude.data.ytpGlobals['ytPlayerSongs'] = songs;
1515
+ // j1.adapter.amplitude.data.ytpGlobals['ytpSongIndex'] = ytpSongIndex;
1516
+
1517
+ var playerState = ytPlayer.getPlayerState();
1518
+ if (playerState === YT_PLAYER_STATE.PLAYING && ytpSongIndex === activeSongIndex) {
1519
+ // do NOT interupt current video (song) is playing
1520
+ return;
1521
+ } else {
1522
+ // set (current) song data
1523
+ songMetaData = songs[ytpSongIndex];
1524
+ songIndex = songMetaData.index;
1525
+ songURL = songMetaData.url;
1526
+ ytpSongIndex = songIndex;
1527
+ ytpVideoID = songURL.split('=')[1];
1528
+ // load new video
1529
+ ytPlayer.loadVideoById(ytpVideoID);
1530
+ }
1531
+
1532
+ // reset|update current time settings
1533
+ resetCurrentTimeContainerYTP();
1534
+ updateDurationTimeContainerYTP(ytPlayer);
1535
+
1536
+ // load cover image for next video
1537
+ var coverImage;
1538
+ var selector = ".cover-image-" + playlist;
1539
+ coverImage = document.querySelector(selector);
1540
+ coverImage.src = songMetaData.cover_art_url;
1541
+
1542
+ // replace new song name (meta-container)
1543
+ var songName = document.getElementsByClassName("song-name");
1544
+ songName[0].innerHTML = songMetaData.name; // player-bottom
1545
+ songName[1].innerHTML = songMetaData.name; // playlist-screen
1546
+
1547
+ // replace song info URL (playlist-screen|meta-container)
1548
+ var largetPlayerSongInfoLink = document.getElementsByClassName("audio-info-link");
1549
+ if (largetPlayerSongInfoLink.length) {
1550
+ if (songMetaData.audio_info) {
1551
+ largetPlayerSongInfoLink[0].href = songMetaData.audio_info;
1552
+ } else {
1553
+ largetPlayerSongInfoLink[0].href = songURL;
1554
+ }
1555
+ } // END if largetPlayerSongInfoLink
1556
+
1557
+ // replace song rating (playlist-screen|meta-container)
1558
+ var largetPlayerSongAudioRating = document.getElementsByClassName("audio-rating");
1559
+ if (largetPlayerSongAudioRating.length) {
1560
+ if (songMetaData.rating) {
1561
+ largetPlayerSongAudioRating[0].innerHTML = songMetaData.rating + ' <i class="mdib mdib-star md-gray-400 mdib-18px"></i>';
1562
+ } else {
1563
+ largetPlayerSongAudioRating[0].innerHTML = '';
1564
+ }
1565
+ } // END if largetPlayerSongAudioRating
1566
+
1567
+ // update AJS play_pause button
1568
+ var largePlayerPlayPauseButton = document.getElementById('large_player_play_pause');
1569
+ largePlayerPlayPauseButton.classList.remove('amplitude-paused');
1570
+ largePlayerPlayPauseButton.classList.add('amplitude-playing');
1571
+
1572
+ // set song active in playlist
1573
+ // if (event.currentTarget.className.includes(ytPlayerID)) {
1574
+ // setSongPlayed(songIndex);
1575
+ // }
1576
+
1577
+ // set song active in playlist
1578
+ setSongPlayed(ytPlayerID, songIndex);
1579
+
1580
+ // do NOT bubble up
1581
+ event.stopPropagation();
1582
+
1583
+ // deactivate AJS events (if any)
1584
+ event.stopImmediatePropagation();
1585
+ }); // END EventListener 'click' SongContainer
1586
+ } // END if
1587
+ } // END for
1588
+
1589
+ // add listeners to all progress bars found
1590
+ // TODO: Fix for multiple players in page
1591
+ // ---------------------------------------------------------------------
1592
+ var progressBars = document.getElementsByClassName("large-player-progress");
1593
+ if (progressBars.length) {
1594
+ for (var i=0; i<progressBars.length; i++) {
1595
+ var progressBar = progressBars[i];
1596
+ // var id = bar.id.split('large-player-progress_')[0];
1597
+ // var progressId = progressBars[i].id.split('large-player-progress_')[0];
1598
+ var progressId = progressBars[i].id;
1599
+ var playerId = progressId.split('large_player_progress_')[1];
1600
+
1601
+ // save YT player data for later use (e.g. events)
1602
+ // j1.adapter.amplitude.data.ytpGlobals['ytPlayerProgressBar'] = progressBars[i];
1603
+ // j1.adapter.amplitude.data.ytPlayers[playerId].progressBar = progressId;
1604
+ j1.adapter.amplitude.data.ytPlayers[playerId].progressBar = progressBar;
1605
+
1606
+ progressBars[i].addEventListener('click', function(event) {
1607
+ // if (ytPlayer.getPlayerState() === YT_PLAYER_STATE.PLAYING) {
1608
+ if (ytPlayer !== undefined) {
1609
+ var progressBar, percentage, time;
1610
+ progressBar = this;
1611
+ percentage = getProgressBarSelectedPositionPercentage(event, progressBar);
1612
+ time = getTimeFromPercentage(ytPlayer, percentage);
1613
+
1614
+ // seek video to current time
1615
+ ytpSeekTo(ytPlayer, time);
1616
+
1617
+ // set current progess value if valid
1618
+ if (isFinite(percentage)) {
1619
+ progressBar.value = percentage;
1620
+ }
1621
+ } // END if ytPlayer
1622
+
1623
+ // deactivate AJS events (if any)
1624
+ event.stopImmediatePropagation();
1625
+ }); // END EventListener 'click'
1626
+ } // END for
1627
+ } // END if progressBars
1628
+
1629
+ } // END if playerType large'
1630
+ }
1631
+ } // END mimikYTPlayerUiEventsForAJS
1632
+
1633
+ {%- endcapture -%}
1634
+
1635
+ {%- if production -%}
1636
+ {{ cache|minifyJS }}
1637
+ {%- else -%}
1638
+ {{ cache|strip_empty_lines }}
1639
+ {%- endif -%}
1640
+
1641
+ {%- assign cache = false -%}