mirror of
				https://github.com/invoiceninja/invoiceninja.git
				synced 2025-10-31 06:27:34 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			153 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			153 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| // maximize-select2-height v1.0.2
 | |
| // (c) Panorama Education 2015
 | |
| // MIT License
 | |
| // https://github.com/panorama-ed/maximize-select2-height
 | |
| 
 | |
| // This jQuery/Select2 plugin expands a Select2 dropdown to take up as much
 | |
| // height as possible given its position on the page and the current viewport
 | |
| // size. The plugin correctly handles:
 | |
| //   - Dynamic window resizing.
 | |
| //   - The effects of scroll bars on the viewport.
 | |
| //   - Select2 rendering dropdowns both upwards and downwards.
 | |
| 
 | |
| // NOTE: The original <select> element that is $().select2()'d *must* have a
 | |
| // unique ID for this code to work. (Ex: <select id="my-unique-id"></select>)
 | |
| 
 | |
| (function ($) {
 | |
|   "use strict";
 | |
| 
 | |
|   // We can find these elements now, since the properties we check on them are
 | |
|   // all via methods that are recalculated each time.
 | |
|   var $window = $(window);
 | |
|   var $document = $(document);
 | |
| 
 | |
|   // @param {Object} options The options object passed in when this plugin is
 | |
|   //   initialized
 | |
|   // @param {Boolean} dropdownDownwards True iff the dropdown is rendered
 | |
|   //   downwards (Select2 sometimes renders the options upwards to better fit on
 | |
|   //   a page)
 | |
|   // @return {Object} The options passed in, combined with defaults. Keys are:
 | |
|   //   - cushion: The number of pixels between the edge of the dropdown and the
 | |
|   //              edge of the viewable window. [Default: 10, except when a
 | |
|   //              horizontal scroll bar would interfere, in which case it's 30.]
 | |
|   //              NOTE: If a value is passed in, no adjustments for possible
 | |
|   //              scroll bars are made.
 | |
|   var settings = function (options, dropdownDownwards) {
 | |
|     return $.extend({
 | |
|       cushion: (
 | |
|         dropdownDownwards && $document.width() > $window.width()
 | |
|       ) ? 30 : 10
 | |
|     }, options);
 | |
|   };
 | |
| 
 | |
|   // @param {String} id The DOM element ID for the original <select> node
 | |
|   // @param {jQuery object} $select2Results The DOM element with class
 | |
|   //   "select2-results"
 | |
|   // @param {jQuery object} $grandparent The grandparent object of the
 | |
|   //   $select2Results object
 | |
|   // @param {Object} options The options object passed in when this plugin is
 | |
|   //   initialized
 | |
|   // @param {Boolean} dropdownDownwards True iff the dropdown is rendered
 | |
|   //   downwards (Select2 sometimes renders the options upwards to better fit on
 | |
|   //   a page)
 | |
|   // @return {Number} the maximum height of the Select2 results box to display
 | |
|   var computeMaxHeight = function (
 | |
|     id, $select2Results, $grandparent, options, dropdownDownwards
 | |
|   ) {
 | |
|     var height;
 | |
|     var resultsBoxMiscellaniaHeight;
 | |
|     var widgetBoxOffset;
 | |
| 
 | |
|     if (dropdownDownwards) {
 | |
|       // When the dropdown appears downwards, the formula is:
 | |
|       //   visible window size
 | |
|       // + out-of-window pixels we've scrolled past
 | |
|       // - size of content (including offscreen content) above results box
 | |
|       // ------------------------------------------
 | |
|       //   total height available to us
 | |
| 
 | |
|       // innerHeight is more accurate across browsers than $(window).height().
 | |
|       height = window.innerHeight +
 | |
|                $window.scrollTop() -
 | |
|                $select2Results.offset().top;
 | |
|     } else {
 | |
|       // When the dropdown appears upwards, the formula is:
 | |
|       //   vertical position of the widget (clickable) dropdown box
 | |
|       // - out-of-window pixels we've scrolled past
 | |
|       // - height of the search box and other content above the actual results
 | |
|       //   but in the results box
 | |
|       // ------------------------------------------
 | |
|       //   total height available to us
 | |
| 
 | |
|       // Compute the global vertical offset of the widget box (the one with the
 | |
|       // downward arrow that the user clicks on to expose options).
 | |
|       widgetBoxOffset = $("#select2-" + id + "-container").
 | |
|                         parent().parent().parent().offset().top;
 | |
| 
 | |
|       // Compute the height, if any, of search box and other content in the
 | |
|       // results box but not part of the results.
 | |
|       resultsBoxMiscellaniaHeight = $grandparent.height() -
 | |
|                                     $select2Results.height();
 | |
|       height = widgetBoxOffset -
 | |
|                $window.scrollTop() -
 | |
|                resultsBoxMiscellaniaHeight;
 | |
|     }
 | |
| 
 | |
|     // Leave a little cushion to prevent the dropdown from
 | |
|     // rendering off the edge of the viewport.
 | |
|     return height - settings(options, dropdownDownwards).cushion;
 | |
|   };
 | |
| 
 | |
|   // Call on a jQuery Select2 element to maximize the height of the dropdown
 | |
|   // every time it is opened.
 | |
|   // @param {Object} options The options object passed in when this plugin is
 | |
|   //   initialized
 | |
|   $.fn.maximizeSelect2Height = function (options) {
 | |
|     return this.each(function (_, el) {
 | |
|       // Each time the Select2 is opened, resize it to take up as much vertical
 | |
|       // space as possible given its position and the current viewport size.
 | |
|       $(el).on("select2:open", function () {
 | |
|         // We have to put this code block inside a timeout because we determine
 | |
|         // whether the dropdown is rendered upwards or downwards via a hack that
 | |
|         // looks at the CSS classes, and these aren't set until Select2 has a
 | |
|         // chance to render the box, which occurs after this event fires.
 | |
| 
 | |
|         // The alternative solution that avoids using a timeout would be to
 | |
|         // directly modify the document's stylesheets (instead of the styles for
 | |
|         // individual elements), but that is both ugly/dangerous and actually
 | |
|         // impossible for us because we need to modify the styles of a parent
 | |
|         // node of a given DOM node when the parent has no unique ID, which CSS
 | |
|         // doesn't have the ability to do.
 | |
|         setTimeout(function () {
 | |
|           var $select2Results = $("#select2-" + el.id + "-results");
 | |
|           var $parent = $select2Results.parent();
 | |
|           var $grandparent = $parent.parent();
 | |
|           var dropdownDownwards = $grandparent
 | |
|                                   .hasClass("select2-dropdown--below");
 | |
| 
 | |
|           var maxHeight = computeMaxHeight(
 | |
|             el.id,
 | |
|             $select2Results,
 | |
|             $grandparent,
 | |
|             options,
 | |
|             dropdownDownwards
 | |
|           );
 | |
| 
 | |
|           // Set the max height of the relevant DOM elements. We use max-height
 | |
|           // instead of height directly to correctly handle cases in which there
 | |
|           // are only a few elements (we don't want a giant empty dropdown box).
 | |
|           $parent.css("max-height", maxHeight);
 | |
|           $select2Results.css("max-height", maxHeight);
 | |
| 
 | |
|           // Select2 corrects the positioning of the results box on scroll, so
 | |
|           // we trigger that event here to let it auto-correct. This is done for
 | |
|           // the case where the dropdown appears upwards; we adjust its max
 | |
|           // height but we also want to move it up further, lest it cover up the
 | |
|           // initial dropdown box.
 | |
|           $(document).trigger("scroll");
 | |
|         });
 | |
|       });
 | |
|     });
 | |
|   };
 | |
| })(jQuery);
 |