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

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

694 lines 30.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 Javascript to handle Codemirror editor
3 Event 'cf7sg-form-change' fired on #contact-form-editor element when codemirror changes occur
4 @since 3.1.2 introduce instaiated cm editor as attribute in anonymous function.
5 */
6 (function( $, cme, jscme, csscme ) {
7
8 $(document).ready( function(){
9 let $codemirror = $('#cf7-codemirror'),
10 $wpcf7Editor = $('textarea#wpcf7-form-hidden'),
11 $editorTabs = $('#form-editor-tabs'),
12 $optionals= $('#optional-editors'),
13 codemirrorUpdated = false, formFields={},
14 $grid = $('#grid-form'),
15 $topTags =$('#top-tags'), $bottomTags =$('#bottom-tags'),
16 $jsTags = $('#js-tags'),
17 gridTab = '#cf7-editor-grid', //default at load time.
18 $jsCodemirror = $('#cf7-js-codemirror'),
19 $cssCodemirror = $('#cf7-css-codemirror'),
20 $jstext = $('textarea#cf7-form-js'),
21 $csstext = $('textarea#cf7-form-css'),
22 jscmUpdated = false, jsInsertAtLine = false,
23 csscmUpdated = false, cssInsertAtLine = false,
24 $jsThemeRadio = $('.codemirror-theme', $jsCodemirror),
25 $cssThemeRadio = $('.codemirror-theme', $cssCodemirror);
26
27 const $cf7key = $('#post_name');
28 $.fn.beautify = function(cursor){
29 let cm = cme, $this=$(this);
30 if($this.is('#cf7-js-codemirror')) cm = jscme;
31 else if($this.is('#cf7-css-codemirror')) cm = csscme;
32 cm.setSelection({
33 'line':cm.firstLine(),
34 'ch':0,
35 'sticky':null
36 },{
37 'line':cm.lastLine(),
38 'ch':0,
39 'sticky':null
40 },
41 {scroll: false});
42 cm.indentSelection("smart");
43 cm.setCursor(cm.firstLine(),0,{scroll: false});
44 if('undefined' != typeof cursor && cursor.find(false)){
45 const from = cursor.from(), to = cursor.to();
46 cm.setSelection(CodeMirror.Pos(from.line, 0), to);
47 cm.scrollIntoView({from: from, to: CodeMirror.Pos(to.line + 10, 0)});
48 }
49 }
50 //set codemirror editor value;
51 cme.setValue($wpcf7Editor.text());
52 cme.setSize("100%");
53 // cme.setOption('viewportMargin',Infinity);
54 $wpcf7Editor.on('grid-ready', function(){ //------ setup the codemirror editor
55 //codemirror editor
56 CodeMirror.defineMode("shortcode", function(config, parserConfig) {
57 let scOverlay = {
58 token: function(stream, state) {
59 let ch;
60 if (stream.match(/^\[([a-zA-Z0-9_]+)\*?\s?/)) {
61 while ((ch = stream.next()) != null){
62 if (ch == "]" ) {
63 //stream.eat("]");
64 return "shortcode";
65 }
66 }
67 }else if(stream.match(/data-([a-z0-9_]+)/)){
68 while ((ch = stream.next()) != null){
69 if (ch == '=' ) {
70 //stream.eat("]");
71 return "cf7sg-attr";
72 }
73 }
74 }
75 while (stream.next() != null && !stream.match(/^\[([a-zA-Z0-9_]+)\*?\s?/, false) && !stream.match(/data-([a-z0-9_]+)/,false) ) {}
76 return null;
77 }
78 };
79 return CodeMirror.overlayMode(CodeMirror.getMode(config, parserConfig.backdrop || "htmlmixed"), scOverlay);
80 });
81
82 if(cf7sgeditor.mode.length>0) cme.setOption('mode',cf7sgeditor.mode);
83 if(cf7sgeditor.theme.user.length>0) cme.setOption('theme',cf7sgeditor.theme.user);
84 /** @since 4.0.0 manage user theme pref */
85 let $themeRadio = $('.codemirror-theme', $codemirror);
86 if($(':input:checked', $themeRadio).length>0){
87 $themeRadio.on('change',':input',function(e){
88 cme.setOption("theme",cf7sgeditor.theme[e.target.value]);
89 });
90 }else $(':input',$themeRadio).prop('disabled',true);
91 $codemirror.beautify();
92
93 cme.on('changes', function(){
94 codemirrorUpdated = true;
95 const disabled = $('#form-editor-tabs').tabs('option','disabled');
96
97 if(true===disabled){
98 const changes = $('<div>').append(cme.getValue());
99 if(0===changes.children().length || changes.children('.container').length>0){
100 $('#form-editor-tabs').tabs('option',{disabled:false});
101 /**
102 * @since 1.2.3 disable cf7sg styling/js for non-cf7sg forms.
103 */
104 $('#is-cf7sg-form').val('true');
105 }
106 }
107
108 $('#contact-form-editor').trigger('cf7sg-form-change');
109 });
110 //toogle body scroll off/on
111 function disableBodyScroll(){$('body').addClass('disable-scroll')}
112 function enableBodyScroll(){$('body').removeClass('disable-scroll')}
113 //create tabs
114 $editorTabs.tabs({
115 beforeActivate: function (event, ui){
116 enableBodyScroll();
117 //update the codemirror panel
118 if('#cf7-codemirror' == ui.newPanel.selector){
119 //finalise any changes in the grid form editor
120 $grid.on('cf7grid-form-ready', function(){
121 let code = $grid.CF7FormHTML();
122 if($grid.children('.container').length > 0){ //beautify.
123 code = html_beautify(code ,
124 {
125 'indent_size': 2,
126 'wrap_line_length': 0
127 });
128 }
129 cme.setValue(code);
130 // cme.refresh();
131 //reset the codemirror change flag
132 codemirrorUpdated = false;
133 //remove id from textarea
134 $('textarea#wpcf7-form').attr('id', '');
135 //change the wpcf7 textarea
136 $('textarea.codemirror-cf7-update', $codemirror).attr('id', 'wpcf7-form');
137 //setup the form code in the hidden textarea
138 $wpcf7Editor.html(code);
139 });
140 /** @since 2.8.3 clear the codemirror textarea##wpcf7-form */
141 $('textarea.codemirror-cf7-update', $codemirror).val('');
142 $grid.trigger('cf7grid-form-finalise');
143 }else{
144 //remove id from textarea
145 $('textarea#wpcf7-form').attr('id', '');
146 }
147 },
148 activate: function( event, ui ) {
149 gridTab = ui.newPanel.selector;
150 $topTags.show();
151 $bottomTags.show();
152 $jsTags.hide();
153 $optionals.hide();
154 $(window).scrollTop($('#form-panel').offset().top);
155
156 switch(gridTab){
157 case '#cf7-editor-grid': //grid editor.
158 $optionals.show();
159 if(codemirrorUpdated){
160 //update the hidden textarea
161 $wpcf7Editor.text(cme.getValue());
162 //trigger rebuild grid event
163 $grid.trigger('build-grid');
164 }else{ //try to set the focus on the 'cf7sgfocus element'
165 const $focus = $('.cf7sgfocus', $grid);
166 if($focus.length>0){
167 const scrollPos = $focus.offset().top - $(window).height()/2 + $focus.height()/2;
168 //console.log(scrollPos);
169 $(window).scrollTop(scrollPos);
170 $focus.removeClass('cf7sgfocus');
171 }
172 }
173 break;
174 case '#cf7-codemirror': //HTML editor.
175 const cursor = cme.getSearchCursor('cf7sgfocus', CodeMirror.Pos(cme.firstLine(), 0), {caseFold: true, multiline: true});
176
177 $codemirror.beautify(cursor);
178 cme.refresh();
179 break;
180 case '#cf7-js-codemirror': //js editor.
181 $topTags.hide();
182 $bottomTags.hide();
183 $jsTags.show();
184 let $form = $('<div>').html($grid.CF7FormHTML());
185 $('.display-none', $jsTags).removeClass('show-events');
186 if( $('div.container.cf7-sg-table', $form).length > 0){
187 $('#table-events', $jsTags).addClass('show-events');
188 }
189 if( $('.container.cf7sg-collapsible', $form).not('.cf7sg-slider-section > .cf7sg-collapsible').length > 0){
190 $('#collapsible-events', $jsTags).addClass('show-events');
191 }
192 if( $('div.container.cf7-sg-tabs-panel', $form).length > 0){
193 $('#tab-events', $jsTags).addClass('show-events');
194 }
195 if( $('.cf7sg-slider-section', $form).length > 0){
196 $('#slider-events', $jsTags).addClass('show-events');
197 }
198
199 //scan all fields.
200 let cf7TagRegexp = /\[(.[^\s]*)\s*(.[^\s\]]*)[\s\[]*(.[^\[]*\"source:([^\s]*)\"[\s^\[]*|[.^\[]*(?!\"source:)[^\[]*)\]/img;
201 //reset form fields.
202 formFields={};
203 $('.field', $form).each(function(){
204 let $field = $(this), search = $field.text(), match = cf7TagRegexp.exec(search);
205 while(null != match && match.length>2){
206 switch(match[1].replace('*','')){
207 case 'recaptcha':
208 case 'recaptch':
209 case 'acceptance':
210 case 'submit':
211 case 'save':
212 match=null;
213 break;//tags with no fields of interest.
214 default:
215 formFields[match[2]] = match[2];
216 if($field.is('.cf7-sg-tabs .field')) formFields[match[2]] += '_tab';
217 if($field.is('.container.cf7-sg-table .field')) formFields[match[2]] += '_row';
218 match = cf7TagRegexp.exec(search); //search next.
219 break;
220 }
221 }
222 });
223 break;
224 case '#cf7-css-codemirror': //css editor.
225 $topTags.hide();
226 $bottomTags.hide();
227 break;
228 }
229 },
230 create: function(e){
231 // $(window).scrollTop($('#meta-box-main-cf7-editor').offset().top);
232 $('#form-editor-tabs .ui-tabs-panel:not(#cf7-editor-grid)').hover(disableBodyScroll,enableBodyScroll);
233 }
234 });
235 /** @since 4.0 js cm editor */
236 $.fn.createNewCMEditor = function(activate=false){
237 let $this = $(this);
238 $this.each(function(activate){
239 let $this = $(this), ref, $theme, $text, cm, theme, $cm, mode,regex;
240 if(!$this.is('a.button.cf7sg-cmtab')) return $this;
241
242 ref = '#'+$this.next('div.display-none').attr('id');
243 $this.attr('href',ref);
244 switch(ref){
245 case '#cf7-js-codemirror':
246 $theme = $jsThemeRadio;
247 $text = $jstext;
248 cm = jscme;
249 theme = cf7sgeditor.jstheme;
250 $cm = $jsCodemirror;
251 mode={name: "javascript", json: true};
252 $this.text('JS');
253 //enable helper popups.
254 regex = /(?<=\/\*)(.*?)(?=\s?\*\/)/im;
255 $('a.helper', $jsTags).each(function(){
256 let $helper = $(this), text = regex.exec($helper.data('cf72post'));
257 if('undefined' != typeof text){
258 $helper.parent().append('<span style="position:relative"><span class="display-none">'+text[0]+'</span></span>');
259 }
260 });
261 break;
262 case '#cf7-css-codemirror':
263 $theme = $cssThemeRadio;
264 $text = $csstext;
265 cm = csscme;
266 theme = cf7sgeditor.csstheme;
267 $cm = $cssCodemirror;
268 mode = "css";
269 $this.text('CSS');
270 break;
271 }
272 $theme.append('<span class="file">'+$text.data('file')+'</span>');
273 //convert to css editor.
274 $editorTabs.append($this.next('div.display-none').remove());
275 $text.data('form', $cf7key.val());
276 $this = $this.remove().wrap('<li></li>');
277 $editorTabs.children('ul').append($this.closest('li'));
278 //set codemirror editor value;
279 cm.setValue($text.text());
280 cm.setOption("mode", mode);
281 cm.setSize("100%");
282 $cm.on('cf7sg-screen-resize',function(){cm.refresh()});
283 $cm.hover(disableBodyScroll);
284 $cm.removeClass('display-none').beautify();
285
286 if(theme.user.length>0) cm.setOption('theme',theme.user);
287 if($(':input:checked', $theme).length>0){
288 $theme.on('change',':input',function(e){
289 cm.setOption("theme",theme[e.target.value]);
290 });
291 }else $(':input',$theme).prop('disabled',true);
292 $editorTabs.tabs('refresh');
293 // if(activate) $this.delay(300).click();
294 });
295 return $this;
296 }
297 //add requried cm editors.
298 $('a.cf7sg-cmtab.required', $optionals).createNewCMEditor();
299 //else listen for user requirement.
300 $optionals.click('a.cf7sg-cmtab',function(e){ $(e.target).createNewCMEditor(true) });
301
302 jscme.on('changes', function(e, changes){
303 jsInsertAtLine = false;
304 let last = jscme.getLine(changes[changes.length-1].to.line);
305 if('undefined'!= typeof last && ""==last.trim()) jsInsertAtLine = true;
306
307 jscmUpdated = false;
308 if(jscme.getValue().length>0){
309 jscmUpdated = true;
310 $jstext.attr('data-form', $cf7key.val()); //set current form slug.
311 }
312 });
313 csscme.on('changes', function(e, changes){
314 cssInsertAtLine = false;
315 let last = csscme.getLine(changes[changes.length-1].to.line);
316 if(""==last.trim()) cssInsertAtLine = true;
317
318 csscmUpdated = false;
319 if(csscme.getValue().length>0){
320 csscmUpdated = true;
321 $csstext.attr('data-form', $cf7key.val()); //set current form slug.
322 }
323 });
324 $cf7key.on('change',function(e){
325 let oldkey = $jstext.data('form'),
326 newkey = $(this).val(), filepath;
327 if( oldkey.length > 0 && oldkey != $cf7key.val() ){
328 /* update editor js */
329 jscme.setValue( jscme.getValue().replace('#'+oldkey, '#'+$cf7key.val()) );
330 $jstext.attr('data-form', newkey);
331 jscmUpdated = true;
332 }
333 //update the file name.
334 oldkey = $('.file',$jsThemeRadio).text();
335 oldkey = oldkey.substring(oldkey.indexOf('js/')+3, oldkey.indexOf('.js'));
336 $('.file',$jsThemeRadio).text( $jstext.data('file').replace(oldkey, newkey) );
337 filepath = $jstext.data('file');
338 filepath = filepath.substring(filepath.indexOf('>>')+3);
339 $('.prev-file:input', $jsThemeRadio).val(filepath);
340 //css cm update.
341 $('.file',$cssThemeRadio).text( $csstext.data('file').replace(oldkey, newkey) );
342 filepath = $csstext.data('file');
343 filepath = filepath.substring(filepath.indexOf('>>')+3);
344 $('.prev-file:input', $cssThemeRadio).val(filepath);
345
346 oldkey = $csstext.data('form');
347 if( oldkey.length > 0 && oldkey != $cf7key.val() ){
348 /* update editor js */
349 csscme.setValue( csscme.getValue().replace('#'+oldkey, '#'+$cf7key.val()) );
350 $csstext.data('form', newkey);
351 csscmUpdated = true;
352 }
353 });
354 $('#js-tags').on('click','a.helper',function(e){
355 let helper = $(this).data('cf72post').replace('{$cf7_key}', $cf7key.val() ), enableArrayFields=false;
356 if(!$('#cf7sg-jstags-comments').is(':checked')){
357 helper = helper.replace(/^\n?\s*?\/\/.*\n?/gmi,'').replace(/(?<=.*)\n$/,'');;
358 }
359 if($(this).is('.all-fields')){
360 let fieldsText = '\n';
361 $.each(formFields, function(field, fidx){
362 fieldsText += " case '"+field+"': //"+field+" updated";
363 switch(fidx){
364 case field+'_tab':
365 fieldsText +=", tIdx is tab index.\n";
366 enableArrayFields=true;
367 break;
368 case field+'_row':
369 fieldsText +=", rIdx is row index.\n";
370 enableArrayFields=true;
371 break;
372 case field+'_tab_row':
373 fieldsText +=", tIdx is tab index / rIdx is row index.\n";
374 enableArrayFields=true;
375 break;
376 default:
377 fieldsText +=".\n //do something\n";
378 break;
379 }
380 fieldsText +=" break;\n"
381 });
382 arrayFields = '';
383 if(enableArrayFields){
384 arrayFields = "//-----code to extract field name and tab/row index -----------\n";
385 arrayFields += "let search='', tIdx=0, rIdx=0;\n";
386 arrayFields += "if( $field.is('.cf7sgtab-field') || $field.is('.cf7sgrow-field') ){\n";
387 arrayFields += " $.each($field.attr('class').split(/\\s+/), function(idx, clss){\n";
388 arrayFields += " if(0==clss.indexOf('cf7sg-')){\n";
389 arrayFields += " clss = clss.replace('cf7sg-','');\n";
390 arrayFields += " search = new RegExp( '(?<='+clss+')(_tab-(\\\\d))?(_row-(\\\\d))?','gi' ).exec(fieldName);\n";
391 arrayFields += " switch(true){\n";
392 arrayFields += " case /\\d+/.test(search[2]*search[4]): //table within a tab.\n";
393 arrayFields += " tIdx = parseInt(search[2]);\n";
394 arrayFields += " rIdx = parseInt(search[4]);\n";
395 arrayFields += " break;\n";
396 arrayFields += " case /\\d+/.test(search[2]): //tab.\n";
397 arrayFields += " tIdx = parseInt(search[2]);\n";
398 arrayFields += " break;\n";
399 arrayFields += " case /\\d+/.test(search[4]): //row.\n";
400 arrayFields += " rIdx = parseInt(search[4]);\n";
401 arrayFields += " break;\n";
402 arrayFields += " }\n";
403 arrayFields += " fieldName = clss;\n";
404 arrayFields += " return false; //break out of each loop.\n";
405 arrayFields += " }\n });\n";
406 arrayFields += "}\n//------ end of code for field extraction ---------\n";
407 }
408 helper = helper.replace('{$array_field_extraction}', arrayFields);
409 helper = helper.replace('{$list_of_fields}', fieldsText);
410 }
411 let line = jscme.getCursor().line;
412 // if(!jsInsertAtLine) line = 0;
413 switch(line){
414 case 0:
415 let il = jscme.lastLine();
416 if(il>1 && jscme.getLine(il).indexOf('(jQuery)')<0){
417 if(jscme.getLine(il-1).indexOf('(jQuery)')>0) il-=1;
418 }
419 jscme.setCursor({'line':il,'ch':0});
420 helper += "\n";
421 break;
422 default:
423 helper += "\n";
424 break;
425 }
426 jscme.replaceSelection(helper);
427 line = jscme.getCursor().line;
428 $jsCodemirror.beautify();
429 jscme.setCursor({'line':line,'ch':line.length});
430 });
431 /*@since 1.1.1 disable grid editor for existing cf7 forms*/
432 if(0==$grid.children('.container').length){
433 $('#form-editor-tabs').tabs('option',{ active:1, disabled:[0]});
434 /** @since 1.2.3 disable cf7sg styling/js for non-cf7sg forms.*/
435 $('#is-cf7sg-form').val('false');
436 }
437 //update the codemirror when tags are inserted
438 $('form.tag-generator-panel .button.insert-tag').on('click', function(){
439 const $textarea = $('textarea#wpcf7-form');
440 if($textarea.is('.codemirror-cf7-update')){
441 const tag = $textarea.delay(100).val();
442 cme.replaceSelection(tag);
443 $textarea.val(''); //clear.
444 }
445 });
446 }); //-----------end codemirror editor setup
447 $('form#post').submit(function(event) {
448 const $this = $(this);
449 $( window ).off( 'beforeunload' ); //remove event to stop cf7 script from warning on save
450 event.preventDefault(); //this will prevent the default submit
451 //close any open UI fields.
452 $('.cf7-field-inner :input:visible').closeUIfield();
453 let $embdedForms = '',$formNoEmbeds = '', codeMirror ='';
454 if('#cf7-editor-grid' == gridTab){ //set up the code in the cf7 textarea
455 const $txta = $('textarea#wpcf7-form');
456 $txta.html($txta.val()+'\n');
457 codeMirror = html_beautify(
458 $grid.CF7FormHTML(),
459 {
460 'indent_size': 2,
461 'wrap_line_length': 0
462 }
463 );
464 $('textarea#wpcf7-form-hidden').html(codeMirror);
465 $formNoEmbeds = $('<div>').append(codeMirror);
466 }else{//we are in text mode.
467 codeMirror = cme.getValue();
468 $('textarea#wpcf7-form-hidden').html(codeMirror).val(codeMirror);
469 $formNoEmbeds = $('<div>').append(codeMirror);
470 }
471 //since 1.8 remove cf7sgfocus class if present.
472 $('.cf7sgfocus', $formNoEmbeds).removeClass('cf7sgfocus');
473 $embdedForms = $formNoEmbeds.find('.cf7sg-external-form').remove();
474 //setup sub-forms hidden field.
475 const embeds = [];
476 let hasTables = false, hasTabs = false, hasToggles=false;
477 if($embdedForms.length>0){
478 $embdedForms.each(function(){
479 embeds[embeds.length] = $(this).data('form');
480 });
481 }
482 $('#cf7sg-embeded-forms').val(JSON.stringify(embeds));
483 const cf7TagRegexp = /\[(.[^\s]*)\s*(.[^\s]*)(|\s*(.[^\[]*))\]/img;
484 /** @since 3.0.0 determine scripts required */
485 let scriptClass ="";
486 if(codeMirror.indexOf("class:sgv-")>0) scriptClass += "has-validation,";
487 if(codeMirror.indexOf("class:select2")>0) scriptClass += "has-select2,";
488 if(codeMirror.indexOf("class:nice-select")>0) scriptClass += "has-nice-select,";
489 /** @since 4.0 enable grouping of collapsible sections as slider */
490 if($('.cf7sg-collapsible', $formNoEmbeds).not('.cf7sg-slider-section .cf7sg-collapsible').length>0){
491 scriptClass += "has-accordion,";
492 }
493 if($('.cf7sg-slider-section', $formNoEmbeds).length>0) scriptClass += "has-slider,";
494 if(codeMirror.indexOf("[benchmark")>0) scriptClass += "has-benchmark,";
495 if(codeMirror.indexOf("[date")>0 || 0<codeMirror.search(/\[text([^\]]+?)class:datepicker/ig)) scriptClass += "has-date,";
496
497 //scan and submit tabs & tables fields.
498 const tableFields = [];
499 $('.row.cf7-sg-table', $formNoEmbeds).each(function(){
500 /**@since 2.4.2 track each tables with unique ids and their fields*/
501 const unique = $(this).closest('.container.cf7-sg-table').attr('id'),
502 fields = {}, search = $(this).html();
503 fields[unique]=[];
504 let match = cf7TagRegexp.exec(search);
505 //console.log('search:'+search);
506 while (match != null) {
507 //ttFields[ match[2] ] = match[1];
508 fields[unique][fields[unique].length] = match[2];
509 //console.log('match'+match[2]);
510 match = cf7TagRegexp.exec(search); //get the next match.
511 }
512 tableFields[tableFields.length] = fields;
513 hasTables = true;
514 });
515
516 const tabFields = [];
517 $('.container.cf7-sg-tabs-panel', $formNoEmbeds).each(function(){
518 /**@since 2.4.2 track each tables with unique ids and their fields*/
519 const unique = $(this).attr('id'),fields = {}, search = $(this).html();
520 fields[unique]=[];
521
522 let match = cf7TagRegexp.exec(search);
523 while (match != null) {
524 //if( -1 === tableFields.indexOf(match[2]) ) /*removed as now want to idenify fields which are both tabs and table fields*/
525 fields[unique][fields[unique].length] = match[2];
526 //ttFields[match[2]] = match[1];
527 match = cf7TagRegexp.exec(search); //get the next match.
528 }
529 tabFields[tabFields.length] = fields;
530 hasTabs = true;
531 });
532 /**
533 * Track toggled fields to see if they are submitted or not.
534 * @since 2.5 */
535
536 const toggledFields = [], tabbedToggles=[], groupedToggles={};
537 $('.container.cf7sg-collapsible.with-toggle', $formNoEmbeds).each(function(){
538 /**@since 2.4.2 track each tables with unique ids and their fields*/
539 const $toggle = $(this), unique = $toggle.attr('id'), group = $toggle.data('group'),
540 fields = {}, search = $toggle.html();
541 fields[unique]=[];
542 if(group.length>0){
543 if('undefined' == typeof groupedToggles[group] ) groupedToggles[group] = [];
544 groupedToggles[group].push(unique);
545 }
546 let match = cf7TagRegexp.exec(search);
547 while (match != null) {
548 fields[unique].push(match[2]);
549 match = cf7TagRegexp.exec(search); //get the next match.
550 }
551 toggledFields.push(fields);
552 /** @since 4.0.0 differentiate toggles in tabed sections.*/
553 if($toggle.is('.cf7-sg-tabs .cf7sg-collapsible')) tabbedToggles.push(unique);
554 hasToggles = true;
555 });
556 //append hidden fields
557 $this.append('<input type="hidden" name="cf7sg-has-tabs" value="'+hasTabs+'" /> ');
558 $this.append('<input type="hidden" name="cf7sg-has-tables" value="'+hasTables+'" /> ');
559 $this.append('<input type="hidden" name="cf7sg-has-toggles" value="'+hasToggles+'" /> ');
560 const disabled = $('#form-editor-tabs').tabs('option','disabled');
561 $this.append('<input type="hidden" name="cf7sg-has-grid" value="'+disabled+'" /> ');
562 //update script classes since v3.
563 if(hasTabs) scriptClass+="has-tabs,";
564 if(hasTables) scriptClass+="has-table,";
565 if(hasToggles) scriptClass+="has-toggles,";
566 if(!disabled) scriptClass+="has-grid,";
567 $this.append('<input type="hidden" name="cf7sg-script-classes" value="'+scriptClass+'" />');
568
569 $('#cf7sg-tabs-fields').val(JSON.stringify(tabFields));
570 $('#cf7sg-table-fields').val(JSON.stringify(tableFields));
571 $('#cf7sg-toggle-fields').val(JSON.stringify(toggledFields));
572 $('#cf7sg-tabbed-toggles').val(JSON.stringify(tabbedToggles));
573 $('#cf7sg-grouped-toggles').val(JSON.stringify(groupedToggles));
574 /** @since 4.0 enable js/css */
575 $jstext.text('');//empty.
576 codeMirror = jscme.getValue();
577 if(jscmUpdated){
578 if(codeMirror.length>2) $jstext.html(codeMirror);
579 }else if(codeMirror.length>1) $jstext.prop('disabled',true);
580 $csstext.text('');//empty.
581 codeMirror = csscme.getValue();
582 if(csscmUpdated){
583 if(codeMirror.length>2) $csstext.html(csscme.getValue());
584 }else if(codeMirror.length>1) $csstext.prop('disabled',true);
585 // continue the submit unbind preventDefault.
586 $this.unbind('submit').submit();
587 });
588 /*
589 Function to convert the UI form into its html final form for editing in the codemirror and/or saving to the CF7 plugin.
590 */
591 $.fn.CF7FormHTML = function(){
592 const $this = $(this);
593 if( !$this.is('#grid-form') ){
594 return '';
595 }
596 const $form = $('<div>').append( $this.html() );
597 let text='';
598 //remove the external forms
599 const external = {};
600 $('.cf7sg-external-form', $form).each(function(){
601 const $exform = $(this), id = $exform.data('form');
602 external[id] = $exform.children('.cf7sg-external-form-content').remove();
603 $exform.children('.form-controls').remove();
604 });
605 //remove the row controls
606 $('.row', $form).removeClass('ui-sortable').children('.row-controls').remove();
607
608 //remove the collapsible input
609 $('.container.cf7sg-collapsible', $form).each(function(){
610 const $this = $(this),cid = $this.attr('id'), $title = $this.children('.cf7sg-collapsible-title');
611 let text = $title.children('label').children('input[type="hidden"]').val();
612 $title.children('label').remove();
613 let toggle = '';
614 if($this.is('.with-toggle')){
615 toggle=' toggled';
616 }
617 text = '<span class="cf7sg-title'+toggle+'">'+text+'</span>';
618 $title.html(text + $title.html());
619 });
620 //remove tabs inputs
621 $('ul.cf7-sg-tabs-list li label', $form).remove();
622
623 const cf7TagRegexp = /\[(.[^\s]*)\s*(.[^\s]*)(|\s*(.[^\[]*))\]/img,
624 cf7sgToggleRegex = /class:cf7sg-toggle-(.[^\s]+)/i;
625 //remove textarea and embed its content
626 $('.columns', $form).each(function(){
627 const $this = $(this), $gridCol = $this.children('.grid-column'),
628 $text = $('textarea.grid-input', $gridCol);
629 $this.removeClass('ui-sortable');
630 if($text.length>0){
631 let text = $text.text();
632 //verify if this column is within a toggled section.
633 const $toggle = $this.closest('.container.cf7sg-collapsible.with-toggle');
634 if($toggle.length>0){
635 const cid = $toggle.attr('id');
636 /**
637 * track toggled checkbox/radio fields, because they are not submitted when not filled.
638 *@since 2.1.5
639 */
640 const $field = $text.siblings('div.cf7-field-type');
641 let isToggled = false;
642
643 if($field.length>0){
644 if($field.is('.checkbox.required') || $field.is('.radio') || $field.is('.file.required')) isToggled = true;
645 }else isToggled = true; //custom column, needs checking.
646
647 if(isToggled){
648 let search = text, match = cf7TagRegexp.exec(search);
649 while (match != null) {
650 switch(match[1]){
651 case 'checkbox*':
652 case 'radio':
653 case 'file*':
654 let options = '';
655 if(match.length>4){
656 const tglmatch = cf7sgToggleRegex.exec(match[4]);
657 if(tglmatch != null){
658 if(tglmatch[1] == cid) break;
659 options =match[4].replace(tglmatch[0],'class:cf7sg-toggle-'+cid);
660 }else{
661 options = 'class:cf7sg-toggle-'+cid+' '+match[4];
662 }
663 }else{
664 options = 'class:cf7sg-toggle-'+cid;
665 }
666 text = text.replace(match[0], '['+match[1]+' '+match[2]+' '+options+']');
667 //hasRadios = true;
668 break;
669 }
670 //console.log('match'+match[2]);
671 match = cf7TagRegexp.exec(search); //get the next match.
672 }
673 }//end isToggled.
674 }
675 $this.html('\n'+text);
676 }//else this column is a grid.
677 $gridCol.remove();
678 });
679 //reinsert the external forms
680 $('.cf7sg-external-form', $form).each(function(){
681 const $this = $(this);
682 let id = $this.data('form');
683 $this.append( external[id] );
684 });
685 text = $form.html();
686 if($grid.children('.container').length > 0){ //strip tabs/newlines
687 text = text.replace(/^(?:[\t ]*(?:\r?\n|\r))+/gm, "");
688 }
689 return text;
690 }
691 });//dcoument ready end
692
693 })( jQuery, codeMirror_5_32, jsCodeMirror_5_32, cssCodeMirror_5_32);
694