Make typedInput keyboard navigable

This commit is contained in:
Nick O'Leary 2016-11-08 13:18:28 +00:00
parent 9c675a7847
commit 91f16215e5
3 changed files with 99 additions and 33 deletions

View File

@ -133,7 +133,7 @@
this.options.types = this.options.types||Object.keys(allOptions); this.options.types = this.options.types||Object.keys(allOptions);
this.selectTrigger = $('<a href="#"></a>').prependTo(this.uiSelect); this.selectTrigger = $('<button tabindex="0"></button>').prependTo(this.uiSelect);
$('<i class="fa fa-sort-desc"></i>').appendTo(this.selectTrigger); $('<i class="fa fa-sort-desc"></i>').appendTo(this.selectTrigger);
this.selectLabel = $('<span></span>').appendTo(this.selectTrigger); this.selectLabel = $('<span></span>').appendTo(this.selectTrigger);
@ -160,32 +160,72 @@
}) })
this.selectTrigger.click(function(event) { this.selectTrigger.click(function(event) {
event.preventDefault(); event.preventDefault();
if (that.typeList.length > 1) { that._showTypeMenu();
that._showMenu(that.menu,that.selectTrigger);
} else {
that.element.focus();
}
}); });
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' // explicitly set optionSelectTrigger display to inline-block otherwise jQ sets it to 'inline'
this.optionSelectTrigger = $('<a href="#" class="red-ui-typedInput-option-trigger" style="display:inline-block"><i class="fa fa-sort-desc"></i></a>').appendTo(this.uiSelect); this.optionSelectTrigger = $('<button tabindex="0" class="red-ui-typedInput-option-trigger" style="display:inline-block"><span class="red-ui-typedInput-option-caret"><i class="fa fa-sort-desc"></i></span></button>').appendTo(this.uiSelect);
this.optionSelectLabel = $('<span></span>').prependTo(this.optionSelectTrigger); this.optionSelectLabel = $('<span class="red-ui-typedInput-option-label"></span>').prependTo(this.optionSelectTrigger);
this.optionSelectTrigger.click(function(event) { this.optionSelectTrigger.click(function(event) {
event.preventDefault(); event.preventDefault();
if (that.optionMenu) { that._showOptionSelectMenu();
that.optionMenu.css({ }).on('keydown', function(evt) {
minWidth:that.optionSelectLabel.width() if (evt.keyCode === 40) {
}); // Down
that._showOptionSelectMenu();
that._showMenu(that.optionMenu,that.optionSelectLabel)
} }
}).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); 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) { _hideMenu: function(menu) {
$(document).off("mousedown.close-property-select"); $(document).off("mousedown.close-property-select");
menu.hide(); 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) { _createMenu: function(opts,callback) {
var that = this; var that = this;
@ -194,7 +234,7 @@
if (typeof opt === 'string') { if (typeof opt === 'string') {
opt = {value:opt,label:opt}; opt = {value:opt,label:opt};
} }
var op = $('<a href="#">').attr("value",opt.value).appendTo(menu); var op = $('<a href="#"></a>').attr("value",opt.value).appendTo(menu);
if (opt.label) { if (opt.label) {
op.text(opt.label); op.text(opt.label);
} }
@ -214,6 +254,21 @@
display: "none", display: "none",
}); });
menu.appendTo(document.body); 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; return menu;
}, },
@ -273,7 +328,7 @@
var labelWidth = this._getLabelWidth(this.selectTrigger); var labelWidth = this._getLabelWidth(this.selectTrigger);
this.elementDiv.css('left',labelWidth+"px"); this.elementDiv.css('left',labelWidth+"px");
if (this.optionSelectTrigger) { if (this.optionSelectTrigger) {
this.optionSelectTrigger.css('left',(labelWidth+5)+"px"); this.optionSelectTrigger.css({'left':(labelWidth)+"px",'width':'calc( 100% - '+labelWidth+'px )'});
} }
} }
}, },

View File

@ -58,7 +58,7 @@ $workspace-button-color-focus-outline: rgba(85,150,230,0.2);
$typedInput-button-background: #efefef; $typedInput-button-background: #efefef;
$typedInput-button-background-hover: #ddd; $typedInput-button-background-hover: #ddd;
$typedInput-button-background-active: #e3e3e3; $typedInput-button-background-active: #ddd;
$editor-button-color-primary: #eee; $editor-button-color-primary: #eee;
$editor-button-background-primary: #AD1625; $editor-button-background-primary: #AD1625;

View File

@ -49,7 +49,10 @@
border-color: $form-input-focus-color !important; border-color: $form-input-focus-color !important;
} }
a { button {
text-align: left;
border: none;
position: absolute;
box-sizing: border-box; box-sizing: border-box;
border-top-left-radius: 4px; border-top-left-radius: 4px;
border-bottom-left-radius: 4px; border-bottom-left-radius: 4px;
@ -82,13 +85,11 @@
&:not(.disabled):hover { &:not(.disabled):hover {
text-decoration: none; text-decoration: none;
background: $typedInput-button-background-hover; background: $typedInput-button-background-hover;
span {
background: $typedInput-button-background-hover;
}
} }
&:focus { &:focus {
text-decoration: none; text-decoration: none;
outline: none;
box-shadow: inset 0 0 0 1px $form-input-focus-color;
} }
&:not(.disabled):active { &:not(.disabled):active {
background: $typedInput-button-background-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-top-left-radius: 0px;
border-bottom-left-radius: 0px; border-bottom-left-radius: 0px;
border-top-right-radius: 4px; border-top-right-radius: 4px;
border-bottom-right-radius: 4px; border-bottom-right-radius: 4px;
padding: 0 5px 0 0; padding: 0 0 0 0;
position:absolute; position:absolute;
left:0; width: calc( 100% );
top:0;
bottom:0;
right:0;
i { i {
position:absolute; position:absolute;
right: 4px; right: 4px;
top: 7px; top: 7px;
} }
span { .red-ui-typedInput-option-label {
background:#fff; background:#fff;
position:absolute; position:absolute;
left:0; left:0;
right:23px; right:23px;
top: 0;
padding: 0 5px 0 5px; 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 { .red-ui-typedInput-options {
@ -139,12 +150,12 @@
} }
&:focus { &:focus {
text-decoration: none; text-decoration: none;
background: $typedInput-button-background-active;
outline: none;
} }
&:active { &:active {
background: $typedInput-button-background-active;
text-decoration: none; text-decoration: none;
background: $typedInput-button-background-active;
} }
} }
} }