-
Notifications
You must be signed in to change notification settings - Fork 216
Replaced mutation observer with root element zone changes #184
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,30 +24,54 @@ | |
* Supports up to 2.0.0-beta-1 | ||
*/ | ||
|
||
declare var ng: { probe: Function }; | ||
declare var ng: { probe: Function, coreTokens: any }; | ||
declare var getAllAngularRootElements: Function; | ||
|
||
import { TreeNode, BaseAdapter } from './base'; | ||
import { DirectiveProvider } from 'angular2/src/core/linker/element'; | ||
import { Description } from '../utils/description'; | ||
|
||
import {DirectiveResolver} from '../directive-resolver'; | ||
import * as Rx from 'rxjs'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would import only what is needed from rxjs here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. using it in creating debounce observable and subject There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can import There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. will do in another PR There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
|
||
export class Angular2Adapter extends BaseAdapter { | ||
_observer: MutationObserver; | ||
|
||
_tree: any = {}; | ||
_onEventDone: any; | ||
|
||
constructor() { | ||
super(); | ||
this._onEventDone = new Rx.Subject(); | ||
|
||
this._onEventDone | ||
.debounce((x) => Rx.Observable.timer(250)) | ||
.subscribe(this.renderTree.bind(this)); | ||
} | ||
|
||
renderTree() { | ||
this.reset(); | ||
const root = this._findRoot(); | ||
this._tree = {}; | ||
this._traverseElements(ng.probe(root), | ||
true, | ||
'0', | ||
this._emitNativeElement); | ||
} | ||
|
||
setup(): void { | ||
// only supports applications with single root for now | ||
const root = this._findRoot(); | ||
|
||
this._tree = {}; | ||
this._traverseElements(ng.probe(root), | ||
true, | ||
'0', | ||
this._emitNativeElement); | ||
|
||
this._trackChanges(root); | ||
this._trackAngularChanges(ng.probe(root)); | ||
} | ||
|
||
_trackAngularChanges(rootNgProbe: any) { | ||
const ngZone = rootNgProbe.inject(ng.coreTokens.NgZone); | ||
ngZone.onEventDone.subscribe(this._onEventDone.next); | ||
} | ||
|
||
_traverseElements(compEl: any, isRoot: boolean, idx: string, cb: Function) { | ||
|
@@ -109,11 +133,6 @@ export class Angular2Adapter extends BaseAdapter { | |
}; | ||
} | ||
|
||
cleanup(): void { | ||
this._removeAllListeners(); | ||
this.unsubscribe(); | ||
} | ||
|
||
_findRoot(): Element { | ||
const ngRootEl = getAllAngularRootElements()[0]; | ||
|
||
|
@@ -147,32 +166,6 @@ export class Angular2Adapter extends BaseAdapter { | |
this.addChild(compEl); | ||
}; | ||
|
||
_trackChanges(el: Element): void { | ||
this._observer = new MutationObserver(this._handleChanges); | ||
|
||
this._observer.observe(el, { | ||
attributes: true, | ||
childList: true, | ||
characterData: true, | ||
subtree: true | ||
}); | ||
} | ||
|
||
_handleChanges = (mutations: MutationRecord[]): void => { | ||
this.reset(); | ||
|
||
// Our handling of the change events will, in turn, cause DOM mutations | ||
// (e.g setting) | ||
this._observer.disconnect(); | ||
|
||
const root = this._findRoot(); | ||
this._tree = {}; | ||
this._traverseElements(ng.probe(root), | ||
true, | ||
'0', | ||
this._emitNativeElement); | ||
this._trackChanges(root); | ||
}; | ||
|
||
_getComponentChildren(compEl: any): any[] { | ||
return <any[]>compEl.componentViewChildren; | ||
|
@@ -186,10 +179,6 @@ export class Angular2Adapter extends BaseAdapter { | |
return compEl.nativeElement; | ||
} | ||
|
||
_removeAllListeners(): void { | ||
this._observer.disconnect(); | ||
} | ||
|
||
_selectorMatches(el: Element, selector: string): boolean { | ||
function genericMatch(s: string): boolean { | ||
return [].indexOf.call(document.querySelectorAll(s), this) !== -1; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,7 @@ import {Angular2Adapter} from './adapters/angular2'; | |
import Highlighter from './utils/highlighter'; | ||
import ParseData from '../frontend/utils/parse-data'; | ||
|
||
declare var ng: { probe: Function }; | ||
declare var ng: { probe: Function, coreTokens: any }; | ||
|
||
let channel = { | ||
sendMessage: (message) => { | ||
|
@@ -30,13 +30,6 @@ window.addEventListener('message', function(event) { | |
|
||
if (event.data.message.message.actionType === | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the message.message is not a part of this PR, but this is a leftover from the days when I used to contribute to this :), we should unnest this sometime in the future. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. will do in this issue #142 |
||
'START_COMPONENT_TREE_INSPECTION') { | ||
|
||
adapter._observer.disconnect(); | ||
adapter.cleanup(); | ||
|
||
adapter = new Angular2Adapter(); | ||
dom = new DomController(adapter, channel); | ||
dom.hookIntoBackend(); | ||
adapter.setup(); | ||
} else if (event.data.message.message.actionType === 'HIGHLIGHT_NODE') { | ||
const highlightStr = '[batarangle-id=\"' + | ||
|
@@ -50,12 +43,17 @@ window.addEventListener('message', function(event) { | |
const highlightStr = '[batarangle-id=\"' + | ||
event.data.message.message.node.id + '\"]'; | ||
|
||
(<HTMLElement>document.querySelector(highlightStr)).scrollIntoView(); | ||
const element: HTMLElement = | ||
<HTMLElement>document.querySelector(highlightStr); | ||
if (element) { | ||
element.scrollIntoView(); | ||
|
||
Object.defineProperty(window, '$a', { | ||
configurable: true, | ||
value: ng.probe(document.querySelector(highlightStr)) | ||
}); | ||
} | ||
|
||
Object.defineProperty(window, '$a', { | ||
configurable: true, | ||
value: ng.probe(document.querySelector(highlightStr)) | ||
}); | ||
} else if (event.data.message.message.actionType === 'UPDATE_PROPERTY') { | ||
const highlightStr = '[batarangle-id=\"' + | ||
event.data.message.message.property.id + '\"]'; | ||
|
@@ -79,7 +77,9 @@ window.addEventListener('message', function(event) { | |
|
||
dE.componentInstance[event.data.message.message.property.key] = | ||
newValue; | ||
dE.injector._depProvider.componentView.changeDetector.detectChanges(); | ||
|
||
const appRef = dE.inject(ng.coreTokens.ApplicationRef); | ||
appRef.tick(); | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,8 @@ import { AdapterEvent } from '../adapters/base'; | |
import { Angular2Adapter } from '../adapters/angular2'; | ||
import { BaseController } from './base'; | ||
|
||
import * as Rx from 'rxjs'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would import only what is needed from rxjs as opposed to the whole thing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. using it in creating debounce observable There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can import There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. will do in another PR There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
|
||
interface Sendable { | ||
sendMessage: Function; | ||
} | ||
|
@@ -27,6 +29,7 @@ export class DomController extends BaseController { | |
private adapter: any; | ||
private channel: Sendable; | ||
private model: Array<any>; | ||
private callToRenderTree: any; | ||
|
||
static detectFramework(): Angular2Adapter { | ||
return new Angular2Adapter; | ||
|
@@ -41,6 +44,15 @@ export class DomController extends BaseController { | |
this.model = []; | ||
this.adapter = adapter; | ||
this.channel = channel; | ||
|
||
this.callToRenderTree = new Rx.Subject(); | ||
this.callToRenderTree | ||
.debounce(() => Rx.Observable.timer(250)) | ||
.subscribe(this.callFrontend.bind(this)); | ||
} | ||
|
||
callFrontend(data) { | ||
data.channel.sendMessage(data.message); | ||
} | ||
|
||
hookIntoBackend(): void { | ||
|
@@ -69,7 +81,10 @@ export class DomController extends BaseController { | |
} | ||
|
||
if (ch) { | ||
ch.sendMessage({ type: 'model_change', payload: this.model}); | ||
this.callToRenderTree.next({ | ||
channel: ch, | ||
message: { type: 'model_change', payload: this.model } | ||
}); | ||
} | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am wondering if the typings for those are defined somewhere within angular's generated *.d.ts files? This way we could get rid of the ambient declaration here, but this is just a nice to have :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call...I need to double check but for some reason I seem to recall that it was typed but the typing weren't exported. Probably has changed since this is a public API.