-
Notifications
You must be signed in to change notification settings - Fork 3.4k
feat(interaction): added service to detect last interaction #5589
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
angular | ||
.module('material.core.interaction', []) | ||
.service('$mdInteraction', MdInteractionService); | ||
|
||
/* | ||
* @ngdoc service | ||
* @name $mdInteraction | ||
* @module material.core.interaction | ||
* | ||
* @description | ||
* | ||
* Service which keeps track of the last interaction type and validates them for several browsers. | ||
* The service hooks into the document's body and listens for touch, mouse and keyboard events. | ||
* | ||
* The last interaction type can be retrieved by using the `getLastInteractionType` method, which returns | ||
* the following possible values: | ||
* - `touch` | ||
* - `mouse` | ||
* - `keyboard` | ||
* | ||
* Here is an example markup for using the interaction service. | ||
* ``` | ||
* var lastType = $mdInteraction.getLastInteractionType(); | ||
* if (lastType === 'keyboard') { | ||
* restoreFocus(); | ||
* }} | ||
* ``` | ||
* | ||
*/ | ||
function MdInteractionService($timeout) { | ||
var body = angular.element(document.body); | ||
var mouseEvent = window.MSPointerEvent ? 'MSPointerDown' : window.PointerEvent ? 'pointerdown' : 'mousedown'; | ||
var buffer = false; | ||
var timer; | ||
var lastInteractionType; | ||
|
||
// Type Mappings for the different events | ||
// There will be three three interaction types | ||
// `keyboard`, `mouse` and `touch` | ||
// type `pointer` will be evaluated in `pointerMap` for IE Browser events | ||
var inputMap = { | ||
'keydown': 'keyboard', | ||
'mousedown': 'mouse', | ||
'mouseenter': 'mouse', | ||
'touchstart': 'touch', | ||
'pointerdown': 'pointer', | ||
'MSPointerDown': 'pointer' | ||
}; | ||
|
||
// IE PointerDown events will be validated in `touch` or `mouse` | ||
// Index numbers referenced here: https://msdn.microsoft.com/library/windows/apps/hh466130.aspx | ||
var pointerMap = { | ||
2: 'touch', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i'd really like to know what are those, please add an explanation There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Input MapMSPointerdown < IE11: https://msdn.microsoft.com/de-de/library/windows/apps/hh465891.aspx Pointer Map:https://msdn.microsoft.com/de-de/library/windows/apps/hh466130.aspx Then I will validate the right pointer event type :) I hope, know its clear :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 please add this in a comment :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @devversion i pinged you on gitter |
||
3: 'touch', | ||
4: 'mouse' | ||
}; | ||
|
||
function onInput(event) { | ||
if (buffer) return; | ||
var type = inputMap[event.type]; | ||
if (type === 'pointer') { | ||
type = (typeof event.pointerType === 'number') ? pointerMap[event.pointerType] : event.pointerType; | ||
} | ||
lastInteractionType = type; | ||
} | ||
|
||
function onBufferInput(event) { | ||
$timeout.cancel(timer); | ||
|
||
onInput(event); | ||
buffer = true; | ||
|
||
// The timeout of 650ms is needed to delay the touchstart, because otherwise the touch will call | ||
// the `onInput` function multiple times. | ||
timer = $timeout(function() { | ||
buffer = false; | ||
}, 650); | ||
} | ||
|
||
body.on('keydown', onInput); | ||
body.on(mouseEvent, onInput); | ||
body.on('mouseenter', onInput); | ||
if ('ontouchstart' in document.documentElement) { | ||
body.on('touchstart', onBufferInput); | ||
} | ||
|
||
/** | ||
* Gets the last interaction type triggered in body. | ||
* Possible return values are `mouse`, `keyboard` and `touch` | ||
* @returns {string} | ||
*/ | ||
this.getLastInteractionType = function() { | ||
return lastInteractionType; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
describe("$mdInteraction service", function() { | ||
var $mdInteraction; | ||
|
||
beforeEach(module('material.core')); | ||
|
||
beforeEach(inject(function(_$mdInteraction_) { | ||
$mdInteraction = _$mdInteraction_; | ||
})); | ||
|
||
describe("last interaction type", function() { | ||
|
||
it("imitates a basic keyboard interaction and checks it", function() { | ||
|
||
var event = document.createEvent('Event'); | ||
event.keyCode = 37; | ||
event.initEvent('keydown', false, true); | ||
document.body.dispatchEvent(event); | ||
|
||
expect($mdInteraction.getLastInteractionType()).toBe('keyboard'); | ||
}); | ||
|
||
it("dispatches a mousedown event on the document body and checks it", function() { | ||
|
||
var event = document.createEvent("MouseEvent"); | ||
event.initMouseEvent("mousedown", true, true, window, null, 0, 0, 0, 0, false, false, false, false, 0, null); | ||
document.body.dispatchEvent(event); | ||
|
||
expect($mdInteraction.getLastInteractionType()).toBe("mouse"); | ||
}); | ||
|
||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about documentation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this service should be documented, it's not really generic and there aren't much use cases for a user to use that service. It's mostly a service which helps us with the accessibility for the components. But if you wan't me to document it, it won't be a problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ThomasBurleson @topherfangio any thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regardless of whether we make the docs public, it is always nice to have them for ourselves 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, will do that tomorrow 👍