PluginProbe
Smart Grid-Layout Design for Contact Form 7 / 4.0.0
Smart Grid-Layout Design for Contact Form 7 v4.0.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.0.0, at admin/js/cf7-grid-layout-admin.js

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