main.js 30 KB

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