edlp_studio.js 14 KB

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