fix(tracker): capture selection event
This commit is contained in:
parent
c57846eab3
commit
c2501530a0
17 changed files with 176 additions and 5 deletions
|
|
@ -10,5 +10,5 @@ func IsIOSType(id int) bool {
|
|||
}
|
||||
|
||||
func IsDOMType(id int) bool {
|
||||
return 0 == id || 4 == id || 5 == id || 6 == id || 7 == id || 8 == id || 9 == id || 10 == id || 11 == id || 12 == id || 13 == id || 14 == id || 15 == id || 16 == id || 18 == id || 19 == id || 20 == id || 37 == id || 38 == id || 49 == id || 50 == id || 51 == id || 54 == id || 55 == id || 57 == id || 58 == id || 59 == id || 60 == id || 61 == id || 67 == id || 69 == id || 70 == id || 71 == id || 72 == id || 73 == id || 74 == id || 75 == id || 76 == id || 77 == id || 90 == id || 93 == id || 96 == id || 100 == id || 102 == id || 103 == id || 105 == id
|
||||
return 0 == id || 4 == id || 5 == id || 6 == id || 7 == id || 8 == id || 9 == id || 10 == id || 11 == id || 12 == id || 13 == id || 14 == id || 15 == id || 16 == id || 18 == id || 19 == id || 20 == id || 37 == id || 38 == id || 49 == id || 50 == id || 51 == id || 54 == id || 55 == id || 57 == id || 58 == id || 59 == id || 60 == id || 61 == id || 67 == id || 69 == id || 70 == id || 71 == id || 72 == id || 73 == id || 74 == id || 75 == id || 76 == id || 77 == id || 84 == id || 90 == id || 93 == id || 96 == id || 100 == id || 102 == id || 103 == id || 105 == id
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ const (
|
|||
MsgBatchMetadata = 81
|
||||
MsgPartitionedMessage = 82
|
||||
MsgInputChange = 83
|
||||
MsgSelectionChange = 84
|
||||
MsgIssueEvent = 125
|
||||
MsgSessionEnd = 126
|
||||
MsgSessionSearch = 127
|
||||
|
|
@ -2143,6 +2144,31 @@ func (msg *InputChange) TypeID() int {
|
|||
return 83
|
||||
}
|
||||
|
||||
type SelectionChange struct {
|
||||
message
|
||||
SelectionStart uint64
|
||||
SelectionEnd uint64
|
||||
Selection string
|
||||
}
|
||||
|
||||
func (msg *SelectionChange) Encode() []byte {
|
||||
buf := make([]byte, 31+len(msg.Selection))
|
||||
buf[0] = 84
|
||||
p := 1
|
||||
p = WriteUint(msg.SelectionStart, buf, p)
|
||||
p = WriteUint(msg.SelectionEnd, buf, p)
|
||||
p = WriteString(msg.Selection, buf, p)
|
||||
return buf[:p]
|
||||
}
|
||||
|
||||
func (msg *SelectionChange) Decode() Message {
|
||||
return msg
|
||||
}
|
||||
|
||||
func (msg *SelectionChange) TypeID() int {
|
||||
return 84
|
||||
}
|
||||
|
||||
type IssueEvent struct {
|
||||
message
|
||||
MessageID uint64
|
||||
|
|
|
|||
|
|
@ -1308,6 +1308,21 @@ func DecodeInputChange(reader BytesReader) (Message, error) {
|
|||
return msg, err
|
||||
}
|
||||
|
||||
func DecodeSelectionChange(reader BytesReader) (Message, error) {
|
||||
var err error = nil
|
||||
msg := &SelectionChange{}
|
||||
if msg.SelectionStart, err = reader.ReadUint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if msg.SelectionEnd, err = reader.ReadUint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if msg.Selection, err = reader.ReadString(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return msg, err
|
||||
}
|
||||
|
||||
func DecodeIssueEvent(reader BytesReader) (Message, error) {
|
||||
var err error = nil
|
||||
msg := &IssueEvent{}
|
||||
|
|
@ -1919,6 +1934,8 @@ func ReadMessage(t uint64, reader BytesReader) (Message, error) {
|
|||
return DecodePartitionedMessage(reader)
|
||||
case 83:
|
||||
return DecodeInputChange(reader)
|
||||
case 84:
|
||||
return DecodeSelectionChange(reader)
|
||||
case 125:
|
||||
return DecodeIssueEvent(reader)
|
||||
case 126:
|
||||
|
|
|
|||
|
|
@ -753,6 +753,15 @@ class InputChange(Message):
|
|||
self.hesitation_time = hesitation_time
|
||||
|
||||
|
||||
class SelectionChange(Message):
|
||||
__id__ = 84
|
||||
|
||||
def __init__(self, selection_start, selection_end, selection):
|
||||
self.selection_start = selection_start
|
||||
self.selection_end = selection_end
|
||||
self.selection = selection
|
||||
|
||||
|
||||
class IssueEvent(Message):
|
||||
__id__ = 125
|
||||
|
||||
|
|
|
|||
|
|
@ -667,6 +667,13 @@ class MessageCodec(Codec):
|
|||
hesitation_time=self.read_int(reader)
|
||||
)
|
||||
|
||||
if message_id == 84:
|
||||
return SelectionChange(
|
||||
selection_start=self.read_uint(reader),
|
||||
selection_end=self.read_uint(reader),
|
||||
selection=self.read_string(reader)
|
||||
)
|
||||
|
||||
if message_id == 125:
|
||||
return IssueEvent(
|
||||
message_id=self.read_uint(reader),
|
||||
|
|
|
|||
|
|
@ -627,6 +627,18 @@ export default class RawMessageReader extends PrimitiveReader {
|
|||
};
|
||||
}
|
||||
|
||||
case 84: {
|
||||
const selectionStart = this.readUint(); if (selectionStart === null) { return resetPointer() }
|
||||
const selectionEnd = this.readUint(); if (selectionEnd === null) { return resetPointer() }
|
||||
const selection = this.readString(); if (selection === null) { return resetPointer() }
|
||||
return {
|
||||
tp: MType.SelectionChange,
|
||||
selectionStart,
|
||||
selectionEnd,
|
||||
selection,
|
||||
};
|
||||
}
|
||||
|
||||
case 90: {
|
||||
const timestamp = this.readUint(); if (timestamp === null) { return resetPointer() }
|
||||
const projectID = this.readUint(); if (projectID === null) { return resetPointer() }
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
import { MType } from './raw.gen'
|
||||
|
||||
const DOM_TYPES = [0,4,5,6,7,8,9,10,11,12,13,14,15,16,18,19,20,37,38,49,50,51,54,55,57,58,59,60,61,67,69,70,71,72,73,74,75,76,77,90,93,96,100,102,103,105]
|
||||
const DOM_TYPES = [0,4,5,6,7,8,9,10,11,12,13,14,15,16,18,19,20,37,38,49,50,51,54,55,57,58,59,60,61,67,69,70,71,72,73,74,75,76,77,84,90,93,96,100,102,103,105]
|
||||
export function isDOMType(t: MType) {
|
||||
return DOM_TYPES.includes(t)
|
||||
}
|
||||
|
|
@ -55,6 +55,7 @@ import type {
|
|||
RawAdoptedSsAddOwner,
|
||||
RawAdoptedSsRemoveOwner,
|
||||
RawZustand,
|
||||
RawSelectionChange,
|
||||
RawIosSessionStart,
|
||||
RawIosCustomEvent,
|
||||
RawIosScreenChanges,
|
||||
|
|
@ -169,6 +170,8 @@ export type AdoptedSsRemoveOwner = RawAdoptedSsRemoveOwner & Timed
|
|||
|
||||
export type Zustand = RawZustand & Timed
|
||||
|
||||
export type SelectionChange = RawSelectionChange & Timed
|
||||
|
||||
export type IosSessionStart = RawIosSessionStart & Timed
|
||||
|
||||
export type IosCustomEvent = RawIosCustomEvent & Timed
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ export const enum MType {
|
|||
AdoptedSsAddOwner = 76,
|
||||
AdoptedSsRemoveOwner = 77,
|
||||
Zustand = 79,
|
||||
SelectionChange = 84,
|
||||
IosSessionStart = 90,
|
||||
IosCustomEvent = 93,
|
||||
IosScreenChanges = 96,
|
||||
|
|
@ -418,6 +419,13 @@ export interface RawZustand {
|
|||
state: string,
|
||||
}
|
||||
|
||||
export interface RawSelectionChange {
|
||||
tp: MType.SelectionChange,
|
||||
selectionStart: number,
|
||||
selectionEnd: number,
|
||||
selection: string,
|
||||
}
|
||||
|
||||
export interface RawIosSessionStart {
|
||||
tp: MType.IosSessionStart,
|
||||
timestamp: number,
|
||||
|
|
@ -489,4 +497,4 @@ export interface RawIosNetworkCall {
|
|||
}
|
||||
|
||||
|
||||
export type RawMessage = RawTimestamp | RawSetPageLocation | RawSetViewportSize | RawSetViewportScroll | RawCreateDocument | RawCreateElementNode | RawCreateTextNode | RawMoveNode | RawRemoveNode | RawSetNodeAttribute | RawRemoveNodeAttribute | RawSetNodeData | RawSetCssData | RawSetNodeScroll | RawSetInputValue | RawSetInputChecked | RawMouseMove | RawNetworkRequest | RawConsoleLog | RawCssInsertRule | RawCssDeleteRule | RawFetch | RawProfiler | RawOTable | RawRedux | RawVuex | RawMobX | RawNgRx | RawGraphQl | RawPerformanceTrack | RawStringDict | RawSetNodeAttributeDict | RawResourceTiming | RawConnectionInformation | RawSetPageVisibility | RawLoadFontFace | RawSetNodeFocus | RawLongTask | RawSetNodeAttributeURLBased | RawSetCssDataURLBased | RawCssInsertRuleURLBased | RawMouseClick | RawCreateIFrameDocument | RawAdoptedSsReplaceURLBased | RawAdoptedSsReplace | RawAdoptedSsInsertRuleURLBased | RawAdoptedSsInsertRule | RawAdoptedSsDeleteRule | RawAdoptedSsAddOwner | RawAdoptedSsRemoveOwner | RawZustand | RawIosSessionStart | RawIosCustomEvent | RawIosScreenChanges | RawIosClickEvent | RawIosPerformanceEvent | RawIosLog | RawIosNetworkCall;
|
||||
export type RawMessage = RawTimestamp | RawSetPageLocation | RawSetViewportSize | RawSetViewportScroll | RawCreateDocument | RawCreateElementNode | RawCreateTextNode | RawMoveNode | RawRemoveNode | RawSetNodeAttribute | RawRemoveNodeAttribute | RawSetNodeData | RawSetCssData | RawSetNodeScroll | RawSetInputValue | RawSetInputChecked | RawMouseMove | RawNetworkRequest | RawConsoleLog | RawCssInsertRule | RawCssDeleteRule | RawFetch | RawProfiler | RawOTable | RawRedux | RawVuex | RawMobX | RawNgRx | RawGraphQl | RawPerformanceTrack | RawStringDict | RawSetNodeAttributeDict | RawResourceTiming | RawConnectionInformation | RawSetPageVisibility | RawLoadFontFace | RawSetNodeFocus | RawLongTask | RawSetNodeAttributeURLBased | RawSetCssDataURLBased | RawCssInsertRuleURLBased | RawMouseClick | RawCreateIFrameDocument | RawAdoptedSsReplaceURLBased | RawAdoptedSsReplace | RawAdoptedSsInsertRuleURLBased | RawAdoptedSsInsertRule | RawAdoptedSsDeleteRule | RawAdoptedSsAddOwner | RawAdoptedSsRemoveOwner | RawZustand | RawSelectionChange | RawIosSessionStart | RawIosCustomEvent | RawIosScreenChanges | RawIosClickEvent | RawIosPerformanceEvent | RawIosLog | RawIosNetworkCall;
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ export const TP_MAP = {
|
|||
76: MType.AdoptedSsAddOwner,
|
||||
77: MType.AdoptedSsRemoveOwner,
|
||||
79: MType.Zustand,
|
||||
84: MType.SelectionChange,
|
||||
90: MType.IosSessionStart,
|
||||
93: MType.IosCustomEvent,
|
||||
96: MType.IosScreenChanges,
|
||||
|
|
|
|||
|
|
@ -436,8 +436,15 @@ type TrInputChange = [
|
|||
hesitationTime: number,
|
||||
]
|
||||
|
||||
type TrSelectionChange = [
|
||||
type: 84,
|
||||
selectionStart: number,
|
||||
selectionEnd: number,
|
||||
selection: string,
|
||||
]
|
||||
|
||||
export type TrackerMessage = TrTimestamp | TrSetPageLocation | TrSetViewportSize | TrSetViewportScroll | TrCreateDocument | TrCreateElementNode | TrCreateTextNode | TrMoveNode | TrRemoveNode | TrSetNodeAttribute | TrRemoveNodeAttribute | TrSetNodeData | TrSetNodeScroll | TrSetInputTarget | TrSetInputValue | TrSetInputChecked | TrMouseMove | TrNetworkRequest | TrConsoleLog | TrPageLoadTiming | TrPageRenderTiming | TrCustomEvent | TrUserID | TrUserAnonymousID | TrMetadata | TrCSSInsertRule | TrCSSDeleteRule | TrFetch | TrProfiler | TrOTable | TrStateAction | TrRedux | TrVuex | TrMobX | TrNgRx | TrGraphQL | TrPerformanceTrack | TrStringDict | TrSetNodeAttributeDict | TrResourceTiming | TrConnectionInformation | TrSetPageVisibility | TrLoadFontFace | TrSetNodeFocus | TrLongTask | TrSetNodeAttributeURLBased | TrSetCSSDataURLBased | TrTechnicalInfo | TrCustomIssue | TrCSSInsertRuleURLBased | TrMouseClick | TrCreateIFrameDocument | TrAdoptedSSReplaceURLBased | TrAdoptedSSInsertRuleURLBased | TrAdoptedSSDeleteRule | TrAdoptedSSAddOwner | TrAdoptedSSRemoveOwner | TrJSException | TrZustand | TrBatchMetadata | TrPartitionedMessage | TrInputChange
|
||||
|
||||
export type TrackerMessage = TrTimestamp | TrSetPageLocation | TrSetViewportSize | TrSetViewportScroll | TrCreateDocument | TrCreateElementNode | TrCreateTextNode | TrMoveNode | TrRemoveNode | TrSetNodeAttribute | TrRemoveNodeAttribute | TrSetNodeData | TrSetNodeScroll | TrSetInputTarget | TrSetInputValue | TrSetInputChecked | TrMouseMove | TrNetworkRequest | TrConsoleLog | TrPageLoadTiming | TrPageRenderTiming | TrCustomEvent | TrUserID | TrUserAnonymousID | TrMetadata | TrCSSInsertRule | TrCSSDeleteRule | TrFetch | TrProfiler | TrOTable | TrStateAction | TrRedux | TrVuex | TrMobX | TrNgRx | TrGraphQL | TrPerformanceTrack | TrStringDict | TrSetNodeAttributeDict | TrResourceTiming | TrConnectionInformation | TrSetPageVisibility | TrLoadFontFace | TrSetNodeFocus | TrLongTask | TrSetNodeAttributeURLBased | TrSetCSSDataURLBased | TrTechnicalInfo | TrCustomIssue | TrCSSInsertRuleURLBased | TrMouseClick | TrCreateIFrameDocument | TrAdoptedSSReplaceURLBased | TrAdoptedSSInsertRuleURLBased | TrAdoptedSSDeleteRule | TrAdoptedSSAddOwner | TrAdoptedSSRemoveOwner | TrJSException | TrZustand | TrBatchMetadata | TrPartitionedMessage | TrInputChange | TrSelectionChange
|
||||
|
||||
export default function translate(tMsg: TrackerMessage): RawMessage | null {
|
||||
switch(tMsg[0]) {
|
||||
|
|
@ -874,6 +881,15 @@ export default function translate(tMsg: TrackerMessage): RawMessage | null {
|
|||
}
|
||||
}
|
||||
|
||||
case 84: {
|
||||
return {
|
||||
tp: MType.SelectionChange,
|
||||
selectionStart: tMsg[1],
|
||||
selectionEnd: tMsg[2],
|
||||
selection: tMsg[3],
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
return null
|
||||
}
|
||||
|
|
|
|||
|
|
@ -481,6 +481,12 @@ message 83, 'InputChange', :replayer => false do
|
|||
int 'HesitationTime'
|
||||
end
|
||||
|
||||
message 84, 'SelectionChange' do
|
||||
uint 'SelectionStart'
|
||||
uint 'SelectionEnd'
|
||||
string 'Selection'
|
||||
end
|
||||
|
||||
## Backend-only
|
||||
message 125, 'IssueEvent', :replayer => false, :tracker => false do
|
||||
uint 'MessageID'
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ export declare const enum Type {
|
|||
BatchMetadata = 81,
|
||||
PartitionedMessage = 82,
|
||||
InputChange = 83,
|
||||
SelectionChange = 84,
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -498,6 +499,13 @@ export type InputChange = [
|
|||
/*hesitationTime:*/ number,
|
||||
]
|
||||
|
||||
export type SelectionChange = [
|
||||
/*type:*/ Type.SelectionChange,
|
||||
/*selectionStart:*/ number,
|
||||
/*selectionEnd:*/ number,
|
||||
/*selection:*/ string,
|
||||
]
|
||||
|
||||
type Message = Timestamp | SetPageLocation | SetViewportSize | SetViewportScroll | CreateDocument | CreateElementNode | CreateTextNode | MoveNode | RemoveNode | SetNodeAttribute | RemoveNodeAttribute | SetNodeData | SetNodeScroll | SetInputTarget | SetInputValue | SetInputChecked | MouseMove | NetworkRequest | ConsoleLog | PageLoadTiming | PageRenderTiming | CustomEvent | UserID | UserAnonymousID | Metadata | CSSInsertRule | CSSDeleteRule | Fetch | Profiler | OTable | StateAction | Redux | Vuex | MobX | NgRx | GraphQL | PerformanceTrack | StringDict | SetNodeAttributeDict | ResourceTiming | ConnectionInformation | SetPageVisibility | LoadFontFace | SetNodeFocus | LongTask | SetNodeAttributeURLBased | SetCSSDataURLBased | TechnicalInfo | CustomIssue | CSSInsertRuleURLBased | MouseClick | CreateIFrameDocument | AdoptedSSReplaceURLBased | AdoptedSSInsertRuleURLBased | AdoptedSSDeleteRule | AdoptedSSAddOwner | AdoptedSSRemoveOwner | JSException | Zustand | BatchMetadata | PartitionedMessage | InputChange
|
||||
|
||||
type Message = Timestamp | SetPageLocation | SetViewportSize | SetViewportScroll | CreateDocument | CreateElementNode | CreateTextNode | MoveNode | RemoveNode | SetNodeAttribute | RemoveNodeAttribute | SetNodeData | SetNodeScroll | SetInputTarget | SetInputValue | SetInputChecked | MouseMove | NetworkRequest | ConsoleLog | PageLoadTiming | PageRenderTiming | CustomEvent | UserID | UserAnonymousID | Metadata | CSSInsertRule | CSSDeleteRule | Fetch | Profiler | OTable | StateAction | Redux | Vuex | MobX | NgRx | GraphQL | PerformanceTrack | StringDict | SetNodeAttributeDict | ResourceTiming | ConnectionInformation | SetPageVisibility | LoadFontFace | SetNodeFocus | LongTask | SetNodeAttributeURLBased | SetCSSDataURLBased | TechnicalInfo | CustomIssue | CSSInsertRuleURLBased | MouseClick | CreateIFrameDocument | AdoptedSSReplaceURLBased | AdoptedSSInsertRuleURLBased | AdoptedSSDeleteRule | AdoptedSSAddOwner | AdoptedSSRemoveOwner | JSException | Zustand | BatchMetadata | PartitionedMessage | InputChange | SelectionChange
|
||||
export default Message
|
||||
|
|
|
|||
|
|
@ -805,3 +805,16 @@ export function InputChange(
|
|||
]
|
||||
}
|
||||
|
||||
export function SelectionChange(
|
||||
selectionStart: number,
|
||||
selectionEnd: number,
|
||||
selection: string,
|
||||
): Messages.SelectionChange {
|
||||
return [
|
||||
Messages.Type.SelectionChange,
|
||||
selectionStart,
|
||||
selectionEnd,
|
||||
selection,
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import Focus from './modules/focus.js'
|
|||
import Fonts from './modules/fonts.js'
|
||||
import Network from './modules/network.js'
|
||||
import ConstructedStyleSheets from './modules/constructedStyleSheets.js'
|
||||
import Selection from './modules/selection.js'
|
||||
import { IN_BROWSER, deprecationWarn, DOCS_HOST } from './utils.js'
|
||||
|
||||
import type { Options as AppOptions } from './app/index.js'
|
||||
|
|
@ -131,6 +132,7 @@ export default class API {
|
|||
Focus(app)
|
||||
Fonts(app)
|
||||
Network(app, options.network)
|
||||
Selection(app)
|
||||
;(window as any).__OPENREPLAY__ = this
|
||||
|
||||
if (options.autoResetOnWindowOpen) {
|
||||
|
|
|
|||
39
tracker/tracker/src/main/modules/selection.ts
Normal file
39
tracker/tracker/src/main/modules/selection.ts
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import type App from '../app/index.js'
|
||||
import { SelectionChange } from '../app/messages.gen.js'
|
||||
|
||||
function selection(app: App) {
|
||||
app.attachEventListener(document, 'selectionchange', () => {
|
||||
const selection = document.getSelection()
|
||||
if (selection !== null && !selection.isCollapsed) {
|
||||
const selectionStart = app.nodes.getID(selection.anchorNode!)
|
||||
const selectionEnd = app.nodes.getID(selection.focusNode!)
|
||||
const selectedText = selection.toString().replace(/\s+/g, ' ')
|
||||
if (selectionStart && selectionEnd) {
|
||||
app.send(SelectionChange(selectionStart, selectionEnd, selectedText))
|
||||
}
|
||||
} else {
|
||||
app.send(SelectionChange(0, 0, ''))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default selection
|
||||
|
||||
/** TODO: research how to get all in-between nodes inside selection range
|
||||
* including nodes between anchor and focus nodes and their children
|
||||
* without recursively searching the dom tree
|
||||
*/
|
||||
|
||||
// if (selection.rangeCount) {
|
||||
// const nodes = [];
|
||||
// for (let i = 0; i < selection.rangeCount; i++) {
|
||||
// const range = selection.getRangeAt(i);
|
||||
// let node: Node | null = range.startContainer;
|
||||
// while (node) {
|
||||
// nodes.push(node);
|
||||
// if (node === range.endContainer) break;
|
||||
// node = node.nextSibling;
|
||||
// }
|
||||
// }
|
||||
// // send selected nodes
|
||||
// }
|
||||
|
|
@ -258,6 +258,10 @@ export default class MessageEncoder extends PrimitiveEncoder {
|
|||
return this.uint(msg[1]) && this.string(msg[2]) && this.int(msg[3])
|
||||
break
|
||||
|
||||
case Messages.Type.SelectionChange:
|
||||
return this.uint(msg[1]) && this.uint(msg[2]) && this.string(msg[3])
|
||||
break
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue