PluginProbe
Smart Grid-Layout Design for Contact Form 7 / 4.1.0
Smart Grid-Layout Design for Contact Form 7 v4.1.0
4.18.0 4.17.0 3.2.0 3.2.1 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.3.8 4.0.0 4.0.1 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.10 4.11 4.12 4.13 4.14 All 119 releases
cf7-grid-layout / admin / js / cf7-grid-layout-admin.js

cf7-grid-layout-admin.js in Smart Grid-Layout Design for Contact Form 7 4.1.0, at admin/js/cf7-grid-layout-admin.js

1,281 lines 51.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1
2 /**
3 Javascript to handle grid editor
4 Event 'cf7sg-form-change' fired on #contact-form-editor element when codemirror changes occur
5 */
6 (function( $ ) {
7 'use strict';
8 const offsets = ['offset-one','offset-two', 'offset-three', 'offset-four', 'offset-five', 'offset-six', 'offset-seven', 'offset-eight', 'offset-nine', 'offset-ten', 'offset-eleven'],
9 columnsizes = ['one', 'two', 'one-fourth', 'one-third', 'five', 'one-half', 'seven', 'two-thirds', 'nine', 'ten', 'eleven', 'full'];
10 let $wpcf7Editor,$grid,$rowControl = null;
11 //graphics UI template pattern
12 const $pattern = $('<div>').html(cf7grid.preHTML+'\\s*(\\[.*\\s*\\].*\\s*){0,}\\s*'+cf7grid.postHTML),
13 required = cf7grid.requiredHTML.replace('*', '\\*');
14 // console.log('r:'+required);
15 $pattern.find('label').html('((\\s*.*)('+required+'){1}|(\\s*.*))');
16 $pattern.find('.info-tip').text('(.*\\s*)');
17 //console.log('p:'+$pattern.html());
18 const templateRegex = new RegExp($pattern.html().replace('><','>\\s?<'), 'ig');
19 let seekTemplate = false, cssTemplate = 'div.field',
20 $template = $('<div id="cf7sg-dummy">').append(cf7grid.preHTML+cf7grid.postHTML);
21 $template = $template.children();
22 if(1==$template.length && $template.find('label').length>0){
23 seekTemplate = true;
24 cssTemplate = $template.prop('nodeName');
25 if($template.prop('class').length>0){
26 cssTemplate += '.'+$template.attr('class').split(' ').join('.');
27 }
28 }
29 let wpcf7Value = '';
30
31 $(document).ready( function(){
32 //change the form id to mimic cf7 plugin custom admin page.
33 /** @since 2.11.0 full screen button*/
34 let $editor = $('#cf7sg-editor'), bodyWidth = $('#wpbody').width();
35 $editor.css('background-color',$('body').css('background-color'));
36 $('#full-screen-cf7').on('click', function(){
37 $editor.toggleClass('full-screen');
38 $(this).toggleClass('full-screen');
39 if($editor.is('.full-screen')) $editor.width(bodyWidth);
40 else $editor.width('auto');
41 $('#form-editor-tabs .ui-tabs-panel', $editor).trigger('cf7sg-screen-resize');
42 });
43 $wpcf7Editor = $('textarea#wpcf7-form-hidden');
44 $grid = $('#grid-form');
45 $rowControl = $('#top-grid-controls');
46
47 /*
48 Build grid from existing form------------------------- BUILD UI FORM
49 */
50 function buildGridForm(){
51 let formhtml = $wpcf7Editor.text();
52 if(0===formhtml.length){
53 formhtml = '<div class="container"><div class="row"><div class="columns full"></div></div></div>';
54 }
55 const $form = $('<div>').append( formhtml );
56 let isGrid = true; //return value.
57 $grid.html(''); //empty the grid.
58 if(0===$form.children('.container').length){
59 isGrid = false;
60 }
61 //remove the external forms
62 $('.cf7sg-external-form .cf7sg-external-form-content', $form).remove();
63 //replace columns content with textareas
64 /*--------------------------------------------------- convert columns */
65 $('div.columns', $form).each(function(){
66 const $this = $(this), $area = $($('#grid-col').html());
67 if($this.children().is('.container')){
68 $('textarea.grid-input', $area).remove();
69 $('div.cf7-field-inner', $area).remove();
70 }else{
71 if(cf7grid.ui) $('textarea.grid-input', $area).html($this.html().trim());
72 else $('textarea.grid-input', $area).val($this.html().trim());
73
74 $this.children().remove();
75 $this.text('');
76 }
77 $this.prepend($area);
78 });
79 $('div.row', $form).each(function(){
80 $(this).append( $('#grid-row .row-controls').clone() );
81 });
82 /*--------------------------------------------------- convert collapsible sections */
83 $('div.container.cf7sg-collapsible', $form).each(function(){
84 const $this = $(this);
85 let id = $this.attr('id');
86 if(typeof id == 'undefined'){
87 id = randString(6);
88 $this.attr('id', id); //assign a random id
89 }
90 let text = $this.children('.cf7sg-collapsible-title span.cf7sg-title').text();
91 if(0==text.length){ //pre v1.8 title?.
92 text = $this.children('.cf7sg-collapsible-title').text();
93 }
94 let $toggle = $('.toggle', $this.children('.cf7sg-collapsible-title'));
95 if($toggle.length>0){
96 $toggle = $toggle.clone();
97 }
98
99 $this.children('.cf7sg-collapsible-title').remove();
100 $this.prepend( $('#grid-collapsible').html());
101 $('input', $this.children('.cf7sg-collapsible-title')).not('[type="checkbox"]').val(text);
102 if($toggle.length>0){
103 $this.children('.cf7sg-collapsible-title').append($toggle);
104 $('input[type="checkbox"]', $this.children('.cf7sg-collapsible-title') ).prop('checked', true);
105 }
106 const $ctrl = $this.children('.row').children('.row-controls').find('.collapsible-row-label');
107 $('input', $ctrl).prop('checked', true);
108 //toggle disable the sibling input
109 $('input', $ctrl.siblings('.unique-mod')).prop('disabled', function(i,v){return !v;});
110 });
111 /*--------------------------------------------------- convert tables */
112 $('div.container.cf7-sg-table', $form).each(function(){
113 const $this = $(this);
114 let id = $this.attr('id');
115 if(typeof id == 'undefined'){
116 id = 'cf7-sg-table-'+(new Date).getTime();
117 $this.attr('id', id);
118 }
119 let $ctrl = $this.find('.row.cf7-sg-table > .row-controls' ).first().find('.table-row-label');
120 $('input', $ctrl).prop('checked', true);
121 //set button label
122 let text = $this.data('button');
123 if(typeof text == 'undefined'){
124 text = 'Add Row';
125 $this.attr('data-button',text);
126 }
127 $ctrl.next('.table-row-button').children('input').val(text);
128 //toggle disable the sibling input
129 $('input', $ctrl.siblings('.unique-mod')).prop('disabled', function(i,v){return !v;});
130 //toggle footer row
131 const $footer = $this.next();
132 if($footer.is('.cf7-sg-table-footer')){
133 $ctrl = $footer.children('.row').first().find('.row-controls .footer-row-label');
134 $('input.footer-row', $ctrl).prop('checked', true);
135 $('input', $ctrl.siblings('.unique-mod')).prop('disabled', function(i,v){return !v;});
136 }
137 });
138 //tabs
139 /*--------------------------------------------------- convert tabs */
140 $('ul.cf7-sg-tabs-list li', $form).each(function(){
141 const $this = $(this);
142 let text = $this.children('a').text();
143 $this.append($('#grid-tabs ul li label').clone());
144 $('label input', $this).val(text);
145 //setup checkbox
146 let $ctrl = $this.parent().siblings('.cf7-sg-tabs-panel');
147 $ctrl = $ctrl.children('.row').find('.row-controls' ).first().find('.tabs-row-label');
148 $('input.tabs-row', $ctrl).prop('checked', true);
149 $('input', $ctrl.siblings('.unique-mod')).prop('disabled', function(i,v){return !v;});
150 });
151 //reinsert the external forms
152 $('.cf7sg-external-form', $form).each(function(){
153 const $extform = $(this);
154 $extform.append($( $('#grid-cf7-forms .cf7sg-external-form').html() ) );
155 let id = $extform.data('form');
156 if($('#grid-cf7-forms .form-select option[value="'+id+'"]' ).length > 0 ){
157 //add controls
158 //$extform.append($('#grid-cf7-forms .form-controls').clone());
159 $('.form-controls .form-select', $extform).val(id);
160 //check for form update.
161 const data = {
162 'action' : 'get_cf7_content',
163 'id': $('#post_ID').val(),
164 'nonce' : $('#_wpcf7nonce').val(),
165 'cf7_key' : id,
166 'update' :true
167 };
168 $.post(ajaxurl, data, function(response) {
169 if(response.length > 0){
170 $('.cf7sg-external-form-content', $extform).attr('id','cf7sg-form-'+id).append( response );
171 }//TODO if error insert a msg.
172 });
173
174 }
175 });
176 /** @since 3.4 enable groupings of collapsible rows */
177 $('.cf7sg-accordion-rows.columns, .cf7sg-slider-section.columns', $form).each(function(){
178 let $col = $(this),
179 $control = $col.children('.grid-column').addClass('enable-grouping'); //enable checkboxes.
180 if($col.is('.cf7sg-accordion-rows')){
181 $('.accordion-rows:input', $control).prop('checked', true);
182 }else{ //is .cf7sg-slider-section
183 $('.slider-rows:input', $control).prop('checked', true);
184 }
185 //remove toggle checkbox.
186 $('input[type="checkbox"]', $col.children('.cf7sg-collapsible').children('.cf7sg-collapsible-title') ).hide().next('span').hide();
187 });
188 //check if any columns have more than 2 collapsible sections.
189 $('.row .cf7sg-collapsible:first-child', $form).each(function(){
190 $(this).siblings('.cf7sg-collapsible').closest('.columns').children('.grid-column').addClass('enable-grouping');
191 });
192 //add the form to the grid
193 if($form.children('.container').length >0 || $form.children('.cf7sg-external-form').length>0){
194 $grid.append($form.children());
195 }else{ //this is not a cf7sg form.
196 $grid.html($form.html());
197 }
198 //set the value of each textarea as inner text
199 $('textarea', $grid).each(function(){
200 const $this = $(this);
201 $this.html($this.val());
202 });
203 /*--------------------------------------------------- if ui mode, then convert to gui template */
204 let $textareaSelected='';
205 if(cf7grid.ui){
206 $('div.columns', $grid).each(function(){
207 const $this = $(this);
208 if($this.children().is('.container')) return true;
209 $this.html2gui();
210 });
211 }else{
212 //set the first textarea as our default tag consumer
213 $('textarea#wpcf7-form').attr('id','');
214 $textareaSelected = $('textarea', $grid).first();
215 $textareaSelected.attr('id', 'wpcf7-form');
216 }
217 //change this to whichever is live
218 $('textarea', $grid).on('focus', function(){
219 const $this = $(this);
220 if($textareaSelected.length>0 && $textareaSelected.is('#wpcf7-form')){
221 $textareaSelected.attr('id','');
222 $textareaSelected.html($textareaSelected.val()); //set its inner html
223 }
224 if($this.is('.grid-input')){
225 $('textarea#wpcf7-form').attr('id','');
226 $textareaSelected = $this.attr('id','wpcf7-form');
227 }
228 });
229 return isGrid;
230 } //end buildGridForm()
231 /** @since 3.4.0 enalbe accordion class for containers having multiple collapsible rows */
232 $grid.on('cf7sg-update', function(e, update){
233 let $container = $(e.target);
234 if(undefined !== update.add){
235 switch(update.add){
236 case 'collapsible-row':
237 let $pc = $container.closest('.columns');
238 if( $pc.children('.cf7sg-collapsible').length>1 ){
239 //enable column accordion control.
240 $pc.children('.grid-column').addClass('enable-grouping');
241 }
242 }
243 }
244 if(undefined !== update.remove){
245 switch(update.remove){
246 case 'collapsible-row':
247 let $pc = $container.closest('.columns');
248 if( $pc.children('.cf7sg-collapsible').length<2 ){
249 //disable column accordion control.
250 $pc.children('.grid-column').removeClass('enable-grouping');
251 }
252 }
253 }
254 });
255 //offset/size change using event delegation
256 /*---------------------------------------------------------------------------- ui menus */
257 $grid.on('change', function(event){
258 const $target = $(event.target);
259 if($target.is('.column-setting')){ //----------- column size/offset settings
260 let validation = ['dummy'];
261 if( $target.is('.column-offset') ){
262 validation = offsets;
263 }else if( $target.is('.column-size') ){
264 validation = columnsizes;
265 }else{
266 return false;
267 }
268 const $column = $target.closest('.columns'), classList = $column.attr('class').split(/\s+/);
269 for(let idx=0; idx<classList.length; idx++){
270 if($.inArray(classList[idx], validation) > -1){
271 $column.removeClass(classList[idx]);
272 }
273 }
274 $column.addClass($target.val());
275 //filter the options
276 $target.closest('.grid-controls').filterColumnControls();
277 }else if($target.is('.form-select')){ //-------------- external form selection
278 const $container = $target.closest('.cf7sg-external-form');
279 $container.attr('data-form', $target.val());
280 const data = {
281 'action' : 'get_cf7_content',
282 'id': $('#post_ID').val(),
283 'nonce' : $('#_wpcf7nonce').val(),
284 'cf7_key' : $target.val()
285 };
286 $.post(ajaxurl, data, function(response) {
287 $('.cf7sg-external-form-content', $container).attr('id','cf7sg-form-'+$target.val()).html(response);
288 });
289 }
290 /*
291 Collapsible / tabs rows input changes
292 */
293 if($target.is('.cf7sg-collapsible-title label input[type="text"]')){ //------- Collapsible title
294 $target.siblings('input[type="hidden"]').val($target.val());
295 }else if( $target.is('.cf7sg-collapsible-title label input[type="checkbox"]')){ //------- Collapsible title toggled
296 const $title = $target.closest('.cf7sg-collapsible-title');
297 if($target.is(':checked')){
298 $title.append($('#grid-collapsible-with-toggle').html());
299 $title.closest('.container.cf7sg-collapsible').addClass('with-toggle').attr('data-group','').attr('data-open','false');
300 }else{
301 $('.toggle', $title).remove();
302 $title.closest('.container.cf7sg-collapsible').removeClass('with-toggle').removeAttr( 'data-group').removeAttr( 'data-open');
303 }
304 }else if($target.is('ul.cf7-sg-tabs-list li label input[type="text"]')){ //------- Tabs title
305 $target.parent().siblings('a').text($target.val());
306 }else if($target.is('label.table-row-button input')){
307 $target.closest('.container.cf7-sg-table').attr('data-button',$target.val());
308 }
309 if(cf7grid.ui){
310 if($target.is('.cf7-field-inner textarea')){
311 let label = $target.scanCF7Tag();
312 $target.siblings('p.content').html(label);//.show();
313 $target.parent().siblings('textarea.grid-input').updateGridForm();
314 }else if($target.is('.cf7-field-inner input')){
315 $target.siblings('p.content').html($target.val());
316 $target.parent().siblings('textarea.grid-input').updateGridForm();
317 }
318 }
319 });
320
321 //grid click event delegation
322 $grid.on('click', function(event){
323 const $target = $(event.target);
324 switch(true){
325 case $target.is('input[type="text"]:visible'):
326 case $target.is('textarea:visible'): //click on a field.
327 case $target.is('select:visible'):
328 return true;
329 break;
330 }
331 //close any open row/column controls
332 closeAllControls();
333
334 /*
335 Row controls
336 ----------------------------------------------------------ROW CONTRLS
337 */
338 let $parentRow,$parentContainer, $parentColumn;
339 if($target.is('.dashicons-trash.form-control')){ //--------TRASH included form
340 $target.closest('.cf7sg-external-form').remove();
341 }else if($target.is('.dashicons-plus.form-control') ){ //---ADD external form
342 $target.closest('.cf7sg-external-form').insertNewRow();
343 }else if($target.is('.dashicons-trash.row-control')){ //--------TRASH
344 $parentContainer = $target.closest('.container');
345 let $parent = $parentContainer.parent();
346 $parentContainer.remove();
347 if( $parent.is('.columns') ) { //verify is this is the last row being deleted
348 if( 0 == $parent.children('.container').length ){
349 //add a text area to the column
350 $parent.children('.grid-column').append('<textarea class="grid-input"></textarea>');
351 }
352 }
353 }else if($target.is('.dashicons-plus.row-control')){ //-----------ADD Row
354 $target.closest('.container').insertNewRow();
355 }else if($target.is('.dashicons-edit.row-control')){ //-----------Show controls
356 //hide any other controls that might be open
357 //taken care by closeAllControls
358
359 $target.siblings('.grid-controls').show();
360 $target.hide();
361 $target.siblings('.dashicons-no-alt').show();
362 /*
363 TODO: use $('.grid-controls')filterColumnControls() to make sure columns sizes/offsets are correct.
364 possibly introduce a boolean to check if filter has been run already on this row
365 */
366 }else if( $target.is('.dashicons-no-alt.row-control') ) { //----------------hide controls
367 //take care by closeAllControls
368 }else if($target.is('input.collapsible-row')){ //-------------checkbox collapsible row
369 const $container = $target.closest('.container');
370 if($target.is(':checked')){
371 $container.addClass('cf7sg-collapsible');
372 let id = $container.attr('id');
373 if(typeof id == 'undefined'){
374 id = randString(6);
375 $container.attr('id', id); //assign a random id
376 }
377 $container.prepend($('#grid-collapsible').html()).fireGridUpdate('add','collapsible-row');
378 }else{
379 $container.removeClass('cf7sg-collapsible');
380 $container.children('.cf7sg-collapsible-title').remove();
381 $container.fireGridUpdate('remove','collapsible-row');
382 }
383 //toggle disable the sibling input
384 $target.parent().siblings('label.unique-mod').children('input').prop('disabled', function(i,v){return !v;});
385 }else if($target.is('input.table-row')){ //-------------checkbox table row
386 if($target.is(':checked')){
387 let id = 'cf7-sg-table-'+(new Date).getTime();
388 $target.closest('.row').addClass('cf7-sg-table');
389 $target.closest('.container').addClass('cf7-sg-table').attr('id',id).fireGridUpdate('add','table-row');
390 }else{
391 $target.closest('.row').removeClass('cf7-sg-table');
392 $target.closest('.container').removeClass('cf7-sg-table').removeAttr('id').removeAttr('data-button').fireGridUpdate('remove','table-row');
393 }
394 //toggle disable the sibling input
395 $target.parent().siblings('label.unique-mod').children('input').prop('disabled', function(i,v){return !v;});
396 }else if($target.is('input.tabs-row')){ //-------------checkbox tabbed row
397 const $panel = $target.closest('.container');
398 if($target.is(':checked')){
399 let id = 'cf7-sg-tab-'+(new Date).getTime();
400 $panel.addClass('cf7-sg-tabs-panel').attr('id',id);
401 $panel.before($('#grid-tabs').html());
402 $panel.closest('.columns').addClass('cf7-sg-tabs');
403 $('li a', $panel.siblings('ul.cf7-sg-tabs-list')).attr('href','#'+id);
404 $panel.fireGridUpdate('add','tabbed-row');
405 }else{
406 $panel.removeClass('cf7-sg-tabs-panel');
407 $panel.closest('.columns').removeClass('cf7-sg-tabs');
408 $panel.siblings('ul.cf7-sg-tabs-list').remove();
409 $panel.fireGridUpdate('remove','tabbed-row');
410 }
411 //toggle disable the sibling input
412 $target.parent().siblings('label.unique-mod').children('input').prop('disabled', function(i,v){return !v;});
413 }else if($target.is('input.footer-row')){ //-------------checkbox footer row
414 const $table = $target.closest('.container').prev();
415 if($table.is('.container.cf7-sg-table')){
416 if($target.is(':checked')){
417 $target.closest('.container').addClass('cf7-sg-table-footer').fireGridUpdate('add','footer-row');
418 }else{
419 $target.closest('.container').removeClass('cf7-sg-table-footer').fireGridUpdate('remove','footer-row');
420 }
421 //toggle disable the sibling input
422 $target.parent().siblings('label.unique-mod').children('input').prop('disabled', function(i,v){return !v;});
423 }
424 }else if( $target.is('.make-grid.row-control') ){ /** @since 3.4.0--wrap row into column ->make grid*/
425 //close the grid-control box
426 $target.parent().hide();
427 $target.parent().siblings('.dashicons-no-alt').hide();
428 $target.parent().siblings('.dashicons-edit').show();
429 //convert to grid if multiple columns
430 $parentRow = $target.closest('.row');
431 if($parentRow && $parentRow.children('.columns').length>1){
432 //is row table/tab
433 $parentContainer = $parentRow.closest('.container');
434 const $content = $parentRow.children('.columns');
435 $content.wrapAll('<div class="columns full"></div>');
436 $parentColumn = $content.parent('.columns');
437 $parentColumn.prepend( $( $('#grid-col').html() ) );
438 //remove single cell UI content
439 $parentColumn.children('.grid-column').children('textarea.grid-input').remove();
440 $parentColumn.children('.grid-column').children('div.cf7-field-inner').remove();
441 //finally insert a new row with the content moved to the new row.
442 $parentColumn.insertNewRow($content.remove());
443 }
444 }
445
446
447 /*
448 Column controls, show/hide contols, add column, and refresh select dropdowns for colum size on addition
449 */
450
451 if( $target.is('.columns')){
452 $parentColumn = $target;
453 }else{
454 $parentColumn = $target.closest('.columns');
455 }
456 //verify which target was clicked
457 if( $target.is('.dashicons-edit.column-control') ){ //------------------show controls
458 //now show this control
459 $target.siblings('.grid-controls').show().filterColumnControls();
460 $target.hide();
461 $target.siblings('.dashicons-no-alt').show();
462 }else if( $target.is('.php-icon.column-control') ) { //--------show hooks
463 let $helper =$('<div class="helper-popup">').html( $('#grid-helper').html()),
464 $copy = $('.copy-helper', $helper),
465 field = $target.data('field'),
466 tag = $target.data('tag'),
467 search = $target.data('search'),
468 $hooks = $(search, '#fieldhelperdiv').clone();
469 $target.after($helper)
470 $('.cf7sg-helper-list', $helper).append($hooks);
471 $('a.helper', $helper).each(function(){
472 new Clipboard($(this)[0], {
473 text: function(trigger) {
474 let $target = $(trigger);
475 let text = $target.data('cf72post');
476 //get post slug
477 let key = $('#post_name').val();
478 text = text.replace(/\{\$form_key\}/gi, key);
479 text = text.replace(/\{\$field_name\}/gi, field);
480 text = text.replace(/\{\$field_name_slug\}/gi, field.replace(/\-/g,'_'));
481 text = text.replace(/\{\$field_type\}/gi, tag);
482 text = text.replace(/\[dqt\]/gi, '"');
483 return text;
484 }
485 });
486 $(this).append($copy.clone());
487 });
488 $helper.click('a.helper, .dashicons-no-alt', function(e){
489 $(this).remove();
490 });
491 }else if( $target.is('.js-icon.column-control') ) { //--------show js hooks
492 let $helper =$('<div class="helper-popup">').html( $('#grid-js-helper').html()),
493 $copy = $('.copy-helper', $helper),
494 field = $target.data('field'),
495 tag = $target.data('tag'),
496 search = $target.data('search'),
497 $hooks = $(search, '#fieldhelperjs').clone();
498 $target.after($helper);
499 $('.cf7sg-helper-list', $helper).append($hooks);
500 $('a.helper', $helper).each(function(){
501 new Clipboard($(this)[0], {
502 text: function(trigger) {
503 let $target = $(trigger);
504 let text = $target.data('cf72post');
505 //get post slug
506 let key = $('#post_name').val();
507 text = text.replace(/\{\$form_key\}/gi, key);
508 text = text.replace(/\{\$field_name\}/gi, field);
509 text = text.replace(/\{\$field_name_slug\}/gi, field.replace(/\-/g,'_'));
510 text = text.replace(/\{\$field_type\}/gi, tag);
511 text = text.replace(/\[dqt\]/gi, '"');
512 return text;
513 }
514 });
515 $(this).append($copy.clone());
516 });
517 $helper.click('a.helper, .dashicons-no-alt', function(e){
518 $(this).remove();
519 });
520 }else if($target.is('.icon-code.column-control') ){
521 const $focus = $target.closest('.columns');
522 //toggle cf7sgfocus class on inner field to focus on.
523 if($focus.is('.cf7sgfocus')){
524 $focus.removeClass('cf7sgfocus');
525 }else{
526 $('.cf7sgfocus', $grid).removeClass('cf7sgfocus');
527 $focus.addClass('cf7sgfocus');
528 }
529 //move to text editor.
530 $('#form-editor-tabs').tabs('option',{ active:1});
531 $('body').addClass('disable-scroll');
532 }else if($target.is('.dashicons-trash.column-control') ){ //-------------------delete column
533 $parentColumn.closest('.row').fireGridUpdate('remove','column');
534 $parentColumn.remove();
535 //refilter
536 //$target.siblings('.grid-controls').filterColumnControls();
537 }else if( $target.is('.make-grid.column-control') ){ //--------------------add row/convert column to grid
538
539 //close the grid-control box
540 $target.parent().hide();
541 $target.parent().siblings('.dashicons-no-alt').hide();
542 $target.parent().siblings('.dashicons-edit').show();
543 //convert to grid
544 $parentColumn = $target.closest('.columns');
545 if($parentColumn.length > 0){
546 //column already has a row?
547 let text = '';
548 if(0 == $parentColumn.children('.container').length){
549 //keep the textarea and remove from the column
550 if(cf7grid.ui){
551 text = $('textarea.grid-input', $parentColumn).remove().text();
552 $('div.cf7-field-inner', $parentColumn).remove();
553 }else{
554 text = $('textarea.grid-input', $parentColumn).remove().val();
555 }
556 }else{
557 text = $parentColumn.children('.container').remove();
558 }
559 $parentColumn.insertNewRow(text);
560 }else{ //add to the main container
561 $grid.insertNewRow();
562 }
563 }else if($target.is('.external-form')){ //---------------- insert cf7 form
564 //close the grid-control box
565 $target.parent().hide();
566 $target.parent().siblings('.dashicons-no-alt').hide();
567 $target.parent().siblings('.dashicons-edit').show();
568 //replace container with form selector
569 $target.closest('.container').after($('#grid-cf7-forms').html());
570 $target.closest('.container').remove();
571 }else if( $target.is('.dashicons-plus.column-control') ){ //--------------------add column
572 $parentColumn = $target.closest('.columns');
573 $parentRow = $parentColumn.closest('.row');
574 let classList, idx , columns, row, newSize=0, createColumn = true, total = 0;
575 let sizes = [], $newColumn = $('<div class="columns"></div>');
576 //is the row filled up?
577 //first check if the current column fills the entire row
578 if( $parentColumn.is('.full') ){
579 total = 12;
580 columns = 1;
581 sizes[0] = columnsizes.length - 1; //ie 11, the last value
582 }else{
583 row = $parentRow.getRowSize();
584 total = row.length;
585 sizes = row.cols;
586 columns = sizes.length;
587 }
588 if(12 == total) {
589 newSize = Math.floor( total/(columns + 1) ) - 1 ;
590 if(newSize < 0 ){ //max columns reached
591 /*TODO: display an error message and return */
592 return false;
593 }
594 createColumn = false;
595 let newClass = columnsizes[newSize];
596 $parentRow.children('.columns').each(function(index){
597 //make sure the column is not size 1
598 if( sizes[index] > 0 ){
599 $(this).changeColumnSize(columnsizes[sizes[index]], newClass );
600 createColumn = true;
601 }
602 });
603 if(!createColumn){ //not enough space to create extra column
604 /*TODO: display an error message and return */
605 return false;
606 }
607 }else if(total < 12){ //just add the new column as size 1
608 if( (12 - total) < total){
609 newSize = 12 - total - 1;
610 }else{
611 newSize = total - 1;
612 }
613 }else{ //should never reach here
614 return false;
615 }
616 //add the new column
617 $newColumn.append( $( $('#grid-col').html() ) );
618 if(cf7grid.ui){
619 $('textarea.grid-input' ,$newColumn).hide();
620 }else{
621 $('div.cf7-field-inner', $newColumn).hide();
622 }
623 $newColumn.changeColumnSize('',columnsizes[newSize]);
624 $parentColumn.after($newColumn);
625 }else if( $target.is('.accordion-rows.column-control') ){ /** @since 3.4.0 enable accordion */
626 if($target.is(':checked')){
627 $parentColumn.addClass('cf7sg-accordion-rows').removeClass('cf7sg-slider-section').removeAttr("data-next data-prev data-submit");
628 $target.parent('label').siblings('.grouping-option').children(':input').prop('checked', false);
629 $target.fireGridUpdate('add','accordion-rows');
630 //hide toggle checkbox.
631 $('input[type="checkbox"]', $parentColumn.children('.cf7sg-collapsible').children('.cf7sg-collapsible-title') ).hide().next('span').hide();
632 }else{
633 $target.closest('.columns').removeClass('cf7sg-accordion-rows');
634 $target.fireGridUpdate('remove','accordion-rows');
635 //show toggle checkbox.
636 $('input[type="checkbox"]', $parentColumn.children('.cf7sg-collapsible').children('.cf7sg-collapsible-title') ).show().next('span').show();
637 }
638 }else if( $target.is('.slider-rows.column-control') ) { /** @since 3.4.0 enable slider */
639 if($target.is(':checked')){
640 let attrs = { "data-next":"", "data-prev":"", "data-submit":""};
641 $target.closest('.columns').addClass('cf7sg-slider-section').attr(attrs).removeClass('cf7sg-accordion-rows');
642 $target.parent('label').siblings('.grouping-option').children(':input').prop('checked', false);
643 $target.fireGridUpdate('add','slider-section');
644 //hide toggle checkbox.
645 $('input[type="checkbox"]', $parentColumn.children('.cf7sg-collapsible').children('.cf7sg-collapsible-title') ).hide().next('span').hide();
646 }else{
647 $target.closest('.columns').removeClass('cf7sg-slider-section').removeAttr("data-next data-prev data-submit");
648 $target.fireGridUpdate('remove','slider-section');
649 //show toggle checkbox.
650 $('input[type="checkbox"]', $parentColumn.children('.cf7sg-collapsible').children('.cf7sg-collapsible-title') ).show().next('span').show();
651 }
652 }
653 /*
654 Column UI fields
655 */
656 if(cf7grid.ui){
657 //close any open ui fields
658 closeAlluiFields();
659 if($target.is('.cf7-field-inner p.content')){
660 $target.parent().showUIfield();
661 }else if($target.is('.cf7-field-inner span.dashicons')){
662 //field will be closed by closeAlluiFields
663 }else if('none'!==$('#wpcf7-form').css('display') && !$target.is('#wpcf7-form')){
664 changeTextarea();
665 }
666 }
667 });
668
669 // capture tab and move to the next field
670 if(cf7grid.ui){
671 $grid.keydown('div.cf7-field-inner', function(event){
672 if(9 !== event.which ){//tab
673 return;
674 }
675 $target = $(event.target);
676 if($target.is('div.cf7-field-inner :input')){
677 $target.closeUIfield();
678 const $next = $target.parent().next('div.cf7-field-inner');
679 if($next.length>0){
680 $next.showUIfield();
681 event.preventDefault(); //stop tab focus on this element.
682 }
683 }
684 });
685
686 }
687 //general inputs into the textareas will trigger form change event
688 $grid.on('input selectionchange propertychange', 'textarea', function(event){
689 const $target = $(event.target);
690 if($target.is('.cf7-field-type textarea')){
691 return false; //form change trigger will happen after this
692 }else if($target.is('textarea')){
693 $target.html($target.val()+'\n'); //ensure changes are capture in the codemirror editor
694 $('#contact-form-editor').trigger('cf7sg-form-change');
695 }
696 });
697 //before grid editor is closed, update the form with the last textarea
698 //event 'cf7grid-tab-finalise' is fired in cf7-grid-codemirror.js file
699 $grid.on('cf7grid-form-finalise', function(){
700 if(cf7grid.ui){
701 $('#wpcf7-form').parent().siblings('textarea.grid-input').on('change', function(){
702 $grid.trigger('cf7grid-form-ready'); //codemirror initialisation
703 });
704 $('textarea.grid-input#wpcf7-form').on('change', function(){ //special case for custom code in cf7ui mode
705 $grid.trigger('cf7grid-form-ready'); //codemirror initialisation
706 });
707 changeTextarea(true);
708 }else{
709 const $txta = $('textarea#wpcf7-form');
710 $txta.html($txta.val()+'\n');
711 $grid.trigger('cf7grid-form-ready'); //codemirror initialisation
712 }
713 });
714
715 //initial construction of grid form
716 buildGridForm();
717 $grid.on('build-grid', function(){
718 if( !buildGridForm() ){
719 $('#form-editor-tabs').tabs('option',{ active:1, disabled:true});
720 }else{
721 const $focus = $('.cf7sgfocus', $grid);
722 if($focus.length>0){
723 const scrollPos = $focus.offset().top - $(window).height()/2 + $focus.height()/2;
724 //console.log(scrollPos);
725 $(window).scrollTop(scrollPos);
726 $focus.removeClass('cf7sgfocus');
727 }
728 }
729
730 });
731 //make columns sortable
732 sortableRows();
733 //make rows sortable
734 $('.columns, #grid-form').sortable({
735 //placeholder: "ui-state-highlight",
736 handle:'.row-controls > .dashicons-move',
737 axis: 'y',
738 //containment:'parent',
739 items: '> .container, > .cf7sg-external-form',
740 helper:'clone'
741 });
742 //grid is ready
743 $wpcf7Editor.trigger('grid-ready');
744 }); //end document ready
745
746 //random id function.
747 function randString(n){
748 if(!n){
749 n = 5;
750 }
751 let text = '';
752 const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
753 for(let i=0; i < n; i++){
754 text += possible.charAt(Math.floor(Math.random() * possible.length));
755 }
756 return text;
757 }
758 //function to close any ui fields
759 function closeAlluiFields(){
760 $('.cf7-field-inner :input:visible').each(function(){
761 $(this).closeUIfield();
762 });
763 }
764 //close controls row/column
765 function closeAllControls(){
766 $('.grid-controls:visible', $grid).each(function(){
767 const $this = $(this);
768 $this.hide();
769 $this.siblings('.dashicons-no-alt').hide();
770 $this.siblings('.dashicons-edit').show();
771 });
772 //close helper popups.
773 $('.column-control+.helper-popup').remove();
774 }
775 //trigger a change on the textarea#wpcf7-form field if its value has changed
776 function changeTextarea(finalise = false){
777 if(cf7grid.ui){
778 const $lastTA = $('#wpcf7-form');
779 if($lastTA.length >0 && wpcf7Value !== $lastTA.val()){
780 wpcf7Value = '';
781 $lastTA.trigger('change');
782 }else if(finalise){
783 $grid.trigger('cf7grid-form-ready'); //codemirror initialisation
784 }
785 }
786 }
787 function sortableRows( $newRow='' ){
788 if($newRow.lenght>0){
789 $('.row', $grid).not($newRow).sortable('destroy');
790 }
791 $('.row', $grid).sortable({
792 //placeholder: "ui-state-highlight",
793 //containment:'.row',
794 handle:'.grid-column > .dashicons-move',
795 connectWith: '.row',
796 helper:'clone',
797 items: '> .columns',
798 receive: function( event, ui ) {
799 //ui.item validate column size relative to new row columns.
800 //ui.sender original row. cnacel if column does not fit in new row.
801 //$targetRow has more than 12 columns then cancel.
802 const $targetRow = $(event.target);//receiving row
803 let row = $targetRow.getRowSize();
804
805 if( row.length > 12){
806 ui.sender.sortable('cancel');
807 const $warning = $('<span class="cf7sg-warning">Not enough space in this row to add column</span>');
808 $targetRow.after($warning);
809 $warning.delay(2000).fadeOut('slow', function(){
810 $(this).remove();
811 });
812 }else{
813 //make sure the row controls is at the end.
814 const control = $targetRow.children('.row-controls').remove();
815 $targetRow.append(control);
816 }
817 }
818 });
819 }
820 /* some function definitions...*/
821 $.fn.closeUIfield = function(){
822 let obj = this;
823 if(!Array.isArray(this)) obj=[this];
824 $.each(obj,function(idx, item){
825 const $this = $(item);
826 if(!$this.is('.cf7-field-inner :input:visible')){
827 return $this;
828 }
829 if($this.parent().is('.cf7-field-type')) changeTextarea();
830 $this.hide().attr('id', '');
831 $this.siblings('.dashicons-no-alt').hide();
832 $this.siblings('.content').show();
833 });
834 return true;
835 }
836 $.fn.showUIfield = function(){
837 const $this = $(this);
838 if(!$this.is('.cf7-field-inner')){
839 return $this;
840 }
841 $this.find('p.content').hide();
842 $this.find('span.dashicons').show();
843 const $input = $(':input', $this).show();
844 $input.focus();
845 if($input.is('textarea')){
846 $('textarea#wpcf7-form').attr('id','');
847 $input.attr('id', 'wpcf7-form');
848 wpcf7Value = $input.val();
849 }else{
850 changeTextarea();
851 }
852 return $this;
853 }
854 $.fn.html2gui = function(html){
855 const $this = $(this);
856 if(typeof html === 'undefined') html ='';
857 if(html.length === 0){
858 //get the fields from the textarea
859 html = $('textarea.grid-input', $this).text();
860 if(html.length === 0){
861 $('textarea.grid-input', $this).hide();
862 return $this;
863 }
864 }
865 let singleField = true;
866 let search = $('<div>').append(html);
867
868 if(seekTemplate && 1==search.children(cssTemplate).length){
869 const lines = html.split(/\r\n|\r|\n/g);
870 search = '';
871 for(let i=0; i<lines.length; i++){
872 search += lines[i].trim();
873 }
874 const match = templateRegex.exec(search);
875 if(null !== match){
876 //populate the fields
877 let $field = $('div.cf7-field-label', $this);
878 $('input', $field).val(match[1]);
879 $('p.content', $field).html(match[1]);
880 $field = $('div.cf7-field-type', $this);
881 const tag = $('textarea', $field).val(match[5]).scanCF7Tag();
882 $('p.content', $field).html(tag);
883 $field = $('div.cf7-field-tip', $this);
884 $('input', $field).val(match[6]);
885 $('p.content', $field).html(match[6]);
886 //hide the textarea
887 $('textarea.grid-input', $this).hide();
888 //reset global regex
889 templateRegex.lastIndex = 0;
890 }else{ //this html does not match our templates
891 $('div.cf7-field-inner', $this).remove();
892 }
893 }else{//this html does not match our templates
894 $('div.cf7-field-inner', $this).remove();
895 }
896 }
897
898 $.fn.scanCF7Tag = function(){
899 let $this = $(this);
900 if(!$this.is('textarea')){
901 return '';
902 }
903 let $parent = $this.parent(), //.cf7-field-type.
904 $helper = $parent.siblings('.php-icon'),
905 $jshelper = $parent.siblings('.js-icon');
906 $helper.each(function(index){
907 if(index>0){
908 $(this).remove();
909 return;
910 }
911 $(this).removeAttr('data-field').removeAttr('data-tag').removeAttr('data-search');
912 });
913 //reset helper.
914 $helper = $parent.siblings('.php-icon');
915 //handle jshleper
916 $jshelper.each(function(index){
917 if(index>0){
918 $(this).remove();
919 return;
920 }
921 $(this).removeAttr('data-field').removeAttr('data-tag').removeAttr('data-search');
922 });
923 //reset jshelper.
924 $jshelper = $parent.siblings('.js-icon');
925
926 let cf7TagRegexp = /\[(.[^\s]*)\s*(.[^\s\]]*)[\s\[]*(.[^\[]*\"source:([^\s]*)\"[\s^\[]*|[.^\[]*(?!\"source:)[^\[]*)\]/img,
927 search = $this.val(),
928 match = cf7TagRegexp.exec(search),
929 label='',
930 isRequired = false,
931 type = [],
932 fields = [],
933 hooks = [],jshooks=[],
934 tag='',
935 isSubmit = false, hasHidden = false,
936 count =0, counth = 0,
937 field = '',
938 stopSearch = false;
939
940 while (match != null && !stopSearch) {
941 count++;
942 label+='['+match[1]+' '+match[2]+']';
943 tag = match[1].replace('*','');
944 field = match[2];
945 let helpers = ['cf7sg-tag-all'], jsHelpers = ['cf7sg-tag-all'];
946 helpers[helpers.length] = 'cf7sg-tag-'+tag;
947 jsHelpers[jsHelpers.length] = 'cf7sg-tag-'+tag;
948 switch(tag){
949 case 'submit':
950 case 'save':
951 tag +='-button';
952 isSubmit = true;
953 break;
954 case 'textarea':
955 if( match[0].search(/\s[0-9]{0,3}x[0-9]{1,3}\s?/ig) <0){
956 let cf7sc = match[0].replace(']',' x5]');
957 cf7sc = search.replace(match[0], cf7sc);
958 $this.val(cf7sc);
959 }
960 break;
961 case 'acceptance': //special case with closing tag.
962 stopSearch = true;
963 break;
964 case 'recaptch':
965 case 'recaptcha': //special case with closing tag.
966 label='[recaptcha]';
967 stopSearch = true;
968 break;
969 case 'dynamic_select':
970 let source ='';
971 switch(true){
972 case ( match.length > 4 && 'undefined' !== typeof match[4] ) : //match[4] exists.
973 source = match[4].split(':');
974 source = source[0];
975 helpers[helpers.length] = 'cf7sg-tag-dynamic_select-'+source;
976 case match.length > 3: //lets deal with match[3]
977 if(0=== source.length){
978 source="filter";
979 switch(true){
980 case match[3].indexOf("source:post")>0:
981 source="post";
982 break;
983 case match[3].indexOf("slug:")>0:
984 source="taxonomy";
985 break;
986 }
987 }
988 helpers[helpers.length] = 'cf7sg-tag-dynamic_select-'+source;
989
990 if(match[3].indexOf('class:tags')>-1){
991 helpers[helpers.length] = 'cf7sg-tag-dynamic_select-tags';
992 if(source.length>0){
993 helpers[helpers.length] = 'cf7sg-tag-dynamic_select-'+source+'-tags';
994 }
995 }
996 break;
997 }
998 break;
999 case 'hidden': /** @since 3.2.1 fix hidden field class */
1000 tag+='-input';
1001 counth++;
1002 break;
1003 }
1004 /** @since 3.3.0 add extension classes */
1005 if(undefined !== cf7sgCustomHelperModule[tag]){
1006 let ch = cf7sgCustomHelperModule[tag](search);
1007 if(Array.isArray(ch.php) && ch.php.length>0) helpers = helpers.concat(ch.php);
1008 if(Array.isArray(ch.js) && ch.js.length>0) jsHelpers = jsHelpers.concat(ch.js);
1009 }
1010 type[type.length] = tag;
1011 fields[fields.length] = field;
1012 hooks[hooks.length] = helpers;
1013 jshooks[jshooks.length] = jsHelpers;
1014 if('*' === match[1][match[1].length -1]){
1015 isRequired = true;
1016 }
1017 if(!stopSearch) match = cf7TagRegexp.exec(search); //get the next match.
1018 }
1019 let classes = $('#grid-col div.cf7-field-type').attr('class');
1020 classes += " "+ type.join(' ');
1021 field = fields.join(' ');
1022 // $parent.removeClass('required');
1023 if(isRequired) classes += ' required';//$parent.addClass('required').
1024 const $parentColumn = $parent.closest('.columns');
1025 if($parentColumn.is('[class*="cf7-tags-"]')){
1026 $parentColumn.removeClass(function (index, className) {
1027 return (className.match (/(^|\s)cf7-tags-\S+/g) || []).join(' ');
1028 });
1029 }
1030 if( (count-counth) >1 ){ /** @since 3.2.1 don't count hidden fields */
1031 classes += ' cf7-tags-'+count;
1032 $parentColumn.addClass('cf7-tags-'+count);
1033 }
1034 $parent.attr('class',classes);
1035 /**@since 2.0.0
1036 * setup fields for tag specific filters/actions.
1037 */
1038 //for each tag get corresponding set of filters.
1039 let helperUsed = false, jsHelperUsed=false,len = type.length, jlen=0;
1040 search = '';
1041 for (let i = 0; i < len; i++) {
1042 for (let j=0, jlen = hooks[i].length; j<jlen; j++){
1043 search += 'li.'+hooks[i][j]+',';
1044 }
1045 search = search.slice(0,-1); //remove last ','
1046 if($( search ,$('#fieldhelperdiv')).length>0){
1047 //this tag has some filters.
1048 if(helperUsed){
1049 const $clone = $helper.clone();
1050 $helper.after($clone);
1051 $helper = $clone;
1052 }
1053 helperUsed = true;
1054 $helper.attr('data-field', fields[i]);
1055 $helper.attr('data-tag', type[i]);
1056 $helper.attr('data-search', search);
1057 $helper.show();
1058 }
1059 //js helpers.
1060 search='', jlen = jshooks[i].length;
1061 for (let j=0; j<jlen; j++){
1062 search += 'li.'+jshooks[i][j]+',';
1063 }
1064 search = search.slice(0,-1); //remove last ','
1065 if($( search ,$('#fieldhelperjs')).length>0){
1066 //this tag has some filters.
1067 if(jsHelperUsed){
1068 const $clone = $jshelper.clone();
1069 $jshelper.after($clone);
1070 $jshelper = $clone;
1071 }
1072 jsHelperUsed = true;
1073 $jshelper.attr('data-field', fields[i]);
1074 $jshelper.attr('data-tag', type[i]);
1075 $jshelper.attr('data-search', search);
1076 $jshelper.show();
1077 }
1078 }
1079 if(isSubmit){
1080 $parent.parent().addClass('submit-field');
1081 }
1082
1083 return label;
1084 }
1085 $.fn.updateGridForm = function(){
1086 const $this = $(this);
1087 if(!$this.is('textarea.grid-input')){
1088 return $this;
1089 }
1090 //label
1091 const $label = $this.siblings('div.cf7-field-label').find(':input');
1092 let label = $label.val();
1093 //field
1094 const field = $this.siblings('div.cf7-field-type').find('textarea.field-entry').val();
1095 let idx = 0;
1096 if(cf7grid.requiredHTML.length>0) idx=label.indexOf(cf7grid.requiredHTML)
1097 if($this.siblings('div.cf7-field-type').is('.required')){
1098 /** @since 2.10.4 fix for custom manual labels, allow replacement with empty span*/
1099 if(idx<0) idx = label.search(/<span>[\w\W]*<\/span>/g);
1100 if(idx<0){
1101 label += cf7grid.requiredHTML;
1102 $label.val(label);//input field.
1103 $label.siblings('p.content').html(label);
1104 }
1105 }else{
1106 if(idx>=0){
1107 label = label.replace(cf7grid.requiredHTML, '');
1108 $label.val(label);//input field.
1109 $label.siblings('p.content').html(label);
1110 }
1111 }
1112 //tip
1113 const tip = $this.siblings('div.cf7-field-tip').find(':input').val(),
1114 $cell = $('<div>').append( cf7grid.preHTML + field + cf7grid.postHTML );
1115 $('label', $cell).html(label);
1116 $('.info-tip', $cell).html(tip);
1117 //update grid input and trigger change to udpate form
1118 if(cf7grid.ui) $this.html($cell.html()+'\n').trigger('change');
1119 else $this.val($cell.html()).trigger('change');
1120 return $this;
1121 };
1122
1123 $.fn.toggleSiblingUIFields = function(){
1124 const $this = $(this);
1125 if(!$this.is('div.cf7-field-inner')){
1126 return $this;
1127 }
1128 $this.siblings('div.cf7-field-inner').each(function(){
1129 const $this = $(this);
1130 $('p.content', $this).show();
1131 $(':input', $this).hide().attr('id','');
1132 $('span.dashicons', $this).hide();
1133 });
1134 }
1135 $.fn.getRowSize = function(){
1136 let size, off, idx, foundSize, classList,total = 0;
1137 const sizes = [0];
1138 $(this).children('.columns').each(function(index){
1139 classList = $(this).attr('class').split(/\s+/);
1140 foundSize = false;
1141 for(idx=0;idx<classList.length; idx++){
1142 size = $.inArray(classList[idx], columnsizes);
1143 off = $.inArray(classList[idx], offsets);
1144 if(size > -1){
1145 foundSize = true;
1146 sizes[index] = size;
1147 total += size + 1;
1148 }
1149 if(off > -1) total+= off+1;
1150 }
1151 if(!foundSize){ //by default a colum which is not set set is treated as 1
1152 sizes[index] = 0;
1153 total += 1;
1154 }
1155 });
1156 return {'length':total, 'cols':sizes};
1157 }
1158 $.fn.getColumnTotalSize = function(){
1159 const $this = $(this);
1160 if(! $this.is('.columns')){
1161 return 0;
1162 }
1163 let off, foundSize, size = 0,total = 0, classList = $this.attr('class').split(/\s+/);
1164 const $sizes = $this.find('.grid-column select.column-size'), $offsets = $this.find('.grid-column select.column-offset');
1165 $offsets.val('');
1166 $sizes.val('one');
1167 foundSize = false;
1168 for(let idx=0;idx<classList.length; idx++){
1169 if(!foundSize){
1170 size = $.inArray(classList[idx], columnsizes);
1171 if(size > -1){
1172 foundSize = true;
1173 total += size + 1;
1174 //reset select
1175 $sizes.val(classList[idx]);
1176 }
1177 }
1178 off = $.inArray(classList[idx], offsets);
1179 if(off > -1){
1180 total += off+1;
1181 $offsets.val(classList[idx]);
1182 }
1183 }
1184 if(!foundSize){ //by default a colum which is not set set is treated as 1
1185 size = 0; //by default a colum which is not set set is treated as 1
1186 total += 1;
1187 }
1188 return {'length':total, 'size':size};
1189 }
1190 //add new rows
1191 $.fn.insertNewRow = function(areaCode){
1192 const $this = $(this);
1193 if(typeof areaCode === 'undefined') areaCode ='';
1194 const $newRow = $( $('#grid-row').html() );
1195 //append the column controls and textarea
1196 $('.columns', $newRow).append( $($('#grid-col').html()) );
1197
1198 switch(true){
1199 case $this.is('.columns'):
1200 case $this.is($grid):
1201 case $this.is('.row'):
1202 $this.append($newRow);
1203 break;
1204 // $this.prepend($newRow);
1205 // break;
1206 case $this.is('.container'):
1207 case $this.is('.cf7sg-external-form'):
1208 $this.after($newRow);
1209 break;
1210 default: //unknown element, maybe an error.
1211 return $this;
1212 }
1213
1214 //is areaCode text or jQuery object?
1215 if(areaCode instanceof jQuery){
1216 $('.columns', $newRow).remove();
1217 $('.row', $newRow).prepend(areaCode);
1218 }else{
1219 //add the code to the textarea
1220 if(cf7grid.ui){
1221 $('textarea.grid-input',$newRow).html(areaCode).hide();//.trigger('change');
1222 $newRow.html2gui(areaCode);
1223 }else{
1224 $('textarea.grid-input',$newRow).val(areaCode);//.trigger('change');
1225 $('div.cf7-field-inner', $newRow).hide();
1226 }
1227 }
1228 //make new row's columns sortable.
1229 sortableRows($newRow);
1230 $newRow.fireGridUpdate('add','row');
1231 return $this;
1232 }
1233 //refresh controls select
1234 $.fn.changeColumnSize = function(oldSize, newSize){
1235 const $this = $(this);
1236 if(oldSize.length > 0) $this.removeClass(oldSize);
1237 $this.addClass(newSize);
1238 $('.column-size option[value="'+newSize+'"]', $this ).prop('selected', true);
1239 }
1240 //$target.closest('.grid-controls').filterColumnControls();
1241 $.fn.filterColumnControls = function(){
1242 const $this = $(this);
1243 if(!$this.is('.grid-controls')){
1244 return $this;
1245 }
1246 //enable all options
1247 $('.column-size option', $this ).prop('disabled', false);
1248 $('.column-offset option', $this ).prop('disabled', false);
1249 const $parentRow = $this.closest('.row'), $parentColumn = $this.closest('.columns');
1250 const row = $parentRow.getRowSize(), col = $parentColumn.getColumnTotalSize();
1251 let idx, start, free = 0;
1252 if(row.length < 12) free = (12 - row.length);
1253 for(idx = start = col.size+1; idx < columnsizes.length; idx++){
1254 if( idx > (free + start - 1) ){
1255 $('.column-size option[value="'+columnsizes[idx]+'"]', $this ).prop('disabled', true);
1256 }
1257 }
1258 for(idx = start = col.length - col.size - 1 ;idx< offsets.length; idx++){
1259 if( idx > (free + start - 1) ){
1260 $('.column-offset option[value="'+offsets[idx]+'"]', $this ).prop('disabled', true);
1261 }
1262 }
1263 return $this;
1264 }
1265 /** @since 3.4.0 fire grid ui update events.*/
1266 $.fn.fireGridUpdate = function(action, element){
1267 let e={
1268 bubbles: true,
1269 cancelable: true,
1270 };
1271 e[action]=element;
1272 $(this).trigger('cf7sg-update',e);
1273 }
1274
1275 })( jQuery );
1276
1277 /** @since 3.3.0 custom helpers */
1278 var cf7sgCustomHelperModule = (function (cch) {
1279 return cch;
1280 }(cf7sgCustomHelperModule || {}));
1281