| 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 |
|