All files / lib/components button-toolbar.vue

15.38% Statements 8/52
8.11% Branches 3/37
21.43% Functions 3/14
15.38% Lines 8/52
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 11918x 18x 18x   18x 18x                     18x       18x                                                   18x                                                                                                                                                
<template>
    <div :class="classObject"
    I     role="toolbar"
         :tabindex="keyNav ? '0' : null"
         @fEocusin.self="focusFirst"
         @keydown.left="focusNext($event,true)"
         @keydown.up="focusNext($event,true)"
         @keydown.right="focusNext($event,false)"
         @keydown.down="focusNext($event,false)"
         @keydown.shift.left="focusFirst($event)"
         @keydown.shift.up="focusFirst($event)"
         @keydown.shift.right="focusLast($event)"
         @keydown.shift.down="focusLast($event)"
    >
        <slot></slot>
    </div>
</template>
 
<script>
    import { from as arrayFrom } from '../utils/array'
    const ITEM_SELECTOR = [
        '.btn:not(.disabled):not([disabled])',
        '.form-control:not(.disabled):not([disabled])',
        'select:not(.disabled):not([disabled])',
        'input[type="checkbox"]:not(.disabled)',
        'input[type="radio"]:not(.disabled)'
    ].join(',');
 
    // Determine if an HTML element is visible - Faster than CSS check
    function isVisible(el) {
        return el && (el.offsetWidth > 0 || el.offsetHeight > 0);
    }
 
    export default {
        computed: {
            classObject() {
                return [
                    'btn-toolbar',
                    (this.justify && !this.vertical) ? 'justify-content-between' : ''
                ];
            }
        },
        props: {
            justify: {
                type: Boolean,
                default: false
            },
            keyNav: {
                type: Boolean,
                default: false
            }
        },
        methods: {
            setItemFocus(item) {
                this.$nextTick(() => {
                    item.focus();
                });
            },
            focusNext(e, prev) {
                if (!this.keyNav) {
                    return;
                }
                e.preventDefault();
                e.stopPropagation();
                const items = this.getItems();
                if (items.length < 1) {
                    return;
                }
                let index = items.indexOf(e.target);
                if (prev && index > 0) {
                    index--;
                } else if (!prev && index < items.length - 1) {
                    index++;
                }
                if (index < 0) {
                    index = 0;
                }
                this.setItemFocus(items[index]);
            },
            focusFirst(e) {
                if (!this.keyNav) {
                    return;
                }
                e.preventDefault();
                e.stopPropagation();
                const items = this.getItems();
                if (items.length > 0) {
                    this.setItemFocus(items[0]);
                }
            },
            focusLast(e) {
                if (!this.keyNav) {
                    return;
                }
                e.preventDefault();
                e.stopPropagation();
                const items = this.getItems();
                if (items.length > 0) {
                    this.setItemFocus([items.length - 1]);
                }
            },
            getItems() {
                let items = arrayFrom(this.$el.querySelectorAll(ITEM_SELECTOR));
                items.forEach(item => {
                    // Ensure tabfocus is -1 on any new elements
                    item.tabIndex = -1;
                });
                return items.filter(el => isVisible(el));
            }
        },
        mounted() {
            if (this.keyNav) {
                // Pre-set the tabindexes if the markup does not include tabindex="-1" on the toolbar items
                this.getItems();
            }
        }
    };
</script>