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

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