PluginProbe
FakerPress / 0.8.0
FakerPress v0.8.0
0.9.2 trunk 0.1.0 0.1.1 0.1.2 0.1.3 0.5.2 0.5.3 0.6.1 0.6.2 0.6.3 0.6.4 0.6.5 0.6.6 0.7.0 0.7.1 0.7.2 0.8.0 0.9.0 0.9.1
fakerpress / src / resources / js / fields.js

fields.js in FakerPress 0.8.0, at src/resources/js/fields.js

742 lines 19.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 ( function( $, _ ){
2 'use strict';
3
4 const isNumeric = ( n ) => {
5 return ! isNaN( parseFloat( n ) ) && isFinite( n );
6 };
7
8 const fp = {};
9
10 fp.fields = {};
11 fp.ready_class = 'fp-js-ready';
12 fp.plugin = 'fakerpress';
13 fp.abbr = 'fp';
14
15 fp.fieldName = function( pieces ){
16 pieces = pieces.map( function( piece ) {
17 return new String( piece );
18 } );
19
20 return this.plugin + '[' + pieces.join( '][' ) + ']';
21 };
22
23 fp.fieldId = function( pieces ){
24 return this.plugin + '-field-' + pieces.join( '-' );
25 };
26
27 fp.searchId = function ( e ) {
28 var id = null;
29
30 if ( 'undefined' !== typeof e.id ){
31 id = e.id;
32 } else if ( 'undefined' !== typeof e.ID ){
33 id = e.ID;
34 } else if ( 'undefined' !== typeof e.value ){
35 id = e.value;
36 }
37 return e == undefined ? null : id;
38 };
39
40 // Date Fields
41 fp.fields.dates = function( $, _ ){
42 'use strict';
43 var datepicker_args = {
44 after: ['attr'],
45 constrainInput: false,
46 dateFormat: 'yy-mm-dd',
47 };
48
49 $( '.fp-type-date' ).not( '.hasDatepicker' ).datepicker( datepicker_args );
50 $( '.fp-type-interval-wrap' ).each( function(){
51 var $container = $( this ),
52 $interval = $container.find( '.fp-type-dropdown' ),
53 $min = $container.find( '[data-type="min"]' ),
54 $max = $container.find( '[data-type="max"]' );
55
56 if ( $container.hasClass( fp.ready_class ) ){
57 return;
58 }
59 $container.addClass( fp.ready_class );
60
61 $min.on({
62 'change': function(e){
63 $min.parents( '.fp-field-wrap' ).find( '[data-type="max"]' ).datepicker( 'option', 'minDate', $( this ).val() ).datepicker( 'refresh' );
64 $( '.fp-type-date.hasDatepicker' ).datepicker( 'refresh' );
65 }
66 });
67
68 $max.on({
69 'change': function(e){
70 $max.parents( '.fp-field-wrap' ).find( '[data-type="min"]' ).datepicker( 'option', 'maxDate', $( this ).val() ).datepicker( 'refresh' );
71 $( '.fp-type-date.hasDatepicker' ).datepicker( 'refresh' );
72 }
73 });
74
75 $interval.on({
76 'change': function(e){
77 var $selected = $interval.find(':selected'),
78 min = $selected.attr('min'),
79 max = $selected.attr('max');
80
81 $min.datepicker( 'setDate', min );
82 $max.datepicker( 'setDate', max );
83 }
84 }).trigger( 'change' );
85 } );
86 };
87
88 // Select2 Fields
89 fp.fields.dropdown = function( $, _ ){
90 'use strict';
91 var $elements = $( '.fp-type-dropdown' ).not( '.select2-offscreen, .select2-container' ),
92 config = {
93 wp_query_title: []
94 };
95
96 config.wp_query_title.push( "ID: &quot;<%= ID %>&quot;" );
97 config.wp_query_title.push( "Title: &quot;<%= post_title %>&quot;" );
98 config.wp_query_title.push( "Post Type: &quot;<%= post_type.labels.singular_name %>&quot;" );
99 config.wp_query_title.push( "Author: &quot;<%= post_author %>&quot;" );
100
101 $elements.each(function(){
102 var $select = $(this),
103 args = {
104 width: 420
105 };
106
107 if ( $select.is( '[multiple]' ) ){
108 args.multiple = true;
109
110 if ( ! $select.is( '[data-tags]' ) ){
111 args.data = function(){
112 return { 'results': $select.data( 'options' ) };
113 };
114 }
115
116 if ( ! _.isArray( $select.data( 'separator' ) ) ){
117 args.tokenSeparators = [ $select.data( 'separator' ) ];
118 } else {
119 args.tokenSeparators = $select.data( 'separator' );
120 }
121 args.separator = $select.data( 'separator' );
122
123 // Define the regular Exp based on
124 args.regexSeparatorElements = [ '^(' ];
125 args.regexSplitElements = [ '(?:' ];
126 $.each( args.tokenSeparators, function ( i, token ){
127 args.regexSeparatorElements.push( '[^' + token + ']+' );
128 args.regexSplitElements.push( '[' + token + ']' );
129 } );
130 args.regexSeparatorElements.push( ')$' );
131 args.regexSplitElements.push( ')' );
132
133 args.regexSeparatorString = args.regexSeparatorElements.join( '' )
134 args.regexSplitString = args.regexSplitElements.join( '' )
135
136 args.regexToken = new RegExp( args.regexSeparatorString, 'ig');
137 args.regexSplit = new RegExp( args.regexSplitString, 'ig');
138
139 args.id = fp.searchId;
140
141 } else {
142 args.width = 200;
143 }
144
145 args.matcher = function( term, text ) {
146 var result = text.toUpperCase().indexOf( term.toUpperCase() ) == 0;
147
148 if ( ! result && 'undefined' !== typeof args.tags ){
149 var possible = _.where( args.tags, { text: text } );
150 if ( args.tags.length > 0 && _.isObject( possible ) ){
151 var test_value = fp.searchId( possible[0] );
152 result = test_value.toUpperCase().indexOf( term.toUpperCase() ) == 0;
153 }
154 }
155
156 return result;
157 };
158
159 if ( $select.is( '[data-tags]' ) ){
160 args.tags = $select.data( 'options' );
161
162 args.initSelection = function ( element, callback ) {
163 var data = [];
164 $( element.val().split( args.regexSplit ) ).each( function () {
165 var obj = { id: this, text: this };
166 if ( args.tags.length > 0 && _.isObject( args.tags[0] ) ){
167 var _obj = _.where( args.tags, { value: this } );
168 if ( _obj.length > 0 ){
169 obj = _obj[0];
170 obj = {
171 id: obj.value,
172 text: obj.text,
173 };
174 }
175 }
176
177 data.push( obj );
178
179 } );
180 callback( data );
181 };
182
183 args.createSearchChoice = function(term, data) {
184 if ( term.match( args.regexToken ) ){
185 return { id: term, text: term };
186 }
187 };
188
189 if ( 0 === args.tags.length ){
190 args.formatNoMatches = function( ){
191 return $select.attr( 'placeholder' );
192 };
193 }
194 }
195
196
197 if ( $select.is( '[data-source]' ) ){
198 var source = $select.data( 'source' );
199 var nonce = $select.data( 'nonce' );
200
201 args.data = { results: [] };
202 args.allowClear = true;
203
204 args.escapeMarkup = function (m) {
205 return m;
206 };
207
208 args.ajax = { // instead of writing the function to execute the request we use Select2's convenient helper
209 dataType: 'json',
210 type: 'POST',
211 url: window.ajaxurl,
212 results: function ( data ) { // parse the results into the format expected by Select2.
213 $.each( data.results, function( k, result ){
214 result.id = result.ID;
215 } );
216 return data;
217 }
218 };
219
220 // Now we set the data for the source we are looking
221 if ( 'WP_Query' === source ){
222 args.formatSelection = function ( post ){
223 return _.template('<abbr title="' + config.wp_query_title.join( '&#13;&#10;' ) + '"><%= post_type.labels.singular_name %>: <%= ID %>')( post )
224 };
225 args.formatResult = function ( post ){
226 return _.template('<abbr title="' + config.wp_query_title.join( '&#13;&#10;' ) + '"><%= post_type.labels.singular_name %>: <%= ID %> <b>[</b> <em><%= post_title %></em> <b>]</b></abbr>')( post )
227 };
228
229 args.ajax.data = function( search, page ) {
230 var post_types = _.intersection( $( '#fakerpress-field-post_types' ).val().split( ',' ), _.pluck( _.where( $( '#fakerpress-field-post_types' ).data( 'options' ), { hierarchical: true } ) , 'id' ) );
231
232 return {
233 action: 'fakerpress.select2-' + source,
234 nonce: nonce,
235 query: {
236 s: search,
237 posts_per_page: 10,
238 paged: page,
239 post_type: post_types
240 }
241 };
242 }
243 } else {
244 args.ajax.data = function( search, page ) {
245 var $container = $select.parents( '.fp-table-taxonomy' ).eq( 0 );
246 return {
247 action: 'fakerpress.select2-' + source,
248 search: search,
249 nonce: nonce,
250 page: page,
251 page_limit: 25,
252 taxonomies: $container.find( '.fp-taxonomies' ).select2( 'val' ),
253 exclude: $( this ).select2( 'val' )
254 };
255 }
256
257 args.formatSelection = function ( result ){
258 return _.template( '<%= taxonomy %>: <%= name %>' )( result );
259 };
260 args.formatResult = function ( result ){
261 return _.template( '<%= taxonomy %>: <%= name %>' )( result );
262 };
263 }
264 }
265
266 $select.select2( args );
267 })
268 .on( 'change', function( event ) {
269 var $select = $(this),
270 data = $( this ).data( 'value' );
271
272 if ( ! $select.is( '[multiple]' ) ){
273 return;
274 }
275 if ( ! $select.is( '[data-source]' ) ){
276 return;
277 }
278
279 if ( event.added ){
280 if ( _.isArray( data ) ) {
281 data.push( event.added );
282 } else {
283 data = [ event.added ];
284 }
285 } else {
286 if ( _.isArray( data ) ) {
287 data = _.without( data, event.removed );
288 } else {
289 data = [];
290 }
291 }
292 $select.data( 'value', data ).attr( 'data-value', JSON.stringify( data ) );
293 } )
294 .on( 'select2-open', ( event ) => {
295 const $target = $( event.target );
296 const select2 = $target.data( 'select2' );
297 const width = select2.dropdown.width();
298
299 select2.dropdown.width( width+2 ).css( 'margin-left', '-1px' );
300
301 } );
302 };
303
304 // Quantity Range Fields
305 fp.fields.range = function( $, _ ){
306 'use strict';
307
308 $( '.fp-type-range-wrap' ).each(function(){
309 var $container = $( this );
310 var $minField = $container.find( '.fp-type-number[data-type="min"]' );
311 var $maxField = $container.find( '.fp-type-number[data-type="max"]' );
312
313 if ( $container.hasClass( fp.ready_class ) ){
314 return;
315 }
316 $container.addClass( fp.ready_class );
317
318 $minField.on( {
319 'change keyup': function(e){
320 var minValue = parseInt( $minField.val(), 10 );
321 var maxValue = parseInt( $maxField.val(), 10 );
322
323 if ( isNumeric( minValue ) ) {
324 $maxField.prop( 'disabled', false );
325
326 // When we have max value we don't allow min to be bigger than max
327 if ( maxValue && isNumeric( maxValue ) && minValue > maxValue ){
328 $minField.val( maxValue );
329 }
330 } else {
331 $maxField.prop( 'disabled', true );
332 $minField.val( '' );
333 }
334 }
335 } ).trigger( 'change' );
336
337 $maxField.on( {
338 'change keyup': function(e){
339 var minValue = parseInt( $minField.val(), 10 );
340 var maxValue = parseInt( $maxField.val(), 10 );
341
342 if ( isNumeric( maxValue ) && minValue > maxValue ) {
343 $minField.val( maxValue );
344 }
345 }
346 } ).trigger( 'change' );
347 } );
348 };
349
350 fp.fieldset = {
351 items: [
352 {
353 name: 'meta',
354
355 $: {},
356 selector: {
357 container: '.fp-type-meta-container',
358
359 item: '.fp-table-meta',
360
361 type_container: '.fp-meta_type-container',
362 type: '.fp-meta_type',
363
364 name_container: '.fp-meta_name-container',
365 name: '.fp-meta_name',
366
367 conf_container: '.fp-meta_conf-container'
368 },
369
370 update: function( $item ) {
371 // Render again the Configuration
372 this.render( $item );
373 },
374
375 render: function( $item ) {
376 var fieldset = this,
377 $type = $item.find( fieldset.selector.type ),
378 type = $type.select2( 'val' ),
379
380 $name = $item.find( fieldset.selector.name ),
381 name = $name.val(),
382
383 $name_container = $item.find( fieldset.selector.name_container ),
384 $type_container = $item.find( fieldset.selector.type_container ),
385 $conf_container = $item.find( fieldset.selector.conf_container ),
386
387 $place = $conf_container.find( fp.fieldset.selector.wrap ),
388 config = $conf_container.data( 'config' ),
389
390 $template,
391 template;
392
393 // Before constructing the Type Object check if it's a jQuery element (Select2 bug)
394 if ( type instanceof jQuery ){
395 type = type.val();
396 }
397
398 // Find templates relevant to the current container
399 $template = $( '.fp-template-' + type ).filter( '[data-rel="' + fieldset.$.container.attr( 'id' ) + '"]' ).filter( '[data-callable]' );
400 template = $template.html();
401
402 // Only place if there is a template
403 if ( template && type !== $conf_container.data( 'type' ) ) {
404 $conf_container.data( 'type', type );
405 $place.empty().append( template );
406
407 this.configure( $conf_container );
408 }
409
410 // Make Styles Match the what needs to be done
411 if ( ! type ){
412 $name_container.addClass( 'fp-last-child' );
413 $conf_container.hide();
414 } else {
415 $name_container.removeClass( 'fp-last-child' );
416 $conf_container.show();
417 }
418 },
419
420 /**
421 * A way to setup the configuration fields for Meta
422 *
423 * @param jQuery $conf The configuration Container
424 *
425 * @return null
426 */
427 configure: function( $conf ) {
428 var fieldset = this;
429 var config = $conf.data( 'config' );
430 var $fields = $conf.find( fp.fieldset.selector.field );
431
432 // Reset the Configuration, only happens once!
433 // $conf.removeAttr( 'data-config', false ).data( 'config', {} );
434
435 // Loop fields
436 $fields.each( function() {
437 var $field = $( this );
438 var $fieldset = $field.parents( fieldset.selector.item ).eq( 0 );
439 var $label = $field.next( fp.fieldset.selector.label );
440 var $internal_label = $field.next( fp.fieldset.selector.internal_label );
441
442 var name = $field.data( 'name' );
443 var index = parseInt( $fieldset.find( fp.fieldset.selector.order ).val(), 10 ) - 1;
444 var key = name[ index ];
445 var __name = $field.data( 'name' );
446 var __id = $field.data( 'id' );
447 var id = [];
448 var name = [];
449
450 // If didn't find a label inside of the parent element
451 if ( 0 === $label.length ){
452 $label = $field.parents( fp.fieldset.selector.field_container ).eq( 0 ).find( fp.fieldset.selector.label );
453 }
454
455 _.each( __id, function( value, key, list ) {
456 id.push( value );
457 if ( 'meta' === value || 'taxonomy' === value ){
458 id.push( index );
459 }
460 } );
461
462 _.each( __name, function( value, key, list ) {
463 name.push( value );
464 if ( 'meta' === value || 'taxonomy' === value ){
465 name.push( index );
466 }
467 } );
468
469 if ( 0 !== id.length ){
470 $field.attr( 'id', fp.fieldId( id ) );
471 $label.attr( 'for', fp.fieldId( id ) );
472 $internal_label.attr( 'for', fp.fieldId( id ) );
473 }
474
475 if ( 0 !== name.length ){
476 $field.attr( 'name', fp.fieldName( name ) );
477 }
478
479 if ( 'undefined' === typeof config || 'undefined' === typeof config[ key ] ) {
480 return;
481 }
482
483 $field.val( config[ key ] );
484 } );
485 },
486
487 is_removeable: function() {
488 if ( 1 === this.$.items.length ){
489 var $item = this.$.items.eq( 0 );
490
491 if ( _.isEmpty( $item.find( this.selector.type ).select2( 'val' ) ) ) {
492 return true;
493 } else {
494 return false;
495 }
496 }
497
498 return false;
499 },
500
501 setup: function() {
502 var fieldset = this;
503
504 fieldset.$.container.on( 'change', fieldset.selector.type, [], function( event ){
505 var $field = $( this );
506
507 // Render again the Configuration
508 fieldset.render( $field );
509
510 // Update all the required information
511 fp.fieldset.update( fieldset, false );
512 } );
513 },
514
515 reset: function( $item ) {
516
517 }
518 },
519 {
520 name: 'taxonomy',
521
522 $: {},
523 selector: {
524 container: '.fp-type-taxonomy-container',
525
526 item: '.fp-table-taxonomy',
527
528 taxonomies_container: '.fp-taxonomies-container',
529 taxonomies: '.fp-taxonomies',
530
531 terms_container: '.fp-terms-container',
532 terms: '.fp-terms',
533
534 weight_container: '.fp-weight-container',
535 weight: '.fp-weight'
536 },
537
538 update: function( $item ) {
539
540 },
541
542 is_removeable: function() {
543 if ( 1 === this.$.items.length ){
544 var $item = this.$.items.eq( 0 );
545
546 if (
547 _.isEmpty( $item.find( this.selector.taxonomies ).select2( 'val' ) ) &&
548 _.isEmpty( $item.find( this.selector.terms ).val() )
549 ) {
550 return true;
551 } else {
552 return false;
553 }
554 }
555
556 return false;
557 },
558
559 setup: function() {
560 var fieldset = this;
561 },
562
563 reset: function( $item ) {
564
565 }
566 },
567 ],
568
569 // Global Elements
570 selector: {
571 wrap: '.fp-field-wrap',
572 duplicate: '.fp-action-duplicate',
573 remove: '.fp-action-remove',
574 order: '.fp-action-order',
575 label: '.fp-field-label',
576 internal_label: '.fp-internal-label',
577 field: '.fp-field',
578 field_container: '.fp-field-container'
579 },
580
581 setup: function( fieldset ) {
582 var $tbody = $( 'form' ).children( '.form-table' ).children( 'tbody' );
583
584 // Reset the Elements (safety)
585 fieldset.$ = {};
586
587 // Based on the Argument set the container
588 fieldset.$.container = $tbody.children( fieldset.selector.container );
589
590 // Get the Field Wrapper
591 fieldset.$.wrap = fieldset.$.container.children( fp.fieldset.selector.wrap );
592
593 // Setup the Duplicate action
594 fieldset.$.container.on( 'click', this.selector.duplicate, [], function( event ){
595 var $button = $( this ),
596 $item = $button.parents( fieldset.selector.item ),
597 $clone = $item.clone();
598
599 $clone
600 .find( '.fp-type-date' ).removeClass( 'hasDatepicker' )
601 .end().find( '.fp-type-dropdown' ).removeClass( 'select2-offscreen' )
602 .filter( '.select2-container' ).remove();
603
604 fp.fieldset.reset( fieldset, $clone );
605
606 // Append the new Meta to the Wrap
607 fieldset.$.wrap.append( $clone );
608
609 // Update all the required information
610 fp.fieldset.update( fieldset );
611 } );
612
613 // Setup the Remove action
614 fieldset.$.container.on( 'click', this.selector.remove, [], function( event ){
615 var $button = $( this ),
616 $item = $button.parents( fieldset.selector.item );
617
618 // Prevent remove when there is just one meta
619 if ( 1 === fieldset.$.items.length ){
620 fp.fieldset.reset( fieldset, fieldset.$.items.eq( 0 ) );
621 } else {
622 // Remove the Meta where the remove was clicked
623 $item.remove();
624 }
625
626 // Update all the required information
627 fp.fieldset.update( fieldset );
628 } );
629
630 fieldset.setup();
631
632 // Update all the required information
633 this.update( fieldset, false );
634 },
635
636 reset: function( fieldset, $item ) {
637 var $fields = $item.find( 'tbody' ).find( fp.fieldset.selector.field );
638
639 $fields.each( function() {
640 var $field = $( this );
641
642 // Reset normal fields
643 $field.val( '' );
644
645 // Resets the Select2
646 if ( $field.hasClass( 'select2-offscreen' ) ){
647 $field.select2( 'val', '' );
648 }
649 } );
650
651 fieldset.reset( $item );
652 },
653
654 update: function( fieldset ) {
655 // Setup a base list of items
656 fieldset.$.items = fieldset.$.wrap.children( fieldset.selector.item );
657
658 // If there is just one meta, disable the remove button
659 if ( fieldset.is_removeable() ) {
660 fieldset.$.items.eq( 0 )
661 .find( fp.fieldset.selector.remove ).prop( 'disabled', true )
662 .end().find( fieldset.selector.name ).prop( 'required', false );
663 } else {
664 fieldset.$.items
665 .find( fp.fieldset.selector.remove ).prop( 'disabled', false )
666 .end().find( fieldset.selector.name ).prop( 'required', true );
667 }
668
669 // Regenerate Order Index
670 fieldset.$.items.each( function( index ){
671 var $item = $( this ),
672 $index = $item.find( fp.fieldset.selector.order ),
673 $fields = $item.find( fp.fieldset.selector.field );
674
675 // Change the index first
676 $index.val( index + 1 );
677
678 $fields.filter( 'input, textarea, select' ).each( function( ){
679 var $field = $( this ),
680 $label = $field.next( fp.fieldset.selector.label ),
681 $internal_label = $field.next( fp.fieldset.selector.internal_label ),
682
683 __name = $field.data( 'name' ),
684 __id = $field.data( 'id' ),
685 id = [],
686 name = [];
687
688 // If didn't find a label inside of the parent element
689 if ( 0 === $label.length ){
690 $label = $field.parents( fp.fieldset.selector.field_container ).eq(0).find( fp.fieldset.selector.label );
691 }
692
693 _.each( __id, function( value, key, list ) {
694 id.push( value );
695 if ( 'meta' === value || 'taxonomy' === value ){
696 id.push( index );
697 }
698 } );
699
700 _.each( __name, function( value, key, list ) {
701 name.push( value );
702 if ( 'meta' === value || 'taxonomy' === value ){
703 name.push( index );
704 }
705 } );
706
707 if ( 0 !== id.length ){
708 $field.attr( 'id', fp.fieldId( id ) );
709 $label.attr( 'for', fp.fieldId( id ) );
710 $internal_label.attr( 'for', fp.fieldId( id ) );
711 }
712
713 if ( 0 !== name.length ){
714 $field.attr( 'name', fp.fieldName( name ) );
715 }
716 } );
717
718 fieldset.update( $item );
719 } );
720
721 $.each( fp.fields, function( key, callback ){
722 callback( window.jQuery, window._ );
723 } );
724 }
725 };
726
727 $( () => {
728 $.each( fp.fieldset.items, function( index, fieldset ) {
729 fp.fieldset.setup( fieldset );
730 fieldset.$.container.each( function( _index, container ) {
731 // We need this to avoid having a `this` variable been a HTML element
732 fp.fieldset.update( fieldset );
733 } );
734 } );
735
736 $.each( fp.fields, function( key, callback ){
737 callback( window.jQuery, window._ );
738 } );
739 } );
740
741 }( window.jQuery, window._ ) );
742