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

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