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

415 lines 17.1 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 ) {
7
8 $(document).ready( function(){
9 var $codemirror = $('#cf7-codemirror');
10 var $wpcf7Editor = $('textarea#wpcf7-form-hidden');
11 var codemirrorUpdated = false;
12 var $grid = $('#grid-form');
13 var gridTab = '#cf7-editor-grid'; //default at load time.
14 //set codemirror editor value;
15 cme.setValue($wpcf7Editor.text());
16
17 $wpcf7Editor.on('grid-ready', function(){ //------ setup the codemirror editor
18 //codemirror editor
19 CodeMirror.defineMode("shortcode", function(config, parserConfig) {
20 var cf7Overlay = {
21 token: function(stream, state) {
22 var ch;
23 if (stream.match(/^\[([a-zA-Z0-9_]+)\*?\s?/)) {
24 while ((ch = stream.next()) != null)
25 if (ch == "]" ) {
26 //stream.eat("]");
27 return "shortcode";
28 }
29 }
30 while (stream.next() != null && !stream.match(/^\[([a-zA-Z0-9_]+)\*?\s?/, false)) {}
31 return null;
32 }
33 };
34 return CodeMirror.overlayMode(CodeMirror.getMode(config, parserConfig.backdrop || "htmlmixed"), cf7Overlay);
35 });
36 // var cmConfig =
37 if(cf7sgeditor.mode.length>0) cme.setOption('mode',cf7sgeditor.mode);
38 if(cf7sgeditor.theme.length>0) cme.setOption('theme',cf7sgeditor.theme);
39 // cmEditor = CodeMirror( $codemirror.get(0), cmConfig);
40
41 /* TODO: enable shortcode edit at a future date
42 $('.cm-shortcode',$codemirror).each(function(){
43 $(this).append('<span class="dashicons dashicons-edit"></span>');
44 });
45 $('.dashicons-edit', $codemirror).on('click', function(){
46 alert('shortcode '+ $(this).parent().text());
47 });
48 */
49 $.fn.beautify = function(cursor){
50 cme.setSelection({
51 'line':cme.firstLine(),
52 'ch':0,
53 'sticky':null
54 },{
55 'line':cme.lastLine(),
56 'ch':0,
57 'sticky':null
58 },
59 {scroll: false});
60 cme.indentSelection("smart");
61 cme.setCursor(cme.firstLine(),0);
62 if('undefined' != typeof cursor && cursor.find(false)){
63 var from = cursor.from();
64 var to = cursor.to();
65 cme.setSelection(CodeMirror.Pos(from.line, 0), to);
66 cme.scrollIntoView({from: from, to: CodeMirror.Pos(to.line + 10, 0)});
67 }
68 }
69 $codemirror.beautify();
70
71 //var cur = cme.getCursor();
72 //cme.setCursor(99, cur.ch);
73
74 cme.on('changes', function(){
75 codemirrorUpdated = true;
76 var disabled = $('#form-editor-tabs').tabs('option','disabled');
77
78 if(true===disabled){
79 var changes = $('<div>').append(cme.getValue());
80 if(0===changes.children().length || changes.children('.container').length>0){
81 $('#form-editor-tabs').tabs('option',{disabled:false});
82 /**
83 * @since 1.2.3 disable cf7sg styling/js for non-cf7sg forms.
84 */
85 $('#is-cf7sg-form').val('true');
86 }
87 }
88
89 $('#contact-form-editor').trigger('cf7sg-form-change');
90 });
91
92 //create tabs
93 $('#form-editor-tabs').tabs({
94 beforeActivate: function (event, ui){
95 //update the codemirror panel
96 if('#cf7-codemirror' == ui.newPanel.selector){
97 //finalise any changes in the grid form editor
98 $grid.on('cf7grid-form-ready', function(){
99 var code = $grid.CF7FormHTML();
100 if($grid.children('.container').length > 0){ //beautify.
101 code = html_beautify(code ,
102 {
103 'indent_size': 2,
104 'wrap_line_length': 0
105 });
106 }
107 cme.setValue(code);
108 //reset the codemirror change flag
109 codemirrorUpdated = false;
110 //remove id from textarea
111 $('textarea#wpcf7-form').attr('id', '');
112 //change the wpcf7 textarea
113 $('textarea.codemirror-cf7-update', $codemirror).attr('id', 'wpcf7-form');
114 //setup the form code in the hidden textarea
115 $wpcf7Editor.html(code);
116 });
117 /** @since 2.8.3 clear the codemirror textarea##wpcf7-form */
118 $('textarea.codemirror-cf7-update', $codemirror).val('');
119 $grid.trigger('cf7grid-form-finalise');
120 }else{
121 //remove id from textarea
122 $('textarea#wpcf7-form').attr('id', '');
123 }
124 },
125 activate: function( event, ui ) {
126 gridTab = ui.newPanel.selector;
127 if('#cf7-editor-grid' == ui.newPanel.selector){
128 if(codemirrorUpdated){
129 //update the hidden textarea
130 $wpcf7Editor.text(cme.getValue());
131 //trigger rebuild grid event
132 $grid.trigger('build-grid');
133 }else{ //try to set the focus on the 'cf7sgfocus element'
134 var $focus = $('.cf7sgfocus', $grid);
135 if($focus.length>0){
136 var scrollPos = $focus.offset().top - $(window).height()/2 + $focus.height()/2;
137 //console.log(scrollPos);
138 $(window).scrollTop(scrollPos);
139 $focus.removeClass('cf7sgfocus');
140 }
141 }
142 }else if('#cf7-codemirror' == ui.newPanel.selector){
143 var cursor = cme.getSearchCursor('cf7sgfocus', CodeMirror.Pos(cme.firstLine(), 0), {caseFold: true, multiline: true});
144
145 $codemirror.beautify(cursor);
146
147 if($grid.children('.container').length>0){
148 var scrollPos = $('#form-panel').offset().top;
149 $(window).scrollTop(scrollPos);
150 }
151 }
152 }
153 });
154 /*@since 1.1.1 disable grid editor for existing cf7 forms*/
155 if(0==$grid.children('.container').length){
156 $('#form-editor-tabs').tabs('option',{ active:1, disabled:true});
157 /**
158 * @since 1.2.3 disable cf7sg styling/js for non-cf7sg forms.
159 */
160 $('#is-cf7sg-form').val('false');
161 }
162
163 //update the codemirror when tags are inserted
164 $('form.tag-generator-panel .button.insert-tag').on('click', function(){
165 var $textarea = $('textarea#wpcf7-form');
166 if($textarea.is('.codemirror-cf7-update')){
167 var tag = $textarea.delay(100).val();
168 cme.replaceSelection(tag);
169 //update codemirror.
170 $textarea.val(''); //clear.
171 }
172 });
173 }); //-----------end codemirror editor setup
174
175 $('form#post').submit(function(event) {
176 var $this = $(this);
177 $( window ).off( 'beforeunload' ); //remove event to stop cf7 script from warning on save
178 event.preventDefault(); //this will prevent the default submit
179 var $embdedForms = '';
180 var $formNoEmbeds = '';
181 var codeMirror ='';
182 if('#cf7-editor-grid' == gridTab){ //set up the code in the cf7 textarea
183 var $txta = $('textarea#wpcf7-form');
184 $txta.html($txta.val()+'\n');
185 codeMirror = html_beautify(
186 $grid.CF7FormHTML(),
187 {
188 'indent_size': 2,
189 'wrap_line_length': 0
190 }
191 );
192 $('textarea#wpcf7-form-hidden').html(codeMirror);
193 $formNoEmbeds = $('<div>').append(codeMirror);
194 }else{//we are in text mode.
195 codeMirror = cme.getValue();
196 $('textarea#wpcf7-form-hidden').html(codeMirror).val(codeMirror);
197 $formNoEmbeds = $('<div>').append(codeMirror);
198 }
199 //since 1.8 remove cf7sgfocus class if present.
200 $('.cf7sgfocus', $formNoEmbeds).removeClass('cf7sgfocus');
201 $embdedForms = $formNoEmbeds.find('.cf7sg-external-form').remove();
202 //setup sub-forms hidden field.
203 var embeds = [];
204 var hasTables = false, hasTabs = false, hasToggles=false;
205 if($embdedForms.length>0){
206 $embdedForms.each(function(){
207 embeds[embeds.length] = $(this).data('form');
208 });
209 }
210 $('#cf7sg-embeded-forms').val(JSON.stringify(embeds));
211 var cf7TagRegexp = /\[(.[^\s]*)\s*(.[^\s]*)(|\s*(.[^\[]*))\]/img;
212 /** @since 3.0.0 determine scripts required */
213 var scriptClass ="";
214 if(codeMirror.indexOf("class:sgv-")>0) scriptClass += "has-validation,";
215 if(codeMirror.indexOf("class:select2")>0) scriptClass += "has-select2,";
216 if(codeMirror.indexOf("class:nice-select")>0) scriptClass += "has-nice-select,";
217 if($('.cf7sg-collapsible', $formNoEmbeds).length>0) scriptClass += "has-accordion,";
218 if(codeMirror.indexOf("[benchmark")>0) scriptClass += "has-benchmark,";
219 if(codeMirror.indexOf("[date")>0 || 0<codeMirror.search(/\[text([^\]]+?)class:datepicker/ig)) scriptClass += "has-date,";
220
221 //scan and submit tabs & tables fields.
222 var tableFields = [];
223 $('.row.cf7-sg-table', $formNoEmbeds).each(function(){
224 /**@since 2.4.2 track each tables with unique ids and their fields*/
225 var unique = $(this).closest('.container.cf7-sg-table').attr('id');
226 var fields = {};
227 fields[unique]=[];
228 var search = $(this).html();
229 var match = cf7TagRegexp.exec(search);
230 //console.log('search:'+search);
231 while (match != null) {
232 //ttFields[ match[2] ] = match[1];
233 fields[unique][fields[unique].length] = match[2];
234 //console.log('match'+match[2]);
235 match = cf7TagRegexp.exec(search); //get the next match.
236 }
237 tableFields[tableFields.length] = fields;
238 hasTables = true;
239 });
240 //var cf7TagRegexp = /\[(.[^\s]*)\s*(.[^\s]*)\s*(.[^\[]*)\]/img;
241 var tabFields = [],toggleInTabs=[];
242 $('.container.cf7-sg-tabs-panel', $formNoEmbeds).each(function(){
243 /**@since 2.4.2 track each tables with unique ids and their fields*/
244 $tab = $(this), unique = $tab.attr('id'),fields = {}, search = $tab.html();
245 fields[unique]=[];
246 var match = cf7TagRegexp.exec(search);
247 while (match != null) {
248 //if( -1 === tableFields.indexOf(match[2]) ) /*removed as now want to idenify fields which are both tabs and table fields*/
249 fields[unique][fields[unique].length] = match[2];
250 //ttFields[match[2]] = match[1];
251 match = cf7TagRegexp.exec(search); //get the next match.
252 }
253 tabFields[tabFields.length] = fields;
254 hasTabs = true;
255 /** @since 3.3.5 track toggled sections in tabs */
256 $('.container.cf7sg-collapsible.with-toggle',$tab).each(function(){
257 toggleInTabs[toggleInTabs.length]=$(this).attr('id');
258 });
259 });
260 /**
261 * Track toggled fields to see if they are submitted or not.
262 * @since 2.5 */
263
264 var toggledFields = [];
265 $('.container.cf7sg-collapsible.with-toggle', $formNoEmbeds).each(function(){
266 /**@since 2.4.2 track each tables with unique ids and their fields*/
267 var unique = $(this).attr('id');
268 var fields = {};
269 fields[unique]=[];
270 var search = $(this).html();
271 var match = cf7TagRegexp.exec(search);
272 while (match != null) {
273 //if( -1 === tableFields.indexOf(match[2]) ) /*removed as now want to idenify fields which are both tabs and table fields*/
274 fields[unique][fields[unique].length] = match[2];
275 //ttFields[match[2]] = match[1];
276 match = cf7TagRegexp.exec(search); //get the next match.
277 }
278 toggledFields[toggledFields.length] = fields;
279 hasToggles = true;
280 });
281 //append hidden fields
282 $this.append('<input type="hidden" name="cf7sg-has-tabs" value="'+hasTabs+'" /> ');
283 $this.append('<input type="hidden" name="cf7sg-has-tables" value="'+hasTables+'" /> ');
284 $this.append('<input type="hidden" name="cf7sg-has-toggles" value="'+hasToggles+'" /> ');
285 var disabled = $('#form-editor-tabs').tabs('option','disabled');
286 $this.append('<input type="hidden" name="cf7sg-has-grid" value="'+disabled+'" /> ');
287 /** @since 3.3.5 track toggles in tabs */
288 $this.append('<input type="hidden" name="cf7sg-toggle-in-tabs" id="cf7sg-tggl-tabs" /> ');
289 $('#cf7sg-tggl-tabs',$this).val(JSON.stringify(toggleInTabs));
290 //update script classes since v3.
291 if(hasTabs) scriptClass+="has-tabs,";
292 if(hasTables) scriptClass+="has-table,";
293 if(hasToggles) scriptClass+="has-toggles,";
294 if(!disabled) scriptClass+="has-grid,";
295 $this.append('<input type="hidden" name="cf7sg-script-classes" value="'+scriptClass+'" />');
296
297 $('#cf7sg-tabs-fields').val(JSON.stringify(tabFields));
298 $('#cf7sg-table-fields').val(JSON.stringify(tableFields));
299 $('#cf7sg-toggle-fields').val(JSON.stringify(toggledFields));
300
301 //alert(ttFields);
302 // continue the submit unbind preventDefault.
303 $this.unbind('submit').submit();
304 });
305 /*
306 Function to convert the UI form into its html final form for editing in the codemirror and/or saving to the CF7 plugin.
307 */
308 $.fn.CF7FormHTML = function(){
309 var $this = $(this);
310 if( !$this.is('#grid-form') ){
311 return '';
312 }
313 var $form = $('<div>').append( $this.html() );
314 var text='';
315 //remove the external forms
316 var external = {};
317 $('.cf7sg-external-form', $form).each(function(){
318 var $exform = $(this);
319 var id = $exform.data('form');
320 external[id] = $exform.children('.cf7sg-external-form-content').remove();
321 $exform.children('.form-controls').remove();
322 });
323 //remove the row controls
324 $('.row', $form).removeClass('ui-sortable').children('.row-controls').remove();
325
326 //remove the collapsible input
327 $('.container.cf7sg-collapsible', $form).each(function(){
328 var $this = $(this);
329 var cid = $this.attr('id');
330 var $title = $this.children('.cf7sg-collapsible-title');
331 var text = $title.children('label').children('input[type="hidden"]').val();
332 $title.children('label').remove();
333 var toggle = '';
334 if($this.is('.with-toggle')){
335 toggle=' toggled';
336 }
337 text = '<span class="cf7sg-title'+toggle+'">'+text+'</span>';
338 $title.html(text + $title.html());
339 });
340 //remove tabs inputs
341 $('ul.cf7-sg-tabs-list li label', $form).remove();
342
343 var cf7TagRegexp = /\[(.[^\s]*)\s*(.[^\s]*)(|\s*(.[^\[]*))\]/img;
344 var cf7sgToggleRegex = /class:cf7sg-toggle-(.[^\s]+)/i;
345 //remove textarea and embed its content
346 $('.columns', $form).each(function(){
347 var $this = $(this);
348 $this.removeClass('ui-sortable');
349 var $gridCol = $this.children('.grid-column');
350 var $text = $('textarea.grid-input', $gridCol);
351 if($text.length>0){
352 text = $text.text();
353 //verify if this column is within a toggled section.
354 var $toggle = $this.closest('.container.cf7sg-collapsible.with-toggle');
355 if($toggle.length>0){
356 var cid = $toggle.attr('id');
357 /**
358 * track toggled checkbox/radio fields, because they are not submitted when not filled.
359 *@since 2.1.5
360 */
361 var $field = $text.siblings('div.cf7-field-type');
362 var isToggled = false;
363 if($field.length>0){
364 if($field.is('.checkbox.required') || $field.is('.radio') || $field.is('.file.required')) isToggled = true;
365 }else isToggled = true; //custom column, needs checking.
366 if(isToggled){
367 var search = text;
368 var match = cf7TagRegexp.exec(search);
369 //var hasRadios = false;
370 while (match != null) {
371 switch(match[1]){
372 case 'checkbox*':
373 case 'radio':
374 case 'file*':
375 var options = '';
376 if(match.length>4){
377 var tglmatch = cf7sgToggleRegex.exec(match[4]);
378 if(tglmatch != null){
379 if(tglmatch[1] == cid) break;
380 options =match[4].replace(tglmatch[0],'class:cf7sg-toggle-'+cid);
381 }else{
382 options = 'class:cf7sg-toggle-'+cid+' '+match[4];
383 }
384 }else{
385 options = 'class:cf7sg-toggle-'+cid;
386 }
387 text = text.replace(match[0], '['+match[1]+' '+match[2]+' '+options+']');
388 //hasRadios = true;
389 break;
390 }
391 //console.log('match'+match[2]);
392 match = cf7TagRegexp.exec(search); //get the next match.
393 }
394 }//end isToggled.
395 }
396 $this.html('\n'+text);
397 }//else this column is a grid.
398 $gridCol.remove();
399 });
400 //reinsert the external forms
401 $('.cf7sg-external-form', $form).each(function(){
402 var $this = $(this);
403 var id = $this.data('form');
404 $this.append( external[id] );
405 });
406 text = $form.html();
407 if($grid.children('.container').length > 0){ //strip tabs/newlines
408 text = text.replace(/^(?:[\t ]*(?:\r?\n|\r))+/gm, "");
409 }
410 return text;
411 }
412 });//dcoument ready end
413
414 })( jQuery, codeMirror_5_32);
415