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

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