Archive

Archive for the ‘CSS’ Category

Select2: jqModal + Select2 = can’t type in

June 10th, 2015 No comments

    The Select2 control placed in the jqModal modal dialog doesn’t allow typing anything in. It’s unexpected, but explainable: jqModal eliminates all keypress and keydown events coming from without, i.e. coming from the controls not residing in the jqModal container. As I mentioned in the Select2: Make dropdown vertically wider, the Select2, in turn, dynamically appends the elements making up the dropdown (including the type-ahead search box) to the Body-tag, so they are literally out of jqModal dialog.

Select2 in jqModal - No Typing in

Where the contracted jqModal markup resembles the following:

<div id="myModalDialog" class="popup-6"...>
    <div class="pp6-header">
        <h3>Some Fancy Modal Dialog</h3>
        <span class="close" ...></span>
    </div>
    <div class="pp6-body" ...>
        
        <select id="mySelect2" ...>
			<option value="">Select an option</option>
			<option value="Product">Product</option>
			<option value="Producer">Producer</option>
			...
		</select>
			
    </div>
    <div class="pp6-footer">
        <a href="javascript: void(0)" class="ok" ...>OK</a>
        <a href="javascript: void(0)" class="close" ...>Cancel</a>
    </div>    
</div>

The Select2 and modal dialog are created as follows:

	$("#mySelect2").select2();
	...
	$("#myModalDialog").jqm({
            modal: true,
            trigger: false,
            onHide: function (h) {
                // hash object;
                //  w: (jQuery object) The modal element
                //  c: (object) The modal's options object 
                //  o: (jQuery object) The overlay element
                //  t: (DOM object) The triggering element                
                h.o.remove(); // remove overlay
                h.w.hide(); // hide window      
            },
            onShow: function (hash) {                
                hash.o.addClass("modalBackground").prependTo("body"); // add overlay
				
				// getNextDialogZIndex is my custom function, 
				// which increments z-index counter to place each new dialog atop the preceding one
                if (typeof getNextDialogZIndex === "function") {
                    var zIndex = getNextDialogZIndex();
                    hash.o.css("z-index", zIndex);
                    hash.w.css("z-index", zIndex + 1);
                }
                hash.w.css("left", 0);
                hash.w.css("right", 0);
                hash.w.css("position", "fixed");
                hash.w.css("margin-left", "auto");
                hash.w.css("margin-right", "auto");                
                hash.w.fadeIn();//show();
            }
        });		
	...
	$("#myModalDialog").jqmShow();

Below I quote the code from jqModal.js where the keypress, keydown, mousedown events are being handled, and their bubbling is being interrupted

F = function(t){
	// F: The Keep Focus Function (for modal: true dialos)
	// Binds or Unbinds (t) the Focus Examination Function (X) to keypresses and clicks
		
	$(document)[t]("keypress keydown mousedown",X);		
		
}, X = function(e){
	// X: The Focus Examination Function (for modal: true dialogs)

	var modal = $(e.target).data('jqm') || $(e.target).parents('.jqm-init:first').data('jqm'),
		activeModal = A[A.length-1].data('jqm');
		
	// allow bubbling if event target is within active modal dialog
	if(modal && modal.ID == activeModal.ID) return true; 

	// else, trigger focusFunc (focus on first input element and halt bubbling)
	return $.jqm.focusFunc(activeModal);
}

The code examines if the event target control or its first found parent marked with the ‘jqm-init‘ class have the associated datajqm‘. If so, the event will be allowed to pass through, otherwise it will be ignored.

Based on that, we can apply a workaround to Select2 control to unlock the type-ahead search box for typing in. The solution implies to associate the proper data named ‘jqm‘ with the Select2‘s dropdown. To catch the right dropdown (we don’t want to affect other Select2 controls on the page), a unique css class has to be applied to it. Plus the dropdown has to have the ‘jqm-init‘ class to be considered and analyzed by the jqModal code (note the following fragment in the listing above:)

$(e.target).parents('.jqm-init:first')

So, the solution should look like

// create Select2 and apply proper css classes to its dropdown
$("#mySelect2").select2({ dropdownCssClass: "someUniqueCssClass jqm-init" });

// capture the data associated with the jqModal container
var d = $("#myModalDialog").data("jqm");

