PageRenderTime 89ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

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

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