PluginProbe
Smart Grid-Layout Design for Contact Form 7 / 3.2.0
Smart Grid-Layout Design for Contact Form 7 v3.2.0
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-layout-admin.js

cf7-grid-layout-admin.js in Smart Grid-Layout Design for Contact Form 7 3.2.0, at admin/js/cf7-grid-layout-admin.js

1,129 lines 43.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1
2 /**
3 Javascript to handle grid editor
4 Event 'cf7sg-form-change' fired on #contact-form-editor element when codemirror changes occur
5 */
6 (function( $ ) {
7 var offsets = ['offset-one','offset-two', 'offset-three', 'offset-four', 'offset-five', 'offset-six', 'offset-seven', 'offset-eight', 'offset-nine', 'offset-ten', 'offset-eleven'];
8 var columnsizes = ['one', 'two', 'one-fourth', 'one-third', 'five', 'one-half', 'seven', 'two-thirds', 'nine', 'ten', 'eleven', 'full'];
9 var $wpcf7Editor,$grid,$rowControl = null;
10 //graphics UI template pattern
11 var $pattern = $('<div>').html(cf7grid.preHTML+'\\s*(\\[.*\\s*\\].*\\s*){0,}\\s*'+cf7grid.postHTML);
12 var required = cf7grid.requiredHTML.replace('*', '\\*');
13 // console.log('r:'+required);
14 $pattern.find('label').html('((\\s*.*)('+required+'){1}|(\\s*.*))');
15 $pattern.find('.info-tip').text('(.*\\s*)');
16 //console.log('p:'+$pattern.html());
17 var templateRegex = new RegExp($pattern.html(), 'ig');
18 var seekTemplate = false;
19 var cssTemplate = 'div.field';
20 var $template = $('<div id="cf7sg-dummy">').append(cf7grid.preHTML+cf7grid.postHTML);
21 $template = $template.children();
22 if(1==$template.length && $template.find('label').length>0){
23 seekTemplate = true;
24 cssTemplate = $template.prop('nodeName');
25 if($template.prop('class').length>0){
26 cssTemplate += '.'+$template.attr('class').split(' ').join('.');
27 }
28 }
29 var wpcf7Value = '';
30
31 $(document).ready( function(){
32 //change the form id to mimic cf7 plugin custom admin page.
33 /** @since 2.11.0 full screen button*/
34 var $editor = $('#cf7sg-editor'),
35 bodyWidth = $('#wpbody').width();
36 $editor.css('background-color',$('body').css('background-color'));
37 $('#full-screen-cf7').on('click', function(){
38 $editor.toggleClass('full-screen');
39 $(this).toggleClass('full-screen');
40 if($editor.is('.full-screen')) $editor.width(bodyWidth);
41 else $editor.width('auto');
42 // $oldParent = $editor.parent();
43 // $editor.detach();
44 // $nextParent.prepend($editor);
45 // $nextParent = $oldParent;
46 });
47 $wpcf7Editor = $('textarea#wpcf7-form-hidden');
48 $grid = $('#grid-form');
49 $rowControl = $('#top-grid-controls');
50
51 /*
52 Build grid from existing form------------------------- BUILD UI FORM
53 */
54 function buildGridForm(){
55 var formhtml = $wpcf7Editor.text();
56 if(0===formhtml.length){
57 formhtml = '<div class="container"><div class="row"><div class="columns full"></div></div></div>';
58 }
59 var $form = $('<div>').append( formhtml );
60 var isGrid = true; //return value.
61 $grid.html(''); //empty the grid.
62 if(0===$form.children('.container').length){
63 isGrid = false;
64 }
65 //remove the external forms
66 $('.cf7sg-external-form .cf7sg-external-form-content', $form).remove();
67 //replace columns content with textareas
68 /*--------------------------------------------------- convert columns */
69 $('div.columns', $form).each(function(){
70 var $this = $(this);
71 var $area = $($('#grid-col').html());
72 if($this.children().is('.container')){
73 $('textarea.grid-input', $area).remove();
74 $('div.cf7-field-inner', $area).remove();
75 }else{
76 if(cf7grid.ui) $('textarea.grid-input', $area).html($this.html().trim());
77 else $('textarea.grid-input', $area).val($this.html().trim());
78
79 $this.children().remove();
80 $this.text('');
81 }
82 $this.prepend($area);
83 });
84 $('div.row', $form).each(function(){
85 $(this).append( $('#grid-row .row-controls').clone() );
86 });
87 /*--------------------------------------------------- convert collapsible sections */
88 $('div.container.cf7sg-collapsible', $form).each(function(){
89 var $this = $(this);
90 var id = $this.attr('id');
91 if(typeof id == 'undefined'){
92 id = randString(6);
93 $this.attr('id', id); //assign a random id
94 }
95 var text = $this.children('.cf7sg-collapsible-title span.cf7sg-title').text();
96 if(0==text.length){ //pre v1.8 title?.
97 text = $this.children('.cf7sg-collapsible-title').text();
98 }
99 var $toggle = $('.toggle', $this.children('.cf7sg-collapsible-title'));
100 if($toggle.length>0){
101 $toggle = $toggle.clone();
102 }
103
104 $this.children('.cf7sg-collapsible-title').remove();
105 $this.prepend( $('#grid-collapsible').html());
106 $('input', $this.children('.cf7sg-collapsible-title')).not('[type="checkbox"]').val(text);
107 if($toggle.length>0){
108 $this.children('.cf7sg-collapsible-title').append($toggle);
109 $('input[type="checkbox"]', $this.children('.cf7sg-collapsible-title') ).prop('checked', true);
110 }
111 var $ctrl = $this.children('.row').children('.row-controls').find('.collapsible-row-label');
112 $('input', $ctrl).prop('checked', true);
113 //toggle disable the sibling input
114 $('input', $ctrl.siblings('.unique-mod')).prop('disabled', function(i,v){return !v;});
115 });
116 /*--------------------------------------------------- convert tables */
117 $('div.container.cf7-sg-table', $form).each(function(){
118 var $this = $(this);
119 var id = $this.attr('id');
120 if(typeof id == 'undefined'){
121 id = 'cf7-sg-table-'+(new Date).getTime();
122 $this.attr('id', id);
123 }
124 var $ctrl = $this.find('.row.cf7-sg-table > .row-controls' ).first().find('.table-row-label');
125 $('input', $ctrl).prop('checked', true);
126 //set button label
127 var text = $this.data('button');
128 if(typeof text == 'undefined'){
129 text = 'Add Row';
130 $this.attr('data-button',text);
131 }
132 $ctrl.next('.table-row-button').children('input').val(text);
133 //toggle disable the sibling input
134 $('input', $ctrl.siblings('.unique-mod')).prop('disabled', function(i,v){return !v;});
135 //toggle footer row
136 var $footer = $this.next();
137 if($footer.is('.cf7-sg-table-footer')){
138 $ctrl = $footer.children('.row').first().find('.row-controls .footer-row-label');
139 $('input.footer-row', $ctrl).prop('checked', true);
140 $('input', $ctrl.siblings('.unique-mod')).prop('disabled', function(i,v){return !v;});
141 }
142 });
143 //tabs
144 /*--------------------------------------------------- convert tabs */
145 $('ul.cf7-sg-tabs-list li', $form).each(function(){
146 var $this = $(this);
147 var text = $this.children('a').text();
148 $this.append($('#grid-tabs ul li label').clone());
149 $('label input', $this).val(text);
150 //setup checkbox
151 var $ctrl = $this.parent().siblings('.cf7-sg-tabs-panel');
152 $ctrl = $ctrl.children('.row').find('.row-controls' ).first().find('.tabs-row-label');
153 $('input.tabs-row', $ctrl).prop('checked', true);
154 $('input', $ctrl.siblings('.unique-mod')).prop('disabled', function(i,v){return !v;});
155 });
156 //reinsert the external forms
157 $('.cf7sg-external-form', $form).each(function(){
158 var $extform = $(this);
159 $extform.append($( $('#grid-cf7-forms .cf7sg-external-form').html() ) );
160 var id = $extform.data('form');
161 if($('#grid-cf7-forms .form-select option[value="'+id+'"]' ).length > 0 ){
162 //add controls
163 //$extform.append($('#grid-cf7-forms .form-controls').clone());
164 $('.form-controls .form-select', $extform).val(id);
165 //check for form update.
166 var data = {
167 'action' : 'get_cf7_content',
168 'id': $('#post_ID').val(),
169 'nonce' : $('#_wpcf7nonce').val(),
170 'cf7_key' : id,
171 'update' :true
172 };
173 $.post(ajaxurl, data, function(response) {
174 if(response.length > 0){
175 $('.cf7sg-external-form-content', $extform).attr('id','cf7sg-form-'+id).append( response );
176 }//TODO if error insert a msg.
177 });
178
179 }
180 });
181 //add the form to the grid
182 if($form.children('.container').length >0 || $form.children('.cf7sg-external-form').length>0){
183 $grid.append($form.children());
184 }else{ //this is not a cf7sg form.
185 $grid.html($form.html());
186 }
187 //set the value of each textarea as inner text
188 $('textarea', $grid).each(function(){
189 var $this = $(this);
190 $this.html($this.val());
191 });
192 /*--------------------------------------------------- if ui mode, then convert to gui template */
193 var $textareaSelected='';
194 if(cf7grid.ui){
195 $('div.columns', $grid).each(function(){
196 var $this = $(this);
197 if($this.children().is('.container')) return true;
198 $this.html2gui();
199 });
200 }else{
201 //set the first textarea as our default tag consumer
202 $('textarea#wpcf7-form').attr('id','');
203 $textareaSelected = $('textarea', $grid).first();
204 $textareaSelected.attr('id', 'wpcf7-form');
205 }
206 //change this to whichever is live
207 $('textarea', $grid).on('focus', function(){
208 var $this = $(this);
209 if($textareaSelected.length>0 && $textareaSelected.is('#wpcf7-form')){
210 $textareaSelected.attr('id','');
211 $textareaSelected.html($textareaSelected.val()); //set its inner html
212 }
213 if($this.is('.grid-input')){
214 $('textarea#wpcf7-form').attr('id','');
215 $textareaSelected = $this.attr('id','wpcf7-form');
216 }
217 });
218 return isGrid;
219 } //end buildGridForm()
220
221 //offset/size change using event delegation
222 /*---------------------------------------------------------------------------- ui menus */
223 $grid.on('change', function(event){
224 var $target = $(event.target);
225 if($target.is('.column-setting')){ //----------- column size/offset settings
226 var validation = ['dummy'];
227 if( $target.is('.column-offset') ){
228 validation = offsets;
229 }else if( $target.is('.column-size') ){
230 validation = columnsizes;
231 }else{
232 return false;
233 }
234 var $column = $target.closest('.columns');
235 var classList = $column.attr('class').split(/\s+/);
236 var idx;
237 for(idx=0; idx<classList.length; idx++){
238 if($.inArray(classList[idx], validation) > -1){
239 $column.removeClass(classList[idx]);
240 }
241 }
242 $column.addClass($target.val());
243 //filter the options
244 $target.closest('.grid-controls').filterColumnControls();
245 }else if($target.is('.form-select')){ //-------------- external form selection
246 var $container = $target.closest('.cf7sg-external-form');
247 $container.attr('data-form', $target.val());
248 var data = {
249 'action' : 'get_cf7_content',
250 'id': $('#post_ID').val(),
251 'nonce' : $('#_wpcf7nonce').val(),
252 'cf7_key' : $target.val()
253 };
254 $.post(ajaxurl, data, function(response) {
255 $('.cf7sg-external-form-content', $container).attr('id','cf7sg-form-'+$target.val()).html(response);
256 });
257 }
258 /*
259 Collapsible / tabs rows input changes
260 */
261 if($target.is('.cf7sg-collapsible-title label input[type="text"]')){ //------- Collapsible title
262 $target.siblings('input[type="hidden"]').val($target.val());
263 }else if( $target.is('.cf7sg-collapsible-title label input[type="checkbox"]')){ //------- Collapsible title toggled
264 var $title = $target.closest('.cf7sg-collapsible-title');
265 if($target.is(':checked')){
266 $title.append($('#grid-collapsible-with-toggle').html());
267 $title.closest('.container.cf7sg-collapsible').addClass('with-toggle').attr('data-group','');
268 }else{
269 $('.toggle', $title).remove();
270 $title.closest('.container.cf7sg-collapsible').removeClass('with-toggle').removeAttr( 'data-group');
271 }
272 }else if($target.is('ul.cf7-sg-tabs-list li label input[type="text"]')){ //------- Tabs title
273 $target.parent().siblings('a').text($target.val());
274 }else if($target.is('label.table-row-button input')){
275 $target.closest('.container.cf7-sg-table').attr('data-button',$target.val());
276 }
277 if(cf7grid.ui){
278 if($target.is('.cf7-field-inner textarea')){
279 var label = $target.scanCF7Tag();
280 $target.siblings('p.content').html(label);//.show();
281 $target.parent().siblings('textarea.grid-input').updateGridForm();
282 }else if($target.is('.cf7-field-inner input')){
283 $target.siblings('p.content').html($target.val());
284 $target.parent().siblings('textarea.grid-input').updateGridForm();
285 }
286 }
287 });
288
289 //grid click event delegation
290 $grid.on('click', function(event){
291 var $target = $(event.target);
292 switch(true){
293 case $target.is('input[type="text"]:visible'):
294 case $target.is('textarea:visible'): //click on a field.
295 case $target.is('select:visible'):
296 return true;
297 break;
298 }
299 //close any open row/column controls
300 closeAllControls();
301
302 /*
303 Row controls
304 ----------------------------------------------------------ROW CONTRLS
305 */
306 var $parentRow;
307 if($target.is('.dashicons-trash.form-control')){ //--------TRASH included form
308 $target.closest('.cf7sg-external-form').remove();
309 }else if($target.is('.dashicons-plus.form-control') ){ //---ADD external form
310 $target.closest('.cf7sg-external-form').insertNewRow();
311 }else if($target.is('.dashicons-trash.row-control')){ //--------TRASH
312 var $parentContainer = $target.closest('.container');
313 var $parent = $parentContainer.parent();
314 $parentContainer.remove();
315 if( $parent.is('.columns') ) { //verify is this is the last row being deleted
316 if( 0 == $parent.children('.container').length ){
317 //add a text area to the column
318 $parent.children('.grid-column').append('<textarea class="grid-input"></textarea>');
319 }
320 }
321 }else if($target.is('.dashicons-plus.row-control')){ //-----------ADD Row
322 $target.closest('.container').insertNewRow();
323 }else if($target.is('.dashicons-edit.row-control')){ //-----------Show controls
324 //hide any other controls that might be open
325 //taken care by closeAllControls
326 // $('.grid-controls', $grid).hide();
327 // $('.dashicons-no-alt', $grid).hide();
328 // $('.dashicons-edit', $grid).show();
329 //now show this control
330 $target.siblings('.grid-controls').show();
331 $target.hide();
332 $target.siblings('.dashicons-no-alt').show();
333 /*
334 TODO: use $('.grid-controls')filterColumnControls() to make sure columns sizes/offsets are correct.
335 possibly introduce a boolean to check if filter has been run already on this row
336 */
337 }else if( $target.is('.dashicons-no-alt.row-control') ) { //----------------hide controls
338 //take care by closeAllControls
339 // $target.siblings('.grid-controls').hide();
340 // $target.hide();
341 // $target.siblings('.dashicons-edit').show();
342 }else if($target.is('input.collapsible-row')){ //-------------checkbox collapsible row
343 var $container = $target.closest('.container');
344 if($target.is(':checked')){
345 $container.addClass('cf7sg-collapsible');
346 var id = $container.attr('id');
347 if(typeof id == 'undefined'){
348 id = randString(6);
349 $container.attr('id', id); //assign a random id
350 }
351 $container.prepend($('#grid-collapsible').html());
352 }else{
353 $container.removeClass('cf7sg-collapsible');
354 $container.children('.cf7sg-collapsible-title').remove();
355 }
356 //toggle disable the sibling input
357 $target.parent().siblings('label.unique-mod').children('input').prop('disabled', function(i,v){return !v;});
358 }else if($target.is('input.table-row')){ //-------------checkbox table row
359 if($target.is(':checked')){
360 var id = 'cf7-sg-table-'+(new Date).getTime();
361 $target.closest('.row').addClass('cf7-sg-table');
362 $target.closest('.container').addClass('cf7-sg-table').attr('id',id);
363 }else{
364 $target.closest('.row').removeClass('cf7-sg-table');
365 $target.closest('.container').removeClass('cf7-sg-table').removeAttr('id');
366 }
367 //toggle disable the sibling input
368 $target.parent().siblings('label.unique-mod').children('input').prop('disabled', function(i,v){return !v;});
369 }else if($target.is('input.tabs-row')){ //-------------checkbox tabbed row
370 var $panel = $target.closest('.container');
371 if($target.is(':checked')){
372 var id = 'cf7-sg-tab-'+(new Date).getTime();
373 $panel.addClass('cf7-sg-tabs-panel').attr('id',id);
374 $panel.before($('#grid-tabs').html());
375 $panel.closest('.columns').addClass('cf7-sg-tabs');
376 $('li a', $panel.siblings('ul.cf7-sg-tabs-list')).attr('href','#'+id);
377 }else{
378 $panel.removeClass('cf7-sg-tabs-panel');
379 $panel.closest('.columns').removeClass('cf7-sg-tabs');
380 $panel.siblings('ul.cf7-sg-tabs-list').remove();
381 }
382 //toggle disable the sibling input
383 $target.parent().siblings('label.unique-mod').children('input').prop('disabled', function(i,v){return !v;});
384 }else if($target.is('input.footer-row')){ //-------------checkbox footer row
385 var $table = $target.closest('.container').prev();
386 if($table.is('.container.cf7-sg-table')){
387 if($target.is(':checked')){
388 $target.closest('.container').addClass('cf7-sg-table-footer');
389 }else{
390 $target.closest('.container').removeClass('cf7-sg-table-footer');
391 }
392 //toggle disable the sibling input
393 $target.parent().siblings('label.unique-mod').children('input').prop('disabled', function(i,v){return !v;});
394 }
395 }
396
397
398 /*
399 Column controls, show/hide contols, add column, and refresh select dropdowns for colum size on addition
400 */
401
402 var $parentColumn ;
403 if( $target.is('.columns')){
404 $parentColumn = $target;
405 }else{
406 $parentColumn = $target.closest('.columns');
407 }
408 //let's close any column controls : taken care by closeAllControls
409 // if(0===$target.closest('.grid-controls').length ){
410 // $('.grid-column .grid-controls', $grid).hide();
411 // $('.grid-column .column-control.dashicons-no-alt', $grid).hide();
412 // $('.grid-column .column-control.dashicons-edit', $grid).show();
413 // //close any ui fields if any
414 // if(cf7grid.ui && !$target.is('.cf7-field-inner *')){
415 // $('.grid-column .cf7-field-inner span.dashicons').trigger('click');
416 // }
417 // }
418 //verify which target was clicked
419 if( $target.is('.dashicons-edit.column-control') ){ //------------------show controls
420 //now show this control
421 $target.siblings('.grid-controls').show().filterColumnControls();
422 $target.hide();
423 $target.siblings('.dashicons-no-alt').show();
424 }else if( $target.is('.dashicons-controls-repeat.column-control') ) { //--------show hooks
425 var $helper =$('<div class="helper-popup">').html( $('#grid-helper').html());
426 $target.after($helper);
427 var $copy = $('.copy-helper', $helper);
428 var field = $target.data('field');
429 var tag = $target.data('tag');
430 var search = $target.data('search');
431 var $hooks = $(search, '#fieldhelperdiv').clone();
432 $('.cf7sg-helper-list', $helper).append($hooks);
433 $('a.helper', $helper).each(function(){
434 new Clipboard($(this)[0], {
435 text: function(trigger) {
436 var $target = $(trigger);
437 var text = $target.data('cf72post');
438 //get post slug
439 var key = $('#post_name').val();
440 text = text.replace(/\{\$form_key\}/gi, key);
441 text = text.replace(/\{\$field_name\}/gi, field);
442 text = text.replace(/\{\$field_name_slug\}/gi, field.replace('-','_'));
443 text = text.replace(/\{\$field_type\}/gi, tag);
444 text = text.replace(/\[dqt\]/gi, '"');
445 return text;
446 }
447 });
448 $(this).append($copy.clone());
449 });
450 $helper.click('a.helper, .dashicons-no-alt', function(e){
451 $(this).remove();
452 });
453 }else if($target.is('.icon-code.column-control') ){
454 var $focus = $target.closest('.columns');
455 //toggle cf7sgfocus class on inner field to focus on.
456 if($focus.is('.cf7sgfocus')){
457 $focus.removeClass('cf7sgfocus');
458 }else{
459 $('.cf7sgfocus', $grid).removeClass('cf7sgfocus');
460 $focus.addClass('cf7sgfocus');
461 }
462 //move to text editor.
463 $('#form-editor-tabs').tabs('option',{ active:1});
464 }else if($target.is('.dashicons-trash.column-control') ){ //-------------------delete column
465
466 $parentColumn.remove();
467 //refilter
468 //$target.siblings('.grid-controls').filterColumnControls();
469 }else if( $target.is('.make-grid') ){ //--------------------add row/convert column to grid
470
471 //close the grid-control box
472 $target.parent().hide();
473 $target.parent().siblings('.dashicons-no-alt').hide();
474 $target.parent().siblings('.dashicons-edit').show();
475 //convert to grid
476 var $parentColumn = $target.closest('.columns');
477 if($parentColumn.length > 0){
478 //column already has a row?
479 var text = '';
480 if(0 == $parentColumn.children('.container').length){
481 //keep the textarea and remove from the column
482 if(cf7grid.ui){
483 text = $('textarea.grid-input', $parentColumn).remove().text();
484 $('div.cf7-field-inner', $parentColumn).remove();
485 }else{
486 text = $('textarea.grid-input', $parentColumn).remove().val();
487 }
488 }else{
489 text = $parentColumn.children('.container').remove();
490 }
491 $parentColumn.insertNewRow(text);
492 }else{ //add to the main container
493 $grid.insertNewRow();
494 }
495 }else if($target.is('.external-form')){ //---------------- insert cf7 form
496 //close the grid-control box
497 $target.parent().hide();
498 $target.parent().siblings('.dashicons-no-alt').hide();
499 $target.parent().siblings('.dashicons-edit').show();
500 //replace container with form selector
501 $target.closest('.container').after($('#grid-cf7-forms').html());
502 $target.closest('.container').remove();
503 }else if( $target.is('.dashicons-plus.column-control') ){ //--------------------add column
504 var $parentColumn = $target.closest('.columns');
505 var $parentRow = $parentColumn.closest('.row');
506 var classList, idx , columns, row;
507 var newSize=0;
508 var sizes = [];
509 var $newColumn = $('<div class="columns"></div>');
510 var createColumn = true;
511 //is the row filled up?
512 var total = 0;
513 //first check if the current column fills the entire row
514 if( $parentColumn.is('.full') ){
515 total = 12;
516 columns = 1;
517 sizes[0] = columnsizes.length - 1; //ie 11, the last value
518 }else{
519 row = $parentRow.getRowSize();
520 total = row.length;
521 sizes = row.cols;
522 columns = sizes.length;
523 }
524 if(12 == total) {
525 newSize = Math.floor( total/(columns + 1) ) - 1 ;
526 if(newSize < 0 ){ //max columns reached
527 /*TODO: display an error message and return */
528 return false;
529 }
530 createColumn = false;
531 var newClass = columnsizes[newSize];
532 $parentRow.children('.columns').each(function(index){
533 //make sure the column is not size 1
534 if( sizes[index] > 0 ){
535 $(this).changeColumnSize(columnsizes[sizes[index]], newClass );
536 createColumn = true;
537 }
538 });
539 if(!createColumn){ //not enough space to create extra column
540 /*TODO: display an error message and return */
541 return false;
542 }
543 }else if(total < 12){ //just add the new column as size 1
544 if( (12 - total) < total){
545 newSize = 12 - total - 1;
546 }else{
547 newSize = total - 1;
548 }
549 }else{ //should never reach here
550 return false;
551 }
552 //add the new column
553 $newColumn.append( $( $('#grid-col').html() ) );
554 if(cf7grid.ui){
555 $('textarea.grid-input' ,$newColumn).hide();
556 }else{
557 $('div.cf7-field-inner', $newColumn).hide();
558 }
559 $newColumn.changeColumnSize('',columnsizes[newSize]);
560 $parentColumn.after($newColumn);
561 }
562 /*
563 Column UI fields
564 */
565 if(cf7grid.ui){
566 //close any open ui fields
567 closeAlluiFields();
568 if($target.is('.cf7-field-inner p.content')){
569 $target.parent().showUIfield();
570 }else if($target.is('.cf7-field-inner span.dashicons')){
571 //field will be closed by closeAlluiFields
572 }else if('none'!==$('#wpcf7-form').css('display') && !$target.is('#wpcf7-form')){
573 changeTextarea();
574 }
575 }
576 });
577
578 // capture tab and move to the next field
579 if(cf7grid.ui){
580 $grid.keydown('div.cf7-field-inner', function(event){
581 if(9 !== event.which ){//tab
582 return;
583 }
584 $target = $(event.target);
585 if($target.is('div.cf7-field-inner :input')){
586 $target.closeUIfield();
587 var $next = $target.parent().next('div.cf7-field-inner');
588 if($next.length>0){
589 $next.showUIfield();
590 event.preventDefault(); //stop tab focus on this element.
591 }
592 }
593 });
594
595 }
596 //general inputs into the textareas will trigger form change event
597 $grid.on('input selectionchange propertychange', 'textarea', function(event){
598 var $target = $(event.target);
599 if($target.is('.cf7-field-type textarea')){
600 return false; //form change trigger will happen after this
601 }else if($target.is('textarea')){
602 $target.html($target.val()+'\n'); //ensure changes are capture in the codemirror editor
603 $('#contact-form-editor').trigger('cf7sg-form-change');
604 }
605 });
606 //before grid editor is closed, update the form with the last textarea
607 //event 'cf7grid-tab-finalise' is fired in cf7-grid-codemirror.js file
608 $grid.on('cf7grid-form-finalise', function(){
609 if(cf7grid.ui){
610 $('#wpcf7-form').parent().siblings('textarea.grid-input').on('change', function(){
611 $grid.trigger('cf7grid-form-ready'); //codemirror initialisation
612 });
613 $('textarea.grid-input#wpcf7-form').on('change', function(){ //special case for custom code in cf7ui mode
614 $grid.trigger('cf7grid-form-ready'); //codemirror initialisation
615 });
616 changeTextarea(true);
617 }else{
618 var $txta = $('textarea#wpcf7-form');
619 $txta.html($txta.val()+'\n');
620 $grid.trigger('cf7grid-form-ready'); //codemirror initialisation
621 }
622 });
623
624 //initial construction of grid form
625 buildGridForm();
626 $grid.on('build-grid', function(){
627 if( !buildGridForm() ){
628 $('#form-editor-tabs').tabs('option',{ active:1, disabled:true});
629 }else{
630 var $focus = $('.cf7sgfocus', $grid);
631 if($focus.length>0){
632 var scrollPos = $focus.offset().top - $(window).height()/2 + $focus.height()/2;
633 //console.log(scrollPos);
634 $(window).scrollTop(scrollPos);
635 $focus.removeClass('cf7sgfocus');
636 }
637 }
638
639 });
640 //make columns sortable
641 sortableRows();
642 //make rows sortable
643 $('.columns, #grid-form').sortable({
644 //placeholder: "ui-state-highlight",
645 handle:'.row-controls > .dashicons-move',
646 axis: 'y',
647 //containment:'parent',
648 items: '> .container, > .cf7sg-external-form',
649 helper:'clone'
650 });
651 //grid is ready
652 $wpcf7Editor.trigger('grid-ready');
653 }); //end document ready
654
655 //random id function.
656 function randString(n){
657 if(!n){
658 n = 5;
659 }
660 var text = '';
661 var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
662 for(var i=0; i < n; i++){
663 text += possible.charAt(Math.floor(Math.random() * possible.length));
664 }
665 return text;
666 }
667 //function to close any ui fields
668 function closeAlluiFields(){
669 $('.cf7-field-inner :input:visible').each(function(){
670 $(this).closeUIfield();
671 });
672 }
673 //close controls row/column
674 function closeAllControls(){
675 $('.grid-controls:visible', $grid).each(function(){
676 var $this = $(this);
677 $this.hide();
678 $this.siblings('.dashicons-no-alt').hide();
679 $this.siblings('.dashicons-edit').show();
680 });
681 //close helper popups.
682 $('.dashicons-controls-repeat.column-control+.helper-popup').remove();
683 }
684 //trigger a change on the textarea#wpcf7-form field if its value has changed
685 function changeTextarea(finalise = false){
686 if(cf7grid.ui){
687 var $lastTA = $('#wpcf7-form');
688 if($lastTA.length >0 && wpcf7Value !== $lastTA.val()){
689 wpcf7Value = '';
690 $lastTA.trigger('change');
691 }else if(finalise){
692 $grid.trigger('cf7grid-form-ready'); //codemirror initialisation
693 }
694 }
695 }
696 function sortableRows( $newRow='' ){
697 if($newRow.lenght>0){
698 $('.row', $grid).not($newRow).sortable('destroy');
699 }
700 $('.row', $grid).sortable({
701 //placeholder: "ui-state-highlight",
702 //containment:'.row',
703 handle:'.grid-column > .dashicons-move',
704 connectWith: '.row',
705 helper:'clone',
706 items: '> .columns',
707 receive: function( event, ui ) {
708 //ui.item validate column size relative to new row columns.
709 //ui.sender original row. cnacel if column does not fit in new row.
710 //$targetRow has more than 12 columns then cancel.
711 var $targetRow = $(event.target);//receiving row
712 var row = $targetRow.getRowSize();
713 //var total = row.length;
714 //var sizes = row.cols;
715 //var columns = sizes.length;
716 if( row.length > 12){
717 ui.sender.sortable('cancel');
718 var $warning = $('<span class="cf7sg-warning">Not enough space in this row to add column</span>');
719 $targetRow.after($warning);
720 $warning.delay(2000).fadeOut('slow', function(){
721 $(this).remove();
722 });
723 }else{
724 //make sure the row controls is at the end.
725 var control = $targetRow.children('.row-controls').remove();
726 $targetRow.append(control);
727 }
728 }
729 });
730 }
731 /* some function definitions...*/
732 $.fn.closeUIfield = function(){
733 var $this = $(this);
734 if(!$this.is('.cf7-field-inner :input:visible')){
735 return $this;
736 }
737 if($this.parent().is('.cf7-field-type')) changeTextarea();
738 $this.hide().attr('id', '');
739 $this.siblings('.dashicons-no-alt').hide();
740 $this.siblings('.content').show();
741 return $this;
742 }
743 $.fn.showUIfield = function(){
744 var $this = $(this);
745 if(!$this.is('.cf7-field-inner')){
746 return $this;
747 }
748 $this.find('p.content').hide();
749 $this.find('span.dashicons').show();
750 var $input = $(':input', $this).show();
751 $input.focus();
752 if($input.is('textarea')){
753 $('textarea#wpcf7-form').attr('id','');
754 $input.attr('id', 'wpcf7-form');
755 wpcf7Value = $input.val();
756 }else{
757 changeTextarea();
758 }
759 return $this;
760 }
761 $.fn.html2gui = function(html){
762 var $this = $(this);
763 if(typeof html === 'undefined') html ='';
764 if(html.length === 0){
765 //get the fields from the textarea
766 html = $('textarea.grid-input', $this).text();
767 if(html.length === 0){
768 $('textarea.grid-input', $this).hide();
769 return $this;
770 }
771 }
772 var singleField = true;
773 var search = $('<div>').append(html);
774
775 if(seekTemplate && 1==search.children(cssTemplate).length){
776 var lines = html.split(/\r\n|\r|\n/g);
777 search = '';
778 for(var i=0; i<lines.length; i++){
779 search += lines[i].trim();
780 }
781 var match = templateRegex.exec(search);
782 if(null !== match){
783 //populate the fields
784 var $field = $('div.cf7-field-label', $this);
785 $('input', $field).val(match[1]);
786 $('p.content', $field).html(match[1]);
787 $field = $('div.cf7-field-type', $this);
788 var tag = $('textarea', $field).val(match[5]).scanCF7Tag();
789 $('p.content', $field).html(tag);
790 $field = $('div.cf7-field-tip', $this);
791 $('input', $field).val(match[6]);
792 $('p.content', $field).html(match[6]);
793 //hide the textarea
794 $('textarea.grid-input', $this).hide();
795 //reset global regex
796 templateRegex.lastIndex = 0;
797 }else{ //this html does not match our templates
798 $('div.cf7-field-inner', $this).remove();
799 }
800 }else{//this html does not match our templates
801 $('div.cf7-field-inner', $this).remove();
802 }
803 }
804
805 $.fn.scanCF7Tag = function(){
806 var $this = $(this);
807 if(!$this.is('textarea')){
808 return '';
809 }
810 var $parent = $this.parent(); //.cf7-field-type.
811 var $helper = $parent.siblings('.dashicons-controls-repeat');
812 $helper.each(function(index){
813 if(index>0){
814 $(this).remove();
815 return;
816 }
817 $(this).removeAttr('data-field').removeAttr('data-tag').removeAttr('data-search');
818 });
819 //reset helper.
820 $helper = $parent.siblings('.dashicons-controls-repeat');
821
822 var cf7TagRegexp = /\[(.[^\s]*)\s*(.[^\s\]]*)[\s\[]*(.[^\[]*\"source:([^\s]*)\"[\s^\[]*|[.^\[]*(?!\"source:)[^\[]*)\]/img;
823 var search = $this.val();
824 var match = cf7TagRegexp.exec(search);
825 var label='';
826 var isRequired = false;
827 var type = [];
828 var fields = [];
829 var hooks = [];
830 var tag='';
831 var isSubmit = false;
832 var count =0;
833 var field = '';
834 var stopSearch = false;
835 while (match != null && !stopSearch) {
836 count++;
837 label+='['+match[1]+' '+match[2]+']';
838 tag = match[1].replace('*','');
839 field = match[2];
840 var helpers = ['cf7sg-tag-all'];
841 helpers[helpers.length] = 'cf7sg-tag-'+tag;
842 switch(tag){
843 case 'submit':
844 case 'save':
845 tag +='-button';
846 isSubmit = true;
847 break;
848 case 'textarea':
849 if( match[0].search(/\s[0-9]{0,3}x[0-9]{1,3}\s?/ig) <0){
850 var cf7sc = match[0].replace(']',' x5]');
851 cf7sc = search.replace(match[0], cf7sc);
852 $this.val(cf7sc);
853 }
854 break;
855 case 'acceptance': //special case with closing tag.
856 stopSearch = true;
857 break;
858 case 'recaptch':
859 case 'recaptcha': //special case with closing tag.
860 label='[recaptcha]';
861 stopSearch = true;
862 break;
863 case 'dynamic_select':
864 var source ='';
865 switch(match.length){
866 case 5: //match[4] exists.
867 if('undefined' !== typeof match[4]){
868 source = match[4].split(':');
869 source = source[0];
870 helpers[helpers.length] = 'cf7sg-tag-dynamic_select-'+source;
871 }
872 case 4: //lets deal with match[3]
873 if(0=== source.length && match[3].indexOf('slug:'>-1)){
874 source = 'taxonomy';
875 }
876 if(match[3].indexOf('class:tags')>-1){
877 helpers[helpers.length] = 'cf7sg-tag-dynamic_select-tags';
878 if(source.length>0){
879 helpers[helpers.length] = 'cf7sg-tag-dynamic_select-'+source+'-tags';
880 }
881 }
882 break;
883 }
884 break;
885 }
886 type[type.length] = tag;
887 fields[fields.length] = field;
888 hooks[hooks.length] = helpers;
889 if('*' === match[1][match[1].length -1]){
890 isRequired = true;
891 }
892 if(!stopSearch) match = cf7TagRegexp.exec(search); //get the next match.
893 }
894 var classes = $('#grid-col div.cf7-field-type').attr('class');
895 classes += " "+ type.join(' ');
896 field = fields.join(' ');
897 // $parent.removeClass('required');
898 if(isRequired) classes += ' required';//$parent.addClass('required').
899 var $parentColumn = $parent.closest('.columns');
900 if($parentColumn.is('[class*="cf7-tags-"]')){
901 $parentColumn.removeClass(function (index, className) {
902 return (className.match (/(^|\s)cf7-tags-\S+/g) || []).join(' ');
903 });
904 }
905 if(count>1){
906 classes += ' cf7-tags-'+count;
907 $parentColumn.addClass('cf7-tags-'+count);
908 }
909 $parent.attr('class',classes);
910 /**@since 2.0.0
911 * setup fields for tag specific filters/actions.
912 */
913 //for each tag get corresponding set of filters.
914 var helperUsed = false;
915 for (var i = 0, len = type.length; i < len; i++) {
916 var search = '';
917 var helpers = hooks[i];
918 for (var j=0, jlen = helpers.length; j<jlen; j++){
919 search += 'li.'+helpers[j]+',';
920 }
921 search = search.slice(0,-1); //remove last ','
922 if($( search ,$('#fieldhelperdiv')).length>0){
923 //this tag has soem filters.
924 if(helperUsed){
925 var $clone = $helper.clone();
926 $helper.after($clone);
927 $helper = $clone;
928 }
929 helperUsed = true;
930 $helper.attr('data-field', fields[i]);
931 $helper.attr('data-tag', type[i]);
932 $helper.attr('data-search', search);
933 $helper.show();
934 }
935 }
936 if(isSubmit){
937 $parent.parent().addClass('submit-field');
938 }
939
940 return label;
941 }
942 $.fn.updateGridForm = function(){
943 var $this = $(this);
944 if(!$this.is('textarea.grid-input')){
945 return $this;
946 }
947 //label
948 var $label = $this.siblings('div.cf7-field-label').find(':input');
949 var label = $label.val();
950 //field
951 var field = $this.siblings('div.cf7-field-type').find('textarea').val();
952 var idx = 0;
953 if(cf7grid.requiredHTML.length>0) idx=label.indexOf(cf7grid.requiredHTML)
954 if($this.siblings('div.cf7-field-type').is('.required')){
955 /** @since 2.10.4 fix for custom manual labels, allow replacement with empty span*/
956 if(idx<0) idx = label.search(/<span>[\w\W]*<\/span>/g);
957 if(idx<0){
958 label += cf7grid.requiredHTML;
959 $label.val(label);//input field.
960 $label.siblings('p.content').html(label);
961 }
962 }else{
963 if(idx>=0){
964 label = label.replace(cf7grid.requiredHTML, '');
965 $label.val(label);//input field.
966 $label.siblings('p.content').html(label);
967 }
968 }
969 //tip
970 var tip = $this.siblings('div.cf7-field-tip').find(':input').val();
971 var $cell = $('<div>').append( cf7grid.preHTML + field + cf7grid.postHTML );
972 $('label', $cell).html(label);
973 $('.info-tip', $cell).html(tip);
974 //update grid input and trigger change to udpate form
975 if(cf7grid.ui) $this.html($cell.html()+'\n').trigger('change');
976 else $this.val($cell.html()).trigger('change');
977 return $this;
978 };
979
980 $.fn.toggleSiblingUIFields = function(){
981 var $this = $(this);
982 if(!$this.is('div.cf7-field-inner')){
983 return $this;
984 }
985 $this.siblings('div.cf7-field-inner').each(function(){
986 var $this = $(this);
987 $('p.content', $this).show();
988 $(':input', $this).hide().attr('id','');
989 $('span.dashicons', $this).hide();
990 });
991 }
992 $.fn.getRowSize = function(){
993 var size, off, idx, foundSize, classList;
994 var total = 0;
995 var sizes = [0];
996 $(this).children('.columns').each(function(index){
997 classList = $(this).attr('class').split(/\s+/);
998 foundSize = false;
999 for(idx=0;idx<classList.length; idx++){
1000 size = $.inArray(classList[idx], columnsizes);
1001 off = $.inArray(classList[idx], offsets);
1002 if(size > -1){
1003 foundSize = true;
1004 sizes[index] = size;
1005 total += size + 1;
1006 }
1007 if(off > -1) total+= off+1;
1008 }
1009 if(!foundSize){ //by default a colum which is not set set is treated as 1
1010 sizes[index] = 0;
1011 total += 1;
1012 }
1013 });
1014 return {'length':total, 'cols':sizes};
1015 }
1016 $.fn.getColumnTotalSize = function(){
1017 var $this = $(this);
1018 if(! $this.is('.columns')){
1019 return 0;
1020 }
1021 var off, foundSize, size = 0;
1022 var total = 0;
1023 var classList = $this.attr('class').split(/\s+/);
1024 var $sizes = $this.find('.grid-column select.column-size');
1025 var $offsets = $this.find('.grid-column select.column-offset');
1026 $offsets.val('');
1027 $sizes.val('one');
1028 foundSize = false;
1029 for(var idx=0;idx<classList.length; idx++){
1030 if(!foundSize){
1031 size = $.inArray(classList[idx], columnsizes);
1032 if(size > -1){
1033 foundSize = true;
1034 total += size + 1;
1035 //reset select
1036 $sizes.val(classList[idx]);
1037 }
1038 }
1039 off = $.inArray(classList[idx], offsets);
1040 if(off > -1){
1041 total += off+1;
1042 $offsets.val(classList[idx]);
1043 }
1044 }
1045 if(!foundSize){ //by default a colum which is not set set is treated as 1
1046 size = 0; //by default a colum which is not set set is treated as 1
1047 total += 1;
1048 }
1049 return {'length':total, 'size':size};
1050 }
1051 //add new rows
1052 $.fn.insertNewRow = function(areaCode){
1053 var $this = $(this);
1054 if(typeof areaCode === 'undefined') areaCode ='';
1055 var append=true;
1056 switch(true){
1057 case ( $this.is('.columns') || $this.is($grid)):
1058 case $this.is('.container.cf7-sg-tabs-panel'): /* fixes rows added in panels*/
1059 append=true;
1060 break;
1061 case ($this.is('.container') || $this.is('.cf7sg-external-form') ):
1062 append=false;
1063 break;
1064 default: //unknown element, maybe an error.
1065 return $this;
1066 }
1067
1068 var $newRow = $( $('#grid-row').html() );
1069 //append the column controls and textarea
1070 $('.columns', $newRow).append( $($('#grid-col').html()) );
1071 //append the new row to the column or container
1072 if(append) $this.append($newRow);
1073 else $this.after($newRow);
1074 //is areaCode text or jQuery object?
1075 if(areaCode instanceof jQuery){
1076 $('.cf7-field-inner', $newRow).remove();
1077 $('textarea.grid-input',$newRow).remove();
1078 $('.columns', $newRow).append(areaCode);
1079 }else{
1080 //add the code to the textarea
1081 if(cf7grid.ui){
1082 $('textarea.grid-input',$newRow).html(areaCode).hide();//.trigger('change');
1083 $newRow.html2gui(areaCode);
1084 }else{
1085 $('textarea.grid-input',$newRow).val(areaCode);//.trigger('change');
1086 $('div.cf7-field-inner', $newRow).hide();
1087 }
1088 }
1089 //make new row's columns sortable.
1090 sortableRows($newRow);
1091 return $this;
1092 }
1093 //refresh controls select
1094 $.fn.changeColumnSize = function(oldSize, newSize){
1095 var $this = $(this);
1096 if(oldSize.length > 0) $this.removeClass(oldSize);
1097 $this.addClass(newSize);
1098 $('.column-size option[value="'+newSize+'"]', $this ).prop('selected', true);
1099 }
1100 //$target.closest('.grid-controls').filterColumnControls();
1101 $.fn.filterColumnControls = function(){
1102 var $this = $(this);
1103 if(!$this.is('.grid-controls')){
1104 return $this;
1105 }
1106 //enable all options
1107 $('.column-size option', $this ).prop('disabled', false);
1108 $('.column-offset option', $this ).prop('disabled', false);
1109 var $parentRow = $this.closest('.row');
1110 var $parentColumn = $this.closest('.columns');
1111 var row = $parentRow.getRowSize();
1112 var col = $parentColumn.getColumnTotalSize();
1113 var idx, start, free = 0;
1114 if(row.length < 12) free = (12 - row.length);
1115 for(idx = start = col.size+1; idx < columnsizes.length; idx++){
1116 if( idx > (free + start - 1) ){
1117 $('.column-size option[value="'+columnsizes[idx]+'"]', $this ).prop('disabled', true);
1118 }
1119 }
1120 for(idx = start = col.length - col.size - 1 ;idx< offsets.length; idx++){
1121 if( idx > (free + start - 1) ){
1122 $('.column-offset option[value="'+offsets[idx]+'"]', $this ).prop('disabled', true);
1123 }
1124 }
1125 return $this;
1126 }
1127
1128 })( jQuery );
1129