@openreplay/tracker 3.5.12 → 3.5.13-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/app/guards.d.ts +17 -0
- package/cjs/app/guards.js +24 -0
- package/cjs/app/index.d.ts +4 -0
- package/cjs/app/index.js +20 -16
- package/cjs/app/nodes.d.ts +1 -1
- package/cjs/app/observer/observer.d.ts +2 -2
- package/cjs/app/observer/observer.js +38 -46
- package/cjs/app/observer/top_observer.js +3 -3
- package/cjs/app/sanitizer.js +2 -2
- package/cjs/index.js +1 -1
- package/cjs/modules/console.d.ts +1 -1
- package/cjs/modules/console.js +2 -1
- package/cjs/modules/cssrules.d.ts +1 -1
- package/cjs/modules/cssrules.js +2 -4
- package/cjs/modules/exception.d.ts +1 -1
- package/cjs/modules/img.d.ts +1 -1
- package/cjs/modules/img.js +2 -1
- package/cjs/modules/input.d.ts +1 -1
- package/cjs/modules/input.js +13 -12
- package/cjs/modules/longtasks.d.ts +1 -1
- package/cjs/modules/mouse.d.ts +1 -1
- package/cjs/modules/mouse.js +3 -2
- package/cjs/modules/performance.d.ts +1 -1
- package/cjs/modules/scroll.d.ts +1 -1
- package/cjs/modules/scroll.js +5 -5
- package/cjs/modules/timing.d.ts +1 -1
- package/cjs/modules/timing.js +2 -1
- package/cjs/modules/viewport.d.ts +1 -1
- package/lib/app/guards.d.ts +17 -0
- package/lib/app/guards.js +16 -0
- package/lib/app/index.d.ts +4 -0
- package/lib/app/index.js +20 -16
- package/lib/app/nodes.d.ts +1 -1
- package/lib/app/observer/observer.d.ts +2 -2
- package/lib/app/observer/observer.js +34 -42
- package/lib/app/observer/top_observer.js +3 -3
- package/lib/app/sanitizer.js +2 -2
- package/lib/common/tsconfig.tsbuildinfo +1 -1
- package/lib/index.js +1 -1
- package/lib/modules/console.d.ts +1 -1
- package/lib/modules/console.js +2 -1
- package/lib/modules/cssrules.d.ts +1 -1
- package/lib/modules/cssrules.js +2 -4
- package/lib/modules/exception.d.ts +1 -1
- package/lib/modules/img.d.ts +1 -1
- package/lib/modules/img.js +2 -1
- package/lib/modules/input.d.ts +1 -1
- package/lib/modules/input.js +13 -12
- package/lib/modules/longtasks.d.ts +1 -1
- package/lib/modules/mouse.d.ts +1 -1
- package/lib/modules/mouse.js +3 -2
- package/lib/modules/performance.d.ts +1 -1
- package/lib/modules/scroll.d.ts +1 -1
- package/lib/modules/scroll.js +5 -5
- package/lib/modules/timing.d.ts +1 -1
- package/lib/modules/timing.js +2 -1
- package/lib/modules/viewport.d.ts +1 -1
- package/package.json +1 -1
- package/cjs/app/context.d.ts +0 -18
- package/cjs/app/context.js +0 -73
- package/lib/app/context.d.ts +0 -18
- package/lib/app/context.js +0 -68
package/cjs/modules/input.js
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getInputLabel = void 0;
|
|
4
4
|
const utils_js_1 = require("../utils.js");
|
|
5
|
+
const guards_js_1 = require("../app/guards.js");
|
|
5
6
|
const messages_js_1 = require("../common/messages.js");
|
|
6
7
|
function isTextEditable(node) {
|
|
7
|
-
if (node
|
|
8
|
+
if ((0, guards_js_1.hasTag)(node, "TEXTAREA")) {
|
|
8
9
|
return true;
|
|
9
10
|
}
|
|
10
|
-
if (!(node
|
|
11
|
+
if (!(0, guards_js_1.hasTag)(node, "INPUT")) {
|
|
11
12
|
return false;
|
|
12
13
|
}
|
|
13
14
|
const type = node.type;
|
|
@@ -19,7 +20,7 @@ function isTextEditable(node) {
|
|
|
19
20
|
type === 'range');
|
|
20
21
|
}
|
|
21
22
|
function isCheckable(node) {
|
|
22
|
-
if (!(node
|
|
23
|
+
if (!(0, guards_js_1.hasTag)(node, "INPUT")) {
|
|
23
24
|
return false;
|
|
24
25
|
}
|
|
25
26
|
const type = node.type;
|
|
@@ -29,7 +30,7 @@ const labelElementFor = utils_js_1.IN_BROWSER && 'labels' in HTMLInputElement.pr
|
|
|
29
30
|
? (node) => {
|
|
30
31
|
let p = node;
|
|
31
32
|
while ((p = p.parentNode) !== null) {
|
|
32
|
-
if (p
|
|
33
|
+
if ((0, guards_js_1.hasTag)(p, "LABEL")) {
|
|
33
34
|
return p;
|
|
34
35
|
}
|
|
35
36
|
}
|
|
@@ -41,7 +42,7 @@ const labelElementFor = utils_js_1.IN_BROWSER && 'labels' in HTMLInputElement.pr
|
|
|
41
42
|
: (node) => {
|
|
42
43
|
let p = node;
|
|
43
44
|
while ((p = p.parentNode) !== null) {
|
|
44
|
-
if (p
|
|
45
|
+
if ((0, guards_js_1.hasTag)(p, "LABEL")) {
|
|
45
46
|
return p;
|
|
46
47
|
}
|
|
47
48
|
}
|
|
@@ -71,7 +72,7 @@ function default_1(app, opts) {
|
|
|
71
72
|
const options = Object.assign({
|
|
72
73
|
obscureInputNumbers: true,
|
|
73
74
|
obscureInputEmails: true,
|
|
74
|
-
defaultInputMode: 0 /* Plain */,
|
|
75
|
+
defaultInputMode: 0 /* InputMode.Plain */,
|
|
75
76
|
}, opts);
|
|
76
77
|
function sendInputTarget(id, node) {
|
|
77
78
|
const label = getInputLabel(node);
|
|
@@ -83,22 +84,22 @@ function default_1(app, opts) {
|
|
|
83
84
|
let value = node.value;
|
|
84
85
|
let inputMode = options.defaultInputMode;
|
|
85
86
|
if (node.type === 'password' || (0, utils_js_1.hasOpenreplayAttribute)(node, 'hidden')) {
|
|
86
|
-
inputMode = 2 /* Hidden */;
|
|
87
|
+
inputMode = 2 /* InputMode.Hidden */;
|
|
87
88
|
}
|
|
88
89
|
else if ((0, utils_js_1.hasOpenreplayAttribute)(node, 'obscured') ||
|
|
89
|
-
(inputMode === 0 /* Plain */ &&
|
|
90
|
+
(inputMode === 0 /* InputMode.Plain */ &&
|
|
90
91
|
((options.obscureInputNumbers && /\d\d\d\d/.test(value)) ||
|
|
91
92
|
(options.obscureInputEmails &&
|
|
92
93
|
(node.type === 'email' || !!~value.indexOf('@')))))) {
|
|
93
|
-
inputMode = 1 /* Obscured */;
|
|
94
|
+
inputMode = 1 /* InputMode.Obscured */;
|
|
94
95
|
}
|
|
95
96
|
let mask = 0;
|
|
96
97
|
switch (inputMode) {
|
|
97
|
-
case 2 /* Hidden */:
|
|
98
|
+
case 2 /* InputMode.Hidden */:
|
|
98
99
|
mask = -1;
|
|
99
100
|
value = '';
|
|
100
101
|
break;
|
|
101
|
-
case 1 /* Obscured */:
|
|
102
|
+
case 1 /* InputMode.Obscured */:
|
|
102
103
|
mask = value.length;
|
|
103
104
|
value = '';
|
|
104
105
|
break;
|
|
@@ -148,7 +149,7 @@ function default_1(app, opts) {
|
|
|
148
149
|
return;
|
|
149
150
|
}
|
|
150
151
|
// TODO: support multiple select (?): use selectedOptions; Need send target?
|
|
151
|
-
if (node
|
|
152
|
+
if ((0, guards_js_1.hasTag)(node, "SELECT")) {
|
|
152
153
|
sendInputValue(id, node);
|
|
153
154
|
app.attachEventListener(node, "change", () => {
|
|
154
155
|
sendInputValue(id, node);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import App from "../app/index.js";
|
|
1
|
+
import type App from "../app/index.js";
|
|
2
2
|
export default function (app: App): void;
|
package/cjs/modules/mouse.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import App from "../app/index.js";
|
|
1
|
+
import type App from "../app/index.js";
|
|
2
2
|
export default function (app: App): void;
|
package/cjs/modules/mouse.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const guards_js_1 = require("../app/guards.js");
|
|
3
4
|
const utils_js_1 = require("../utils.js");
|
|
4
5
|
const messages_js_1 = require("../common/messages.js");
|
|
5
6
|
const input_js_1 = require("./input.js");
|
|
@@ -49,7 +50,7 @@ function _getTarget(target) {
|
|
|
49
50
|
}
|
|
50
51
|
element = element.parentElement;
|
|
51
52
|
}
|
|
52
|
-
if (
|
|
53
|
+
if ((0, guards_js_1.isSVGElement)(target)) {
|
|
53
54
|
let owner = target.ownerSVGElement;
|
|
54
55
|
while (owner !== null) {
|
|
55
56
|
target = owner;
|
|
@@ -79,7 +80,7 @@ function default_1(app) {
|
|
|
79
80
|
if (dl !== null) {
|
|
80
81
|
return dl;
|
|
81
82
|
}
|
|
82
|
-
if (target
|
|
83
|
+
if ((0, guards_js_1.hasTag)(target, "INPUT")) {
|
|
83
84
|
return (0, input_js_1.getInputLabel)(target);
|
|
84
85
|
}
|
|
85
86
|
if (isClickable(target)) {
|
package/cjs/modules/scroll.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import App from "../app/index.js";
|
|
1
|
+
import type App from "../app/index.js";
|
|
2
2
|
export default function (app: App): void;
|
package/cjs/modules/scroll.js
CHANGED
|
@@ -22,11 +22,11 @@ function default_1(app) {
|
|
|
22
22
|
documentScroll = false;
|
|
23
23
|
nodeScroll.clear();
|
|
24
24
|
});
|
|
25
|
-
app.nodes.attachNodeCallback(node => {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
})
|
|
25
|
+
// app.nodes.attachNodeCallback(node => {
|
|
26
|
+
// if (isElementNode(node) && node.scrollLeft + node.scrollTop > 0) {
|
|
27
|
+
// nodeScroll.set(node, [node.scrollLeft, node.scrollTop]);
|
|
28
|
+
// }
|
|
29
|
+
// })
|
|
30
30
|
app.attachEventListener(window, 'scroll', (e) => {
|
|
31
31
|
const target = e.target;
|
|
32
32
|
if (target === document) {
|
package/cjs/modules/timing.d.ts
CHANGED
package/cjs/modules/timing.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const guards_js_1 = require("../app/guards.js");
|
|
3
4
|
const utils_js_1 = require("../utils.js");
|
|
4
5
|
const messages_js_1 = require("../common/messages.js");
|
|
5
6
|
function getPaintBlocks(resources) {
|
|
@@ -9,7 +10,7 @@ function getPaintBlocks(resources) {
|
|
|
9
10
|
for (let i = 0; i < elements.length; i++) {
|
|
10
11
|
const element = elements[i];
|
|
11
12
|
let src = '';
|
|
12
|
-
if (element
|
|
13
|
+
if ((0, guards_js_1.hasTag)(element, "IMG")) {
|
|
13
14
|
src = element.currentSrc || element.src;
|
|
14
15
|
}
|
|
15
16
|
if (!src) {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import App from "../app/index.js";
|
|
1
|
+
import type App from "../app/index.js";
|
|
2
2
|
export default function (app: App): void;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare function isSVGElement(node: Element): node is SVGElement;
|
|
2
|
+
export declare function isElementNode(node: Node): node is Element;
|
|
3
|
+
export declare function isTextNode(node: Node): node is Text;
|
|
4
|
+
export declare function isRootNode(node: Node): boolean;
|
|
5
|
+
declare type TagTypeMap = {
|
|
6
|
+
HTML: HTMLHtmlElement;
|
|
7
|
+
IMG: HTMLImageElement;
|
|
8
|
+
INPUT: HTMLInputElement;
|
|
9
|
+
TEXTAREA: HTMLTextAreaElement;
|
|
10
|
+
SELECT: HTMLSelectElement;
|
|
11
|
+
LABEL: HTMLLabelElement;
|
|
12
|
+
IFRAME: HTMLIFrameElement;
|
|
13
|
+
STYLE: HTMLStyleElement | SVGStyleElement;
|
|
14
|
+
LINK: HTMLLinkElement;
|
|
15
|
+
};
|
|
16
|
+
export declare function hasTag<T extends keyof TagTypeMap>(el: Node, tagName: T): el is TagTypeMap[typeof tagName];
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export function isSVGElement(node) {
|
|
2
|
+
return node.namespaceURI === 'http://www.w3.org/2000/svg';
|
|
3
|
+
}
|
|
4
|
+
export function isElementNode(node) {
|
|
5
|
+
return node.nodeType === Node.ELEMENT_NODE;
|
|
6
|
+
}
|
|
7
|
+
export function isTextNode(node) {
|
|
8
|
+
return node.nodeType === Node.TEXT_NODE;
|
|
9
|
+
}
|
|
10
|
+
export function isRootNode(node) {
|
|
11
|
+
return node.nodeType === Node.DOCUMENT_NODE ||
|
|
12
|
+
node.nodeType === Node.DOCUMENT_FRAGMENT_NODE;
|
|
13
|
+
}
|
|
14
|
+
export function hasTag(el, tagName) {
|
|
15
|
+
return el.nodeName.toUpperCase() === tagName;
|
|
16
|
+
}
|
package/lib/app/index.d.ts
CHANGED
|
@@ -44,6 +44,8 @@ declare type AppOptions = {
|
|
|
44
44
|
__is_snippet: boolean;
|
|
45
45
|
__debug_report_edp: string | null;
|
|
46
46
|
__debug__?: LoggerOptions;
|
|
47
|
+
localStorage: Storage;
|
|
48
|
+
sessionStorage: Storage;
|
|
47
49
|
onStart?: StartCallback;
|
|
48
50
|
} & WebworkerOptions;
|
|
49
51
|
export declare type Options = AppOptions & ObserverOptions & SanitizerOptions;
|
|
@@ -56,6 +58,8 @@ export default class App {
|
|
|
56
58
|
readonly debug: Logger;
|
|
57
59
|
readonly notify: Logger;
|
|
58
60
|
readonly session: Session;
|
|
61
|
+
readonly localStorage: Storage;
|
|
62
|
+
readonly sessionStorage: Storage;
|
|
59
63
|
private readonly messages;
|
|
60
64
|
private readonly observer;
|
|
61
65
|
private readonly startCallbacks;
|
package/lib/app/index.js
CHANGED
|
@@ -29,7 +29,7 @@ export default class App {
|
|
|
29
29
|
this.stopCallbacks = [];
|
|
30
30
|
this.commitCallbacks = [];
|
|
31
31
|
this.activityState = ActivityState.NotActive;
|
|
32
|
-
this.version = '3.5.
|
|
32
|
+
this.version = '3.5.13-beta.0'; // TODO: version compatability check inside each plugin.
|
|
33
33
|
this.projectKey = projectKey;
|
|
34
34
|
this.options = Object.assign({
|
|
35
35
|
revID: '',
|
|
@@ -43,10 +43,9 @@ export default class App {
|
|
|
43
43
|
verbose: false,
|
|
44
44
|
__is_snippet: false,
|
|
45
45
|
__debug_report_edp: null,
|
|
46
|
+
localStorage: window.localStorage,
|
|
47
|
+
sessionStorage: window.sessionStorage,
|
|
46
48
|
}, options);
|
|
47
|
-
if (sessionToken != null) {
|
|
48
|
-
sessionStorage.setItem(this.options.session_token_key, sessionToken);
|
|
49
|
-
}
|
|
50
49
|
this.revID = this.options.revID;
|
|
51
50
|
this.sanitizer = new Sanitizer(this, options);
|
|
52
51
|
this.nodes = new Nodes(this.options.node_id);
|
|
@@ -56,6 +55,11 @@ export default class App {
|
|
|
56
55
|
this.debug = new Logger(this.options.__debug__);
|
|
57
56
|
this.notify = new Logger(this.options.verbose ? LogLevel.Warnings : LogLevel.Silent);
|
|
58
57
|
this.session = new Session(this);
|
|
58
|
+
this.localStorage = this.options.localStorage;
|
|
59
|
+
this.sessionStorage = this.options.sessionStorage;
|
|
60
|
+
if (sessionToken != null) {
|
|
61
|
+
this.sessionStorage.setItem(this.options.session_token_key, sessionToken);
|
|
62
|
+
}
|
|
59
63
|
try {
|
|
60
64
|
this.worker = new Worker(URL.createObjectURL(new Blob([`"use strict";function t(t){function i(...i){return new t(...i)}return i.prototype=t.prototype,i}const i=new Map;const s=t(class{constructor(t,i,s){this.pageNo=t,this.firstIndex=i,this.timestamp=s,this._id=80}encode(t){return t.uint(80)&&t.uint(this.pageNo)&&t.uint(this.firstIndex)&&t.int(this.timestamp)}});i.set(80,s);const e=t(class{constructor(t){this.timestamp=t,this._id=0}encode(t){return t.uint(0)&&t.uint(this.timestamp)}});i.set(0,e);const n=t(class{constructor(t,i,s){this.url=t,this.referrer=i,this.navigationStart=s,this._id=4}encode(t){return t.uint(4)&&t.string(this.url)&&t.string(this.referrer)&&t.uint(this.navigationStart)}});i.set(4,n);const r=t(class{constructor(t,i){this.width=t,this.height=i,this._id=5}encode(t){return t.uint(5)&&t.uint(this.width)&&t.uint(this.height)}});i.set(5,r);const h=t(class{constructor(t,i){this.x=t,this.y=i,this._id=6}encode(t){return t.uint(6)&&t.int(this.x)&&t.int(this.y)}});i.set(6,h);const o=t(class{constructor(){this._id=7}encode(t){return t.uint(7)}});i.set(7,o);const c=t(class{constructor(t,i,s,e,n){this.id=t,this.parentID=i,this.index=s,this.tag=e,this.svg=n,this._id=8}encode(t){return t.uint(8)&&t.uint(this.id)&&t.uint(this.parentID)&&t.uint(this.index)&&t.string(this.tag)&&t.boolean(this.svg)}});i.set(8,c);const a=t(class{constructor(t,i,s){this.id=t,this.parentID=i,this.index=s,this._id=9}encode(t){return t.uint(9)&&t.uint(this.id)&&t.uint(this.parentID)&&t.uint(this.index)}});i.set(9,a);const u=t(class{constructor(t,i,s){this.id=t,this.parentID=i,this.index=s,this._id=10}encode(t){return t.uint(10)&&t.uint(this.id)&&t.uint(this.parentID)&&t.uint(this.index)}});i.set(10,u);const d=t(class{constructor(t){this.id=t,this._id=11}encode(t){return t.uint(11)&&t.uint(this.id)}});i.set(11,d);const l=t(class{constructor(t,i,s){this.id=t,this.name=i,this.value=s,this._id=12}encode(t){return t.uint(12)&&t.uint(this.id)&&t.string(this.name)&&t.string(this.value)}});i.set(12,l);const p=t(class{constructor(t,i){this.id=t,this.name=i,this._id=13}encode(t){return t.uint(13)&&t.uint(this.id)&&t.string(this.name)}});i.set(13,p);const m=t(class{constructor(t,i){this.id=t,this.data=i,this._id=14}encode(t){return t.uint(14)&&t.uint(this.id)&&t.string(this.data)}});i.set(14,m);const g=t(class{constructor(t,i,s){this.id=t,this.x=i,this.y=s,this._id=16}encode(t){return t.uint(16)&&t.uint(this.id)&&t.int(this.x)&&t.int(this.y)}});i.set(16,g);const f=t(class{constructor(t,i){this.id=t,this.label=i,this._id=17}encode(t){return t.uint(17)&&t.uint(this.id)&&t.string(this.label)}});i.set(17,f);const y=t(class{constructor(t,i,s){this.id=t,this.value=i,this.mask=s,this._id=18}encode(t){return t.uint(18)&&t.uint(this.id)&&t.string(this.value)&&t.int(this.mask)}});i.set(18,y);const _=t(class{constructor(t,i){this.id=t,this.checked=i,this._id=19}encode(t){return t.uint(19)&&t.uint(this.id)&&t.boolean(this.checked)}});i.set(19,_);const v=t(class{constructor(t,i){this.x=t,this.y=i,this._id=20}encode(t){return t.uint(20)&&t.uint(this.x)&&t.uint(this.y)}});i.set(20,v);const b=t(class{constructor(t,i){this.level=t,this.value=i,this._id=22}encode(t){return t.uint(22)&&t.string(this.level)&&t.string(this.value)}});i.set(22,b);const S=t(class{constructor(t,i,s,e,n,r,h,o,c){this.requestStart=t,this.responseStart=i,this.responseEnd=s,this.domContentLoadedEventStart=e,this.domContentLoadedEventEnd=n,this.loadEventStart=r,this.loadEventEnd=h,this.firstPaint=o,this.firstContentfulPaint=c,this._id=23}encode(t){return t.uint(23)&&t.uint(this.requestStart)&&t.uint(this.responseStart)&&t.uint(this.responseEnd)&&t.uint(this.domContentLoadedEventStart)&&t.uint(this.domContentLoadedEventEnd)&&t.uint(this.loadEventStart)&&t.uint(this.loadEventEnd)&&t.uint(this.firstPaint)&&t.uint(this.firstContentfulPaint)}});i.set(23,S);const w=t(class{constructor(t,i,s){this.speedIndex=t,this.visuallyComplete=i,this.timeToInteractive=s,this._id=24}encode(t){return t.uint(24)&&t.uint(this.speedIndex)&&t.uint(this.visuallyComplete)&&t.uint(this.timeToInteractive)}});i.set(24,w);const E=t(class{constructor(t,i,s){this.name=t,this.message=i,this.payload=s,this._id=25}encode(t){return t.uint(25)&&t.string(this.name)&&t.string(this.message)&&t.string(this.payload)}});i.set(25,E);const x=t(class{constructor(t,i){this.name=t,this.payload=i,this._id=27}encode(t){return t.uint(27)&&t.string(this.name)&&t.string(this.payload)}});i.set(27,x);const T=t(class{constructor(t){this.id=t,this._id=28}encode(t){return t.uint(28)&&t.string(this.id)}});i.set(28,T);const z=t(class{constructor(t){this.id=t,this._id=29}encode(t){return t.uint(29)&&t.string(this.id)}});i.set(29,z);const k=t(class{constructor(t,i){this.key=t,this.value=i,this._id=30}encode(t){return t.uint(30)&&t.string(this.key)&&t.string(this.value)}});i.set(30,k);const I=t(class{constructor(t,i,s){this.id=t,this.rule=i,this.index=s,this._id=37}encode(t){return t.uint(37)&&t.uint(this.id)&&t.string(this.rule)&&t.uint(this.index)}});i.set(37,I);const M=t(class{constructor(t,i){this.id=t,this.index=i,this._id=38}encode(t){return t.uint(38)&&t.uint(this.id)&&t.uint(this.index)}});i.set(38,M);const B=t(class{constructor(t,i,s,e,n,r,h){this.method=t,this.url=i,this.request=s,this.response=e,this.status=n,this.timestamp=r,this.duration=h,this._id=39}encode(t){return t.uint(39)&&t.string(this.method)&&t.string(this.url)&&t.string(this.request)&&t.string(this.response)&&t.uint(this.status)&&t.uint(this.timestamp)&&t.uint(this.duration)}});i.set(39,B);const L=t(class{constructor(t,i,s,e){this.name=t,this.duration=i,this.args=s,this.result=e,this._id=40}encode(t){return t.uint(40)&&t.string(this.name)&&t.uint(this.duration)&&t.string(this.args)&&t.string(this.result)}});i.set(40,L);const C=t(class{constructor(t,i){this.key=t,this.value=i,this._id=41}encode(t){return t.uint(41)&&t.string(this.key)&&t.string(this.value)}});i.set(41,C);const A=t(class{constructor(t){this.type=t,this._id=42}encode(t){return t.uint(42)&&t.string(this.type)}});i.set(42,A);const U=t(class{constructor(t,i,s){this.action=t,this.state=i,this.duration=s,this._id=44}encode(t){return t.uint(44)&&t.string(this.action)&&t.string(this.state)&&t.uint(this.duration)}});i.set(44,U);const N=t(class{constructor(t,i){this.mutation=t,this.state=i,this._id=45}encode(t){return t.uint(45)&&t.string(this.mutation)&&t.string(this.state)}});i.set(45,N);const R=t(class{constructor(t,i){this.type=t,this.payload=i,this._id=46}encode(t){return t.uint(46)&&t.string(this.type)&&t.string(this.payload)}});i.set(46,R);const O=t(class{constructor(t,i,s){this.action=t,this.state=i,this.duration=s,this._id=47}encode(t){return t.uint(47)&&t.string(this.action)&&t.string(this.state)&&t.uint(this.duration)}});i.set(47,O);const P=t(class{constructor(t,i,s,e){this.operationKind=t,this.operationName=i,this.variables=s,this.response=e,this._id=48}encode(t){return t.uint(48)&&t.string(this.operationKind)&&t.string(this.operationName)&&t.string(this.variables)&&t.string(this.response)}});i.set(48,P);const q=t(class{constructor(t,i,s,e){this.frames=t,this.ticks=i,this.totalJSHeapSize=s,this.usedJSHeapSize=e,this._id=49}encode(t){return t.uint(49)&&t.int(this.frames)&&t.int(this.ticks)&&t.uint(this.totalJSHeapSize)&&t.uint(this.usedJSHeapSize)}});i.set(49,q);const D=t(class{constructor(t,i,s,e,n,r,h,o){this.timestamp=t,this.duration=i,this.ttfb=s,this.headerSize=e,this.encodedBodySize=n,this.decodedBodySize=r,this.url=h,this.initiator=o,this._id=53}encode(t){return t.uint(53)&&t.uint(this.timestamp)&&t.uint(this.duration)&&t.uint(this.ttfb)&&t.uint(this.headerSize)&&t.uint(this.encodedBodySize)&&t.uint(this.decodedBodySize)&&t.string(this.url)&&t.string(this.initiator)}});i.set(53,D);const W=t(class{constructor(t,i){this.downlink=t,this.type=i,this._id=54}encode(t){return t.uint(54)&&t.uint(this.downlink)&&t.string(this.type)}});i.set(54,W);const H=t(class{constructor(t){this.hidden=t,this._id=55}encode(t){return t.uint(55)&&t.boolean(this.hidden)}});i.set(55,H);const J=t(class{constructor(t,i,s,e,n,r,h){this.timestamp=t,this.duration=i,this.context=s,this.containerType=e,this.containerSrc=n,this.containerId=r,this.containerName=h,this._id=59}encode(t){return t.uint(59)&&t.uint(this.timestamp)&&t.uint(this.duration)&&t.uint(this.context)&&t.uint(this.containerType)&&t.string(this.containerSrc)&&t.string(this.containerId)&&t.string(this.containerName)}});i.set(59,J);const F=t(class{constructor(t,i,s,e){this.id=t,this.name=i,this.value=s,this.baseURL=e,this._id=60}encode(t){return t.uint(60)&&t.uint(this.id)&&t.string(this.name)&&t.string(this.value)&&t.string(this.baseURL)}});i.set(60,F);const X=t(class{constructor(t,i,s){this.id=t,this.data=i,this.baseURL=s,this._id=61}encode(t){return t.uint(61)&&t.uint(this.id)&&t.string(this.data)&&t.string(this.baseURL)}});i.set(61,X);const G=t(class{constructor(t,i){this.type=t,this.value=i,this._id=63}encode(t){return t.uint(63)&&t.string(this.type)&&t.string(this.value)}});i.set(63,G);const K=t(class{constructor(t,i){this.name=t,this.payload=i,this._id=64}encode(t){return t.uint(64)&&t.string(this.name)&&t.string(this.payload)}});i.set(64,K);const j=t(class{constructor(){this._id=65}encode(t){return t.uint(65)}});i.set(65,j);const Q=t(class{constructor(t,i,s,e){this.id=t,this.rule=i,this.index=s,this.baseURL=e,this._id=67}encode(t){return t.uint(67)&&t.uint(this.id)&&t.string(this.rule)&&t.uint(this.index)&&t.string(this.baseURL)}});i.set(67,Q);const V=t(class{constructor(t,i,s,e){this.id=t,this.hesitationTime=i,this.label=s,this.selector=e,this._id=69}encode(t){return t.uint(69)&&t.uint(this.id)&&t.uint(this.hesitationTime)&&t.string(this.label)&&t.string(this.selector)}});i.set(69,V);const Y=t(class{constructor(t,i){this.frameID=t,this.id=i,this._id=70}encode(t){return t.uint(70)&&t.uint(this.frameID)&&t.uint(this.id)}});i.set(70,Y);class Z{constructor(t,i,s,e=10,n=1e3){this.onUnauthorised=i,this.onFailure=s,this.MAX_ATTEMPTS_COUNT=e,this.ATTEMPT_TIMEOUT=n,this.attemptsCount=0,this.busy=!1,this.queue=[],this.token=null,this.ingestURL=t+"/v1/web/i"}authorise(t){this.token=t}push(t){this.busy||!this.token?this.queue.push(t):this.sendBatch(t)}retry(t){this.attemptsCount>=this.MAX_ATTEMPTS_COUNT?this.onFailure():(this.attemptsCount++,setTimeout(()=>this.sendBatch(t),this.ATTEMPT_TIMEOUT*this.attemptsCount))}sendBatch(t){this.busy=!0,fetch(this.ingestURL,{body:t,method:"POST",headers:{Authorization:"Bearer "+this.token},keepalive:t.length<65536}).then(i=>{if(401===i.status)return this.busy=!1,void this.onUnauthorised();if(i.status>=400)return void this.retry(t);this.attemptsCount=0;const s=this.queue.shift();s?this.sendBatch(s):this.busy=!1}).catch(i=>{console.warn("OpenReplay:",i),this.retry(t)})}clean(){this.queue.length=0}}const tt="function"==typeof TextEncoder?new TextEncoder:{encode(t){const i=t.length,s=new Uint8Array(3*i);let e=-1;for(var n=0,r=0,h=0;h!==i;){if(n=t.charCodeAt(h),h+=1,n>=55296&&n<=56319){if(h===i){s[e+=1]=239,s[e+=1]=191,s[e+=1]=189;break}if(!((r=t.charCodeAt(h))>=56320&&r<=57343)){s[e+=1]=239,s[e+=1]=191,s[e+=1]=189;continue}if(h+=1,(n=1024*(n-55296)+r-56320+65536)>65535){s[e+=1]=240|n>>>18,s[e+=1]=128|n>>>12&63,s[e+=1]=128|n>>>6&63,s[e+=1]=128|63&n;continue}}n<=127?s[e+=1]=0|n:n<=2047?(s[e+=1]=192|n>>>6,s[e+=1]=128|63&n):(s[e+=1]=224|n>>>12,s[e+=1]=128|n>>>6&63,s[e+=1]=128|63&n)}return s.subarray(0,e+1)}};class it{constructor(t){this.size=t,this.offset=0,this.checkpointOffset=0,this.data=new Uint8Array(t)}checkpoint(){this.checkpointOffset=this.offset}isEmpty(){return 0===this.offset}boolean(t){return this.data[this.offset++]=+t,this.offset<=this.size}uint(t){for((t<0||t>Number.MAX_SAFE_INTEGER)&&(t=0);t>=128;)this.data[this.offset++]=t%256|128,t=Math.floor(t/128);return this.data[this.offset++]=t,this.offset<=this.size}int(t){return t=Math.round(t),this.uint(t>=0?2*t:-2*t-1)}string(t){const i=tt.encode(t),s=i.byteLength;return!(!this.uint(s)||this.offset+s>this.size)&&(this.data.set(i,this.offset),this.offset+=s,!0)}reset(){this.offset=0,this.checkpointOffset=0}flush(){const t=this.data.slice(0,this.checkpointOffset);return this.reset(),t}}class st{constructor(t,i,s){this.pageNo=t,this.timestamp=i,this.onBatch=s,this.nextIndex=0,this.beaconSize=2e5,this.writer=new it(this.beaconSize),this.isEmpty=!0,this.beaconSizeLimit=1e6,this.prepareBatchMeta()}prepareBatchMeta(){return new s(this.pageNo,this.nextIndex,this.timestamp).encode(this.writer)}setBeaconSizeLimit(t){this.beaconSizeLimit=t}writeMessage(t){if(t instanceof e&&(this.timestamp=t.timestamp),!t.encode(this.writer))for(this.isEmpty||(this.onBatch(this.writer.flush()),this.prepareBatchMeta());!t.encode(this.writer);){if(this.beaconSize===this.beaconSizeLimit)return console.warn("OpenReplay: beacon size overflow. Skipping large message."),this.writer.reset(),this.prepareBatchMeta(),void(this.isEmpty=!0);this.beaconSize=Math.min(2*this.beaconSize,this.beaconSizeLimit),this.writer=new it(this.beaconSize),this.prepareBatchMeta()}this.writer.checkpoint(),this.nextIndex++,this.isEmpty=!1}finaliseBatch(){this.isEmpty||(this.onBatch(this.writer.flush()),this.prepareBatchMeta(),this.isEmpty=!0)}clean(){this.writer.reset()}}let et=null,nt=null;function rt(){nt&&nt.finaliseBatch()}function ht(){null!==ct&&(clearInterval(ct),ct=null),nt&&(nt.clean(),nt=null)}let ot,ct=null;self.onmessage=({data:t})=>{if(null!=t){if("stop"===t)return rt(),void ht();if(Array.isArray(t)){if(!nt)throw new Error("WebWorker: writer not initialised.");const s=nt;t.forEach(t=>{const e=new(i.get(t._id));Object.assign(e,t),e instanceof H&&(e.hidden?ot=setTimeout(()=>self.postMessage("restart"),18e5):clearTimeout(ot)),s.writeMessage(e)})}else{if("start"===t.type)return et=new Z(t.ingestPoint,()=>{self.postMessage("restart")},()=>{et&&(et.clean(),et=null),ht(),self.postMessage("failed")},t.connAttemptCount,t.connAttemptGap),nt=new st(t.pageNo,t.timestamp,t=>et&&et.push(t)),void(null===ct&&(ct=setInterval(rt,1e4)));if("auth"===t.type){if(!et)throw new Error("WebWorker: sender not initialised. Recieved auth.");if(!nt)throw new Error("WebWorker: writer not initialised. Recieved auth.");return et.authorise(t.token),void(t.beaconSizeLimit&&nt.setBeaconSizeLimit(t.beaconSizeLimit))}}}else rt()};
|
|
61
65
|
`], { type: 'text/javascript' })));
|
|
@@ -163,7 +167,7 @@ export default class App {
|
|
|
163
167
|
}
|
|
164
168
|
getStartInfo() {
|
|
165
169
|
return {
|
|
166
|
-
userUUID: localStorage.getItem(this.options.local_uuid_key),
|
|
170
|
+
userUUID: this.localStorage.getItem(this.options.local_uuid_key),
|
|
167
171
|
projectKey: this.projectKey,
|
|
168
172
|
revID: this.revID,
|
|
169
173
|
timestamp: timestamp(),
|
|
@@ -175,7 +179,7 @@ export default class App {
|
|
|
175
179
|
return Object.assign(Object.assign({}, this.session.getInfo()), this.getStartInfo());
|
|
176
180
|
}
|
|
177
181
|
getSessionToken() {
|
|
178
|
-
const token = sessionStorage.getItem(this.options.session_token_key);
|
|
182
|
+
const token = this.sessionStorage.getItem(this.options.session_token_key);
|
|
179
183
|
if (token !== null) {
|
|
180
184
|
return token;
|
|
181
185
|
}
|
|
@@ -217,10 +221,10 @@ export default class App {
|
|
|
217
221
|
}
|
|
218
222
|
resetNextPageSession(flag) {
|
|
219
223
|
if (flag) {
|
|
220
|
-
sessionStorage.setItem(this.options.session_reset_key, 't');
|
|
224
|
+
this.sessionStorage.setItem(this.options.session_reset_key, 't');
|
|
221
225
|
}
|
|
222
226
|
else {
|
|
223
|
-
sessionStorage.removeItem(this.options.session_reset_key);
|
|
227
|
+
this.sessionStorage.removeItem(this.options.session_reset_key);
|
|
224
228
|
}
|
|
225
229
|
}
|
|
226
230
|
_start(startOpts) {
|
|
@@ -232,12 +236,12 @@ export default class App {
|
|
|
232
236
|
}
|
|
233
237
|
this.activityState = ActivityState.Starting;
|
|
234
238
|
let pageNo = 0;
|
|
235
|
-
const pageNoStr = sessionStorage.getItem(this.options.session_pageno_key);
|
|
239
|
+
const pageNoStr = this.sessionStorage.getItem(this.options.session_pageno_key);
|
|
236
240
|
if (pageNoStr != null) {
|
|
237
241
|
pageNo = parseInt(pageNoStr);
|
|
238
242
|
pageNo++;
|
|
239
243
|
}
|
|
240
|
-
sessionStorage.setItem(this.options.session_pageno_key, pageNo.toString());
|
|
244
|
+
this.sessionStorage.setItem(this.options.session_pageno_key, pageNo.toString());
|
|
241
245
|
const startInfo = this.getStartInfo();
|
|
242
246
|
const startWorkerMsg = {
|
|
243
247
|
type: "start",
|
|
@@ -248,14 +252,14 @@ export default class App {
|
|
|
248
252
|
connAttemptGap: this.options.connAttemptGap,
|
|
249
253
|
};
|
|
250
254
|
this.worker.postMessage(startWorkerMsg); // brings delay of 10th ms?
|
|
251
|
-
const sReset = sessionStorage.getItem(this.options.session_reset_key);
|
|
252
|
-
sessionStorage.removeItem(this.options.session_reset_key);
|
|
255
|
+
const sReset = this.sessionStorage.getItem(this.options.session_reset_key);
|
|
256
|
+
this.sessionStorage.removeItem(this.options.session_reset_key);
|
|
253
257
|
return window.fetch(this.options.ingestPoint + '/v1/web/start', {
|
|
254
258
|
method: 'POST',
|
|
255
259
|
headers: {
|
|
256
260
|
'Content-Type': 'application/json',
|
|
257
261
|
},
|
|
258
|
-
body: JSON.stringify(Object.assign(Object.assign({}, startInfo), { userID: startOpts.userID || this.session.getInfo().userID, token: sessionStorage.getItem(this.options.session_token_key), deviceMemory,
|
|
262
|
+
body: JSON.stringify(Object.assign(Object.assign({}, startInfo), { userID: startOpts.userID || this.session.getInfo().userID, token: this.sessionStorage.getItem(this.options.session_token_key), deviceMemory,
|
|
259
263
|
jsHeapSizeLimit, reset: startOpts.forceNew || sReset !== null })),
|
|
260
264
|
})
|
|
261
265
|
.then(r => {
|
|
@@ -278,8 +282,8 @@ export default class App {
|
|
|
278
282
|
(typeof beaconSizeLimit !== 'number' && typeof beaconSizeLimit !== 'undefined')) {
|
|
279
283
|
return Promise.reject(`Incorrect server response: ${JSON.stringify(r)}`);
|
|
280
284
|
}
|
|
281
|
-
sessionStorage.setItem(this.options.session_token_key, token);
|
|
282
|
-
localStorage.setItem(this.options.local_uuid_key, userUUID);
|
|
285
|
+
this.sessionStorage.setItem(this.options.session_token_key, token);
|
|
286
|
+
this.localStorage.setItem(this.options.local_uuid_key, userUUID);
|
|
283
287
|
this.session.update(Object.assign({ sessionID }, startOpts));
|
|
284
288
|
this.activityState = ActivityState.Active;
|
|
285
289
|
const startWorkerMsg = {
|
|
@@ -300,7 +304,7 @@ export default class App {
|
|
|
300
304
|
return SuccessfulStart(onStartInfo);
|
|
301
305
|
})
|
|
302
306
|
.catch(reason => {
|
|
303
|
-
sessionStorage.removeItem(this.options.session_token_key);
|
|
307
|
+
this.sessionStorage.removeItem(this.options.session_token_key);
|
|
304
308
|
this.stop();
|
|
305
309
|
if (reason === CANCELED) {
|
|
306
310
|
return UnsuccessfulStart(CANCELED);
|
package/lib/app/nodes.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export default class Nodes {
|
|
|
7
7
|
constructor(node_id: string);
|
|
8
8
|
attachNodeCallback(nodeCallback: NodeCallback): void;
|
|
9
9
|
attachElementListener(type: string, node: Element, elementListener: EventListener): void;
|
|
10
|
-
registerNode(node: Node): [number, boolean];
|
|
10
|
+
registerNode(node: Node): [id: number, isNew: boolean];
|
|
11
11
|
unregisterNode(node: Node): number | undefined;
|
|
12
12
|
callNodeCallbacks(node: Node): void;
|
|
13
13
|
getID(node: Node): number | undefined;
|
|
@@ -4,11 +4,11 @@ export default abstract class Observer {
|
|
|
4
4
|
protected readonly isTopContext: boolean;
|
|
5
5
|
private readonly observer;
|
|
6
6
|
private readonly commited;
|
|
7
|
-
private readonly recents;
|
|
8
|
-
private readonly myNodes;
|
|
9
7
|
private readonly indexes;
|
|
10
8
|
private readonly attributesList;
|
|
11
9
|
private readonly textSet;
|
|
10
|
+
private readonly newSet;
|
|
11
|
+
private readonly affectedSet;
|
|
12
12
|
constructor(app: App, isTopContext?: boolean);
|
|
13
13
|
private clear;
|
|
14
14
|
private sendNodeAttribute;
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import { RemoveNodeAttribute, SetNodeAttribute, SetNodeAttributeURLBased, SetCSSDataURLBased, SetNodeData, CreateTextNode, CreateElementNode, MoveNode, RemoveNode, } from "../../common/messages.js";
|
|
2
|
-
import {
|
|
3
|
-
function isSVGElement(node) {
|
|
4
|
-
return node.namespaceURI === 'http://www.w3.org/2000/svg';
|
|
5
|
-
}
|
|
2
|
+
import { isRootNode, isTextNode, isElementNode, isSVGElement, hasTag, } from "../guards.js";
|
|
6
3
|
function isIgnored(node) {
|
|
7
|
-
if (
|
|
4
|
+
if (isTextNode(node)) {
|
|
8
5
|
return false;
|
|
9
6
|
}
|
|
10
|
-
if (!
|
|
7
|
+
if (!isElementNode(node)) {
|
|
11
8
|
return true;
|
|
12
9
|
}
|
|
13
10
|
const tag = node.tagName.toUpperCase();
|
|
@@ -22,9 +19,6 @@ function isIgnored(node) {
|
|
|
22
19
|
tag === 'TITLE' ||
|
|
23
20
|
tag === 'BASE');
|
|
24
21
|
}
|
|
25
|
-
function isRootNode(node) {
|
|
26
|
-
return isInstance(node, Document) || isInstance(node, ShadowRoot);
|
|
27
|
-
}
|
|
28
22
|
function isObservable(node) {
|
|
29
23
|
if (isRootNode(node)) {
|
|
30
24
|
return true;
|
|
@@ -36,20 +30,23 @@ export default class Observer {
|
|
|
36
30
|
this.app = app;
|
|
37
31
|
this.isTopContext = isTopContext;
|
|
38
32
|
this.commited = [];
|
|
39
|
-
this.recents = [];
|
|
40
|
-
this.myNodes = [];
|
|
41
33
|
this.indexes = [];
|
|
42
34
|
this.attributesList = [];
|
|
43
35
|
this.textSet = new Set();
|
|
36
|
+
this.newSet = new Set();
|
|
37
|
+
this.affectedSet = new Set();
|
|
44
38
|
this.observer = new MutationObserver(this.app.safe((mutations) => {
|
|
45
39
|
for (const mutation of mutations) {
|
|
46
40
|
const target = mutation.target;
|
|
47
41
|
const type = mutation.type;
|
|
48
|
-
if (!isObservable(target)
|
|
42
|
+
if (!isObservable(target) /*|| !inDocument() */) {
|
|
49
43
|
continue;
|
|
50
44
|
}
|
|
51
45
|
if (type === 'childList') {
|
|
52
46
|
for (let i = 0; i < mutation.removedNodes.length; i++) {
|
|
47
|
+
// TODO: handle node removal separately from binding.
|
|
48
|
+
// Node removals should go first in the commit.
|
|
49
|
+
// To check: MoveNode and other possible unbinding behaviours
|
|
53
50
|
this.bindTree(mutation.removedNodes[i]);
|
|
54
51
|
}
|
|
55
52
|
for (let i = 0; i < mutation.addedNodes.length; i++) {
|
|
@@ -61,9 +58,6 @@ export default class Observer {
|
|
|
61
58
|
if (id === undefined) {
|
|
62
59
|
continue;
|
|
63
60
|
}
|
|
64
|
-
if (id >= this.recents.length) { // TODO: something more convinient
|
|
65
|
-
this.recents[id] = undefined;
|
|
66
|
-
}
|
|
67
61
|
if (type === 'attributes') {
|
|
68
62
|
const name = mutation.attributeName;
|
|
69
63
|
if (name === null) {
|
|
@@ -74,10 +68,12 @@ export default class Observer {
|
|
|
74
68
|
this.attributesList[id] = attr = new Set();
|
|
75
69
|
}
|
|
76
70
|
attr.add(name);
|
|
71
|
+
this.affectedSet.add(id);
|
|
77
72
|
continue;
|
|
78
73
|
}
|
|
79
74
|
if (type === 'characterData') {
|
|
80
75
|
this.textSet.add(id);
|
|
76
|
+
this.affectedSet.add(id);
|
|
81
77
|
continue;
|
|
82
78
|
}
|
|
83
79
|
}
|
|
@@ -86,10 +82,11 @@ export default class Observer {
|
|
|
86
82
|
}
|
|
87
83
|
clear() {
|
|
88
84
|
this.commited.length = 0;
|
|
89
|
-
this.recents.length = 0;
|
|
90
85
|
this.indexes.length = 1;
|
|
91
86
|
this.attributesList.length = 0;
|
|
92
87
|
this.textSet.clear();
|
|
88
|
+
this.newSet.clear();
|
|
89
|
+
this.affectedSet.clear();
|
|
93
90
|
}
|
|
94
91
|
sendNodeAttribute(id, node, name, value) {
|
|
95
92
|
if (isSVGElement(node)) {
|
|
@@ -119,7 +116,7 @@ export default class Observer {
|
|
|
119
116
|
return;
|
|
120
117
|
}
|
|
121
118
|
if (name === 'value' &&
|
|
122
|
-
|
|
119
|
+
hasTag(node, "INPUT") &&
|
|
123
120
|
node.type !== 'button' &&
|
|
124
121
|
node.type !== 'reset' &&
|
|
125
122
|
node.type !== 'submit') {
|
|
@@ -129,7 +126,7 @@ export default class Observer {
|
|
|
129
126
|
this.app.send(new RemoveNodeAttribute(id, name));
|
|
130
127
|
return;
|
|
131
128
|
}
|
|
132
|
-
if (name === 'style' || name === 'href' &&
|
|
129
|
+
if (name === 'style' || name === 'href' && hasTag(node, "LINK")) {
|
|
133
130
|
this.app.send(new SetNodeAttributeURLBased(id, name, value, this.app.getBaseHref()));
|
|
134
131
|
return;
|
|
135
132
|
}
|
|
@@ -139,7 +136,7 @@ export default class Observer {
|
|
|
139
136
|
this.app.send(new SetNodeAttribute(id, name, value));
|
|
140
137
|
}
|
|
141
138
|
sendNodeData(id, parentElement, data) {
|
|
142
|
-
if (
|
|
139
|
+
if (hasTag(parentElement, "STYLE")) {
|
|
143
140
|
this.app.send(new SetCSSDataURLBased(id, data, this.app.getBaseHref()));
|
|
144
141
|
return;
|
|
145
142
|
}
|
|
@@ -147,10 +144,11 @@ export default class Observer {
|
|
|
147
144
|
this.app.send(new SetNodeData(id, data));
|
|
148
145
|
}
|
|
149
146
|
bindNode(node) {
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
147
|
+
const [id, isNew] = this.app.nodes.registerNode(node);
|
|
148
|
+
if (isNew) {
|
|
149
|
+
this.newSet.add(id);
|
|
150
|
+
}
|
|
151
|
+
this.affectedSet.add(id);
|
|
154
152
|
}
|
|
155
153
|
bindTree(node) {
|
|
156
154
|
if (!isObservable(node)) {
|
|
@@ -170,7 +168,8 @@ export default class Observer {
|
|
|
170
168
|
}
|
|
171
169
|
unbindNode(node) {
|
|
172
170
|
const id = this.app.nodes.unregisterNode(node);
|
|
173
|
-
if (id !== undefined && this.recents[id] === false) {
|
|
171
|
+
// if (id !== undefined && this.recents[id] === false) { // In the old version it === flase when bindNode() was called on node but it was not new
|
|
172
|
+
if (id !== undefined && !this.newSet.has(id) && this.affectedSet.has(id)) { // Unbinding logic should be simplified. Node removals should go first.
|
|
174
173
|
this.app.send(new RemoveNode(id));
|
|
175
174
|
}
|
|
176
175
|
}
|
|
@@ -183,7 +182,7 @@ export default class Observer {
|
|
|
183
182
|
// Disable parent check for the upper context HTMLHtmlElement, because it is root there... (before)
|
|
184
183
|
// TODO: get rid of "special" cases (there is an issue with CreateDocument altered behaviour though)
|
|
185
184
|
// TODO: Clean the logic (though now it workd fine)
|
|
186
|
-
if (!
|
|
185
|
+
if (!hasTag(node, "HTML") || !this.isTopContext) {
|
|
187
186
|
if (parent === null) {
|
|
188
187
|
this.unbindNode(node);
|
|
189
188
|
return false;
|
|
@@ -210,15 +209,15 @@ export default class Observer {
|
|
|
210
209
|
sibling = sibling.previousSibling;
|
|
211
210
|
}
|
|
212
211
|
if (sibling === null) {
|
|
213
|
-
this.indexes[id] = 0;
|
|
212
|
+
this.indexes[id] = 0;
|
|
214
213
|
}
|
|
215
|
-
const isNew = this.
|
|
214
|
+
const isNew = this.newSet.has(id);
|
|
216
215
|
const index = this.indexes[id];
|
|
217
216
|
if (index === undefined) {
|
|
218
217
|
throw 'commitNode: missing node index';
|
|
219
218
|
}
|
|
220
219
|
if (isNew === true) {
|
|
221
|
-
if (
|
|
220
|
+
if (isElementNode(node)) {
|
|
222
221
|
if (parentID !== undefined) {
|
|
223
222
|
this.app.send(new CreateElementNode(id, parentID, index, node.tagName, isSVGElement(node)));
|
|
224
223
|
}
|
|
@@ -227,7 +226,7 @@ export default class Observer {
|
|
|
227
226
|
this.sendNodeAttribute(id, node, attr.nodeName, attr.value);
|
|
228
227
|
}
|
|
229
228
|
}
|
|
230
|
-
else if (
|
|
229
|
+
else if (isTextNode(node)) {
|
|
231
230
|
// for text node id != 0, hence parentID !== undefined and parent is Element
|
|
232
231
|
this.app.send(new CreateTextNode(id, parentID, index));
|
|
233
232
|
this.sendNodeData(id, parent, node.data);
|
|
@@ -235,11 +234,12 @@ export default class Observer {
|
|
|
235
234
|
return true;
|
|
236
235
|
}
|
|
237
236
|
if (isNew === false && parentID !== undefined) {
|
|
237
|
+
// does this happen a lot?
|
|
238
238
|
this.app.send(new MoveNode(id, parentID, index));
|
|
239
239
|
}
|
|
240
240
|
const attr = this.attributesList[id];
|
|
241
241
|
if (attr !== undefined) {
|
|
242
|
-
if (!
|
|
242
|
+
if (!isElementNode(node)) {
|
|
243
243
|
throw 'commitNode: node is not an element';
|
|
244
244
|
}
|
|
245
245
|
for (const name of attr) {
|
|
@@ -247,7 +247,7 @@ export default class Observer {
|
|
|
247
247
|
}
|
|
248
248
|
}
|
|
249
249
|
if (this.textSet.has(id)) {
|
|
250
|
-
if (!
|
|
250
|
+
if (!isTextNode(node)) {
|
|
251
251
|
throw 'commitNode: node is not a text';
|
|
252
252
|
}
|
|
253
253
|
// for text node id != 0, hence parent is Element
|
|
@@ -268,19 +268,12 @@ export default class Observer {
|
|
|
268
268
|
}
|
|
269
269
|
commitNodes() {
|
|
270
270
|
let node;
|
|
271
|
-
|
|
272
|
-
// TODO: make things/logic nice here.
|
|
273
|
-
// commit required in any case if recents[id] true or false (in case of unbinding) or undefined (in case of attr change).
|
|
274
|
-
// Possible solution: separate new node commit (recents) and new attribute/move node commit
|
|
275
|
-
// Otherwise commitNode is called on each node, which might be a lot
|
|
276
|
-
if (!this.myNodes[id]) {
|
|
277
|
-
continue;
|
|
278
|
-
}
|
|
271
|
+
this.affectedSet.forEach(id => {
|
|
279
272
|
this.commitNode(id);
|
|
280
|
-
if (this.
|
|
273
|
+
if (this.newSet.has(id) && (node = this.app.nodes.getNode(id))) {
|
|
281
274
|
this.app.nodes.callNodeCallbacks(node);
|
|
282
275
|
}
|
|
283
|
-
}
|
|
276
|
+
});
|
|
284
277
|
this.clear();
|
|
285
278
|
}
|
|
286
279
|
// ISSSUE
|
|
@@ -300,6 +293,5 @@ export default class Observer {
|
|
|
300
293
|
disconnect() {
|
|
301
294
|
this.observer.disconnect();
|
|
302
295
|
this.clear();
|
|
303
|
-
this.myNodes.length = 0;
|
|
304
296
|
}
|
|
305
297
|
}
|