felixarntz/wpdlib

View on GitHub
assets/src/js/fields.js

Summary

Maintainability
F
3 wks
Test Coverage
( function( $ ) {
    if ( typeof _wpdlib_data === 'undefined' ) {
        console.error( 'WPDLib data object not found' );
    }

    var WPDLibFieldManager = {
        /**
         * Global arguments coming from `wp_localize_script()`
         * @type object
         */
        args: _wpdlib_data,

        /**
         * Whether Select2 is enabled
         * @type bool
         */
        select2_enabled: typeof $.fn.select2 !== 'undefined',

        /**
         * Arguments for Select2 initialization
         * @type object
         */
        select2_args: {},

        /**
         * Whether DateTimePicker is enabled
         * @type bool
         */
        datetimepicker_enabled: typeof $.fn.datetimepicker !== 'undefined',

        /**
         * Arguments for DateTimePicker initialization
         * @type object
         */
        datetimepicker_args: {},

        /**
         * Whether WPColorPicker is enabled
         * @type bool
         */
        colorpicker_enabled: typeof $.fn.wpColorPicker !== 'undefined',

        /**
         * Arguments for WPColorPicker initialization
         * @type object
         */
        colorpicker_args: {},

        /**
         * Whether WPMediaPicker is enabled
         * @type bool
         */
        mediapicker_enabled: typeof $.fn.wpMediaPicker !== 'undefined',

        /**
         * Arguments for WPMediaPicker initialization
         * @type object
         */
        mediapicker_args: {},

        /**
         * Whether WPMapPicker is enabled
         * @type bool
         */
        mappicker_enabled: typeof $.fn.wpMapPicker !== 'undefined',

        /**
         * Arguments for WPMapPicker initialization
         * @type object
         */
        mappicker_args: {},

        /**
         * Initializes all the fields.
         *
         * This is the only function that should be accessed publically.
         */
        init: function() {
            var self = WPDLibFieldManager;

            self.select2_args = {
                width: 'element',
                closeOnSelect: true,
                templateResult: self._formatSelect2,
                templateSelection: self._formatSelect2,
                minimumResultsForSearch: 8
            };

            self.datetimepicker_args = {
                formatDate: 'Y-m-d',
                formatTime: 'H:i',
                dayOfWeekStart: self.args.start_of_week,
                scrollMonth: false,
                scrollTime: false,
                scrollInput: false,
                validateOnBlur: false
            };

            self.colorpicker_args = {
                mode: 'hsv'
            };

            self.mediapicker_args = {
                filterable: false,
                label_add: self.args.media_i18n_add,
                label_replace: self.args.media_i18n_replace,
                label_remove: self.args.media_i18n_remove,
                label_modal: self.args.media_i18n_modal,
                label_button: self.args.media_i18n_button
            };

            self.mappicker_args = {};

            if ( this.datetimepicker_enabled ) {
                $.datetimepicker.setLocale( self.args.language );
            }

            self._initJQueryPluginFields();

            self._setupRange( '.wpdlib-input-range' );
            self._setupRadio( '.wpdlib-input-radio' );
            self._setupMultibox( '.wpdlib-input-multibox' );
            self._setupRepeatable( '.wpdlib-input-repeatable' );
        },

        /**
         * Initializes all fields that rely on jQuery plugins.
         *
         * @param string selector_prefix an optional (parent) selector string to prefix all the selectors with
         */
        _initJQueryPluginFields: function( selector_prefix ) {
            var self = WPDLibFieldManager;

            if ( typeof selector_prefix !== 'string' ) {
                selector_prefix = '';
            } else {
                selector_prefix += ' ';
            }

            self._setupSelect2( selector_prefix + '.wpdlib-input-select' );
            self._setupSelect2( selector_prefix + '.wpdlib-input-multiselect' );
            self._setupDatetimepicker( selector_prefix + '.wpdlib-input-datetime' );
            self._setupDatepicker( selector_prefix + '.wpdlib-input-date' );
            self._setupTimepicker( selector_prefix + '.wpdlib-input-time' );
            self._setupColorpicker( selector_prefix + '.wpdlib-input-color' );
            self._setupMediapicker( selector_prefix + '.wpdlib-input-media' );
            self._setupMappicker( selector_prefix + '.wpdlib-input-map' );
        },

        /**
         * Initializes Select2 on a selection of fields.
         *
         * @param string|jQuery selector a selector or a jQuery object
         */
        _setupSelect2: function( selector ) {
            if ( ! this.select2_enabled ) {
                return;
            }

            var $fields = this._getJQuery( selector );

            $fields.select2( this.select2_args );
        },

        /**
         * Initializes DateTimePicker for datetime inputs on a selection of fields.
         *
         * @param string|jQuery selector a selector or a jQuery object
         */
        _setupDatetimepicker: function( selector ) {
            if ( ! this.datetimepicker_enabled ) {
                return;
            }

            var $fields = this._getJQuery( selector );

            $fields.datetimepicker( $.extend( {
                format: this.args.date_format + ' ' + this.args.time_format,
                onShow: this._datetimeOnShow
            }, this.datetimepicker_args ) );
        },

        /**
         * Initializes DateTimePicker for date inputs on a selection of fields.
         *
         * @param string|jQuery selector a selector or a jQuery object
         */
        _setupDatepicker: function( selector ) {
            if ( ! this.datetimepicker_enabled ) {
                return;
            }

            var $fields = this._getJQuery( selector );

            $fields.datetimepicker( $.extend( {
                format: this.args.date_format,
                timepicker: false,
                onShow: this._dateOnShow
            }, this.datetimepicker_args ) );
        },

        /**
         * Initializes DateTimePicker for time inputs on a selection of fields.
         *
         * @param string|jQuery selector a selector or a jQuery object
         */
        _setupTimepicker: function( selector ) {
            if ( ! this.datetimepicker_enabled ) {
                return;
            }

            var $fields = this._getJQuery( selector );

            $fields.datetimepicker( $.extend( {
                format: this.args.time_format,
                datepicker: false,
                onShow: this._timeOnShow
            }, this.datetimepicker_args ) );
        },

        /**
         * Initializes WPColorPicker on a selection of fields.
         *
         * @param string|jQuery selector a selector or a jQuery object
         */
        _setupColorpicker: function( selector ) {
            if ( ! this.colorpicker_enabled ) {
                return;
            }

            var $fields = this._getJQuery( selector );

            $fields.wpColorPicker( this.colorpicker_args );
        },

        /**
         * Initializes WPMediaPicker on a selection of fields.
         *
         * @param string|jQuery selector a selector or a jQuery object
         */
        _setupMediapicker: function( selector ) {
            if ( ! this.mediapicker_enabled ) {
                return;
            }

            var $fields = this._getJQuery( selector );

            $fields.wpMediaPicker( this.mediapicker_args );
        },

        /**
         * Initializes WPMapPicker on a selection of fields.
         *
         * @param string|jQuery selector a selector or a jQuery object
         */
        _setupMappicker: function( selector ) {
            if ( ! this.mappicker_enabled ) {
                return;
            }

            var $fields = this._getJQuery( selector );

            $fields.wpMapPicker( this.mappicker_args );
        },

        /**
         * Adds listeners to handle range inputs.
         *
         * @param string selector a selector
         */
        _setupRange: function( selector ) {
            $( document ).on( 'change', selector, function() {
                $( this ).prev( 'input' ).val( $( this ).val() );
            });

            $( document ).on( 'change', selector + '-viewer', function() {
                $( this ).next( 'input' ).val( $( this ).val() );
            });
        },

        /**
         * Adds listeners to handle radio inputs with images/colors.
         *
         * @param string selector a selector
         */
        _setupRadio: function( selector ) {
            $( document ).on( 'click', selector + ' .wpdlib-radio div', function() {
                var input_id = $( this ).attr( 'id' ).replace( '-asset', '' );

                $( '#' + input_id ).prop( 'checked', true ).trigger( 'change' );
            });

            $( document ).on( 'change', selector + ' .wpdlib-radio input', function() {
                var input_id = $( this ).attr( 'id' );

                $( this ).parent().parent().find( '.wpdlib-radio div' ).removeClass( 'checked' );
                $( '#' + input_id ).addClass( 'checked' );
            });
        },

        /**
         * Adds listeners to handle multibox inputs with images/colors.
         *
         * @param string selector a selector
         */
        _setupMultibox: function( selector ) {
            $( document ).on( 'click', selector + ' .wpdlib-checkbox div', function() {
                var input_id = $( this ).attr( 'id' ).replace( '-asset', '' );

                if ( $( this ).hasClass( 'checked' ) ) {
                    $( this ).removeClass( 'checked' );

                    $( '#' + input_id ).prop( 'checked', false );
                } else {
                    $( this ).addClass( 'checked' );

                    $( '#' + input_id ).prop( 'checked', true );
                }
            });
        },

        /**
         * Initializes repeatable elements
         *
         * @param string|jQuery selector a selector or a jQuery object
         */
        _setupRepeatable: function( selector ) {
            var self = WPDLibFieldManager;
            var $fields = this._getJQuery( selector );

            $fields.each(function() {
                $( this ).on( 'click', '.wpdlib-new-repeatable-button', function( e ) {
                    var parent_selector = '#' + e.delegateTarget.id;
                    var $parent = $( parent_selector );
                    var limit = parseInt( $parent.data( 'limit' ));
                    var id = $parent.attr( 'id' );
                    var key = $parent.find( '.wpdlib-repeatable-row' ).length;

                    if ( typeof self.args.repeatable_field_templates[ id ] !== 'undefined' ) {
                        var output = self.args.repeatable_field_templates[ id ].replace( /{{KEY}}/g, key ).replace( /{{KEY_PLUSONE}}/g, key + 1 );

                        $parent.find( '.wpdlib-repeatable-table' ).show();
                        $parent.find( '.wpdlib-repeatable-table' ).append( output );

                        if ( limit > 0 && limit === key + 1 ) {
                            $parent.find( '.wpdlib-new-repeatable-button' ).hide();
                        }

                        $( document ).trigger( 'wpdlib-added-repeatable-item', [ parent_selector ] );
                    }

                    e.preventDefault();
                });

                $( this ).on( 'click', '.wpdlib-remove-repeatable-button', function( e ) {
                    var $parent = $( '#' + e.delegateTarget.id );

                    var $rows = $parent.find( '.wpdlib-repeatable-row' );

                    var number = parseInt( $( this ).data( 'number' ) ) + 1;

                    e.preventDefault();

                    $rows.filter( ':nth-child(' + ( number + 1 ) + ')' ).remove();

                    $rows.filter( ':gt(' + ( number - 1 ) + ')' ).each(function() {
                        var $row = $( this );

                        var number = parseInt( $row.find( '.wpdlib-remove-repeatable-button' ).data( 'number' ) );

                        var target = number - 1;

                        $row.find( 'span:first' ).html( $row.find( 'span:first' ).html().replace( ( number + 1 ).toString(), ( target + 1 ).toString() ) );

                        $row.find( '.wpdlib-repeatable-col input, .wpdlib-repeatable-col select, .wpdlib-repeatable-col img, .wpdlib-repeatable-col a' ).each(function() {
                            if ( $( this ).attr( 'id' ) ) {
                                $( this ).attr( 'id', $( this ).attr( 'id' ).replace( number.toString(), target.toString() ) );
                            }

                            if ( $( this ).attr( 'name' ) ) {
                                $( this ).attr( 'name', $( this ).attr( 'name' ).replace( number.toString(), target.toString() ) );
                            }
                        });

                        $row.find('.wpdlib-remove-repeatable-button').data( 'number', target.toString() );
                    });

                    var limit = parseInt( $parent.data( 'limit' ) );

                    if ( limit > 0 && limit > $parent.find( '.wpdlib-repeatable-row' ).length ) {
                        $parent.find( '.wpdlib-new-repeatable-button' ).show();
                    }
                    if ( $parent.find( '.wpdlib-repeatable-row' ).length < 1 ) {
                        $parent.find( '.wpdlib-repeatable-table' ).hide();
                    }
                });
            });

            $( document ).on( 'wpdlib-added-repeatable-item', function( e, parent_selector ) {
                self._initJQueryPluginFields( parent_selector );
            });
        },

        /**
         * Returns a jQuery object from a string.
         *
         * @param string|jQuery selector a selector or a jQuery object
         * @return jQuery a jQuery object
         */
        _getJQuery: function( selector ) {
            if ( typeof selector === 'string' ) {
                return $( selector );
            }
            return selector;
        },

        /**
         * Formatting function passed to Select2.
         *
         * @param object selection contains information about the current selection
         * @return string the formatted (HTML) text
         */
        _formatSelect2: function( selection ) {
            if ( typeof selection.id === 'undefined' ) {
                return selection.text;
            }

            var $option = $( selection.element );
            var option_data = $option.data();

            if ( option_data ) {
                if ( option_data.hasOwnProperty( 'image' ) ) {
                    return $( '<div class="wpdlib-option-box-wrap"><div class="wpdlib-option-box" style="background-image:url(' + $option.data( 'image' ) + ');"></div><span class="wpdlib-option-box-text">' + selection.text + '</span></div>' );
                } else if ( option_data.hasOwnProperty( 'color' ) ) {
                    return $( '<div class="wpdlib-option-box-wrap"><div class="wpdlib-option-box" style="background-color:#' + $option.data( 'color' ) + ';"></div><span class="wpdlib-option-box-text">' + selection.text + '</span></div>' );
                }
            }

            return selection.text;
        },

        /**
         * OnShow function passed to DateTimePicker for datetime inputs.
         *
         * @param object ct contains information about the current datetime
         * @param jQuery $input the input element
         */
        _datetimeOnShow: function( ct, $input ) {
            var helper = '';
            if ( $input.attr( 'min' ) ) {
                helper = $input.attr( 'min' ).split( ' ' );
                if ( helper.length === 2 ) {
                    this.setOptions({
                        minDate: helper[0],
                        minTime: helper[1]
                    });
                } else if( helper.length === 1 ) {
                    this.setOptions({
                        minDate: helper[0]
                    });
                }
            }

            if ( $input.attr( 'max' ) ) {
                helper = $input.attr( 'max' ).split( ' ' );
                if ( helper.length === 2 ) {
                    this.setOptions({
                        maxDate: helper[0],
                        maxTime: helper[1]
                    });
                } else if( helper.length === 1 ) {
                    this.setOptions({
                        maxDate: helper[0]
                    });
                }
            }

            if ( $input.attr( 'step' ) ) {
                this.setOptions({
                    step: parseInt( $input.attr( 'step' ) )
                });
            }
        },

        /**
         * OnShow function passed to DateTimePicker for date inputs.
         *
         * @param object ct contains information about the current date
         * @param jQuery $input the input element
         */
        _dateOnShow: function( ct, $input ) {
            if ( $input.attr( 'min' ) ) {
                this.setOptions({
                    minDate: $input.attr( 'min' )
                });
            }

            if ( $input.attr( 'max' ) ) {
                this.setOptions({
                    maxDate: $input.attr( 'max' )
                });
            }
        },

        /**
         * OnShow function passed to DateTimePicker for time inputs.
         *
         * @param object ct contains information about the current time
         * @param jQuery $input the input element
         */
        _timeOnShow: function( ct, $input ) {
            if ( $input.attr( 'min' ) ) {
                this.setOptions({
                    minTime: $input.attr( 'min' )
                });
            }

            if ( $input.attr( 'max' ) ) {
                this.setOptions({
                    maxTime: $input.attr( 'max' )
                });
            }

            if ( $input.attr( 'step' ) ) {
                this.setOptions({
                    step: parseInt( $input.attr( 'step' ) )
                });
            }
        }
    };

    $( document ).ready( function() {
        WPDLibFieldManager.init();
    });
}( jQuery ) );