symphonycms/symphony-2

View on GitHub
symphony/assets/js/src/symphony.pickable.js

Summary

Maintainability
A
3 hrs
Test Coverage
/**
 * @package assets
 */

(function($) {
    'use strict';

    /**
     * Pickable allows to show and hide elements based on the value of a select box.
     *
     * Each option is mapped to its associated content by matching the option `value`
     * with the content `id`. If the option value is numeric, Pickable prefices it
     * with `choice`. Only the content of the currently selected option is
     * shown, all other elements associated with the given select box are hidden.
     *
     * If no content element of the given `id` is found, Pickable checks for a
     * `data-request` attribute on the selected option. If a `data-request` URL is set,
     * Pickable tries to fetch the content remotely and expects an content element with
     * no additional markup in return.
     *
     * @name $.symphonyPickable
     * @class
     *
     * @param {Object} options An object containing the element selectors specified below
     * @param {String} [options.content='#contents'] Selector to find the container that wraps all pickable elements
     * @param {String} [options.pickables='.pickable'] Selector used to find pickable elements
     *
     * @example

            $('.picker').symphonyPickable();
     */
    $.fn.symphonyPickable = function(options) {
        var objects = $(this),
            settings = {
                content: '#contents',
                pickables: '.pickable'
            };

        $.extend(settings, options);

    /*-------------------------------------------------------------------------
        Events
    -------------------------------------------------------------------------*/

        // Switch content
        objects.on('change.pickable', function pick() {
            var object = $(this),
                choice = object.val(),
                relation = object.attr('id') || object.attr('name'),
                related = $(settings.pickables + '[data-relation="' + relation + '"]'),
                picked, request;

            // Handle numeric values
            if($.isNumeric(choice) === true) {
                choice = 'choice' + choice;
            }

            // Hide all choices
            object.trigger('pickstart.pickable');
            related.hide().find('input, select, textarea').prop('readonly', true);

            // Selection found
            picked = $('#' + choice);
            if(picked.length > 0) {
                picked.show().find('input, select, textarea').prop('readonly', false).trigger('pick.pickable');
                object.trigger('pickstop.pickable');
            }

            // Selection not found
            else {
                request = object.data('request');

                // Fetch picked element
                if(request) {
                    $.ajax({
                        type: 'GET',
                        url: request,
                        data: { 'choice': choice },
                        dataType: 'html',
                        success: function(remote) {
                            content.append(remote);
                            remote.trigger('pick.pickable');
                            object.trigger('pickstop.pickable');
                        }
                    });
                }
            }
        });

    /*-------------------------------------------------------------------------
        Initialisation
    -------------------------------------------------------------------------*/

        var content = $(settings.content);

        // Set up relationships
        objects.each(function init() {
            var object = $(this),
                relation = object.attr('id') || object.attr('name');

            object.find('option').each(function() {
                $('#' + $(this).val()).attr('data-relation', relation);
            });
        });

        // Show picked content
        objects.trigger('change.pickable');

    /*-----------------------------------------------------------------------*/

        return objects;
    };

})(window.jQuery);