j1-template 2024.3.19 → 2024.3.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/_layouts/page.html +1 -0
  3. data/assets/data/amplitude_app.html +192 -163
  4. data/assets/data/swiper_app.2.html +757 -0
  5. data/assets/data/swiper_app.4.html +769 -0
  6. data/assets/data/swiper_app.html +171 -27
  7. data/assets/theme/j1/adapter/js/amplitude.js +1104 -216
  8. data/assets/theme/j1/adapter/js/swiper.js +63 -15
  9. data/assets/theme/j1/core/css/themes/bootstrap/bootstrap.css +111 -101
  10. data/assets/theme/j1/core/css/themes/bootstrap/bootstrap.min.css +1 -1
  11. data/assets/theme/j1/core/css/themes/unodark/bootstrap.css +111 -101
  12. data/assets/theme/j1/core/css/themes/unodark/bootstrap.min.css +1 -1
  13. data/assets/theme/j1/core/css/themes/unolight/bootstrap.css +111 -101
  14. data/assets/theme/j1/core/css/themes/unolight/bootstrap.min.css +1 -1
  15. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/amplitude.css +177 -216
  16. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/amplitude.min.css +1 -1
  17. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/player/compact.css +220 -339
  18. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/player/compact.min.css +1 -2
  19. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/player/large.css +324 -491
  20. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/player/large.min.css +1 -2
  21. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/player/mini.css +70 -60
  22. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/player/mini.min.css +2 -1
  23. data/assets/theme/j1/modules/amplitudejs/js/tech/ytp.js +2074 -843
  24. data/assets/theme/j1/modules/amplitudejs/scss/theme/uno/dark/player/large.scss +439 -264
  25. data/assets/theme/j1/modules/swiperjs/css/modules/layoutBase.css +16 -0
  26. data/assets/theme/j1/modules/swiperjs/css/modules/layoutBase.min.css +16 -0
  27. data/assets/theme/j1/modules/swiperjs/css/modules/layoutExpanding.css +24 -24
  28. data/assets/theme/j1/modules/swiperjs/css/modules/layoutExpanding.min.css +1 -235
  29. data/assets/theme/j1/modules/swiperjs/css/modules/layoutNeighbor.min.css +2 -2
  30. data/assets/theme/j1/modules/swiperjs/css/modules/layoutParallax.css +16 -0
  31. data/assets/theme/j1/modules/swiperjs/css/modules/layoutParallax.min.css +16 -0
  32. data/assets/theme/j1/modules/swiperjs/css/modules/layoutStacked.css +6 -7
  33. data/assets/theme/j1/modules/swiperjs/css/modules/layoutStacked.min.css +1 -82
  34. data/assets/theme/j1/modules/swiperjs/css/modules/layoutThumbs.min.css +2 -29
  35. data/assets/theme/j1/modules/swiperjs/css/theme/uno.css +29 -12
  36. data/assets/theme/j1/modules/swiperjs/css/theme/uno.min.css +1 -1
  37. data/assets/theme/j1/modules/swiperjs/js/modules/layoutBase.js +25 -0
  38. data/assets/theme/j1/modules/swiperjs/js/modules/layoutBase.min.js +25 -0
  39. data/assets/theme/j1/modules/swiperjs/js/modules/layoutExpanding.js +1 -5
  40. data/assets/theme/j1/modules/swiperjs/js/modules/layoutExpanding.min.js +1 -5
  41. data/assets/theme/j1/modules/swiperjs/js/modules/layoutNeighbor.js +12 -14
  42. data/assets/theme/j1/modules/swiperjs/js/modules/layoutNeighbor.min.js +1 -17
  43. data/assets/theme/j1/modules/swiperjs/js/modules/layoutPanorama.js +0 -1
  44. data/assets/theme/j1/modules/swiperjs/js/modules/layoutParallax.js +25 -0
  45. data/assets/theme/j1/modules/swiperjs/js/modules/layoutParallax.min.js +25 -0
  46. data/assets/theme/j1/modules/swiperjs/js/modules/layoutStacked.0.js +114 -0
  47. data/assets/theme/j1/modules/swiperjs/js/modules/layoutStacked.1.js +93 -0
  48. data/assets/theme/j1/modules/swiperjs/js/modules/layoutStacked.js +42 -13
  49. data/assets/theme/j1/modules/swiperjs/js/modules/layoutStacked.min.js +17 -0
  50. data/assets/theme/j1/modules/swiperjs/js/modules/layoutThumbs.js +76 -25
  51. data/assets/theme/j1/modules/swiperjs/js/modules/layoutThumbs.min.js +1 -17
  52. data/assets/theme/j1/modules/swiperjs/js/swiper-bundle.js +9152 -9131
  53. data/assets/theme/j1/modules/swiperjs/js/swiper-bundle.min.js +1 -1
  54. data/lib/j1/version.rb +1 -1
  55. data/lib/starter_web/README.md +5 -5
  56. data/lib/starter_web/_config.yml +1 -1
  57. data/lib/starter_web/_data/modules/amplitude_app.yml +206 -23
  58. data/lib/starter_web/_data/modules/amplitude_playlists.yml +1122 -19
  59. data/lib/starter_web/_data/modules/defaults/{amplitude_app.yml → amplitude.yml} +73 -26
  60. data/lib/starter_web/_data/modules/swiper_app.yml +356 -155
  61. data/lib/starter_web/_data/modules/swiper_playlists.yml +77 -1
  62. data/lib/starter_web/_data/resources.yml +6 -2
  63. data/lib/starter_web/_data/templates/feed.xml +1 -1
  64. data/lib/starter_web/_includes/attributes.asciidoc +5 -4
  65. data/lib/starter_web/_plugins/filter/filters.rb +1 -11
  66. data/lib/starter_web/_plugins/index/lunr.rb +1 -1
  67. data/lib/starter_web/assets/image/icon/bokeh/bokeh-32x32.ico +0 -0
  68. data/lib/starter_web/assets/image/icon/bokeh/bokeh.ico +0 -0
  69. data/lib/starter_web/assets/image/icon/bokeh/logo-160x160.png +0 -0
  70. data/lib/starter_web/assets/image/icon/hyvor-talk/hyvore-talk.ico +0 -0
  71. data/lib/starter_web/assets/image/icon/hyvor-talk/jpg/hyvor-logo.512x512.jpg +0 -0
  72. data/lib/starter_web/assets/image/icon/hyvor-talk/png/hyvor-logo.24x24.jpg +0 -0
  73. data/lib/starter_web/assets/image/icon/hyvor-talk/png/hyvor-logo.24x24.png +0 -0
  74. data/lib/starter_web/assets/image/icon/hyvor-talk/png/hyvor-logo.512x512.png +0 -0
  75. data/lib/starter_web/assets/image/icon/hyvor-talk/scalable/hyvor-logo.svg +81 -0
  76. data/lib/starter_web/assets/image/icon/jupyter/jupyter-32x32.ico +0 -0
  77. data/lib/starter_web/assets/image/icon/jupyter/jupyter.ico +0 -0
  78. data/lib/starter_web/assets/image/icon/jupyter/logo.png +0 -0
  79. data/lib/starter_web/assets/image/icon/mdi/mdi.svg +1 -0
  80. data/lib/starter_web/assets/image/icon/mdi/mdil.svg +1 -0
  81. data/lib/starter_web/assets/image/icon/scalable/facebook.svg +34 -0
  82. data/lib/starter_web/assets/image/icon/scalable/google.svg +35 -0
  83. data/lib/starter_web/assets/image/icon/scalable/ibm.svg +24 -0
  84. data/lib/starter_web/assets/image/icon/scalable/microsoft.svg +42 -0
  85. data/lib/starter_web/assets/image/module/swiper/avatar/avatar-1.png +0 -0
  86. data/lib/starter_web/assets/image/module/swiper/avatar/avatar-2.png +0 -0
  87. data/lib/starter_web/assets/image/module/swiper/avatar/avatar-3.png +0 -0
  88. data/lib/starter_web/assets/image/module/swiper/avatar/avatar-4.png +0 -0
  89. data/lib/starter_web/assets/image/module/swiper/avatar/avatar-5.png +0 -0
  90. data/lib/starter_web/assets/image/module/swiper/simple/test/image/diana_krall.jpg +0 -0
  91. data/lib/starter_web/index.html +3 -3
  92. data/lib/starter_web/package.json +1 -1
  93. data/lib/starter_web/pages/public/learn/where_to_go.adoc +1 -1
  94. data/lib/starter_web/pages/public/tools/previewer/preview_amplitudejs.adoc +69 -36
  95. data/lib/starter_web/pages/public/tools/tester/app_tester_amplitudejs_yt.adoc +65 -18
  96. data/lib/starter_web/pages/public/tools/tester/app_tester_swiper.adoc +87 -0
  97. data/lib/starter_web/pages/public/tools/tester/app_tester_swiperjs.adoc +121 -36
  98. data/lib/starter_web/pages/public/tour/_includes/attributes.asciidoc +3 -3
  99. data/lib/starter_web/pages/public/tour/{play_audio.adoc → audio_data.adoc} +51 -86
  100. data/lib/starter_web/pages/public/tour/{present_images.adoc → image_data.adoc} +4 -5
  101. data/lib/starter_web/pages/public/tour/{play_video.adoc → video_data.adoc} +18 -17
  102. metadata +52 -17
  103. data/assets/theme/j1/modules/swiperjs/js/highlightJS.js +0 -13376
  104. data/assets/theme/j1/modules/swiperjs/js/highlightJS.min.js +0 -1246
  105. data/assets/theme/j1/modules/swiperjs/js/modules/!readme +0 -3
  106. /data/lib/starter_web/assets/image/module/swiper/extended/{poster → stacked}/!info/!readme +0 -0
  107. /data/lib/starter_web/assets/image/module/swiper/extended/{poster → stacked}/image/!readme +0 -0
  108. /data/lib/starter_web/assets/image/module/swiper/extended/{poster → stacked}/image/1.jpg +0 -0
  109. /data/lib/starter_web/assets/image/module/swiper/extended/{poster → stacked}/image/2.jpg +0 -0
  110. /data/lib/starter_web/assets/image/module/swiper/extended/{poster → stacked}/image/3.jpg +0 -0
  111. /data/lib/starter_web/assets/image/module/swiper/extended/{poster → stacked}/image/4.jpg +0 -0
  112. /data/lib/starter_web/assets/image/module/swiper/extended/{poster → stacked}/image/5.jpg +0 -0
  113. /data/lib/starter_web/assets/image/module/swiper/extended/{poster → stacked}/image/6.jpg +0 -0
@@ -6,7 +6,7 @@ regenerate: true
6
6
 
7
7
  {% comment %}
8
8
  # -----------------------------------------------------------------------------
9
- # ~/assets/theme/j1/adapter/js/amplitude.js
9
+ # ~/assets/theme/j1/adapter/js/amplitude.40.js
10
10
  # Liquid template to adapt J1 AmplitudeJS Apps
11
11
  #
12
12
  # Product/Info:
@@ -41,7 +41,7 @@ regenerate: true
41
41
 
42
42
  {% comment %} Set config data (settings only)
43
43
  -------------------------------------------------------------------------------- {% endcomment %}
44
- {% assign amplitude_defaults = modules.defaults.amplitude_app.defaults %}
44
+ {% assign amplitude_defaults = modules.defaults.amplitude.defaults %}
45
45
  {% assign amplitude_players = modules.amplitude_app.settings %}
46
46
  {% assign amplitude_playlists = modules.amplitude_playlists.settings %}
47
47
 
@@ -63,7 +63,7 @@ regenerate: true
63
63
 
64
64
  /*
65
65
  # -----------------------------------------------------------------------------
66
- # ~/assets/theme/j1/adapter/js/amplitude.js
66
+ # ~/assets/theme/j1/adapter/js/amplitude.40.js
67
67
  # J1 Adapter for the amplitude module
68
68
  #
69
69
  # Product/Info:
@@ -83,8 +83,8 @@ regenerate: true
83
83
  // -----------------------------------------------------------------------------
84
84
  /* eslint indent: "off" */
85
85
  // -----------------------------------------------------------------------------
86
-
87
86
  "use strict";
