metal-keyboard-focus
Advanced tools
Comparing version 1.0.2 to 1.1.0
@@ -94,7 +94,8 @@ 'use strict'; | ||
KeyboardFocusManager.prototype.getNextFocusable_ = function getNextFocusable_(position, increment) { | ||
var initialPosition = position; | ||
var element = void 0; | ||
do { | ||
position += increment; | ||
position = this.increment_(position, increment); | ||
element = this.component_.refs[this.buildRef_(position)]; | ||
} while (element && element.getAttribute('data-unfocusable') === 'true'); | ||
} while (this.isFocusable_(element) && position !== initialPosition); | ||
return element; | ||
@@ -104,3 +105,3 @@ }; | ||
/** | ||
* Handles a `keyup` event. Decides if a new element should be focused | ||
* Handles a `keydown` event. Decides if a new element should be focused | ||
* according to the key that was pressed. | ||
@@ -155,2 +156,51 @@ * @param {!Event} event | ||
/** | ||
* Increments the given position, making sure to follow circular rules if | ||
* enabled. | ||
* @param {number} position | ||
* @param {number} increment | ||
* @return {number} | ||
* @protected | ||
*/ | ||
KeyboardFocusManager.prototype.increment_ = function increment_(position, increment) { | ||
var size = this.circularLength_; | ||
position += increment; | ||
if (_metal.core.isNumber(size)) { | ||
if (position < 0) { | ||
position = size - 1; | ||
} else if (position >= size) { | ||
position = 0; | ||
} | ||
} | ||
return position; | ||
}; | ||
/** | ||
* Checks if the given element is focusable. | ||
* @param {Element} element | ||
* @return {boolean} | ||
* @protected | ||
*/ | ||
KeyboardFocusManager.prototype.isFocusable_ = function isFocusable_(element) { | ||
return element && element.getAttribute('data-unfocusable') === 'true'; | ||
}; | ||
/** | ||
* Sets the length of the focusable elements. If a number is passed, the | ||
* default focusing behavior will follow a circular pattern, going from the | ||
* last to the first element, and vice versa. | ||
* @param {?number} circularLength | ||
* @chainable | ||
*/ | ||
KeyboardFocusManager.prototype.setCircularLength = function setCircularLength(circularLength) { | ||
this.circularLength_ = circularLength; | ||
return this; | ||
}; | ||
/** | ||
* Sets a handler function that will be called to decide which element should | ||
@@ -183,3 +233,3 @@ * be focused according to the key that was pressed. It will receive the key | ||
if (!this.handle_) { | ||
this.handle_ = this.component_.delegate('keyup', this.selector_, this.handleKey_); | ||
this.handle_ = this.component_.delegate('keydown', this.selector_, this.handleKey_); | ||
} | ||
@@ -186,0 +236,0 @@ return this; |
{ | ||
"name": "metal-keyboard-focus", | ||
"version": "1.0.2", | ||
"version": "1.1.0", | ||
"description": "Manages focus on components via keyboard events", | ||
@@ -5,0 +5,0 @@ "license": "BSD", |
@@ -70,7 +70,8 @@ 'use strict'; | ||
getNextFocusable_(position, increment) { | ||
const initialPosition = position; | ||
let element; | ||
do { | ||
position += increment; | ||
position = this.increment_(position, increment); | ||
element = this.component_.refs[this.buildRef_(position)]; | ||
} while (element && element.getAttribute('data-unfocusable') === 'true'); | ||
} while (this.isFocusable_(element) && position !== initialPosition); | ||
return element; | ||
@@ -80,3 +81,3 @@ } | ||
/** | ||
* Handles a `keyup` event. Decides if a new element should be focused | ||
* Handles a `keydown` event. Decides if a new element should be focused | ||
* according to the key that was pressed. | ||
@@ -127,2 +128,45 @@ * @param {!Event} event | ||
/** | ||
* Increments the given position, making sure to follow circular rules if | ||
* enabled. | ||
* @param {number} position | ||
* @param {number} increment | ||
* @return {number} | ||
* @protected | ||
*/ | ||
increment_(position, increment) { | ||
const size = this.circularLength_; | ||
position += increment; | ||
if (core.isNumber(size)) { | ||
if (position < 0) { | ||
position = size - 1; | ||
} else if (position >= size) { | ||
position = 0; | ||
} | ||
} | ||
return position; | ||
} | ||
/** | ||
* Checks if the given element is focusable. | ||
* @param {Element} element | ||
* @return {boolean} | ||
* @protected | ||
*/ | ||
isFocusable_(element) { | ||
return element && element.getAttribute('data-unfocusable') === 'true'; | ||
} | ||
/** | ||
* Sets the length of the focusable elements. If a number is passed, the | ||
* default focusing behavior will follow a circular pattern, going from the | ||
* last to the first element, and vice versa. | ||
* @param {?number} circularLength | ||
* @chainable | ||
*/ | ||
setCircularLength(circularLength) { | ||
this.circularLength_ = circularLength; | ||
return this; | ||
} | ||
/** | ||
* Sets a handler function that will be called to decide which element should | ||
@@ -152,3 +196,3 @@ * be focused according to the key that was pressed. It will receive the key | ||
this.handle_ = this.component_.delegate( | ||
'keyup', | ||
'keydown', | ||
this.selector_, | ||
@@ -155,0 +199,0 @@ this.handleKey_ |
@@ -37,3 +37,3 @@ 'use strict'; | ||
dom.triggerEvent(component.refs.el1, 'keyup', { | ||
dom.triggerEvent(component.refs.el1, 'keydown', { | ||
keyCode: 37 | ||
@@ -49,3 +49,3 @@ }); | ||
dom.triggerEvent(component.refs.el1, 'keyup', { | ||
dom.triggerEvent(component.refs.el1, 'keydown', { | ||
keyCode: 38 | ||
@@ -62,3 +62,3 @@ }); | ||
const prevActiveElement = document.activeElement; | ||
dom.triggerEvent(component.refs.el0, 'keyup', { | ||
dom.triggerEvent(component.refs.el0, 'keydown', { | ||
keyCode: 37 | ||
@@ -68,3 +68,3 @@ }); | ||
dom.triggerEvent(component.refs.el0, 'keyup', { | ||
dom.triggerEvent(component.refs.el0, 'keydown', { | ||
keyCode: 38 | ||
@@ -80,3 +80,3 @@ }); | ||
dom.triggerEvent(component.refs.el0, 'keyup', { | ||
dom.triggerEvent(component.refs.el0, 'keydown', { | ||
keyCode: 39 | ||
@@ -92,3 +92,3 @@ }); | ||
dom.triggerEvent(component.refs.el0, 'keyup', { | ||
dom.triggerEvent(component.refs.el0, 'keydown', { | ||
keyCode: 40 | ||
@@ -105,3 +105,3 @@ }); | ||
const prevActiveElement = document.activeElement; | ||
dom.triggerEvent(component.refs.el2, 'keyup', { | ||
dom.triggerEvent(component.refs.el2, 'keydown', { | ||
keyCode: 39 | ||
@@ -111,3 +111,3 @@ }); | ||
dom.triggerEvent(component.refs.el2, 'keyup', { | ||
dom.triggerEvent(component.refs.el2, 'keydown', { | ||
keyCode: 40 | ||
@@ -124,3 +124,3 @@ }); | ||
const prevActiveElement = document.activeElement; | ||
dom.triggerEvent(component.refs.el0, 'keyup', { | ||
dom.triggerEvent(component.refs.el0, 'keydown', { | ||
keyCode: 10 | ||
@@ -147,3 +147,3 @@ }); | ||
const prevActiveElement = document.activeElement; | ||
dom.triggerEvent(component.element.childNodes[0], 'keyup', { | ||
dom.triggerEvent(component.element.childNodes[0], 'keydown', { | ||
keyCode: 40 | ||
@@ -170,3 +170,3 @@ }); | ||
const prevActiveElement = document.activeElement; | ||
dom.triggerEvent(component.refs.button0, 'keyup', { | ||
dom.triggerEvent(component.refs.button0, 'keydown', { | ||
keyCode: 40 | ||
@@ -182,3 +182,3 @@ }); | ||
dom.triggerEvent(component.refs.el0, 'keyup', { | ||
dom.triggerEvent(component.refs.el0, 'keydown', { | ||
keyCode: 40 | ||
@@ -204,3 +204,3 @@ }); | ||
dom.triggerEvent(component.refs.el0, 'keyup', { | ||
dom.triggerEvent(component.refs.el0, 'keydown', { | ||
keyCode: 40 | ||
@@ -227,3 +227,3 @@ }); | ||
dom.triggerEvent(component.refs.el0, 'keyup', { | ||
dom.triggerEvent(component.refs.el0, 'keydown', { | ||
keyCode: 39 | ||
@@ -238,3 +238,3 @@ }); | ||
dom.triggerEvent(component.refs.el0, 'keyup', { | ||
dom.triggerEvent(component.refs.el0, 'keydown', { | ||
keyCode: 40 | ||
@@ -251,3 +251,3 @@ }); | ||
dom.triggerEvent(component.refs.el0, 'keyup', { | ||
dom.triggerEvent(component.refs.el0, 'keydown', { | ||
keyCode: 40 | ||
@@ -264,3 +264,3 @@ }); | ||
dom.triggerEvent(component.refs.el1, 'keyup', { | ||
dom.triggerEvent(component.refs.el1, 'keydown', { | ||
keyCode: 37 | ||
@@ -271,2 +271,86 @@ }); | ||
describe('setCircularLength', function() { | ||
it('should focus last element when the left arrow key is pressed on first element', function() { | ||
component = new TestComponent(); | ||
manager = new KeyboardFocusManager(component, 'button') | ||
.setCircularLength(3) | ||
.start(); | ||
dom.triggerEvent(component.refs.el0, 'keydown', { | ||
keyCode: 37 | ||
}); | ||
assert.strictEqual(component.refs.el2, document.activeElement); | ||
}); | ||
it('should focus last element when the up arrow key is pressed on first element', function() { | ||
component = new TestComponent(); | ||
manager = new KeyboardFocusManager(component, 'button') | ||
.setCircularLength(3) | ||
.start(); | ||
dom.triggerEvent(component.refs.el0, 'keydown', { | ||
keyCode: 38 | ||
}); | ||
assert.strictEqual(component.refs.el2, document.activeElement); | ||
}); | ||
it('should focus first element when the right arrow key is pressed on last element', function() { | ||
component = new TestComponent(); | ||
manager = new KeyboardFocusManager(component, 'button') | ||
.setCircularLength(3) | ||
.start(); | ||
dom.triggerEvent(component.refs.el2, 'keydown', { | ||
keyCode: 39 | ||
}); | ||
assert.strictEqual(component.refs.el0, document.activeElement); | ||
}); | ||
it('should focus first element when the down arrow key is pressed on last element', function() { | ||
component = new TestComponent(); | ||
manager = new KeyboardFocusManager(component, 'button') | ||
.setCircularLength(3) | ||
.start(); | ||
dom.triggerEvent(component.refs.el2, 'keydown', { | ||
keyCode: 40 | ||
}); | ||
assert.strictEqual(component.refs.el0, document.activeElement); | ||
}); | ||
it('should focus next element when right/down arrow key is pressed on non last element', function() { | ||
component = new TestComponent(); | ||
manager = new KeyboardFocusManager(component, 'button') | ||
.setCircularLength(3) | ||
.start(); | ||
dom.triggerEvent(component.refs.el0, 'keydown', { | ||
keyCode: 39 | ||
}); | ||
assert.strictEqual(component.refs.el1, document.activeElement); | ||
dom.triggerEvent(component.refs.el1, 'keydown', { | ||
keyCode: 40 | ||
}); | ||
assert.strictEqual(component.refs.el2, document.activeElement); | ||
}); | ||
it('should focus previous element when left/up arrow key is pressed on non first element', function() { | ||
component = new TestComponent(); | ||
manager = new KeyboardFocusManager(component, 'button') | ||
.setCircularLength(3) | ||
.start(); | ||
dom.triggerEvent(component.refs.el2, 'keydown', { | ||
keyCode: 37 | ||
}); | ||
assert.strictEqual(component.refs.el1, document.activeElement); | ||
dom.triggerEvent(component.refs.el1, 'keydown', { | ||
keyCode: 38 | ||
}); | ||
assert.strictEqual(component.refs.el0, document.activeElement); | ||
}); | ||
}); | ||
describe('setFocusHandler', function() { | ||
@@ -279,3 +363,3 @@ it('should focus the element returned by the custom focus handler', function() { | ||
dom.triggerEvent(component.refs.el0, 'keyup', { | ||
dom.triggerEvent(component.refs.el0, 'keydown', { | ||
keyCode: 10 | ||
@@ -292,3 +376,3 @@ }); | ||
dom.triggerEvent(component.refs.el0, 'keyup', { | ||
dom.triggerEvent(component.refs.el0, 'keydown', { | ||
keyCode: 10 | ||
@@ -306,3 +390,3 @@ }); | ||
var prevActiveElement = document.activeElement; | ||
dom.triggerEvent(component.refs.el0, 'keyup', { | ||
dom.triggerEvent(component.refs.el0, 'keydown', { | ||
keyCode: 39 | ||
@@ -319,3 +403,3 @@ }); | ||
dom.triggerEvent(component.refs.el0, 'keyup', { | ||
dom.triggerEvent(component.refs.el0, 'keydown', { | ||
keyCode: 39 | ||
@@ -322,0 +406,0 @@ }); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
28485
728