// associate the captured data with the dropdown 
// to mimic the residence within the jqModal dialog
$(".someUniqueCssClass.jqm-init").data('jqm', d);

After that every keypress, keydown or mousedown event won’t be suppressed, but will be properly handled.

Select2: Make dropdown vertically wider

June 1st, 2015 No comments

    The Select2 is a quite useful and fancy replacement for ordinary Html Selects. Having a fixed number of items available to pick, you may want to make the dropdown of a Select2 control vertically wider to avoid extra scrolling.

Before - Select2 With Scrolling

Where the Select2 control is defined as follows

<select name="criteria" id="criteria">
	<option value="">Select a Search Criteria</option>
	<option value="Product">Product</option>
	<option value="Producer">Producer</option>
	<option value="Store">Store</option>
	<option value="State">State</option>
	<option value="Country">Country</option>
	<option value="Continent">Continent</option>
	<option value="Planet">Planet</option>
	<option value="Galaxy">Galaxy</option>
	<option value="Universe">Universe</option>
	<option value="Reality">Reality</option>
</select>
	$("#criteria").select2({
		minimumResultsForSearch: -1 // allows to hide the type-ahead search box,
		                            // so the Select2 acts as a regular dropdown list
	});

Whenever the Select2 has been clicked, the dropdown-elements will be dynamically added to the DOM at the end of the body-tag and will pop up. To make the dropdown wider we need to apply the proper ccs style to it. Of course, we can change the default css styles accompanying the Select2 control, but there is a way to apply desired changes to a certain control, not affecting other Select2 controls on the page. The custom css class can be attached to the target dropdown by the following call:

	$("#criteria").select2({
		minimumResultsForSearch: -1,
		dropdownCssClass: "verticallyWider" // the dropdownCssClass option is intended 
                                            // to specify a custom dropdown css class
	});                        

The Html markup dynamically added to the DOM when clicking the Select2 resembles the following (note the verticallyWider class, which among others has been applied to the outer div-tag):

<div class="select2-drop-mask" id="select2-drop-mask"></div>

<div class="select2-drop select2-display-none verticallyWider select2-drop-active" 
	id="select2-drop" 
	style="left: 828.49px; top: 112.61px; width: 300px; bottom: auto; display: block;">
	<div class="select2-search select2-search-hidden select2-offscreen">
		<label class="select2-offscreen" for="s2id_autogen2_search"></label>
		<input class="select2-input" id="s2id_autogen2_search" role="combobox" 
			aria-expanded="true" aria-activedescendant="select2-result-label-8" 
			aria-owns="select2-results-2" spellcheck="false" aria-autocomplete="list" 
			type="text" placeholder="" autocapitalize="off" 
			autocorrect="off" autocomplete="off" />
	</div>
   <ul class="select2-results" id="select2-results-2" role="listbox">
      <li class="select2-results-dept-0 select2-result select2-result-selectable" 
		role="presentation">
         <div class="select2-result-label" id="select2-result-label-3" role="option">
			<span class="select2-match"></span>Select a Search Criteria
		 </div>
      </li>
      <li class="select2-results-dept-0 select2-result select2-result-selectable" 
		role="presentation">
         <div class="select2-result-label" id="select2-result-label-4" role="option">
			<span class="select2-match"></span>Product
		 </div>
      </li>
      <li class="select2-results-dept-0 select2-result select2-result-selectable" 
		role="presentation">
         <div class="select2-result-label" id="select2-result-label-5" role="option">
			<span class="select2-match"></span>Producer
		 </div>
      </li>
      ...
      <li class="select2-results-dept-0 select2-result select2-result-selectable" 
		role="presentation">
         <div class="select2-result-label" id="select2-result-label-13" role="option">
			<span class="select2-match"></span>Reality
		 </div>
      </li>
   </ul>
</div>

The verticallyWider class, in turn, is defined as the following (so, specify the desired min/max heights in the styles):

.verticallyWider.select2-container .select2-results {
    max-height: 400px;
}
.verticallyWider .select2-results {
    max-height: 400px;
}
.verticallyWider .select2-choices {
    min-height: 150px; max-height: 400px; overflow-y: auto;
}

Below is the result of the modifications

After - Select2 With No Scrolling - Vertically Wider