Skip to content
This repository has been archived by the owner on May 25, 2021. It is now read-only.

Replaced mutation observer with root element zone changes #184

Merged
merged 4 commits into from
Mar 11, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 29 additions & 40 deletions src/backend/adapters/angular2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,30 +24,54 @@
* Supports up to 2.0.0-beta-1
*/

declare var ng: { probe: Function };
declare var ng: { probe: Function, coreTokens: any };
Copy link

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 :)

Copy link
Contributor

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.

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';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would import only what is needed from rxjs here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using it in creating debounce observable and subject

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can import debounce operators on its own as well.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will do in another PR

Copy link

Choose a reason for hiding this comment

The 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) {
Expand Down Expand Up @@ -109,11 +133,6 @@ export class Angular2Adapter extends BaseAdapter {
};
}

cleanup(): void {
this._removeAllListeners();
this.unsubscribe();
}

_findRoot(): Element {
const ngRootEl = getAllAngularRootElements()[0];

Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
1 change: 0 additions & 1 deletion src/backend/adapters/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,5 +117,4 @@ export abstract class BaseAdapter {

abstract serializeComponent(el: any, event: string): TreeNode;

abstract cleanup(): void;
}
28 changes: 14 additions & 14 deletions src/backend/backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand All @@ -30,13 +30,6 @@ window.addEventListener('message', function(event) {

if (event.data.message.message.actionType ===
Copy link

Choose a reason for hiding this comment

The 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.

Copy link
Member Author

Choose a reason for hiding this comment

The 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=\"' +
Expand All @@ -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 + '\"]';
Expand All @@ -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();
}
}

Expand Down
17 changes: 16 additions & 1 deletion src/backend/controllers/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import { AdapterEvent } from '../adapters/base';
import { Angular2Adapter } from '../adapters/angular2';
import { BaseController } from './base';

import * as Rx from 'rxjs';
Copy link

Choose a reason for hiding this comment

The 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

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using it in creating debounce observable

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can import debounce operators on its own as well.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will do in another PR

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


interface Sendable {
sendMessage: Function;
}
Expand All @@ -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;
Expand All @@ -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 {
Expand Down Expand Up @@ -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 }
});
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/frontend/frontend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ class App {

// Listen for changes in selected node
this.componentDataStore.dataStream
.debounce((x) => {
return Rx.Observable.timer(500);
})
// .debounce((x) => {
// return Rx.Observable.timer(500);
// })
.filter((data: any) => data.action &&
data.action === UserActionType.START_COMPONENT_TREE_INSPECTION)
.subscribe(data => {
Expand Down