openreplay/backend/pkg/handlers/web/deadClick.go

85 lines
1.9 KiB
Go

package web
import (
. "openreplay/backend/pkg/messages"
)
const ClickRelationTime = 1234
type DeadClickDetector struct {
lastMouseClick *MouseClick
lastTimestamp uint64
lastClickTimestamp uint64
lastMessageID uint64
inputIDSet map[uint64]bool
}
func NewDeadClickDetector() *DeadClickDetector {
return &DeadClickDetector{inputIDSet: make(map[uint64]bool)}
}
func (d *DeadClickDetector) addInputID(id uint64) {
d.inputIDSet[id] = true
}
func (d *DeadClickDetector) clearInputIDs() {
d.inputIDSet = make(map[uint64]bool)
}
func (d *DeadClickDetector) reset() {
d.lastMouseClick = nil
d.lastClickTimestamp = 0
d.lastMessageID = 0
d.clearInputIDs()
}
func (d *DeadClickDetector) Build() Message {
// remove reset from external Build call
defer d.reset()
if d.lastMouseClick == nil || d.lastClickTimestamp+ClickRelationTime > d.lastTimestamp { // reaction is instant
return nil
}
event := &IssueEvent{
Type: "dead_click",
ContextString: d.lastMouseClick.Label,
Timestamp: d.lastClickTimestamp,
MessageID: d.lastMessageID,
Context: d.lastMouseClick.Selector, // hack to pass selector to db (tags filter)
}
return event
}
func (d *DeadClickDetector) Handle(message Message, timestamp uint64) Message {
d.lastTimestamp = timestamp
switch msg := message.(type) {
case *SetInputTarget:
d.addInputID(msg.ID)
case *CreateDocument:
d.clearInputIDs()
case *MouseClick:
if msg.Label == "" {
return nil
}
isInputEvent := d.inputIDSet[msg.ID]
event := d.Build()
if isInputEvent {
return event
}
d.lastMouseClick = msg
d.lastClickTimestamp = timestamp
d.lastMessageID = message.MsgID()
return event
case *SetNodeAttribute,
*RemoveNodeAttribute,
*CreateElementNode,
*CreateTextNode,
*SetNodeFocus,
*MoveNode,
*RemoveNode,
*SetCSSData,
*SetInputValue,
*SetInputChecked:
return d.Build()
}
return nil
}