busy-web/components

View on GitHub
addon/components/bc-list.js

Summary

Maintainability
A
1 hr
Test Coverage
/**
 * @module component
 *
 */
import $ from 'jquery';
import { on } from '@ember/object/evented';
import { isNone, isEmpty } from '@ember/utils';
import { computed, observer } from '@ember/object';
import Component from '@ember/component';
import layout from '../templates/components/bc-list';

/**
 * `BC/List`
 *
 * @class
 * Renders a list view of model objects
 *
 * bc-list has two event callbacks `onClick` and `onSelect`.
 * The onSelect method must be used with `selector=true` refer to example two
 *
 * @example
 * // example 1
 * {{#bc-list content=controller.content as |item|}}
 *    <!-- image container - left most container for images -->
 *    <div class="bc-list-thumbnail"><img src={{item.imageName}} /></div>
 *
 *    <!-- info container - left aligned container -->
 *    <div class="bc-list-info><h1>{{item.fullName}}</h1></div>
 *
 *    <!-- image container - right aligned container -->
 *    <div class="bc-list-status></div>
 * {{/bc-list}}
 *
 * //example 2
 * {{#bc-list selector=true edit=controller.edit onSelect="mySelectMethod" content=controller.content as |item|}}
 *    <div class="bc-list-thumbnail"><img src={{item.imageName}} /></div>
 *    <div class="bc-list-info><h1>{{item.fullName}}</h1></div>
 * {{/bc-list}}
 *
 * @extends Ember.Component
 */
export default Component.extend({
    layout: layout,
    classNames: ['bc-list'],

    /**
     * Bool for setting the type of list
     * true if the list is selectable
     *
     * @public
     * @property selector
     * @type boolean
     */
    selector: false,

    /**
     *
     * @public
     * @property hasImage
     * @type boolean
     */
    hasImage: false,

    /**
     * Bool for toggling select mode
     * set to true to show the select boxes
     *
     * @public
     * @property edit
     * @type boolean
     */
    edit: false,

    large: false,
    hasHeader: true,
    minimal: false,
    isSelectAll: false,

    /**
     * The model array to render in the list
     *
     * @public
     * @property model
     * @type array
     */
    model: null,

    clickable: computed('onClick', function() {
        return !isNone(this.get('onClick')) && !isEmpty(this.get('onClick')) ? true : false;
    }),

    isLoading: computed('model', 'model.isLoaded', 'model.[]', 'model.length', function() {
        if (!isNone(this.get('model'))) {
            if (this.get('model.isLoaded') === true) {
                return false;
            } else if (isNone(this.get('model.isLoaded'))) {
                return false;
            }
        }
        return true;
    }),

    modelChange: observer('model.@each.id', function() {
        this.set('selectedRows', []);
        this.set('isSelectAll', false);
    }),

    hasModel: computed('model', function() {
        if (this.get('model.length') > 0) {
            return true;
        }
    }),

    hasLoadedDOM: on('didRender', function() {
        this.renderTemplates();
    }),

    renderTemplates: function() {
        const list = this.$();
        if (list && list.find) {
            const row = list.find('section').children('.content-row').first();
            if (row.length > 0) {
                const cols = row.children();
                const header = this.$('.bc-list-header.auto-list');

                header.html('');
                header.append('<span class="header-extra"></span>');

                this.$('.list-no-results > td').attr('colspan', cols.length);

                $.each(cols, (key, item) => {
                    let el = $(item);
                    if (!el.hasClass('list-extra')) {
                        let span = '<span';
                        if (el.attr('class') !== undefined) {
                            span += ' class="' + el.attr('class') + '"';
                        }
                        span += '>';
                        if (el.attr('title') !== undefined) {
                            span += el.attr('title');
                        }
                        span += '</span>';
                        header.append(span);
                    }
                });
            }
        }
    },

    /**
     * Storage array for all selected rows that get passed to onSelect event callback
     *
     * @private
     * @property selectedRows
     * @type array
     */
    selectedRows: null,

    actions: {

        /**
         * Row clicked action handler
         *
         * @private
         * @method rowClick
         * @param {Object} model The clicked rows model
         * @returns {void}
         */
        rowClick(model) {
            this.sendAction('onClick', model);
        },

        itemSelected(isChecked, row) {
            if (isNone(this.get('selectedRows'))) {
                this.set('selectedRows', []);
            }

            if (isChecked) {
                this.get('selectedRows').pushObject(row);
            } else {
                this.get('selectedRows').removeObject(row);
            }

            if (this.get('selectedRows.length') === this.get('model.length')) {
                this.set('isSelectAll', true);
            } else if (this.get('selectedRows.length') === 0) {
                this.set('isSelectAll', false);
            }
            this.sendAction('onSelect', isChecked, row);
        },

        selectAll(isChecked) {
            const model = this.get('model');
            const selectedRows = [];

            if (isChecked) {
                this.set('isSelectAll', true);
            } else {
                this.set('isSelectAll', false);
            }

            model.forEach(row => {
                row.set('isSelected', isChecked ? true : false);
                if (row.get('isSelected')) {
                    selectedRows.pushObject(row);
                } else {
                    selectedRows.removeObject(row);
                }
            });
            this.set('selectedRows', selectedRows);
            this.sendAction('selectAll', isChecked, selectedRows.copy());
        }
    }
});