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

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