Skip to content

Commit

Permalink
feat: Create elements chain string as we store it
Browse files Browse the repository at this point in the history
  • Loading branch information
tiina303 committed Oct 5, 2023
1 parent 5f493d2 commit d89ac78
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 2 deletions.
88 changes: 87 additions & 1 deletion src/autocapture-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* @param {Element} el - element to get the className of
* @returns {string} the element's class
*/
import { AutocaptureConfig } from 'types'
import { AutocaptureConfig, Properties } from 'types'
import { _each, _includes, _isUndefined, _trim } from './utils'

export function getClassName(el: Element): string {
Expand Down Expand Up @@ -342,3 +342,89 @@ export function getNestedSpanText(target: Element): string {
}
return text
}

/*
Back in the day storing events in Postgres we use Elements for autocapture events.
Now we're using elements_chain. We used to do this parsing/processing during ingestion.
This code is just copied over from ingestion, but we should optimize it
to create elements_chain string directly.
*/
export function getElementsChainString(elements: Properties[]): string {
return elementsToString(extractElements(elements))
}

interface Element {
text?: string;
tag_name?: string;
href?: string;
attr_id?: string;
attr_class?: string[];
nth_child?: number;
nth_of_type?: number;
attributes?: Record<string, any>;
event_id?: number;
order?: number;
group_id?: number;
}

function escapeQuotes(input: string): string {
return input.replace(/"/g, '\\"')
}

function elementsToString(elements: Element[]): string {
const ret = elements.map((element) => {
let el_string = ''
if (element.tag_name) {
el_string += element.tag_name
}
if (element.attr_class) {
element.attr_class.sort()
for (const single_class of element.attr_class) {
el_string += `.${single_class.replace(/"/g, '')}`
}
}
let attributes: Record<string, any> = {
...(element.text ? { text: element.text } : {}),
'nth-child': element.nth_child ?? 0,
'nth-of-type': element.nth_of_type ?? 0,
...(element.href ? { href: element.href } : {}),
...(element.attr_id ? { attr_id: element.attr_id } : {}),
...element.attributes,
}
attributes = Object.fromEntries(
Object.entries(attributes)
.sort(([a], [b]) => a.localeCompare(b))
.map(([key, value]) => [escapeQuotes(key.toString()), escapeQuotes(value.toString())])
)
el_string += ':'
el_string += Object.entries(attributes)
.map(([key, value]) => `${key}="${value}"`)
.join('')
return el_string
})
return ret.join(';')
}

function extractElements(elements: Properties[]): Element[] {
return elements.map((el) => ({
text: el['$el_text']?.slice(0, 400),
tag_name: el['tag_name'],
href: el['attr__href']?.slice(0, 2048),
attr_class: extractAttrClass(el),
attr_id: el['attr__id'],
nth_child: el['nth_child'],
nth_of_type: el['nth_of_type'],
attributes: Object.fromEntries(Object.entries(el).filter(([key]) => key.startsWith('attr__'))),
}))
}

function extractAttrClass(el: Properties): Element['attr_class'] {
const attr_class = el['attr__class']
if (!attr_class) {
return undefined
} else if (Array.isArray(attr_class)) {
return attr_class
} else {
return attr_class.split(' ')
}
}
3 changes: 2 additions & 1 deletion src/autocapture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
isAngularStyleAttr,
isDocumentFragment,
getDirectAndNestedSpanText,
getElementsChainString,
} from './autocapture-utils'
import RageClick from './extensions/rageclick'
import { AutocaptureConfig, AutoCaptureCustomProperty, DecideResponse, Properties } from './types'
Expand Down Expand Up @@ -263,7 +264,7 @@ const autocapture = {
const props = _extend(
this._getDefaultProperties(e.type),
{
$elements: elementsJson,
$elements_chain: getElementsChainString(elementsJson),
},
elementsJson[0]?.['$el_text'] ? { $el_text: elementsJson[0]?.['$el_text'] } : {},
this._getCustomProperties(targetElementList),
Expand Down

0 comments on commit d89ac78

Please sign in to comment.