PageSourceSearch

https://terrancelaw.github.io/cow_event/js/dropdownMenu.js

js terrancelaw.github.io collected 2026-10-03 10:04:32 UTC 7,849 bytes, 269 lines download raw bytes

1function DropdownMenu(dropdownEl, dropdownName, dropdownList, onClickListItem, isDisabled, defaultSelection = null) {
2	const self = this;
3
4	self.dropdownEl = dropdownEl;
5	self.dropdownName = dropdownName;
6	self.dropdownList = dropdownList;
7	self.onClickListItem = onClickListItem;
8	self.isDisabled = isDisabled;
9	self.defaultSelection = defaultSelection;
10
11	if (isDisabled) {
12		self.initName();
13		self.addDropdownObjectToEl();
14		self.addDisabledClass();
15	}
16	else if (!isDisabled) {
17		self.initName();
18		self.addDropdownObjectToEl();
19		self.addDisabledClass();
20		self.initDefaultSelection();
21		self.initClickButtonBehaviour();
22	}
23}
24
25DropdownMenu.prototype.initName = initDropdownMenuName;
26DropdownMenu.prototype.addDropdownObjectToEl = addDropdownObjectToEl;
27DropdownMenu.prototype.addDisabledClass = addDisabledClassForDropdownMenu;
28DropdownMenu.prototype.initDefaultSelection = initDropdownDefaultSelection;
29DropdownMenu.prototype.initClickButtonBehaviour = initClickDropdownButtonBehaviour;
30
31DropdownMenu.prototype.appendContainerToDropdownMenu = appendContainerToDropdownMenu;
32DropdownMenu.prototype.appendListItemsToDropdownMenu = appendListItemsToDropdownMenu;
33DropdownMenu.prototype.initSearchBoxBehaviour = initDropdownSearchBoxBehaviour;
34DropdownMenu.prototype.initClickListItemBehaviour = initClickDropdownListItemBehaviour;
35DropdownMenu.prototype.showDropdownMenu = showDropdownMenu;
36
37DropdownMenu.prototype.closeDropdownMenu = closeDropdownMenu;
38DropdownMenu.prototype.updateDropdownMenu = updateDropdownMenu;
39
40function initDropdownMenuName() {
41	const self = this;
42	var dropdownEl = self.dropdownEl;
43	var dropdownName = self.dropdownName;
44
45	$(dropdownEl).find('.name')
46		.html(dropdownName);
47}
48
49function addDropdownObjectToEl() {
50	const self = this;
51	var dropdownEl = self.dropdownEl;
52
53	d3.select(dropdownEl).datum(self);
54}
55
56function addDisabledClassForDropdownMenu() {
57	const self = this;
58	var dropdownEl = self.dropdownEl;
59	var isDisabled = self.isDisabled;
60
61	if (isDisabled)
62		$(dropdownEl).addClass('disabled');
63	else if (!isDisabled)
64		$(dropdownEl).removeClass('disabled');
65}
66
67function initDropdownDefaultSelection() {
68	const self = this;
69	var dropdownList = self.dropdownList;
70	var defaultSelection = self.defaultSelection;
71	var dropdownEl = self.dropdownEl;
72	var defaultSelectionExist = false;
73
74	// check if defaultSelectionExist
75	for (var i = 0; i < dropdownList.length; i++)
76		if (dropdownList[i] == defaultSelection) 
77			{ defaultSelectionExist = true; break; }
78
79	// if defaultSelectionExist
80	if (defaultSelectionExist) {
81		$(dropdownEl).find('.open-menu-button > .button-text')
82			.html(defaultSelection);
83	}
84
85	// if not defaultSelectionExist
86	else if (!defaultSelectionExist) {
87		self.defaultSelection = null;
88		$(dropdownEl).find('.open-menu-button > .button-text')
89			.html('');
90	}
91}
92
93function initClickDropdownButtonBehaviour() {
94	const self = this;
95	var dropdownEl = self.dropdownEl;
96
97	$(dropdownEl)
98		.unbind('click')
99		.on('click', clickDropdownButton);
100
101	function clickDropdownButton() {
102		$('#dropdown-menu')
103			.removeClass()
104			.removeAttr('style')
105			.empty();
106
107		self.appendContainerToDropdownMenu();
108		self.appendListItemsToDropdownMenu();
109		self.initSearchBoxBehaviour();
110		self.initClickListItemBehaviour();
111		self.showDropdownMenu();
112	}
113}
114
115function appendContainerToDropdownMenu() {
116	var searchBoxHTML = '<div class="search-box">' +
117							'<input type="text">' +
118							'<span class="fa fa-search"></span>' +
119						'</div>';
120	var containerHTML = '<div class="container"></div>';
121
122	$('#dropdown-menu')
123		.append(searchBoxHTML)
124		.append(containerHTML);
125}
126
127function appendListItemsToDropdownMenu() {
128	const self = this;
129	var dropdownList = self.dropdownList;
130
131	for (var i = 0; i < dropdownList.length; i++) {
132		var listItem = dropdownList[i];
133		var listItemHTML = '<div class="item">' + listItem + '</div>';
134		var addedListItemEl = null;
135
136		$('#dropdown-menu').find('.container').append(listItemHTML);
137		addedListItemEl = $('#dropdown-menu > .container > .item').last()[0];
138		d3.select(addedListItemEl).datum(listItem);
139	}
140}
141
142function initDropdownSearchBoxBehaviour() {
143	const self = this;
144
145	$('#dropdown-menu > .search-box > input')
146		.unbind('input')
147		.on('input', onInputSearchQuery);
148
149	function onInputSearchQuery() {
150		var searchQueryInLowerCase = $(this).val().toLowerCase();
151
152		if (searchQueryInLowerCase == '') {
153			showAllListItems();
154			markMatchedString(searchQueryInLowerCase);
155		}
156		else if (searchQueryInLowerCase != '') {
157			showMatchedListItems(searchQueryInLowerCase);
158			markMatchedString(searchQueryInLowerCase);
159		}
160	}
161
162	function showAllListItems() {
163		$('#dropdown-menu > .container > .item').each(function() {
164			$(this).css('display', '');
165		});
166	}
167
168	function showMatchedListItems(searchQueryInLowerCase) {
169		$('#dropdown-menu > .container > .item').each(function() {
170			var data = d3.select(this).datum();
171			var listItemInLowerCase = data.toLowerCase();
172			var queryFoundInListItem = listItemInLowerCase.indexOf(searchQueryInLowerCase) != -1;
173			if (queryFoundInListItem) $(this).css('display', '');
174			else if (!queryFoundInListItem) $(this).css('display', 'none');
175		});
176	}
177
178	function markMatchedString(searchQueryInLowerCase) {
179		var markInstance = new Mark(document.querySelectorAll('#dropdown-menu > .container'));
180
181		markInstance.unmark({
182	  		done: function(){
183	    		markInstance.mark(searchQueryInLowerCase, {
184    				'separateWordSearch': false,
185    				'diacritics': false
186	    		});
187	    	}
188	  	});
189	}
190}
191
192function initClickDropdownListItemBehaviour() {
193	const self = this;
194
195	$('#dropdown-menu > .container > .item')
196		.unbind('click')
197		.on('click', onClickDropdownMenuItem);
198
199	function onClickDropdownMenuItem() {
200		var data = d3.select(this).datum();
201
202		self.closeDropdownMenu();
203		self.updateDropdownMenu(data);
204		self.onClickListItem(data);
205	}
206}
207
208function showDropdownMenu() {
209	const self = this;
210	var dropdownEl = self.dropdownEl;
211	var dropdownList = self.dropdownList;
212	var dropdownButtonEl = $(dropdownEl).find('.open-menu-button');
213	var dropdownNameEl = $(dropdownEl).find('.name')[0];
214	var dropdownNameHeight = $(dropdownNameEl).outerHeight();
215	var dropdownButtonOffset = $(dropdownButtonEl).offset();
216	var dropdownButtonHeight = $(dropdownButtonEl).outerHeight();
217	var dropdownButtonWidth = $(dropdownButtonEl).outerWidth();
218	var dropdownButtonTop = dropdownButtonOffset.top - 8 - 8 + dropdownNameHeight + 6;
219	var dropdownButtonLeft = dropdownButtonOffset.left - 8;
220	var windowHeight = $(window).height();
221	var dropdownMenuHeight = 0; // estimate
222	var isYOverflown = null;
223
224	dropdownMenuHeight = dropdownList.length * 33 + 41
225	if (dropdownMenuHeight > 180) dropdownMenuHeight = 180;
226	isYOverflown = dropdownButtonTop + dropdownButtonHeight + dropdownMenuHeight > windowHeight;
227
228	if (!isYOverflown)
229		$('#dropdown-menu')
230			.addClass('dropdown-menu-items')
231			.addClass('top-arrow')
232			.addClass('show')
233			.css('width', dropdownButtonWidth)
234			.css('top', dropdownButtonTop + dropdownButtonHeight + 8)
235			.css('left', dropdownButtonLeft + dropdownButtonWidth / 2);
236
237	else if (isYOverflown)
238		$('#dropdown-menu')
239			.addClass('dropdown-menu-items')
240			.addClass('bottom-arrow')
241			.addClass('show')
242			.css('width', dropdownButtonWidth)
243			.css('top', dropdownButtonTop - dropdownButtonHeight - 3)
244			.css('left', dropdownButtonLeft + dropdownButtonWidth / 2);
245
246	// add class to dropdown for changing visual
247	$(dropdownEl).addClass('opened');
248}
249
250function closeDropdownMenu() {
251	const self = this;
252	var dropdownEl = self.dropdownEl;
253
254	$('#dropdown-menu')
255		.removeClass()
256		.removeAttr('style')
257		.empty();
258
259	// remove class from dropdown for changing visual
260	$(dropdownEl).removeClass('opened');
261}
262
263function updateDropdownMenu(data) {
264	const self = this;
265	var dropdownEl = self.dropdownEl;
266
267	$(dropdownEl).find('.open-menu-button > .button-text')
268		.html(data);
269}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.