function createDOMNodeRestorable() {
    const restorable = createObjectRestorable();
    return {
        ...restorable,
        // Track method calls
        invoke (targetNode, fnName, targetfn, args) {
            switch (fnName) {
                // For setAttribute() the undo is to reset attribute to original state
                case 'setAttribute': {
                    const [ name ] = args;
                    const key = `attr:${name}`;
                    restorable.once(key, () => {
                        const oldVal = targetNode.getAttribute(name);
                        return targetNode.hasAttribute(name)
                            ? restorable.pushUndo(() => targetNode.setAttribute(name, oldVal))
                            : restorable.pushUndo(() => targetNode.removeAttribute(name));
                    });
                    break;
                }
                // For setAttributeNS() the undo is to reset attribute to original state
                case 'setAttributeNS': {
                    const [ namespace, name ] = args;
                    const key = `attr:${namespace}:${name}`;
                    restorable.once(key, () => {
                        const oldVal = targetNode.getAttributeNS(namespace, name);
                        return targetNode.hasAttributeNS(namespace, name)
                            ? restorable.pushUndo(() => targetNode.setAttributeNS(namespace, name, oldVal))
                            : restorable.pushUndo(() => targetNode.removeAttributeNS(namespace, name));
                    });
                    break;
                }
                // For removeAttribute() the undo is to add attribute back
                case 'removeAttribute': {
                    const [ name ] = args;
                    const key = `attr:${name}`;
                    restorable.once(key, () => {
                        const oldVal = targetNode.getAttribute(name);
                        restorable.pushUndo(() => targetNode.setAttribute(name, oldVal));
                    });
                    break;
                }
                // For removeAttributeNS() the undo is to add attribute back
                case 'removeAttributeNS': {
                    const [ namespace, name ] = args;
                    const key = `attr:${namespace}:${name}`;
                    restorable.once(key, () => {
                        const oldVal = targetNode.getAttributeNS(namespace, name);
                        restorable.pushUndo(() => targetNode.setAttributeNS(namespace, name, oldVal));
                    });
                    break;
                }
                // For addEventListener the undo is to remove the event listener
                case 'addEventListener': {
                    const sameArgs = args.slice(0, 3);
                    restorable.pushUndo(() => targetNode.removeEventListener(...sameArgs));
                    break;
                }
                // For attachEvent the undo is to remove the event listener
                case 'attachEvent': {
                    const sameArgs = args.slice(0, 2);
                    restorable.pushUndo(() => targetNode.detachEvent(...sameArgs));
                    break;
                }
                default: {
                    // Debug logging for operations we might be missing
                    if (!fnName.startsWith('get') &&
                        !fnName.startsWith('has') &&
                        !fnName.startsWith('query')) {
                        debug.log(`WARNING: cannot undo operation: <${targetNode.tagName}/>.${fnName}()`);
                    }
                }
            }
            // Perform actual method invocation
            return targetfn.apply(targetNode, args);
        },
    };
}
/**
 * Creates a Restorable which can track DOM Node property assignments and modifying method invocations.
 * Tracks methods that it knows how to undo (e.g. setAttribute, addEventListener).
 * 
 * @returns {DOMNodeRestorable}
 */
Creates a Restorable which can track DOM Node property assignments and modifying method invocations.
Tracks methods that it knows how to undo .


