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

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