rx/presenters

View on GitHub
views/mdc/assets/js/components/chips.js

Summary

Maintainability
A
35 mins
Test Coverage
import {MDCChip} from '@material/chips';
import {MDCChipSet} from '@material/chips';
import {eventHandlerMixin} from './mixins/event-handler';
import {VBaseComponent, hookupComponentsManually} from './base-component';

export const EVENT_SELECT = 'select';
export const EVENT_DESELECT = 'deselect';
export const EVENT_TRAILING_ICON_CLICK = 'trailing_icon_click';

const SELECTABLE_VARIANT_CLASS = 'v-chip-set--selectable-variant';
const CHIP_BEHAVIOR_AUTO_REMOVE = 'auto_remove';
const CHIP_BEHAVIOR_NO_AUTO_REMOVE = 'no_auto_remove';

export function initChips(e) {
    console.debug('\tChips');

    // The chip set > chips hierarchy is established differently than other
    // components: a chip set constructs and manages Chip components for its
    // chip elements.
    //
    // Because the chip set constructs chips on its own, a `hookupComponents`
    // call for chips is not needed.

    hookupComponentsManually(e, '.v-chip-set', function(element) {
        const chipFactory = voomChipFactoryFactory(CHIP_BEHAVIOR_NO_AUTO_REMOVE);
        const mdcComponent = new MDCChipSet(element, undefined, chipFactory);

        return new VChipSet(element, mdcComponent);
    });
}

export class VChip extends eventHandlerMixin(VBaseComponent) {
    constructor(element, mdcComponent) {
        super(element, mdcComponent);

        this.element.addEventListener('click', (e) => {
            if (this.selectable) {
                this.mdcComponent.selected = !this.mdcComponent.selected;

                const eventType = this.mdcComponent.selected
                    ? EVENT_SELECT
                    : EVENT_DESELECT;
                const selectionEvent = new Event(eventType, {bubbles: false});

                this.element.dispatchEvent(selectionEvent);
            }
        });
    }

    get trailingIcon() {
        return this.element.querySelector(
            '.mdc-chip__icon.mdc-chip__icon--trailing'
        );
    }

    // Called to collect data for submission
    prepareSubmit(params) {
        if (this.shouldSubmitParams()) {
            params.push([this.name(), this.value()]);
        }
    }

    name() {
        return this.element.getAttribute('data-name');
    }

    value() {
        return this.element.getAttribute('data-value');
    }

    clear() {
        console.debug('Chip clear is a no-op');
    }

    setValue(value) {
        this.element.setAttribute('data-value', value);
    }

    shouldSubmitParams() {
        // Selectable chips (those within a :filter or :choice chipset) which
        // are not currently selected do not submit their value.
        return this.name() && this.value()
            && (!this.selectable || this.mdcComponent.selected);
    }

    get selectable() {
        return this.element.parentElement.classList.contains(
            SELECTABLE_VARIANT_CLASS
        );
    }
}

// Returns a function which constructs VChip components.
function voomChipFactoryFactory(behavior = CHIP_BEHAVIOR_AUTO_REMOVE) {
    const autoRemove = behavior === CHIP_BEHAVIOR_AUTO_REMOVE;

    return function(element) {
        const mdcComponent = new MDCChip(element);
        mdcComponent.shouldRemoveOnTrailingIconClick = autoRemove;

        return new VChip(element, mdcComponent);
    };
}

export class VChipSet extends eventHandlerMixin(VBaseComponent) {
    constructor(element, mdcComponent) {
        super(element, mdcComponent);
    }
}