main.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900
  1. (function($, Drupal, drupalSettings) {
  2. EdlpTheme = function(){
  3. var _$body = $('body');
  4. var _is_front = _$body.is('.path-frontpage');
  5. var _$corpus_canvas;
  6. var _$row = $('main[role="main"]>.layout-content>.row');
  7. var _$ajaxLinks;
  8. var _audioPlayer;
  9. var _randomPlayer;
  10. var _compoPlayer;
  11. // ___ _ _
  12. // |_ _|_ _ (_) |_
  13. // | || ' \| | _|
  14. // |___|_||_|_|\__|
  15. function init(){
  16. console.log("EdlpTheme init()");
  17. // TODO: redirect all no-front pages to front with write hash
  18. _$body.on('corpus-map-ready', onCorpusMapReady);
  19. _audioPlayer = new AudioPlayer();
  20. _compoPlayer = new CompoPlayer();
  21. initAjaxLinks();
  22. if (_$body.is('.path-productions')){
  23. initProductions();
  24. }
  25. if(_$body.is('.path-frontpage')){
  26. addCloseBtnToCols();
  27. }
  28. // initScrollbars();
  29. initEvents();
  30. };
  31. // ___ _
  32. // | __|_ _____ _ _| |_ ___
  33. // | _|\ V / -_) ' \ _(_-<
  34. // |___|\_/\___|_||_\__/__/
  35. function initEvents(){
  36. $('body')
  37. .on('on-studio-chutier-updated', initAjaxLinks)
  38. .on('on-studio-compo-updated', function(e){
  39. initAjaxLinks();
  40. _compoPlayer.refresh();
  41. })
  42. .on('on-studio-compo-opened', function(e){
  43. initAjaxLinks();
  44. _compoPlayer.newCompo();
  45. })
  46. .on('search-results-loaded', initAjaxLinks)
  47. .on('open_entree', closeAllModals)
  48. .on('close_entree', backToFrontPage);
  49. }
  50. // ___ _ _ ___
  51. // / __| __ _ _ ___| | | _ ) __ _ _ _ ___
  52. // \__ \/ _| '_/ _ \ | | _ \/ _` | '_(_-<
  53. // |___/\__|_| \___/_|_|___/\__,_|_| /__/
  54. function initScrollbars(){
  55. // console.log("initScrollbars");
  56. // TODO: find a better js scroll than overlayScrollbars which does not handle well max-height + overflow-y:auto;
  57. // $('.os-scroll').overlayScrollbars({
  58. // overflowBehavior:{
  59. // x:'h',
  60. // y:'scroll',
  61. // clipAlways:false
  62. // }
  63. // });
  64. };
  65. // _ _
  66. // /_\ (_)__ ___ __
  67. // / _ \ | / _` \ \ /
  68. // /_/ \_\/ \__,_/_\_\
  69. // |__/
  70. // TODO: add url hash nav
  71. // TODO: implement history.js
  72. function initAjaxLinks(){
  73. console.log('initAjaxLinks');
  74. $('a', '#block-mainnavigation')
  75. .add('a', '#block-footer.menu--footer')
  76. .add('a', '#block-productions')
  77. .add('a', 'article.node:not(.node--type-enregistrement) h2.node-title')
  78. .add('a', '.productions-subtree')
  79. .add('a', '.productions-parent')
  80. // .add('a.index-link, a.notice-link', '#block-edlpentreesblock')
  81. .addClass('ajax-link');
  82. _$ajaxLinks = $('.ajax-link:not(.ajax-enabled)')
  83. .each(function(i,e){
  84. var $this = $(this);
  85. // avoid already ajaxified links
  86. if($this.is('.ajax-enable')) return;
  87. if($this.attr('data-drupal-link-system-path')){
  88. $this.on('click', onClickAjaxLink).addClass('ajax-enable');
  89. }
  90. });
  91. };
  92. function onClickAjaxLink(e){
  93. e.preventDefault();
  94. var $link = $(this);
  95. if($link.is('.is-active'))
  96. return false;
  97. // Audio links
  98. if($link.is('.audio-link')){
  99. // TODO: stop randomplayer
  100. _audioPlayer
  101. .emmit('stop-shuffle')
  102. .openDocument({
  103. nid:$link.attr('nid'),
  104. audio_url:$link.attr('audio_url')
  105. });
  106. return false;
  107. }
  108. // other links
  109. var sys_path = $(this).attr('data-drupal-link-system-path');
  110. var ajax_path = sys_path;
  111. if(sys_path == '<front>'){
  112. backToFrontPage();
  113. return false;
  114. }
  115. // convert node link to edlp_ajax_node module links
  116. var node_match = ajax_path.match(/^\/?(node\/\d+)$/g);
  117. var term_match = ajax_path.match(/^\/?(taxonomy\/term\/\d+)$/g);
  118. if(node_match){
  119. ajax_path = 'edlp/ajax/json/'+node_match[0];
  120. // check for viewmode attribute
  121. if($link.attr('viewmode')){
  122. ajax_path += '/'+$link.attr('viewmode');
  123. }
  124. }else if(term_match){
  125. ajax_path = 'edlp/ajax/json/'+term_match[0];
  126. ajax_path = ajax_path.replace(/taxonomy\/term/, 'taxonomy_term');
  127. // check for viewmode attribute
  128. if($link.attr('viewmode')){
  129. ajax_path += '/'+$link.attr('viewmode');
  130. }
  131. }else{
  132. // convert other link to ajax
  133. ajax_path += '/ajax'
  134. }
  135. _$body.addClass('ajax-loading');
  136. $link.addClass('ajax-loading');
  137. // TODO: use Drupal.url()
  138. // Drupal.url = function (path) {
  139. // return drupalSettings.path.baseUrl + drupalSettings.path.pathPrefix + path;
  140. // };
  141. var path = window.location.origin + Drupal.url(ajax_path);
  142. $.getJSON(path, {})
  143. .done(function(data){
  144. onAjaxLinkLoaded(data, $link, sys_path);
  145. })
  146. .fail(function(jqxhr, textStatus, error){
  147. onAjaxLinkLoadError(jqxhr, textStatus, error, $link, sys_path);
  148. });
  149. return false;
  150. };
  151. function onAjaxLinkLoadError(jqxhr, textStatus, error, $link, sys_path){
  152. console.warn('ajaxlink load failed for '+sys_path+' : '+error, jqxhr.responseText);
  153. $link.removeClass('ajax-loading');
  154. _$body.removeClass('ajax-loading');
  155. };
  156. function onAjaxLinkLoaded(data, $link, sys_path){
  157. console.log('ajax link loaded : data', data);
  158. _$body.removeClass('ajax-loading');
  159. // replace all content with newly loaded
  160. // TODO: build a system to replace or append contents (like studio + search)
  161. _$row.html(data.rendered);
  162. // add close btn
  163. if(sys_path != 'procuction'){
  164. addCloseBtnToCols();
  165. }
  166. // add body class for currently loaded content
  167. var body_classes = [
  168. 'path-'+sys_path.replace(/\//g, '-'),
  169. 'entity-type-'+data.entity_type,
  170. 'bundle-'+data.bundle,
  171. 'view-mode-'+data.view_mode
  172. ];
  173. _$body.removeClass().addClass(body_classes.join(' '));
  174. // id node add a generic path-node class to body
  175. m = sys_path.match(/^\/?(node\/\d+)$/g);
  176. if(m)
  177. _$body.addClass('path-edlp-node');
  178. // handle clicked link classes
  179. _$ajaxLinks.removeClass('is-active');
  180. $link.removeClass('ajax-loading').addClass('is-active');
  181. // if block attached (eg : from edlp_productions module)
  182. if(typeof data.block != 'undefined'){
  183. // if block not already added
  184. if(!$('#'+data.block.id, '.region-'+data.block.region).length){
  185. $('.region-'+data.block.region).append(data.block.rendered);
  186. }
  187. }
  188. initScrollbars();
  189. if(sys_path == "productions")
  190. initProductions();
  191. initAjaxLinks();
  192. _$body.trigger({'type':'new-content-ajax-loaded'});
  193. // call behaviours
  194. Drupal.attachBehaviors(_$row[0]);
  195. };
  196. function addCloseBtnToCols(){
  197. $('.col', _$row).each(function(index, el) {
  198. if($('span.close-col-btn', this).length)
  199. return true;
  200. $(this).children('.wrapper').append($('<span>')
  201. .addClass('close-col-btn')
  202. .on('click', function(e){
  203. // check for theme attribute and emmit event
  204. var $col = $(this).parents('.col');
  205. var theme = $col.attr('theme');
  206. if(theme != ''){
  207. _$body.trigger({'type':theme+'-col-closed'});
  208. }
  209. // remove the col
  210. $col.remove();
  211. // if row is empty call closeAllModals()
  212. if(!$('.col', _$row).length){
  213. backToFrontPage();
  214. }
  215. })
  216. );
  217. });
  218. };
  219. // ___
  220. // / __|___ _ _ _ __ _ _ ___
  221. // | (__/ _ \ '_| '_ \ || (_-<
  222. // \___\___/_| | .__/\_,_/__/
  223. // |_|
  224. function onCorpusMapReady(e){
  225. console.log('theme : onCorpusReady', e);
  226. _$corpus_canvas = $('canvas#corpus-map');
  227. _$corpus_canvas
  228. .on('corpus-cliked-on-map', function(e) {
  229. console.log('theme : corpus-cliked-on-map');
  230. backToFrontPage();
  231. })
  232. .on('corpus-cliked-on-node', function(e) {
  233. console.log('theme : corpus-cliked-on-node', e);
  234. _audioPlayer
  235. .emmit('stop-shuffle')
  236. .openDocument(e.target_node);
  237. });
  238. _randomPlayer = new RandomPlayer(e.playlist);
  239. _$body.attr('corpus-map', 'ready');
  240. }
  241. // _ _ _
  242. // /_\ _ _ __| (_)___
  243. // / _ \ || / _` | / _ \
  244. // /_/ \_\_,_\__,_|_\___/
  245. //
  246. // https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement
  247. // https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/samples/gg589528%28v%3dvs.85%29
  248. // https://www.binarytides.com/using-html5-audio-element-javascript/
  249. function AudioPlayer(){
  250. var that = this;
  251. this.fid;
  252. this.audio = new Audio();
  253. // audio events
  254. this.audio_events = ["loadedmetadata","canplay","playing","pause","timeupdate","ended"];
  255. // UI dom objects
  256. this.$container = $('<div id="audio-player">');
  257. // btns
  258. this.$btns = $('<div>').addClass('btns').appendTo(this.$container);
  259. this.$previous = $('<div>').addClass('previous').appendTo(this.$btns);
  260. this.$playpause = $('<div>').addClass('play-pause').appendTo(this.$btns);
  261. this.$next = $('<div>').addClass('next').appendTo(this.$btns);
  262. // timeline
  263. this.$timelinecont= $('<div>').addClass('time-line-container').appendTo(this.$container);
  264. this.$timeline = $('<div>').addClass('time-line').appendTo(this.$timelinecont);
  265. this.$loader = $('<div>').addClass('loader').appendTo(this.$timeline);
  266. this.$cursor = $('<div>').addClass('cursor').appendTo(this.$timeline);
  267. // time
  268. this.$time = $('<div>').addClass('time').appendTo(this.$container);
  269. this.$currentTime = $('<div>').addClass('current-time').html('00:00').appendTo(this.$time);
  270. this.$duration = $('<div>').addClass('duration').html('00:00').appendTo(this.$time);
  271. // favoris
  272. this.$fav = $('<div>').addClass('favoris').appendTo(this.$container);
  273. // cartel
  274. this.$cartel = $('<div>').addClass('cartel').appendTo(this.$container);
  275. // hiding
  276. this.hideTimer = false;
  277. this.hideTimeMS = 10000;
  278. // history
  279. this.currentHistoricIndex = null;
  280. this.historic = [];
  281. this.shuffle_is_active = false;
  282. // object events
  283. this.event_handlers = {
  284. 'audio-open-document':[],
  285. 'audio-play':[],
  286. 'audio-pause':[],
  287. 'audio-play-next':[],
  288. 'audio-ended':[],
  289. 'stop-shuffle':[]
  290. };
  291. this.init();
  292. };
  293. AudioPlayer.prototype = {
  294. init(){
  295. // append ui to document
  296. this.$container.appendTo('header[role="banner"] .region-header');
  297. // record timeline width
  298. this.timeline_w = parseInt(this.$timeline.width());
  299. // init audio events
  300. var fn = '';
  301. for (var i = 0; i < this.audio_events.length; i++) {
  302. fn = this.audio_events[i];
  303. // capitalize first letter of event (only cosmetic :p )
  304. fn = 'on'+fn.charAt(0).toUpperCase()+fn.slice(1);
  305. this.audio.addEventListener(
  306. this.audio_events[i],
  307. this[fn].bind(this),
  308. true);
  309. }
  310. // init btns events
  311. this.$previous.on('click', this.playPrevious.bind(this));
  312. this.$playpause.on('click', this.togglePlayPause.bind(this));
  313. this.$next.on('click', this.playNext.bind(this));
  314. // TODO: previous and next btns
  315. },
  316. openDocument(node, caller){
  317. // console.log('AudioPlayer openDocument', node);
  318. if(typeof node == 'undefined'
  319. || typeof node.nid == 'undefined'
  320. || typeof node.audio_url == 'undfined'){
  321. console.warn('AudioPlayer openDocument() node is malformed', node);
  322. return false;
  323. }
  324. this.historic.push(node);
  325. this.currentHistoricIndex = this.historic.length-1;
  326. // this.shuffle_mode = shuffle_mode || false;
  327. this.emmit('audio-open-document', {caller:caller});
  328. this.launch();
  329. },
  330. launch(){
  331. this.clearTimeOutToHide();
  332. this.setSRC(this.historic[this.currentHistoricIndex].audio_url);
  333. this.loadNode(this.historic[this.currentHistoricIndex].nid);
  334. // emmit new playing doc (e.g.: corpus map nowing that audio played from RandomPlayer)
  335. try {
  336. _$corpus_canvas.trigger({
  337. 'type':'audio-node-opened',
  338. 'nid':this.historic[this.currentHistoricIndex].nid
  339. });
  340. } catch (e) {
  341. console.info('AudioPlayer : _$corpus_canvas does not exists');
  342. }
  343. this.showHidePreviousBtn();
  344. this.showHideNextBtn();
  345. this.show();
  346. },
  347. // audio functions
  348. setSRC(url){
  349. // console.log('AudioPlayer setSRC : url', url);
  350. this.audio.src = url;
  351. },
  352. onLoadedmetadata(){
  353. var rem = parseInt(this.audio.duration, 10),
  354. mins = Math.floor(rem/60,10),
  355. secs = rem - mins*60;
  356. this.$duration.html('<span>'+(mins<10 ? '0':'')+mins+':'+(secs<10 ? '0':'')+secs+'</span>');
  357. this.updateLoadingBar();
  358. },
  359. updateLoadingBar(){
  360. this.$loader.css({
  361. 'width':parseInt((100 * this.audio.buffered.end(0) / this.audio.duration), 10)+'%'
  362. });
  363. if( this.audio.buffered.end(0) < this.audio.duration ){
  364. // loop through this function until file is fully loaded
  365. var that = this;
  366. window.requestAnimationFrame(that.updateLoadingBar.bind(that));
  367. }else{
  368. console.log('Audio fully loaded');
  369. }
  370. },
  371. onCanplay(){
  372. this.play();
  373. },
  374. play(){
  375. this.clearTimeOutToHide();
  376. this.audio.play();
  377. },
  378. playPrevious(){
  379. if(this.currentHistoricIndex > 0){
  380. this.currentHistoricIndex -= 1;
  381. this.launch();
  382. }
  383. },
  384. playNext(){
  385. if(this.currentHistoricIndex < this.historic.length-1){
  386. this.currentHistoricIndex += 1;
  387. this.launch();
  388. }else{
  389. this.emmit('audio-play-next');
  390. }
  391. },
  392. togglePlayPause(e){
  393. if(this.audio.paused){
  394. this.audio.play();
  395. }else{
  396. this.audio.pause();
  397. }
  398. },
  399. stop(){
  400. // console.log('AudioPlayer stop()');
  401. this.audio.pause();
  402. this.timeOutToHide();
  403. },
  404. // audio events
  405. onPlaying(){
  406. this.$btns.addClass('is-playing');
  407. this.emmit('audio-play');
  408. },
  409. onPause(){
  410. this.$btns.removeClass('is-playing');
  411. this.emmit('audio-pause');
  412. },
  413. onTimeupdate(){
  414. // move cursor
  415. this.$cursor.css({
  416. 'left':(this.audio.currentTime/this.audio.duration * this.timeline_w)+"px"
  417. });
  418. // update time text display
  419. var rem = parseInt(this.audio.currentTime, 10),
  420. mins = Math.floor(rem/60,10),
  421. secs = rem - mins*60;
  422. this.$currentTime.html('<span>'+(mins<10 ? '0':'')+mins+':'+(secs<10 ? '0':'')+secs+'</span>');
  423. },
  424. onEnded(){
  425. this.emmit('audio-ended');
  426. this.stop();
  427. },
  428. // cartel functions
  429. loadNode(nid){
  430. this.$cartel.addClass('loading');
  431. $.getJSON('/edlp/ajax/json/node/'+nid+'/player_cartel', {})
  432. .done(this.onNodeLoaded.bind(this))
  433. .fail(this.onNodeLoadFail.bind(this));
  434. },
  435. onNodeLoaded(data){
  436. // console.log('AudioPlayer node loaded');
  437. this.$cartel.html(data.rendered).removeClass('loading');
  438. _$body.trigger({'type':'new-audio-cartel-loaded'});
  439. initAjaxLinks();
  440. },
  441. onNodeLoadFail(jqxhr, textStatus, error){
  442. console.warn('AudioPlayer node load failed', jqxhr.responseText);
  443. this.$cartel.removeClass('loading').html('');
  444. },
  445. // global
  446. show(){
  447. this.$container.addClass('visible');
  448. },
  449. showHidePreviousBtn(){
  450. if(this.historic.length > 1 && this.currentHistoricIndex > 0){
  451. this.$previous.addClass('is-active');
  452. }else{
  453. this.$previous.removeClass('is-active');
  454. }
  455. },
  456. showHideNextBtn(){
  457. if(this.currentHistoricIndex < this.historic.length-1 || this.shuffle_is_active){
  458. this.$next.addClass('is-active');
  459. }else{
  460. this.$next.removeClass('is-active');
  461. }
  462. },
  463. timeOutToHide(){
  464. // console.log('AudioPlayer timeOutToHide()');
  465. this.clearTimeOutToHide();
  466. this.hideTimer = setTimeout(this.hide.bind(this), this.hideTimeMS);
  467. },
  468. clearTimeOutToHide(){
  469. // console.log('AudioPlayer clearTimeOutToHide()',this.hideTimer);
  470. if(this.hideTimer){
  471. clearTimeout(this.hideTimer);
  472. this.hideTimer = false;
  473. }
  474. },
  475. hide(){
  476. // console.log('AudioPlayer hide()');
  477. this.$container.removeClass('visible');
  478. // trigger highlighted node remove on corpus map
  479. try {
  480. _$corpus_canvas.trigger('audio-node-closed');
  481. } catch (e) {
  482. console.info('AudioPlayer hide() : _$corpus_canvas does not exists');
  483. }
  484. },
  485. // object events
  486. on(event_name, handler){
  487. if(typeof this.event_handlers[event_name] == 'undefined'){
  488. console.warn('AudioPlayer : event '+event_name+' does not exists');
  489. }
  490. this.event_handlers[event_name].push(handler);
  491. return this;
  492. },
  493. emmit(event_name, args){
  494. // console.log('AudioPlayer emmit() event_name', event_name);
  495. // console.log('AudioPlayer emmit() handlers', this.event_handlers[event_name]);
  496. var handler;
  497. var args = args || {};
  498. for (var i = this.event_handlers[event_name].length-1; i >= 0 ; i--) {
  499. handler = this.event_handlers[event_name][i];
  500. // console.log('AudioPlayer emmit() loop handler', handler);
  501. setTimeout(function(){
  502. // console.log('AudioPlayer emmit() timeout handler', handler);
  503. handler(args);
  504. }, 0);
  505. }
  506. return this;
  507. },
  508. }
  509. // ___ _ ___ _
  510. // | _ \__ _ _ _ __| |___ _ __ | _ \ |__ _ _ _ ___ _ _
  511. // | / _` | ' \/ _` / _ \ ' \| _/ / _` | || / -_) '_|
  512. // |_|_\__,_|_||_\__,_\___/_|_|_|_| |_\__,_|\_, \___|_|
  513. // |__/
  514. function RandomPlayer(playlist){
  515. this.active = false;
  516. this.playlist = playlist;
  517. this.$btn = $('<a>').html('Shuffle').addClass('random-player-btn');
  518. this.init();
  519. };
  520. RandomPlayer.prototype = {
  521. init(){
  522. // this.shuffle();
  523. $('<div>')
  524. .addClass('block random-player')
  525. .append(this.$btn)
  526. .insertAfter('#block-userlogin, #block-studiolinkblock');
  527. // events
  528. this.$btn.on('click', this.toggleActive.bind(this));
  529. // attach an event on AudioPlayer
  530. _audioPlayer
  531. .on('audio-ended', this.onAudioPlayerEnded.bind(this))
  532. .on('audio-play-next', this.onAudioPlayNext.bind(this))
  533. .on('stop-shuffle', this.stop.bind(this));
  534. },
  535. shuffle(){
  536. var tempPLaylist = [];
  537. for (var i = this.playlist.length-1; i >= 0 ; i--) {
  538. tempPLaylist.push(this.playlist[i]);
  539. }
  540. this.shuffledPlaylist = [];
  541. while(tempPLaylist.length > 0){
  542. var r = Math.floor(Math.random() * tempPLaylist.length);
  543. this.shuffledPlaylist.push(tempPLaylist.splice(r,1)[0]);
  544. }
  545. console.log('RandomPlayer, this.shuffledPlaylist', this.shuffledPlaylist);
  546. },
  547. toggleActive(e){
  548. if (this.active) {
  549. this.stop();
  550. }else{
  551. this.start();
  552. }
  553. },
  554. start(){
  555. this.active = _audioPlayer.shuffle_is_active = true;
  556. this.$btn.addClass('is-active');
  557. this.shuffle();
  558. this.next();
  559. },
  560. stop(){
  561. this.active = _audioPlayer.shuffle_is_active = false;
  562. this.$btn.removeClass('is-active');
  563. // stop audio player
  564. // _audioPlayer.stop();
  565. },
  566. next(){
  567. if(this.active && this.shuffledPlaylist.length > 0)
  568. _audioPlayer.openDocument(this.shuffledPlaylist.splice(0,1)[0]);
  569. },
  570. onAudioPlayNext(){
  571. console.log('RandomPlayer : onAudioPlayNext()');
  572. this.next();
  573. },
  574. onAudioPlayerEnded(){
  575. console.log('RandomPlayer : onAudioPlayerEnded()');
  576. this.next();
  577. }
  578. };
  579. // ___ ___ _
  580. // / __|___ _ __ _ __ ___| _ \ |__ _ _ _ ___ _ _
  581. // | (__/ _ \ ' \| '_ \/ _ \ _/ / _` | || / -_) '_|
  582. // \___\___/_|_|_| .__/\___/_| |_\__,_|\_, \___|_|
  583. // |_| |__/
  584. function CompoPlayer(){
  585. this.playing = false;
  586. this.paused = false;
  587. this.playlist = [];
  588. this.current_index = 0;
  589. this.$compo = null;
  590. this.init();
  591. };
  592. CompoPlayer.prototype = {
  593. init(){
  594. console.log('CompoPlayer init()');
  595. // attach an event on AudioPlayer
  596. _audioPlayer
  597. .on('audio-open-document', this.onAudioOpenDocument.bind(this))
  598. .on('audio-play', this.onAudioPlayerPlay.bind(this))
  599. .on('audio-pause', this.onAudioPlayerPause.bind(this))
  600. .on('audio-ended', this.onAudioPlayerEnded.bind(this));
  601. // .on('audio-play-next', this.onAudioPlayNext.bind(this));
  602. this.newCompo();
  603. },
  604. newCompo(){
  605. console.log('CompoPlayer newCompo()');
  606. // $('.composition_ui .composer .composition .field--name-documents')
  607. this.$composer = $('.composition_ui .composer');
  608. this.$compo = $('.composition_ui .composer .composition');
  609. this.$controls = $('.composition_ui .composer .compo-player-controls');
  610. if(!this.$controls.is('.ready')){
  611. this.$previous = $('<div>').addClass('previous')
  612. .on('click', this.prev.bind(this))
  613. .appendTo(this.$controls);
  614. this.$playpause = $('<div>').addClass('play-pause')
  615. .on('click', this.togglePlayPause.bind(this))
  616. .appendTo(this.$controls);
  617. this.$next = $('<div>').addClass('next')
  618. .on('click', this.next.bind(this))
  619. .appendTo(this.$controls);
  620. this.$controls.addClass('ready');
  621. }
  622. this.refresh();
  623. },
  624. refresh(){
  625. // console.log('CompoPlayer refresh(), this', this);
  626. // this.playing = false;
  627. // this.paused = false;
  628. // this.resetIndex();
  629. this.stop();
  630. // load new playlist
  631. this.playlist = [];
  632. var that = this;
  633. $('.field--name-documents .field__item',this.$compo).each(function(i,el){
  634. var $link = $('a.audio-link',this);
  635. that.playlist.push({
  636. item:$(this),
  637. audio_url:$link.attr("audio_url"),
  638. nid:$link.attr("nid"),
  639. });
  640. });
  641. this.showHideControls();
  642. },
  643. togglePlayPause(){
  644. // console.log('CompoPlayer togglePlayPause');
  645. if (this.playing && !this.paused) {
  646. this.pause();
  647. }else{
  648. if(this.playing && this.paused){
  649. this.play();
  650. }else{
  651. this.start();
  652. }
  653. }
  654. },
  655. start(){
  656. console.log('start');
  657. // console.log('CompoPlayer start()');
  658. this.playing = true;
  659. this.play();
  660. },
  661. play(){
  662. // console.log('play');
  663. if(this.paused){
  664. this.paused = false;
  665. _audioPlayer.play();
  666. }else{
  667. _audioPlayer.openDocument(this.playlist[this.current_index], this);
  668. }
  669. this.setActiveItem().showHideControls();
  670. },
  671. pause(){
  672. console.log('pause');
  673. this.paused = true;
  674. this.showHideControls();
  675. _audioPlayer.stop();
  676. },
  677. next(){
  678. // console.log('CompoPlayer next()');
  679. if(this.playing){
  680. this.current_index += 1;
  681. if(this.current_index < this.playlist.length){
  682. this.play();
  683. }else{
  684. this.stop();
  685. }
  686. }
  687. },
  688. prev(){
  689. // console.log('CompoPlayer prev()');
  690. if(this.playing){
  691. this.current_index -= 1;
  692. if(this.current_index >= 0){
  693. this.play();
  694. }else{
  695. this.stop();
  696. }
  697. }
  698. },
  699. stop(){
  700. _audioPlayer.stop();
  701. this.reset();
  702. },
  703. reset(){
  704. this.playing = false;
  705. this.paused = false;
  706. this.resetIndex();
  707. },
  708. resetIndex(){
  709. this.current_index = 0;
  710. this.showHideControls().resetActiveItems();
  711. },
  712. setActiveItem(){
  713. this.resetActiveItems();
  714. if(this.playing && this.current_index >= 0){
  715. this.playlist[this.current_index].item.addClass('is-active');
  716. }
  717. // this call shoud not be here
  718. this.showHideControls();
  719. return this;
  720. },
  721. resetActiveItems(){
  722. for (var n = 0; n < this.playlist.length; n++) {
  723. // console.log('node',node);
  724. this.playlist[n].item.removeClass('is-active');
  725. }
  726. return this;
  727. },
  728. showHideControls(){
  729. // console.log('CompoPlayer showHideNextBtn(), playing:'+this.playing+', paused:'+this.paused);
  730. // global playing
  731. if(this.playing && !this.paused){
  732. this.$controls.addClass('is-playing');
  733. }else{
  734. this.$controls.removeClass('is-playing');
  735. }
  736. // playpause
  737. if(this.playlist.length > 0){
  738. this.$playpause.addClass('is-active');
  739. }else{
  740. this.$playpause.removeClass('is-active');
  741. }
  742. // next
  743. if(this.playing && this.playlist.length > 1 && this.current_index < this.playlist.length -1){
  744. this.$next.addClass('is-active');
  745. }else{
  746. this.$next.removeClass('is-active');
  747. }
  748. // previous
  749. if(this.playing && this.playlist.length > 1 && this.current_index > 0){
  750. this.$previous.addClass('is-active');
  751. }else{
  752. this.$previous.removeClass('is-active');
  753. }
  754. return this;
  755. },
  756. // _audioPlayer events
  757. onAudioOpenDocument(args){
  758. if(args.caller !== this){
  759. // console.log('CompoPlayer onAudioOpenDocument() called by other');
  760. this.reset();
  761. }
  762. // else{
  763. // // console.log('CompoPlayer onAudioOpenDocument() self calling');
  764. // }
  765. },
  766. onAudioPlayerPlay(){
  767. if(this.playing && this.paused){
  768. this.paused = false;
  769. this.showHideControls();
  770. }
  771. },
  772. onAudioPlayerPause(){
  773. if(this.playing && !this.paused){
  774. this.paused = true;
  775. this.showHideControls();
  776. }
  777. },
  778. onAudioPlayerEnded(){
  779. this.next();
  780. },
  781. // onAudioPlayNext(){
  782. // this.next();
  783. // }
  784. };
  785. // ___ _ _ _
  786. // | _ \_ _ ___ __| |_ _ __| |_(_)___ _ _ ___
  787. // | _/ '_/ _ \/ _` | || / _| _| / _ \ ' \(_-<
  788. // |_| |_| \___/\__,_|\_,_\__|\__|_\___/_||_/__/
  789. function initProductions(){
  790. console.log('theme : initProductions');
  791. var $grid = $('.row', _$row).masonry({
  792. itemSelector:'.col',
  793. columnWidth:'.col-2'
  794. });
  795. // layout Masonry after each image loads
  796. $grid.imagesLoaded().progress( function() {
  797. $grid.masonry('layout');
  798. });
  799. // var $grid = $('.row', _$row).imagesLoaded( function() {
  800. // // init Masonry after all images have loaded
  801. // $grid.masonry({
  802. // itemSelector:'.col',
  803. // columnWidth:'.col-2'
  804. // });
  805. // });
  806. };
  807. // ___ _ ___
  808. // | __| _ ___ _ _| |_| _ \__ _ __ _ ___
  809. // | _| '_/ _ \ ' \ _| _/ _` / _` / -_)
  810. // |_||_| \___/_||_\__|_| \__,_\__, \___|
  811. // |___/
  812. function backToFrontPage(){
  813. closeAllModals();
  814. // assume we are going back to front page
  815. $('body').removeClass().addClass('path-frontpage');
  816. $('a[data-drupal-link-system-path="<front>"]').addClass('is-active');
  817. }
  818. // __ __ _ _
  819. // | \/ |___ __| |__ _| |___
  820. // | |\/| / _ \/ _` / _` | (_-<
  821. // |_| |_\___/\__,_\__,_|_/__/
  822. function closeAllModals(){
  823. console.log('theme : closeAllModals');
  824. // TODO: animate the remove
  825. _$row.html('');
  826. _$ajaxLinks.removeClass('is-active');
  827. };
  828. init();
  829. } // end EdlpTheme()
  830. $(document).ready(function($) {
  831. var edlptheme = new EdlpTheme();
  832. });
  833. })(jQuery, Drupal, drupalSettings);