Passed
Push — master ( d82885...9cea0f )
by D
02:54
created

Dropdown.initToggleIcon   A

Complexity

Conditions 2

Size

Total Lines 7
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 7
dl 0
loc 7
rs 10
c 0
b 0
f 0
cc 2
1
import {define} from "../globals/globals";
2
import {DropdownInterface} from "../interfaces/DropdownInterface";
3
import {DropdownOptions} from "../types/DropdownOptions";
4
5
(function (root, factory) {
6
    if (typeof define === 'function' && define.amd) {
7
        define([], factory);
8
    } else if (typeof module === 'object' && module.exports) {
9
        module.exports = factory();
10
    } else {
11
        root!.Dropdown = factory();
12
    }
13
}(typeof self !== 'undefined' ? self : this, function () {
14
15
    class Dropdown implements DropdownInterface {
16
        public $el: HTMLElement;
17
        public options: DropdownOptions;
18
        static $toggle: Array<HTMLElement>;
19
        static $content: HTMLElement;
20
21
        constructor($el: string | HTMLElement, options:DropdownOptions) {
22
            if (!$el) {
23
                return;
24
            }
25
26
            this.$el = (typeof $el === 'string' ? document.querySelector($el) : $el) as HTMLElement;
27
28
            if(options) {
29
                this.options = options;
30
                this.options.togglers = options.togglers as NodeListOf<HTMLElement>;
31
                this.options.bodyClose = typeof options.bodyClose === 'undefined' ? true : options.bodyClose as boolean;
32
                this.options.opened = options.opened || false as boolean;
33
                this.options.content = options.content as any;
34
                this.options.onOpen = options.onOpen as Function;
35
                this.options.onClose = options.onClose as Function;
36
                this.options.class = options.class || {} as object;
37
                this.options.class.container = options.class.container || 'dropdown' as string;
38
                this.options.class.content = options.class.content || 'dropdown__content' as string;
39
                this.options.class.toggle = options.class.toggle || 'dropdown__toggle' as string;
40
                this.options.class.open = options.class.open || 'open' as string;
41
            }
42
            else {
43
                this.mergeOptions();
44
            }
45
46
            this.init();
47
        }
48
49
        private mergeOptions(): void {
50
            let defaults = {
51
                bodyClose: true,
52
                opened: false,
53
                onOpen: function () {},
54
                onClose: function () {},
55
                class: {
56
                    container: 'dropdown',
57
                    content: 'dropdown__content',
58
                    toggle: 'dropdown__toggle',
59
                    open: 'open'
60
                }
61
            };
62
63
            this.options = Object.assign(this, defaults)
64
        }
65
66
        protected init(): void {
67
            this.initDom();
68
            this.initEvents();
69
            this.initToggleIcon();
70
        }
71
72
        private initDom(): void {
73
            let that = this;
74
75
            if (!that.options.togglers) {
76
                Dropdown.$toggle = [that.$el.querySelector('button.toggler')] as Array<HTMLElement>;
77
            }
78
            else {
79
                Dropdown.$toggle = [];
80
81
                for (let i = 0; i < (that.options.togglers as NodeListOf<HTMLElement>).length; i++) {
82
                    Dropdown.$toggle[Dropdown.$toggle.length] = (that.options.togglers as NodeListOf<HTMLElement>)[i];
83
                }
84
            }
85
86
            if (that.options.content as string) {
87
                Dropdown.$content = that.options.content;
88
            }
89
            else {
90
                Dropdown.$content = that.$el.querySelector('.dropdown__content') as HTMLElement;
91
            }
92
93
            that.$el.classList.add(that.options.class.container as string);
94
95
            if (that.options.opened) {
96
                that.open();
97
            }
98
99
            for (let i = 0; i < Dropdown.$toggle.length; i++) {
100
                Dropdown.$toggle[i].classList.add(that.options.class.toggle as string);
101
            }
102
103
            Dropdown.$content.classList.add(that.options.class.content as string);
104
        }
105
106
        protected initEvents(): void {
107
            let that = this;
108
109
            for (let i = 0; i < Dropdown.$toggle.length; i++) {
110
                Dropdown.$toggle[i].addEventListener('click', function (event:Event) {
111
                    that.eventToggleClick(event);
112
                });
113
            }
114
115
            if (that.options.bodyClose as boolean) {
116
                document.addEventListener('click', function (event:Event) {
117
                    that.eventBodyClick(event);
118
                });
119
            }
120
        }
121
122
        protected initToggleIcon(): void {
123
            if(this.options.toggleIcon) {
124
                let dropdownToggle = this.$el.querySelector('.dropdown__toggle');
125
                let dropdownToggleIcon = document.createElement('div');
126
                dropdownToggleIcon.innerHTML = this.options.toggleIcon;
127
                dropdownToggle!.appendChild(dropdownToggleIcon);
128
            }
129
        }
130
131
        protected eventToggleClick(event: Event): void {
132
            event.preventDefault();
133
134
            let that = this;
135
136
            if (that.$el.classList.contains(that.options.class.open as string)) {
137
                that.close();
138
            }
139
            else {
140
                that.open();
141
            }
142
        }
143
144
        protected eventBodyClick(event: Event): void {
145
            let that = this;
146
147
            if (!that.elementInDropdown(event.target) ) {
148
                that.close();
149
            }
150
        }
151
152
         protected elementInDropdown($el: any): boolean {
153
            let that = this,
154
                parent = $el;
155
156
            while (parent) {
157
                if (parent === that.$el) {
158
                    return true;
159
                }
160
161
                parent = parent.parentNode as Element;
162
            }
163
164
            return false;
165
        }
166
167
        public open(): void {
168
            this.$el.classList.add(this.options.class.open);
169
170
            if(this.options.onOpen) {
171
                this.options.onOpen.call(this);
172
            }
173
        }
174
175
        public close(): void {
176
            this.$el.classList.remove(this.options.class.open);
177
178
            if(this.options.onClose) {
179
                this.options.onClose.call(this);
180
            }
181
        }
182
    }
183
184
    return Dropdown;
185
}));