<commit_before>'use strict';

var $ = require('jquery');

function FilterBarComponent(html) {
    this.$html = html;
}

FilterBarComponent.prototype.init = function () {
    var component = this;

    this.$container = this.$html.find('.filter-bar');

    this.$container.each(function() {
        var $filterbar = $(this);

        // Create the filter add button
        createFilterListButton($filterbar);

        // Hide the form elements
        hideFormControls($filterbar);

        // Move save button
        moveFormActions($filterbar);

        // Handlers
        showFilterBar(component, $filterbar);
        populateFilterList($filterbar);
        showAddFilterPopover($filterbar);
        addFilter($filterbar);
        removeFilter($filterbar);
        clearAllFilters($filterbar);
    });
};

function showFilterBar (component, $filterbar) {

    component.$html.on('click', '[data-ui="show-filter-bar"]', function(e) {
        var $addFilterButton = $filterbar.find('[data-ui="show-filter-list"]');

        e.preventDefault();

        // Show add button if hidden by clear
        $addFilterButton.removeClass('display--none');

        // Show filter bar
        $filterbar.removeClass('display--none');
    });
}

function createFilterListButton ($filterbar) {
    var $formGroups = $filterbar.find('.form__group'),
        $addFilterButton,
        $filterList = $('

'),
        $filterLabelsWrapper = $('

');

    // Loop through form groups
    $formGroups.each(function() {
        $filterList.append('
'+ $(this).find('.control__label').text() +'
');
    });

    // Build up list and mark up for Add filter button
    $addFilterButton = $('<button class="btn filter-bar__add" data-ui="show-filter-list" data-toggle="popover" data-trigger="click" title="Filter by" data-html="true" data-placement="bottom" data-content="" aria-haspopup="true" aria-expanded="false">Add</button>');
    $addFilterButton.attr('data-content', $filterList[0].outerHTML);

    // Append button and label wrapper
    $filterLabelsWrapper.appendTo($filterbar.find('fieldset'));
    $addFilterButton.appendTo($filterLabelsWrapper);

    // Initialize popover
    $addFilterButton.popover();

    // Prevent default on button
    $filterbar.on('click', '[data-ui="show-filter-list"]', function(e) {
        e.preventDefault();
    });
}

function hideFormControls ($filterbar) {
    $filterbar
        .find('.form__group')
        .addClass('display--none');
    $filterbar
        .find('.form__actions')
        .addClass('display--none');
}

function moveFormActions ($filterbar) {
    var $formActions = $filterbar.find('.form__actions'),
        $fieldset = $filterbar.find('fieldset');

    $formActions.appendTo($fieldset);
    $formActions.addClass('display--none');
}

function showAddFilterPopover ($filterbar) {
    var filterTitle,
        filterId,
        select2Placeholder,
        $formGroup,
        $filterLabel,
        $popoverControls,
        $popoverContent,
        $field,
        $select2,
        $addFilterButton = $filterbar.find('[data-ui="show-filter-list"]');

    $filterbar.on('click', '[data-ui="filter-item"]', function(e) {
        e.preventDefault();

        filterTitle = $(this).attr('data-filter-title');
        filterId = $(this).attr('data-filter-id');
        $field = $filterbar.find('#' + filterId);

        // Hide the filter item in the list
        updateFilterList($addFilterButton, filterId, 'hide');

        // Add new filter label
        $filterLabel = $('' + filterTitle + ' ');
        $filterLabel.insertBefore($addFilterButton);

        // If checkbox, check it but no need to display it or move to popover
        if ($field[0].type === 'checkbox') {

            // Hide the filter list popover
            $addFilterButton.popover('hide');

            // Check the checkbox
            $field.prop('checked', true);

            // Add the remove button to the label
            filterId = $filterLabel.attr('data-filter-id');
            $filterLabel.append('');

            // Add the label
            $filterLabel
                .removeClass('label--primary')
                .addClass('label--inverse');

            // Hide the filter list button if no links remaining
            filterListButtonVisibility($filterbar);

            // Check if save button should be visible
            formActionsVisibility($filterbar);

        } else {

            // Create content for the popover
            $popoverContent = $('

');

            // Move the field into the popover content
            $formGroup = $filterbar.find('#' + filterId).closest('.form__group');
            $formGroup.appendTo($popoverContent);
            $formGroup.addClass('form__group--flush');

            // Hide the control label
            $formGroup
                .removeClass('display--none')
                .find('.control__label')
                    .addClass('hide');

            // Add popover controls
            $popoverControls = $('
<button type="submit" class="btn btn--primary is-disabled" data-ui="add-filter" disabled="disabled">Add</button>Cancel
');
            $popoverControls.insertAfter($formGroup);

            // Refresh the select2
            $select2 = $popoverContent.find('.js-select2:not([data-init="false"])');
            select2Placeholder = $select2.attr('placeholder');
            $select2.select2({placeholder: select2Placeholder});

            // Trigger popover with form field on added label
            /* istanbul ignore next: difficult to test generated popover content */
            $filterLabel.popover({
                html: true,
                title: function () {
                    return filterTitle;
                },
                content: function () {
                    return $popoverContent;
                },
                placement: 'bottom',
                trigger: 'manual'
            });

            // Hide the filter list popover
            $addFilterButton.popover('hide');

            // Show the popover
            $filterLabel.popover('show');

            // Disable the add filter button
            $addFilterButton
                .addClass('is-disabled')
                .attr('disabled', true);

            // Hide the filter list button if no links remaining
            filterListButtonVisibility($filterbar);

            // Focus on field to avoid unnecessary extra click
            if ($field.hasClass('js-select2') && $field.data('init') !== false) {
                $field.select2('open');
            } else {
                /* istanbul ignore next: difficult to test due to generated popover content */
                $field.focus();
            }

            // Enable button when field has value
            /* istanbul ignore next: difficult to test due to field being inside generated popover content */
            $field.on('change keyup', function() {
                if ($field.val()) {
                    $popoverControls
                        .find('[data-ui="add-filter"]')
                        .removeClass('is-disabled')
                        .attr('disabled', false)
                        .attr('aria-disabled', false);
                } else {
                    $popoverControls
                        .find('[data-ui="add-filter"]')
                        .addClass('is-disabled')
                        .attr('disabled', true);
                }
            });
        }
    });
}

/* istanbul ignore next: difficult to test due to field and form controls being inside generated popover content */
function addFilter ($filterbar) {
    $filterbar.on('click', '[data-ui="add-filter"]', function(e) {
        var $field = $(this).closest('.added-popover-content').find('.form__control'),
            $popover = $(this).closest('.popover'),
            $formGroup = $popover.find('.form__group'),
            $label = $popover.prev('.label'),
            $addFilterButton = $filterbar.find('[data-ui="show-filter-list"]'),
            $legend = $filterbar.find('form fieldset legend'),
            values,
            valueForLabel = null,
            filterId;

        e.preventDefault();

        // Check if field is a select2
        if ($field.hasClass('js-select2')) {

            values = $field.select2('data');

            $.each(values, function( index, value ) {
                if (valueForLabel === null) {
                    valueForLabel = value.text;
                } else {
                    valueForLabel = valueForLabel + ', ' + value.text;
                }
            });

        } else {
            valueForLabel = $field.val();
        }

        // Add it to the label
        $label
            .find('.chosen-filter')
            .text(': ' + valueForLabel);

        // Add the remove button to the label
        filterId = $label.attr('data-filter-id');
        $label.append('');

        // Swap classes
        $label
            .removeClass('label--primary')
            .addClass('label--inverse');

        // Hide the field
        $formGroup.addClass('display--none');

        // Move the form group out of the popover and back into the filterbar form
        $formGroup.insertAfter($legend);

        // Close popover and destroy to prevent an empty popover showing on label click
        $label.popover('destroy');

        // Enable add filter button
        $addFilterButton.removeClass('is-disabled')
            .attr('disabled', false)
            .attr('aria-disabled', false);

        // Check if save button should be visible
        formActionsVisibility($filterbar);
    });
}

function removeFilter ($filterbar) {
    var $addFilterButton = $filterbar.find('[data-ui="show-filter-list"]');

    $filterbar.on('click', '[data-ui="filter-cancel"]', function(e) {
        var filterId = $(this).attr('data-filter-id'),
            $legend = $filterbar.find('form fieldset legend'),
            $field = $filterbar.find('#' + filterId),
            $formGroup = $field.closest('.form__group'),
            $label;

        e.preventDefault();

        if ($(this).parents('.popover').length) {
            $label = $(this).closest('.popover').prev('.label');
        } else {
            $label = $(this).closest('.label');
        }

        // Add option back to list
        updateFilterList($addFilterButton, filterId, 'show');

        // Empty values from field
        if ($field[0].type === 'select-one' || $field[0].type === 'select-multiple') {
            $field.find('option:selected').prop('selected', false);
        } else if ($field[0].type === 'checkbox') {
            $field.prop('checked', false);
        } else {
            $field.val('');
        }

        // Destroy select2
        if ($field.hasClass('select2-hidden-accessible')) {
            $field.select2('destroy');
        }

        // Hide the field
        $formGroup.addClass('display--none');

        // Move the form group out of the popover and back into the form
        $formGroup.insertAfter($legend);

        // Remove the popover and label
        $label.popover('hide');
        $label.remove();

        // Enable add filter button
        $addFilterButton
            .removeClass('is-disabled')
            .attr('disabled', false)
            .attr('aria-disabled', false);

        // Find any open add filter button popover
        $addFilterButton.popover('hide');

        // Check if button should be visible
        filterListButtonVisibility($filterbar);

        // Check if save button should be visible
        formActionsVisibility($filterbar);
    });
}

function filterListButtonVisibility ($filterbar) {
    var $addFilterButton = $filterbar.find('[data-ui="show-filter-list"]'),
        addFilterList,
        $addFilterList;

    addFilterList = $addFilterButton.attr('data-content');
    $addFilterList = $(addFilterList);

    if ($addFilterList.find('li:not(.display--none)').length) {
        $addFilterButton.removeClass('display--none');
    } else {
        $addFilterButton.addClass('display--none');
    }
}

function formActionsVisibility ($filterbar) {
    var $formActions = $filterbar.find('.form__actions');

    if ($filterbar.find('.label').length) {
        $formActions.removeClass('display--none');
    } else {
        $formActions.addClass('display--none');
    }
}

function clearAllFilters ($filterbar) {
    var $addFilterButton = $filterbar.find('[data-ui="show-filter-list"]');

    $filterbar.on('click', '[data-ui="clear-all-filters"]', function(e) {

        e.preventDefault();

        // Close filter bar
        $filterbar.addClass('display--none');

        // Remove all labels
        $filterbar.find('.label').remove();

        // Reset filter list
        updateFilterList($addFilterButton, null, 'reset');

        // Hide form actions
        formActionsVisibility($filterbar);

        // Reset form
        $filterbar.find('form').trigger('reset');
    });
}

function updateFilterList ($addFilterButton, filterId, visibility) {
    var addFilterList = $addFilterButton.attr('data-content'),
        $addFilterList = $(addFilterList),
        $filterItem,
        $filterItemParent;

    if (filterId !== null) {
        $filterItem = $addFilterList.find('[data-filter-id="' + filterId + '"]');
        $filterItemParent = $filterItem.parent();
    }

    if (visibility === 'show') {
        $filterItemParent.removeClass('display--none');
    } else if (visibility === 'hide') {
        $filterItemParent.addClass('display--none');
    } else if (visibility === 'reset') {
        $addFilterList.find('li.display--none').removeClass('display--none');
    }

    $addFilterButton.attr('data-content', $addFilterList[0].outerHTML);
}

/**
 *   Fired on load, this reads the values of the hidden filters form and
 *   populates the filterbar with the required labels.
**/
function populateFilterList ($filterbar) {

    var $formGroups = $filterbar.find('.form__group'),
        $labelContainer = $filterbar.find('.filter-bar__labels'),
        $addFilterButton = $filterbar.find('[data-ui="show-filter-list"]');

    $formGroups.each(function() {
        var $this = $(this),
            $filterField = $this.find('.form__control'),
            filterId = $filterField.attr('id'),
            filterLabel = $this.find('.control__label').text().trim(),
            filterValue = $filterField.val();

        if ($filterField.hasClass('select')) {
            filterValue = $(':selected', $filterField).text();
        }

        if ($filterField[0].type === 'checkbox') {
            if ($filterField.prop('checked') === true) {
                filterValue = ' ';
            } else {
                filterValue = '';
            }
        } else {
            filterLabel = filterLabel + ': ';
        }

        if (filterValue !== '' && filterValue !== null) {
            $labelContainer.prepend('' + filterLabel + filterValue + '');

            // Hide the filter item in the list
            updateFilterList($addFilterButton, filterId, 'hide');

            // Show the filterbar
            $filterbar.removeClass('display--none');
        }
    });
}

module.exports = FilterBarComponent;
<commit_msg>Removed aria-expanded as we don’t currently toggle that with the popover js<commit_after>'use strict';

var $ = require('jquery');

function FilterBarComponent(html) {
    this.$html = html;
}

FilterBarComponent.prototype.init = function () {
    var component = this;

    this.$container = this.$html.find('.filter-bar');

    this.$container.each(function() {
        var $filterbar = $(this);

        // Create the filter add button
        createFilterListButton($filterbar);

        // Hide the form elements
        hideFormControls($filterbar);

        // Move save button
        moveFormActions($filterbar);

        // Handlers
        showFilterBar(component, $filterbar);
        populateFilterList($filterbar);
        showAddFilterPopover($filterbar);
        addFilter($filterbar);
        removeFilter($filterbar);
        clearAllFilters($filterbar);
    });
};

function showFilterBar (component, $filterbar) {

    component.$html.on('click', '[data-ui="show-filter-bar"]', function(e) {
        var $addFilterButton = $filterbar.find('[data-ui="show-filter-list"]');

        e.preventDefault();

        // Show add button if hidden by clear
        $addFilterButton.removeClass('display--none');

        // Show filter bar
        $filterbar.removeClass('display--none');
    });
}

function createFilterListButton ($filterbar) {
    var $formGroups = $filterbar.find('.form__group'),
        $addFilterButton,
        $filterList = $('

'),
        $filterLabelsWrapper = $('

');

    // Loop through form groups
    $formGroups.each(function() {
        $filterList.append('
'+ $(this).find('.control__label').text() +'
');
    });

    // Build up list and mark up for Add filter button
    $addFilterButton = $('<button class="btn filter-bar__add" data-ui="show-filter-list" data-toggle="popover" data-trigger="click" title="Filter by" data-html="true" data-placement="bottom" data-content="" aria-haspopup="true">Add</button>');
    $addFilterButton.attr('data-content', $filterList[0].outerHTML);

    // Append button and label wrapper
    $filterLabelsWrapper.appendTo($filterbar.find('fieldset'));
    $addFilterButton.appendTo($filterLabelsWrapper);

    // Initialize popover
    $addFilterButton.popover();

    // Prevent default on button
    $filterbar.on('click', '[data-ui="show-filter-list"]', function(e) {
        e.preventDefault();
    });
}

function hideFormControls ($filterbar) {
    $filterbar
        .find('.form__group')
        .addClass('display--none');
    $filterbar
        .find('.form__actions')
        .addClass('display--none');
}

function moveFormActions ($filterbar) {
    var $formActions = $filterbar.find('.form__actions'),
        $fieldset = $filterbar.find('fieldset');

    $formActions.appendTo($fieldset);
    $formActions.addClass('display--none');
}

function showAddFilterPopover ($filterbar) {
    var filterTitle,
        filterId,
        select2Placeholder,
        $formGroup,
        $filterLabel,
        $popoverControls,
        $popoverContent,
        $field,
        $select2,
        $addFilterButton = $filterbar.find('[data-ui="show-filter-list"]');

    $filterbar.on('click', '[data-ui="filter-item"]', function(e) {
        e.preventDefault();

        filterTitle = $(this).attr('data-filter-title');
        filterId = $(this).attr('data-filter-id');
        $field = $filterbar.find('#' + filterId);

        // Hide the filter item in the list
        updateFilterList($addFilterButton, filterId, 'hide');

        // Add new filter label
        $filterLabel = $('' + filterTitle + ' ');
        $filterLabel.insertBefore($addFilterButton);

        // If checkbox, check it but no need to display it or move to popover
        if ($field[0].type === 'checkbox') {

            // Hide the filter list popover
            $addFilterButton.popover('hide');

            // Check the checkbox
            $field.prop('checked', true);

            // Add the remove button to the label
            filterId = $filterLabel.attr('data-filter-id');
            $filterLabel.append('');

            // Add the label
            $filterLabel
                .removeClass('label--primary')
                .addClass('label--inverse');

            // Hide the filter list button if no links remaining
            filterListButtonVisibility($filterbar);

            // Check if save button should be visible
            formActionsVisibility($filterbar);

        } else {

            // Create content for the popover
            $popoverContent = $('

');

            // Move the field into the popover content
            $formGroup = $filterbar.find('#' + filterId).closest('.form__group');
            $formGroup.appendTo($popoverContent);
            $formGroup.addClass('form__group--flush');

            // Hide the control label
            $formGroup
                .removeClass('display--none')
                .find('.control__label')
                    .addClass('hide');

            // Add popover controls
            $popoverControls = $('
<button type="submit" class="btn btn--primary is-disabled" data-ui="add-filter" disabled="disabled">Add</button>Cancel
');
            $popoverControls.insertAfter($formGroup);

            // Refresh the select2
            $select2 = $popoverContent.find('.js-select2:not([data-init="false"])');
            select2Placeholder = $select2.attr('placeholder');
            $select2.select2({placeholder: select2Placeholder});

            // Trigger popover with form field on added label
            /* istanbul ignore next: difficult to test generated popover content */
            $filterLabel.popover({
                html: true,
                title: function () {
                    return filterTitle;
                },
                content: function () {
                    return $popoverContent;
                },
                placement: 'bottom',
                trigger: 'manual'
            });

            // Hide the filter list popover
            $addFilterButton.popover('hide');

            // Show the popover
            $filterLabel.popover('show');

            // Disable the add filter button
            $addFilterButton
                .addClass('is-disabled')
                .attr('disabled', true);

            // Hide the filter list button if no links remaining
            filterListButtonVisibility($filterbar);

            // Focus on field to avoid unnecessary extra click
            if ($field.hasClass('js-select2') && $field.data('init') !== false) {
                $field.select2('open');
            } else {
                /* istanbul ignore next: difficult to test due to generated popover content */
                $field.focus();
            }

            // Enable button when field has value
            /* istanbul ignore next: difficult to test due to field being inside generated popover content */
            $field.on('change keyup', function() {
                if ($field.val()) {
                    $popoverControls
                        .find('[data-ui="add-filter"]')
                        .removeClass('is-disabled')
                        .attr('disabled', false)
                        .attr('aria-disabled', false);
                } else {
                    $popoverControls
                        .find('[data-ui="add-filter"]')
                        .addClass('is-disabled')
                        .attr('disabled', true);
                }
            });
        }
    });
}

/* istanbul ignore next: difficult to test due to field and form controls being inside generated popover content */
function addFilter ($filterbar) {
    $filterbar.on('click', '[data-ui="add-filter"]', function(e) {
        var $field = $(this).closest('.added-popover-content').find('.form__control'),
            $popover = $(this).closest('.popover'),
            $formGroup = $popover.find('.form__group'),
            $label = $popover.prev('.label'),
            $addFilterButton = $filterbar.find('[data-ui="show-filter-list"]'),
            $legend = $filterbar.find('form fieldset legend'),
            values,
            valueForLabel = null,
            filterId;

        e.preventDefault();

        // Check if field is a select2
        if ($field.hasClass('js-select2')) {

            values = $field.select2('data');

            $.each(values, function( index, value ) {
                if (valueForLabel === null) {
                    valueForLabel = value.text;
                } else {
                    valueForLabel = valueForLabel + ', ' + value.text;
                }
            });

        } else {
            valueForLabel = $field.val();
        }

        // Add it to the label
        $label
            .find('.chosen-filter')
            .text(': ' + valueForLabel);

        // Add the remove button to the label
        filterId = $label.attr('data-filter-id');
        $label.append('');

        // Swap classes
        $label
            .removeClass('label--primary')
            .addClass('label--inverse');

        // Hide the field
        $formGroup.addClass('display--none');

        // Move the form group out of the popover and back into the filterbar form
        $formGroup.insertAfter($legend);

        // Close popover and destroy to prevent an empty popover showing on label click
        $label.popover('destroy');

        // Enable add filter button
        $addFilterButton.removeClass('is-disabled')
            .attr('disabled', false)
            .attr('aria-disabled', false);

        // Check if save button should be visible
        formActionsVisibility($filterbar);
    });
}

function removeFilter ($filterbar) {
    var $addFilterButton = $filterbar.find('[data-ui="show-filter-list"]');

    $filterbar.on('click', '[data-ui="filter-cancel"]', function(e) {
        var filterId = $(this).attr('data-filter-id'),
            $legend = $filterbar.find('form fieldset legend'),
            $field = $filterbar.find('#' + filterId),
            $formGroup = $field.closest('.form__group'),
            $label;

        e.preventDefault();

        if ($(this).parents('.popover').length) {
            $label = $(this).closest('.popover').prev('.label');
        } else {
            $label = $(this).closest('.label');
        }

        // Add option back to list
        updateFilterList($addFilterButton, filterId, 'show');

        // Empty values from field
        if ($field[0].type === 'select-one' || $field[0].type === 'select-multiple') {
            $field.find('option:selected').prop('selected', false);
        } else if ($field[0].type === 'checkbox') {
            $field.prop('checked', false);
        } else {
            $field.val('');
        }

        // Destroy select2
        if ($field.hasClass('select2-hidden-accessible')) {
            $field.select2('destroy');
        }

        // Hide the field
        $formGroup.addClass('display--none');

        // Move the form group out of the popover and back into the form
        $formGroup.insertAfter($legend);

        // Remove the popover and label
        $label.popover('hide');
        $label.remove();

        // Enable add filter button
        $addFilterButton
            .removeClass('is-disabled')
            .attr('disabled', false)
            .attr('aria-disabled', false);

        // Find any open add filter button popover
        $addFilterButton.popover('hide');

        // Check if button should be visible
        filterListButtonVisibility($filterbar);

        // Check if save button should be visible
        formActionsVisibility($filterbar);
    });
}

function filterListButtonVisibility ($filterbar) {
    var $addFilterButton = $filterbar.find('[data-ui="show-filter-list"]'),
        addFilterList,
        $addFilterList;

    addFilterList = $addFilterButton.attr('data-content');
    $addFilterList = $(addFilterList);

    if ($addFilterList.find('li:not(.display--none)').length) {
        $addFilterButton.removeClass('display--none');
    } else {
        $addFilterButton.addClass('display--none');
    }
}

function formActionsVisibility ($filterbar) {
    var $formActions = $filterbar.find('.form__actions');

    if ($filterbar.find('.label').length) {
        $formActions.removeClass('display--none');
    } else {
        $formActions.addClass('display--none');
    }
}

function clearAllFilters ($filterbar) {
    var $addFilterButton = $filterbar.find('[data-ui="show-filter-list"]');

    $filterbar.on('click', '[data-ui="clear-all-filters"]', function(e) {

        e.preventDefault();

        // Close filter bar
        $filterbar.addClass('display--none');

        // Remove all labels
        $filterbar.find('.label').remove();

        // Reset filter list
        updateFilterList($addFilterButton, null, 'reset');

        // Hide form actions
        formActionsVisibility($filterbar);

        // Reset form
        $filterbar.find('form').trigger('reset');
    });
}

function updateFilterList ($addFilterButton, filterId, visibility) {
    var addFilterList = $addFilterButton.attr('data-content'),
        $addFilterList = $(addFilterList),
        $filterItem,
        $filterItemParent;

    if (filterId !== null) {
        $filterItem = $addFilterList.find('[data-filter-id="' + filterId + '"]');
        $filterItemParent = $filterItem.parent();
    }

    if (visibility === 'show') {
        $filterItemParent.removeClass('display--none');
    } else if (visibility === 'hide') {
        $filterItemParent.addClass('display--none');
    } else if (visibility === 'reset') {
        $addFilterList.find('li.display--none').removeClass('display--none');
    }

    $addFilterButton.attr('data-content', $addFilterList[0].outerHTML);
}

/**
 *   Fired on load, this reads the values of the hidden filters form and
 *   populates the filterbar with the required labels.
**/
function populateFilterList ($filterbar) {

    var $formGroups = $filterbar.find('.form__group'),
        $labelContainer = $filterbar.find('.filter-bar__labels'),
        $addFilterButton = $filterbar.find('[data-ui="show-filter-list"]');

    $formGroups.each(function() {
        var $this = $(this),
            $filterField = $this.find('.form__control'),
            filterId = $filterField.attr('id'),
            filterLabel = $this.find('.control__label').text().trim(),
            filterValue = $filterField.val();

        if ($filterField.hasClass('select')) {
            filterValue = $(':selected', $filterField).text();
        }

        if ($filterField[0].type === 'checkbox') {
            if ($filterField.prop('checked') === true) {
                filterValue = ' ';
            } else {
                filterValue = '';
            }
        } else {
            filterLabel = filterLabel + ': ';
        }

        if (filterValue !== '' && filterValue !== null) {
            $labelContainer.prepend('' + filterLabel + filterValue + '');

            // Hide the filter item in the list
            updateFilterList($addFilterButton, filterId, 'hide');

            // Show the filterbar
            $filterbar.removeClass('display--none');
        }
    });
}

module.exports = FilterBarComponent;
<|endoftext|>


<commit_before>
// Reference to the root of the Firebase database
var database = new Firebase("https://conquiz.firebaseio.com/");
var gamebase = new Firebase("https://towercoord.firebaseio.com/");
var coordbase = gamebase.child("-K2aUIZRYFI5l6Tov1JA");
var towerbase = coordbase.child("towers");
var playerbase = coordbase.child("players");
var troopbase = coordbase.child("troops");
// Reference to the google sheets of questions
var questionsLink = 'https://spreadsheets.google.com/feeds/list/1C1POJrIlpm1R3muE0ImmI_ifxpH_aEfPP-QSyl3o2Kg/1/public/basic?alt=json';

var question;
var questionJSON;
var rows;

/*--------------------------------------------*/
/*---> Get Game -> Whole game dir <-----------*/
/*--------------------------------------------*/
function getGame() {
	//var gameHolder = []; // for futre updates with multi-lobby
	var newGame;
	coordbase.on('child_added', function(update){
		var gameJSON = update.val();
		newGame = new Game({
			id: gameJSON['id'],
			moode: gameJSON['mode'],
			name: gameJSON['name'],
			players: loadPlayers(),
			questions: loadQuestions(),
			//questions: [],
			questionLength: parseFloat(gameJSON['questionLength']),
			rounds: parseFloat(gameJSON['rounds']),
			spawnRate: parseFloat(gameJSON['spawnRate']),
			taskManager: null,
			towers: loadTowers(),
			troops: loadTroops()
		});
	});
	//console.log(newGame)
	return newGame;
}

/*--------------------------------------------*/
/*---> Download Task from Firebase <----------*/
/*--------------------------------------------*/
function loadTasks() {

}

/*--------------------------------------------*/
/*---> Download troops from Firebase <--------*/
/*--------------------------------------------*/
function loadTroops() {
	var troopHolder = [];
	var newTroop;
	troopbase.on('child_added', function(update){
		if (update['Empty'] != "DoNotDelete") { //Stops the empty from being pulled
			var troopJSON = update.val();
			newTroop = new Troop({
				id: update['id'],
				name: update['name'],
				playerID: update['playerID'],
				towerID: update['towerID'],
				question: update['question'],
				alive: update['alive']
			});
			troopHolder.push(newTroop);
		}

	});
	return troopHolder;
}

/*--------------------------------------------*/
/*---> Upload troops to Firebase <------------*/
/*--------------------------------------------*/
function uploadTroops(data) {
	$.each(data, function(index, value){
		troopbase.push({
			id: value['id'],
			name: value['name'],
			playerID: value['playerID'],
			towerID: value['towerID'],
			question: value['question'],
			alive: value['alive']
		});
	});
	setDefaultTroops();
}
function setDefaultTroops(){
		towerbase.once('value', function(snapshot){
		snapshot.forEach(function(childSnapshot){
			var child = childSnapshot.val();
			var path = new Firebase(towerbase.child(childSnapshot.key()).toString());
			path.set({
				id: childSnapshot.key(),
				name: child['name'],
				playerID: child['playerID'],
				towerID: child['towerID'],
				question: child['question'],
				alive: child['child']
			});
		});
	});
}
function updateTroops(data) {
	$.each(data, function(index, value){
		var path = new Firebase(troopbase.child(value['id']).toString());
		if (value['alive'] == false) {
			path.remove();
		} else {
			path.set({
				id: value['id'],
				name: value['name'],
				playerID: value['playerID'],
				towerID: value['towerID'],
				question: value['question'],
				alive: value['alive']
			});
		}
	});
}
// This will remove all the troops in the troops folder
function removeTroops(data) {
	$.each(data, function(index, value){
		var path = new Firebase(troopbase.child(value['id']).toString());
		path.remove();
	});
}

/*--------------------------------------------*/
/*---> Download player from Firebase <--------*/
/*--------------------------------------------*/
function loadPlayers() {
	var playerHolder = [];
	var newPlayer;
	playerbase.on('child_added', function(update) {
		var playerJSON = update.val();
		newPlayer = new Player({
			id: playerJSON['id'],
			icon: playerJSON['icon'],
			color: playerJSON['color'],
			latitude: playerJSON['latitude'],
			longitude: playerJSON['longitude'],
			troops: JSON.stringify(playerJSON['troops'])
		});
		playerHolder.push(newPlayer);
	});
	return playerHolder;
}

/*--------------------------------------------*/
/*---> Upload player to Firebase <------------*/
/*--------------------------------------------*/
function uploadPlayerbase(data) {
	$.each(data, function(index, value){
		playerbase.push({
			id: value['id'],
			name: value['name'],
			icon: value['team']['icon'],
			color: value['team']['color'],
			latitude: value['coordinate']['latitude'],
			longitude: value['coordinate']['longitude'],
			troops: JSON.stringify(value['troops'])
		});
	});
	setDefaultPlayer();
}
function setDefaultPlayer(){
	playerbase.once('value', function(snapshot){
		snapshot.forEach(function(childSnapshot){
			var path = new Firebase(playerbase.child(childSnapshot.key()).toString());
			path.set({
				id: childSnapshot.key(),
				name: "",
				icon: "png",
				color: "blue",
				latitude: 0,
				longitude: 0,
				troops: "[]"
			});
		});
	});
}

function updatePlayerbase(data) {
	$.each(data, function(index, value){
		var path = new Firebase(playerbase.child(value['id']).toString());
		path.set({
			id: value['id'],
			name: value['name'],
			icon: value['team']['icon'],
			color: value['team']['color'],
			latitude: value['coordinate']['latitude'],
			longitude: value['coordinate']['longitude'],
			troops: JSON.stringify(value['troops'])
		});
	});
}

/*--------------------------------------------*/
/*---> Download towers from Firebase <--------*/
/*--------------------------------------------*/
function loadTowers() {
	var towerHolder = [];
	var newTower;
	towerbase.on('child_added', function(update) {
		var towerJSON = update.val();
		//console.log(towerJSON);
		newTower = new Tower({
			id: towerJSON['id'],
			name: towerJSON['name'],
			coordinate: {latitude: towerJSON['latitude'], longitude: towerJSON['longitude']},
			size: towerJSON['size'],
			player: JSON.stringify(towerJSON['player']),
			troops: "[]"
		});
		towerHolder.push(newTower);
	});
	return towerHolder;
}

/*--------------------------------------------*/
/*---> Upload towers to Firebase <------------*/
/*--------------------------------------------*/
function uploadTowerbase(data) {
	$.each(data, function(index, value){
		towerbase.push({id: value['id'],
			name: value['name'],
			latitude: value['coordinate']['latitude'],
			longitude: value['coordinate']['longitude'],
			size: value['size'],
			player: value['player'] });
	});
	setDefaultTower();
}
function setDefaultTower(){
	towerbase.once('value', function(snapshot){
		snapshot.forEach(function(childSnapshot){
			var path = new Firebase(towerbase.child(childSnapshot.key()).toString());
			path.set({
				id: childSnapshot.key(),
				name: "",
				latitude: 0,
				longitude: 0,
				size: 10,
				player: ""
			});
		});
	});
}

function updateTowerbase(data) {
	$.each(data, function(index, value){
		var path = new Firebase(towerbase.child(value['id']).toString());
		path.set({
			id: value['id'],
			name: value['name'],
			latitude: value['coordinate']['latitude'],
			longitude: value['coordinate']['longitude'],
			size: value['size'],
			player: value['player']
		});
	});
}
// Don't have time - going for hard code
function removeTowerbase() {
	// ToDO: Remove the towers folders which will remove the subfolders, recreate a towers folder.
}

/*--------------------------------------------*/
/*---> Download question from Firebase <------*/
/*--------------------------------------------*/
function loadQuestions() {
	var questionHolder = [];
    var newQuestion;
    database.on('child_added', function(update) {
        var questionJSON = update.val();
        newQuestion = new Question({
            //id: generateNewID('questions'),
            id: 'question-filler',
            question: questionJSON['question'],
            answers: "["+questionJSON['correct']+", "+questionJSON['wa1']+", "+questionJSON['wa2']+", "+questionJSON['wa3']+"]"
        });
        questionHolder.push(newQuestion);
    });
    return questionHolder;
}

/*--------------------------------------------*/
/*---> Upload question to Firebase <----------*/
// ONE TIME push to update the questions on firebase
/*--------------------------------------------*/
function getData() {
    $.ajax({
        url: questionsLink,
        success: function(data){
            uploadFirebase(data);
        }
    });
}
// upload data to firebase
function uploadFirebase(data){
    var cells = data.feed.entry;
    rows = [];

    for (var i = 0; i < cells.length; i++){
        var rowObj = {};
        rowObj.timestamp = cells[i].title.$t;
        var rowCols = cells[i].content.$t.split(',');
        for (var j = 0; j < rowCols.length; j++){
            var keyVal = rowCols[j].split(':');
            rowObj[keyVal[0].trim()] = keyVal[1].trim();
        }
        rows.push(rowObj);
    }
    for (var i = 0; i < rows.length; i++) {
    	database.push({question: rows[i]['timestamp'], correct: rows[i]['correct'], wa1: rows[i]['wa1'], wa2: rows[i]['wa2'], wa3: rows[i]['wa3']});
    }
}

console.log('LOADED BACKEND');

/* Legacy code

$("#upload").click(function() { // If the user clicks on the input with the id="upload"
	var name = $("#nameInput").val();
	var text = $("#messageInput").val();
	if (name.length != 0 && text.length != 0) { // Don't upload if there's no information in the textboxes
		console.log(name.length);
		console.log(text.length);

		database.push({name: name, text: text}); // Push the data onto the database

	}else { // warns user of their empty textbox
		console.log("Please input values into the textbox");
	}
});

function displayUpdate(name, text) {
	$("<div/>").text(text).prepend($("<em/>").text(name+": ")).appendTo($("#messageDiv"));
	$("#messageDiv")[0].scrollTop = $("#messageDiv")[0].scrollHeight;
};

database.on("child_added", function(update) { // Get an update once the database has new data
	console.log("Callback function: New data has been added to the database");
	var message = update.val();
	displayUpdate(message.name, message.text);
});

*/
<commit_msg>Uncommented default<commit_after>
// Reference to the root of the Firebase database
var database = new Firebase("https://conquiz.firebaseio.com/");
var gamebase = new Firebase("https://towercoord.firebaseio.com/");
var coordbase = gamebase.child("-K2aUIZRYFI5l6Tov1JA");
var towerbase = coordbase.child("towers");
var playerbase = coordbase.child("players");
var troopbase = coordbase.child("troops");
// Reference to the google sheets of questions
var questionsLink = 'https://spreadsheets.google.com/feeds/list/1C1POJrIlpm1R3muE0ImmI_ifxpH_aEfPP-QSyl3o2Kg/1/public/basic?alt=json';

var question;
var questionJSON;
var rows;

/*--------------------------------------------*/
/*---> Get Game -> Whole game dir <-----------*/
/*--------------------------------------------*/
function getGame() {
	//var gameHolder = []; // for futre updates with multi-lobby
	var newGame;
	coordbase.on('child_added', function(update){
		var gameJSON = update.val();
		newGame = new Game({
			id: gameJSON['id'],
			moode: gameJSON['mode'],
			name: gameJSON['name'],
			players: loadPlayers(),
			questions: loadQuestions(),
			//questions: [],
			questionLength: parseFloat(gameJSON['questionLength']),
			rounds: parseFloat(gameJSON['rounds']),
			spawnRate: parseFloat(gameJSON['spawnRate']),
			taskManager: null,
			towers: loadTowers(),
			troops: loadTroops()
		});
	});
	//console.log(newGame)
	return newGame;
}

/*--------------------------------------------*/
/*---> Download Task from Firebase <----------*/
/*--------------------------------------------*/
function loadTasks() {

}

/*--------------------------------------------*/
/*---> Download troops from Firebase <--------*/
/*--------------------------------------------*/
function loadTroops() {
	var troopHolder = [];
	var newTroop;
	troopbase.on('child_added', function(update){
		if (update['Empty'] != "DoNotDelete") { //Stops the empty from being pulled
			var troopJSON = update.val();
			newTroop = new Troop({
				id: update['id'],
				name: update['name'],
				playerID: update['playerID'],
				towerID: update['towerID'],
				question: update['question'],
				alive: update['alive']
			});
			troopHolder.push(newTroop);
		}

	});
	return troopHolder;
}

/*--------------------------------------------*/
/*---> Upload troops to Firebase <------------*/
/*--------------------------------------------*/
function uploadTroops(data) {
	$.each(data, function(index, value){
		troopbase.push({
			id: value['id'],
			name: value['name'],
			playerID: value['playerID'],
			towerID: value['towerID'],
			question: value['question'],
			alive: value['alive']
		});
	});
	setDefaultTroops();
}
function setDefaultTroops(){
		towerbase.once('value', function(snapshot){
		snapshot.forEach(function(childSnapshot){
			var child = childSnapshot.val();
			var path = new Firebase(towerbase.child(childSnapshot.key()).toString());
			path.set({
				id: childSnapshot.key(),
				name: child['name'],
				playerID: child['playerID'],
				towerID: child['towerID'],
				question: child['question'],
				alive: child['child']
			});
		});
	});
}
function updateTroops(data) {
	$.each(data, function(index, value){
		var path = new Firebase(troopbase.child(value['id']).toString());
		if (value['alive'] == false) {
			path.remove();
		} else {
			path.set({
				id: value['id'],
				name: value['name'],
				playerID: value['playerID'],
				towerID: value['towerID'],
				question: value['question'],
				alive: value['alive']
			});
		}
	});
}
// This will remove all the troops in the troops folder
function removeTroops(data) {
	$.each(data, function(index, value){
		var path = new Firebase(troopbase.child(value['id']).toString());
		path.remove();
	});
}

/*--------------------------------------------*/
/*---> Download player from Firebase <--------*/
/*--------------------------------------------*/
function loadPlayers() {
	var playerHolder = [];
	var newPlayer;
	playerbase.on('child_added', function(update) {
		var playerJSON = update.val();
		newPlayer = new Player({
			id: playerJSON['id'],
			icon: playerJSON['icon'],
			color: playerJSON['color'],
			latitude: playerJSON['latitude'],
			longitude: playerJSON['longitude'],
			troops: JSON.stringify(playerJSON['troops'])
		});
		playerHolder.push(newPlayer);
	});
	return playerHolder;
}

/*--------------------------------------------*/
/*---> Upload player to Firebase <------------*/
/*--------------------------------------------*/
function uploadPlayerbase(data) {
	$.each(data, function(index, value){
		playerbase.push({
			id: value['id'],
			name: value['name'],
			icon: value['team']['icon'],
			color: value['team']['color'],
			latitude: value['coordinate']['latitude'],
			longitude: value['coordinate']['longitude'],
			troops: JSON.stringify(value['troops'])
		});
	});
	setDefaultPlayer();
}
function setDefaultPlayer(){
	playerbase.once('value', function(snapshot){
		snapshot.forEach(function(childSnapshot){
			var path = new Firebase(playerbase.child(childSnapshot.key()).toString());
			path.set({
				id: childSnapshot.key(),
				name: "",
				icon: "png",
				color: "blue",
				latitude: 0,
				longitude: 0,
				troops: "[]"
			});
		});
	});
}

function updatePlayerbase(data) {
	$.each(data, function(index, value){
		var path = new Firebase(playerbase.child(value['id']).toString());
		path.set({
			id: value['id'],
			name: value['name'],
			icon: value['team']['icon'],
			color: value['team']['color'],
			latitude: value['coordinate']['latitude'],
			longitude: value['coordinate']['longitude'],
			troops: JSON.stringify(value['troops'])
		});
	});
}

/*--------------------------------------------*/
/*---> Download towers from Firebase <--------*/
/*--------------------------------------------*/
function loadTowers() {
	var towerHolder = [];
	var newTower;
	towerbase.on('child_added', function(update) {
		var towerJSON = update.val();
		//console.log(towerJSON);
		newTower = new Tower({
			id: towerJSON['id'],
			name: towerJSON['name'],
			coordinate: {latitude: towerJSON['latitude'], longitude: towerJSON['longitude']},
			size: towerJSON['size'],
			player: JSON.stringify(towerJSON['player']),
			troops: "[]"
		});
		towerHolder.push(newTower);
	});
	return towerHolder;
}

/*--------------------------------------------*/
/*---> Upload towers to Firebase <------------*/
/*--------------------------------------------*/
function uploadTowerbase(data) {
	$.each(data, function(index, value){
		towerbase.push({id: value['id'],
			name: value['name'],
			latitude: value['coordinate']['latitude'],
			longitude: value['coordinate']['longitude'],
			size: value['size'],
			player: value['player'] });
	});
	//setDefaultTower();
}
function setDefaultTower(){
	towerbase.once('value', function(snapshot){
		snapshot.forEach(function(childSnapshot){
			var path = new Firebase(towerbase.child(childSnapshot.key()).toString());
			path.set({
				id: childSnapshot.key(),
				name: "",
				latitude: 0,
				longitude: 0,
				size: 10,
				player: ""
			});
		});
	});
}

function updateTowerbase(data) {
	$.each(data, function(index, value){
		var path = new Firebase(towerbase.child(value['id']).toString());
		path.set({
			id: value['id'],
			name: value['name'],
			latitude: value['coordinate']['latitude'],
			longitude: value['coordinate']['longitude'],
			size: value['size'],
			player: value['player']
		});
	});
}
// Don't have time - going for hard code
function removeTowerbase() {
	// ToDO: Remove the towers folders which will remove the subfolders, recreate a towers folder.
}

/*--------------------------------------------*/
/*---> Download question from Firebase <------*/
/*--------------------------------------------*/
function loadQuestions() {
	var questionHolder = [];
    var newQuestion;
    database.on('child_added', function(update) {
        var questionJSON = update.val();
        newQuestion = new Question({
            //id: generateNewID('questions'),
            id: 'question-filler',
            question: questionJSON['question'],
            answers: "["+questionJSON['correct']+", "+questionJSON['wa1']+", "+questionJSON['wa2']+", "+questionJSON['wa3']+"]"
        });
        questionHolder.push(newQuestion);
    });
    return questionHolder;
}

/*--------------------------------------------*/
/*---> Upload question to Firebase <----------*/
// ONE TIME push to update the questions on firebase
/*--------------------------------------------*/
function getData() {
    $.ajax({
        url: questionsLink,
        success: function(data){
            uploadFirebase(data);
        }
    });
}
// upload data to firebase
function uploadFirebase(data){
    var cells = data.feed.entry;
    rows = [];

    for (var i = 0; i < cells.length; i++){
        var rowObj = {};
        rowObj.timestamp = cells[i].title.$t;
        var rowCols = cells[i].content.$t.split(',');
        for (var j = 0; j < rowCols.length; j++){
            var keyVal = rowCols[j].split(':');
            rowObj[keyVal[0].trim()] = keyVal[1].trim();
        }
        rows.push(rowObj);
    }
    for (var i = 0; i < rows.length; i++) {
    	database.push({question: rows[i]['timestamp'], correct: rows[i]['correct'], wa1: rows[i]['wa1'], wa2: rows[i]['wa2'], wa3: rows[i]['wa3']});
    }
}

console.log('LOADED BACKEND');

/* Legacy code

$("#upload").click(function() { // If the user clicks on the input with the id="upload"
	var name = $("#nameInput").val();
	var text = $("#messageInput").val();
	if (name.length != 0 && text.length != 0) { // Don't upload if there's no information in the textboxes
		console.log(name.length);
		console.log(text.length);

		database.push({name: name, text: text}); // Push the data onto the database

	}else { // warns user of their empty textbox
		console.log("Please input values into the textbox");
	}
});

function displayUpdate(name, text) {
	$("<div/>").text(text).prepend($("<em/>").text(name+": ")).appendTo($("#messageDiv"));
	$("#messageDiv")[0].scrollTop = $("#messageDiv")[0].scrollHeight;
};

database.on("child_added", function(update) { // Get an update once the database has new data
	console.log("Callback function: New data has been added to the database");
	var message = update.val();
	displayUpdate(message.name, message.text);
});

*/
<|endoftext|>


<commit_before>'use strict';

var $ = require('jquery');

function FilterBarComponent(html) {
    this.$html = html;
}

FilterBarComponent.prototype.init = function () {
    var component = this;

    this.$container = this.$html.find('.filter-bar');

    this.$container.each(function() {
        var $filterbar = $(this);

        // Create the filter add button
        createFilterListButton($filterbar);

        // Hide the form elements
        hideFormControls($filterbar);

        // Move save button
        moveFormActions($filterbar);

        // Handlers
        showFilterBar(component, $filterbar);
        populateFilterList($filterbar);
        showAddFilterPopover($filterbar);
        addFilter($filterbar);
        removeFilter($filterbar);
        clearAllFilters($filterbar);
    });
};

function showFilterBar (component, $filterbar) {

    component.$html.on('click', '[data-ui="show-filter-bar"]', function(e) {
        var $addFilterButton = $filterbar.find('[data-ui="show-filter-list"]');

        e.preventDefault();

        // Show add button if hidden by clear
        $addFilterButton.removeClass('display--none');

        // Show filter bar
        $filterbar.removeClass('display--none');
    });
}

function createFilterListButton ($filterbar) {
    var $formGroups = $filterbar.find('.form__group'),
        $addFilterButton,
        $filterList = $('

'),
        $filterLabelsWrapper = $('

');

    // Loop through form groups
    $formGroups.each(function() {
        $filterList.append('
'+ $(this).find('.control__label').text() +'
');
    });

    // Build up list and mark up for Add filter button
    $addFilterButton = $('<button class="btn filter-bar__add" role="button" data-ui="show-filter-list" data-toggle="popover" data-trigger="click" title="Filter by" data-html="true" data-placement="bottom" data-content=""></button>');
    $addFilterButton.attr('data-content', $filterList[0].outerHTML);

    // Append button and label wrapper
    $filterLabelsWrapper.appendTo($filterbar.find('fieldset'));
    $addFilterButton.appendTo($filterLabelsWrapper);

    // Initialize popover
    $addFilterButton.popover();

    // Prevent default on button
    $filterbar.on('click', '[data-ui="show-filter-list"]', function(e) {
        e.preventDefault();
    });
}

function hideFormControls ($filterbar) {
    $filterbar
        .find('.form__group')
        .addClass('display--none');
    $filterbar
        .find('.form__actions')
        .addClass('display--none');
}

function moveFormActions ($filterbar) {
    var $formActions = $filterbar.find('.form__actions'),
        $fieldset = $filterbar.find('fieldset');

    $formActions.appendTo($fieldset);
    $formActions.addClass('display--none');
}

function showAddFilterPopover ($filterbar) {
    var filterTitle,
        filterId,
        select2Placeholder,
        $formGroup,
        $filterLabel,
        $popoverControls,
        $popoverContent,
        $field,
        $select2,
        $addFilterButton = $filterbar.find('[data-ui="show-filter-list"]');

    $filterbar.on('click', '[data-ui="filter-item"]', function(e) {
        e.preventDefault();

        filterTitle = $(this).attr('data-filter-title');
        filterId = $(this).attr('data-filter-id');
        $field = $filterbar.find('#' + filterId);

        // Hide the filter item in the list
        updateFilterList($addFilterButton, filterId, 'hide');

        // Add new filter label
        $filterLabel = $('' + filterTitle + ' ');
        $filterLabel.insertBefore($addFilterButton);

        // If checkbox, check it but no need to display it or move to popover
        if ($field[0].type === 'checkbox') {

            // Hide the filter list popover
            $addFilterButton.popover('hide');

            // Check the checkbox
            $field.prop('checked', true);

            // Add the remove button to the label
            filterId = $filterLabel.attr('data-filter-id');
            $filterLabel.append('');

            // Add the label
            $filterLabel
                .removeClass('label--primary')
                .addClass('label--inverse');

            // Hide the filter list button if no links remaining
            filterListButtonVisibility($filterbar);

            // Check if save button should be visible
            formActionsVisibility($filterbar);

        } else {

            // Create content for the popover
            $popoverContent = $('

');

            // Move the field into the popover content
            $formGroup = $filterbar.find('#' + filterId).closest('.form__group');
            $formGroup.appendTo($popoverContent);
            $formGroup.addClass('form__group--flush');

            // Hide the control label
            $formGroup
                .removeClass('display--none')
                .find('.control__label')
                    .addClass('hide');

            // Add popover controls
            $popoverControls = $('
<button type="submit" class="btn btn--primary is-disabled" data-ui="add-filter" disabled="disabled">Add</button>Cancel
');
            $popoverControls.insertAfter($formGroup);

            // Refresh the select2
            $select2 = $popoverContent.find('.js-select2:not([data-init="false"])');
            select2Placeholder = $select2.attr('placeholder');
            $select2.select2({placeholder: select2Placeholder});

            // Trigger popover with form field on added label
            /* istanbul ignore next: difficult to test generated popover content */
            $filterLabel.popover({
                html: true,
                title: function () {
                    return filterTitle;
                },
                content: function () {
                    return $popoverContent;
                },
                placement: 'bottom',
                trigger: 'manual'
            });

            // Hide the filter list popover
            $addFilterButton.popover('hide');

            // Show the popover
            $filterLabel.popover('show');

            // Disable the add filter button
            $addFilterButton
                .addClass('is-disabled')
                .attr('disabled', true)
                .attr('aria-disabled', true);

            // Hide the filter list button if no links remaining
            filterListButtonVisibility($filterbar);

            // Focus on field to avoid unnecessary extra click
            if ($field.hasClass('js-select2') && $field.data('init') !== false) {
                $field.select2('open');
            } else {
                /* istanbul ignore next: difficult to test due to generated popover content */
                $field.focus();
            }

            // Enable button when field has value
            /* istanbul ignore next: difficult to test due to field being inside generated popover content */
            $field.on('change keyup', function() {
                if ($field.val()) {
                    $popoverControls
                        .find('[data-ui="add-filter"]')
                        .removeClass('is-disabled')
                        .attr('disabled', false)
                        .attr('aria-disabled', false);
                } else {
                    $popoverControls
                        .find('[data-ui="add-filter"]')
                        .addClass('is-disabled')
                        .attr('disabled', true)
                        .attr('aria-disabled', true);
                }
            });
        }
    });
}

/* istanbul ignore next: difficult to test due to field and form controls being inside generated popover content */
function addFilter ($filterbar) {
    $filterbar.on('click', '[data-ui="add-filter"]', function(e) {
        var $field = $(this).closest('.added-popover-content').find('.form__control'),
            $popover = $(this).closest('.popover'),
            $formGroup = $popover.find('.form__group'),
            $label = $popover.prev('.label'),
            $addFilterButton = $filterbar.find('[data-ui="show-filter-list"]'),
            $legend = $filterbar.find('form fieldset legend'),
            values,
            valueForLabel = null,
            filterId;

        e.preventDefault();

        // Check if field is a select2
        if ($field.hasClass('js-select2')) {

            values = $field.select2('data');

            $.each(values, function( index, value ) {
                if (valueForLabel === null) {
                    valueForLabel = value.text;
                } else {
                    valueForLabel = valueForLabel + ', ' + value.text;
                }
            });

        } else {
            valueForLabel = $field.val();
        }

        // Add it to the label
        $label
            .find('.chosen-filter')
            .text(': ' + valueForLabel);

        // Add the remove button to the label
        filterId = $label.attr('data-filter-id');
        $label.append('');

        // Swap classes
        $label
            .removeClass('label--primary')
            .addClass('label--inverse');

        // Hide the field
        $formGroup.addClass('display--none');

        // Move the form group out of the popover and back into the filterbar form
        $formGroup.insertAfter($legend);

        // Close popover and destroy to prevent an empty popover showing on label click
        $label.popover('destroy');

        // Enable add filter button
        $addFilterButton.removeClass('is-disabled')
            .attr('disabled', false)
            .attr('aria-disabled', false);

        // Check if save button should be visible
        formActionsVisibility($filterbar);
    });
}

function removeFilter ($filterbar) {
    var $addFilterButton = $filterbar.find('[data-ui="show-filter-list"]');

    $filterbar.on('click', '[data-ui="filter-cancel"]', function(e) {
        var filterId = $(this).attr('data-filter-id'),
            $legend = $filterbar.find('form fieldset legend'),
            $field = $filterbar.find('#' + filterId),
            $formGroup = $field.closest('.form__group'),
            $label;

        e.preventDefault();

        if ($(this).parents('.popover').length) {
            $label = $(this).closest('.popover').prev('.label');
        } else {
            $label = $(this).closest('.label');
        }

        // Add option back to list
        updateFilterList($addFilterButton, filterId, 'show');

        // Empty values from field
        if ($field[0].type === 'select-one' || $field[0].type === 'select-multiple') {
            $field.find('option:selected').prop('selected', false);
        } else if ($field[0].type === 'checkbox') {
            $field.prop('checked', false);
        } else {
            $field.val('');
        }

        // Destroy select2
        if ($field.hasClass('js-select2')) {
            $field.select2('destroy');
        }

        // Hide the field
        $formGroup.addClass('display--none');

        // Move the form group out of the popover and back into the form
        $formGroup.insertAfter($legend);

        // Remove the popover and label
        $label.popover('hide');
        $label.remove();

        // Enable add filter button
        $addFilterButton
            .removeClass('is-disabled')
            .attr('disabled', false)
            .attr('aria-disabled', false);

        // Find any open add filter button popover
        $addFilterButton.popover('hide');

        // Check if button should be visible
        filterListButtonVisibility($filterbar);

        // Check if save button should be visible
        formActionsVisibility($filterbar);
    });
}

function filterListButtonVisibility ($filterbar) {
    var $addFilterButton = $filterbar.find('[data-ui="show-filter-list"]'),
        addFilterList,
        $addFilterList;

    addFilterList = $addFilterButton.attr('data-content');
    $addFilterList = $(addFilterList);

    if ($addFilterList.find('li:not(.display--none)').length) {
        $addFilterButton.removeClass('display--none');
    } else {
        $addFilterButton.addClass('display--none');
    }
}

function formActionsVisibility ($filterbar) {
    var $formActions = $filterbar.find('.form__actions');

    if ($filterbar.find('.label').length) {
        $formActions.removeClass('display--none');
    } else {
        $formActions.addClass('display--none');
    }
}

function clearAllFilters ($filterbar) {
    var $addFilterButton = $filterbar.find('[data-ui="show-filter-list"]');

    $filterbar.on('click', '[data-ui="clear-all-filters"]', function(e) {

        e.preventDefault();

        // Close filter bar
        $filterbar.addClass('display--none');

        // Remove all labels
        $filterbar.find('.label').remove();

        // Reset filter list
        updateFilterList($addFilterButton, null, 'reset');

        // Hide form actions
        formActionsVisibility($filterbar);

        // Reset form
        $filterbar.find('form').trigger('reset');
    });
}

function updateFilterList ($addFilterButton, filterId, visibility) {
    var addFilterList = $addFilterButton.attr('data-content'),
        $addFilterList = $(addFilterList),
        $filterItem,
        $filterItemParent;

    if (filterId !== null) {
        $filterItem = $addFilterList.find('[data-filter-id="' + filterId + '"]');
        $filterItemParent = $filterItem.parent();
    }

    if (visibility === 'show') {
        $filterItemParent.removeClass('display--none');
    } else if (visibility === 'hide') {
        $filterItemParent.addClass('display--none');
    } else if (visibility === 'reset') {
        $addFilterList.find('li.display--none').removeClass('display--none');
    }

    $addFilterButton.attr('data-content', $addFilterList[0].outerHTML);
}

/**
 *   Fired on load, this reads the values of the hidden filters form and
 *   populates the filterbar with the required labels.
**/
function populateFilterList ($filterbar) {

    var $formGroups = $filterbar.find('.form__group'),
        $labelContainer = $filterbar.find('.filter-bar__labels'),
        $addFilterButton = $filterbar.find('[data-ui="show-filter-list"]');

    $formGroups.each(function() {
        var $this = $(this),
            $filterField = $this.find('.form__control'),
            filterId = $filterField.attr('id'),
            filterLabel = $this.find('.control__label').text().trim(),
            filterValue = $filterField.val();

        if ($filterField.hasClass('select')) {
            filterValue = $(':selected', $filterField).text();
        }

        if ($filterField[0].type === 'checkbox') {
            if ($filterField.prop('checked') === true) {
                filterValue = ' ';
            } else {
                filterValue = '';
            }
        } else {
            filterLabel = filterLabel + ': ';
        }

        if (filterValue !== '' && filterValue !== null) {
            $labelContainer.prepend('' + filterLabel + filterValue + '');

            // Hide the filter item in the list
            updateFilterList($addFilterButton, filterId, 'hide');

            // Show the filterbar
            $filterbar.removeClass('display--none');
        }
    });
}

module.exports = FilterBarComponent;
<commit_msg>Make sure filterbar only works on fields that have been initialised<commit_after>'use strict';

var $ = require('jquery');

function FilterBarComponent(html) {
    this.$html = html;
}

FilterBarComponent.prototype.init = function () {
    var component = this;

    this.$container = this.$html.find('.filter-bar');

    this.$container.each(function() {
        var $filterbar = $(this);

        // Create the filter add button
        createFilterListButton($filterbar);

        // Hide the form elements
        hideFormControls($filterbar);

        // Move save button
        moveFormActions($filterbar);

        // Handlers
        showFilterBar(component, $filterbar);
        populateFilterList($filterbar);
        showAddFilterPopover($filterbar);
        addFilter($filterbar);
        removeFilter($filterbar);
        clearAllFilters($filterbar);
    });
};

function showFilterBar (component, $filterbar) {

    component.$html.on('click', '[data-ui="show-filter-bar"]', function(e) {
        var $addFilterButton = $filterbar.find('[data-ui="show-filter-list"]');

        e.preventDefault();

        // Show add button if hidden by clear
        $addFilterButton.removeClass('display--none');

        // Show filter bar
        $filterbar.removeClass('display--none');
    });
}

function createFilterListButton ($filterbar) {
    var $formGroups = $filterbar.find('.form__group'),
        $addFilterButton,
        $filterList = $('

'),
        $filterLabelsWrapper = $('

');

    // Loop through form groups
    $formGroups.each(function() {
        $filterList.append('
'+ $(this).find('.control__label').text() +'
');
    });

    // Build up list and mark up for Add filter button
    $addFilterButton = $('<button class="btn filter-bar__add" role="button" data-ui="show-filter-list" data-toggle="popover" data-trigger="click" title="Filter by" data-html="true" data-placement="bottom" data-content=""></button>');
    $addFilterButton.attr('data-content', $filterList[0].outerHTML);

    // Append button and label wrapper
    $filterLabelsWrapper.appendTo($filterbar.find('fieldset'));
    $addFilterButton.appendTo($filterLabelsWrapper);

    // Initialize popover
    $addFilterButton.popover();

    // Prevent default on button
    $filterbar.on('click', '[data-ui="show-filter-list"]', function(e) {
        e.preventDefault();
    });
}

function hideFormControls ($filterbar) {
    $filterbar
        .find('.form__group')
        .addClass('display--none');
    $filterbar
        .find('.form__actions')
        .addClass('display--none');
}

function moveFormActions ($filterbar) {
    var $formActions = $filterbar.find('.form__actions'),
        $fieldset = $filterbar.find('fieldset');

    $formActions.appendTo($fieldset);
    $formActions.addClass('display--none');
}

function showAddFilterPopover ($filterbar) {
    var filterTitle,
        filterId,
        select2Placeholder,
        $formGroup,
        $filterLabel,
        $popoverControls,
        $popoverContent,
        $field,
        $select2,
        $addFilterButton = $filterbar.find('[data-ui="show-filter-list"]');

    $filterbar.on('click', '[data-ui="filter-item"]', function(e) {
        e.preventDefault();

        filterTitle = $(this).attr('data-filter-title');
        filterId = $(this).attr('data-filter-id');
        $field = $filterbar.find('#' + filterId);

        // Hide the filter item in the list
        updateFilterList($addFilterButton, filterId, 'hide');

        // Add new filter label
        $filterLabel = $('' + filterTitle + ' ');
        $filterLabel.insertBefore($addFilterButton);

        // If checkbox, check it but no need to display it or move to popover
        if ($field[0].type === 'checkbox') {

            // Hide the filter list popover
            $addFilterButton.popover('hide');

            // Check the checkbox
            $field.prop('checked', true);

            // Add the remove button to the label
            filterId = $filterLabel.attr('data-filter-id');
            $filterLabel.append('');

            // Add the label
            $filterLabel
                .removeClass('label--primary')
                .addClass('label--inverse');

            // Hide the filter list button if no links remaining
            filterListButtonVisibility($filterbar);

            // Check if save button should be visible
            formActionsVisibility($filterbar);

        } else {

            // Create content for the popover
            $popoverContent = $('

');

            // Move the field into the popover content
            $formGroup = $filterbar.find('#' + filterId).closest('.form__group');
            $formGroup.appendTo($popoverContent);
            $formGroup.addClass('form__group--flush');

            // Hide the control label
            $formGroup
                .removeClass('display--none')
                .find('.control__label')
                    .addClass('hide');

            // Add popover controls
            $popoverControls = $('
<button type="submit" class="btn btn--primary is-disabled" data-ui="add-filter" disabled="disabled">Add</button>Cancel
');
            $popoverControls.insertAfter($formGroup);

            // Refresh the select2
            $select2 = $popoverContent.find('.js-select2:not([data-init="false"])');
            select2Placeholder = $select2.attr('placeholder');
            $select2.select2({placeholder: select2Placeholder});

            // Trigger popover with form field on added label
            /* istanbul ignore next: difficult to test generated popover content */
            $filterLabel.popover({
                html: true,
                title: function () {
                    return filterTitle;
                },
                content: function () {
                    return $popoverContent;
                },
                placement: 'bottom',
                trigger: 'manual'
            });

            // Hide the filter list popover
            $addFilterButton.popover('hide');

            // Show the popover
            $filterLabel.popover('show');

            // Disable the add filter button
            $addFilterButton
                .addClass('is-disabled')
                .attr('disabled', true)
                .attr('aria-disabled', true);

            // Hide the filter list button if no links remaining
            filterListButtonVisibility($filterbar);

            // Focus on field to avoid unnecessary extra click
            if ($field.hasClass('js-select2', '.select2-hidden-accessible') && $field.data('init') !== false) {
                $field.select2('open');
            } else {
                /* istanbul ignore next: difficult to test due to generated popover content */
                $field.focus();
            }

            // Enable button when field has value
            /* istanbul ignore next: difficult to test due to field being inside generated popover content */
            $field.on('change keyup', function() {
                if ($field.val()) {
                    $popoverControls
                        .find('[data-ui="add-filter"]')
                        .removeClass('is-disabled')
                        .attr('disabled', false)
                        .attr('aria-disabled', false);
                } else {
                    $popoverControls
                        .find('[data-ui="add-filter"]')
                        .addClass('is-disabled')
                        .attr('disabled', true)
                        .attr('aria-disabled', true);
                }
            });
        }
    });
}

/* istanbul ignore next: difficult to test due to field and form controls being inside generated popover content */
function addFilter ($filterbar) {
    $filterbar.on('click', '[data-ui="add-filter"]', function(e) {
        var $field = $(this).closest('.added-popover-content').find('.form__control'),
            $popover = $(this).closest('.popover'),
            $formGroup = $popover.find('.form__group'),
            $label = $popover.prev('.label'),
            $addFilterButton = $filterbar.find('[data-ui="show-filter-list"]'),
            $legend = $filterbar.find('form fieldset legend'),
            values,
            valueForLabel = null,
            filterId;

        e.preventDefault();

        // Check if field is a select2
        if ($field.hasClass('js-select2')) {

            values = $field.select2('data');

            $.each(values, function( index, value ) {
                if (valueForLabel === null) {
                    valueForLabel = value.text;
                } else {
                    valueForLabel = valueForLabel + ', ' + value.text;
                }
            });

        } else {
            valueForLabel = $field.val();
        }

        // Add it to the label
        $label
            .find('.chosen-filter')
            .text(': ' + valueForLabel);

        // Add the remove button to the label
        filterId = $label.attr('data-filter-id');
        $label.append('');

        // Swap classes
        $label
            .removeClass('label--primary')
            .addClass('label--inverse');

        // Hide the field
        $formGroup.addClass('display--none');

        // Move the form group out of the popover and back into the filterbar form
        $formGroup.insertAfter($legend);

        // Close popover and destroy to prevent an empty popover showing on label click
        $label.popover('destroy');

        // Enable add filter button
        $addFilterButton.removeClass('is-disabled')
            .attr('disabled', false)
            .attr('aria-disabled', false);

        // Check if save button should be visible
        formActionsVisibility($filterbar);
    });
}

function removeFilter ($filterbar) {
    var $addFilterButton = $filterbar.find('[data-ui="show-filter-list"]');

    $filterbar.on('click', '[data-ui="filter-cancel"]', function(e) {
        var filterId = $(this).attr('data-filter-id'),
            $legend = $filterbar.find('form fieldset legend'),
            $field = $filterbar.find('#' + filterId),
            $formGroup = $field.closest('.form__group'),
            $label;

        e.preventDefault();

        if ($(this).parents('.popover').length) {
            $label = $(this).closest('.popover').prev('.label');
        } else {
            $label = $(this).closest('.label');
        }

        // Add option back to list
        updateFilterList($addFilterButton, filterId, 'show');

        // Empty values from field
        if ($field[0].type === 'select-one' || $field[0].type === 'select-multiple') {
            $field.find('option:selected').prop('selected', false);
        } else if ($field[0].type === 'checkbox') {
            $field.prop('checked', false);
        } else {
            $field.val('');
        }

        // Destroy select2
        if ($field.hasClass('js-select2', '.select2-hidden-accessible')) {
            $field.select2('destroy');
        }

        // Hide the field
        $formGroup.addClass('display--none');

        // Move the form group out of the popover and back into the form
        $formGroup.insertAfter($legend);

        // Remove the popover and label
        $label.popover('hide');
        $label.remove();

        // Enable add filter button
        $addFilterButton
            .removeClass('is-disabled')
            .attr('disabled', false)
            .attr('aria-disabled', false);

        // Find any open add filter button popover
        $addFilterButton.popover('hide');

        // Check if button should be visible
        filterListButtonVisibility($filterbar);

        // Check if save button should be visible
        formActionsVisibility($filterbar);
    });
}

function filterListButtonVisibility ($filterbar) {
    var $addFilterButton = $filterbar.find('[data-ui="show-filter-list"]'),
        addFilterList,
        $addFilterList;

    addFilterList = $addFilterButton.attr('data-content');
    $addFilterList = $(addFilterList);

    if ($addFilterList.find('li:not(.display--none)').length) {
        $addFilterButton.removeClass('display--none');
    } else {
        $addFilterButton.addClass('display--none');
    }
}

function formActionsVisibility ($filterbar) {
    var $formActions = $filterbar.find('.form__actions');

    if ($filterbar.find('.label').length) {
        $formActions.removeClass('display--none');
    } else {
        $formActions.addClass('display--none');
    }
}

function clearAllFilters ($filterbar) {
    var $addFilterButton = $filterbar.find('[data-ui="show-filter-list"]');

    $filterbar.on('click', '[data-ui="clear-all-filters"]', function(e) {

        e.preventDefault();

        // Close filter bar
        $filterbar.addClass('display--none');

        // Remove all labels
        $filterbar.find('.label').remove();

        // Reset filter list
        updateFilterList($addFilterButton, null, 'reset');

        // Hide form actions
        formActionsVisibility($filterbar);

        // Reset form
        $filterbar.find('form').trigger('reset');
    });
}

function updateFilterList ($addFilterButton, filterId, visibility) {
    var addFilterList = $addFilterButton.attr('data-content'),
        $addFilterList = $(addFilterList),
        $filterItem,
        $filterItemParent;

    if (filterId !== null) {
        $filterItem = $addFilterList.find('[data-filter-id="' + filterId + '"]');
        $filterItemParent = $filterItem.parent();
    }

    if (visibility === 'show') {
        $filterItemParent.removeClass('display--none');
    } else if (visibility === 'hide') {
        $filterItemParent.addClass('display--none');
    } else if (visibility === 'reset') {
        $addFilterList.find('li.display--none').removeClass('display--none');
    }

    $addFilterButton.attr('data-content', $addFilterList[0].outerHTML);
}

/**
 *   Fired on load, this reads the values of the hidden filters form and
 *   populates the filterbar with the required labels.
**/
function populateFilterList ($filterbar) {

    var $formGroups = $filterbar.find('.form__group'),
        $labelContainer = $filterbar.find('.filter-bar__labels'),
        $addFilterButton = $filterbar.find('[data-ui="show-filter-list"]');

    $formGroups.each(function() {
        var $this = $(this),
            $filterField = $this.find('.form__control'),
            filterId = $filterField.attr('id'),
            filterLabel = $this.find('.control__label').text().trim(),
            filterValue = $filterField.val();

        if ($filterField.hasClass('select')) {
            filterValue = $(':selected', $filterField).text();
        }

        if ($filterField[0].type === 'checkbox') {
            if ($filterField.prop('checked') === true) {
                filterValue = ' ';
            } else {
                filterValue = '';
            }
        } else {
            filterLabel = filterLabel + ': ';
        }

        if (filterValue !== '' && filterValue !== null) {
            $labelContainer.prepend('' + filterLabel + filterValue + '');

            // Hide the filter item in the list
            updateFilterList($addFilterButton, filterId, 'hide');

            // Show the filterbar
            $filterbar.removeClass('display--none');
        }
    });
}

module.exports = FilterBarComponent;
<|endoftext|>


<commit_before>// takes an IR function object and returns a list of Scratch blocks

module.exports.ffi = {};

module.exports.generateFunctionHat = function(func) {
	var spec = func.funcName;
	var inputs = [];
	var defaults = [];

	for(var i = 0; i < func.paramList.length; ++i) {
		if(func.paramList[i][1])
			inputs.push(func.paramList[i][1]);
		else
			inputs.push("param"+i);

		defaults.push(defaultForType(func.paramList[i][0]));
		spec += " "+specifierForType(func.paramList[i][0]);
	}

	return ["procDef", spec, inputs, defaults, false];

}

module.exports.compileFunction = function(func) {
	console.log("Compiling "+JSON.stringify(func)+"...");

	var blockList = [module.exports.generateFunctionHat(func)]
					.concat(initLocal());

	for(var i = 0; i < func.code.length; ++i) {
		console.log(func.code[i]);
		if(func.code[i].type == "call") {
			// calling a (potentially foreign) function

			blockList = blockList.concat(callBlock(func.code[i]));

		} else if(func.code[i].type == "ffi") {
			// FFI block
			// load the code from the options
			blockList = blockList.concat(module.exports.ffi[func.code[i].ffiBlock]);
		}
	}

	blockList = blockList.concat(returnBlock());

	return blockList;
}

// fixme: stub
function defaultForType(type) {
	console.log(type);
	return 0;
}

// fixme: stub
function specifierForType(type) {
	return "%s";
}

// fixme: stub
function formatValue(type, value) {
	return value;
}

// higher-level code generation
function initLocal() {
	return [
		["append:toList:", "0", "# of locals"]
	]
}

function allocateLocal(val) {
	return [
		["setLine:ofList:to:", "last", "# of locals", ["+", ["getLine:ofList:", "last", "# of locals"], 1]],
		["append:toList:", val, "Stack"]
	];
}

function freeLocals() {
	return [
		["doRepeat", ["getLine:ofList:", "last", "# of locals"], [["deleteLine:ofList:", "last", "Stack"]]],
		["deleteLine:ofList:", "last", "# of locals"]
	];
}

function returnBlock(val) {
	var proc = freeLocals();

	if(val) {
		proc.push(["setVar:to:", "return value", val]);
	}

	proc.push(["stopScripts", "this script"]);

	return proc;
}

function callBlock(block) {
	var spec = block.funcName;
	var args = [];

	for(var a = 0; a < block.paramList.length; ++a) {
		args.push(formatValue(block.paramList[a][0], block.paramList[a][1]));
		spec += " "+specifierForType(block.paramList[a][0]);
	}

	return [
		["call", spec]
	];
}<commit_msg>Bugfix: missing arguments in call<commit_after>// takes an IR function object and returns a list of Scratch blocks

module.exports.ffi = {};

module.exports.generateFunctionHat = function(func) {
	var spec = func.funcName;
	var inputs = [];
	var defaults = [];

	for(var i = 0; i < func.paramList.length; ++i) {
		if(func.paramList[i][1])
			inputs.push(func.paramList[i][1]);
		else
			inputs.push("param"+i);

		defaults.push(defaultForType(func.paramList[i][0]));
		spec += " "+specifierForType(func.paramList[i][0]);
	}

	return ["procDef", spec, inputs, defaults, false];

}

module.exports.compileFunction = function(func) {
	console.log("Compiling "+JSON.stringify(func)+"...");

	var blockList = [module.exports.generateFunctionHat(func)]
					.concat(initLocal());

	for(var i = 0; i < func.code.length; ++i) {
		console.log(func.code[i]);
		if(func.code[i].type == "call") {
			// calling a (potentially foreign) function

			blockList = blockList.concat(callBlock(func.code[i]));

		} else if(func.code[i].type == "ffi") {
			// FFI block
			// load the code from the options
			blockList = blockList.concat(module.exports.ffi[func.code[i].ffiBlock]);
		}
	}

	blockList = blockList.concat(returnBlock());

	return blockList;
}

// fixme: stub
function defaultForType(type) {
	console.log(type);
	return 0;
}

// fixme: stub
function specifierForType(type) {
	return "%s";
}

// fixme: stub
function formatValue(type, value) {
	return value;
}

// higher-level code generation
function initLocal() {
	return [
		["append:toList:", "0", "# of locals"]
	]
}

function allocateLocal(val) {
	return [
		["setLine:ofList:to:", "last", "# of locals", ["+", ["getLine:ofList:", "last", "# of locals"], 1]],
		["append:toList:", val, "Stack"]
	];
}

function freeLocals() {
	return [
		["doRepeat", ["getLine:ofList:", "last", "# of locals"], [["deleteLine:ofList:", "last", "Stack"]]],
		["deleteLine:ofList:", "last", "# of locals"]
	];
}

function returnBlock(val) {
	var proc = freeLocals();

	if(val) {
		proc.push(["setVar:to:", "return value", val]);
	}

	proc.push(["stopScripts", "this script"]);

	return proc;
}

function callBlock(block) {
	var spec = block.funcName;
	var args = [];

	for(var a = 0; a < block.paramList.length; ++a) {
		args.push(formatValue(block.paramList[a][0], block.paramList[a][1]));
		spec += " "+specifierForType(block.paramList[a][0]);
	}

	return [
		["call", spec].concat(args)
	];
}<|endoftext|>


<commit_before>window.jsLibs = [
	{
		url: 'https://code.jquery.com/jquery-3.2.1.min.js',
		label: 'jQuery',
		type: 'js'
	},
	{
		url: 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js',
		label: 'Bootstrap 3',
		type: 'js'
	},
	{
		url:
			'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js',
		label: 'Bootstrap 4α',
		type: 'js'
	},
	{
		url:
			'https://cdnjs.cloudflare.com/ajax/libs/foundation/6.3.1/js/foundation.min.js',
		label: 'Foundation',
		type: 'js'
	},
	{
		url: 'https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js',
		label: 'Angular',
		type: 'js'
	},
	{
		url: 'https://cdnjs.cloudflare.com/ajax/libs/react/15.5.4/react.min.js',
		label: 'React',
		type: 'js'
	},
	{
		url: 'https://cdnjs.cloudflare.com/ajax/libs/react/15.5.4/react-dom.min.js',
		label: 'React DOM',
		type: 'js'
	},
	{
		url: 'https://unpkg.com/vue@2.4.2/dist/vue.min.js',
		label: 'Vue.js',
		type: 'js'
	},
	{
		url: 'https://cdnjs.cloudflare.com/ajax/libs/three.js/85/three.min.js',
		label: 'Three.js',
		type: 'js'
	},
	{
		url: 'https://cdnjs.cloudflare.com/ajax/libs/d3/4.9.1/d3.min.js',
		label: 'D3',
		type: 'js'
	},
	{
		url:
			'https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js',
		label: 'Underscore',
		type: 'js'
	},
	{
		url: 'https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.1/TweenMax.min.js',
		label: 'Greensock TweenMax',
		type: 'js'
	},
	{
		url: 'https://cdnjs.cloudflare.com/ajax/libs/uikit/2.27.4/js/uikit.min.js',
		label: 'UIkit 2',
		type: 'js'
	},
	{
		url:
			'https://cdnjs.cloudflare.com/ajax/libs/uikit/3.0.0-beta.28/js/uikit.min.js',
		label: 'UIkit 3',
		type: 'js'
	}
];
window.cssLibs = [
	{
		url:
			'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css',
		label: 'Bootstrap 3',
		type: 'css'
	},
	{
		url:
			'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css',
		label: 'Bootstrap 4α',
		type: 'css'
	},
	{
		url: 'https://cdnjs.cloudflare.com/ajax/libs/bulma/0.4.2/css/bulma.min.css',
		label: 'Bulma',
		type: 'css'
	},
	{
		url:
			'https://cdnjs.cloudflare.com/ajax/libs/foundation/6.3.1/css/foundation.min.css',
		label: 'Foundation',
		type: 'css'
	},
	{
		url: 'https://cdnjs.cloudflare.com/ajax/libs/hint.css/2.5.0/hint.min.css',
		label: 'Hint.css',
		type: 'css'
	},
	{
		url:
			'https://cdnjs.cloudflare.com/ajax/libs/uikit/2.27.4/css/uikit.min.css',
		label: 'UIkit 2',
		type: 'css'
	},
	{
		url:
			'https://cdnjs.cloudflare.com/ajax/libs/uikit/3.0.0-beta.28/css/uikit.min.css',
		label: 'UIkit 3',
		type: 'css'
	},
	{
		url:
			'https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.5.2/animate.min.css',
		label: 'Animate.css',
		type: 'css'
	},
	{
		url:
			'https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css',
		label: 'FontAwesome',
		type: 'css'
	}
];
<commit_msg>Update library-list.js<commit_after>window.jsLibs = [
	{
		url: 'https://code.jquery.com/jquery-3.2.1.min.js',
		label: 'jQuery',
		type: 'js'
	},
	{
		url: 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js',
		label: 'Bootstrap 3',
		type: 'js'
	},
	{
		url:
			'https://cdnjs.cloudflare.com/ajax/libs/foundation/6.4.3/js/foundation.min.js',
		label: 'Foundation',
		type: 'js'
	},
	{
		url:
			'https://semantic-ui.com/dist/semantic.min.js',
		label: 'Semantic UI',
		type: 'js'
	},
	{
		url: 'https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js',
		label: 'Angular',
		type: 'js'
	},
	{
		url: 'https://cdnjs.cloudflare.com/ajax/libs/react/15.5.4/react.min.js',
		label: 'React',
		type: 'js'
	},
	{
		url: 'https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react-dom.min.js',
		label: 'React DOM',
		type: 'js'
	},
	{
		url: 'https://unpkg.com/vue@2.4.4/dist/vue.min.js',
		label: 'Vue.js',
		type: 'js'
	},
	{
		url: 'https://cdnjs.cloudflare.com/ajax/libs/three.js/85/three.min.js',
		label: 'Three.js',
		type: 'js'
	},
	{
		url: 'https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.2/d3.min.js',
		label: 'D3',
		type: 'js'
	},
	{
		url:
			'https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js',
		label: 'Underscore',
		type: 'js'
	},
	{
		url: 'https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.1/TweenMax.min.js',
		label: 'Greensock TweenMax',
		type: 'js'
	},
	{
		url: 'https://cdnjs.cloudflare.com/ajax/libs/uikit/2.27.4/js/uikit.min.js',
		label: 'UIkit 2',
		type: 'js'
	},
	{
		url:
			'https://cdnjs.cloudflare.com/ajax/libs/uikit/3.0.0-beta.30/js/uikit.min.js',
		label: 'UIkit 3',
		type: 'js'
	}
];
window.cssLibs = [
	{
		url:
			'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css',
		label: 'Bootstrap 3',
		type: 'css'
	},
	{
		url: 'https://cdnjs.cloudflare.com/ajax/libs/bulma/0.5.2/css/bulma.min.css',
		label: 'Bulma',
		type: 'css'
	},
	{
		url:
			'https://cdnjs.cloudflare.com/ajax/libs/foundation/6.4.3/css/foundation.min.css',
		label: 'Foundation',
		type: 'css'
	},
	{
		url: 'https://cdnjs.cloudflare.com/ajax/libs/hint.css/2.5.0/hint.min.css',
		label: 'Hint.css',
		type: 'css'
	},
	{
		url:'https://semantic-ui.com/dist/semantic.min.css',
		label: 'Semantic UI',
		type: 'css'
	},
	{
		url:
			'https://cdnjs.cloudflare.com/ajax/libs/uikit/2.27.4/css/uikit.min.css',
		label: 'UIkit 2',
		type: 'css'
	},
	{
		url:
			'https://cdnjs.cloudflare.com/ajax/libs/uikit/3.0.0-beta.30/css/uikit.min.css',
		label: 'UIkit 3',
		type: 'css'
	},
	{
		url:
			'https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.5.2/animate.min.css',
		label: 'Animate.css',
		type: 'css'
	},
	{
		url:
			'https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css',
		label: 'FontAwesome',
		type: 'css'
	}
];
<|endoftext|>