196 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			196 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
import {isBlank, isPresent, BaseException} from 'angular2/src/facade/lang';
 | 
						|
import {MapWrapper, ListWrapper, List, Map} from 'angular2/src/facade/collection';
 | 
						|
import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
 | 
						|
import {DOM} from 'angular2/src/dom/dom_adapter';
 | 
						|
 | 
						|
import {Parser, Lexer} from 'angular2/change_detection';
 | 
						|
import {DirectDomRenderer} from 'angular2/src/render/dom/direct_dom_renderer';
 | 
						|
import {DefaultDomCompiler} from 'angular2/src/render/dom/compiler/compiler';
 | 
						|
import {RenderProtoViewRef, ProtoViewDto, ViewDefinition, RenderViewContainerRef, EventDispatcher, DirectiveMetadata} from 'angular2/src/render/api';
 | 
						|
import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader';
 | 
						|
import {UrlResolver} from 'angular2/src/services/url_resolver';
 | 
						|
import {EmulatedUnscopedShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/emulated_unscoped_shadow_dom_strategy';
 | 
						|
import {EventManager, EventManagerPlugin} from 'angular2/src/render/dom/events/event_manager';
 | 
						|
import {VmTurnZone} from 'angular2/src/core/zone/vm_turn_zone';
 | 
						|
import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver';
 | 
						|
import {ViewFactory} from 'angular2/src/render/dom/view/view_factory';
 | 
						|
import {RenderViewHydrator} from 'angular2/src/render/dom/view/view_hydrator';
 | 
						|
 | 
						|
export class IntegrationTestbed {
 | 
						|
  renderer;
 | 
						|
  renderCompiler;
 | 
						|
  parser;
 | 
						|
  eventPlugin;
 | 
						|
  _templates:Map<string, ViewDefinition>;
 | 
						|
 | 
						|
  constructor({urlData, viewCacheCapacity, shadowDomStrategy, templates}) {
 | 
						|
    this._templates = MapWrapper.create();
 | 
						|
    if (isPresent(templates)) {
 | 
						|
      ListWrapper.forEach(templates, (template) => {
 | 
						|
        MapWrapper.set(this._templates, template.componentId, template);
 | 
						|
      });
 | 
						|
    }
 | 
						|
    var parser = new Parser(new Lexer());
 | 
						|
    var urlResolver = new UrlResolver();
 | 
						|
    if (isBlank(shadowDomStrategy)) {
 | 
						|
      shadowDomStrategy = new EmulatedUnscopedShadowDomStrategy(new StyleUrlResolver(urlResolver), null);
 | 
						|
    }
 | 
						|
    this.renderCompiler = new DefaultDomCompiler(parser, shadowDomStrategy, new FakeTemplateLoader(urlResolver, urlData));
 | 
						|
 | 
						|
    if (isBlank(viewCacheCapacity)) {
 | 
						|
      viewCacheCapacity = 0;
 | 
						|
    }
 | 
						|
    if (isBlank(urlData)) {
 | 
						|
      urlData = MapWrapper.create();
 | 
						|
    }
 | 
						|
    this.eventPlugin = new FakeEventManagerPlugin();
 | 
						|
    var eventManager = new EventManager([this.eventPlugin], new FakeVmTurnZone());
 | 
						|
    var viewFactory = new ViewFactory(viewCacheCapacity, eventManager, shadowDomStrategy);
 | 
						|
    var viewHydrator = new RenderViewHydrator(eventManager, viewFactory, shadowDomStrategy);
 | 
						|
    this.renderer = new DirectDomRenderer(viewFactory, viewHydrator, shadowDomStrategy);
 | 
						|
  }
 | 
						|
 | 
						|
  compileRoot(componentMetadata):Promise<ProtoViewDto> {
 | 
						|
    return this.renderCompiler.compileHost(componentMetadata).then( (rootProtoView) => {
 | 
						|
      return this._compileNestedProtoViews(rootProtoView, [componentMetadata]);
 | 
						|
    });
 | 
						|
  }
 | 
						|
 | 
						|
  compile(componentId):Promise<ProtoViewDto> {
 | 
						|
    var childTemplate = MapWrapper.get(this._templates, componentId);
 | 
						|
    if (isBlank(childTemplate)) {
 | 
						|
      throw new BaseException(`No template for component ${componentId}`);
 | 
						|
    }
 | 
						|
    return this.renderCompiler.compile(childTemplate).then( (protoView) => {
 | 
						|
      return this._compileNestedProtoViews(protoView, childTemplate.directives);
 | 
						|
    });
 | 
						|
  }
 | 
						|
 | 
						|
  _compileNestedProtoViews(protoView, directives):Promise<ProtoViewDto> {
 | 
						|
    var childComponentRenderPvRefs = [];
 | 
						|
    var nestedPVPromises = [];
 | 
						|
    ListWrapper.forEach(protoView.elementBinders, (elementBinder) => {
 | 
						|
      var nestedComponentId = null;
 | 
						|
      ListWrapper.forEach(elementBinder.directives, (db) => {
 | 
						|
        var directiveMeta = directives[db.directiveIndex];
 | 
						|
        if (directiveMeta.type === DirectiveMetadata.COMPONENT_TYPE) {
 | 
						|
          nestedComponentId = directiveMeta.id;
 | 
						|
        }
 | 
						|
      });
 | 
						|
      var nestedCall;
 | 
						|
      if (isPresent(nestedComponentId)) {
 | 
						|
        var childTemplate = MapWrapper.get(this._templates, nestedComponentId);
 | 
						|
        if (isBlank(childTemplate)) {
 | 
						|
          // dynamic component
 | 
						|
          ListWrapper.push(childComponentRenderPvRefs, null);
 | 
						|
        } else {
 | 
						|
          nestedCall = this.compile(nestedComponentId);
 | 
						|
        }
 | 
						|
      } else if (isPresent(elementBinder.nestedProtoView)) {
 | 
						|
        nestedCall = this._compileNestedProtoViews(elementBinder.nestedProtoView, directives);
 | 
						|
      }
 | 
						|
      if (isPresent(nestedCall)) {
 | 
						|
        ListWrapper.push(
 | 
						|
          nestedPVPromises,
 | 
						|
          nestedCall.then( (nestedPv) => {
 | 
						|
            elementBinder.nestedProtoView = nestedPv;
 | 
						|
            if (isPresent(nestedComponentId)) {
 | 
						|
              ListWrapper.push(childComponentRenderPvRefs, nestedPv.render);
 | 
						|
            }
 | 
						|
          })
 | 
						|
        );
 | 
						|
      }
 | 
						|
    });
 | 
						|
    if (nestedPVPromises.length > 0) {
 | 
						|
      return PromiseWrapper.all(nestedPVPromises).then((_) => {
 | 
						|
        this.renderCompiler.mergeChildComponentProtoViews(protoView.render, childComponentRenderPvRefs);
 | 
						|
        return protoView;
 | 
						|
      });
 | 
						|
    } else {
 | 
						|
      return PromiseWrapper.resolve(protoView);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
class FakeTemplateLoader extends TemplateLoader {
 | 
						|
  _urlData: Map<string, string>;
 | 
						|
 | 
						|
  constructor(urlResolver, urlData) {
 | 
						|
    super(null, urlResolver);
 | 
						|
    this._urlData = urlData;
 | 
						|
  }
 | 
						|
 | 
						|
  load(template: ViewDefinition) {
 | 
						|
    if (isPresent(template.template)) {
 | 
						|
      return PromiseWrapper.resolve(DOM.createTemplate(template.template));
 | 
						|
    }
 | 
						|
 | 
						|
    if (isPresent(template.absUrl)) {
 | 
						|
      var content = this._urlData[template.absUrl];
 | 
						|
      if (isPresent(content)) {
 | 
						|
        return PromiseWrapper.resolve(DOM.createTemplate(content));
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    return PromiseWrapper.reject('Load failed');
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
export class FakeVmTurnZone extends VmTurnZone {
 | 
						|
  constructor() {
 | 
						|
    super({enableLongStackTrace: false});
 | 
						|
  }
 | 
						|
 | 
						|
  run(fn) {
 | 
						|
    fn();
 | 
						|
  }
 | 
						|
 | 
						|
  runOutsideAngular(fn) {
 | 
						|
    fn();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
export class FakeEventManagerPlugin extends EventManagerPlugin {
 | 
						|
  _eventHandlers: Map;
 | 
						|
 | 
						|
  constructor() {
 | 
						|
    super();
 | 
						|
    this._eventHandlers = MapWrapper.create();
 | 
						|
  }
 | 
						|
 | 
						|
  dispatchEvent(eventName, event) {
 | 
						|
    MapWrapper.get(this._eventHandlers, eventName)(event);
 | 
						|
  }
 | 
						|
 | 
						|
  supports(eventName: string): boolean {
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  addEventListener(element, eventName: string, handler: Function, shouldSupportBubble: boolean) {
 | 
						|
    MapWrapper.set(this._eventHandlers, eventName, handler);
 | 
						|
    return () => {MapWrapper.delete(this._eventHandlers, eventName);}
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
export class LoggingEventDispatcher extends EventDispatcher {
 | 
						|
  log:List;
 | 
						|
  constructor() {
 | 
						|
    super();
 | 
						|
    this.log = [];
 | 
						|
  }
 | 
						|
  dispatchEvent(
 | 
						|
    elementIndex:number, eventName:string, locals:Map<string, any>
 | 
						|
  ) {
 | 
						|
    ListWrapper.push(this.log, [elementIndex, eventName, locals]);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
export class FakeEvent {
 | 
						|
  target;
 | 
						|
  constructor(target) {
 | 
						|
    this.target = target;
 | 
						|
  }
 | 
						|
}
 |