Compact style mutation (#464)
* Don't store the full style attribute change, as small mutations to single style properties result in storage of a rewrite for the full style attribute, which may be very large. Had an example of a website using http://schillmania.com/projects/snowstorm/ where many direct style changes were happening every second across many 'snowflake' elements, with each attribute change looking like: "style":"color: rgb(255, 255, 255); position: absolute; width: 8px; height: 8px; font-family: arial, verdana; overflow: hidden; font-weight: normal; z-index: 0; display: block; bottom: auto; opacity: 1; padding: 0px; margin: 0px; font-size: 10px; line-height: 10px; text-align: center; vertical-align: baseline; left: 242.807px; top: 85.7332px;" even though maybe just the left/top position had been changed * More compact storage for the much more common attribute value without an `!important` flag - saves 6 chars per style attr in the json :) * Fix bug: attributes weren't getting removed after changes to treatment of 'style' attributes
This commit is contained in:
@@ -449,6 +449,7 @@ export default class MutationBuffer {
|
||||
break;
|
||||
}
|
||||
case 'attributes': {
|
||||
const target = (m.target as HTMLElement);
|
||||
let value = (m.target as HTMLElement).getAttribute(m.attributeName!);
|
||||
if (m.attributeName === 'value') {
|
||||
value = maskInputValue({
|
||||
@@ -472,13 +473,42 @@ export default class MutationBuffer {
|
||||
};
|
||||
this.attributes.push(item);
|
||||
}
|
||||
// overwrite attribute if the mutations was triggered in same time
|
||||
item.attributes[m.attributeName!] = transformAttribute(
|
||||
this.doc,
|
||||
(m.target as HTMLElement).tagName,
|
||||
m.attributeName!,
|
||||
value!,
|
||||
);
|
||||
if (m.attributeName === 'style') {
|
||||
const old = this.doc.createElement('span');
|
||||
old.setAttribute('style', m.oldValue);
|
||||
if (item.attributes['style'] === undefined) {
|
||||
item.attributes['style'] = {};
|
||||
}
|
||||
for (let i=0; i<target.style.length; i++) {
|
||||
let pname = target.style[i];
|
||||
const newValue = target.style.getPropertyValue(pname);
|
||||
const newPriority = target.style.getPropertyPriority(pname);
|
||||
if (newValue != old.style.getPropertyValue(pname) ||
|
||||
newPriority != old.style.getPropertyPriority(pname)) {
|
||||
if (newPriority == '') {
|
||||
item.attributes['style'][pname] = newValue;
|
||||
} else {
|
||||
item.attributes['style'][pname] = [newValue, newPriority];
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let i=0; i<old.style.length; i++) {
|
||||
let pname = old.style[i];
|
||||
if (target.style.getPropertyValue(pname) === '' ||
|
||||
!target.style.getPropertyValue(pname) // covering potential non-standard browsers
|
||||
) {
|
||||
item.attributes['style'][pname] = false; // delete
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// overwrite attribute if the mutations was triggered in same time
|
||||
item.attributes[m.attributeName!] = transformAttribute(
|
||||
this.doc,
|
||||
(m.target as HTMLElement).tagName,
|
||||
m.attributeName!,
|
||||
value!,
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'childList': {
|
||||
|
||||
@@ -1310,18 +1310,28 @@ export class Replayer {
|
||||
for (const attributeName in mutation.attributes) {
|
||||
if (typeof attributeName === 'string') {
|
||||
const value = mutation.attributes[attributeName];
|
||||
try {
|
||||
if (value !== null) {
|
||||
if (value === null) {
|
||||
((target as Node) as Element).removeAttribute(attributeName);
|
||||
} else if (typeof value === 'string') {
|
||||
try {
|
||||
((target as Node) as Element).setAttribute(attributeName, value);
|
||||
} else {
|
||||
((target as Node) as Element).removeAttribute(attributeName);
|
||||
} catch (error) {
|
||||
if (this.config.showWarning) {
|
||||
console.warn(
|
||||
'An error occurred may due to the checkout feature.',
|
||||
error,
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
if (this.config.showWarning) {
|
||||
console.warn(
|
||||
'An error occurred may due to the checkout feature.',
|
||||
error,
|
||||
);
|
||||
} else if (attributeName === 'style') {
|
||||
for (var s in value) {
|
||||
if (value[s] === false) {
|
||||
((target as Node) as Element).style.removeProperty(s);
|
||||
} else if (Array.isArray(value[s])) {
|
||||
((target as Node) as Element).style.setProperty(s, value[s][0], value[s][1]);
|
||||
} else {
|
||||
((target as Node) as Element).style.setProperty(s, value[s]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,16 +294,20 @@ export type textMutation = {
|
||||
value: string | null;
|
||||
};
|
||||
|
||||
export type styleAttributeValue = {
|
||||
[key:string]: [string, string] | string | false;
|
||||
};
|
||||
|
||||
export type attributeCursor = {
|
||||
node: Node;
|
||||
attributes: {
|
||||
[key: string]: string | null;
|
||||
[key: string]: string | styleAttributeValue | null;
|
||||
};
|
||||
};
|
||||
export type attributeMutation = {
|
||||
id: number;
|
||||
attributes: {
|
||||
[key: string]: string | null;
|
||||
[key: string]: string | styleAttributeValue | null;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user