Completed
Push — master ( 784db1...530622 )
by D
02:33
created

Dropdown.mergeOptions   B

Complexity

Conditions 8

Size

Total Lines 16
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 14
dl 0
loc 16
c 0
b 0
f 0
rs 7.3333
cc 8
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
        }
70
71
        private initDom(): void {
72
            let that = this;
73
74
            if (!that.options.togglers) {
75
                Dropdown.$toggle = [that.$el.querySelector('a.toggler')] as Array<HTMLElement>;
76
            }
77
            else {
78
                Dropdown.$toggle = [];
79
80
                for (let i = 0; i < (that.options.togglers as NodeListOf<HTMLElement>).length; i++) {
81
                    Dropdown.$toggle[Dropdown.$toggle.length] = (that.options.togglers as NodeListOf<HTMLElement>)[i];
82
                }
83
            }
84
85
            if (that.options.content as string) {
86
                Dropdown.$content = that.options.content;
87
            }
88
            else {
89
                Dropdown.$content = that.$el.querySelector('.dropdown__content') as HTMLElement;
90
            }
91
92
            that.$el.classList.add(that.options.class.container as string);
93
94
            if (that.options.opened) {
95
                that.open();
96
            }
97
98
            for (let i = 0; i < Dropdown.$toggle.length; i++) {
99
                Dropdown.$toggle[i].classList.add(that.options.class.toggle as string);
100
            }
101
102
            Dropdown.$content.classList.add(that.options.class.content as string);
103
        }
104
105
        protected initEvents(): void {
106
            let that = this;
107
108
            for (let i = 0; i < Dropdown.$toggle.length; i++) {
109
                Dropdown.$toggle[i].addEventListener('click', function (event:Event) {
110
                    that.eventToggleClick(event);
111
                });
112
            }
113
114
            if (that.options.bodyClose as boolean) {
115
                document.addEventListener('click', function (event:Event) {
116
                    that.eventBodyClick(event);
117
                });
118
            }
119
        }
120
121
        protected eventToggleClick(event: Event): void {
122
            event.preventDefault();
123
124
            let that = this;
125
126
            if (that.$el.classList.contains(that.options.class.open as string)) {
127
                that.close();
128
            }
129
            else {
130
                that.open();
131
            }
132
        }
133
134
        protected eventBodyClick(event: Event): void {
135
            let that = this;
136
137
            if (!that.elementInDropdown(event.target) ) {
138
                that.close();
139
            }
140
        }
141
142
         protected elementInDropdown($el: any): boolean {
143
            let that = this,
144
                parent = $el;
145
146
            while (parent) {
147
                if (parent === that.$el) {
148
                    return true;
149
                }
150
151
                parent = parent.parentNode as Element;
152
            }
153
154
            return false;
155
        }
156
157
        public open(): void {
158
            this.$el.classList.add(this.options.class.open);
159
160
            if(this.options.onOpen) {
161
                this.options.onOpen.call(this);
162
            }
163
        }
164
165
        public close(): void {
166
            this.$el.classList.remove(this.options.class.open);
167
168
            if(this.options.onClose) {
169
                this.options.onClose.call(this);
170
            }
171
        }
172
    }
173
174
    return Dropdown;
175
}));