From 664a9d9032aa199b541a6829a0948c3370782899 Mon Sep 17 00:00:00 2001 From: Jack Lukic Date: Wed, 13 Apr 2016 11:18:16 -0400 Subject: [PATCH] Multiple select dropdown now uses a sizer element to determine current text width, instead of estimating based on character count --- RELEASE-NOTES.md | 1 + src/definitions/modules/dropdown.js | 47 ++++++++++++++----- src/definitions/modules/dropdown.less | 8 ++++ src/themes/default/modules/dropdown.variables | 12 ++--- 4 files changed, 49 insertions(+), 19 deletions(-) diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index db3149845..ee754d627 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -5,6 +5,7 @@ **Major Enhancements** - **Webpack** - Modified all relative paths in project to prefix with `./` to make them webpack friendly (wont be misinterpreted as module) - **Popup** - Added new settings `autoRemove`, which is enabled by default. This will add special event listeners to auto hide a popup if the triggering element is removed from the DOM. This is useful in controlled DOM environments like Meteor/Ember/React to ensure a popup auto-hides itself when a page navigation or other DOM change occurs that may not trigger `mouseout`. +- **Dropdown** - Multiple select dropdown now sizes current dropdown input based on rendered width of a hidden element, not using an estimate based on character count. This means search will never break to a second line earlier than would normally fit in current line. - **Dropdown** - Added new setting for search selection `hideAdditions` this will remove showing user additions inside the menu, making for a more intuitive adding process. Dropdowns now have a new state `empty` which will format an active dropdown with empty results. #3791 - **All UI** - All UI now include _all_ sizing variations, `mini`, `tiny`, `small`, `large`, `big`, `huge`, `massive`. Headers remain with only 5 sizes `small-huge` to match `H1-H5` - **Icons** - Icons now use the latest Font Awesome `4.5.0` Icons. 50+ new icons+ are included. Thanks @BreadMaker for the PR and @davegandy for the font! diff --git a/src/definitions/modules/dropdown.js b/src/definitions/modules/dropdown.js index be9ec39e1..3f3706be3 100644 --- a/src/definitions/modules/dropdown.js +++ b/src/definitions/modules/dropdown.js @@ -62,6 +62,7 @@ $.fn.dropdown = function(parameters) { $context = $(settings.context), $text = $module.find(selector.text), $search = $module.find(selector.search), + $sizer = $module.find(selector.sizer), $input = $module.find(selector.input), $icon = $module.find(selector.icon), @@ -227,6 +228,12 @@ $.fn.dropdown = function(parameters) { .addClass(className.menu) .appendTo($module) ; + }, + sizer: function() { + $sizer = $('') + .addClass(className.sizer) + .insertAfter($search) + ; } }, @@ -306,6 +313,9 @@ $.fn.dropdown = function(parameters) { .insertBefore($text) ; } + if( module.is.multiple() && module.is.searchSelection() && !module.has.sizer()) { + module.create.sizer(); + } if(settings.allowTab) { module.set.tabbable(); } @@ -1406,11 +1416,11 @@ $.fn.dropdown = function(parameters) { module.verbose('Determining action', settings.action); if( $.isFunction( module.action[settings.action] ) ) { module.verbose('Triggering preset action', settings.action, text, value); - module.action[ settings.action ].call(this, text, value); + module.action[ settings.action ].call(element, text, value, this); } else if( $.isFunction(settings.action) ) { module.verbose('Triggering user action', settings.action, text, value); - settings.action.call(this, text, value); + settings.action.call(element, text, value, this); } else { module.error(error.action, settings.action); @@ -1464,13 +1474,13 @@ $.fn.dropdown = function(parameters) { nothing: function() {}, - activate: function(text, value) { + activate: function(text, value, element) { value = (value !== undefined) ? value : text ; - if( module.can.activate( $(this) ) ) { - module.set.selected(value, $(this)); + if( module.can.activate( $(element) ) ) { + module.set.selected(value, $(element)); if(module.is.multiple() && !module.is.allFiltered()) { return; } @@ -1480,21 +1490,21 @@ $.fn.dropdown = function(parameters) { } }, - select: function(text, value) { + select: function(text, value, element) { // mimics action.activate but does not select text - module.action.activate.call(this); + module.action.activate.call(element); }, - combo: function(text, value) { + combo: function(text, value, element) { value = (value !== undefined) ? value : text ; - module.set.selected(value, $(this)); + module.set.selected(value, $(element)); module.hideAndClear(); }, - hide: function(text, value) { + hide: function(text, value, element) { module.set.value(value, text); module.hideAndClear(); } @@ -1520,8 +1530,14 @@ $.fn.dropdown = function(parameters) { query: function() { return $.trim($search.val()); }, - searchWidth: function(characterCount) { - return (characterCount * settings.glyphWidth) + 'em'; + searchWidth: function(value) { + value = (value !== undefined) + ? value + : $search.val() + ; + $sizer.text(value); + // prevent rounding issues + return Math.ceil( $sizer.width() + 1); }, selectionCount: function() { var @@ -2062,7 +2078,7 @@ $.fn.dropdown = function(parameters) { ? module.get.query() : '', hasSearchValue = (typeof searchValue === 'string' && searchValue.length > 0), - searchWidth = module.get.searchWidth(searchValue.length), + searchWidth = module.get.searchWidth(), valueIsSet = searchValue !== '' ; if(isMultiple && hasSearchValue) { @@ -2802,6 +2818,9 @@ $.fn.dropdown = function(parameters) { search: function() { return ($search.length > 0); }, + sizer: function() { + return ($sizer.length > 0); + }, selectInput: function() { return ( $input.is('select') ); }, @@ -3508,6 +3527,7 @@ $.fn.dropdown.settings = { message : '.message', menuIcon : '.dropdown.icon', search : 'input.search, .menu > .search > input', + sizer : '> input.sizer', text : '> .text:not(.icon)', unselectable : '.disabled, .filtered' }, @@ -3528,6 +3548,7 @@ $.fn.dropdown.settings = { message : 'message', multiple : 'multiple', placeholder : 'default', + sizer : 'sizer', search : 'search', selected : 'selected', selection : 'selection', diff --git a/src/definitions/modules/dropdown.less b/src/definitions/modules/dropdown.less index 3235aaa41..a70ffa421 100755 --- a/src/definitions/modules/dropdown.less +++ b/src/definitions/modules/dropdown.less @@ -575,6 +575,14 @@ select.ui.dropdown { padding: @searchSelectionInputPadding; } +/* Used to size multi select input to character width */ +.ui.search.selection.dropdown > span.sizer { + line-height: @searchSelectionLineHeight; + padding: @searchSelectionInputPadding; + display: none; + white-space: pre; +} + /* Active/Visible Search */ .ui.search.dropdown.active > input.search, .ui.search.dropdown.visible > input.search { diff --git a/src/themes/default/modules/dropdown.variables b/src/themes/default/modules/dropdown.variables index 2b956826f..53755f2b3 100644 --- a/src/themes/default/modules/dropdown.variables +++ b/src/themes/default/modules/dropdown.variables @@ -132,7 +132,7 @@ @selectionMinHeight: @inputLineHeight + (@selectionVerticalPadding * 2) - @selectionBorderEmWidth; @selectionBackground: @inputBackground; @selectionDisplay: inline-block; -@selectionIconDistance: @inputHorizontalPadding + @glyphWidth + 0.5em; +@selectionIconDistance: @inputHorizontalPadding + @glyphWidth; @selectionPadding: @selectionVerticalPadding @selectionIconDistance @selectionVerticalPadding @selectionHorizontalPadding; @selectionZIndex: 10; @@ -231,10 +231,10 @@ @searchWidescreenMaxMenuHeight: @selectionWidescreenMaxMenuHeight; /* Inline */ -@inlineIconMargin: 0em 0.5em 0em 0.25em; +@inlineIconMargin: 0em @relative7px 0em @relative3px; @inlineTextColor: inherit; @inlineTextFontWeight: bold; -@inlineMenuDistance: 0.25em; +@inlineMenuDistance: @relative3px; @inlineMenuBorderRadius: @borderRadius; @@ -244,7 +244,7 @@ /* Split Actual Padding Between Child and Parent (allows for label spacing) */ @multipleSelectionVerticalPadding: (@searchSelectionVerticalPadding * (1/3)); -@multipleSelectionLeftPadding: (@selectionHorizontalPadding - @labelHorizontalPadding); +@multipleSelectionLeftPadding: @relative5px; @multipleSelectionRightPadding: @selectionIconDistance; @multipleSelectionPadding: @multipleSelectionVerticalPadding @multipleSelectionRightPadding @multipleSelectionVerticalPadding @multipleSelectionLeftPadding; @@ -256,7 +256,7 @@ @multipleSelectionSearchStartWidth: (@glyphWidth * 2); /* Dropdown Icon */ -@multipleSelectionDropdownIconMargin: -@searchSelectionVerticalPadding -@labelHorizontalPadding 0em 0em; +@multipleSelectionDropdownIconMargin: ''; @multipleSelectionDropdownIconPadding: ''; @multipleSelectionSearchAfterLabelDistance: @relative2px; @@ -264,7 +264,7 @@ /* Selection Label */ @labelSize: @relativeMedium; @labelHorizontalMargin: @4px; -@labelVerticalMargin: (@relative6px / 2); +@labelVerticalMargin: @2px; @labelMargin: @labelVerticalMargin @labelHorizontalMargin @labelVerticalMargin 0em; @labelBorderWidth: 1px; @labelBoxShadow: 0px 0px 0px @labelBorderWidth @borderColor inset;