main.js 29 KB

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