dynamic select field
This commit is contained in:
		
							parent
							
								
									f8cfcf9f34
								
							
						
					
					
						commit
						29a7b0c3e0
					
				|  | @ -1219,6 +1219,8 @@ class htmlSelect extends htmlElement { | ||||||
| 	protected $tableRowsToHide = array(); | 	protected $tableRowsToHide = array(); | ||||||
| 	/** list of enclosing table rows to show when checked */ | 	/** list of enclosing table rows to show when checked */ | ||||||
| 	protected $tableRowsToShow = array(); | 	protected $tableRowsToShow = array(); | ||||||
|  | 	/** dynamic scrolling */ | ||||||
|  | 	private $dynamicScrolling = false; | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * Constructor. | 	 * Constructor. | ||||||
|  | @ -1349,6 +1351,10 @@ class htmlSelect extends htmlElement { | ||||||
| 	 * @param array $elements list of options | 	 * @param array $elements list of options | ||||||
| 	 */ | 	 */ | ||||||
| 	private function printOptionsHTML($elements) { | 	private function printOptionsHTML($elements) { | ||||||
|  | 		if ($this->dynamicScrolling) { | ||||||
|  | 			echo "<option value=\"#\">#</option>\n"; | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
| 		// sorting
 | 		// sorting
 | ||||||
| 		if ($this->sortElements) { | 		if ($this->sortElements) { | ||||||
| 			if ($this->hasDescriptiveElements) { | 			if ($this->hasDescriptiveElements) { | ||||||
|  | @ -1568,6 +1574,24 @@ class htmlSelect extends htmlElement { | ||||||
| 		return 'tr'; | 		return 'tr'; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Enable dynamic scrolling. This limits the number of select options to 10000 by dynamically adding/removing options. | ||||||
|  | 	 * This will not be enabled when optgroups are used or the option size is less than 10000. | ||||||
|  | 	 */ | ||||||
|  | 	public function enableDynamicScrolling() { | ||||||
|  | 		// not possible for optgroups and smaller option lists
 | ||||||
|  | 		if ((sizeof($this->elements) < 10000) || $this->containsOptgroups) { | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		$this->dynamicScrolling = true; | ||||||
|  | 		$elementData = array(); | ||||||
|  | 		foreach ($this->elements as $key => $value) { | ||||||
|  | 			$elementData[] = array('label' => $key, 'value' => $value); | ||||||
|  | 		} | ||||||
|  | 		$this->addDataAttribute('dynamic-options', json_encode($elementData)); | ||||||
|  | 		$this->cssClasses[] = 'lam-dynamicOptions'; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  |  | ||||||
|  | @ -1111,6 +1111,139 @@ window.lam.html.preventEnter = function() { | ||||||
| 	}); | 	}); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | window.lam.dynamicSelect = window.lam.dynamicSelect || {}; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Activates dynamic selection for all marked select fields. | ||||||
|  |  */ | ||||||
|  | window.lam.dynamicSelect.activate = function() { | ||||||
|  | 	var dynamicSelects = jQuery('.lam-dynamicOptions'); | ||||||
|  | 	dynamicSelects.each(function() { | ||||||
|  | 		var selectField = jQuery(this); | ||||||
|  | 		selectField.data('option-height', selectField.find("option").height()); | ||||||
|  | 		selectField.data('select-height', selectField.height()); | ||||||
|  | 		selectField.data('select-last-scroll-top', 0); | ||||||
|  | 		selectField.data('select-current-scroll', 0); | ||||||
|  | 		selectField.html(''); | ||||||
|  | 		var options = selectField.data('dynamic-options'); | ||||||
|  | 		var maxOptions = 3000; | ||||||
|  | 		var numOfOptionBeforeToLoadNextSet = 10; | ||||||
|  | 		var numberOfOptionsToLoad = 200; | ||||||
|  | 		for (var i = 0; i < maxOptions; i++) { | ||||||
|  | 			selectField.append(window.lam.dynamicSelect.createOption(options[i], i)); | ||||||
|  | 		} | ||||||
|  | 		if (options.length > maxOptions) { | ||||||
|  | 			// activate scrolling logic only if enough options are set
 | ||||||
|  | 			selectField.scroll(function(event) { | ||||||
|  | 				window.lam.dynamicSelect.onScroll(selectField, event, maxOptions, numOfOptionBeforeToLoadNextSet, numberOfOptionsToLoad); | ||||||
|  | 			}); | ||||||
|  | 		} | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Creates an option field inside the select. | ||||||
|  |  * | ||||||
|  |  * @param data option data | ||||||
|  |  * @param index index in list of all options | ||||||
|  |  * @returns option | ||||||
|  |  */ | ||||||
|  | window.lam.dynamicSelect.createOption = function(data, index) { | ||||||
|  | 	var newOption = jQuery(document.createElement("option")); | ||||||
|  | 	newOption.attr('value', data.value); | ||||||
|  | 	newOption.data('index', index); | ||||||
|  | 	newOption.text(data.label); | ||||||
|  | 	return newOption; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Onscroll event. | ||||||
|  |  * | ||||||
|  |  * @param selectField select field | ||||||
|  |  * @param event event | ||||||
|  |  * @param maxOptions maximum options to show | ||||||
|  |  * @param numOfOptionBeforeToLoadNextSet number of options to reach before end of list | ||||||
|  |  * @param numberOfOptionsToLoad number of options to add | ||||||
|  |  */ | ||||||
|  | window.lam.dynamicSelect.onScroll = function(selectField, event, maxOptions, numOfOptionBeforeToLoadNextSet, numberOfOptionsToLoad) { | ||||||
|  | 	var scrollTop = selectField.scrollTop(); | ||||||
|  | 	var totalHeight = selectField.find("option").length * selectField.data('option-height'); | ||||||
|  | 	var lastScrollTop = selectField.data('select-last-scroll-top'); | ||||||
|  | 	var selectBoxHeight = selectField.data('select-height'); | ||||||
|  | 	var singleOptionHeight = selectField.data('option-height'); | ||||||
|  | 	var currentScroll = scrollTop + selectBoxHeight; | ||||||
|  | 	selectField.data('select-current-scroll-top', scrollTop); | ||||||
|  | 	if ((scrollTop >= lastScrollTop) | ||||||
|  | 			&& ((currentScroll + (numOfOptionBeforeToLoadNextSet * singleOptionHeight)) >= totalHeight)) { | ||||||
|  | 		window.lam.dynamicSelect.loadNextOptions(selectField, maxOptions, numberOfOptionsToLoad); | ||||||
|  | 	} | ||||||
|  | 	else if ((scrollTop <= lastScrollTop) | ||||||
|  | 			&& ((scrollTop - (numOfOptionBeforeToLoadNextSet * singleOptionHeight)) <= 0)) { | ||||||
|  | 		window.lam.dynamicSelect.loadPreviousOptions(selectField, maxOptions, numberOfOptionsToLoad); | ||||||
|  | 	} | ||||||
|  | 	selectField.data('select-last-scroll-top', scrollTop); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Loads the next bunch of options at the end. | ||||||
|  |  * | ||||||
|  |  * @param selectField selct field | ||||||
|  |  * @param maxOptions maximum options to show | ||||||
|  |  * @param numberOfOptionsToLoad number of options to add | ||||||
|  |  */ | ||||||
|  | window.lam.dynamicSelect.loadNextOptions = function(selectField, maxOptions, numberOfOptionsToLoad) { | ||||||
|  | 	var selectBoxHeight = selectField.data('select-height'); | ||||||
|  | 	var singleOptionHeight = selectField.data('option-height'); | ||||||
|  | 	var currentScrollPosition = selectField.data('select-current-scroll-top') + selectBoxHeight; | ||||||
|  | 	var options = selectField.data('dynamic-options'); | ||||||
|  | 	var lastIndex = selectField.children().last().data('index'); | ||||||
|  | 	for (var toAdd = 0; toAdd < numberOfOptionsToLoad; toAdd++) { | ||||||
|  | 		var addPos = lastIndex + 1 + toAdd; | ||||||
|  | 		if (options[addPos] === undefined) { | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 		selectField.append(window.lam.dynamicSelect.createOption(options[addPos], addPos)); | ||||||
|  | 	} | ||||||
|  | 	var numberOfOptions = selectField.children().length; | ||||||
|  | 	var toRemove = numberOfOptions - maxOptions; | ||||||
|  | 	if (toRemove > 0) { | ||||||
|  | 		selectField.children().slice(0, toRemove).remove(); | ||||||
|  | 	} | ||||||
|  | 	else { | ||||||
|  | 		toRemove = 0; | ||||||
|  | 	} | ||||||
|  | 	selectField.scrollTop(currentScrollPosition - selectBoxHeight - (toRemove * singleOptionHeight)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Loads the next bunch of options at the beginning. | ||||||
|  |  * | ||||||
|  |  * @param selectField selct field | ||||||
|  |  * @param maxOptions maximum options to show | ||||||
|  |  * @param numberOfOptionsToLoad number of options to add | ||||||
|  |  */ | ||||||
|  | window.lam.dynamicSelect.loadPreviousOptions = function(selectField, maxOptions, numberOfOptionsToLoad) { | ||||||
|  | 	var singleOptionHeight = selectField.data('option-height'); | ||||||
|  | 	var currentScrollPosition = selectField.data('select-current-scroll-top'); | ||||||
|  | 	var options = selectField.data('dynamic-options'); | ||||||
|  | 	var lastIndex = selectField.children().first().data('index'); | ||||||
|  | 	var added = 0; | ||||||
|  | 	for (var toAdd = 0; toAdd < numberOfOptionsToLoad; toAdd++) { | ||||||
|  | 		var addPos = lastIndex - 1 - toAdd; | ||||||
|  | 		if (options[addPos] === undefined) { | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 		added++; | ||||||
|  | 		selectField.prepend(window.lam.dynamicSelect.createOption(options[addPos], addPos)); | ||||||
|  | 	} | ||||||
|  | 	var numberOfOptions = selectField.children().length; | ||||||
|  | 	var toRemove = numberOfOptions - maxOptions; | ||||||
|  | 	if (toRemove > 0) { | ||||||
|  | 		selectField.children().slice(maxOptions).remove(); | ||||||
|  | 	} | ||||||
|  | 	selectField.scrollTop(currentScrollPosition + (added * singleOptionHeight)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| window.lam.selfservice = window.lam.selfservice || {}; | window.lam.selfservice = window.lam.selfservice || {}; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  | @ -1173,6 +1306,7 @@ jQuery(document).ready(function() { | ||||||
| 	window.lam.tools.schema.select(); | 	window.lam.tools.schema.select(); | ||||||
| 	window.lam.html.activateLightboxes(); | 	window.lam.html.activateLightboxes(); | ||||||
| 	window.lam.html.preventEnter(); | 	window.lam.html.preventEnter(); | ||||||
|  | 	window.lam.dynamicSelect.activate(); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue