/
index.js
128 lines (110 loc) · 3.15 KB
/
index.js
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
119
120
121
122
123
124
125
126
127
128
/* jshint browser: true */
var eevee = require('eevee')
var query = require('query')
var tap = require('tap-event')
var keyname = require('keyname')
var classes = require('classes')
var closest = require('closest')
var clickable = require('clickable')
var matches = require('matches-selector')
var Emitter = require('emitter')
exports = module.exports = new Emitter()
exports.position = positionDropdown
exports.open = openDropdown
exports.close = closeDropdown
exports.clear = clearMenus
exports.right = true
exports.up = true
document.addEventListener('click', onclick, false)
document.addEventListener('touchstart', tap(onclick), false)
document.addEventListener('focus', clearAllMenus, true)
document.addEventListener('keyup', function (e) {
switch (keyname(e.which)) {
case 'esc': return clearMenus()
}
}, false)
eevee(document)
.on('click tap', '.Dropdown-toggle', function (e) {
e.preventDefault()
e.stopPropagation()
var dropdown = closest(this, '.Dropdown')
var c_dropdown = classes(dropdown)
var activate = !c_dropdown.has('open')
// just clear all the menus
if (!activate) return clearMenus()
// clear all menus but this one
clearMenus(dropdown)
// open this one
openDropdown(dropdown)
})
function onclick(e) {
if (!clickable(e)) return
clearAllMenus(e)
}
/**
* Clear all menus whenever a click or tap event occurs,
* but don't clear the current one.
*/
function clearAllMenus(e) {
var target = e.target
var dropdown
if (matches(target, '.Dropdown.open, .Dropdown.open *')) {
dropdown = closest(target, '.Dropdown', true)
}
clearMenus(dropdown)
}
/**
* Clear all menus except `except`.
*/
function clearMenus(except) {
var dropdowns = query.all('.Dropdown.open')
var dropdown
for (var i = 0; i < dropdowns.length; i++) {
dropdown = dropdowns[i]
if (dropdown !== except) closeDropdown(dropdown)
}
}
/**
* Position a menu.
*/
function positionDropdown(dropdown) {
var c_dropdown = classes(dropdown)
var rect = dropdown.getBoundingClientRect()
var d_width = dropdown.offsetWidth
// var d_height = dropdown.offsetHeight
var menu = query('.Dropdown-menu', dropdown)
var m_width = menu.offsetWidth
var m_height = menu.offsetHeight
var pos_x = 'left' // left-justified by default
var pos_y = 'down' // drop down by default
// calculate pos_x only if the menu is larger than .Dropdown
if (exports.right && d_width < m_width) {
var w_width = window.innerWidth
if (m_width - d_width > w_width - rect.right) pos_x = 'right'
}
// calculate pos_y
var w_height = window.innerHeight
if (exports.up && m_height > w_height - rect.bottom) pos_y = 'up'
c_dropdown
.add(pos_x)
.add(pos_y)
.remove(pos_x === 'left' ? 'right' : 'left')
.remove(pos_y === 'down' ? 'up' : 'down')
return dropdown
}
/**
* Open a menu.
*/
function openDropdown(dropdown) {
var c_dropdown = classes(dropdown)
if (c_dropdown.has('open')) return
c_dropdown.add('open')
positionDropdown(dropdown) // has to be after opening for iOS
exports.emit('open', dropdown)
return dropdown
}
function closeDropdown(dropdown) {
classes(dropdown).remove('open')
exports.emit('close', dropdown)
return dropdown
}