Code Monkey home page Code Monkey logo

dom-interceptor's Introduction

dom interceptor Build Status Code Climate

See the NPM module.

## Background

This library is designed for use with AngularHintDom, a runtime hinting tool that depends on detecting manipulation of the DOM in AngularJS applications to warn developers about best practices. The goal of this library is to explore different ways of 'intercepting' or patching DOM APIs in order to provide this hinting.

To provide this service, the library creates a main manipulationListener that is used by AngularHintDom. This listener is the interceptor that listens for use of certain DOM APIs.

Previously this library contained other methods for patching individual element properties and using proxies that are not used by the current manipulationListener. These methods were developed as part of an exploration of how to effectively listen for DOM manipulation.

Especially, the library aims to detect the use of methods such as:

  • retrieval methods such as document.getElementById()
  • element.remove
  • element.insertBefore
  • element.appendChild

Originally, other manipulative methods like element.innerHTML and element.parentElement were also identified as goal methods for the overall manipulationListener to detect. However, detecting these DOM APIs in certain browsers requires patching of individual elements (Firefox attaches properties like .innerHTML to Element.prototype so patching get/set properties of the prototypes would be sufficient in that browser). In an earlier iteration, methods patchExistingElements() and patchElementProperties() were implemented to fill this need. However, for the best effort goal of detecting DOM manipulation, patching individual elements was deemed too heavy-handed, dangerous, and costly in terms of performance. For example, some browsers such as Safari do not allow the patching of element properties. Moreover, these patched elements do not have the same behavior as unpatched elements.

A better solution than patchExistingElements() or patchElementProperties() for providing this interception on the level of individual elements is to use proxies. In one iteration, the method patchAccess() used the harmony-reflect library to provide this service.

However, proxies are still considered experimental javascript. In Chrome for instance this javascript feature can only be enabled by setting the flag chrome://flags/#enable-javascript-harmony. Hence, these features are not used be the current manipulationListener. Instead, the manipulationListener provides a 'best-effort' detection of the majority of DOM API calls by patching functions on the prototypes of Element, Node, and Document.

## API

#####Use as: addManipulationListener(newListener)

Add a listener - a function - that will be fired when use of DOM APIs is detected.

####Example

var domInterceptor = require('dom-interceptor');
var listenerFunction = function(message) {
  console.log(message);
};
//Will console.log the given message when manipulation is detected
domInterceptor.addManipulationListener(listenerFunction);

####Params

Param Type Description
newListener function A function that will be triggered when use of DOM APIs is detected

#####Use as: enableLineNumbers(stackTraceLocation)

Enable the listener message passed to the given listener to include the line number of the call that manipulated the DOM. A stackTraceLocation is required in order to pick a line from the stack trace that is not within the domInterceptor code.

####Example

var domInterceptor = require('dom-interceptor');
domInterceptor.enableLineNumbers(3);

####Params

Param Type Description
stackTraceLocation number The line of the stack trace that is of interest to the user

#####Use as: patchOnePrototype(type, typeName)

Patch all functions on a given type.prototype to trigger the manipulationListener when called.

####Example

var domInterceptor = require('dom-interceptor');
domInterceptor.patchOnePrototype(Document, 'Document');
//Triggers the manipulationListener
document.getElementById('foo');

####Params

Param Type Description
type function A function whose prototype should be patched.
typeName String The string name of the function whose prototype should be patched

#####Use as: removeManipulationListener()

Remove the manipulationListener.

####Example

var domInterceptor = require('dom-interceptor');
var listenerFunction = function(message) {
  console.log(message);
};
//Will console.log the given message when manipulation is detected
domInterceptor.addManipulationListener(listenerFunction);
//triggers console.log
document.getElementById('foo');

domInterceptor.removeManipulationListener();
//does not trigger console.log
document.getElementById('foo');

#####Use as: unpatchOnePrototype(type, typeName)

Unpatch all functions on a given type.prototype that had been patched to trigger the manipulationListener.

####Example

var domInterceptor = require('dom-interceptor');
domInterceptor.patchOnePrototype(Document, 'Document');
//Triggers the manipulationListener
document.getElementById('foo');
domInterceptor.unpatchOnePrototype(Document, 'Document');
//Does not trigger the manipulationListener
document.getElementById('foo');

####Params

Param Type Description
type function A function whose prototype should be unpatched.
typeName String The string name of the function whose prototype should be unpatched

License

Apache 2.0

dom-interceptor's People

Contributors

btford avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dom-interceptor's Issues

Different function uses in javascript

@btford with the way that domInterceptor object is currently set up to be tied to window.domInterceptor in order that it can be used in angularHintDom, I'm wondering if not all of the methods should be exposed on domInterceptor. Basically the only public functions needed to run the library would be addManipulationListener and removeManipulationListener. But I'm wondering if other uses of the library would motivate users to dive into using individual methods.

creating proxy elements creates a null element

In 523dfb4 I'm attempting to handle the case where the user creates a new element and starts to manipulate it. This would still presumable be covered by patching Document.prototype and logging an error whenever an element is created. But then that created element would not cause errors after that point. Is this worth pursuing? I assume that something is happening where the proxy is operating correctly for get and set but interfering with .appendChild.

Line Numbers In Error Message

Originally HintLog had a function to find the line number of where a violation of the best practice was detected. However, this behavior did not seem very applicable to other modules. Dom-interceptor/ hintDOM should add back this behavior so that error messages will be more helpful.

Best effort manipulation detection

@btford Given the current state of proxy implementation, and the errors currently received from patching individual DOM elements. I'm wondering if a best effort detection could be to just rely on the methods that can be patched via the prototypes? In order to change an element, it is fairly likely that a method like getElementById will be called in order to get the element.

Is this a high enough level of accuracy, or should we still focus on trying to improve the patching of individual elements?

Cross browser consistency

Earlier we had noted issues specifically with our interception of the DOM and Firefox (ex: #1). Often, it seemed that more calls were generated in Firefox than Chrome and Safari. When integration testing with AngularHintDom and AngularHint, it became clear that these extra detections in Firefox are because Firefox attaches more configurable get/set properties on Element.prototype. For example, in Firefox, Object.getOwnPropertyDescriptor(Element.prototype, "innerHTML") returns a configurable version of innerHTML. In Chrome and Safari this property is only configurable on individual elements: hence, our exploration of methods like patchExistingElements() in earlier iterations that were meant to patch this function on individual methods. Since this strategy of patching individual methods was abandoned as too expensive, and proxies are not supported consistently by browsers, we should not patch these properties that are available in Firefox. Although it allows a higher degree of accuracy in detecting DOM manipulation in Firefox, it means that the tool behaves differently in that browser. For consistency between Firefox and other browsers, we are removing the patching of get/set properties when patching prototypes.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.