PageRenderTime 77ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-content/plugins/fusion-core/admin/page-builder/assets/js/editor.js

https://gitlab.com/webkod3r/tripolis
JavaScript | 477 lines | 343 code | 72 blank | 62 comment | 61 complexity | 3dced30b4f7ddb446befdc1663ab68bc MD5 | raw file
  1. /*
  2. * This is the Canvas placeholder which contains all selected elements
  3. */
  4. (function( $ ) {
  5. $.fn.outerHTML = function() {
  6. return (!this.length) ? this : (this[0].outerHTML || (function( el ) {
  7. var div = document.createElement( 'div' );
  8. div.appendChild( el.cloneNode( true ) );
  9. var contents = div.innerHTML;
  10. div = null;
  11. return contents;
  12. })( this[0] ));
  13. }
  14. var Editor = {};
  15. window.Editor = Editor;
  16. window['fusion_builder_tinymce_count'] = 1;
  17. // Selected element model
  18. Editor.ElementEntry = Backbone.Model.extend(
  19. {
  20. urlRoot: ajaxurl
  21. }
  22. );
  23. // Selected Element collection, it act as array for all selected elements
  24. Editor.SelectedElements = Backbone.Collection.extend(
  25. {
  26. model: Editor.ElementEntry,
  27. comparator: function( collection ) {
  28. // order collection by property "index"
  29. return (collection.get( 'index' ));
  30. },
  31. url: ajaxurl
  32. }
  33. );
  34. Editor.Display = Backbone.View.extend(
  35. {
  36. initialize: function() {
  37. this.selectedElements = new Editor.SelectedElements();
  38. // bind reset event to render function. i.e. when the collection is fetched this event is fired.
  39. this.selectedElements.bind( "reset", this.render, this );
  40. // bind add event to reRender function. i.e. when element is added this event is fired,
  41. // reRendring is needed to remove old elements as some element might be changed in the server and the view is not aware of that.
  42. this.selectedElements.bind( "add", this.reRender, this );
  43. },
  44. render: function() {
  45. this.selectedElements.each(
  46. function( element ) {
  47. var elementPlaceholder = new Editor.ElementPlaceholder( {model: element} );
  48. var renderedElement = elementPlaceholder.render();
  49. // if element contain parentId, it means it's a child and should not be rendered at this step.
  50. if ( !element.get( 'parentId' ) ) {
  51. this.$el.append( renderedElement.el );
  52. }
  53. }, this
  54. );
  55. return this;
  56. },
  57. reRender: function() {
  58. this.selectedElements.each(
  59. function( element ) {
  60. $( "#" + element.get( 'id' ) ).remove();
  61. }, this
  62. );
  63. this.render();
  64. return this;
  65. }
  66. }
  67. );
  68. Editor.deleteAllElements = function() {
  69. var editorElements = $( "#editor" ).find( '.item-wrapper' );
  70. for ( var i = 0; i < editorElements.length; i++ ) {
  71. var editorElement = $( editorElements[i] );
  72. var elementId = editorElement.attr( 'id' );
  73. if ( elementId ) {
  74. var element = app.editor.selectedElements.get( elementId );
  75. //$("#"+elementId).remove();
  76. $( "#delete-element-" + elementId ).trigger( "click" ); // trigger click event
  77. }
  78. }
  79. },
  80. // Selected Element view object
  81. Editor.ElementPlaceholder = Backbone.View.extend(
  82. {
  83. // tag name for the element is div, it means each element will be surrounding by <div></div>
  84. tagName: 'div',
  85. // classes for the element div
  86. className: 'item-wrapper sortable-element drag-element',
  87. initialize: function() {
  88. // use template that has name "content-child-div-template"
  89. this.template = window.HandlebarsLoadTemplate( 'content-child-div' );
  90. // find render function to the change event, for example when any attribute in element object is changed
  91. this.model.on( 'change', this.render, this );
  92. },
  93. events: function() {
  94. var _events = {};
  95. // When any of the below element's id is clicked the corresponding method will be executed
  96. _events["click " + "#increase-width-" + this.model.get( 'id' )] = "increaseWidth";
  97. _events["click " + "#decrease-width-" + this.model.get( 'id' )] = "decreaseWidth";
  98. _events["click " + "#delete-element-" + this.model.get( 'id' )] = "deleteElement";
  99. _events["click " + "#edit-element-" + this.model.get( 'id' )] = "openEditPanel";
  100. _events["click " + "#clone-element-" + this.model.get( 'id' )] = "cloneElement";
  101. return _events;
  102. },
  103. render: function() {
  104. $( this.el ).attr( 'id', this.model.get( 'id' ) );
  105. $( this.el ).addClass( this.model.get( 'css_class' ) );
  106. $( this.el ).html( this.template( this.model.toJSON() ) );
  107. // Get model "data" array and loop over it and add it to the DOM element with prefix "data-"
  108. var dataArray = this.model.get( 'data' );
  109. if ( dataArray ) {
  110. for ( var index in dataArray ) {
  111. $( this.el ).attr( "data-" + index, dataArray[index] );
  112. $( this.el ).find( '.innerElement' ).attr( "data-" + index, dataArray[index] );
  113. }
  114. }
  115. // get all children elements and render them
  116. if ( this.model.get( 'childrenId' ) ) {
  117. var childrenId = this.model.get( 'childrenId' );
  118. var childrenElements = new Editor.SelectedElements();
  119. for ( var i = 0; i < childrenId.length; i++ ) {
  120. var elementId = childrenId[i];
  121. var element = app.editor.selectedElements.get( elementId );
  122. if ( element ) {
  123. childrenElements.add( element );
  124. }
  125. }
  126. childrenElements.each(
  127. function( element ) {
  128. var elementOutput = new Editor.ElementPlaceholder( {model: element} ).render().el;
  129. $( this.el ).children().closest( '.innerElement' ).append( elementOutput );
  130. }, this
  131. );
  132. }
  133. //update previews
  134. fusionPreview.updatePreview( this, this.model, this.model.get( 'subElements' ) );
  135. this.activateDragging( $( this.el ) );
  136. this.activateDropping( $( this.el ) );
  137. return this;
  138. },
  139. openEditPanel: function() {
  140. // generate form html with help of currnt model data
  141. DdElementParser.generateHtml( this.model );
  142. var ElementName = this.model.get( 'name' );
  143. this.model.attributes.newElements = [];
  144. // add the element property "editPanel_innerHtml" to the jquery modal dialog
  145. document.getElementById('dialog_form').innerHTML = this.model.get('editPanel_innerHtml');
  146. var $dialog = $( document.getElementById( 'dialog_form' ) );
  147. // change dialog title
  148. $dialog.dialog( 'option', 'title', this.model.get( 'name' ) );
  149. var $appendMenu = "";
  150. if ( this.model.get( 'editPanel_appendtoTitle' ) && this.model.get( 'editPanel_appendtoTitle' ) != "" ) {
  151. $appendMenu = this.model.get( 'editPanel_appendtoTitle' );
  152. }
  153. // add the current element object to the dialog as a reference for later use
  154. $dialog.dialog( 'option', 'referencedView', this );
  155. // add noscroll css class to prevent scrolling the page while editing any element
  156. $( 'body' ).addClass( 'noscroll' );
  157. // open the dialog
  158. $dialog.data( 'appendMenu', $appendMenu ).dialog( "open" );
  159. //if slider type element then perform relative operations to show/hide elements w.r.t image/video
  160. if ( ElementName == "Slider" ) {
  161. $.each(
  162. $( "select[name*='fusion_slider_type']" ), function( key, value ) {
  163. var selectValue = $( value ).val();
  164. var parent = $( value ).parent().parent().parent();
  165. if ( selectValue == "video" ) {
  166. $( parent ).find( '.funsion-element-child' ).hide();
  167. $( parent ).find( "select[name*='fusion_slider_type']" ).parent().parent().show();
  168. $( parent ).find( "[name*='video_content']" ).parent().parent().show();
  169. } else {
  170. $( parent ).find( "[name*='video_content']" ).parent().parent().hide();
  171. }
  172. }
  173. );
  174. }
  175. //activae color picker
  176. if ( $( '.fusion-color-field' ).length > 0 ) {
  177. $dialog.find( '.fusion-color-field' ).wpColorPicker();
  178. }
  179. //for jQuery chosen
  180. if ( $( '.chosen-select' ).length > 0 ) {
  181. $( '.chosen-select' ).chosen(
  182. {
  183. placeholder_text_multiple: 'Select Options'
  184. }
  185. );
  186. }
  187. //replace text area with wp_editor if element is text block
  188. if ( typeof( tinyMCE ) == "object" && typeof( tinyMCE.execCommand ) == "function" ) {
  189. $dialog.find( ".html-field" ).each(
  190. function() {
  191. $( this ).attr( 'id', 'fusion_content_wp_' + window['fusion_builder_tinymce_count'] );
  192. window['fusion_builder_tinymce_count']++;
  193. var value = $( this ).val();
  194. $( this ).wp_editor( value );
  195. }
  196. );
  197. }
  198. // icons
  199. $( '.icon_select_container' ).each(
  200. function() {
  201. var icon_name = $( this ).parents( '.element-type' ).find( 'input[type=hidden]' ).val();
  202. if ( icon_name ) {
  203. $( this ).find( '.' + icon_name ).addClass( 'selected-element' );
  204. }
  205. }
  206. );
  207. },
  208. updateElement: function() {
  209. // get form data
  210. var subelements = $( '#element-edit-form' ).serializeArray();
  211. var newElements = this.model.get( 'newElements' );
  212. this.model.attributes.newElements = [];
  213. var originalSubElements = this.model.get( 'subElements' );
  214. //clean data before updatins elements
  215. for ( var t = 0; t < originalSubElements.length; t++ ) {
  216. if ( originalSubElements[t]['type'] == 'addmore' ) {
  217. //add new elements
  218. for ( var j = 0; j < newElements.length; j++ ) {
  219. originalSubElements[t]['elements'].push( newElements[j] );
  220. }
  221. //for add more
  222. var children = new Array();
  223. var regex = '/([)/g';
  224. //get children IDs from form elements
  225. for ( var i = 0; i < subelements.length; i++ ) {
  226. if ( subelements[i]['name'].indexOf( '[' ) !== -1 ) {
  227. var intVal = subelements[i]['name'].replace( /[^\d.]/g, '' );
  228. if ( $.inArray( intVal, children ) > -1 ) {
  229. //already in array
  230. } else {
  231. children.push( intVal );
  232. }
  233. }
  234. }
  235. var firstElement = JSON.stringify( originalSubElements[t]['elements'][0] );
  236. //empty sub elements
  237. originalSubElements[t]['elements'] = [];
  238. for ( var j = 0; j < children.length; j++ ) {
  239. originalSubElements[t]['elements'][j] = JSON.parse( firstElement );
  240. //get ID
  241. var eVal = originalSubElements[t]['elements'][j][0]['id'].replace( /[^\d.]/g, '' );
  242. //update IDs as per form elements
  243. for ( k = 0; k < originalSubElements[t]['elements'][j].length; k++ ) {
  244. if ( originalSubElements[t]['elements'][j][k] !== undefined && originalSubElements[t]['elements'][j][k] !== undefined ) {
  245. originalSubElements[t]['elements'][j][k]['id'] =
  246. originalSubElements[t]['elements'][j][k]['id'].replace(
  247. '[' + eVal + ']', '[' + children[j] + ']'
  248. );
  249. }
  250. }
  251. }
  252. } else if ( originalSubElements[t]['type'] == 'multiselect' ) {
  253. originalSubElements[t]['value'] = [];
  254. }
  255. }
  256. //clean data code ends here
  257. for ( var i = 0; i < subelements.length; i++ ) {
  258. for ( var t = 0; t < originalSubElements.length; t++ ) {
  259. if ( originalSubElements[t]['type'] == 'addmore' ) {
  260. for ( j = 0; j < originalSubElements[t]['elements'].length; j++ ) {
  261. for ( k = 0; k < originalSubElements[t]['elements'][j].length; k++ ) {
  262. if ( originalSubElements[t]['elements'][j][k]['id'] === subelements[i]['name'] ) {
  263. originalSubElements[t]['elements'][j][k]['value'] = subelements[i]['value'];
  264. }
  265. }
  266. }
  267. }
  268. else if ( subelements[i]['name'] === originalSubElements[t]['id'] ) {
  269. var tempPlaceholder = originalSubElements[t];
  270. if ( originalSubElements[t]['type'] == 'multiselect' ) {
  271. tempPlaceholder['value'].push( subelements[i]['value'] );
  272. } else {
  273. tempPlaceholder['value'] = subelements[i]['value'];
  274. }
  275. }
  276. }
  277. }
  278. //update previews
  279. fusionPreview.updatePreview( this, this.model, originalSubElements );
  280. // capture editor
  281. fusionHistoryManager.captureEditor();
  282. },
  283. cloneElement: function() {
  284. var newElementID = DdHelper.cloneElement( this.model );
  285. var parent = this.model.get( 'parentId' );
  286. if ( parent != null ) {
  287. //get parent element
  288. var parentElement = app.editor.selectedElements.get( parent );
  289. if ( parentElement.get( 'css_class' ).indexOf( 'fusion_full_width' ) > -1 ) {
  290. //update ChidlrendIDs
  291. DdHelper.updateChildrenIDs( this.model.get( 'id' ) );
  292. }
  293. }
  294. //turn off editor tracking first
  295. fusionHistoryManager.turnOffTracking();
  296. //re-render all elements for deep copy of model
  297. var elements = fusionHistoryManager.getAllElementsData();
  298. //remove all current editor elements first
  299. Editor.deleteAllElements();
  300. //reset models with new elements
  301. app.editor.selectedElements.reset( JSON.parse( elements ) );
  302. //turn on tracking now
  303. fusionHistoryManager.turnOnTracking();
  304. // capture editor
  305. fusionHistoryManager.captureEditor();
  306. return newElementID;
  307. },
  308. increaseWidth: function() {
  309. this.changeElementSize( 1 );
  310. },
  311. decreaseWidth: function() {
  312. this.changeElementSize( -1 );
  313. },
  314. changeElementSize: function( direction ) {
  315. var currentModel = this.model;
  316. var dataObject = currentModel.get( "data" );
  317. var currentSize = dataObject['width'];
  318. var currentElement;
  319. var nextElement;
  320. var columnSizes = [
  321. // phpClass, elementName, specific cssClass, width, base
  322. ['TF_GridOne', '1/1', 'grid_one', '6/6', 'one_full'],
  323. ['TF_GridFiveSix', '5/6', 'grid_five_sixth', '5/6', 'five_sixth'],
  324. ['TF_GridFourFifth', '4/5', 'grid_four_fifth', '4/5', 'four_fifth'],
  325. ['TF_GridThreeFourth', '3/4', 'grid_three_fourth', '3/4', 'three_fourth'],
  326. ['TF_GridTwoThird', '2/3', 'grid_two_third', '2/3', 'two_third'],
  327. ['TF_GridThreeFifth', '3/5', 'grid_three_fifth', '3/5', 'three_fifth'],
  328. ['TF_GridTwo', '1/2', 'grid_two', '2', 'one_half'],
  329. ['TF_GridTwoFifth', '2/5', 'grid_two_fifth', '2/5', 'two_fifth'],
  330. ['TF_GridThree', '1/3', 'grid_three', '3', 'one_third'],
  331. ['TF_GridFour', '1/4', 'grid_four', '4', 'one_fourth'],
  332. ['TF_GridFive', '1/5', 'grid_five', '5', 'one_fifth'],
  333. ['TF_GridSix', '1/6', 'grid_six', '6', 'one_sixth'],
  334. ];
  335. for ( var i = 0; i < columnSizes.length; i++ ) {
  336. if ( columnSizes[i][3] === currentSize ) {
  337. currentElement = columnSizes[i];
  338. nextElement = columnSizes[i - direction];
  339. break;
  340. }
  341. }
  342. if ( nextElement ) {
  343. // update element width
  344. dataObject['width'] = nextElement[3];
  345. dataObject['floated_width'] = eval( nextElement[1] ).toFixed( 2 );
  346. currentModel.attributes.data = dataObject;
  347. $( this.el ).data( 'width', nextElement[3] ).find( '.innerElement' ).data(
  348. 'width', nextElement[3]
  349. );
  350. // update element css class
  351. $( this.el ).removeClass( currentElement[2] );
  352. $( this.el ).removeClass( currentElement[2] );
  353. var cssClass = currentModel.get( "css_class" );
  354. cssClass = cssClass.replace( currentElement[2], nextElement[2] );
  355. currentModel.attributes.css_class = cssClass;
  356. // update element php class
  357. currentModel.attributes.php_class = nextElement[0];
  358. // update element name
  359. currentModel.attributes.name = nextElement[1];
  360. // update base
  361. currentModel.attributes.base = nextElement[4];
  362. var dataArray = currentModel.get( 'data' );
  363. if ( dataArray ) {
  364. for ( var index in dataArray ) {
  365. $( this.el ).attr( "data-" + index, dataArray[index] );
  366. $( this.el ).find( '.innerElement' ).attr( "data-" + index, dataArray[index] );
  367. }
  368. }
  369. $( this.el ).attr( 'id', currentModel.get( 'id' ) );
  370. $( this.el ).addClass( currentModel.get( 'css_class' ) );
  371. $( this.el ).find( '.grid_width' ).text( nextElement[1] );
  372. this.model = currentModel;
  373. // capture editor
  374. fusionHistoryManager.captureEditor();
  375. }
  376. },
  377. deleteElement: function() {
  378. var elementId = this.model.get( 'id' );
  379. $( "#" + elementId ).remove();
  380. // Check if the element has parent, and remove the reference to the element
  381. DdHelper.removeElementFromParent( elementId, this.model.get( 'parentId' ) );
  382. this.model.destroy(
  383. {
  384. error: function( errorResponse, errorDescription ) {
  385. //alert("Error during removing element "+errorDescription.responseText)
  386. }
  387. }
  388. );
  389. //patch for dropping when last item is removed
  390. if ( $( '#editor div' ).length == 0 ) {
  391. $( '#editor' ).droppable( 'destroy' );
  392. this.activateDropping( $( '#editor' ) );
  393. }
  394. // capture editor
  395. fusionHistoryManager.captureEditor();
  396. },
  397. activateDragging: function( element ) {
  398. DdHelper.activateDragging( element );
  399. },
  400. activateDropping: function( element ) {
  401. DdHelper.activateDropping( element );
  402. },
  403. }
  404. );
  405. })( jQuery );