From 6852d0807d4501e266f23560479d2cffc33cad17 Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Wed, 5 Jun 2013 22:45:19 +0000 Subject: [PATCH] Improve UI of multi-row selectbox - Only check button, no x (check toggles all/none), aligned with checkboxes - Header with buttons hides when not hovering over checkbox, saving space - Account select now has quick-select in header --- etemplate/js/et2_widget_selectAccount.js | 47 ++++++++++++++++++---- etemplate/js/et2_widget_selectbox.js | 28 ++++++++----- etemplate/templates/default/etemplate2.css | 28 +++++++++++-- 3 files changed, 80 insertions(+), 23 deletions(-) diff --git a/etemplate/js/et2_widget_selectAccount.js b/etemplate/js/et2_widget_selectAccount.js index a8b98811f5..643054dce5 100644 --- a/etemplate/js/et2_widget_selectAccount.js +++ b/etemplate/js/et2_widget_selectAccount.js @@ -71,19 +71,31 @@ var et2_selectAccount = et2_selectbox.extend( this.egw().debug("warn", "Invalid account_type: %s Valid options:",_attrs['account_type'], this.account_types); } - this._super.apply(this, arguments); - // Holder for search jQuery nodes this.search = null; // Reference to object with dialog this.dialog = null; + + this._super.apply(this, arguments); }, destroy: function() { this._super.apply(this, arguments); }, + /** + * Tell et2 widget framework where to go + */ + getDOMNode: function(_sender) { + if(_sender == this.search_widget) + { + return this.search != null ? this.search[0] : this.search_widget._parent.getDOMNode(); + } + return this._super.apply(this, arguments); + }, + + /** * Single selection - override to add search button */ @@ -141,18 +153,38 @@ var et2_selectAccount = et2_selectbox.extend( var type = this.egw().preference('account_selection', 'common'); if(type == 'primary_group') { + // Allow search 'inside' this widget + this.supportedWidgetClasses = [et2_link_entry]; + // Add quick search - turn off multiple to get normal result list + this.options.multiple = false; + this._create_search(); + + // Clear search box after select + var old_select = this.search_widget.select; + this.search_widget.select = function() { + old_select.apply(this, arguments); + this.search.val(''); + }; + + // Put search results as a DOM sibling of the options, for proper display + this.search_widget.search.on("autocompleteopen", jQuery.proxy(function() { + this.search_widget.search.data("autocomplete").menu.element.appendTo(this.node); + },this)); + this.search = jQuery(document.createElement("li")) + .appendTo(this.multiOptions.prev().find('ul')); + this.options.multiple = true; + // Add search button var button = jQuery(document.createElement("li")) .addClass("et2_clickable") .click(this, this._open_multi_search) .append('') - .append(""+this.egw().lang('search')+""); var type = this.egw().preference('account_selection', 'common'); - // Put it first so check/uncheck don't move around - this.multiOptions.prev().show().find('ul') - .prepend(button); + // Put it last so check/uncheck doesn't move around + this.multiOptions.prev().find('ul') + .append(button); } else if (type == 'popup') { @@ -490,7 +522,6 @@ var et2_selectAccount = et2_selectbox.extend( .addClass("et2_clickable") .click(selected, function(e) {jQuery("li",e.data).remove();}) .append('') - .append(""+this.egw().lang('Remove all')+"") .appendTo(controls); // Add in currently selected @@ -513,7 +544,7 @@ var et2_selectAccount = et2_selectbox.extend( var option = jQuery(document.createElement('li')) .attr("id",'sel_'+value) .appendTo(list); - jQuery('') + jQuery('
') .css("float", "right") .appendTo(option) .click(function() { diff --git a/etemplate/js/et2_widget_selectbox.js b/etemplate/js/et2_widget_selectbox.js index faac3cdc31..b4b5b3a957 100644 --- a/etemplate/js/et2_widget_selectbox.js +++ b/etemplate/js/et2_widget_selectbox.js @@ -374,16 +374,10 @@ var et2_selectbox = et2_inputWidget.extend( icon_class: 'ui-icon-check', label: 'Check all', click: function(e) { - jQuery("input",e.data).attr("checked", true); + var all_set = jQuery("input[type='checkbox']",e.data).prop("checked"); + jQuery("input[type='checkbox']",e.data).prop("checked", !all_set); } }, - uncheck: { - icon_class: 'ui-icon-closethick', - label: 'Uncheck all', - click: function(e) { - jQuery("input",e.data).attr("checked", false); - } - } }; for(var key in header_controls) { @@ -391,15 +385,27 @@ var et2_selectbox = et2_inputWidget.extend( .addClass("et2_clickable") .click(options, header_controls[key].click) .append('') - .append(""+this.egw().lang(header_controls[key].label)+"") .appendTo(controls); } } - else if (header[0].childNodes.length == 0) + + // Hide the header, only show it on hover / focus, but show it out of flow, above + // the list of options so it doesn't reflow the page + var hide_header = !this.options.empty_label && !this.options.label; + if(hide_header) { - // Hide header - nothing there but padding + // Hide header header.hide(); + + // Show / hide again + node.on('mouseenter focusin', function() { + header.show(); + header.css("width", header.css("width")); + header.css("position", "absolute"); + header.css("top", options.position().top - header.outerHeight()); + }); + node.on('mouseleave focusout', function() {if(hide_header) header.hide();}); } this.setDOMNode(node[0]); diff --git a/etemplate/templates/default/etemplate2.css b/etemplate/templates/default/etemplate2.css index a52bddaf4d..860293051e 100644 --- a/etemplate/templates/default/etemplate2.css +++ b/etemplate/templates/default/etemplate2.css @@ -251,20 +251,31 @@ button.et2_button_text:focus, input[type=button]:focus { * Multi-select widget */ .et2_selectbox .ui-widget-header { - padding: 2px 6px 0px 6px; + padding: 0px 6px 0px 6px; + text-align: center; } .et2_selectbox .ui-widget-header ul { - float: right; + float: left; + margin-left: -5px; + text-align: left; } .et2_selectbox .ui-widget-header li { float: left; - padding: 2px; padding-top: 0px } -.et2_selectbox .ui-widget-header li span.ui-icon { +.et2_selectbox .ui-widget-header li>span.ui-icon { float: left; margin-top: -2px; } +.et2_selectbox .ui-widget-header li>div.et2_link_entry { + /* Shrink search box to same size as header */ + margin-top: -2px; + margin-bottom: -2px; + margin-right: 1ex; +} +.et2_selectbox .ui-widget-header li>div.et2_link_entry input { + height: 14px; +} .et2_selectbox .ui-multiselect-checkboxes { overflow-y: scroll; position: relative; @@ -304,6 +315,14 @@ button.et2_button_text:focus, input[type=button]:focus { height: 1.8em; } +.et2_selectbox .ui-multiselect-checkboxes div.ui-icon-close { + visibility: hidden; + padding: 0px; +} +.et2_selectbox .ui-multiselect-checkboxes li:hover div.ui-icon-close { + visibility: visible; +} + /* Read-only multi-select */ ul.et2_selectbox { margin: 0px; @@ -493,6 +512,7 @@ div.et2_link_entry input.ui-autocomplete-input { top: 3px; left: -18px; cursor: pointer; + margin-top: -3px; } /* Link to */