j1-template 2024.3.19 → 2024.3.20

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 (87) hide show
  1. checksums.yaml +4 -4
  2. data/assets/data/amplitude_app.html +174 -150
  3. data/assets/data/swiper_app.2.html +757 -0
  4. data/assets/data/swiper_app.4.html +769 -0
  5. data/assets/data/swiper_app.html +171 -27
  6. data/assets/theme/j1/adapter/js/amplitude.js +817 -165
  7. data/assets/theme/j1/adapter/js/swiper.js +63 -15
  8. data/assets/theme/j1/core/css/themes/bootstrap/bootstrap.css +111 -101
  9. data/assets/theme/j1/core/css/themes/bootstrap/bootstrap.min.css +1 -1
  10. data/assets/theme/j1/core/css/themes/unodark/bootstrap.css +111 -101
  11. data/assets/theme/j1/core/css/themes/unodark/bootstrap.min.css +1 -1
  12. data/assets/theme/j1/core/css/themes/unolight/bootstrap.css +111 -101
  13. data/assets/theme/j1/core/css/themes/unolight/bootstrap.min.css +1 -1
  14. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/amplitude.css +140 -219
  15. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/amplitude.min.css +1 -1
  16. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/player/compact.css +117 -23
  17. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/player/compact.min.css +1 -1
  18. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/player/large.css +323 -493
  19. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/player/large.min.css +1 -2
  20. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/player/mini.css +20 -73
  21. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/player/mini.min.css +1 -1
  22. data/assets/theme/j1/modules/amplitudejs/js/tech/ytp.js +2062 -843
  23. data/assets/theme/j1/modules/amplitudejs/scss/theme/uno/dark/player/large.scss +439 -264
  24. data/assets/theme/j1/modules/swiperjs/css/modules/layoutBase.css +16 -0
  25. data/assets/theme/j1/modules/swiperjs/css/modules/layoutBase.min.css +16 -0
  26. data/assets/theme/j1/modules/swiperjs/css/modules/layoutExpanding.css +24 -24
  27. data/assets/theme/j1/modules/swiperjs/css/modules/layoutExpanding.min.css +1 -235
  28. data/assets/theme/j1/modules/swiperjs/css/modules/layoutNeighbor.min.css +2 -2
  29. data/assets/theme/j1/modules/swiperjs/css/modules/layoutParallax.css +16 -0
  30. data/assets/theme/j1/modules/swiperjs/css/modules/layoutParallax.min.css +16 -0
  31. data/assets/theme/j1/modules/swiperjs/css/modules/layoutStacked.css +6 -7
  32. data/assets/theme/j1/modules/swiperjs/css/modules/layoutStacked.min.css +1 -82
  33. data/assets/theme/j1/modules/swiperjs/css/modules/layoutThumbs.min.css +2 -29
  34. data/assets/theme/j1/modules/swiperjs/css/theme/uno.css +29 -12
  35. data/assets/theme/j1/modules/swiperjs/css/theme/uno.min.css +1 -1
  36. data/assets/theme/j1/modules/swiperjs/js/modules/layoutBase.js +25 -0
  37. data/assets/theme/j1/modules/swiperjs/js/modules/layoutBase.min.js +25 -0
  38. data/assets/theme/j1/modules/swiperjs/js/modules/layoutExpanding.js +1 -5
  39. data/assets/theme/j1/modules/swiperjs/js/modules/layoutExpanding.min.js +1 -5
  40. data/assets/theme/j1/modules/swiperjs/js/modules/layoutNeighbor.js +12 -14
  41. data/assets/theme/j1/modules/swiperjs/js/modules/layoutNeighbor.min.js +1 -17
  42. data/assets/theme/j1/modules/swiperjs/js/modules/layoutPanorama.js +0 -1
  43. data/assets/theme/j1/modules/swiperjs/js/modules/layoutParallax.js +25 -0
  44. data/assets/theme/j1/modules/swiperjs/js/modules/layoutParallax.min.js +25 -0
  45. data/assets/theme/j1/modules/swiperjs/js/modules/layoutStacked.0.js +114 -0
  46. data/assets/theme/j1/modules/swiperjs/js/modules/layoutStacked.1.js +93 -0
  47. data/assets/theme/j1/modules/swiperjs/js/modules/layoutStacked.js +42 -13
  48. data/assets/theme/j1/modules/swiperjs/js/modules/layoutStacked.min.js +17 -0
  49. data/assets/theme/j1/modules/swiperjs/js/modules/layoutThumbs.js +76 -25
  50. data/assets/theme/j1/modules/swiperjs/js/modules/layoutThumbs.min.js +1 -17
  51. data/assets/theme/j1/modules/swiperjs/js/swiper-bundle.js +9152 -9131
  52. data/assets/theme/j1/modules/swiperjs/js/swiper-bundle.min.js +1 -1
  53. data/lib/j1/version.rb +1 -1
  54. data/lib/starter_web/README.md +5 -5
  55. data/lib/starter_web/_config.yml +1 -1
  56. data/lib/starter_web/_data/modules/amplitude_app.yml +206 -23
  57. data/lib/starter_web/_data/modules/amplitude_playlists.yml +1122 -19
  58. data/lib/starter_web/_data/modules/defaults/{amplitude_app.yml → amplitude.yml} +70 -26
  59. data/lib/starter_web/_data/modules/swiper_app.yml +289 -155
  60. data/lib/starter_web/_data/modules/swiper_playlists.yml +51 -1
  61. data/lib/starter_web/_data/resources.yml +6 -2
  62. data/lib/starter_web/_data/templates/feed.xml +1 -1
  63. data/lib/starter_web/_plugins/filter/filters.rb +1 -11
  64. data/lib/starter_web/_plugins/index/lunr.rb +1 -1
  65. data/lib/starter_web/assets/image/module/swiper/avatar/avatar-1.png +0 -0
  66. data/lib/starter_web/assets/image/module/swiper/avatar/avatar-2.png +0 -0
  67. data/lib/starter_web/assets/image/module/swiper/avatar/avatar-3.png +0 -0
  68. data/lib/starter_web/assets/image/module/swiper/avatar/avatar-4.png +0 -0
  69. data/lib/starter_web/assets/image/module/swiper/avatar/avatar-5.png +0 -0
  70. data/lib/starter_web/package.json +1 -1
  71. data/lib/starter_web/pages/public/tools/previewer/preview_amplitudejs.adoc +82 -34
  72. data/lib/starter_web/pages/public/tools/tester/app_tester_amplitudejs_yt.adoc +62 -15
  73. data/lib/starter_web/pages/public/tools/tester/app_tester_swiperjs.adoc +121 -36
  74. data/lib/starter_web/pages/public/tour/play_audio.adoc +60 -70
  75. data/lib/starter_web/pages/public/tour/play_video.adoc +1 -1
  76. metadata +29 -14
  77. data/assets/theme/j1/modules/swiperjs/js/highlightJS.js +0 -13376
  78. data/assets/theme/j1/modules/swiperjs/js/highlightJS.min.js +0 -1246
  79. data/assets/theme/j1/modules/swiperjs/js/modules/!readme +0 -3
  80. /data/lib/starter_web/assets/image/module/swiper/extended/{poster → stacked}/!info/!readme +0 -0
  81. /data/lib/starter_web/assets/image/module/swiper/extended/{poster → stacked}/image/!readme +0 -0
  82. /data/lib/starter_web/assets/image/module/swiper/extended/{poster → stacked}/image/1.jpg +0 -0
  83. /data/lib/starter_web/assets/image/module/swiper/extended/{poster → stacked}/image/2.jpg +0 -0
  84. /data/lib/starter_web/assets/image/module/swiper/extended/{poster → stacked}/image/3.jpg +0 -0
  85. /data/lib/starter_web/assets/image/module/swiper/extended/{poster → stacked}/image/4.jpg +0 -0
  86. /data/lib/starter_web/assets/image/module/swiper/extended/{poster → stacked}/image/5.jpg +0 -0
  87. /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.38.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.38.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,7 +163,10 @@ j1.adapter.amplitude = ((j1, window) => {
157
163
  var playersProcessed = [];
158
164
  var playersHtmlLoaded = false;
159
165
  var processingPlayersFinished = false;
160
- var pluginManagerRunOnce = false;
166
+
167
+ var playerSongElementHeigthDesktop = {{amplitude_defaults.player.song_element_heigt_desktop}};
168
+ var playerSongElementHeigthMobile = {{amplitude_defaults.player.song_element_heigth_mobile}};
169
+ var playerAutoScrollSongElement = {{amplitude_defaults.player.player_auto_scroll_song_element}};
161
170
 
162
171
  var playerAudioInfo = ('{{amplitude_defaults.playlist.audio_info}}' === 'true') ? true : false;
163
172
  var playerDefaultPluginManager = ('{{amplitude_defaults.player.plugin_manager.enabled}}' === 'true') ? true : false;
@@ -208,21 +217,24 @@ j1.adapter.amplitude = ((j1, window) => {
208
217
  amplitudePlaylists = $.extend({}, {{amplitude_playlists | replace: 'nil', 'null' | replace: '=>', ':' }});
209
218
  amplitudeOptions = $.extend(true, {}, amplitudeDefaults, amplitudePlayers, amplitudePlaylists);
210
219
 
211
- // save AJS player setiings for later use (e.g. the AJS plugins)
212
- // j1.adapter.amplitude['amplitudeDefaults'] = amplitudeDefaults;
213
- // j1.adapter.amplitude['amplitudeSettings'] = amplitudeSettings;
214
- // j1.adapter.amplitude['amplitudeOptions'] = amplitudeOptions;
215
-
216
220
  // -----------------------------------------------------------------------
217
221
  // control|logging settings
218
222
  // -----------------------------------------------------------------------
219
- _this = j1.adapter.amplitude;
220
- logger = log4javascript.getLogger('j1.adapter.amplitude');
223
+ _this = j1.adapter.amplitude;
224
+ logger = log4javascript.getLogger('j1.adapter.amplitude');
221
225
 
222
226
  // prepare data element for later use
223
227
  j1.adapter.amplitude.data = {};
224
- j1.adapter.amplitude.data.ytpGlobals = {};
228
+ j1.adapter.amplitude.data.atpGlobals = {};
229
+ j1.adapter.amplitude.data.ytpGlobals = {};
225
230
  j1.adapter.amplitude.data.ytPlayers = {};
231
+
232
+ // (initial) YT player data for later use (e.g. events)
233
+ j1.adapter.amplitude.data.activePlayer = 'not_set';
234
+ j1.adapter.amplitude.data.playerSongElementHeigth = 'not_set';
235
+ j1.adapter.amplitude.data.atpGlobals.activePlayerType = 'not_set';
236
+ j1.adapter.amplitude.data.atpGlobals.ytpInstalled = false;
237
+ j1.adapter.amplitude.data.ytpGlobals.activePlayerType = 'not_set';
226
238
 
227
239
  // -----------------------------------------------------------------------
228
240
  // module initializer
@@ -231,14 +243,18 @@ j1.adapter.amplitude = ((j1, window) => {
231
243
  var pageState = $('#content').css("display");
232
244
  var pageVisible = (pageState === 'block') ? true : false;
233
245
  var j1CoreFinished = (j1.getState() === 'finished') ? true : false;
246
+ var atticFinished = (j1.adapter.attic.getState() == 'finished') ? true : false;
234
247
 
235
- if (j1CoreFinished && pageVisible) {
248
+ if (j1CoreFinished && pageVisible && atticFinished) {
236
249
  startTimeModule = Date.now();
237
250
 
238
251
  _this.setState('started');
239
252
  logger.debug('\n' + 'module state: ' + _this.getState());
240
253
  logger.info('\n' + 'module is being initialized');
241
254
 
255
+ // set default viewport setting
256
+ j1.adapter.amplitude.data.playerSongElementHeigth = playerSongElementHeigthDesktop;
257
+
242
258
  // -------------------------------------------------------------------
243
259
  // create global playlist (songs)
244
260
  // -------------------------------------------------------------------
@@ -263,7 +279,7 @@ j1.adapter.amplitude = ((j1, window) => {
263
279
  }, 10); // END dependencies_met_players_loaded
264
280
 
265
281
  // -------------------------------------------------------------------
266
- // initialize player specific UI events
282
+ // initialize player specific events
267
283
  // -------------------------------------------------------------------
268
284
  var dependencies_met_api_initialized = setInterval (() => {
269
285
  if (apiInitialized.state) {
@@ -273,6 +289,24 @@ j1.adapter.amplitude = ((j1, window) => {
273
289
  } // END if apiInitialized
274
290
  }, 10); // END dependencies_met_api_initialized
275
291
 
292
+ // initialize viewPort specific (GLOBAL) settings
293
+ $(window).bind('resizeEnd', function() {
294
+ var viewPortSize = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0);
295
+ //do something, window hasn't changed size in 500ms
296
+ if (viewPortSize > 578) {
297
+ j1.adapter.amplitude.data.playerSongElementHeigth = playerSongElementHeigthDesktop;
298
+ } else {
299
+ j1.adapter.amplitude.data.playerSongElementHeigth = playerSongElementHeigthMobile;
300
+ }
301
+ });
302
+
303
+ $(window).resize(function() {
304
+ if(this.resizeTO) clearTimeout(this.resizeTO);
305
+ this.resizeTO = setTimeout(function() {
306
+ $(this).trigger('resizeEnd');
307
+ }, 500);
308
+ });
309
+
276
310
  clearInterval(dependencies_met_page_ready);
277
311
  } // END pageVisible
278
312
  }, 10); // END dependencies_met_page_ready
@@ -320,7 +354,10 @@ j1.adapter.amplitude = ((j1, window) => {
320
354
  continue;
321
355
  } else if (key === 'rating') {
322
356
  song.rating = item[key];
323
- continue;
357
+ continue;
358
+ } else if (key === 'shuffle') {
359
+ song.shuffle = item[key];
360
+ continue;
324
361
  } else {
325
362
  song[key] = item[key];
326
363
  } // END if key
@@ -332,7 +369,7 @@ j1.adapter.amplitude = ((j1, window) => {
332
369
 
333
370
  {% endif %} {% endfor %}
334
371
 
335
- logger.info('\n' + 'creating global playlist (API): finished');
372
+ logger.info('\n' + 'creating global playlist (API): finished');
336
373
  }, // END songLoader
337
374
 
338
375
  // -------------------------------------------------------------------------
@@ -408,6 +445,7 @@ j1.adapter.amplitude = ((j1, window) => {
408
445
  // initApi
409
446
  // -------------------------------------------------------------------------
410
447
  initApi: (songlist) => {
448
+
411
449
  logger.info('\n' + 'initialze API: started');
412
450
 
413
451
  {% comment %} collect playlists
@@ -424,16 +462,25 @@ j1.adapter.amplitude = ((j1, window) => {
424
462
  {% assign playlist_title = list.title %}
425
463
 
426
464
  {% comment %} collect song items
465
+ NOTE: configure all properties avaialble in songs array
427
466
  ------------------------------------------------------------------------ {% endcomment %}
428
467
  {% for item in playlist_items %} {% if item.enabled %}
429
468
  {% capture song_item %}
430
469
  {
431
470
  "name": "{{item.title}}",
471
+ // "track": "{{item.track}}",
432
472
  "artist": "{{item.artist}}",
473
+ "playlist": "{{item.playlist}}",
433
474
  "album": "{{item.name}}",
434
475
  "url": "{{item.audio_base}}/{{item.audio}}",
435
476
  "audio_info": "{{item.audio_info}}",
436
477
  "rating": "{{item.rating}}",
478
+ "start": "{{item.start}}",
479
+ "end": "{{item.end}}",
480
+ "shuffle": "{{item.shuffle}}",
481
+ "duration": "{{item.duration}}",
482
+ // "audio_fade_in": "{{item.audio_fade_in}}",
483
+ // "audio_fade_out": "{{item.audio_fade_out}}",
437
484
  "cover_art_url": "{{item.cover_image}}"
438
485
  }{% if forloop.last %}{% else %},{% endif %}
439
486
  {% endcapture %}
@@ -492,26 +539,40 @@ j1.adapter.amplitude = ((j1, window) => {
492
539
  console.error('\n' + 'Amplitude API failed on initialization');
493
540
  },
494
541
  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';
542
+ // make sure the player is playing
543
+ setTimeout(() => {
544
+ onPlayerStateChange(1);
545
+ }, 150);
499
546
  },
500
547
  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';
548
+ // make sure the player is paused
549
+ setTimeout(() => {
550
+ onPlayerStateChange(2);
551
+ }, 150);
552
+ },
553
+ stop: function() {
554
+ // make sure the player is stopped
555
+ setTimeout(() => {
556
+ onPlayerStateChange(3);
557
+ }, 150);
505
558
  },
506
559
  song_change: function() {
507
- var songMetaData = Amplitude.getActiveSongMetadata();
508
- logger.debug('\n' + 'changed to title: ' + songMetaData.name + ' with titleIndex ' + songMetaData.index);
560
+ // make sure the player has changed
561
+ setTimeout(() => {
562
+ var currentState = Amplitude.getPlayerState();
563
+ if (currentState === 'stopped') {
564
+ // onPlayerStateChange(3);
565
+ return;
566
+ } else {
567
+ onPlayerStateChange(6);
568
+ }
569
+ }, 150);
509
570
  },
510
- next: function() {
511
- var songMetaData = Amplitude.getActiveSongMetadata();
512
-
571
+ prev: function() {
572
+ var currentState = Amplitude.getPlayerState();
573
+ onPlayerStateChange(4);
513
574
  if (playerDelayNextTitle) {
514
- logger.debug('\n' + 'delay on next title: ' + songMetaData.name + ' with titleIndex ' + songMetaData.index);
575
+ logger.debug('\n' + 'delay on previous title: ' + songMetaData.name + ' with titleIndex ' + songMetaData.index);
515
576
  }
516
577
 
517
578
  if (playerPauseNextTitle) {
@@ -524,12 +585,13 @@ j1.adapter.amplitude = ((j1, window) => {
524
585
  }, 150);
525
586
  } // END if playing
526
587
  } // END if pause on next title
527
- },
528
- prev: function() {
529
- var songMetaData = Amplitude.getActiveSongMetadata();
530
588
 
589
+ return;
590
+ },
591
+ next: function() {
592
+ onPlayerStateChange(5);
531
593
  if (playerDelayNextTitle) {
532
- logger.debug('\n' + 'delay on previous title: ' + songMetaData.name + ' with titleIndex ' + songMetaData.index);
594
+ logger.debug('\n' + 'delay on next title: ' + songMetaData.name + ' with titleIndex ' + songMetaData.index);
533
595
  }
534
596
 
535
597
  if (playerPauseNextTitle) {
@@ -542,6 +604,12 @@ j1.adapter.amplitude = ((j1, window) => {
542
604
  }, 150);
543
605
  } // END if playing
544
606
  } // END if pause on next title
607
+
608
+ return;
609
+ },
610
+ ended: function() {
611
+ onPlayerStateChange(0);
612
+ return;
545
613
  }
546
614
  }, // END callbacks
547
615
 
@@ -556,8 +624,403 @@ j1.adapter.amplitude = ((j1, window) => {
556
624
 
557
625
  }); // END Amplitude init
558
626
 
627
+ // -----------------------------------------------------------------------
628
+ // timestamp2seconds
629
+ //
630
+ // TODO: Add support for timestamp w/o hours like mm:ss
631
+ // -----------------------------------------------------------------------
632
+ function timestamp2seconds(timestamp) {
633
+ // split timestamp
634
+ const parts = timestamp.split(':');
635
+
636
+ // check timestamp format
637
+ if (parts.length !== 3) {
638
+ // return "invalid timestamp";
639
+ return false;
640
+ }
641
+
642
+ // convert parts to integers
643
+ const hours = parseInt(parts[0], 10);
644
+ const minutes = parseInt(parts[1], 10);
645
+ const seconds = parseInt(parts[2], 10);
646
+
647
+ // check valid timestamp values
648
+ if (isNaN(hours) || isNaN(minutes) || isNaN(seconds) ||
649
+ hours < 0 || hours > 23 ||
650
+ minutes < 0 || minutes > 59 ||
651
+ seconds < 0 || seconds > 59) {
652
+ return "invalid timestamp";
653
+ }
654
+
655
+ const totalSeconds = (hours * 3600) + (minutes * 60) + seconds;
656
+
657
+ return totalSeconds;
658
+ } // END timestamp2seconds
659
+
660
+ // -----------------------------------------------------------------------
661
+ // seconds2timestamp
662
+ // -----------------------------------------------------------------------
663
+ function seconds2timestamp(seconds) {
664
+
665
+ if (isNaN(seconds)) {
666
+ return false;
667
+ }
668
+
669
+ const hours = Math.floor(seconds / 3600);
670
+ const minutes = Math.floor((seconds % 3600) / 60);
671
+ const remainSeconds = seconds % 60;
672
+ const tsHours = hours.toString().padStart(2, '0');
673
+ const tsMinutes = minutes.toString().padStart(2, '0');
674
+ const tsSeconds = remainSeconds.toString().padStart(2, '0');
675
+
676
+ return `${tsHours}:${tsMinutes}:${tsSeconds}`;
677
+ } // END seconds2timestamp
678
+
679
+ // -----------------------------------------------------------------------
680
+ // atpFadeInAudio
681
+ // -----------------------------------------------------------------------
682
+ function atpFadeInAudio(params) {
683
+ const cycle = 1;
684
+ var settings, currentStep, steps, sliderID, volumeSlider;
685
+
686
+ isFadingIn = true;
687
+
688
+ // current fade-in settings using DEFAULTS (if available)
689
+ settings = {
690
+ playerID: params.playerID,
691
+ targetVolume: params.targetVolume = 50,
692
+ speed: params.speed = 'default'
693
+ };
694
+
695
+ // number of iteration steps to INCREASE the players volume on fade-in
696
+ // NOTE: number of steps controls how long and smooth the fade-in
697
+ // transition will be
698
+ const iterationSteps = {
699
+ 'default': 150,
700
+ 'slow': 250,
701
+ 'slower': 350,
702
+ 'slowest': 500
703
+ };
704
+
705
+ sliderID = 'volume_slider_' + settings.playerID;
706
+ volumeSlider = document.getElementById(sliderID);
707
+ steps = iterationSteps[settings.speed];
708
+ currentStep = 1;
709
+
710
+ if (volumeSlider === undefined || volumeSlider === null) {
711
+ logger.warn('\n' + 'no volume slider found at playerID: ' + settings.playerID);
712
+ return;
713
+ }
714
+
715
+ // Start the players volume muted
716
+ Amplitude.setVolume(0);
717
+
718
+ const fadeInInterval = setInterval(() => {
719
+ const newVolume = settings.targetVolume * (currentStep / steps);
720
+
721
+ Amplitude.setVolume(newVolume);
722
+ volumeSlider.value = newVolume;
723
+ currentStep++;
724
+
725
+ if (currentStep > steps) {
726
+ isFadingIn = false;
727
+ clearInterval(fadeInInterval);
728
+ }
729
+
730
+ }, cycle);
731
+
732
+ } // END atpFadeInAudio
733
+
734
+ // -----------------------------------------------------------------------
735
+ // atpFadeAudioOut
736
+ //
737
+ // returns true if fade-out is finished
738
+ // -----------------------------------------------------------------------
739
+ function atpFadeAudioOut(params) {
740
+ const cycle = 1;
741
+ var settings, currentStep, steps, sliderID, songs,
742
+ startVolume, newVolume, defaultVolume, volumeSlider;
743
+
744
+ // current fade-out settings using DEFAULTS (if available)
745
+ settings = {
746
+ playerID: params.playerID,
747
+ speed: params.speed = 'default'
748
+ };
749
+
750
+ isFadingOut = true;
751
+
752
+ // number of iteration steps to INCREASE the players volume on fade-in
753
+ // NOTE: number of steps controls how long and smooth the fade-in
754
+ // transition will be
755
+ const iterationSteps = {
756
+ 'default': 150,
757
+ 'slow': 250,
758
+ 'slower': 350,
759
+ 'slowest': 500
760
+ };
761
+
762
+ sliderID = 'volume_slider_' + settings.playerID;
763
+ volumeSlider = document.getElementById(sliderID);
764
+ startVolume = Amplitude.getVolume();
765
+ steps = iterationSteps[settings.speed];
766
+ currentStep = 1;
767
+ defaultVolume = 50;
768
+
769
+ var songMetaData = Amplitude.getActiveSongMetadata();
770
+ var songEndTS = songMetaData.end;
771
+ var playlist = songMetaData.playlist;
772
+ var songIndex = songMetaData.index;
773
+ var trackID = songIndex + 1;
774
+
775
+ if (volumeSlider !== null) {
776
+ const fadeOutInterval = setInterval(() => {
777
+ newVolume = startVolume * (1 - currentStep / steps);
778
+
779
+ Amplitude.setVolume(newVolume);
780
+ volumeSlider.value = newVolume;
781
+ currentStep++;
782
+
783
+ // seek current audio to total end to continue on next track
784
+ if (currentStep > steps) {
785
+ songs = Amplitude.getSongsInPlaylist(playlist);
786
+
787
+ if (songIndex === songs.length-1) {
788
+ logger.debug('\n' + 'restore player volume on last trackID|volume at: ' + trackID + '|' + defaultVolume);
789
+ volumeSlider.value = defaultVolume;
790
+ }
791
+
792
+ isFadingOut = false;
793
+ clearInterval(fadeOutInterval);
794
+ }
795
+ }, cycle);
796
+ } // END if volumeSlider
797
+
798
+ } // END atpFadeAudioOut
799
+
800
+ // -----------------------------------------------------------------------
801
+ // onPlayerStateChange
802
+ //
803
+ // update AT player on state change
804
+ // -----------------------------------------------------------------------
805
+ function onPlayerStateChange(state) {
806
+ var playerID, playlist, songs, songIndex, songIndex, trackID,
807
+ songStart, songEnd, songStartSec, songEndSec,
808
+ songStartTS, songEndTS, songMetaData, currentVolume,
809
+ activeSongMetadata, fadeAudio;
810
+
811
+ activeSongMetadata = Amplitude.getActiveSongMetadata();
812
+ playlist = Amplitude.getActivePlaylist();
813
+ // playlist = activeSongMetadata.playlist
814
+ playerID = playlist + '_large';
815
+ songs = Amplitude.getSongsInPlaylist(playlist);
816
+ songMetaData = Amplitude.getActiveSongMetadata();
817
+ songIndex = songMetaData.index;
818
+ trackID = songIndex + 1;
819
+
820
+ if (state === AT_PLAYER_STATE.UNSTARTED) {
821
+ // logger.debug('\n' + 'current audio state: unstarted');
822
+ return;
823
+ }
824
+
825
+ if (state === AT_PLAYER_STATE.STOPPED) {
826
+ logger.debug('\n' + 'audio player on playlist: ' + playlist + ' at trackID|state: ' + trackID + '|' + AT_PLAYER_STATE_NAMES[state]);
827
+ return;
828
+ }
829
+
830
+ if (state === AT_PLAYER_STATE.PAUSED) {
831
+ logger.debug('\n' + 'audio player on playlist: ' + playlist + ' at trackID|state: ' + trackID + '|' + AT_PLAYER_STATE_NAMES[state]);
832
+ return;
833
+ }
834
+
835
+ if (state === AT_PLAYER_STATE.PREVIOUS) {
836
+ logger.debug('\n' + 'audio player on playlist: ' + playlist + ' at trackID|state: ' + trackID + '|' + AT_PLAYER_STATE_NAMES[state]);
837
+ return;
838
+ }
839
+
840
+ if (state === AT_PLAYER_STATE.NEXT) {
841
+ logger.debug('\n' + 'audio player on playlist: ' + playlist + ' at trackID|state: ' + trackID + '|' + AT_PLAYER_STATE_NAMES[state]);
842
+ return;
843
+ }
844
+
845
+ if (state === AT_PLAYER_STATE.CHANGED) {
846
+ logger.debug('\n' + 'audio player on playlist: ' + playlist + ' at trackID|state: ' + trackID + '|' + AT_PLAYER_STATE_NAMES[state]);
847
+ return;
848
+ }
849
+
850
+ if (state === AT_PLAYER_STATE.PLAYING) {
851
+ var playList, activePlayist, playerID, playerType,
852
+ activePlayerType, startVolume, songIndex,
853
+ ratingIndex, rating, ratingElement,
854
+ screenControlRatingElements, screenControlRating;
855
+
856
+ songMetaData = Amplitude.getActiveSongMetadata();
857
+ songIndex = songMetaData.index;
858
+ playList = songMetaData.playlist;
859
+ playList = Amplitude.getActivePlaylist();
860
+ trackID = songIndex + 1;
861
+
862
+ songStartTS = songMetaData.start;
863
+ songEndTS = songMetaData.end;
864
+ songStartSec = timestamp2seconds(songStartTS);
865
+ songEndSec = timestamp2seconds(songEndTS);
866
+ startVolume = Amplitude.getVolume();
867
+
868
+ logger.debug('\n' + 'audio player on playlist: ' + playList + ' at trackID|state: ' + trackID + '|' + AT_PLAYER_STATE_NAMES[state]);
869
+
870
+ // update song rating in playlist-screen|meta-container
871
+ // -------------------------------------------------------------------
872
+
873
+ // search for ACTIVE screenControlRatingElement
874
+ screenControlRating = null;
875
+ screenControlRatingElements = document.getElementsByClassName('audio-rating-screen-controls');
876
+ for (let i=0; i<screenControlRatingElements.length; i++) {
877
+ ratingElement = screenControlRatingElements[i];
878
+ rating = parseInt(songMetaData.rating);
879
+ playerType = ratingElement.dataset.playerType;
880
+ activePlayerType = j1.adapter.amplitude.data.atpGlobals.activePlayerType;
881
+ activePlayist = songMetaData.playlist
882
+
883
+ if (ratingElement.dataset.amplitudePlaylist === activePlayist && playerType === activePlayerType) {
884
+ ratingIndex = i;
885
+ screenControlRating = ratingElement;
886
+ break;
887
+ }
888
+ }
889
+
890
+ // set the rating for ACTIVE screenControlRatingElements
891
+ if (screenControlRating) {
892
+ if (rating) {
893
+ screenControlRatingElements[ratingIndex].innerHTML = '<img src="/assets/image/pattern/rating/scalable/' + rating + '-star.svg"' + 'alt="song rating">';
894
+ } else {
895
+ screenControlRatingElements[ratingIndex].innerHTML = '';
896
+ }
897
+ } // END if screenControlRating
898
+
899
+ // process audio for configured START position
900
+ // -------------------------------------------------------------------
901
+ var checkIsFading = setInterval (() => {
902
+ if (!isFadingIn) {
903
+ var currentAudioTime = Amplitude.getSongPlayedSeconds();
904
+ if (songStartSec && currentAudioTime <= songStartSec) {
905
+ var songDurationSec = timestamp2seconds(songMetaData.duration);
906
+
907
+ // seek audio to configured START position
908
+ // NOTE: use setSongPlayedPercentage for seeking to NOT
909
+ // generation any addition state changes like stopped
910
+ // or playing
911
+ logger.debug('\n' + 'seek audio in on playlist: ' + playList + ' at|to trackID|timestamp: ' + trackID + '|' + songStartTS);
912
+ Amplitude.setSongPlayedPercentage((songStartSec / songDurationSec) * 100);
913
+
914
+ // fade-in audio (if enabled)
915
+ var fadeAudioIn = (songMetaData.audio_fade_in === 'true') ? true : false;
916
+ if (fadeAudioIn) {
917
+ logger.debug('\n' + 'faden audio in on playlist: ' + playList + ' at|to trackID|timestamp: ' + trackID + '|' + songStartTS);
918
+ atpFadeInAudio({ playerID: playerID });
919
+ } // END if fadeAudio
920
+
921
+ } // END if songStartSec
922
+
923
+ clearInterval(checkIsFading);
924
+ }
925
+ }, 100); // END checkIsFading
926
+
927
+ // check|process audio for configured END position
928
+ // -------------------------------------------------------------------
929
+ if (songEndSec > songStartSec) {
930
+ var checkIsOnVideoEnd = setInterval(() => {
931
+
932
+ if (!isFadingOut) {
933
+ var currentAudioTime = Amplitude.getSongPlayedSeconds();
934
+ var songMetaData = Amplitude.getActiveSongMetadata();
935
+ var songEndTS = songMetaData.end;
936
+ var songEndSec = timestamp2seconds(songEndTS);
937
+
938
+ if (currentAudioTime > songEndSec) {
939
+ songMetaData = Amplitude.getActiveSongMetadata();
940
+ songIndex = songMetaData.index;
941
+ trackID = songIndex + 1;
942
+
943
+ // seek audio out to total end END position
944
+ // NOTE: use setSongPlayedPercentage for seeking to NOT
945
+ // generation any addition state changes like stopped
946
+ // or playing
947
+ logger.debug('\n' + 'seek audio out to end on playlist: ' + playList + ' at trackID|timestamp: ' + trackID + '|' + songEndTS);
948
+ Amplitude.setSongPlayedPercentage(99.99);
949
+
950
+ // fade-out audio (if enabled)
951
+ var fadeAudioOut = (songMetaData.audio_fade_out === 'true') ? true : false;
952
+ if (fadeAudioOut) {
953
+ logger.debug('\n' + 'fade audio out on playlist: ' + playList + ' at|to trackID|timestamp: ' + trackID + '|' + songEndTS);
954
+ atpFadeAudioOut({ playerID: playerID });
955
+ } // END if fadeAudio
956
+
957
+ clearInterval(checkIsOnVideoEnd);
958
+ } // END if currentAudioTime
959
+
960
+ } // END if !isFading
961
+
962
+ }, 100); // END checkIsOnVideoEnd
963
+ } // END if songEndSec
964
+
965
+ // stop active YT players running in parallel
966
+ // -------------------------------------------------------------------
967
+ const ytPlayers = Object.keys(j1.adapter.amplitude.data.ytPlayers);
968
+ for (let i=0; i<ytPlayers.length; i++) {
969
+ const ytPlayerID = ytPlayers[i];
970
+ const playerProperties = j1.adapter.amplitude.data.ytPlayers[ytPlayerID];
971
+
972
+ var player = j1.adapter.amplitude['data']['ytPlayers'][ytPlayerID]['player'];
973
+ var playerState = (player.getPlayerState() > 0) ? player.getPlayerState() : 6;
974
+ var ytPlayerState = YT_PLAYER_STATE_NAMES[playerState];
975
+
976
+ // if (ytPlayerState === 'playing' || ytPlayerState === 'paused' || ytPlayerState === 'buffering' || ytPlayerState === 'cued' || ytPlayerState === 'unstarted') {
977
+ if (ytPlayerState === 'playing' || ytPlayerState === 'paused') {
978
+ logger.debug('\n' + `STOP YT player at onPlayerStateChange for id: ${ytPlayerID}`);
979
+ player.stopVideo();
980
+ j1.adapter.amplitude.data.ytpGlobals.activeIndex = 0;
981
+ }
982
+
983
+ } // END stop active YT players
984
+
985
+ } // END state AT_PLAYER_STATE PLAYING
986
+
987
+ if (state === AT_PLAYER_STATE.ENDED) {
988
+ // Amplitude.setVolume(50);
989
+ } // END state AT_PLAYER_STATE.ENDED
990
+
991
+ } // END onPlayerStateChange
992
+
559
993
  }, // END initApi
560
994
 
995
+ // -------------------------------------------------------------------------
996
+ // monitorPlayerActiveElementChanges
997
+ //
998
+ // -------------------------------------------------------------------------
999
+ monitorPlayerActiveElementChanges: () => {
1000
+ // var playerSongContainers = document.getElementsByClassName("large-player-title-list");
1001
+ var playerSongContainers = document.getElementsByClassName("large-player-title-list");
1002
+ for (var i=0; i<playerSongContainers.length; i++) {
1003
+ var scrollableList = document.getElementById(playerSongContainers[0].id);
1004
+ var observer = new MutationObserver((mutationsList, observer) => {
1005
+ for (const mutation of mutationsList) {
1006
+ if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
1007
+ // Überprüfen, ob das geänderte Element jetzt die aktive Klasse besitzt
1008
+ if (mutation.target.classList.contains('amplitude-active-song-container')) {
1009
+ scrollableList.scrollTop = mutation.target.offsetTop;
1010
+ }
1011
+ }
1012
+ }
1013
+ }); // END observer
1014
+
1015
+ // Optionen für den Observer: Nur Änderungen an Attributen beobachten
1016
+ observer.observe(scrollableList, {
1017
+ attributes: true,
1018
+ subtree: true
1019
+ }); // END observer options
1020
+
1021
+ } // END for playerSongContainers
1022
+ }, // END monitorPlayerActiveElementChanges
1023
+
561
1024
  // -------------------------------------------------------------------------
562
1025
  // initPlayerUiEvents
563
1026
  // -------------------------------------------------------------------------
@@ -574,14 +1037,6 @@ j1.adapter.amplitude = ((j1, window) => {
574
1037
  {% assign xhr_data_path = amplitude_options.xhr_data_path %}
575
1038
  {% capture xhr_container_id %}{{player.id}}_app{% endcapture %}
576
1039
 
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
1040
  // dynamic loader variable to setup the player on ID {{player.id}}
586
1041
  dependency = 'dependencies_met_player_loaded_{{player.id}}';
587
1042
  load_dependencies[dependency] = '';
@@ -590,11 +1045,18 @@ j1.adapter.amplitude = ((j1, window) => {
590
1045
  // initialize player instance (when player UI is loaded)
591
1046
  // -----------------------------------------------------------------
592
1047
  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;
1048
+ var xhrDataLoaded = (j1.xhrDOMState['#' + '{{xhr_container_id}}'] === 'success') ? true : false;
1049
+ var playerExistsInPage = ($('#' + '{{xhr_container_id}}')[0] !== undefined) ? true : false;
596
1050
 
597
- if (xhrLoadState === 'success' && playerExistsInPage) {
1051
+ // check the player HTML portion is loaded and player exists (in page)
1052
+ if (xhrDataLoaded && playerExistsInPage) {
1053
+ var playerID = '{{player.id}}';
1054
+ var playerType = '{{player.type}}';
1055
+ var playList = '{{player.playlist}}';
1056
+ var playListName = '{{player.playlist.name}}';
1057
+ var playListTitle = '{{player.playlist.title}}';
1058
+
1059
+ logger.debug('\n' + 'initialize audio player instance on id: {{player.id}}');
598
1060
 
599
1061
  // set song (title) specific audio info links
600
1062
  // -------------------------------------------------------------
@@ -603,15 +1065,9 @@ j1.adapter.amplitude = ((j1, window) => {
603
1065
  _this.setAudioInfo(infoLinks);
604
1066
  }
605
1067
 
606
- // jadams, 2024-10-19: (song) events DISABLED
607
- // set song (title) specific UI events
1068
+ // set player specific UI events
608
1069
  // -------------------------------------------------------------
609
- // var songElements = document.getElementsByClassName('song');
610
- // _this.songEvents(songElements);
611
-
612
- // player specific UI events
613
- // -------------------------------------------------------------
614
- logger.debug('\n' + 'setup player specific UI events on ID #{{player.id}}: started');
1070
+ logger.debug('\n' + 'setup audio player specific UI events on ID #{{player.id}}: started');
615
1071
 
616
1072
  var dependencies_met_api_initialized = setInterval (() => {
617
1073
  if (apiInitialized.state) {
@@ -641,15 +1097,20 @@ j1.adapter.amplitude = ((j1, window) => {
641
1097
  }
642
1098
  } // END for
643
1099
 
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
-
649
- // Amplitude.setSongPlayedPercentage(
650
- // (parseFloat(xpos)/parseFloat(this.offsetWidth))*100);
651
- // });
652
- // }
1100
+ // click on play_pause button (MINI player)
1101
+ var miniPlayerPlayPauseButton = document.getElementsByClassName('mini-player-play-pause');
1102
+ for (var i=0; i<miniPlayerPlayPauseButton.length; i++) {
1103
+ if (miniPlayerPlayPauseButton[i].dataset.amplitudeSource === 'youtube') {
1104
+ // do nothing
1105
+ } else {
1106
+ var currentPlaylist = miniPlayerPlayPauseButton[i].dataset.amplitudePlaylist;
1107
+ if (currentPlaylist === playList) {
1108
+ miniPlayerPlayPauseButton[i].addEventListener('click', function(event) {
1109
+ // do nothing
1110
+ });
1111
+ }
1112
+ }
1113
+ } // END play_pause button (MINI player)
653
1114
 
654
1115
  } // END mini player UI events
655
1116
  {% endif %}
@@ -670,10 +1131,8 @@ j1.adapter.amplitude = ((j1, window) => {
670
1131
  }
671
1132
  }
672
1133
 
673
- // show|hide playlist
674
- // -------------------------------------------------------
675
-
676
1134
  // show playlist
1135
+ // -------------------------------------------------------
677
1136
  var showPlaylist = document.getElementById("show_playlist_{{player.id}}");
678
1137
  if (showPlaylist !== null) {
679
1138
  showPlaylist.addEventListener('click', function(event) {
@@ -701,81 +1160,138 @@ j1.adapter.amplitude = ((j1, window) => {
701
1160
  }
702
1161
  }
703
1162
  }); // END EventListener 'click' (compact player|show playlist)
704
- } // END if showPlaylist
1163
+ } // END if showPlaylist
1164
+
1165
+ // hide playlist
1166
+ // -------------------------------------------------------
1167
+ var hidePlaylist = document.getElementById("hide_playlist_{{player.id}}");
1168
+ if (hidePlaylist !== null) {
1169
+ hidePlaylist.addEventListener('click', function(event) {
1170
+ var playlistScreen = document.getElementById("playlist_screen_{{player.id}}");
1171
+
1172
+ playlistScreen.classList.remove('slide-in-top');
1173
+ playlistScreen.classList.add('slislide-out-top');
1174
+ playlistScreen.style.display = "none";
1175
+ playlistScreen.style.zIndex = "1";
1176
+
1177
+ // enable scrolling
1178
+ if ($('body').hasClass('stop-scrolling')) {
1179
+ $('body').removeClass('stop-scrolling');
1180
+ }
1181
+ }); // END EventListener 'click' (compact player|show playlist)
1182
+ } // END if hidePlaylist
705
1183
 
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}}");
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
+ // add listeners to all progress bars found (compact-player)
1186
+ // getElementsByClassName returns an Array-like object
1187
+ // -------------------------------------------------------
1188
+ var progressBars = document.getElementsByClassName("compact-player-progress");
1189
+ for (var i=0; i<progressBars.length; i++) {
1190
+ if (progressBars[i].dataset.amplitudeSource === 'youtube') {
1191
+ // do nothing
1192
+ } else {
1193
+ progressBars[i].addEventListener('click', function(event) {
1194
+ var offset = this.getBoundingClientRect();
1195
+ var xpos = event.pageX - offset.left;
716
1196
 
717
- // enable scrolling
718
- if ($('body').hasClass('stop-scrolling')) {
719
- $('body').removeClass('stop-scrolling');
1197
+ Amplitude.setSongPlayedPercentage(
1198
+ (parseFloat(xpos)/parseFloat(this.offsetWidth))*100);
1199
+ }); // END EventListener 'click'
720
1200
  }
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
1201
+ } // END for
1202
+
1203
+
1204
+ // click on Next|Previous Buttons (COMPACT player)
1205
+ // -------------------------------------------------------
1206
+
1207
+ // add listeners to all Next Buttons found
1208
+ var largeNextButtons = document.getElementsByClassName("compact-player-next");
1209
+ for (var i=0; i<largeNextButtons.length; i++) {
1210
+ if (largeNextButtons[i].dataset.amplitudeSource === 'youtube') {
1211
+ // do nothing
1212
+ } else {
1213
+ if (largeNextButtons[i].id === 'compact_player_next_{{player.id}}') {
1214
+ largeNextButtons[i].addEventListener('click', function(event) {
1215
+ // do nothing
1216
+ }); // END EventListener 'click'
1217
+ } // END if ID
1218
+ }
1219
+ } // END Next Buttons (COMPACT player)
1220
+
1221
+ // add listeners to all Previous Buttons found
1222
+ var compactPreviousButtons = document.getElementsByClassName("compact-player-previous");
1223
+ for (var i=0; i<compactPreviousButtons.length; i++) {
1224
+ if (compactPreviousButtons[i].dataset.amplitudeSource === 'youtube') {
1225
+ // do nothing
1226
+ } else {
1227
+ if (compactPreviousButtons[i].id === 'compact_player_previous_{{player.id}}') {
1228
+ compactPreviousButtons[i].addEventListener('click', function(event) {
1229
+ // do nothing
1230
+ }); // END EventListener 'click'
1231
+ } // END if ID
1232
+ }
1233
+ } // END Previous Buttons (COMPACT player)
741
1234
 
742
- // click on skip forward|backward (compact player)
1235
+ // click on play_pause button (COMPACT player)
1236
+ var compactPlayerPlayPauseButton = document.getElementsByClassName('compact-player-play-pause');
1237
+ for (var i=0; i<compactPlayerPlayPauseButton.length; i++) {
1238
+ if (compactPlayerPlayPauseButton[i].dataset.amplitudeSource === 'youtube') {
1239
+ // do nothing (managed by plugin)
1240
+ } else {
1241
+ var currentPlaylist = compactPlayerPlayPauseButton[i].dataset.amplitudePlaylist;
1242
+ if (currentPlaylist === playList) {
1243
+ compactPlayerPlayPauseButton[i].addEventListener('click', function(event) {
1244
+ // do nothing
1245
+ });
1246
+ }
1247
+ }
1248
+ } // END play_pause button (COMPACT player)
1249
+
1250
+ // click on skip forward|backward (COMPACT player)
743
1251
  // See: https://github.com/serversideup/amplitudejs/issues/384
744
1252
  // -------------------------------------------------------
745
1253
 
746
1254
  // add listeners to all SkipForwardButtons found
747
1255
  var compactPlayerSkipForwardButtons = document.getElementsByClassName("compact-player-skip-forward");
748
1256
  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
1257
+ if (compactPlayerSkipForwardButtons[i].dataset.amplitudeSource === 'youtube') {
1258
+ // do nothing
1259
+ } else {
1260
+ if (compactPlayerSkipForwardButtons[i].id === 'skip-forward_{{player.id}}') {
1261
+ compactPlayerSkipForwardButtons[i].addEventListener('click', function(event) {
1262
+ const skipOffset = parseFloat(playerForwardBackwardSkipSeconds);
1263
+ const duration = Amplitude.getSongDuration();
1264
+ const currentTime = parseFloat(Amplitude.getSongPlayedSeconds());
1265
+ const targetTime = parseFloat(currentTime + skipOffset);
1266
+
1267
+ if (currentTime > 0) {
1268
+ Amplitude.setSongPlayedPercentage((targetTime / duration) * 100);
1269
+ }
1270
+ }); // END EventListener 'click'
1271
+ } // END if ID
1272
+ }
1273
+ } // END SkipForwardButtons (COMPACT player)
762
1274
 
763
1275
  // add listeners to all SkipBackwardButtons found
764
1276
  var compactPlayerSkipBackwardButtons = document.getElementsByClassName("compact-player-skip-backward");
765
1277
  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
1278
+ if (compactPlayerSkipBackwardButtons[i].dataset.amplitudeSource === 'youtube') {
1279
+ // do nothing
1280
+ } else {
1281
+ if (compactPlayerSkipBackwardButtons[i].id === 'skip-backward_{{player.id}}') {
1282
+ compactPlayerSkipBackwardButtons[i].addEventListener('click', function(event) {
1283
+ const skipOffset = parseFloat(playerForwardBackwardSkipSeconds);
1284
+ const duration = Amplitude.getSongDuration();
1285
+ const currentTime = parseFloat(Amplitude.getSongPlayedSeconds());
1286
+ const targetTime = parseFloat(currentTime - skipOffset);
1287
+
1288
+ if (currentTime > 0) {
1289
+ Amplitude.setSongPlayedPercentage((targetTime / duration) * 100);
1290
+ }
1291
+ }); // END EventListener 'click'
1292
+ } // END if ID
1293
+ }
1294
+ } // END SkipBackwardButtons (COMPACT player)
779
1295
 
780
1296
  // click on shuffle button
781
1297
  var compactPlayerShuffleButton = document.getElementById('compact_player_shuffle');
@@ -785,7 +1301,7 @@ j1.adapter.amplitude = ((j1, window) => {
785
1301
 
786
1302
  Amplitude.setShuffle(shuffleState)
787
1303
  }); // END EventListener 'click'
788
- } // END compactPlayerShuffleButton
1304
+ } // END PlayerShuffleButton (COMPACT player)
789
1305
 
790
1306
  // click on repeat button
791
1307
  var compactPlayerRepeatButton = document.getElementById('compact_player_repeat');
@@ -795,18 +1311,44 @@ j1.adapter.amplitude = ((j1, window) => {
795
1311
 
796
1312
  Amplitude.setRepeat(repeatState)
797
1313
  }); // END EventListener 'click'
798
- } // END compactPlayerRepeatButton
1314
+ } // END PlayerRepeatButton (COMPACT player)
799
1315
 
800
1316
  } // END compact player UI events
801
1317
  {% endif %}
802
1318
 
803
1319
  {% if player.id contains 'large' %}
804
1320
  // START large player UI events
805
- //
1321
+ // ---------------------------------------------------------
806
1322
  if (document.getElementById('{{player.id}}') !== null) {
1323
+ // var playlist = '{{player.id}}_yt';
1324
+ var playlistInfo = {{player.playlist | replace: 'nil', 'null' | replace: '=>', ':'}};
1325
+ var playList = playlistInfo.name;
807
1326
 
808
1327
  // NOTE: listener overloads for video managed by plugin
809
1328
  // -------------------------------------------------------
1329
+ var largetPlayerSongContainer = document.getElementsByClassName("amplitude-song-container");
1330
+ for (var i=0; i<largetPlayerSongContainer.length; i++) {
1331
+ if (largetPlayerSongContainer[i].dataset.amplitudeSource === 'youtube') {
1332
+ // do nothing
1333
+ } else {
1334
+ var currentPlaylist = largetPlayerSongContainer[i].dataset.amplitudePlaylist;
1335
+ if (currentPlaylist === playList) {
1336
+ largetPlayerSongContainer[i].addEventListener('click', function(event) {
1337
+ var ytpPlayer, ytpPlayerState, ytpPlayerState, playerState,
1338
+ classArray, atpPlayerActive, playlist;
1339
+
1340
+ classArray = [].slice.call(this.classList, 0);
1341
+ atpPlayerActive = classArray[0].split('-');
1342
+ playlist = this.getAttribute("data-amplitude-playlist");
1343
+
1344
+ // scroll song active at index in player
1345
+ if (playerAutoScrollSongElement) {
1346
+ j1.adapter.amplitude.atPlayerScrollToActiveElement(playlist);
1347
+ }
1348
+ });
1349
+ }
1350
+ }
1351
+ } // END player SongContainer
810
1352
 
811
1353
  // click on prev button
812
1354
  var largePlayerPreviousButton = document.getElementById('large_player_previous');
@@ -814,9 +1356,22 @@ j1.adapter.amplitude = ((j1, window) => {
814
1356
  // do nothing (managed by plugin)
815
1357
  }
816
1358
 
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)
1359
+ // click on play_pause button (LARGE player)
1360
+ var largePlayerPlayPauseButton = document.getElementsByClassName('large-player-play-pause');
1361
+ for (var i=0; i<largePlayerPlayPauseButton.length; i++) {
1362
+ if (largePlayerPlayPauseButton[i].dataset.amplitudeSource === 'youtube') {
1363
+ // do nothing (managed by YTP plugin)
1364
+ } else {
1365
+ var currentPlaylist = largePlayerPlayPauseButton[i].dataset.amplitudePlaylist;
1366
+ if (currentPlaylist === playList) {
1367
+ largePlayerPlayPauseButton[i].addEventListener('click', function(event) {
1368
+ // do nothing
1369
+ });
1370
+ }
1371
+ }
1372
+ } // END play_pause button (LARGE player)
1373
+
1374
+ // add listeners to all progress bars found (LARGE player)
820
1375
  // -------------------------------------------------------
821
1376
  var progressBars = document.getElementsByClassName("large-player-progress");
822
1377
  for (var i=0; i<progressBars.length; i++) {
@@ -826,13 +1381,69 @@ j1.adapter.amplitude = ((j1, window) => {
826
1381
  progressBars[i].addEventListener('click', function(event) {
827
1382
  var offset = this.getBoundingClientRect();
828
1383
  var xpos = event.pageX - offset.left;
829
-
830
- Amplitude.setSongPlayedPercentage(
831
- (parseFloat(xpos)/parseFloat(this.offsetWidth))*100);
1384
+
1385
+ if (Amplitude.getPlayerState() === 'playing') {
1386
+ Amplitude.setSongPlayedPercentage((parseFloat(xpos)/parseFloat(this.offsetWidth))*100);
1387
+ }
832
1388
  }); // END EventListener 'click'
833
1389
  }
834
1390
  } // END for
835
1391
 
1392
+
1393
+ // click on Next|Previous Buttons (LARGE player)
1394
+ // -------------------------------------------------------
1395
+
1396
+ // add listeners to all Next Buttons found
1397
+ var largeNextButtons = document.getElementsByClassName("large-player-next");
1398
+ for (var i=0; i<largeNextButtons.length; i++) {
1399
+ if (largeNextButtons[i].dataset.amplitudeSource === 'youtube') {
1400
+ // do nothing (managed by plugin)
1401
+ } else {
1402
+ if (largeNextButtons[i].id === 'large_player_next_{{player.id}}') {
1403
+ largeNextButtons[i].addEventListener('click', function(event) {
1404
+ var atpPlayerID = this.id;
1405
+ var atpPlayerActive = atpPlayerID.split('_');
1406
+ var playlist = this.getAttribute("data-amplitude-playlist");
1407
+
1408
+ // scroll song active at index in player
1409
+ if (playerAutoScrollSongElement) {
1410
+ j1.adapter.amplitude.atPlayerScrollToActiveElement(playlist);
1411
+ }
1412
+
1413
+ // save YT player data for later use (e.g. events)
1414
+ j1.adapter.amplitude.data.activePlayer = 'atp';
1415
+ j1.adapter.amplitude.data.atpGlobals.activePlayerType = atpPlayerActive[0];
1416
+ }); // END EventListener 'click'
1417
+ } // END if ID
1418
+ }
1419
+ } // END for Next Buttons
1420
+
1421
+ // add listeners to all Previous Buttons found
1422
+ var largePreviousButtons = document.getElementsByClassName("large-player-previous");
1423
+ for (var i=0; i<largePreviousButtons.length; i++) {
1424
+ if (largePreviousButtons[i].dataset.amplitudeSource === 'youtube') {
1425
+ // do nothing (managed by plugin)
1426
+ } else {
1427
+ if (largePreviousButtons[i].id === 'large_player_previous_{{player.id}}') {
1428
+ largePreviousButtons[i].addEventListener('click', function(event) {
1429
+ var atpPlayerID = this.id;
1430
+ var atpPlayerActive = atpPlayerID.split('_');
1431
+ var playlist = this.getAttribute("data-amplitude-playlist");
1432
+
1433
+ // scroll song active at index in player
1434
+ if (playerAutoScrollSongElement) {
1435
+ j1.adapter.amplitude.atPlayerScrollToActiveElement(playlist);
1436
+ }
1437
+
1438
+ // save YT player data for later use (e.g. events)
1439
+ j1.adapter.amplitude.data.activePlayer = 'atp';
1440
+ j1.adapter.amplitude.data.atpGlobals.activePlayerType = atpPlayerActive[0];
1441
+ }); // END EventListener 'click'
1442
+ } // END if ID
1443
+ }
1444
+ } // END for Previous Buttons
1445
+
1446
+
836
1447
  // click on skip forward|backward (large player)
837
1448
  // See: https://github.com/serversideup/amplitudejs/issues/384
838
1449
  // -------------------------------------------------------
@@ -890,7 +1501,7 @@ j1.adapter.amplitude = ((j1, window) => {
890
1501
 
891
1502
  // click on repeat button
892
1503
  var largePlayerRepeatButton = document.getElementById('large_player_repeat');
893
- if (largePlayerShuffleButton) {
1504
+ if (largePlayerRepeatButton) {
894
1505
  largePlayerRepeatButton.addEventListener('click', function(event) {
895
1506
  var repeatState = (document.getElementById('large_player_repeat').className.includes('amplitude-repeat-on')) ? true : false;
896
1507
  Amplitude.setRepeat(repeatState)
@@ -903,8 +1514,7 @@ j1.adapter.amplitude = ((j1, window) => {
903
1514
 
904
1515
  // show|hide scrollbar in playlist
905
1516
  // -----------------------------------------------------
906
- const songsInPlaylist = Amplitude.getSongsInPlaylist(playListName);
907
-
1517
+ var songsInPlaylist = Amplitude.getSongsInPlaylist(playListName);
908
1518
  if (songsInPlaylist.length <= 8) {
909
1519
  const titleListLargePlayer = document.getElementById('large_player_title_list_' + playListName);
910
1520
  if (titleListLargePlayer !== null) {
@@ -1037,11 +1647,9 @@ j1.adapter.amplitude = ((j1, window) => {
1037
1647
  playerExistsInPage = (document.getElementById('{{player.id}}_app') !== null) ? true : false;
1038
1648
  pluginManagerEnabled = ('{{player.plugin_manager.enabled}}'.length > 0 && '{{player.plugin_manager.enabled}}' === 'true') ? true : playerDefaultPluginManager;
1039
1649
 
1040
- if (playerExistsInPage && pluginManagerEnabled && !pluginManagerRunOnce) {
1650
+ var ytpPluginInstalled = j1.adapter.amplitude.data.atpGlobals.ytpInstalled;
1651
+ if (playerExistsInPage && pluginManagerEnabled && !ytpPluginInstalled) {
1041
1652
  _this.pluginManager('{{player.plugin_manager.plugins}}');
1042
-
1043
- // make sure the plugin is loaded|run only ONCE
1044
- pluginManagerRunOnce = true;
1045
1653
  }
1046
1654
 
1047
1655
  clearInterval(load_dependencies['dependencies_met_player_loaded_{{player.id}}']);
@@ -1116,9 +1724,21 @@ j1.adapter.amplitude = ((j1, window) => {
1116
1724
  // pluginManager()
1117
1725
  //
1118
1726
  // -------------------------------------------------------------------------
1119
- pluginManager: (plugin) => {
1120
- // if (plugin === 'ytp' && j1.adapter.amplitude['ytPlayerReady'] === undefined ) {
1121
- if (plugin === 'ytp') {
1727
+ pluginManager: (plugin) => {
1728
+
1729
+ function isPluginLoaded(pluginName) {
1730
+ const scripts = document.scripts;
1731
+ const pluginFile = pluginName + '.js';
1732
+
1733
+ for (let i = 0; i < scripts.length; i++) {
1734
+ if (scripts[i].src.includes(pluginFile)) {
1735
+ return true;
1736
+ }
1737
+ }
1738
+ return false;
1739
+ }
1740
+
1741
+ if (plugin !== '' && plugin === 'ytp') {
1122
1742
  var tech;
1123
1743
  var techScript;
1124
1744
 
@@ -1129,8 +1749,40 @@ j1.adapter.amplitude = ((j1, window) => {
1129
1749
 
1130
1750
  techScript.parentNode.insertBefore(tech, techScript);
1131
1751
  }
1752
+
1753
+ if (plugin !== '' && isPluginLoaded(plugin)) {
1754
+ logger.debug('\n' + 'plugin loaded: ' + plugin);
1755
+
1756
+ // make sure the plugin installed only ONCE
1757
+ j1.adapter.amplitude.data.atpGlobals.ytpInstalled = true;
1758
+ }
1132
1759
  }, // END pluginManager
1133
1760
 
1761
+ // -------------------------------------------------------------------------
1762
+ // atPlayerScrollToActiveElement(activePlaylist)
1763
+ // -------------------------------------------------------------------------
1764
+ atPlayerScrollToActiveElement: (activePlaylist) => {
1765
+ var scrollableList, songIndex,
1766
+ activeElement, activeElementOffsetTop;
1767
+
1768
+ scrollableList = document.getElementById('large_player_title_list_' + activePlaylist);
1769
+ activeElement = scrollableList.querySelector('.amplitude-active-song-container');
1770
+
1771
+ if (activeElement === null || scrollableList === null) {
1772
+ // do nothing if NO scrollableList or active element found (failsafe)
1773
+ return;
1774
+ }
1775
+
1776
+ songIndex = parseInt(activeElement.getAttribute("data-amplitude-song-index"));
1777
+ activeElementOffsetTop = songIndex * j1.adapter.amplitude.data.playerSongElementHeigth;
1778
+ scrollableList.scrollTop = activeElementOffsetTop;
1779
+
1780
+ if (songIndex === 0) {
1781
+ var bla = 'puups';
1782
+ }
1783
+
1784
+ }, // END atPlayerScrollToActiveElement
1785
+
1134
1786
  // -------------------------------------------------------------------------
1135
1787
  // messageHandler()
1136
1788
  // manage messages send from other J1 modules