diff --git a/apps/tests/xml-declaration/errors/non-existing-element-in-template.xml b/apps/tests/xml-declaration/errors/non-existing-element-in-template.xml
new file mode 100644
index 000000000..2b9d87ff1
--- /dev/null
+++ b/apps/tests/xml-declaration/errors/non-existing-element-in-template.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/tests/xml-declaration/xml-declaration-tests.ts b/apps/tests/xml-declaration/xml-declaration-tests.ts
index d07a4bcb2..08cb151cd 100644
--- a/apps/tests/xml-declaration/xml-declaration-tests.ts
+++ b/apps/tests/xml-declaration/xml-declaration-tests.ts
@@ -837,7 +837,7 @@ export function test_parse_template_property() {
TKUnit.assertEqual(button.text, "Click!", "Expected child Button to have text 'Click!'");
}
-export function test_ParserError() {
+export function test_NonExistingElementError() {
var basePath = "xml-declaration/";
var expectedErrorStart =
"Building UI from XML. @file:///app/" + basePath + "errors/non-existing-element.xml:11:5\n" +
@@ -856,3 +856,28 @@ export function test_ParserError() {
}
TKUnit.assertEqual(message.substr(0, expectedErrorStart.length), expectedErrorStart, "Expected load to throw, and the message to start with specific string");
}
+
+export function test_NonExistingElementInTemplateError() {
+ var basePath = "xml-declaration/";
+ var expectedErrorStart =
+ "Building UI from XML. @file:///app/" + basePath + "errors/non-existing-element-in-template.xml:14:17\n" +
+ " ↳Module 'ui/unicorn' not found for element 'Unicorn'.\n";
+ if (global.android) {
+ expectedErrorStart += " ↳Module \"ui/unicorn\" not found";
+ } else {
+ expectedErrorStart += " ↳Failed to find module 'ui/unicorn'";
+ }
+
+ var message;
+ var page = builder.load(__dirname + "/errors/non-existing-element-in-template.xml");
+ TKUnit.assert(view, "Expected the xml to generate a page");
+ var templateView = page.getViewById("template-view");
+ TKUnit.assert(templateView, "Expected the page to have a TemplateView with 'temaplte-view' id.");
+
+ try {
+ templateView.parseTemplate();
+ } catch(e) {
+ message = e.message;
+ }
+ TKUnit.assertEqual(message.substr(0, expectedErrorStart.length), expectedErrorStart, "Expected load to throw, and the message to start with specific string");
+}
\ No newline at end of file
diff --git a/tsconfig.json b/tsconfig.json
index b7aef072f..7464a795f 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -478,8 +478,6 @@
"ui/builder/component-builder.ts",
"ui/builder/special-properties.d.ts",
"ui/builder/special-properties.ts",
- "ui/builder/template-builder.d.ts",
- "ui/builder/template-builder.ts",
"ui/button/button-common.ts",
"ui/button/button.android.ts",
"ui/button/button.d.ts",
diff --git a/ui/builder/builder.ts b/ui/builder/builder.ts
index 56e18294a..3955e1b08 100644
--- a/ui/builder/builder.ts
+++ b/ui/builder/builder.ts
@@ -3,24 +3,13 @@ import fs = require("file-system");
import xml = require("xml");
import types = require("utils/types");
import componentBuilder = require("ui/builder/component-builder");
-import templateBuilderDef = require("ui/builder/template-builder");
import platform = require("platform");
import definition = require("ui/builder");
import page = require("ui/page");
import fileResolverModule = require("file-system/file-name-resolver");
import trace = require("trace");
import debug = require("utils/debug");
-
-var KNOWNCOLLECTIONS = "knownCollections";
-
-function isPlatform(value: string): boolean {
- return value && (value.toLowerCase() === platform.platformNames.android.toLowerCase()
- || value.toLowerCase() === platform.platformNames.ios.toLowerCase());
-}
-
-function isCurentPlatform(value: string): boolean {
- return value && value.toLowerCase() === platform.device.os.toLowerCase();
-}
+import builder = require("ui/builder");
export function parse(value: string | view.Template, context: any): view.View {
if (types.isString(value)) {
@@ -43,164 +32,19 @@ export function parse(value: string | view.Template, context: any): view.View {
}
function parseInternal(value: string, context: any, uri?: string): componentBuilder.ComponentModule {
- var currentPage: page.Page;
- var rootComponentModule: componentBuilder.ComponentModule;
- // Temporary collection used for parent scope.
- var parents = new Array();
- var complexProperties = new Array();
+
+ var start: xml2ui.XmlStringParser;
+ var ui: xml2ui.ComponentParser;
+
+ var errorFormat = (debug.debug && uri) ? xml2ui.SourceErrorFormat(uri) : xml2ui.PositionErrorFormat;
+
+ (start = new xml2ui.XmlStringParser(errorFormat))
+ .pipe(new xml2ui.PlatformFilter())
+ .pipe(new xml2ui.XmlStateParser(ui = new xml2ui.ComponentParser(context, errorFormat)));
- var templateBuilder: templateBuilderDef.TemplateBuilder;
+ start.parse(value);
- var currentPlatformContext: string;
-
- var wrapSource: (e: Error, p: xml.Position) => Error;
- if (debug.debug && uri) {
- wrapSource = (e: Error, p: xml.Position) => {
- var source = new debug.Source(uri, p.line, p.column);
- e = new debug.SourceError(e, source, "Building UI from XML.");
- return e;
- }
- } else {
- wrapSource = e => e; // no-op identity
- }
-
- // Parse the XML.
- var xmlParser = new xml.XmlParser((args: xml.ParserEvent) => {
- try {
- if (args.eventType === xml.ParserEventType.StartElement) {
- if (isPlatform(args.elementName)) {
-
- if (currentPlatformContext) {
- throw new Error("Already in '" + currentPlatformContext + "' platform context and cannot switch to '" + args.elementName + "' platform! Platform tags cannot be nested.");
- }
-
- currentPlatformContext = args.elementName;
- return;
- }
- }
-
- if (args.eventType === xml.ParserEventType.EndElement) {
- if (isPlatform(args.elementName)) {
- currentPlatformContext = undefined;
- return;
- }
- }
-
- if (currentPlatformContext && !isCurentPlatform(currentPlatformContext)) {
- return;
- }
-
- if (templateBuilder) {
- var finished = templateBuilder.handleElement(args);
- if (finished) {
- // Clean-up and continnue
- templateBuilder = undefined;
- }
- else {
- // Skip processing untill the template builder finishes his job.
- return;
- }
- }
-
- // Get the current parent.
- var parent = parents[parents.length - 1];
- var complexProperty = complexProperties[complexProperties.length - 1];
-
- // Create component instance from every element declaration.
- if (args.eventType === xml.ParserEventType.StartElement) {
- if (isComplexProperty(args.elementName)) {
-
- var name = getComplexProperty(args.elementName);
-
- complexProperties.push({
- parent: parent,
- name: name,
- items: [],
- });
-
- if (templateBuilderDef.isKnownTemplate(name, parent.exports)) {
- templateBuilder = new templateBuilderDef.TemplateBuilder({
- context: parent ? getExports(parent.component) : null, // Passing 'context' won't work if you set "codeFile" on the page
- parent: parent,
- name: name,
- elementName: args.elementName,
- templateItems: []
- });
- }
-
- } else {
-
- var componentModule: componentBuilder.ComponentModule;
-
- if (args.prefix && args.namespace) {
- // Custom components
- componentModule = loadCustomComponent(args.namespace, args.elementName, args.attributes, context, currentPage);
- } else {
- // Default components
- componentModule = componentBuilder.getComponentModule(args.elementName, args.namespace, args.attributes, context);
- }
-
- if (componentModule) {
- if (parent) {
- if (componentModule.component instanceof view.View) {
- if (complexProperty) {
- // Add to complex property to component.
- addToComplexProperty(parent, complexProperty, componentModule)
- } else if ((parent.component)._addChildFromBuilder) {
- // Add component to visual tree
- (parent.component)._addChildFromBuilder(args.elementName, componentModule.component);
- }
- } else if (complexProperty) {
- // Add component to complex property of parent component.
- addToComplexProperty(parent, complexProperty, componentModule);
- } else if ((parent.component)._addChildFromBuilder) {
- (parent.component)._addChildFromBuilder(args.elementName, componentModule.component);
- }
- } else if (parents.length === 0) {
- // Set root component.
- rootComponentModule = componentModule;
-
- if (rootComponentModule && rootComponentModule.component instanceof page.Page) {
- currentPage = rootComponentModule.component;
- }
- }
-
- // Add the component instance to the parents scope collection.
- parents.push(componentModule);
- }
- }
-
- } else if (args.eventType === xml.ParserEventType.EndElement) {
- if (isComplexProperty(args.elementName)) {
- if (complexProperty) {
- if (parent && (parent.component)._addArrayFromBuilder) {
- // If parent is AddArrayFromBuilder call the interface method to populate the array property.
- (parent.component)._addArrayFromBuilder(complexProperty.name, complexProperty.items);
- complexProperty.items = [];
- }
- }
- // Remove the last complexProperty from the complexProperties collection (move to the previous complexProperty scope).
- complexProperties.pop();
-
- } else {
- // Remove the last parent from the parents collection (move to the previous parent scope).
- parents.pop();
- }
- }
-
- } catch(e) {
- throw wrapSource(e, args.position);
- }
- }, (e, p) => {
- throw wrapSource(new Error("XML parse error: " + e.message), p);
- }, true);
-
- if (types.isString(value)) {
- value = value.replace(/xmlns=("|')http:\/\/((www)|(schemas))\.nativescript\.org\/tns\.xsd\1/, "");
- xmlParser.parse(value);
- }
-
- return rootComponentModule;
+ return ui.rootComponentModule;
}
function loadCustomComponent(componentPath: string, componentName?: string, attributes?: Object, context?: Object, parentPage?: page.Page): componentBuilder.ComponentModule {
@@ -297,44 +141,6 @@ function loadInternal(fileName: string, context?: any): componentBuilder.Compone
return componentModule;
}
-function isComplexProperty(name: string): boolean {
- return types.isString(name) && name.indexOf(".") !== -1;
-}
-
-function getComplexProperty(fullName: string): string {
- var name: string;
-
- if (types.isString(fullName)) {
- var names = fullName.split(".");
- name = names[names.length - 1];
- }
-
- return name;
-}
-
-function isKnownCollection(name: string, context: any): boolean {
- return KNOWNCOLLECTIONS in context && context[KNOWNCOLLECTIONS] && name in context[KNOWNCOLLECTIONS];
-}
-
-function addToComplexProperty(parent: componentBuilder.ComponentModule, complexProperty: ComplexProperty, elementModule: componentBuilder.ComponentModule) {
- // If property name is known collection we populate array with elements.
- var parentComponent = parent.component;
- if (isKnownCollection(complexProperty.name, parent.exports)) {
- complexProperty.items.push(elementModule.component);
- } else if (parentComponent._addChildFromBuilder) {
- parentComponent._addChildFromBuilder(complexProperty.name, elementModule.component);
- } else {
- // Or simply assign the value;
- parentComponent[complexProperty.name] = elementModule.component;
- }
-}
-
-interface ComplexProperty {
- parent: componentBuilder.ComponentModule;
- name: string;
- items?: Array;
-}
-
function getExports(instance: view.View): any {
var parent = instance.parent;
@@ -344,3 +150,400 @@ function getExports(instance: view.View): any {
return parent ? (parent).exports : undefined;
}
+
+namespace xml2ui {
+
+ /**
+ * Pipes and filters:
+ * https://en.wikipedia.org/wiki/Pipeline_(software)
+ */
+ interface XmlProducer {
+ pipe(next: Next): Next;
+ }
+
+ interface XmlConsumer {
+ parse(args: xml.ParserEvent);
+ }
+
+ export class XmlProducerBase implements XmlProducer {
+ private _next: XmlConsumer;
+ public pipe(next: Next) {
+ this._next = next;
+ return next;
+ }
+ protected next(args: xml.ParserEvent) {
+ this._next.parse(args);
+ }
+ }
+
+ export class XmlStringParser extends XmlProducerBase implements XmlProducer {
+ private error: ErrorFormatter;
+
+ constructor(error?: ErrorFormatter) {
+ super();
+ this.error = error || PositionErrorFormat;
+ }
+
+ public parse(value: string) {
+ var xmlParser = new xml.XmlParser((args: xml.ParserEvent) => {
+ try {
+ this.next(args);
+ } catch(e) {
+ throw this.error(e, args.position);
+ }
+ }, (e, p) => {
+ throw this.error(e, p);
+ }, true);
+
+ if (types.isString(value)) {
+ value = value.replace(/xmlns=("|')http:\/\/((www)|(schemas))\.nativescript\.org\/tns\.xsd\1/, "");
+ xmlParser.parse(value);
+ }
+ }
+ }
+
+ interface ErrorFormatter {
+ (e: Error, p: xml.Position): Error;
+ }
+
+ export function PositionErrorFormat(e: Error, p: xml.Position): Error {
+ return new debug.ScopeError(e, "Parsing XML at " + p.line + ":" + p.column);
+ }
+
+ export function SourceErrorFormat(uri): ErrorFormatter {
+ return (e: Error, p: xml.Position) => {
+ var source = new debug.Source(uri, p.line, p.column);
+ e = new debug.SourceError(e, source, "Building UI from XML.");
+ return e;
+ }
+ }
+
+ export class PlatformFilter extends XmlProducerBase implements XmlProducer, XmlConsumer {
+ private currentPlatformContext: string;
+
+ public parse(args: xml.ParserEvent) {
+ if (args.eventType === xml.ParserEventType.StartElement) {
+ if (PlatformFilter.isPlatform(args.elementName)) {
+
+ if (this.currentPlatformContext) {
+ throw new Error("Already in '" + this.currentPlatformContext + "' platform context and cannot switch to '" + args.elementName + "' platform! Platform tags cannot be nested.");
+ }
+
+ this.currentPlatformContext = args.elementName;
+ return;
+ }
+ }
+
+ if (args.eventType === xml.ParserEventType.EndElement) {
+ if (PlatformFilter.isPlatform(args.elementName)) {
+ this.currentPlatformContext = undefined;
+ return;
+ }
+ }
+
+ if (this.currentPlatformContext && !PlatformFilter.isCurentPlatform(this.currentPlatformContext)) {
+ return;
+ }
+
+ this.next(args);
+ }
+
+ private static isPlatform(value: string): boolean {
+ return value && (value.toLowerCase() === platform.platformNames.android.toLowerCase()
+ || value.toLowerCase() === platform.platformNames.ios.toLowerCase());
+ }
+
+ private static isCurentPlatform(value: string): boolean {
+ return value && value.toLowerCase() === platform.device.os.toLowerCase();
+ }
+ }
+
+ export class XmlArgsReplay extends XmlProducerBase implements XmlProducer {
+ private error: ErrorFormatter;
+ private args: xml.ParserEvent[];
+
+ constructor(args: xml.ParserEvent[], errorFormat: ErrorFormatter) {
+ super();
+ this.args = args;
+ this.error = errorFormat;
+ }
+
+ public replay() {
+ this.args.forEach((args: xml.ParserEvent) => {
+ try {
+ this.next(args);
+ } catch(e) {
+ throw this.error(e, args.position);
+ }
+ });
+ }
+ }
+
+ interface TemplateProperty {
+ context?: any;
+ parent: componentBuilder.ComponentModule;
+ name: string;
+ elementName: string;
+ templateItems: Array;
+ errorFormat: ErrorFormatter;
+ }
+
+ /**
+ * It is a state pattern
+ * https://en.wikipedia.org/wiki/State_pattern
+ */
+ export class XmlStateParser implements XmlConsumer {
+ private state: XmlStateConsumer;
+
+ constructor(state: XmlStateConsumer) {
+ this.state = state;
+ }
+
+ parse(args: xml.ParserEvent) {
+ this.state = this.state.parse(args);
+ }
+ }
+
+ interface XmlStateConsumer extends XmlConsumer {
+ parse(args: xml.ParserEvent): XmlStateConsumer;
+ }
+
+ export class TemplateParser implements XmlStateConsumer {
+
+ private _context: any;
+ private _recordedXmlStream: Array;
+ private _templateProperty: TemplateProperty;
+ private _nestingLevel: number;
+ private _state: TemplateParser.State;
+
+ private parent: XmlStateConsumer;
+
+ constructor(parent: XmlStateConsumer, templateProperty: TemplateProperty) {
+ this.parent = parent;
+
+ this._context = templateProperty.context;
+ this._recordedXmlStream = new Array();
+ this._templateProperty = templateProperty;
+ this._nestingLevel = 0;
+ this._state = TemplateParser.State.EXPECTING_START;
+ }
+
+ public parse(args: xml.ParserEvent): XmlStateConsumer {
+ if (args.eventType === xml.ParserEventType.StartElement) {
+ this.parseStartElement(args.prefix, args.namespace, args.elementName, args.attributes);
+ } else if (args.eventType === xml.ParserEventType.EndElement) {
+ this.parseEndElement(args.prefix, args.elementName);
+ }
+
+ this._recordedXmlStream.push(args);
+
+ return this._state === TemplateParser.State.FINISHED ? this.parent : this;
+ }
+
+ public get elementName(): string {
+ return this._templateProperty.elementName;
+ }
+
+ private parseStartElement(prefix: string, namespace: string, elementName: string, attributes: Object) {
+ if (this._state === TemplateParser.State.EXPECTING_START) {
+ this._state = TemplateParser.State.PARSING;
+ } else if (this._state === TemplateParser.State.FINISHED) {
+ throw new Error("Template must have exactly one root element but multiple elements were found.");
+ }
+
+ this._nestingLevel++;
+ }
+
+ private parseEndElement(prefix: string, elementName: string) {
+ if (this._state === TemplateParser.State.EXPECTING_START) {
+ throw new Error("Template must have exactly one root element but none was found.");
+ } else if (this._state === TemplateParser.State.FINISHED) {
+ throw new Error("No more closing elements expected for this template.");
+ }
+
+ this._nestingLevel--;
+
+ if (this._nestingLevel === 0) {
+ this._state = TemplateParser.State.FINISHED;
+ this.build();
+ }
+ }
+
+ private build() {
+ if (this._templateProperty.name in this._templateProperty.parent.component) {
+ var context = this._context;
+ var errorFormat = this._templateProperty.errorFormat;
+ var template: view.Template = () => {
+ var start: xml2ui.XmlArgsReplay;
+ var ui: xml2ui.ComponentParser;
+
+ (start = new xml2ui.XmlArgsReplay(this._recordedXmlStream, errorFormat))
+ // No platform filter, it has been filtered allready
+ .pipe(new XmlStateParser(ui = new ComponentParser(context, errorFormat)));
+
+ start.replay();
+
+ return ui.rootComponentModule.component;
+ }
+ this._templateProperty.parent.component[this._templateProperty.name] = template;
+ }
+ }
+ }
+
+ export namespace TemplateParser {
+ export const enum State {
+ EXPECTING_START,
+ PARSING,
+ FINISHED
+ }
+ }
+
+ export class ComponentParser implements XmlStateConsumer {
+
+ private static KNOWNCOLLECTIONS = "knownCollections";
+ private static KNOWNTEMPLATES = "knownTemplates";
+
+ public rootComponentModule: componentBuilder.ComponentModule;
+
+ private context: any;
+
+ private currentPage: page.Page;
+ private parents = new Array();
+ private complexProperties = new Array();
+
+ private error;
+
+ constructor(context: any, errorFormat: ErrorFormatter) {
+ this.context = context;
+ this.error = errorFormat;
+ }
+
+ public parse(args: xml.ParserEvent): XmlStateConsumer {
+
+ // Get the current parent.
+ var parent = this.parents[this.parents.length - 1];
+ var complexProperty = this.complexProperties[this.complexProperties.length - 1];
+
+ // Create component instance from every element declaration.
+ if (args.eventType === xml.ParserEventType.StartElement) {
+ if (ComponentParser.isComplexProperty(args.elementName)) {
+
+ var name = ComponentParser.getComplexPropertyName(args.elementName);
+
+ this.complexProperties.push({
+ parent: parent,
+ name: name,
+ items: [],
+ });
+
+ if (ComponentParser.isKnownTemplate(name, parent.exports)) {
+ return new TemplateParser(this, {
+ context: parent ? getExports(parent.component) : null, // Passing 'context' won't work if you set "codeFile" on the page
+ parent: parent,
+ name: name,
+ elementName: args.elementName,
+ templateItems: [],
+ errorFormat: this.error
+ });
+ }
+
+ } else {
+
+ var componentModule: componentBuilder.ComponentModule;
+
+ if (args.prefix && args.namespace) {
+ // Custom components
+ componentModule = loadCustomComponent(args.namespace, args.elementName, args.attributes, this.context, this.currentPage);
+ } else {
+ // Default components
+ componentModule = componentBuilder.getComponentModule(args.elementName, args.namespace, args.attributes, this.context);
+ }
+
+ if (componentModule) {
+ if (parent) {
+ if (complexProperty) {
+ // Add component to complex property of parent component.
+ ComponentParser.addToComplexProperty(parent, complexProperty, componentModule);
+ } else if ((parent.component)._addChildFromBuilder) {
+ (parent.component)._addChildFromBuilder(args.elementName, componentModule.component);
+ }
+ } else if (this.parents.length === 0) {
+ // Set root component.
+ this.rootComponentModule = componentModule;
+
+ if (this.rootComponentModule && this.rootComponentModule.component instanceof page.Page) {
+ this.currentPage = this.rootComponentModule.component;
+ }
+ }
+
+ // Add the component instance to the parents scope collection.
+ this.parents.push(componentModule);
+ }
+ }
+
+ } else if (args.eventType === xml.ParserEventType.EndElement) {
+ if (ComponentParser.isComplexProperty(args.elementName)) {
+ if (complexProperty) {
+ if (parent && (parent.component)._addArrayFromBuilder) {
+ // If parent is AddArrayFromBuilder call the interface method to populate the array property.
+ (parent.component)._addArrayFromBuilder(complexProperty.name, complexProperty.items);
+ complexProperty.items = [];
+ }
+ }
+ // Remove the last complexProperty from the complexProperties collection (move to the previous complexProperty scope).
+ this.complexProperties.pop();
+
+ } else {
+ // Remove the last parent from the parents collection (move to the previous parent scope).
+ this.parents.pop();
+ }
+ }
+
+ return this;
+ }
+
+ private static isComplexProperty(name: string): boolean {
+ return types.isString(name) && name.indexOf(".") !== -1;
+ }
+
+ private static getComplexPropertyName(fullName: string): string {
+ var name: string;
+
+ if (types.isString(fullName)) {
+ var names = fullName.split(".");
+ name = names[names.length - 1];
+ }
+
+ return name;
+ }
+
+ private static isKnownTemplate(name: string, exports: any): boolean {
+ return ComponentParser.KNOWNTEMPLATES in exports && exports[ComponentParser.KNOWNTEMPLATES] && name in exports[ComponentParser.KNOWNTEMPLATES];
+ }
+
+ private static addToComplexProperty(parent: componentBuilder.ComponentModule, complexProperty: ComponentParser.ComplexProperty, elementModule: componentBuilder.ComponentModule) {
+ // If property name is known collection we populate array with elements.
+ var parentComponent = parent.component;
+ if (ComponentParser.isKnownCollection(complexProperty.name, parent.exports)) {
+ complexProperty.items.push(elementModule.component);
+ } else if (parentComponent._addChildFromBuilder) {
+ parentComponent._addChildFromBuilder(complexProperty.name, elementModule.component);
+ } else {
+ // Or simply assign the value;
+ parentComponent[complexProperty.name] = elementModule.component;
+ }
+ }
+
+ private static isKnownCollection(name: string, context: any): boolean {
+ return ComponentParser.KNOWNCOLLECTIONS in context && context[ComponentParser.KNOWNCOLLECTIONS] && name in context[ComponentParser.KNOWNCOLLECTIONS];
+ }
+ }
+
+ export namespace ComponentParser {
+ export interface ComplexProperty {
+ parent: componentBuilder.ComponentModule;
+ name: string;
+ items?: Array;
+ }
+ }
+}
\ No newline at end of file
diff --git a/ui/builder/template-builder.d.ts b/ui/builder/template-builder.d.ts
deleted file mode 100644
index f989952bd..000000000
--- a/ui/builder/template-builder.d.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-//@private
-declare module "ui/builder/template-builder" {
- import xml = require("xml");
- import page = require("ui/page");
- import componentBuilder = require("ui/builder/component-builder");
-
- class TemplateBuilder {
- constructor(templateProperty: TemplateProperty);
-
- elementName: string;
-
- /*
- * Returns true if the template builder has finished parsing template and the parsing should continue.
- * @param args - ParserEvent argument to handle.
- */
- handleElement(args: xml.ParserEvent): boolean;
- }
-
- export function isKnownTemplate(name: string, exports: any): boolean;
-
- interface TemplateProperty {
- context?: any;
- parent: componentBuilder.ComponentModule;
- name: string;
- elementName: string;
- templateItems: Array
- }
-}
\ No newline at end of file
diff --git a/ui/builder/template-builder.ts b/ui/builder/template-builder.ts
deleted file mode 100644
index 53877e215..000000000
--- a/ui/builder/template-builder.ts
+++ /dev/null
@@ -1,92 +0,0 @@
-import definition = require("ui/builder/template-builder");
-import builder = require("ui/builder");
-import view = require("ui/core/view");
-import page = require("ui/page");
-import xml = require("xml");
-
-var KNOWNTEMPLATES = "knownTemplates";
-
-export class TemplateBuilder {
- private _context: any;
- private _items: Array;
- private _templateProperty: definition.TemplateProperty;
- private _nestingLevel: number;
-
- constructor(templateProperty: definition.TemplateProperty) {
- this._context = templateProperty.context;
- this._items = new Array();
- this._templateProperty = templateProperty;
- this._nestingLevel = 0;
- }
-
- public get elementName(): string {
- return this._templateProperty.elementName;
- }
-
- handleElement(args: xml.ParserEvent): boolean {
- if (args.eventType === xml.ParserEventType.StartElement) {
- this.addStartElement(args.prefix, args.namespace, args.elementName, args.attributes);
- } else if (args.eventType === xml.ParserEventType.EndElement) {
- this.addEndElement(args.prefix, args.elementName);
- }
-
- if (this.hasFinished()) {
- this.build();
- return true;
- }
- else {
- return false;
- }
- }
-
- private addStartElement(prefix: string, namespace: string, elementName: string, attributes: Object) {
- this._nestingLevel++;
- this._items.push("<" +
- getElementNameWithPrefix(prefix, elementName) +
- (namespace ? " " + getNamespace(prefix, namespace) : "") +
- (attributes ? " " + getAttributesAsString(attributes) : "") +
- ">");
- }
-
- private addEndElement(prefix: string, elementName: string) {
- this._nestingLevel--;
- if (!this.hasFinished()) {
- this._items.push("" + getElementNameWithPrefix(prefix, elementName) + ">");
- }
- }
-
- private hasFinished() {
- return this._nestingLevel < 0;
- }
-
- private build() {
- if (this._templateProperty.name in this._templateProperty.parent.component) {
- var xml = this._items.join("");
- var context = this._context;
- var template: view.Template = () => builder.parse(xml, context);
- this._templateProperty.parent.component[this._templateProperty.name] = template;
- }
- }
-}
-
-export function isKnownTemplate(name: string, exports: any): boolean {
- return KNOWNTEMPLATES in exports && exports[KNOWNTEMPLATES] && name in exports[KNOWNTEMPLATES];
-}
-
-function getAttributesAsString(attributes: Object): string {
- var result = [];
-
- for (var item in attributes) {
- result.push(item + '="' + attributes[item] + '"');
- }
-
- return result.join(" ");
-}
-
-function getElementNameWithPrefix(prefix: string, elementName: string): string {
- return (prefix ? prefix + ":" : "") + elementName;
-}
-
-function getNamespace(prefix: string, namespace: string): string {
- return 'xmlns:' + prefix + '="' + namespace + '"';
-}
\ No newline at end of file