forked from vaadin/vaadin-combo-box
-
Notifications
You must be signed in to change notification settings - Fork 0
/
vaadin-dropdown-behavior.html
145 lines (126 loc) · 4.32 KB
/
vaadin-dropdown-behavior.html
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
<script>
window.vaadin = window.vaadin || {};
vaadin.elements = vaadin.elements || {};
vaadin.elements.combobox = vaadin.elements.combobox || {};
/** @polymerBehavior vaadin.elements.combobox.DropdownBehavior */
vaadin.elements.combobox.DropdownBehavior = {
properties: {
/**
* True if the dropdown is open, false otherwise.
*/
opened: {
type: Boolean,
notify: true,
value: false,
reflectToAttribute: true,
observer: '_openedChanged'
},
/**
* Set to true to disable this element.
*/
disabled: {
type: Boolean,
value: false,
reflectToAttribute: true
},
/**
* When present, it specifies that the element field is read-only.
*/
readonly: {
type: Boolean,
value: false,
reflectToAttribute: true
}
},
/**
* Fired after the `vaadin-dropdown` opens.
*
* @event vaadin-dropdown-opened
*/
/**
* Fired after the `vaadin-dropdown` closes.
*
* @event vaadin-dropdown-closed
*/
/**
* Opens the dropdown list.
*/
open: function() {
// Prevent _open() being called when input is disabled or read-only
if (!this.disabled && !this.readonly) {
this.opened = true;
}
},
/**
* Closes the dropdown list.
*/
close: function() {
this.opened = false;
},
detached: function() {
// Making sure the overlay is closed and removed from DOM after detaching the dropdown.
this.close();
},
_openedChanged: function(value, old) {
// Prevent _close() being called when opened is set to its default value (false).
if (old === undefined) {
return;
}
if (this.opened) {
this._open();
} else {
this._close();
}
},
_open: function() {
this.$.overlay._moveTo(document.body);
this._addOutsideClickListener();
// For touch devices, we don't want to popup virtual keyboard on touch devices unless input
// is explicitly focused by the user.
if (!this.$.overlay.touchDevice) {
// If the inputElement is a paper-input, it would trigger an
// unnecessary blur event on focus. Check to see if there is a
// focused property and if it's already true.
// See also https://github.com/PolymerElements/paper-input/issues/341
if (!this.inputElement.focused) {
this.inputElement.focus();
}
}
this.fire('vaadin-dropdown-opened');
},
_close: function() {
this.$.overlay._moveTo(this.root);
this._removeOutsideClickListener();
this.fire('vaadin-dropdown-closed');
},
// We need to listen on 'click' / 'tap' event and capture it and close the overlay before
// propagating the event to the listener in the button. Otherwise, if the clicked button would call
// open(), this would happen: https://www.youtube.com/watch?v=Z86V_ICUCD4
_outsideClickListener: function(event) {
var eventPath = Polymer.dom(event).path;
if (eventPath.indexOf(this) < 0 && eventPath.indexOf(this.$.overlay) < 0) {
this.opened = false;
}
},
_addOutsideClickListener: function() {
// With desktop mouse, 'click' will make Polymer to fire 'tap' event.
// With touch devices, 'touchend' will make Polymer to fire 'tap' event, but browser will also fire 'click'.
// So, 'click' and 'tap' can come in any order and we need to make sure that the first one fired will close the overlay.
if (this.$.overlay.touchDevice) {
Polymer.Gestures.add(document, 'tap', null);
document.addEventListener('tap', this._outsideClickListener.bind(this), true);
} else {
document.addEventListener('click', this._outsideClickListener.bind(this), true);
}
},
_removeOutsideClickListener: function() {
if (this.$.overlay.touchDevice) {
// Not sure if this is a good idea to remove this Gesture globally, but that's how the iron-overlay-behavior does it.
Polymer.Gestures.remove(document, 'tap', null);
document.removeEventListener('tap', this._outsideClickListener.bind(this), true);
} else {
document.removeEventListener('click', this._outsideClickListener.bind(this), true);
}
}
};
</script>