edlp_studio.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. (function ($, Drupal, drupalSettings) {
  2. var _settings = drupalSettings.edlp_studio;
  3. var _$composer;
  4. // audio play is handled by edlp_theme
  5. function init(){
  6. // console.log('Studio Init');
  7. initEvents();
  8. initStudio();
  9. };
  10. function initEvents(){
  11. $('body')
  12. .on('new-audio-cartel-loaded', initAjaxChutierLinks)
  13. .on('new-content-ajax-loaded', initAjaxChutierLinks)
  14. .on('new-content-ajax-loaded', initStudio)
  15. .on('all-modal-closed', initStudio);
  16. };
  17. function initStudio(){
  18. if($('#studio-ui').length){
  19. _$composer = $('.composition_ui .composer', '#studio-ui');
  20. initAjaxChutierLinks();
  21. initAjaxCompoLinks();
  22. initDragAndDropUI();
  23. initUsedChutierInCompo();
  24. $('body').trigger({'type':'studio-initialized'});
  25. }else{
  26. $('body').trigger({'type':'studio-not-active'});
  27. }
  28. }
  29. // ___ _ _ _ _ _ _ _ _ _
  30. // / __| |_ _ _| |_(_)___ _ _ | \| |___ __| |___ | | (_)_ _ | |__ ___
  31. // | (__| ' \ || | _| / -_) '_| | .` / _ \/ _` / -_) | |__| | ' \| / /(_-<
  32. // \___|_||_\_,_|\__|_\___|_| |_|\_\___/\__,_\___| |____|_|_||_|_\_\/__/
  33. function initAjaxChutierLinks(){
  34. //console.log('studio initAjaxChutierLinks');
  35. $('.chutier-ajax-link:not(.ajax-enabled)')
  36. .addClass('ajax-enabled')
  37. .on('click', onClickChutierAjaxLink);
  38. };
  39. function onClickChutierAjaxLink(e){
  40. //console.log('studio onClickAjaxLink chutier');
  41. e.preventDefault();
  42. addRemoveToChutier($(this));
  43. return false;
  44. };
  45. function addRemoveToChutier($link){
  46. // var ajax_path = 'edlp_studio/ajax/chutier/add/'+id; // + '/' +cid;
  47. var ajax_path = $link.attr('data-drupal-link-system-path');
  48. var path = window.location.origin + drupalSettings.path.baseUrl + ajax_path;
  49. $link.addClass('ajax-loading');
  50. $.getJSON(path, {})
  51. .done(function(data){
  52. onActionToChutierDone($link, data);
  53. })
  54. .fail(function(jqxhr, textStatus, error){
  55. onErrorActionToChutier(jqxhr, textStatus, error, $link);
  56. });
  57. };
  58. function onActionToChutierDone($link, data){
  59. //console.log('onActionToChutierDone',data);
  60. $('body').trigger({
  61. 'type':'chutier-action-done',
  62. 'action_done':data.action_done,
  63. 'new_action':data.action_done == 'add' ? 'remove' : 'add',
  64. 'target_id':$link.attr('target_id'),
  65. });
  66. $link.replaceWith(data.new_link);
  67. initAjaxChutierLinks();
  68. // reload Studio chutier_ui's documents list
  69. updateStudioChutier();
  70. };
  71. function onErrorActionToChutier(jqxhr, textStatus, error, $link){
  72. console.warn('action to chuttier load failed : '+error, jqxhr.responseText);
  73. };
  74. // ___ _ _ _
  75. // / __|___ _ __ _ __ ___ __(_) |_(_)___ _ _ ___
  76. // | (__/ _ \ ' \| '_ \/ _ (_-< | _| / _ \ ' \(_-<
  77. // \___\___/_|_|_| .__/\___/__/_|\__|_\___/_||_/__/
  78. // |_|
  79. function initAjaxCompoLinks(){
  80. //console.log('studio initAjaxCompoLinks');
  81. $('.new-composition-link:not(.ajax-enabled)')
  82. .on('click', onClickNewCompoLink)
  83. .addClass('ajax-enabled');
  84. $('.composition-link:not(.ajax-enabled)')
  85. .on('click', onClickCompoLink)
  86. .addClass('ajax-enabled');
  87. $('.delete-composition-link:not(.ajax-enabled)')
  88. .on('click', onClickDeleteCompoLink)
  89. .addClass('ajax-enabled');
  90. };
  91. function initUsedChutierInCompo(){
  92. console.log('initUsedChutierInCompo');
  93. $('.chutier-link.on-compo', '#studio-ui .chutier_ui').removeClass('on-compo');
  94. var nid;
  95. $('.audio-link', _$composer).each(function(index, el) {
  96. nid = $(el).attr('nid');
  97. console.log('compo item', nid);
  98. $('.chutier-link[target_id="'+nid+'"]', '#studio-ui .chutier_ui').addClass('on-compo');
  99. });
  100. //audio-link
  101. };
  102. // ___ ___
  103. // / _ \ _ __ ___ _ _ / __|___ _ __ _ __ ___
  104. // | (_) | '_ \/ -_) ' \ | (__/ _ \ ' \| '_ \/ _ \
  105. // \___/| .__/\___|_||_| \___\___/_|_|_| .__/\___/
  106. // |_| |_|
  107. function onClickCompoLink(e){
  108. e.preventDefault();
  109. //console.log('onClickCompoLink');
  110. openCompo($(this));
  111. return false;
  112. };
  113. function openCompo($link){
  114. var cid = $link.attr('cid');
  115. var ajax_path = _settings.open_compo_ajax_url+'/'+cid;
  116. var path = window.location.origin + Drupal.url(ajax_path);
  117. $link.addClass('ajax-loading');
  118. _$composer.addClass('ajax-loading');
  119. $.getJSON(path, {})
  120. .done(function(data){
  121. onOpenCompoDone(data, $link);
  122. })
  123. .fail(function(jqxhr, textStatus, error){
  124. onErrorOpenCompo(jqxhr, textStatus, error, $link);
  125. });
  126. };
  127. function onOpenCompoDone(data, $link){
  128. console.log('onOpenCompoDone',data);
  129. $('.composition-link').removeClass('is-active');
  130. $link.removeClass('ajax-loading').addClass('is-active');
  131. if($('.composition', _$composer).length){
  132. $('.composition', _$composer).replaceWith(data.compo);
  133. }else{
  134. $('header', _$composer).after(data.compo);
  135. }
  136. _$composer.removeClass('ajax-loading');
  137. initDragAndDropUI();
  138. initUsedChutierInCompo();
  139. $('body').trigger({
  140. 'type':'on-studio-compo-opened'
  141. });
  142. };
  143. function onErrorOpenCompo(jqxhr, textStatus, error, $link){
  144. $link.removeClass('ajax-loading');
  145. console.warn('open compo load failed : '+error, jqxhr.responseText);
  146. };
  147. // _ _ _____ __ __ __ ___ _ __ _ __ ___
  148. // | ' \/ -_) V V / / _/ _ \ ' \| '_ \/ _ \
  149. // |_||_\___|\_/\_/ \__\___/_|_|_| .__/\___/
  150. // |_|
  151. function onClickNewCompoLink(e){
  152. e.preventDefault();
  153. setInputForNewCompoName($(this));
  154. return false;
  155. };
  156. function setInputForNewCompoName($link){
  157. var $form = $('<form>').addClass('new-compo-form')
  158. .append($('<input>').attr('type', 'text').attr('placeholder', 'new name'))
  159. .append($('<button>').attr('type', 'submit').html('+'))
  160. .submit(function(e){
  161. onNewCompoFormSubmit(e, $link, $(this));
  162. });
  163. $link
  164. .after($form)
  165. .addClass('folded');
  166. $form.children('input[type="text"]').focus();
  167. };
  168. function onNewCompoFormSubmit(e, $link, $form){
  169. var name = $('input[type="text"]',$form).val();
  170. //console.log('onNewCompoFormSubmit', name);
  171. if(name != ''){
  172. $form.addClass('ajax-loading').children('*').attr('disabled', 'disabled');
  173. createNewCompo(name, $link, $form);
  174. }
  175. e.preventDefault();
  176. };
  177. function createNewCompo(name,$link, $form){
  178. var ajax_path = $link.attr('data-drupal-link-system-path');
  179. var path = window.location.origin + drupalSettings.path.baseUrl + ajax_path;
  180. // $link.addClass('ajax-loading');
  181. $.getJSON(path, {
  182. 'new_name':name
  183. })
  184. .done(function(data){
  185. onCreateCompoDone(data, $link, $form);
  186. })
  187. .fail(function(jqxhr, textStatus, error){
  188. onErrorCreateCompo(jqxhr, textStatus, error, $link);
  189. });
  190. };
  191. function onCreateCompoDone(data, $link, $form){
  192. //console.log('onActionToCompoDone',data);
  193. var $new_link = $(data.new_link);
  194. var $delete_link = $(data.delete_link);
  195. $link
  196. .removeClass('folded')
  197. .parents('li')
  198. .after($('<li>').append($new_link).append($delete_link));
  199. $form.remove();
  200. // open new composition to composer
  201. initAjaxCompoLinks();
  202. openCompo($new_link);
  203. };
  204. function onErrorCreateCompo(jqxhr, textStatus, error, $link){
  205. console.warn('action to compo load failed : '+error, jqxhr.responseText);
  206. };
  207. // ___ _ _
  208. // | \ ___| |___| |_ ___ __ ___ _ __ _ __ ___
  209. // | |) / -_) / -_) _/ -_) / _/ _ \ ' \| '_ \/ _ \
  210. // |___/\___|_\___|\__\___| \__\___/_|_|_| .__/\___/
  211. // |_|
  212. function onClickDeleteCompoLink(e){
  213. e.preventDefault();
  214. // TODO: confirm compo deletion
  215. deleteCompo($(this));
  216. return false;
  217. };
  218. function deleteCompo($link){
  219. var ajax_path = $link.attr('data-drupal-link-system-path');
  220. var path = window.location.origin + Drupal.url(ajax_path);
  221. $link.parents('li').addClass('ajax-loading');
  222. $.getJSON(path, {})
  223. .done(function(data){
  224. onDeleteCompoDone(data, $link);
  225. })
  226. .fail(function(jqxhr, textStatus, error){
  227. onErrorDeleteCompo(jqxhr, textStatus, error, $link);
  228. });
  229. };
  230. function onDeleteCompoDone(data, $link, $form){
  231. //console.log('onDeleteCompoDone',data);
  232. if(data.status == "ok"){
  233. $link.parents('li').remove();
  234. //console.log("$('.composition-link').length", $('.composition-link').length);
  235. if($('.composition-link').length){
  236. openCompo($('.composition-link').eq(0));
  237. }else{
  238. $('.composition', _$composer).html();
  239. }
  240. }else{
  241. console.warn(data.message);
  242. }
  243. };
  244. function onErrorDeleteCompo(jqxhr, textStatus, error, $link){
  245. $link.parents('li').removeClass('ajax-loading');
  246. console.warn('delete compo load failed : '+error, jqxhr.responseText);
  247. };
  248. // ___ _ _ _ _
  249. // / __| |_ _ _ __| (_)___ ___ _ _(_)
  250. // \__ \ _| || / _` | / _ \___| || | |
  251. // |___/\__|\_,_\__,_|_\___/ \_,_|_|
  252. // this seems dirty
  253. function updateStudioChutier(){
  254. $studioChutier = $('#studio-ui .chutier_ui');
  255. if($studioChutier.length){
  256. var ajax_path = _settings.chutier_ui_ajax;
  257. var path = window.location.origin + drupalSettings.path.baseUrl + ajax_path;
  258. $studioChutier.addClass('loading');
  259. $.getJSON(path, {})
  260. .done(function(data){
  261. onLoadedChutier($studioChutier, data);
  262. })
  263. .fail(function(jqxhr, textStatus, error){
  264. onLoadChutierError(jqxhr, textStatus, error, $studioChutier);
  265. });
  266. }
  267. };
  268. function onLoadedChutier($studioChutier, data){
  269. $studioChutier.replaceWith(data.rendered);
  270. initAjaxChutierLinks();
  271. // set chutier element draggable again
  272. setChutierDraggable();
  273. $('body').trigger({
  274. 'type':'on-studio-chutier-updated'
  275. });
  276. }
  277. function onLoadChutierError(jqxhr, textStatus, error, $studioChutier){
  278. console.warn('Chutier load failed', jqxhr.responseText);
  279. $studioChutier.removeClass('loading');
  280. }
  281. // ___ __ ___ _ _ ___
  282. // | \ _ _ __ _ __ _ / _|___ | \ _ _ ___ _ __ | | | |_ _|
  283. // | |) | '_/ _` / _` | > _|_ _| | |) | '_/ _ \ '_ \ | |_| || |
  284. // |___/|_| \__,_\__, | \_____| |___/|_| \___/ .__/ \___/|___|
  285. // |___/ |_|
  286. function initDragAndDropUI(){
  287. // check if field--name-documents exists
  288. if (!$('.composition_ui .composer .composition .field--name-documents').length) {
  289. // if not create it
  290. $field_documents = $('<div>')
  291. .addClass('field').addClass('field--name-documents')
  292. .appendTo('.composition_ui .composer .composition');
  293. }else{
  294. // add real dom square element to handle sorting
  295. $field_documents = $('.composition_ui .composer .composition .field--name-documents'); $('.field__item', $field_documents).each(function(i){
  296. $(this).prepend($('<span>').addClass('handler'));
  297. });
  298. }
  299. // create remove dropzone
  300. var $remove_zone = $('<div>').addClass('remove-drop-zone')
  301. .appendTo('.composition_ui .composer .composition')
  302. .droppable({
  303. tolerance:'pointer',
  304. // scope:'composition_ui',
  305. over:function(e,ui){
  306. // console.log('on over remove : ui', ui);
  307. ui.draggable.addClass('ready-to-remove');
  308. },
  309. out:function(e,ui){
  310. // console.log('on over remove : ui', ui);
  311. ui.draggable.removeClass('ready-to-remove');
  312. },
  313. drop:function(e,ui){
  314. // console.log('on drop remove : ui', ui);
  315. ui.draggable.remove();
  316. // onOrderChanged(ui);
  317. }
  318. });
  319. // create sortable
  320. $field_documents.sortable({
  321. revert:false,
  322. handle: ".handler",
  323. receive:function(e, ui){
  324. $('.field__item', this).attr('style', '');
  325. // TODO: trigger event to enable new audiolink player
  326. },
  327. update:function(e, ui){
  328. onOrderChanged(e, ui);
  329. },
  330. connectWith : $remove_zone,
  331. });
  332. // set chutier element draggable
  333. setChutierDraggable();
  334. };
  335. function setChutierDraggable(){
  336. $('.chutier_ui .item-list li>div').draggable({
  337. containment:$('#studio-ui'),
  338. scroll:false,
  339. helper:function(e){
  340. // we reproduce here the item structure of destination sortable elements
  341. // var $audio_link = $('.audio-link',this);
  342. return $('<div>').addClass('field__item')
  343. .append(
  344. $('<article>').addClass('node').append(
  345. $('<h2>').addClass('node-title').append(
  346. // $('<a>')
  347. // .attr('nid', $audio_link.attr('nid'))
  348. // .html($audio_link.html())
  349. $('.audio-link',this).clone().removeClass('ajax-enable')
  350. )
  351. )
  352. )
  353. .prepend($('<span>').addClass('handler'));
  354. },
  355. // cursor:'grab',
  356. cursorAt:{bottom:10,left:10},
  357. zIndex:999,
  358. revert:true,
  359. revertDuration:0,
  360. connectToSortable:$('.composition_ui .composer .composition .field--name-documents'),
  361. });
  362. }
  363. function onOrderChanged(e, ui){
  364. //console.log('onOrderChanged : e', e);
  365. var cid = $(e.target).parents('.composition').attr('cid');
  366. var documents = {};
  367. $('a', e.target).each(function(i) {
  368. // console.log(this);
  369. documents[i] = $(this).attr('nid');
  370. });
  371. // console.log(documents);
  372. initUsedChutierInCompo();
  373. recordCompoList(cid, documents);
  374. };
  375. function recordCompoList(cid, docs){
  376. //console.log('recordCompoList '+cid, docs);
  377. var ajax_path = _settings.save_compo_ajax_url+'/'+cid;
  378. var path = window.location.origin + Drupal.url(ajax_path);
  379. //console.log('path', path);
  380. $.getJSON(path, {
  381. documents:docs
  382. })
  383. .done(function(data){
  384. onRecordCompoDone(data);
  385. })
  386. .fail(function(jqxhr, textStatus, error){
  387. onErrorRecordCompo(jqxhr, textStatus, error);
  388. });
  389. $('body').trigger({
  390. 'type':'on-studio-compo-updated'
  391. });
  392. }
  393. function onRecordCompoDone(data){
  394. //console.log('onDeleteCompoDone',data);
  395. if(data.status == "ok"){
  396. }else{
  397. console.warn(data.message);
  398. }
  399. };
  400. function onErrorRecordCompo(jqxhr, textStatus, error){
  401. console.warn('record compo failed : '+error, jqxhr.responseText);
  402. };
  403. init();
  404. })(jQuery, Drupal, drupalSettings);