From 91f16215e5287cacb91ad6f9a8226d66f88f94ef Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Tue, 8 Nov 2016 13:18:28 +0000 Subject: [PATCH] Make typedInput keyboard navigable --- editor/js/ui/common/typedInput.js | 89 ++++++++++++++++++++++----- editor/sass/colors.scss | 2 +- editor/sass/ui/common/typedInput.scss | 41 +++++++----- 3 files changed, 99 insertions(+), 33 deletions(-) diff --git a/editor/js/ui/common/typedInput.js b/editor/js/ui/common/typedInput.js index 90749d509..ed13dc501 100644 --- a/editor/js/ui/common/typedInput.js +++ b/editor/js/ui/common/typedInput.js @@ -133,7 +133,7 @@ this.options.types = this.options.types||Object.keys(allOptions); - this.selectTrigger = $('').prependTo(this.uiSelect); + this.selectTrigger = $('').prependTo(this.uiSelect); $('').appendTo(this.selectTrigger); this.selectLabel = $('').appendTo(this.selectTrigger); @@ -160,32 +160,72 @@ }) this.selectTrigger.click(function(event) { event.preventDefault(); - if (that.typeList.length > 1) { - that._showMenu(that.menu,that.selectTrigger); - } else { - that.element.focus(); - } + that._showTypeMenu(); }); + this.selectTrigger.on('keydown',function(evt) { + if (evt.keyCode === 40) { + // Down + that._showTypeMenu(); + } + }).on('focus', function() { + that.uiSelect.addClass('red-ui-typedInput-focus'); + }) // explicitly set optionSelectTrigger display to inline-block otherwise jQ sets it to 'inline' - this.optionSelectTrigger = $('').appendTo(this.uiSelect); - this.optionSelectLabel = $('').prependTo(this.optionSelectTrigger); + this.optionSelectTrigger = $('').appendTo(this.uiSelect); + this.optionSelectLabel = $('').prependTo(this.optionSelectTrigger); this.optionSelectTrigger.click(function(event) { event.preventDefault(); - if (that.optionMenu) { - that.optionMenu.css({ - minWidth:that.optionSelectLabel.width() - }); - - that._showMenu(that.optionMenu,that.optionSelectLabel) + that._showOptionSelectMenu(); + }).on('keydown', function(evt) { + if (evt.keyCode === 40) { + // Down + that._showOptionSelectMenu(); } + }).on('blur', function() { + that.uiSelect.removeClass('red-ui-typedInput-focus'); + }).on('focus', function() { + that.uiSelect.addClass('red-ui-typedInput-focus'); }); + + + + this.type(this.options.default||this.typeList[0].value); }, + _showTypeMenu: function() { + if (this.typeList.length > 1) { + this._showMenu(this.menu,this.selectTrigger); + this.menu.find("[value='"+this.propertyType+"']").focus(); + } else { + this.element.focus(); + } + }, + _showOptionSelectMenu: function() { + if (this.optionMenu) { + this.optionMenu.css({ + minWidth:this.optionSelectLabel.width() + }); + + this._showMenu(this.optionMenu,this.optionSelectLabel); + var selectedOption = this.optionMenu.find("[value='"+this.value()+"']"); + if (selectedOption.length === 0) { + selectedOption = this.optionMenu.children(":first"); + } + selectedOption.focus(); + + } + }, _hideMenu: function(menu) { $(document).off("mousedown.close-property-select"); menu.hide(); - this.element.focus(); + if (this.elementDiv.is(":visible")) { + this.element.focus(); + } else if (this.optionSelectTrigger.is(":visible")){ + this.optionSelectTrigger.focus(); + } else { + this.selectTrigger.focus(); + } }, _createMenu: function(opts,callback) { var that = this; @@ -194,7 +234,7 @@ if (typeof opt === 'string') { opt = {value:opt,label:opt}; } - var op = $('').attr("value",opt.value).appendTo(menu); + var op = $('').attr("value",opt.value).appendTo(menu); if (opt.label) { op.text(opt.label); } @@ -214,6 +254,21 @@ display: "none", }); menu.appendTo(document.body); + + menu.on('keydown', function(evt) { + if (evt.keyCode === 40) { + // DOWN + $(this).children(":focus").next().focus(); + } else if (evt.keyCode === 38) { + // UP + $(this).children(":focus").prev().focus(); + } else if (evt.keyCode === 27) { + that._hideMenu(menu); + } + }) + + + return menu; }, @@ -273,7 +328,7 @@ var labelWidth = this._getLabelWidth(this.selectTrigger); this.elementDiv.css('left',labelWidth+"px"); if (this.optionSelectTrigger) { - this.optionSelectTrigger.css('left',(labelWidth+5)+"px"); + this.optionSelectTrigger.css({'left':(labelWidth)+"px",'width':'calc( 100% - '+labelWidth+'px )'}); } } }, diff --git a/editor/sass/colors.scss b/editor/sass/colors.scss index 6a2f04b1c..702ba0385 100644 --- a/editor/sass/colors.scss +++ b/editor/sass/colors.scss @@ -58,7 +58,7 @@ $workspace-button-color-focus-outline: rgba(85,150,230,0.2); $typedInput-button-background: #efefef; $typedInput-button-background-hover: #ddd; -$typedInput-button-background-active: #e3e3e3; +$typedInput-button-background-active: #ddd; $editor-button-color-primary: #eee; $editor-button-background-primary: #AD1625; diff --git a/editor/sass/ui/common/typedInput.scss b/editor/sass/ui/common/typedInput.scss index b2cbcdfde..25954cc3c 100644 --- a/editor/sass/ui/common/typedInput.scss +++ b/editor/sass/ui/common/typedInput.scss @@ -49,7 +49,10 @@ border-color: $form-input-focus-color !important; } - a { + button { + text-align: left; + border: none; + position: absolute; box-sizing: border-box; border-top-left-radius: 4px; border-bottom-left-radius: 4px; @@ -82,13 +85,11 @@ &:not(.disabled):hover { text-decoration: none; background: $typedInput-button-background-hover; - - span { - background: $typedInput-button-background-hover; - } } &:focus { text-decoration: none; + outline: none; + box-shadow: inset 0 0 0 1px $form-input-focus-color; } &:not(.disabled):active { background: $typedInput-button-background-active; @@ -96,30 +97,40 @@ } } - a.red-ui-typedInput-option-trigger { + button.red-ui-typedInput-option-trigger { border-top-left-radius: 0px; border-bottom-left-radius: 0px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; - padding: 0 5px 0 0; + padding: 0 0 0 0; position:absolute; - left:0; - top:0; - bottom:0; - right:0; + width: calc( 100% ); i { position:absolute; right: 4px; top: 7px; } - span { + .red-ui-typedInput-option-label { background:#fff; position:absolute; left:0; right:23px; + top: 0; padding: 0 5px 0 5px; } + .red-ui-typedInput-option-caret { + top: 0; + position: absolute; + right: 0; + width: 17px; + } + &:focus { + box-shadow: none; + } + &:focus .red-ui-typedInput-option-caret { + box-shadow: inset 0 0 0 1px $form-input-focus-color; + } } } .red-ui-typedInput-options { @@ -139,12 +150,12 @@ } &:focus { text-decoration: none; + background: $typedInput-button-background-active; + outline: none; } &:active { - background: $typedInput-button-background-active; text-decoration: none; + background: $typedInput-button-background-active; } - - } }