PageRenderTime 72ms CodeModel.GetById 19ms RepoModel.GetById 6ms app.codeStats 0ms

/wp-content/plugins/js_composer/assets/js/backend/composer-automapper.js

https://bitbucket.org/acipriani/madeinapulia.com
JavaScript | 599 lines | 571 code | 8 blank | 20 comment | 52 complexity | 207ba50086f96aca0ba932783475f3ef MD5 | raw file
Possible License(s): GPL-3.0, MIT, BSD-3-Clause, LGPL-2.1, GPL-2.0, Apache-2.0
  1. /* =========================================================
  2. * composer-automapper.js v0.2.1
  3. * =========================================================
  4. * Copyright 2013 Wpbakery
  5. *
  6. * Visual composer automapper for shortcodes
  7. * ========================================================= */
  8. var vc_am = {
  9. current_form: false
  10. };
  11. (function ($) {
  12. "use strict";
  13. _.extend( wp.shortcode.prototype, {
  14. taggedString: function() {
  15. var text = '[<span class="vc_preview-tag">' + this.tag + '</span>';
  16. _.each( this.attrs.numeric, function( value ) {
  17. if ( /\s/.test( value ) ) {
  18. text += ' <span class="vc_preview-param">"' + value + '"</span>';
  19. } else {
  20. text += ' <span class="vc_preview-param">' + value + '</span>';
  21. }
  22. });
  23. _.each( this.attrs.named, function( value, name ) {
  24. text += ' <span class="vc_preview-param">' + name + '="' + value + '"</span>';
  25. });
  26. // If the tag is marked as `single` or `self-closing`, close the
  27. // tag and ignore any additional content.
  28. if ( 'single' === this.type ) {
  29. return text + ']';
  30. } else if ( 'self-closing' === this.type ) {
  31. return text + ' /]';
  32. }
  33. // Complete the opening tag.
  34. text += ']';
  35. if ( this.content ) {
  36. text += '<span class="vc_preview-content">' + this.content + '</span>';
  37. }
  38. // Add the closing tag.
  39. return text + '[/<span class="vc_preview-tag">' + this.tag + '</span>]';
  40. }});
  41. wp.shortcode.atmPreview = function(options) {
  42. return new wp.shortcode( options ).taggedString();
  43. };
  44. var message_timer, show_message = function(text, type) {
  45. if(message_timer) {
  46. window.clearTimeout(message_timer);
  47. $('.vc_settings-automapper').remove();
  48. message_timer = false;
  49. }
  50. var $message = $('<div class="vc_atm-message updated' + (type ? ' vc_message-' + type : '') + '" style="display: none;"></div>');
  51. $message.text(text);
  52. $message.prependTo($('#vc_settings-automapper')).fadeIn(500, function(){
  53. var $message = $(this);
  54. window.setTimeout(function(){
  55. $message.remove();
  56. }, 2000);
  57. });
  58. },
  59. template_options = {
  60. evaluate: /<#([\s\S]+?)#>/g,
  61. interpolate: /\{\{\{([\s\S]+?)\}\}\}/g,
  62. escape: /\{\{([^\}]+?)\}\}(?!\})/g
  63. },
  64. regexp_shortcode = _.memoize(function() {
  65. return new RegExp( '\\[(\\[?)(\\S+)(?![\\w-])([^\\]\\/]*(?:\\/(?!\\])[^\\]\\/]*)*?)(?:(\\/)\\]|\\](?:([^\\[]*(?:\\[(?!\\/\\2\\])[^\\[]*)*)(\\[\\/\\2\\]))?)(\\]?)' );
  66. }),
  67. to_title = function(string) {
  68. string = string.replace(/_|-/, ' ');
  69. return string.charAt(0).toUpperCase() + string.slice(1);
  70. };
  71. var request_url = window.ajaxurl + '?vc_action=automapper',
  72. sync_callback = function(method, model, options) {
  73. var data;
  74. if(method === 'create') {
  75. model.set('id', window.vc_guid());
  76. data = {
  77. vc_action: 'create',
  78. data: model.toJSON()
  79. };
  80. } else if(method === 'update') {
  81. data = {
  82. vc_action: 'update',
  83. id: model.get('id'),
  84. data: model.toJSON()
  85. };
  86. } else if(method === 'delete') {
  87. data = {
  88. vc_action: 'delete',
  89. id: model.get('id')
  90. };
  91. } else {
  92. data = {
  93. vc_action: 'read'
  94. };
  95. }
  96. $.ajax({
  97. method: 'POST',
  98. url: request_url,
  99. dataType: 'json',
  100. data:_.extend(data, {action: 'vc_automapper'}),
  101. context: this
  102. }).done(function(data){
  103. var result = model;
  104. if(data && method === 'read') result = data;
  105. // Response
  106. if (result) {
  107. (method === 'read') && options.success(result);
  108. } else {
  109. options.error("Not found");
  110. }
  111. }).error(function(data){
  112. });
  113. };
  114. var ShortcodeModel = Backbone.Model.extend({
  115. defaults:function () {
  116. return {
  117. tag: '',
  118. name: '',
  119. category: '',
  120. description: '',
  121. params: []
  122. };
  123. },
  124. sync: sync_callback
  125. });
  126. var ShortcodesCollection = Backbone.Collection.extend({
  127. model: ShortcodeModel,
  128. sync: sync_callback
  129. });
  130. vc_am.shortcodes = new ShortcodesCollection;
  131. var ShortcodeView = Backbone.View.extend({
  132. tagName: 'li',
  133. // className: 'vc_automapper-item',
  134. className: 'widget',
  135. events: {
  136. 'click .vc_automapper-edit-btn': 'edit',
  137. 'click h4, widget-action': 'edit',
  138. 'click .vc_automapper-delete-btn': 'clear'
  139. },
  140. template_html: $('#vc_automapper-item-tpl').html() || '<span>{{ tag }}</span>',
  141. initialize: function() {
  142. this.listenTo(this.model, 'change', this.render);
  143. this.listenTo(this.model, 'destroy', this.removeView)
  144. },
  145. render: function() {
  146. this.$el.html(_.template(this.template_html, this.model.toJSON(), template_options)).attr('data-item-id', this.model.get('id'));
  147. return this;
  148. },
  149. edit: function(e) {
  150. e && e.preventDefault();
  151. new EditFormView({model: this.model}).render();
  152. },
  153. clear: function(e) {
  154. e && e.preventDefault();
  155. if(confirm(window.i18nLocaleVcAutomapper.are_you_sure_delete)) {
  156. this.model.destroy();
  157. }
  158. },
  159. removeView: function() {
  160. this.$el.remove();
  161. }
  162. });
  163. var FormView = Backbone.View.extend({
  164. render: function() {
  165. vc_am.current_form && vc_am.current_form.close();
  166. vc_am.current_form = this;
  167. return this;
  168. },
  169. getType: function() {
  170. return 'form';
  171. },
  172. validate: function(attrs) {
  173. var result = false;
  174. if(!attrs.name) {
  175. return window.i18nLocaleVcAutomapper.error_shortcode_name_is_required;
  176. }
  177. if (!attrs.tag || !attrs.tag.match(/^\S+$/)) {
  178. return window.i18nLocaleVcAutomapper.error_enter_valid_shortcode_tag;
  179. }
  180. var fields_required = ['param_name', 'heading', 'type'];
  181. _.each(attrs.params, function(param){
  182. _.each(fields_required, function(field){
  183. if(param[field] === '') {
  184. result = window.i18nLocaleVcAutomapper.error_enter_required_fields // '';
  185. } else if(field == 'param_name' && !param[field].match(/^[a-z0-9_]+$/g)) {
  186. result = window.i18nLocaleVcAutomapper.error_enter_required_fields;
  187. }
  188. }, this);
  189. }, this);
  190. return result || null;
  191. },
  192. isValid: function (data) {
  193. this.validationError = this.validate(data);
  194. return this.validationError ? false : true;
  195. },
  196. close: function(e) {
  197. e && e.preventDefault();
  198. vc_am.current_form = false;
  199. this.remove();
  200. }
  201. });
  202. var ComplexShortcodeView = Backbone.View.extend({
  203. _$widget_title: false,
  204. _$form_view: false,
  205. edit_view: false,
  206. tagName: 'li',
  207. className: 'widget',
  208. events: {
  209. 'click .vc_automapper-edit-btn': 'edit',
  210. 'click h4, .widget-action': 'edit'
  211. },
  212. template_html: $('#vc_automapper-item-complex-tpl').html() || '<span>{{ tag }}</span>',
  213. header_template_html: '<h4>{{ name }}<span class="in-widget-title"></span></h4>',
  214. initialize: function() {
  215. _.bindAll(this, 'removeEditForm');
  216. // this.listenTo(this.model, 'change', this.renderTitle);
  217. this.listenTo(this.model, 'destroy', this.removeView);
  218. this.model.view = this;
  219. },
  220. render: function() {
  221. this.$el.html(_.template(this.template_html, this.model.toJSON(), template_options)).attr('data-item-id', this.model.get('id'));
  222. return this;
  223. },
  224. renderTitle: function() {
  225. this.$widgetTitle().html(_.template(this.header_template_html, this.model.toJSON(), template_options));
  226. },
  227. edit: function(e) {
  228. e && e.preventDefault();
  229. if(this.$editForm().is(':animated')) return false;
  230. this.$el.addClass('vc_opened');
  231. if(this.edit_view) {
  232. this.close();
  233. } else {
  234. this.edit_view = new EditFormInnerView({model: this.model}).render();
  235. }
  236. },
  237. $widgetTitle: function() {
  238. if(!this._$widget_title) this._$widget_title = this.$el.find('.widget-title');
  239. return this._$widget_title;
  240. },
  241. $editForm: function() {
  242. if(!this._$edit_form) this._$edit_form = this.$el.find('.widget-inside');
  243. return this._$edit_form;
  244. },
  245. removeEditForm: function() {
  246. this.edit_view && this.edit_view.remove();
  247. this.edit_view = false;
  248. },
  249. beforeSave: function() {
  250. this.$el.find('#vc_atm-name').val($('#vc_atm-header-name').val());
  251. },
  252. close: function() {
  253. vc_am.current_form = false;
  254. this.$el.removeClass('vc_opened');
  255. this.renderTitle();
  256. this.$editForm().slideUp(100, this.removeEditForm);
  257. },
  258. clear: function(e) {
  259. e && e.preventDefault();
  260. this.model.destroy();
  261. },
  262. removeView: function() {
  263. this.remove();
  264. }
  265. });
  266. var AddFormView = FormView.extend({
  267. className: 'vc_add-form-atm',
  268. template_html: $('#vc_automapper-add-form-tpl').html(),
  269. events: {
  270. 'click #vc_atm-parse-string': 'parseShortcode',
  271. 'click .vc_atm-cancel': 'close'
  272. },
  273. getType: function() {
  274. return 'create';
  275. },
  276. render: function() {
  277. AddFormView.__super__.render.call(this);
  278. this.$el.html(_.template(this.template_html, {}, template_options));
  279. this.$el.insertAfter('.vc_automapper-toolbar');
  280. return this;
  281. },
  282. parseShortcode: function(e) {
  283. e && e.preventDefault && e.preventDefault();
  284. var string = $('#vc_atm-shortcode-string').val(), matches, data, params = [], attr;
  285. if(_.isEmpty(string)) return alert(window.i18nLocaleVcAutomapper.error_enter_valid_shortcode);
  286. matches = string.match(regexp_shortcode());
  287. if(!matches) return alert(window.i18nLocaleVcAutomapper.error_enter_valid_shortcode);
  288. attr = wp.shortcode.attrs(matches[3]);
  289. _.each(attr.named, function(value, key){
  290. params.push({param_name: key, type: "textfield", heading: to_title(key), description: 'Example: ' + value , value: value});
  291. }, this);
  292. if(matches[5]) params.push({param_name: 'content', type: "textarea", heading: 'Content', description: '', value: matches[5]});
  293. data = {
  294. tag: matches[2],
  295. name: to_title(matches[2]),
  296. category: window.i18nLocaleVcAutomapper.my_shortcodes_category,
  297. params: params
  298. };
  299. if(this.isValid(data)) {
  300. vc_am.shortcodes.create(data);
  301. show_message(window.i18nLocaleVcAutomapper.new_shortcode_mapped, 'success');
  302. // new EditFormView({model: vc_am.shortcodes.last()}).render();
  303. vc_am.shortcodes.last().view.edit();
  304. } else {
  305. alert(this.validationError);
  306. }
  307. }
  308. });
  309. var EditFormView = FormView.extend({
  310. className: 'vc_edit-form',
  311. active_preview: false,
  312. events: {
  313. 'click #vc_atm-save': 'save',
  314. 'click .vc_atm-cancel': 'close',
  315. 'click .vc_atm-delete': 'clear',
  316. 'click #vc_atm-add-param': 'addParam',
  317. 'click .vc_delete-param': 'deleteParam',
  318. 'change #vc_atm-is-container': 'setContentParam',
  319. 'keyup .vc_param-name, .vc_param-value, #vc_atm-tag': 'setPreview',
  320. 'focus #vc_atm-tag': 'setTagFieldActive',
  321. 'focus .vc_params input, .vc_params textarea': 'setParamFieldActive',
  322. 'focus .vc_param.vc_content input, .vc_param.vc_content textarea': 'setContentParamFieldActive',
  323. 'blur #vc_atm-tag, vc_param input': 'unsetFieldActive'
  324. },
  325. new: false,
  326. template_html: $('#vc_automapper-form-tpl').html(),
  327. param_template_html: $('#vc_atm-form-param-tpl').html(),
  328. getType: function() {
  329. return 'edit';
  330. },
  331. render: function() {
  332. EditFormView.__super__.render.call(this);
  333. this.$el.html(_.template(this.template_html, this.model.toJSON(), template_options));
  334. this.$el.insertAfter($('[data-item-id=' + this.model.id +']').hide());
  335. this.addAllParams();
  336. return this;
  337. },
  338. setTagFieldActive: function(e) {
  339. this.active_preview && $(this.active_preview).removeClass('vc_active');
  340. this.active_preview = '#vc_shortcode-preview .vc_preview-tag';
  341. $(this.active_preview).addClass('vc_active');
  342. },
  343. setParamFieldActive: function(e) {
  344. var $control = $(e.currentTarget),
  345. index = $control.parents('.vc_param:first').index();
  346. this.active_preview && $(this.active_preview).removeClass('vc_active');
  347. this.active_preview = '#vc_shortcode-preview .vc_preview-param:eq(' + index + ')';
  348. $(this.active_preview).addClass('vc_active');
  349. },
  350. setContentParamFieldActive: function(e) {
  351. this.active_preview && $(this.active_preview).removeClass('vc_active');
  352. this.active_preview = '#vc_shortcode-preview .vc_preview-content';
  353. $(this.active_preview).addClass('vc_active');
  354. },
  355. unsetFieldActive: function(e) {
  356. $(this.active_preview).removeClass('vc_active');
  357. this.active_preview = false;
  358. },
  359. /***
  360. * Escape double quotes in params value.
  361. * @param value
  362. * @return {*}
  363. */
  364. escapeParam:function (value) {
  365. return value.replace(/"/g, '``');
  366. },
  367. getPreview: function(data) {
  368. var params = data.params,
  369. content = false,
  370. params_to_string = {};
  371. _.each(params, function (value, key) {
  372. if (value.param_name !== 'content') {
  373. params_to_string[value.param_name] = this.escapeParam(value.value);
  374. } else {
  375. content = value.value;
  376. }
  377. }, this);
  378. return wp.shortcode.atmPreview({
  379. tag: data.tag,
  380. attrs: params_to_string,
  381. content: content,
  382. type: content === false ? 'single' : ''
  383. });
  384. },
  385. setPreview: function() {
  386. var data = {
  387. params: this.getParams(),
  388. tag: $('#vc_atm-tag').val()
  389. };
  390. $('#vc_shortcode-preview').html(this.getPreview(data));
  391. this.active_preview && $(this.active_preview).addClass('vc_active');
  392. },
  393. save: function(e) {
  394. e && e.preventDefault && e.preventDefault();
  395. this.$el.find('.vc_error').removeClass('vc_error');
  396. var data = {
  397. tag: $('#vc_atm-tag').val(),
  398. name: $('#vc_atm-name').val(),
  399. category: $('#vc_atm-category').val(),
  400. description: $('#vc_atm-description').val(),
  401. params: this.getParams()
  402. };
  403. if(this.isValid(data)) {
  404. this.model.save(data);
  405. show_message(window.i18nLocaleVcAutomapper.shortcode_updated, 'success');
  406. this.close();
  407. } else {
  408. alert(this.validationError);
  409. }
  410. },
  411. validate: function(attrs) {
  412. var result = false, added_param_names = {};
  413. if(!attrs.name) {
  414. $('#vc_atm-name').addClass('vc_error');
  415. return window.i18nLocaleVcAutomapper.error_shortcode_name_is_required;
  416. }
  417. if (!attrs.tag || !attrs.tag.match(/^\S+$/)) {
  418. $('#vc_atm-tag').addClass('vc_error');
  419. return window.i18nLocaleVcAutomapper.error_enter_valid_shortcode_tag;
  420. }
  421. var fields_required = ['param_name', 'heading', 'type'];
  422. _.each(attrs.params, function(param, index){
  423. if(param.param_name === 'content' && !$('#vc_atm-params-list [name=param_name]:eq(' + index +')').data('system')) {
  424. result = window.i18nLocaleVcAutomapper.error_content_param_not_manually;
  425. $('#vc_atm-params-list [name=param_name]:eq(' + index +')').addClass('vc_error');
  426. return;
  427. }
  428. if(_.isBoolean(added_param_names[param.param_name]) && added_param_names[param.param_name] == true) {
  429. $('#vc_atm-params-list [name=param_name]:eq(' + index +')').addClass('vc_error');
  430. if(!result) result = window.i18nLocaleVcAutomapper.error_param_already_exists.replace(/\%s/, param.param_name);
  431. }
  432. added_param_names[param.param_name] = true;
  433. _.each(fields_required, function(field){
  434. if(param[field] === '') {
  435. $('#vc_atm-params-list [name=' + field +']:eq(' + index +')').addClass('vc_error');
  436. if(!result) result = window.i18nLocaleVcAutomapper.error_enter_required_fields;
  437. } else if(field == 'param_name' && !param[field].match(/^[a-z0-9_]+$/g)) {
  438. $('#vc_atm-params-list [name=' + field +']:eq(' + index +')').addClass('vc_error');
  439. if(!result) result = window.i18nLocaleVcAutomapper.error_wrong_param_name;
  440. }
  441. }, this);
  442. }, this);
  443. return result || null;
  444. },
  445. setContentParam: function(e) {
  446. var $control = $(e.currentTarget);
  447. if($control.is(':checked')) {
  448. this.addParamField({type: 'textarea', heading: 'Content', description: '', param_name: 'content', value: ''});
  449. this.setParamSorting();
  450. } else {
  451. this.removeParamField('content');
  452. }
  453. this.setPreview();
  454. },
  455. addAllParams: function() {
  456. _.each(this.model.get('params'), function(param){
  457. this.addParamField(param);
  458. if(param.param_name === 'content') $('#vc_atm-is-container').prop('checked', true);
  459. }, this);
  460. this.setParamSorting();
  461. },
  462. getParams: function() {
  463. var params = [];
  464. _.each($('.vc_param'), function(param){
  465. var $param = $(param);
  466. params.push({
  467. param_name: $param.find('[name=param_name]').val(),
  468. type: $param.find('[name=type]').val(),
  469. description: $param.find('[name=description]').val(),
  470. heading: $param.find('[name=heading]').val(),
  471. value: $param.find('[name=value]').val()
  472. });
  473. }, this);
  474. return params;
  475. },
  476. addParam: function(e) {
  477. e && e.preventDefault();
  478. this.addParamField({type: '', heading: '', description: '', param_name: '', value: ''});
  479. this.setPreview();
  480. },
  481. removeParamField: function(name) {
  482. $('.vc_param-name[value="' + name + '"]').parents('.vc_param').remove();
  483. },
  484. addParamField: function(attr) {
  485. var $block = $('<div class="vc_param' + ( attr.param_name === 'content' ? ' vc_content' : '' ) + '"/>').appendTo('#vc_atm-params-list');
  486. $block.html(_.template(this.param_template_html, attr, template_options));
  487. },
  488. setParamSorting: function() {
  489. $('#vc_atm-params-list').sortable({
  490. items: '> .vc_param',
  491. tolerance: "pointer",
  492. handle: '.vc_move-param',
  493. update: this.setPreview,
  494. placeholder: "vc_sortable-placeholder"});
  495. },
  496. deleteParam: function(e) {
  497. var $control;
  498. e && e.preventDefault();
  499. if(confirm(window.i18nLocaleVcAutomapper.are_you_sure_delete_param)) {
  500. $control =$(e.currentTarget);
  501. $control.parents('.vc_param').remove();
  502. this.setPreview();
  503. }
  504. },
  505. close: function(e) {
  506. e && e.preventDefault();
  507. this.model && $('[data-item-id=' + this.model.get('id') +']').show();
  508. vc_am.current_form = false;
  509. this.remove();
  510. },
  511. clear: function(e) {
  512. e && e.preventDefault();
  513. if(confirm(window.i18nLocaleVcAutomapper.are_you_sure_delete)) {
  514. this.model.destroy();
  515. this.close();
  516. }
  517. }
  518. });
  519. var EditFormInnerView = EditFormView.extend({
  520. template_html: $('#vc_automapper-form-tpl').html(),
  521. getType: function() {
  522. return 'edit';
  523. },
  524. initialize: function() {
  525. _.bindAll(this, 'setPreview');
  526. },
  527. render: function() {
  528. var params, content,
  529. parent = this.model.view;
  530. params = this.model.get('params');
  531. EditFormView.__super__.render.call(this);
  532. this.$el.html(_.template(this.template_html, _.extend({shortcode_preview: this.getPreview(this.model.toJSON())}, this.model.toJSON()), template_options));
  533. this.$el.appendTo(parent.$editForm());
  534. parent.$widgetTitle().html('<span class="vc_atm-header"><input type="text" name="name" value="" id="vc_atm-header-name" class="vc_header-name"></span><span class="in-widget-title"></span>');
  535. $('#vc_atm-header-name').val(this.model.get('name'));
  536. this.addAllParams();
  537. parent.$editForm().slideDown();
  538. return this;
  539. },
  540. save: function(e) {
  541. e && e.preventDefault();
  542. this.model.view.beforeSave();
  543. EditFormInnerView.__super__.save.call(this);
  544. },
  545. close: function(e) {
  546. e && e.preventDefault();
  547. vc_am.current_form = false;
  548. this.model.view.close();
  549. },
  550. clear: function(e) {
  551. e && e.preventDefault();
  552. if(confirm(window.i18nLocaleVcAutomapper.are_you_sure_delete)) {
  553. this.model.view.clear();
  554. this.remove();
  555. }
  556. }
  557. });
  558. var AppView = Backbone.View.extend({
  559. events: {
  560. 'click #vc_automapper-add-btn': 'create'
  561. },
  562. className: 'vc_atm-form',
  563. initialize: function() {
  564. this.listenTo(vc_am.shortcodes, 'add', this.addOne);
  565. this.listenTo(vc_am.shortcodes, 'reset', this.addAll);
  566. this.listenTo(vc_am.shortcodes, 'all', this.render);
  567. this.$list = $('.vc_automapper-list');
  568. vc_am.shortcodes.fetch();
  569. },
  570. addAll: function(models) {
  571. models.each(function(model){
  572. this.addOne(model);
  573. }, this);
  574. },
  575. addOne: function(model) {
  576. var view = new ComplexShortcodeView({model: model});
  577. this.$list.append(view.render().el);
  578. },
  579. create: function(e) {
  580. e && e.preventDefault();
  581. if(!vc_am.current_form || vc_am.current_form.getType() !== 'create') {
  582. new AddFormView().render();
  583. }
  584. },
  585. render: function() {
  586. }
  587. });
  588. new AppView({el: $('#vc_settings-automapper')});
  589. })(window.jQuery);