Creates a Restorable which can track DOM Node property assignments and modifying method invocations . Tracks methods that it knows how to undo .
function createDOMNodeRestorable() {
    const restorable = createObjectRestorable();
    return {
        ...restorable,
        invoke (targetNode, fnName, targetfn, args) {
            switch (fnName) {
                case 'setAttribute': {
                    const [ name ] = args;
                    const key = `attr:${name}`;
                    restorable.once(key, () => {
                        const oldVal = targetNode.getAttribute(name);
                        return targetNode.hasAttribute(name)
                            ? restorable.pushUndo(() => targetNode.setAttribute(name, oldVal))
                            : restorable.pushUndo(() => targetNode.removeAttribute(name));
                    });
                    break;
                }
                case 'setAttributeNS': {
                    const [ namespace, name ] = args;
                    const key = `attr:${namespace}:${name}`;
                    restorable.once(key, () => {
                        const oldVal = targetNode.getAttributeNS(namespace, name);
                        return targetNode.hasAttributeNS(namespace, name)
                            ? restorable.pushUndo(() => targetNode.setAttributeNS(namespace, name, oldVal))
                            : restorable.pushUndo(() => targetNode.removeAttributeNS(namespace, name));
                    });
                    break;
                }
                case 'removeAttribute': {
                    const [ name ] = args;
                    const key = `attr:${name}`;
                    restorable.once(key, () => {
                        const oldVal = targetNode.getAttribute(name);
                        restorable.pushUndo(() => targetNode.setAttribute(name, oldVal));
                    });
                    break;
                }
                case 'removeAttributeNS': {
                    const [ namespace, name ] = args;
                    const key = `attr:${namespace}:${name}`;
                    restorable.once(key, () => {
                        const oldVal = targetNode.getAttributeNS(namespace, name);
                        restorable.pushUndo(() => targetNode.setAttributeNS(namespace, name, oldVal));
                    });
                    break;
                }
                case 'addEventListener': {
                    const sameArgs = args.slice(0, 3);
                    restorable.pushUndo(() => targetNode.removeEventListener(...sameArgs));
                    break;
                }
                case 'attachEvent': {
                    const sameArgs = args.slice(0, 2);
                    restorable.pushUndo(() => targetNode.detachEvent(...sameArgs));
                    break;
                }
                default: {
                    if (!fnName.startsWith('get') &&
                        !fnName.startsWith('has') &&
                        !fnName.startsWith('query')) {
                        debug.log(`WARNING: cannot undo operation: <${targetNode.tagName}/>.${fnName}()`);
                    }
                }
            }
            return targetfn.apply(targetNode, args);
        },
    };
}
function createDOMNodeRestorable ( ) { const restorable = createObjectRestorable ( ) ; return { ... restorable , invoke ( targetNode , fnName , targetfn , args ) { switch ( fnName ) { case 'setAttribute' : { const [ name ] = args ; const key = ` ${ name } ` ; restorable . once ( key , ( ) => { const oldVal = targetNode . getAttribute ( name ) ; return targetNode . hasAttribute ( name ) ? restorable . pushUndo ( ( ) => targetNode . setAttribute ( name , oldVal ) ) : restorable . pushUndo ( ( ) => targetNode . removeAttribute ( name ) ) ; } ) ; break ; } case 'setAttributeNS' : { const [ namespace , name ] = args ; const key = ` ${ namespace } ${ name } ` ; restorable . once ( key , ( ) => { const oldVal = targetNode . getAttributeNS ( namespace , name ) ; return targetNode . hasAttributeNS ( namespace , name ) ? restorable . pushUndo ( ( ) => targetNode . setAttributeNS ( namespace , name , oldVal ) ) : restorable . pushUndo ( ( ) => targetNode . removeAttributeNS ( namespace , name ) ) ; } ) ; break ; } case 'removeAttribute' : { const [ name ] = args ; const key = ` ${ name } ` ; restorable . once ( key , ( ) => { const oldVal = targetNode . getAttribute ( name ) ; restorable . pushUndo ( ( ) => targetNode . setAttribute ( name , oldVal ) ) ; } ) ; break ; } case 'removeAttributeNS' : { const [ namespace , name ] = args ; const key = ` ${ namespace } ${ name } ` ; restorable . once ( key , ( ) => { const oldVal = targetNode . getAttributeNS ( namespace , name ) ; restorable . pushUndo ( ( ) => targetNode . setAttributeNS ( namespace , name , oldVal ) ) ; } ) ; break ; } case 'addEventListener' : { const sameArgs = args . slice ( 0 , 3 ) ; restorable . pushUndo ( ( ) => targetNode . removeEventListener ( ... sameArgs ) ) ; break ; } case 'attachEvent' : { const sameArgs = args . slice ( 0 , 2 ) ; restorable . pushUndo ( ( ) => targetNode . detachEvent ( ... sameArgs ) ) ; break ; } default : { if ( ! fnName . startsWith ( 'get' ) && ! fnName . startsWith ( 'has' ) && ! fnName . startsWith ( 'query' ) ) { debug . log ( ` ${ targetNode . tagName } ${ fnName } ` ) ; } } } return targetfn . apply ( targetNode , args ) ; } , } ; }
Creates a Restorable which can track DOM Node property assignments and modifying method invocations.
Creates a Restorable which can track DOM Node property assignments and modifying method invocations .
// Track method calls // For setAttribute() the undo is to reset attribute to original state // For setAttributeNS() the undo is to reset attribute to original state // For removeAttribute() the undo is to add attribute back // For removeAttributeNS() the undo is to add attribute back // For addEventListener the undo is to remove the event listener // For attachEvent the undo is to remove the event listener // Debug logging for operations we might be missing // Perform actual method invocation