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

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