87
+
88
88
  j1.adapter.amplitude = ((j1, window) => {
89
89
 
90
90
  // global settings
@@ -97,17 +97,6 @@ j1.adapter.amplitude = ((j1, window) => {
97
97
  // module settings
98
98
  // ---------------------------------------------------------------------------
99
99
 
100
- // YT player settings
101
- // ---------------------------------------------------------------------------
102
- // const YT_PLAYER_STATE = {
103
- // not_started: -1,
104
- // ended: 0,
105
- // playing: 1,
106
- // paused: 2,
107
- // buffering: 3,
108
- // video_cued: 5
109
- // };
110
-
111
100
  // control|logging
112
101
  // ---------------------------------------------------------------------------
113
102
  var _this;
@@ -126,22 +115,39 @@ j1.adapter.amplitude = ((j1, window) => {
126
115
 
127
116
  // AmplitudeJS API settings
128
117
  // ---------------------------------------------------------------------------
129
- var ytpSongIndex = "0";
130
- var ytpAutoPlay = false;
131
- var ytpLoop = true;
118
+ const AT_PLAYER_STATE = {
119
+ ENDED: 0,
120
+ PLAYING: 1,
121
+ PAUSED: 2,
122
+ STOPPED: 3,
123
+ PREVIOUS: 4,
124
+ NEXT: 5,
125
+ CHANGED: 6,
126
+ };
127
+
128
+ const AT_PLAYER_STATE_NAMES = {
129
+ 0: "ended",
130
+ 1: "playing",
131
+ 2: "paused",
132
+ 3: "stopped",
133
+ 4: "previous",
134
+ 5: "next",
135
+ 6: "changed",
136
+ };
137
+
132
138
  var playLists = {};
133
139
  var playersUILoaded = { state: false };
134
140
  var apiInitialized = { state: false };
135
- var playList;
136
- var playerID;
137
- var playerType;
138
- var playListTitle;
139
- var playListName;
141
+
142
+ var isFadingIn = false;
143
+ var isFadingOut = false;
144
+
140
145
  var amplitudePlayerState;
141
146
  var amplitudeDefaults;
142
147
  var amplitudePlayers
143
148
  var amplitudePlaylists
144
149
  var amplitudeOptions;
150
+
145
151
  var ytPlayer;
146
152
  var ytpPlaybackRate
147
153
 
@@ -157,25 +163,30 @@ j1.adapter.amplitude = ((j1, window) => {
157
163
  var playersProcessed = [];
158
164
  var playersHtmlLoaded = false;
159
165
  var processingPlayersFinished = false;
160
- var pluginManagerRunOnce = false;
161
166
 
162
167
  var playerAudioInfo = ('{{amplitude_defaults.playlist.audio_info}}' === 'true') ? true : false;
163
168
  var playerDefaultPluginManager = ('{{amplitude_defaults.player.plugin_manager.enabled}}' === 'true') ? true : false;
164
169
  var playerDefaultType = '{{amplitude_defaults.player.type}}';
165
- var playerVolumeValue = '{{amplitude_defaults.player.volume_slider.preset_value}}';
166
- var playerVolumeSliderStep = '{{amplitude_defaults.player.volume_slider.slider_step}}';
167
- var playerRepeat = ('{{amplitude_defaults.player.repeat}}' === 'true') ? true : false;
168
- var playerShuffle = ('{{amplitude_defaults.player.shuffle}}' === 'true') ? true : false;
170
+ var playerDefaultVolume = {{amplitude_defaults.player.volume_slider.preset_value}};
171
+ var playerVolumeSliderStep = {{amplitude_defaults.player.volume_slider.slider_step}};
172
+ var playerRepeat = ('{{amplitude_defaults.player.player_repeat}}' === 'true') ? true : false;
173
+ var playerShuffle = ('{{amplitude_defaults.player.player_shuffle}}' === 'true') ? true : false;
169
174
  var playerPlayNextTitle = ('{{amplitude_defaults.player.play_next_title}}' === 'true') ? true : false;
170
175
  var playerPauseNextTitle = ('{{amplitude_defaults.player.pause_next_title}}' === 'true') ? true : false;
171
- var playerDelayNextTitle = '{{amplitude_defaults.player.delay_next_title}}';
172
- var playerForwardBackwardSkipSeconds = '{{amplitude_defaults.player.forward_backward_skip_seconds}}';
176
+ var playerDelayNextTitle = {{amplitude_defaults.player.delay_next_title}};
177
+ var playerForwardBackwardSkipSeconds = {{amplitude_defaults.player.forward_backward_skip_seconds}};
178
+
179
+ var playerSongElementHeigthMobile = {{amplitude_defaults.player.song_element_heigth_mobile}};
180
+ var playerSongElementHeigthDesktop = {{amplitude_defaults.player.song_element_heigt_desktop}};
181
+ var playerScrollerSongElementMin = {{amplitude_defaults.player.player_scroller_song_element_min}};
182
+ var playerScrollControl = {{amplitude_defaults.player.player_scroll_control}};
183
+ var playerAutoScrollSongElement = {{amplitude_defaults.player.player_auto_scroll_song_element}};
173
184
 
174
185
  // AmplitudeJS settings curently NOT used
175
186
  // ---------------------------------------------------------------------------
176
- var playerWaveformsEnabled = '{{amplitude_defaults.player.waveforms.enabled}}';
177
- var playerWaveformsSampleRate = '{{amplitude_defaults.player.waveforms.sample_rate}}';
178
- var playerVisualizationEnabled = '{{amplitude_defaults.player.visualization.enabled}}';
187
+ var playerWaveformsEnabled = {{amplitude_defaults.player.waveforms.enabled}};
188
+ var playerWaveformsSampleRate = {{amplitude_defaults.player.waveforms.sample_rate}};
189
+ var playerVisualizationEnabled = {{amplitude_defaults.player.visualization.enabled}};
179
190
  var playerVisualizationName = '{{amplitude_defaults.player.visualization.name}}';
180
191
 
181
192
  // ---------------------------------------------------------------------------
@@ -216,13 +227,21 @@ j1.adapter.amplitude = ((j1, window) => {
216
227
  // -----------------------------------------------------------------------
217
228
  // control|logging settings
218
229
  // -----------------------------------------------------------------------
219
- _this = j1.adapter.amplitude;
220
- logger = log4javascript.getLogger('j1.adapter.amplitude');
230
+ _this = j1.adapter.amplitude;
231
+ logger = log4javascript.getLogger('j1.adapter.amplitude');
221
232
 
222
233
  // prepare data element for later use
223
234
  j1.adapter.amplitude.data = {};
224
- j1.adapter.amplitude.data.ytpGlobals = {};
235
+ j1.adapter.amplitude.data.atpGlobals = {};
236
+ j1.adapter.amplitude.data.ytpGlobals = {};
225
237
  j1.adapter.amplitude.data.ytPlayers = {};
238
+
239
+ // (initial) YT player data for later use (e.g. events)
240
+ j1.adapter.amplitude.data.playerSongElementHeigth = playerSongElementHeigthDesktop;
241
+ j1.adapter.amplitude.data.activePlayer = 'not_set';
242
+ j1.adapter.amplitude.data.atpGlobals.activePlayerType = 'not_set';
243
+ j1.adapter.amplitude.data.atpGlobals.ytpInstalled = false;
244
+ j1.adapter.amplitude.data.ytpGlobals.activePlayerType = 'not_set';
226
245
 
227
246
  // -----------------------------------------------------------------------
228
247
  // module initializer
@@ -231,14 +250,20 @@ j1.adapter.amplitude = ((j1, window) => {
231
250
  var pageState = $('#content').css("display");
232
251
  var pageVisible = (pageState === 'block') ? true : false;
233
252
  var j1CoreFinished = (j1.getState() === 'finished') ? true : false;
253
+ var atticFinished = (j1.adapter.attic.getState() == 'finished') ? true : false;
234
254
 
235
- if (j1CoreFinished && pageVisible) {
255
+ if (j1CoreFinished && pageVisible && atticFinished) {
236
256
  startTimeModule = Date.now();
237
257
 
238
258
  _this.setState('started');
239
259
  logger.debug('\n' + 'module state: ' + _this.getState());
240
260
  logger.info('\n' + 'module is being initialized');
241
261
 
262
+ // window.addEventListener('resize',(e)=>{
263
+ // console.log( `resize: width: ${e.target.visualViewport.width}px`);
264
+ // console.log( `resize: height: ${e.target.visualViewport.height}px`);
265
+ // });
266
+
242
267
  // -------------------------------------------------------------------
243
268
  // create global playlist (songs)
244
269
  // -------------------------------------------------------------------
@@ -263,7 +288,7 @@ j1.adapter.amplitude = ((j1, window) => {
263
288
  }, 10); // END dependencies_met_players_loaded
264
289
 
265
290
  // -------------------------------------------------------------------
266
- // initialize player specific UI events
291
+ // initialize player specific events
267
292
  // -------------------------------------------------------------------
268
293
  var dependencies_met_api_initialized = setInterval (() => {
269
294
  if (apiInitialized.state) {
@@ -273,6 +298,24 @@ j1.adapter.amplitude = ((j1, window) => {
273
298
  } // END if apiInitialized
274
299
  }, 10); // END dependencies_met_api_initialized
275
300
 
301
+ // initialize viewPort specific (GLOBAL) settings
302
+ $(window).bind('resizeEnd', function() {
303
+ var viewPortSize = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0);
304
+ //do something, window hasn't changed size in 500ms
305
+ if (viewPortSize > 578) {
306
+ j1.adapter.amplitude.data.playerSongElementHeigth = playerSongElementHeigthDesktop;
307
+ } else {
308
+ j1.adapter.amplitude.data.playerSongElementHeigth = playerSongElementHeigthMobile;
309
+ }
310
+ });
311
+
312
+ $(window).resize(function() {
313
+ if (this.resizeTO) clearTimeout(this.resizeTO);
314
+ this.resizeTO = setTimeout(function() {
315
+ $(this).trigger('resizeEnd');
316
+ }, 500);
317
+ });
318
+
276
319
  clearInterval(dependencies_met_page_ready);
277
320
  } // END pageVisible
278
321
  }, 10); // END dependencies_met_page_ready
@@ -321,6 +364,12 @@ j1.adapter.amplitude = ((j1, window) => {
321
364
  } else if (key === 'rating') {
322
365
  song.rating = item[key];
323
366
  continue;
367
+ } else if (key === 'audio_single') {
368
+ song.audio_single = item[key];
369
+ continue;
370
+ } else if (key === 'shuffle') {
371
+ song.shuffle = item[key];
372
+ continue;
324
373
  } else {
325
374
  song[key] = item[key];
326
375
  } // END if key
@@ -332,7 +381,7 @@ j1.adapter.amplitude = ((j1, window) => {
332
381
 
333
382
  {% endif %} {% endfor %}
334
383
 
335
- logger.info('\n' + 'creating global playlist (API): finished');
384
+ logger.info('\n' + 'creating global playlist (API): finished');
336
385
  }, // END songLoader
337
386
 
338
387
  // -------------------------------------------------------------------------
@@ -408,6 +457,7 @@ j1.adapter.amplitude = ((j1, window) => {
408
457
  // initApi
409
458
  // -------------------------------------------------------------------------
410
459
  initApi: (songlist) => {
460
+
411
461
  logger.info('\n' + 'initialze API: started');
412
462
 
413
463
  {% comment %} collect playlists
@@ -424,16 +474,26 @@ j1.adapter.amplitude = ((j1, window) => {
424
474
  {% assign playlist_title = list.title %}
425
475
 
426
476
  {% comment %} collect song items
477
+ NOTE: configure all properties avaialble in songs array
427
478
  ------------------------------------------------------------------------ {% endcomment %}
428
479
  {% for item in playlist_items %} {% if item.enabled %}
429
480
  {% capture song_item %}
430
481
  {
431
482
  "name": "{{item.title}}",
483
+ // "track": "{{item.track}}",
432
484
  "artist": "{{item.artist}}",
485
+ "playlist": "{{item.playlist}}",
433
486
  "album": "{{item.name}}",
434
487
  "url": "{{item.audio_base}}/{{item.audio}}",
435
488
  "audio_info": "{{item.audio_info}}",
436
489
  "rating": "{{item.rating}}",
490
+ "start": "{{item.start}}",
491
+ "end": "{{item.end}}",
492
+ "shuffle": "{{item.shuffle}}",
493
+ "duration": "{{item.duration}}",
494
+ "audio_single": "{{item.audio_single}}",
495
+ // "audio_fade_in": "{{item.audio_fade_in}}",
496
+ // "audio_fade_out": "{{item.audio_fade_out}}",
437
497
  "cover_art_url": "{{item.cover_image}}"
438
498
  }{% if forloop.last %}{% else %},{% endif %}
439
499
  {% endcapture %}
@@ -492,26 +552,40 @@ j1.adapter.amplitude = ((j1, window) => {
492
552
  console.error('\n' + 'Amplitude API failed on initialization');
493
553
  },
494
554
  play: function() {
495
- var songMetaData = Amplitude.getActiveSongMetadata();
496
- logger.debug('\n' + 'playing title: ' + songMetaData.name);
497
- document.getElementById('album-art').style.visibility = 'hidden';
498
- document.getElementById('large-visualization').style.visibility = 'visible';
555
+ // make sure the player is playing
556
+ setTimeout(() => {
557
+ onPlayerStateChange(1);
558
+ }, 150);
499
559
  },
500
560
  pause: function() {
501
- var songMetaData = Amplitude.getActiveSongMetadata();
502
- logger.debug('\n' + 'pause title: ' + songMetaData.name);
503
- document.getElementById('album-art').style.visibility = 'visible';
504
- document.getElementById('large-visualization').style.visibility = 'hidden';
561
+ // make sure the player is paused
562
+ setTimeout(() => {
563
+ onPlayerStateChange(2);
564
+ }, 150);
565
+ },
566
+ stop: function() {
567
+ // make sure the player is stopped
568
+ setTimeout(() => {
569
+ onPlayerStateChange(3);
570
+ }, 150);
505
571
  },
506
572
  song_change: function() {
507
- var songMetaData = Amplitude.getActiveSongMetadata();
508
- logger.debug('\n' + 'changed to title: ' + songMetaData.name + ' with titleIndex ' + songMetaData.index);
573
+ // make sure the player has changed
574
+ setTimeout(() => {
575
+ var currentState = Amplitude.getPlayerState();
576
+ if (currentState === 'stopped') {
577
+ // onPlayerStateChange(3);
578
+ return;
579
+ } else {
580
+ onPlayerStateChange(6);
581
+ }
582
+ }, 150);
509
583
  },
510
- next: function() {
511
- var songMetaData = Amplitude.getActiveSongMetadata();
512
-
584
+ prev: function() {
585
+ var currentState = Amplitude.getPlayerState();
586
+ onPlayerStateChange(4);
513
587
  if (playerDelayNextTitle) {
514
- logger.debug('\n' + 'delay on next title: ' + songMetaData.name + ' with titleIndex ' + songMetaData.index);
588
+ logger.debug('\n' + 'delay on previous title: ' + songMetaData.name + ' with titleIndex ' + songMetaData.index);
515
589
  }
516
590
 
517
591
  if (playerPauseNextTitle) {
@@ -524,12 +598,13 @@ j1.adapter.amplitude = ((j1, window) => {
524
598
  }, 150);
525
599
  } // END if playing
526
600
  } // END if pause on next title
527
- },
528
- prev: function() {
529
- var songMetaData = Amplitude.getActiveSongMetadata();
530
601
 
602
+ return;
603
+ },
604
+ next: function() {
605
+ onPlayerStateChange(5);
531
606
  if (playerDelayNextTitle) {
532
- logger.debug('\n' + 'delay on previous title: ' + songMetaData.name + ' with titleIndex ' + songMetaData.index);
607
+ logger.debug('\n' + 'delay on next title: ' + songMetaData.name + ' with titleIndex ' + songMetaData.index);
533
608
  }
534
609
 
535
610
  if (playerPauseNextTitle) {
@@ -542,6 +617,12 @@ j1.adapter.amplitude = ((j1, window) => {
542
617
  }, 150);
543
618
  } // END if playing
544
619
  } // END if pause on next title
620
+
621
+ return;
622
+ },
623
+ ended: function() {
624
+ onPlayerStateChange(0);
625
+ return;
545
626
  }
546
627
  }, // END callbacks
547
628
 
@@ -550,14 +631,399 @@ j1.adapter.amplitude = ((j1, window) => {
550
631
  // },
551
632
 
552
633
  continue_next: playerPlayNextTitle,
553
- volume: playerVolumeValue,
634
+ volume: playerDefaultVolume,
554
635
  volume_decrement: playerVolumeSliderStep,
555
636
  volume_increment: playerVolumeSliderStep
556
637
 
557
638
  }); // END Amplitude init
558
639
 
640
+ // -----------------------------------------------------------------------
641
+ // timestamp2seconds
642
+ //
643
+ // TODO: Add support for timestamp w/o hours like mm:ss
644
+ // -----------------------------------------------------------------------
645
+ function timestamp2seconds(timestamp) {
646
+ // split timestamp
647
+ const parts = timestamp.split(':');
648
+
649
+ // check timestamp format
650
+ if (parts.length !== 3) {
651
+ // return "invalid timestamp";
652
+ return false;
653
+ }
654
+
655
+ // convert parts to integers
656
+ const hours = parseInt(parts[0], 10);
657
+ const minutes = parseInt(parts[1], 10);
658
+ const seconds = parseInt(parts[2], 10);
659
+
660
+ // check valid timestamp values
661
+ if (isNaN(hours) || isNaN(minutes) || isNaN(seconds) ||
662
+ hours < 0 || hours > 23 ||
663
+ minutes < 0 || minutes > 59 ||
664
+ seconds < 0 || seconds > 59) {
665
+ return "invalid timestamp";
666
+ }
667
+
668
+ const totalSeconds = (hours * 3600) + (minutes * 60) + seconds;
669
+
670
+ return totalSeconds;
671
+ } // END timestamp2seconds
672
+
673
+ // -----------------------------------------------------------------------
674
+ // seconds2timestamp
675
+ // -----------------------------------------------------------------------
676
+ function seconds2timestamp(seconds) {
677
+
678
+ if (isNaN(seconds)) {
679
+ return false;
680
+ }
681
+
682
+ const hours = Math.floor(seconds / 3600);
683
+ const minutes = Math.floor((seconds % 3600) / 60);
684
+ const remainSeconds = seconds % 60;
685
+ const tsHours = hours.toString().padStart(2, '0');
686
+ const tsMinutes = minutes.toString().padStart(2, '0');
687
+ const tsSeconds = remainSeconds.toString().padStart(2, '0');
688
+
689
+ return `${tsHours}:${tsMinutes}:${tsSeconds}`;
690
+ } // END seconds2timestamp
691
+
692
+ // -----------------------------------------------------------------------
693
+ // atpFadeInAudio
694
+ // -----------------------------------------------------------------------
695
+ function atpFadeInAudio(params) {
696
+ const cycle = 1;
697
+ var settings, currentStep, steps, sliderID, volumeSlider;
698
+
699
+ isFadingIn = true;
700
+
701
+ // current fade-in settings using DEFAULTS (if available)
702
+ settings = {
703
+ playerID: params.playerID,
704
+ targetVolume: params.targetVolume = 50,
705
+ speed: params.speed = 'default'
706
+ };
707
+
708
+ // number of iteration steps to INCREASE the players volume on fade-in
709
+ // NOTE: number of steps controls how long and smooth the fade-in
710
+ // transition will be
711
+ const iterationSteps = {
712
+ 'default': 150,
713
+ 'slow': 250,
714
+ 'slower': 350,
715
+ 'slowest': 500
716
+ };
717
+
718
+ sliderID = 'volume_slider_' + settings.playerID;
719
+ volumeSlider = document.getElementById(sliderID);
720
+ steps = iterationSteps[settings.speed];
721
+ currentStep = 1;
722
+
723
+ if (volumeSlider === undefined || volumeSlider === null) {
724
+ logger.warn('\n' + 'no volume slider found at playerID: ' + settings.playerID);
725
+ return;
726
+ }
727
+
728
+ // Start the players volume muted
729
+ Amplitude.setVolume(0);
730
+
731
+ const fadeInInterval = setInterval(() => {
732
+ const newVolume = settings.targetVolume * (currentStep / steps);
733
+
734
+ Amplitude.setVolume(newVolume);
735
+ volumeSlider.value = newVolume;
736
+ currentStep++;
737
+
738
+ if (currentStep > steps) {
739
+ isFadingIn = false;
740
+ clearInterval(fadeInInterval);
741
+ }
742
+
743
+ }, cycle);
744
+
745
+ } // END atpFadeInAudio
746
+
747
+ // -----------------------------------------------------------------------
748
+ // atpFadeAudioOut
749
+ //
750
+ // returns true if fade-out is finished
751
+ // -----------------------------------------------------------------------
752
+ function atpFadeAudioOut(params) {
753
+ const cycle = 1;
754
+ var settings, currentStep, steps, sliderID, songs,
755
+ startVolume, newVolume, defaultVolume, volumeSlider;
756
+
757
+ // current fade-out settings using DEFAULTS (if available)
758
+ settings = {
759
+ playerID: params.playerID,
760
+ speed: params.speed = 'default'
761
+ };
762
+
763
+ isFadingOut = true;
764
+
765
+ // number of iteration steps to INCREASE the players volume on fade-in
766
+ // NOTE: number of steps controls how long and smooth the fade-in
767
+ // transition will be
768
+ const iterationSteps = {
769
+ 'default': 150,
770
+ 'slow': 250,
771
+ 'slower': 350,
772
+ 'slowest': 500
773
+ };
774
+
775
+ sliderID = 'volume_slider_' + settings.playerID;
776
+ volumeSlider = document.getElementById(sliderID);
777
+ startVolume = Amplitude.getVolume();
778
+ steps = iterationSteps[settings.speed];
779
+ currentStep = 1;
780
+ defaultVolume = 50;
781
+
782
+ var songMetaData = Amplitude.getActiveSongMetadata();
783
+ var songEndTS = songMetaData.end;
784
+ var playlist = songMetaData.playlist;
785
+ var songIndex = songMetaData.index;
786
+ var trackID = songIndex + 1;
787
+
788
+ if (volumeSlider !== null) {
789
+ const fadeOutInterval = setInterval(() => {
790
+ newVolume = startVolume * (1 - currentStep / steps);
791
+
792
+ Amplitude.setVolume(newVolume);
793
+ volumeSlider.value = newVolume;
794
+ currentStep++;
795
+
796
+ // seek current audio to total end to continue on next track
797
+ if (currentStep > steps) {
798
+ songs = Amplitude.getSongsInPlaylist(playlist);
799
+
800
+ if (songIndex === songs.length-1) {
801
+ logger.debug('\n' + 'restore player volume on last trackID|volume at: ' + trackID + '|' + defaultVolume);
802
+ volumeSlider.value = defaultVolume;
803
+ }
804
+
805
+ isFadingOut = false;
806
+ clearInterval(fadeOutInterval);
807
+ }
808
+ }, cycle);
809
+ } // END if volumeSlider
810
+
811
+ } // END atpFadeAudioOut
812
+
813
+ // -----------------------------------------------------------------------
814
+ // doNothingOnStateChange(state)
815
+ //
816
+ // wrraper for states that are not processed
817
+ // -----------------------------------------------------------------------
818
+ function doNothingOnStateChange(state) {
819
+ var playlist, songMetaData, songIndex, trackID;
820
+
821
+ playlist = Amplitude.getActivePlaylist();
822
+ songMetaData = Amplitude.getActiveSongMetadata();
823
+ songIndex = songMetaData.index;
824
+ trackID = songIndex + 1;
825
+
826
+ logger.warn('\n' + `DO NOTHING on StateChange for playlist: ${playlist} at trackID|state: ${trackID}|${AT_PLAYER_STATE_NAMES[state]}`);
827
+
828
+ } // END doNothingOnStateChange
829
+
830
+ // -----------------------------------------------------------------------
831
+ // processOnStateChangePlaying()
832
+ //
833
+ // wrraper to update the ACTIVE player on state PLAYING
834
+ // -----------------------------------------------------------------------
835
+ function processOnStateChangePlaying(state) {
836
+ var playList, activePlayist, playerID, playerType,
837
+ activePlayerType, startVolume, songIndex, trackID,
838
+ ratingIndex, rating, ratingElement, songMetaData,
839
+ songStartTS, songEndTS, songStartSec, songEndSec,
840
+ screenControlRatingElements, screenControlRating;
841
+
842
+ songMetaData = Amplitude.getActiveSongMetadata();
843
+ songIndex = songMetaData.index;
844
+ playList = Amplitude.getActivePlaylist();
845
+ trackID = songIndex + 1;
846
+ songStartTS = songMetaData.start;
847
+ songEndTS = songMetaData.end;
848
+ songStartSec = timestamp2seconds(songStartTS);
849
+ songEndSec = timestamp2seconds(songEndTS);
850
+ startVolume = Amplitude.getVolume();
851
+
852
+ logger.debug('\n' + `PLAY audio on processOnStateChangePlaying for playlist \'${playList}\' at trackID|state: ${trackID}|${AT_PLAYER_STATE_NAMES[state]}`);
853
+
854
+ // update song rating in playlist-screen|meta-container
855
+ // -------------------------------------------------------------------
856
+ j1.adapter.amplitude.atUpdateSongRating(Amplitude.getActiveSongMetadata());
857
+
858
+ // scroll active song in players playlist
859
+ // ---------------------------------------------------------------------
860
+ j1.adapter.amplitude.atPlayerScrollToActiveElement(Amplitude.getActiveSongMetadata());
861
+
862
+ // stop active YT players
863
+ // -----------------------------------------------
864
+ const ytPlayers = Object.keys(j1.adapter.amplitude.data.ytPlayers);
865
+ for (let i=0; i<ytPlayers.length; i++) {
866
+ const playerID = ytPlayers[i];
867
+ const playerProperties = j1.adapter.amplitude.data.ytPlayers[playerID];
868
+ logger.debug('\n' + 'process player id: ' + playerID);
869
+ var ytpPlayer = j1.adapter.amplitude.data.ytPlayers[playerID].player;
870
+ var playerState = ytpPlayer.getPlayerState();
871
+ var ytpPlayerState = YT_PLAYER_STATE_NAMES[playerState];
872
+
873
+ if (ytpPlayerState === 'playing' || ytpPlayerState === 'paused' || ytpPlayerState === 'buffering') {
874
+ logger.debug('\n' + 'process player id: ' + playerID + ' stopped');
875
+ ytpPlayer.stopVideo();
876
+ }
877
+ }
878
+
879
+ // process audio for configured START position
880
+ // -------------------------------------------------------------------
881
+ var checkIsFading = setInterval (() => {
882
+ if (!isFadingIn) {
883
+ var currentAudioTime = Amplitude.getSongPlayedSeconds();
884
+ if (songStartSec && currentAudioTime <= songStartSec) {
885
+ var songDurationSec = timestamp2seconds(songMetaData.duration);
886
+
887
+ // seek audio to configured START position
888
+ // NOTE: use setSongPlayedPercentage for seeking to NOT
889
+ // generation any addition state changes like stopped
890
+ // or playing
891
+ logger.debug('\n' + 'seek audio in on playlist: ' + playList + ' at|to trackID|timestamp: ' + trackID + '|' + songStartTS);
892
+ Amplitude.setSongPlayedPercentage((songStartSec / songDurationSec) * 100);
893
+
894
+ // fade-in audio (if enabled)
895
+ var fadeAudioIn = (songMetaData.audio_fade_in === 'true') ? true : false;
896
+ if (fadeAudioIn) {
897
+ logger.debug('\n' + 'faden audio in on playlist: ' + playList + ' at|to trackID|timestamp: ' + trackID + '|' + songStartTS);
898
+ atpFadeInAudio({ playerID: playerID });
899
+ } // END if fadeAudio
900
+
901
+ } // END if songStartSec
902
+
903
+ clearInterval(checkIsFading);
904
+ }
905
+ }, 100); // END checkIsFading
906
+
907
+ // check|process audio for configured END position
908
+ // -------------------------------------------------------------------
909
+ if (songEndSec > songStartSec) {
910
+ var checkIsOnVideoEnd = setInterval(() => {
911
+
912
+ if (!isFadingOut) {
913
+ var currentAudioTime = Amplitude.getSongPlayedSeconds();
914
+ var songMetaData = Amplitude.getActiveSongMetadata();
915
+ var songEndTS = songMetaData.end;
916
+ var songEndSec = timestamp2seconds(songEndTS);
917
+
918
+ if (currentAudioTime > songEndSec) {
919
+ songMetaData = Amplitude.getActiveSongMetadata();
920
+ songIndex = songMetaData.index;
921
+ trackID = songIndex + 1;
922
+
923
+ // seek audio out to total end END position
924
+ // NOTE: use setSongPlayedPercentage for seeking to NOT
925
+ // generation any addition state changes like stopped
926
+ // or playing
927
+ logger.debug('\n' + 'seek audio out to end on playlist: ' + playList + ' at trackID|timestamp: ' + trackID + '|' + songEndTS);
928
+ Amplitude.setSongPlayedPercentage(99.99);
929
+
930
+ // fade-out audio (if enabled)
931
+ var fadeAudioOut = (songMetaData.audio_fade_out === 'true') ? true : false;
932
+ if (fadeAudioOut) {
933
+ logger.debug('\n' + 'fade audio out on playlist: ' + playList + ' at|to trackID|timestamp: ' + trackID + '|' + songEndTS);
934
+ atpFadeAudioOut({ playerID: playerID });
935
+ } // END if fadeAudio
936
+
937
+ clearInterval(checkIsOnVideoEnd);
938
+ } // END if currentAudioTime
939
+
940
+ } // END if !isFading
941
+
942
+ }, 100); // END checkIsOnVideoEnd
943
+ } // END if songEndSec
944
+
945
+ // save YT player data for later use (e.g. events)
946
+ // ---------------------------------------------------------------------
947
+ j1.adapter.amplitude.data.activePlayer = 'atp';
948
+ j1.adapter.amplitude.data.atpGlobals.activePlayerType = 'large';
949
+
950
+ }; // END processOnStateChangePlaying
951
+
952
+ // -----------------------------------------------------------------------
953
+ // onPlayerStateChange
954
+ //
955
+ // process all AT Player specific state changes
956
+ // -----------------------------------------------------------------------
957
+ // NOTE:
958
+ // The AT API fires a lot of INTERMEDIATE states. MOST of them gets
959
+ // ignored (do nothing). Currently, only state PLAYING is actively
960
+ // processed.
961
+ // -----------------------------------------------------------------------
962
+ function onPlayerStateChange(state) {
963
+
964
+ // process all state changes fired by AT API
965
+ // ---------------------------------------------------------------------
966
+ switch(state) {
967
+ case AT_PLAYER_STATE.UNSTARTED:
968
+ doNothingOnStateChange(AT_PLAYER_STATE.UNSTARTED);
969
+ break;
970
+ case AT_PLAYER_STATE.STOPPED:
971
+ doNothingOnStateChange(AT_PLAYER_STATE.STOPPED);
972
+ break;
973
+ case AT_PLAYER_STATE.PAUSED:
974
+ doNothingOnStateChange(AT_PLAYER_STATE.PAUSED);
975
+ break;
976
+ case AT_PLAYER_STATE.PREVIOUS:
977
+ doNothingOnStateChange(AT_PLAYER_STATE.PREVIOUS);
978
+ break;
979
+ case AT_PLAYER_STATE.NEXT:
980
+ doNothingOnStateChange(AT_PLAYER_STATE.NEXT);
981
+ break;
982
+ case AT_PLAYER_STATE.CHANGED:
983
+ doNothingOnStateChange(AT_PLAYER_STATE.CHANGED);
984
+ break;
985
+ case AT_PLAYER_STATE.PLAYING:
986
+ processOnStateChangePlaying(AT_PLAYER_STATE.PLAYING);
987
+ break;
988
+ case AT_PLAYER_STATE.ENDED:
989
+ doNothingOnStateChange(AT_PLAYER_STATE.ENDED);
990
+ break;
991
+ default:
992
+ logger.error('\n' + `UNKNOWN state on StateChange fired: ${state}`);
993
+ } // END switch state
994
+ } // END onPlayerStateChange
995
+
559
996
  }, // END initApi
560
997
 
998
+ // -------------------------------------------------------------------------
999
+ // monitorPlayerActiveElementChanges
1000
+ //
1001
+ // -------------------------------------------------------------------------
1002
+ // monitorPlayerActiveElementChanges: () => {
1003
+ // // var playerSongContainers = document.getElementsByClassName("large-player-title-list");
1004
+ // var playerSongContainers = document.getElementsByClassName("large-player-title-list");
1005
+ // for (var i=0; i<playerSongContainers.length; i++) {
1006
+ // var scrollableList = document.getElementById(playerSongContainers[0].id);
1007
+ // var observer = new MutationObserver((mutationsList, observer) => {
1008
+ // for (const mutation of mutationsList) {
1009
+ // if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
1010
+ // // Überprüfen, ob das geänderte Element jetzt die aktive Klasse besitzt
1011
+ // if (mutation.target.classList.contains('amplitude-active-song-container')) {
1012
+ // scrollableList.scrollTop = mutation.target.offsetTop;
1013
+ // }
1014
+ // }
1015
+ // }
1016
+ // }); // END observer
1017
+
1018
+ // // Optionen für den Observer: Nur Änderungen an Attributen beobachten
1019
+ // observer.observe(scrollableList, {
1020
+ // attributes: true,
1021
+ // subtree: true
1022
+ // }); // END observer options
1023
+
1024
+ // } // END for playerSongContainers
1025
+ // }, // END monitorPlayerActiveElementChanges
1026
+
561
1027
  // -------------------------------------------------------------------------
562
1028
  // initPlayerUiEvents
563
1029
  // -------------------------------------------------------------------------
@@ -574,14 +1040,6 @@ j1.adapter.amplitude = ((j1, window) => {
574
1040
  {% assign xhr_data_path = amplitude_options.xhr_data_path %}
575
1041
  {% capture xhr_container_id %}{{player.id}}_app{% endcapture %}
576
1042
 
577
- playerID = '{{player.id}}';
578
- playerType = '{{player.type}}';
579
- playList = '{{player.playlist}}';
580
- playListName = '{{player.playlist.name}}'
581
- playListTitle = '{{player.playlist.title}}';
582
-
583
- logger.debug('\n' + 'set playlist {{player.playlist}} on id #{{player.id}} with title: ' + playListTitle);
584
-
585
1043
  // dynamic loader variable to setup the player on ID {{player.id}}
586
1044
  dependency = 'dependencies_met_player_loaded_{{player.id}}';
587
1045
  load_dependencies[dependency] = '';
@@ -590,11 +1048,18 @@ j1.adapter.amplitude = ((j1, window) => {
590
1048
  // initialize player instance (when player UI is loaded)
591
1049
  // -----------------------------------------------------------------
592
1050
  load_dependencies['dependencies_met_player_loaded_{{player.id}}'] = setInterval (() => {
593
- // check if HTML portion of the player is loaded successfully
594
- var xhrLoadState = j1.xhrDOMState['#' + '{{xhr_container_id}}'];
595
- var playerExistsInPage = ($('#' + '{{xhr_container_id}}')[0] !== undefined) ? true : false;
1051
+ var xhrDataLoaded = (j1.xhrDOMState['#' + '{{xhr_container_id}}'] === 'success') ? true : false;
1052
+ var playerExistsInPage = ($('#' + '{{xhr_container_id}}')[0] !== undefined) ? true : false;
596
1053
 
597
- if (xhrLoadState === 'success' && playerExistsInPage) {
1054
+ // check the player HTML portion is loaded and player exists (in page)
1055
+ if (xhrDataLoaded && playerExistsInPage) {
1056
+ var playerID = '{{player.id}}';
1057
+ var playerType = '{{player.type}}';
1058
+ var playList = '{{player.playlist}}';
1059
+ var playListName = '{{player.playlist.name}}';
1060
+ var playListTitle = '{{player.playlist.title}}';
1061
+
1062
+ logger.debug('\n' + 'initialize audio player instance on id: {{player.id}}');
598
1063
 
599
1064
  // set song (title) specific audio info links
600
1065
  // -------------------------------------------------------------
@@ -603,33 +1068,50 @@ j1.adapter.amplitude = ((j1, window) => {
603
1068
  _this.setAudioInfo(infoLinks);
604
1069
  }
605
1070
 
606
- // jadams, 2024-10-19: (song) events DISABLED
607
- // set song (title) specific UI events
608
- // -------------------------------------------------------------
609
- // var songElements = document.getElementsByClassName('song');
610
- // _this.songEvents(songElements);
611
-
612
- // player specific UI events
1071
+ // set player specific UI events
613
1072
  // -------------------------------------------------------------
614
- logger.debug('\n' + 'setup player specific UI events on ID #{{player.id}}: started');
1073
+ logger.debug('\n' + 'setup audio player specific UI events on ID #{{player.id}}: started');
615
1074
 
616
1075
  var dependencies_met_api_initialized = setInterval (() => {
617
1076
  if (apiInitialized.state) {
618
1077
  amplitudePlayerState = Amplitude.getPlayerState();
619
1078
 
1079
+ {% comment %} process UI events for all MINI Players
1080
+ ============================================================ {% endcomment %}
620
1081
  {% if player.id contains 'mini' %}
621
- // ---------------------------------------------------------
622
- // START mini player UI events
623
- //
624
1082
  if (document.getElementById('{{player.id}}') !== null) {
625
1083
 
626
- // add listeners to all progress bars found (mini-player)
627
- // getElementsByClassName returns an Array-like object
1084
+ {% comment %} PREPARED event listener for LATER use
1085
+ ----------------------------------------------------------
1086
+ // click on play_pause button (MINI player)
1087
+ var miniPlayerPlayPauseButton = document.getElementsByClassName('mini-player-play-pause');
1088
+ for (var i=0; i<miniPlayerPlayPauseButton.length; i++) {
1089
+ if (miniPlayerPlayPauseButton[i].dataset.amplitudeSource === 'youtube') {
1090
+ // do nothing (managed by plugin)
1091
+ } else {
1092
+ // var currentPlaylist = compactPlayerPlayPauseButton[i].dataset.amplitudePlaylist;
1093
+ // if (currentPlaylist === playListName) {
1094
+ if (miniPlayerPlayPauseButton[i].id === 'mini_player_play_pause_{{player.id}}') {
1095
+ miniPlayerPlayPauseButton[i].addEventListener('click', function(event) {
1096
+ var ytpPlayer;
1097
+
1098
+ // save YT player data for later use (e.g. events)
1099
+ j1.adapter.amplitude.data.activePlayer = 'atp';
1100
+ j1.adapter.amplitude.data.atpGlobals.activePlayerType = 'mini';
1101
+
1102
+ }); // addEventListener END
1103
+ } // END if miniPlayerPlayPauseButton
1104
+ } // END if ATP
1105
+ } // END for miniPlayerPlayPauseButton
1106
+ ----------------------------------------------------------
1107
+ {% endcomment %}
1108
+
1109
+ // add listeners to all progress bars found (MINI Player)
628
1110
  // -------------------------------------------------------
629
1111
  var progressBars = document.getElementsByClassName("mini-player-progress");
630
1112
  for (var i=0; i<progressBars.length; i++) {
631
1113
  if (progressBars[i].dataset.amplitudeSource === 'youtube') {
632
- // do nothing
1114
+ // do nothing for YTP (managed by plugin)
633
1115
  } else {
634
1116
  progressBars[i].addEventListener('click', function(event) {
635
1117
  var offset = this.getBoundingClientRect();
@@ -637,43 +1119,32 @@ j1.adapter.amplitude = ((j1, window) => {
637
1119
 
638
1120
  Amplitude.setSongPlayedPercentage(
639
1121
  (parseFloat(xpos)/parseFloat(this.offsetWidth))*100);
640
- }); // END EventListener 'click'
641
- }
642
- } // END for
643
-
644
- // for (var i=0; i<progressBars.length; i++) {
645
- // progressBars[i].addEventListener('click', function(event) {
646
- // var offset = this.getBoundingClientRect();
647
- // var xpos = event.pageX - offset.left;
648
1122
 
649
- // Amplitude.setSongPlayedPercentage(
650
- // (parseFloat(xpos)/parseFloat(this.offsetWidth))*100);
651
- // });
652
- // }
1123
+ }); // END addEventListener
1124
+ } // END if progressBars
1125
+ } // END for progressBars
653
1126
 
654
1127
  } // END mini player UI events
655
1128
  {% endif %}
656
1129
 
657
- {% if player.id contains 'compact' %}
658
- // ---------------------------------------------------------
659
- // START compact player UI events
660
- //
1130
+
1131
+ {% comment %} process UI events for all COMPACT Players
1132
+ ============================================================ {% endcomment %}
1133
+ {% if player.id contains 'compact' %}
661
1134
  if (document.getElementById('{{player.id}}') !== null) {
662
1135
 
663
1136
  // show|hide scrollbar in playlist (compact player)
664
1137
  // -------------------------------------------------------
665
1138
  const songsInPlaylist = Amplitude.getSongsInPlaylist(playListName);
666
- if (songsInPlaylist.length <= 8) {
1139
+ if (songsInPlaylist.length <= playerScrollerSongElementMin) {
667
1140
  const titleListCompactPlayer = document.getElementById('compact_player_title_list_' + playListName);
668
1141
  if (titleListCompactPlayer !== null) {
669
1142
  titleListCompactPlayer.classList.add('hide-scrollbar');
670
1143
  }
671
- }
672
-
673
- // show|hide playlist
674
- // -------------------------------------------------------
1144
+ } // END if songsInPlaylist
675
1145
 
676
1146
  // show playlist
1147
+ // -------------------------------------------------------
677
1148
  var showPlaylist = document.getElementById("show_playlist_{{player.id}}");
678
1149
  if (showPlaylist !== null) {
679
1150
  showPlaylist.addEventListener('click', function(event) {
@@ -700,82 +1171,192 @@ j1.adapter.amplitude = ((j1, window) => {
700
1171
  $('body').addClass('stop-scrolling');
701
1172
  }
702
1173
  }
703
- }); // END EventListener 'click' (compact player|show playlist)
704
- } // END if showPlaylist
705
1174
 
706
- // hide playlist
707
- var hidePlaylist = document.getElementById("hide_playlist_{{player.id}}");
708
- if (hidePlaylist !== null) {
709
- hidePlaylist.addEventListener('click', function(event) {
710
- var playlistScreen = document.getElementById("playlist_screen_{{player.id}}");
1175
+ }); // END EventListener
1176
+ } // END if showPlaylist
1177
+
1178
+ // hide playlist
1179
+ // -------------------------------------------------------
1180
+ var hidePlaylist = document.getElementById("hide_playlist_{{player.id}}");
1181
+ if (hidePlaylist !== null) {
1182
+ hidePlaylist.addEventListener('click', function(event) {
1183
+ var playlistScreen = document.getElementById("playlist_screen_{{player.id}}");
711
1184
 
712
- playlistScreen.classList.remove('slide-in-top');
713
- playlistScreen.classList.add('slislide-out-top');
714
- playlistScreen.style.display = "none";
715
- playlistScreen.style.zIndex = "1";
1185
+ playlistScreen.classList.remove('slide-in-top');
1186
+ playlistScreen.classList.add('slide-out-top');
1187
+ playlistScreen.style.display = "none";
1188
+ playlistScreen.style.zIndex = "1";
716
1189
 
717
- // enable scrolling
718
- if ($('body').hasClass('stop-scrolling')) {
719
- $('body').removeClass('stop-scrolling');
1190
+ // enable scrolling
1191
+ if ($('body').hasClass('stop-scrolling')) {
1192
+ $('body').removeClass('stop-scrolling');
1193
+ }
1194
+
1195
+ }); // END addEventListener
1196
+ } // END if hidePlaylist
1197
+
1198
+ // add listeners to all progress bars found (compact-player)
1199
+ // -------------------------------------------------------
1200
+ var progressBars = document.getElementsByClassName("compact-player-progress");
1201
+ for (var i=0; i<progressBars.length; i++) {
1202
+ if (progressBars[i].dataset.amplitudeSource === 'youtube') {
1203
+ // do nothing for YTP (managed by plugin)
1204
+ } else {
1205
+ progressBars[i].addEventListener('click', function(event) {
1206
+ var offset = this.getBoundingClientRect();
1207
+ var xpos = event.pageX - offset.left;
1208
+
1209
+ Amplitude.setSongPlayedPercentage(
1210
+ (parseFloat(xpos)/parseFloat(this.offsetWidth))*100);
1211
+
1212
+ }); // END EventListener 'click'
1213
+ } // END if progressBars
1214
+ } // END for progressBars
1215
+
1216
+ // add listeners to all Next Buttons found (COMPACT player)
1217
+ // -------------------------------------------------------
1218
+
1219
+ {% comment %} PREPARED event listener for LATER use
1220
+ ----------------------------------------------------------
1221
+ var compactNextButtons = document.getElementsByClassName("compact-player-next");
1222
+ for (var i=0; i<compactNextButtons.length; i++) {
1223
+ if (compactNextButtons[i].dataset.amplitudeSource === 'youtube') {
1224
+ // do nothing for YTP (managed by plugin)
1225
+ } else {
1226
+ if (compactNextButtons[i].id === 'compact_player_next_{{player.id}}' || compactNextButtons[i].id === 'compact_player_list_next_{{player.id}}') {
1227
+ compactNextButtons[i].addEventListener('click', function(event) {
1228
+ var atpPlayerID = this.id;
1229
+ var atpPlayerActive = atpPlayerID.split('_');
1230
+
1231
+ j1.adapter.amplitude.data.atpGlobals.activePlayerType = 'compact';
1232
+
1233
+ }); // END EventListener 'click'
1234
+ } // END if ID
720
1235
  }
721
- }); // END EventListener 'click' (compact player|show playlist)
722
- } // END if hidePlaylist
723
-
724
- // add listeners to all progress bars found (compact-player)
725
- // getElementsByClassName returns an Array-like object
726
- // -------------------------------------------------------
727
- var progressBars = document.getElementsByClassName("compact-player-progress");
728
- for (var i=0; i<progressBars.length; i++) {
729
- if (progressBars[i].dataset.amplitudeSource === 'youtube') {
730
- // do nothing
731
- } else {
732
- progressBars[i].addEventListener('click', function(event) {
733
- var offset = this.getBoundingClientRect();
734
- var xpos = event.pageX - offset.left;
735
-
736
- Amplitude.setSongPlayedPercentage(
737
- (parseFloat(xpos)/parseFloat(this.offsetWidth))*100);
738
- }); // END EventListener 'click'
739
- }
740
- } // END for
1236
+ } // END Next Buttons (COMPACT player)
1237
+ ----------------------------------------------------------
1238
+ {% endcomment %}
1239
+
1240
+ {% comment %} PREPARED event listener for LATER use
1241
+ ----------------------------------------------------------
1242
+ // add listeners to all Previous Buttons found
1243
+ var compactPreviousButtons = document.getElementsByClassName("compact-player-previous");
1244
+ for (var i=0; i<compactPreviousButtons.length; i++) {
1245
+ if (compactPreviousButtons[i].dataset.amplitudeSource === 'youtube') {
1246
+ // do nothing for YTP (managed by plugin)
1247
+ } else {
1248
+ if (compactPreviousButtons[i].id === 'compact_player_previous_{{player.id}}' || compactPreviousButtons[i].id === 'compact_player_list_previous_{{player.id}}') {
1249
+ compactPreviousButtons[i].addEventListener('click', function(event) {
1250
+ var atpPlayerID = this.id;
1251
+ var atpPlayerActive = atpPlayerID.split('_');
1252
+
1253
+ j1.adapter.amplitude.data.atpGlobals.activePlayerType = 'compact';
741
1254
 
742
- // click on skip forward|backward (compact player)
1255
+ }); // END EventListener 'click'
1256
+ } // END if ID
1257
+ }
1258
+ } // END Previous Buttons (COMPACT player)
1259
+ ----------------------------------------------------------
1260
+ {% endcomment %}
1261
+
1262
+ {% comment %} PREPARED event listener for LATER use
1263
+ ----------------------------------------------------------
1264
+ // click on play_pause button (COMPACT player)
1265
+ var compactPlayerPlayPauseButton = document.getElementsByClassName('compact-player-play-pause');
1266
+ for (var i=0; i<compactPlayerPlayPauseButton.length; i++) {
1267
+ if (compactPlayerPlayPauseButton[i].dataset.amplitudeSource === 'youtube') {
1268
+ // do nothing (managed by plugin)
1269
+ } else {
1270
+ // var currentPlaylist = compactPlayerPlayPauseButton[i].dataset.amplitudePlaylist;
1271
+ // if (currentPlaylist === playListName) {
1272
+ if (compactPlayerPlayPauseButton[i].id === 'compact_player_play_pause_{{player.id}}' || compactPlayerPlayPauseButton[i].id === 'compact_player_list_play_pause_{{player.id}}') {
1273
+ compactPlayerPlayPauseButton[i].addEventListener('click', function(event) {
1274
+ var ytpPlayer;
1275
+ var ytpPlayerState;
1276
+ var playerState;
1277
+
1278
+ // stop active YT players
1279
+ const ytPlayers = Object.keys(j1.adapter.amplitude.data.ytPlayers);
1280
+ for (let i=0; i<ytPlayers.length; i++) {
1281
+ const playerID = ytPlayers[i];
1282
+ const playerProperties = j1.adapter.amplitude.data.ytPlayers[playerID];
1283
+ logger.debug('\n' + 'process player id: ' + playerID);
1284
+ ytpPlayer = j1.adapter.amplitude.data.ytPlayers[playerID].player;
1285
+ playerState = ytpPlayer.getPlayerState();
1286
+ ytpPlayerState = YT_PLAYER_STATE_NAMES[playerState];
1287
+
1288
+ if (ytpPlayerState === 'playing' || ytpPlayerState === 'paused' || ytpPlayerState === 'buffering') {
1289
+ logger.debug('\n' + 'process player id: ' + playerID + ' stopped');
1290
+ ytpPlayer.stopVideo();
1291
+ }
1292
+ }
1293
+
1294
+ // save YT player data for later use (e.g. events)
1295
+ j1.adapter.amplitude.data.activePlayer = 'atp';
1296
+ j1.adapter.amplitude.data.atpGlobals.activePlayerType = 'compact';
1297
+
1298
+ });
1299
+ }
1300
+ }
1301
+ } // END play_pause button (COMPACT player)
1302
+ ----------------------------------------------------------
1303
+ {% endcomment %}
1304
+
1305
+ // click on skip forward|backward (COMPACT player)
743
1306
  // See: https://github.com/serversideup/amplitudejs/issues/384
744
1307
  // -------------------------------------------------------
745
1308
 
746
1309
  // add listeners to all SkipForwardButtons found
747
1310
  var compactPlayerSkipForwardButtons = document.getElementsByClassName("compact-player-skip-forward");
748
1311
  for (var i=0; i<compactPlayerSkipForwardButtons.length; i++) {
749
- if (compactPlayerSkipForwardButtons[i].id === 'skip-forward_{{player.id}}') {
750
- compactPlayerSkipForwardButtons[i].addEventListener('click', function(event) {
751
- const skipOffset = parseFloat(playerForwardBackwardSkipSeconds);
752
- const duration = Amplitude.getSongDuration();
753
- const currentTime = parseFloat(Amplitude.getSongPlayedSeconds());
754
- const targetTime = parseFloat(currentTime + skipOffset);
755
-
756
- if (currentTime > 0) {
757
- Amplitude.setSongPlayedPercentage((targetTime / duration) * 100);
758
- }
759
- }); // END EventListener 'click'
760
- } // END if ID
761
- } // END for SkipForwardButtons
1312
+ if (compactPlayerSkipForwardButtons[i].dataset.amplitudeSource === 'youtube') {
1313
+ // do nothing for YTP (managed by plugin)
1314
+ } else {
1315
+ if (compactPlayerSkipForwardButtons[i].id === 'skip-forward_{{player.id}}') {
1316
+ compactPlayerSkipForwardButtons[i].addEventListener('click', function(event) {
1317
+
1318
+ // load player settings
1319
+ // playerForwardBackwardSkipSeconds = (playerSettings.forward_backward_skip_seconds === undefined) ? playerForwardBackwardSkipSeconds: playerSettings.forward_backward_skip_seconds;
1320
+
1321
+ const skipOffset = parseFloat(playerForwardBackwardSkipSeconds);
1322
+ const duration = Amplitude.getSongDuration();
1323
+ const currentTime = parseFloat(Amplitude.getSongPlayedSeconds());
1324
+ const targetTime = parseFloat(currentTime + skipOffset);
1325
+
1326
+ if (currentTime > 0) {
1327
+ Amplitude.setSongPlayedPercentage((targetTime / duration) * 100);
1328
+ }
1329
+
1330
+ }); // END EventListener 'click'
1331
+ } // END if ID
1332
+ }
1333
+ } // END SkipForwardButtons (COMPACT player)
762
1334
 
763
1335
  // add listeners to all SkipBackwardButtons found
764
1336
  var compactPlayerSkipBackwardButtons = document.getElementsByClassName("compact-player-skip-backward");
765
1337
  for (var i=0; i<compactPlayerSkipBackwardButtons.length; i++) {
766
- if (compactPlayerSkipBackwardButtons[i].id === 'skip-backward_{{player.id}}') {
767
- compactPlayerSkipBackwardButtons[i].addEventListener('click', function(event) {
768
- const skipOffset = parseFloat(playerForwardBackwardSkipSeconds);
769
- const duration = Amplitude.getSongDuration();
770
- const currentTime = parseFloat(Amplitude.getSongPlayedSeconds());
771
- const targetTime = parseFloat(currentTime - skipOffset);
772
-
773
- if (currentTime > 0) {
774
- Amplitude.setSongPlayedPercentage((targetTime / duration) * 100);
775
- }
776
- }); // END EventListener 'click'
777
- } // END if ID
778
- } // END for SkipBackwardButtons
1338
+ if (compactPlayerSkipBackwardButtons[i].dataset.amplitudeSource === 'youtube') {
1339
+ // do nothing for YTP (managed by plugin)
1340
+ } else {
1341
+ if (compactPlayerSkipBackwardButtons[i].id === 'skip-backward_{{player.id}}') {
1342
+ compactPlayerSkipBackwardButtons[i].addEventListener('click', function(event) {
1343
+
1344
+ // load player settings
1345
+ // playerForwardBackwardSkipSeconds = (playerSettings.forward_backward_skip_seconds === undefined) ? playerForwardBackwardSkipSeconds: playerSettings.forward_backward_skip_seconds;
1346
+
1347
+ const skipOffset = parseFloat(playerForwardBackwardSkipSeconds);
1348
+ const duration = Amplitude.getSongDuration();
1349
+ const currentTime = parseFloat(Amplitude.getSongPlayedSeconds());
1350
+ const targetTime = parseFloat(currentTime - skipOffset);
1351
+
1352
+ if (currentTime > 0) {
1353
+ Amplitude.setSongPlayedPercentage((targetTime / duration) * 100);
1354
+ }
1355
+
1356
+ }); // END EventListener 'click'
1357
+ } // END if ID
1358
+ }
1359
+ } // END SkipBackwardButtons (COMPACT player)
779
1360
 
780
1361
  // click on shuffle button
781
1362
  var compactPlayerShuffleButton = document.getElementById('compact_player_shuffle');
@@ -784,8 +1365,9 @@ j1.adapter.amplitude = ((j1, window) => {
784
1365
  var shuffleState = (document.getElementById('compact_player_shuffle').className.includes('amplitude-shuffle-on')) ? true : false;
785
1366
 
786
1367
  Amplitude.setShuffle(shuffleState)
1368
+
787
1369
  }); // END EventListener 'click'
788
- } // END compactPlayerShuffleButton
1370
+ } // END PlayerShuffleButton (COMPACT player)
789
1371
 
790
1372
  // click on repeat button
791
1373
  var compactPlayerRepeatButton = document.getElementById('compact_player_repeat');
@@ -794,55 +1376,267 @@ j1.adapter.amplitude = ((j1, window) => {
794
1376
  var repeatState = (document.getElementById('compact_player_repeat').className.includes('amplitude-repeat-on')) ? true : false;
795
1377
 
796
1378
  Amplitude.setRepeat(repeatState)
1379
+
797
1380
  }); // END EventListener 'click'
798
- } // END compactPlayerRepeatButton
1381
+ } // END PlayerRepeatButton (COMPACT player)
799
1382
 
800
1383
  } // END compact player UI events
801
1384
  {% endif %}
802
1385
 
1386
+
1387
+ {% comment %} process UI events for all LARGE Players
1388
+ ============================================================ {% endcomment %}
803
1389
  {% if player.id contains 'large' %}
804
- // START large player UI events
805
- //
1390
+
806
1391
  if (document.getElementById('{{player.id}}') !== null) {
1392
+ // var playlist = '{{player.id}}_yt';
1393
+ var playlistInfo = {{player.playlist | replace: 'nil', 'null' | replace: '=>', ':'}};
1394
+ var playList = playlistInfo.name;
807
1395
 
808
- // NOTE: listener overloads for video managed by plugin
1396
+ // add listeners to all SongContainers found (LARGE player)
809
1397
  // -------------------------------------------------------
1398
+ var largePlayerSongContainer = document.getElementsByClassName("amplitude-song-container");
1399
+ for (var i=0; i<largePlayerSongContainer.length; i++) {
1400
+ if (largePlayerSongContainer[i].dataset.amplitudeSource === 'youtube') {
1401
+ // do nothing for YTP (managed by plugin)
1402
+ } else {
1403
+ var currentPlaylist = largePlayerSongContainer[i].dataset.amplitudePlaylist;
1404
+ if (currentPlaylist === playList) {
1405
+ // if (largePlayerSongContainer[i].id === 'large-player-play-pause_{{player.id}}' || largePlayerSongContainer[i].id === 'large-player-play-pause_{{player.id}}') {
1406
+ largePlayerSongContainer[i].addEventListener('click', function(event) {
1407
+ var ytpPlayer, ytpPlayerState, ytpPlayerState, atpPlayerState,
1408
+ playerState, classArray, atpPlayerActive, metaData,
1409
+ playlist, playlistIndex;
1410
+
1411
+ classArray = [].slice.call(this.classList, 0);
1412
+ atpPlayerActive = classArray[0].split('-');
1413
+ playlist = this.getAttribute("data-amplitude-playlist");
1414
+ playlistIndex = parseInt(this.getAttribute("data-amplitude-song-index"));
1415
+ metaData = Amplitude.getActiveSongMetadata();
1416
+ atpPlayerState = Amplitude.getPlayerState();
1417
+
1418
+ // update song rating in screen controls
1419
+ // -----------------------------------------------
1420
+ // updateSongRating(playlist, metaData.index, metaData.rating);
1421
+
1422
+ // var largePlayerSongAudioRating = document.getElementsByClassName("audio-rating-screen-controls");
1423
+ // if (largePlayerSongAudioRating.length) {
1424
+ // for (var i=0; i<largePlayerSongAudioRating.length; i++) {
1425
+ // var currentPlaylist = largePlayerSongAudioRating[i].dataset.amplitudePlaylist;
1426
+ // if (currentPlaylist === playlist) {
1427
+ // if (metaData.rating) {
1428
+ // var trackID = metaData.index + 1;
1429
+ // logger.debug('\n' + `UPDATE song rating on updatMetaContainers for trackID|playlist at: ${trackID}|${playlist} with a value of: ${metaData.rating}`);
1430
+ // largePlayerSongAudioRating[i].innerHTML = '<img src="/assets/image/pattern/rating/scalable/' + metaData.rating + '-star.svg"' + 'alt="song rating">';
1431
+ // } else {
1432
+ // largePlayerSongAudioRating[i].innerHTML = '';
1433
+ // }
1434
+ // }
1435
+ // }
1436
+ // } // END if largePlayerSongAudioRating
1437
+
1438
+ // scroll song active at index in player
1439
+ // -----------------------------------------------
1440
+ // if (playerAutoScrollSongElement) {
1441
+ // j1.adapter.amplitude.atPlayerScrollToActiveElement(playlist);
1442
+ // }
1443
+
1444
+ // toggle active AT players
1445
+ // -----------------------------------------------
1446
+ // if (atpPlayerState === 'playing') {
1447
+ // // start|pause active player
1448
+ // // logger.debug('\n' + 'process player id: ' + atpPlayerActive[0] + ' stopped');
1449
+ // Amplitude.pause();
1450
+ // } else {
1451
+ // Amplitude.playPlaylistSongAtIndex(playlistIndex, playlist);
1452
+ // }
1453
+
1454
+ // stop active YT players
1455
+ // -----------------------------------------------
1456
+ const ytPlayers = Object.keys(j1.adapter.amplitude.data.ytPlayers);
1457
+ for (let i=0; i<ytPlayers.length; i++) {
1458
+ const playerID = ytPlayers[i];
1459
+ const playerProperties = j1.adapter.amplitude.data.ytPlayers[playerID];
1460
+ logger.debug('\n' + 'process player id: ' + playerID);
1461
+ ytpPlayer = j1.adapter.amplitude.data.ytPlayers[playerID].player;
1462
+ playerState = ytpPlayer.getPlayerState();
1463
+ ytpPlayerState = YT_PLAYER_STATE_NAMES[playerState];
1464
+
1465
+ if (ytpPlayerState === 'playing' || ytpPlayerState === 'paused' || ytpPlayerState === 'buffering') {
1466
+ logger.debug('\n' + 'process player id: ' + playerID + ' stopped');
1467
+ ytpPlayer.stopVideo();
1468
+ }
1469
+ }
1470
+
1471
+ // save YT player data for later use (e.g. events)
1472
+ // -----------------------------------------------
1473
+ j1.adapter.amplitude.data.activePlayer = 'atp';
1474
+ j1.adapter.amplitude.data.atpGlobals.activePlayerType = atpPlayerActive[3];
1475
+
1476
+ }); // END add EventListener
1477
+ } // END if currentPlaylist
1478
+ } // ENF if largePlayerSongContainer
1479
+ } // END for largePlayerSongContainer
810
1480
 
811
1481
  // click on prev button
812
1482
  var largePlayerPreviousButton = document.getElementById('large_player_previous');
813
1483
  if (largePlayerPreviousButton && largePlayerPreviousButton.getAttribute("data-amplitude-source") === 'youtube') {
814
- // do nothing (managed by plugin)
1484
+ // do nothing for YTP (managed by plugin)
815
1485
  }
816
1486
 
817
- // click on play_pause button
818
- var largePlayerPlayButton = document.getElementById('large_player_play_pause');
819
- // add listeners to all progress bars found (large-player)
1487
+ // add listeners to all PlayPause Buttons found (LARGE player)
1488
+ // -------------------------------------------------------
1489
+
1490
+ {% comment %} PREPARED event listener for LATER use
1491
+ ----------------------------------------------------------
1492
+ var largePlayerPlayPauseButton = document.getElementsByClassName('large-player-play-pause');
1493
+ for (var i=0; i<largePlayerPlayPauseButton.length; i++) {
1494
+ if (largePlayerPlayPauseButton[i].dataset.amplitudeSource === 'youtube') {
1495
+ // do nothing for YTP (managed by plugin)
1496
+ } else {
1497
+ var currentPlaylist = largePlayerPlayPauseButton[i].dataset.amplitudePlaylist;
1498
+ if (currentPlaylist === playList) {
1499
+ largePlayerPlayPauseButton[i].addEventListener('click', function(event) {
1500
+ var ytpPlayer, ytpPlayerState, playlist, metaData, playerState;
1501
+
1502
+ metaData = Amplitude.getActiveSongMetadata();
1503
+ playlist = this.getAttribute("data-amplitude-playlist");
1504
+
1505
+ });
1506
+ }
1507
+ }
1508
+ } // END play_pause button (LARGE player)
1509
+ ----------------------------------------------------------
1510
+ {% endcomment %}
1511
+
1512
+ // add listeners to all progress bars found (LARGE player)
820
1513
  // -------------------------------------------------------
821
1514
  var progressBars = document.getElementsByClassName("large-player-progress");
822
1515
  for (var i=0; i<progressBars.length; i++) {
823
1516
  if (progressBars[i].dataset.amplitudeSource === 'youtube') {
824
- // do nothing (managed by plugin)
1517
+ // do nothing for YTP (managed by plugin)
825
1518
  } else {
826
1519
  progressBars[i].addEventListener('click', function(event) {
827
1520
  var offset = this.getBoundingClientRect();
828
1521
  var xpos = event.pageX - offset.left;
829
-
830
- Amplitude.setSongPlayedPercentage(
831
- (parseFloat(xpos)/parseFloat(this.offsetWidth))*100);
1522
+
1523
+ if (Amplitude.getPlayerState() === 'playing') {
1524
+ Amplitude.setSongPlayedPercentage((parseFloat(xpos)/parseFloat(this.offsetWidth))*100);
1525
+ }
1526
+
832
1527
  }); // END EventListener 'click'
833
1528
  }
834
1529
  } // END for
835
1530
 
836
- // click on skip forward|backward (large player)
837
- // See: https://github.com/serversideup/amplitudejs/issues/384
1531
+ // add listeners to all Next Buttons found (LARGE player)
838
1532
  // -------------------------------------------------------
1533
+ var largeNextButtons = document.getElementsByClassName("large-player-next");
1534
+ for (var i=0; i<largeNextButtons.length; i++) {
1535
+ if (largeNextButtons[i].dataset.amplitudeSource === 'youtube') {
1536
+ // do nothing for YTP (managed by plugin)
1537
+ } else {
1538
+ if (largeNextButtons[i].id === 'large_player_next_{{player.id}}') {
1539
+ largeNextButtons[i].addEventListener('click', function(event) {
1540
+ var atpPlayerID, atpPlayerActive, metaData, playlist;
1541
+
1542
+ atpPlayerID = this.id;
1543
+ atpPlayerActive = atpPlayerID.split('_');
1544
+ playlist = this.getAttribute("data-amplitude-playlist");
1545
+ metaData = Amplitude.getActiveSongMetadata();
1546
+
1547
+ // update song rating in screen controls
1548
+ var largePlayerSongAudioRating = document.getElementsByClassName("audio-rating-screen-controls");
1549
+ if (largePlayerSongAudioRating.length) {
1550
+ for (var i=0; i<largePlayerSongAudioRating.length; i++) {
1551
+ var currentPlaylist = largePlayerSongAudioRating[i].dataset.amplitudePlaylist;
1552
+ if (currentPlaylist === playlist) {
1553
+ if (metaData.rating) {
1554
+ var trackID = metaData.index + 1;
1555
+ logger.debug('\n' + `UPDATE song rating on updatMetaContainers for trackID|playlist at: ${trackID}|${playlist} with a value of: ${metaData.rating}`);
1556
+ largePlayerSongAudioRating[i].innerHTML = '<img src="/assets/image/pattern/rating/scalable/' + metaData.rating + '-star.svg"' + 'alt="song rating">';
1557
+ } else {
1558
+ largePlayerSongAudioRating[i].innerHTML = '';
1559
+ }
1560
+ }
1561
+ }
1562
+ } // END if largePlayerSongAudioRating
1563
+
1564
+ // scroll song active at index in player
1565
+ // -----------------------------------------------
1566
+ if (playerAutoScrollSongElement) {
1567
+ j1.adapter.amplitude.atPlayerScrollToActiveElement(playlist);
1568
+ }
1569
+
1570
+ // save YT player data for later use (e.g. events)
1571
+ // -----------------------------------------------
1572
+ j1.adapter.amplitude.data.activePlayer = 'atp';
1573
+ j1.adapter.amplitude.data.atpGlobals.activePlayerType = atpPlayerActive[0];
839
1574
 
840
- // add listeners to all SkipForwardButtons found
1575
+ }); // END EventListener 'click'
1576
+ } // END addEventListener
1577
+ } // END if largeNextButtons
1578
+ } // END for Next Buttons
1579
+
1580
+ // add listeners to all Previous Buttons found
1581
+ // -------------------------------------------------------
1582
+ var largePreviousButtons = document.getElementsByClassName("large-player-previous");
1583
+ for (var i=0; i<largePreviousButtons.length; i++) {
1584
+ if (largePreviousButtons[i].dataset.amplitudeSource === 'youtube') {
1585
+ // do nothing for YTP (managed by plugin)
1586
+ } else {
1587
+ if (largePreviousButtons[i].id === 'large_player_previous_{{player.id}}') {
1588
+ largePreviousButtons[i].addEventListener('click', function(event) {
1589
+ var atpPlayerID, atpPlayerActive, metaData, playlist;
1590
+
1591
+ atpPlayerID = this.id;
1592
+ atpPlayerActive = atpPlayerID.split('_');
1593
+ playlist = this.getAttribute("data-amplitude-playlist");
1594
+ metaData = Amplitude.getActiveSongMetadata();
1595
+
1596
+ // update song rating in screen controls
1597
+ var largePlayerSongAudioRating = document.getElementsByClassName("audio-rating-screen-controls");
1598
+ if (largePlayerSongAudioRating.length) {
1599
+ for (var i=0; i<largePlayerSongAudioRating.length; i++) {
1600
+ var currentPlaylist = largePlayerSongAudioRating[i].dataset.amplitudePlaylist;
1601
+ if (currentPlaylist === playlist) {
1602
+ if (metaData.rating) {
1603
+ var trackID = metaData.index + 1;
1604
+ logger.debug('\n' + `UPDATE song rating on updatMetaContainers for trackID|playlist at: ${trackID}|${playlist} with a value of: ${metaData.rating}`);
1605
+ largePlayerSongAudioRating[i].innerHTML = '<img src="/assets/image/pattern/rating/scalable/' + metaData.rating + '-star.svg"' + 'alt="song rating">';
1606
+ } else {
1607
+ largePlayerSongAudioRating[i].innerHTML = '';
1608
+ }
1609
+ }
1610
+ }
1611
+ } // END if largePlayerSongAudioRating
1612
+
1613
+ // scroll song active at index in player
1614
+ if (playerAutoScrollSongElement) {
1615
+ j1.adapter.amplitude.atPlayerScrollToActiveElement(playlist);
1616
+ }
1617
+
1618
+ // scroll song active at index in player
1619
+ if (playerAutoScrollSongElement) {
1620
+ j1.adapter.amplitude.atPlayerScrollToActiveElement(playlist);
1621
+ }
1622
+
1623
+ // save YT player data for later use (e.g. events)
1624
+ j1.adapter.amplitude.data.activePlayer = 'atp';
1625
+ j1.adapter.amplitude.data.atpGlobals.activePlayerType = atpPlayerActive[0];
1626
+
1627
+ }); // END addEventListener
1628
+ } // END if largePreviousButtons
1629
+ } // END if largePreviousButtons
1630
+ } // END for Previous Buttons
1631
+
1632
+ // add listeners to all SkipForward Buttons found
1633
+ // See: https://github.com/serversideup/amplitudejs/issues/384
1634
+ // -------------------------------------------------------
841
1635
  var largePlayerSkipForwardButtons = document.getElementsByClassName("large-player-skip-forward");
842
1636
  for (var i=0; i<largePlayerSkipForwardButtons.length; i++) {
843
1637
  if (largePlayerSkipForwardButtons[i].id === 'skip-forward_{{player.id}}') {
844
1638
  if (largePlayerSkipForwardButtons[i].dataset.amplitudeSource === 'youtube') {
845
- // do nothing (managed by plugin)
1639
+ // do nothing for YTP (managed by plugin)
846
1640
  } else {
847
1641
  largePlayerSkipForwardButtons[i].addEventListener('click', function(event) {
848
1642
  const skipOffset = parseFloat(playerForwardBackwardSkipSeconds);
@@ -851,19 +1645,21 @@ j1.adapter.amplitude = ((j1, window) => {
851
1645
  const targetTime = parseFloat(currentTime + skipOffset);
852
1646
 
853
1647
  if (currentTime > 0) {
1648
+ logger.debug('\n' + `SKIP forward on Button skipForward for ${skipOffset} seconds`);
854
1649
  Amplitude.setSongPlayedPercentage((targetTime / duration) * 100);
855
1650
  }
856
- }); // END EventListener 'click'
857
- } // END else
858
- } // END if ID
1651
+ }); // END addEventListener
1652
+ } // END largePlayerSkipForwardButtons
1653
+ } // END if largePlayerSkipForwardButtons
859
1654
  } // END for SkipForwardButtons
860
1655
 
861
- // add listeners to all SkipBackwardButtons found
1656
+ // add listeners to all SkipBackward Buttons found
1657
+ // -------------------------------------------------------
862
1658
  var largePlayerSkipBackwardButtons = document.getElementsByClassName("large-player-skip-backward");
863
1659
  for (var i=0; i<largePlayerSkipBackwardButtons.length; i++) {
864
1660
  if (largePlayerSkipBackwardButtons[i].id === 'skip-backward_{{player.id}}') {
865
1661
  if (largePlayerSkipBackwardButtons[i].dataset.amplitudeSource === 'youtube') {
866
- // do nothing (managed by plugin)
1662
+ // do nothing for YTP (managed by plugin)
867
1663
  } else {
868
1664
  largePlayerSkipBackwardButtons[i].addEventListener('click', function(event) {
869
1665
  const skipOffset = parseFloat(playerForwardBackwardSkipSeconds);
@@ -872,11 +1668,12 @@ j1.adapter.amplitude = ((j1, window) => {
872
1668
  const targetTime = parseFloat(currentTime - skipOffset);
873
1669
 
874
1670
  if (currentTime > 0) {
1671
+ logger.debug('\n' + `SKIP backward on Button skipForward for ${skipOffset} seconds`);
875
1672
  Amplitude.setSongPlayedPercentage((targetTime / duration) * 100);
876
1673
  }
877
- }); // END EventListener 'click'
1674
+ }); // END addEventListener
878
1675
  } // END else
879
- } // END if ID
1676
+ } // END if largePlayerSkipBackwardButtons
880
1677
  } // END for SkipBackwardButtons
881
1678
 
882
1679
  // click on shuffle button
@@ -884,35 +1681,36 @@ j1.adapter.amplitude = ((j1, window) => {
884
1681
  if (largePlayerShuffleButton) {
885
1682
  largePlayerShuffleButton.addEventListener('click', function(event) {
886
1683
  var shuffleState = (document.getElementById('large_player_shuffle').className.includes('amplitude-shuffle-on')) ? true : false;
1684
+ logger.debug('\n' + `Set shuffle state to: ${shuffleState}`);
887
1685
  Amplitude.setShuffle(shuffleState)
888
- }); // END EventListener 'click'
889
- } // END largePlayerShuffleButton
1686
+ }); // END addEventListener
1687
+ } // END if largePlayerShuffleButton
890
1688
 
891
1689
  // click on repeat button
892
1690
  var largePlayerRepeatButton = document.getElementById('large_player_repeat');
893
- if (largePlayerShuffleButton) {
1691
+ if (largePlayerRepeatButton) {
894
1692
  largePlayerRepeatButton.addEventListener('click', function(event) {
895
1693
  var repeatState = (document.getElementById('large_player_repeat').className.includes('amplitude-repeat-on')) ? true : false;
1694
+ logger.debug('\n' + `Set repeat state to: ${repeatState}`);
896
1695
  Amplitude.setRepeat(repeatState)
897
- }); // END EventListener 'click'
1696
+ }); // END addEventListener
898
1697
  } // END if largePlayerRepeatButton
899
1698
 
900
- // enable|disable scrolling on playlist (large player)
1699
+ // enable|disable scrolling on playlist (LARGE player)
901
1700
  // -------------------------------------------------------
902
1701
  if (document.getElementById('large_player_right') !== null) {
903
1702
 
904
1703
  // show|hide scrollbar in playlist
905
1704
  // -----------------------------------------------------
906
- const songsInPlaylist = Amplitude.getSongsInPlaylist(playListName);
907
-
908
- if (songsInPlaylist.length <= 8) {
1705
+ var songsInPlaylist = Amplitude.getSongsInPlaylist(playListName);
1706
+ if (songsInPlaylist.length <= playerScrollerSongElementMin) {
909
1707
  const titleListLargePlayer = document.getElementById('large_player_title_list_' + playListName);
910
1708
  if (titleListLargePlayer !== null) {
911
1709
  titleListLargePlayer.classList.add('hide-scrollbar');
912
1710
  }
913
- }
1711
+ } // END show|hide scrollbar in playlist
914
1712
 
915
- // scroll to player top position (large player)
1713
+ // scroll player to top position (LARGE player)
916
1714
  //
917
1715
  // Bootstrap grid breakpoints
918
1716
  // SN: 576px Mobile
@@ -928,21 +1726,21 @@ j1.adapter.amplitude = ((j1, window) => {
928
1726
  var playlistHeader = document.getElementById("playlist_header_{{player.id}}");
929
1727
  var scrollOffset = (window.innerWidth >= 992) ? -130 : -44;
930
1728
 
931
- // scroll player|playlist to top position (large player)
932
- //
1729
+ // scroll player|playlist to top position (LARGE player)
1730
+ // NOTE: depending on WINDOW SIZE the relation changes to TOP POSITION (targetDivPosition)
1731
+ // -- ------------------------------------------------
933
1732
  const targetDivPlayerRight = playerRight;
934
1733
  const targetDivPositionPlayerRight = targetDivPlayerRight.offsetTop;
935
1734
  const targetDivPlaylistHeader = playlistHeader;
936
1735
  const targetDivPositionplaylistHeader = targetDivPlaylistHeader.offsetTop;
937
1736
 
938
- // NOTE: depending on WINDOW SIZE the relation changes to TOP POSITION (targetDivPosition)
939
- //
940
1737
  if (targetDivPositionPlayerRight > targetDivPositionplaylistHeader) {
941
1738
  window.scrollTo(0, targetDivPositionPlayerRight + targetDivPlaylistHeader.offsetParent.firstElementChild.clientHeight + scrollOffset);
942
1739
  } else {
943
1740
  window.scrollTo(0, targetDivPositionplaylistHeader + scrollOffset);
944
1741
  }
945
- }); // END EventListener 'click' largePlayerTitleHeader
1742
+
1743
+ }); // END addEventListener
946
1744
 
947
1745
  var largePlayerPlaylistHeader = document.getElementById("playlist_header_{{player.id}}");
948
1746
  largePlayerPlaylistHeader.addEventListener('click', function(event) {
@@ -950,7 +1748,7 @@ j1.adapter.amplitude = ((j1, window) => {
950
1748
  var playlistHeader = document.getElementById("playlist_header_{{player.id}}");
951
1749
  var scrollOffset = (window.innerWidth >= 992) ? -130 : -44;
952
1750
 
953
- // scroll player|playlist to top position (large player)
1751
+ // scroll player|playlist to top position (LARGE player)
954
1752
  //
955
1753
  const targetDivPlayerRight = playerRight;
956
1754
  const targetDivPositionPlayerRight = targetDivPlayerRight.offsetTop;
@@ -965,7 +1763,7 @@ j1.adapter.amplitude = ((j1, window) => {
965
1763
  window.scrollTo(0, targetDivPositionplaylistHeader + scrollOffset);
966
1764
  }
967
1765
 
968
- }); // END EventListener 'click' largePlayerPlaylistHeader
1766
+ }); // END addEventListener
969
1767
 
970
1768
  // disable scrolling (if window viewport >= BS Medium and above)
971
1769
  document.getElementById('large_player_right').addEventListener('mouseenter', function() {
@@ -976,14 +1774,14 @@ j1.adapter.amplitude = ((j1, window) => {
976
1774
  $('body').addClass('stop-scrolling');
977
1775
  }
978
1776
  }
979
- }); // END EventListener 'mouseenter'
1777
+ }); // END addEventListener
980
1778
 
981
1779
  // enable scrolling
982
1780
  document.getElementById('large_player_right').addEventListener('mouseleave', function() {
983
1781
  if ($('body').hasClass('stop-scrolling')) {
984
1782
  $('body').removeClass('stop-scrolling');
985
1783
  }
986
- }); // END EventListener 'mouseleave'
1784
+ }); // END addEventListener
987
1785
 
988
1786
  } // END enable|disable scrolling on playlist
989
1787
 
@@ -1037,11 +1835,9 @@ j1.adapter.amplitude = ((j1, window) => {
1037
1835
  playerExistsInPage = (document.getElementById('{{player.id}}_app') !== null) ? true : false;
1038
1836
  pluginManagerEnabled = ('{{player.plugin_manager.enabled}}'.length > 0 && '{{player.plugin_manager.enabled}}' === 'true') ? true : playerDefaultPluginManager;
1039
1837
 
1040
- if (playerExistsInPage && pluginManagerEnabled && !pluginManagerRunOnce) {
1838
+ var ytpPluginInstalled = j1.adapter.amplitude.data.atpGlobals.ytpInstalled;
1839
+ if (playerExistsInPage && pluginManagerEnabled && !ytpPluginInstalled) {
1041
1840
  _this.pluginManager('{{player.plugin_manager.plugins}}');
1042
-
1043
- // make sure the plugin is loaded|run only ONCE
1044
- pluginManagerRunOnce = true;
1045
1841
  }
1046
1842
 
1047
1843
  clearInterval(load_dependencies['dependencies_met_player_loaded_{{player.id}}']);
@@ -1116,9 +1912,21 @@ j1.adapter.amplitude = ((j1, window) => {
1116
1912
  // pluginManager()
1117
1913
  //
1118
1914
  // -------------------------------------------------------------------------
1119
- pluginManager: (plugin) => {
1120
- // if (plugin === 'ytp' && j1.adapter.amplitude['ytPlayerReady'] === undefined ) {
1121
- if (plugin === 'ytp') {
1915
+ pluginManager: (plugin) => {
1916
+
1917
+ function isPluginLoaded(pluginName) {
1918
+ const scripts = document.scripts;
1919
+ const pluginFile = pluginName + '.js';
1920
+
1921
+ for (let i = 0; i < scripts.length; i++) {
1922
+ if (scripts[i].src.includes(pluginFile)) {
1923
+ return true;
1924
+ }
1925
+ }
1926
+ return false;
1927
+ }
1928
+
1929
+ if (plugin !== '' && plugin === 'ytp') {
1122
1930
  var tech;
1123
1931
  var techScript;
1124
1932
 
@@ -1129,8 +1937,88 @@ j1.adapter.amplitude = ((j1, window) => {
1129
1937
 
1130
1938
  techScript.parentNode.insertBefore(tech, techScript);
1131
1939
  }
1940
+
1941
+ if (plugin !== '' && isPluginLoaded(plugin)) {
1942
+ logger.debug('\n' + 'plugin loaded: ' + plugin);
1943
+
1944
+ // make sure the plugin installed only ONCE
1945
+ j1.adapter.amplitude.data.atpGlobals.ytpInstalled = true;
1946
+ }
1132
1947
  }, // END pluginManager
1133
1948
 
1949
+ // -------------------------------------------------------------------------
1950
+ // atPlayerScrollToActiveElement(metaData)
1951
+ // -------------------------------------------------------------------------
1952
+ atPlayerScrollToActiveElement: (metaData) => {
1953
+ var scrollableList, songIndex,
1954
+ activeElement, activeElementOffsetTop,
1955
+ songElementMin, numSongs;
1956
+
1957
+ if (!playerAutoScrollSongElement) {
1958
+ // do nothing if playerAutoScrollSongElement is false
1959
+ return;
1960
+ }
1961
+
1962
+ songIndex = metaData.index;
1963
+ songElementMin = playerScrollerSongElementMin;
1964
+ numSongs = Amplitude.getSongsInPlaylist(metaData.playlist).length;
1965
+ scrollableList = document.getElementById('large_player_title_list_' + metaData.playlist);
1966
+ activeElement = scrollableList.querySelector('.amplitude-active-song-container');
1967
+
1968
+ if (activeElement === null || scrollableList === null) {
1969
+ // do nothing if NO scrollableList or ACTIVE element found (failsafe)
1970
+ return;
1971
+ }
1972
+
1973
+ if (songIndex > 0 && numSongs >= songElementMin) {
1974
+ scrollableList = document.getElementById('large_player_title_list_' + metaData.playlist);
1975
+ activeElement = scrollableList.querySelector('.amplitude-active-song-container');
1976
+ activeElementOffsetTop = songIndex * j1.adapter.amplitude.data.playerSongElementHeigth;
1977
+ scrollableList.scrollTop = activeElementOffsetTop;
1978
+ } else {
1979
+ // do nothing if songIndex is 0 or less than songElementMin
1980
+ return;
1981
+ }
1982
+
1983
+ }, // END atPlayerScrollToActiveElement
1984
+
1985
+ // -------------------------------------------------------------------------
1986
+ // atUpdateSongRating(playlist, rating)
1987
+ //
1988
+ // update song rating in playlist-screen|meta-container
1989
+ // -------------------------------------------------------------------------
1990
+ atUpdateSongRating: (metaData) => {
1991
+ var screenControlRating = null;
1992
+ var screenControlRatingElements = document.getElementsByClassName('audio-rating-screen-controls');
1993
+ var ratingIndex;
1994
+
1995
+ for (let i=0; i<screenControlRatingElements.length; i++) {
1996
+ var ratingElement = screenControlRatingElements[i];
1997
+ var rating = parseInt(metaData.rating);
1998
+ var playerType = ratingElement.dataset.playerType;
1999
+ var activePlayerType = j1.adapter.amplitude.data.atpGlobals.activePlayerType;
2000
+ var activePlayist = metaData.playlist;
2001
+
2002
+ if (ratingElement.dataset.amplitudePlaylist === activePlayist && playerType === activePlayerType) {
2003
+ ratingIndex = i;
2004
+ screenControlRating = ratingElement;
2005
+ break;
2006
+ }
2007
+
2008
+ }
2009
+
2010
+ // set the rating for ACTIVE screenControlRatingElement
2011
+ // -----------------------------------------------------------------------
2012
+ if (screenControlRating) {
2013
+ if (rating) {
2014
+ ratingElement.innerHTML = '<img src="/assets/image/pattern/rating/scalable/' + rating + '-star.svg"' + 'alt="song rating">';
2015
+ } else {
2016
+ ratingElement.innerHTML = '';
2017
+ }
2018
+ }
2019
+
2020
+ }, // END atUpdateSongRating
2021
+
1134
2022
  // -------------------------------------------------------------------------
1135
2023
  // messageHandler()
1136
2024
  // manage messages send from other J1 modules