From efcc0d0ddfba59cca59a4062c9cd1487e0eddf69 Mon Sep 17 00:00:00 2001 From: Vladimir Enchev Date: Fri, 24 Apr 2015 14:44:12 +0300 Subject: [PATCH] support for custom components inside templates with tests --- .../xml-declaration/xml-declaration-tests.ts | 32 ++++++++++++ ui/builder/builder.ts | 51 ++++++++++--------- ui/builder/template-builder.d.ts | 4 +- ui/builder/template-builder.ts | 20 ++++++-- 4 files changed, 78 insertions(+), 29 deletions(-) diff --git a/apps/tests/xml-declaration/xml-declaration-tests.ts b/apps/tests/xml-declaration/xml-declaration-tests.ts index 26d636473..2f12d1e94 100644 --- a/apps/tests/xml-declaration/xml-declaration-tests.ts +++ b/apps/tests/xml-declaration/xml-declaration-tests.ts @@ -13,6 +13,10 @@ import observable = require("data/observable"); import stackLayoutModule = require("ui/layouts/stack-layout"); import labelModule = require("ui/label"); import myCustomControlWithoutXml = require("./mymodule/MyControl"); +import listViewModule = require("ui/list-view"); +import frame = require("ui/frame"); +import helper = require("../ui/helper"); +import viewModule = require("ui/core/view"); export var test_load_IsDefined = function () { TKUnit.assert(types.isFunction(builder.load), "ui/builder should have load method!"); @@ -179,3 +183,31 @@ export var test_parse_ShouldParseCustomComponentWitXmlWithAttributes = function TKUnit.assert(panel.visibility === "collapsed", "Expected result: 'collapsed'; Actual result: " + panel.visibility); }; + +export function test_parse_ShouldParseCustomComponentWithoutXmlInListViewTemplate() { + var p = builder.parse(''); + + function testAction(views: Array) { + var ctrl; + + var obj = new observable.Observable(); + obj.set("items", [1]); + obj.set("itemLoading", function (args: listViewModule.ItemEventData) { + ctrl = args.view + }); + p.bindingContext = obj; + + TKUnit.wait(0.2); + + TKUnit.assert(ctrl instanceof myCustomControlWithoutXml.MyControl, "Expected result: custom control is defined!; Actual result: " + ctrl); + }; + + helper.navigate(function () { return p; }); + + try { + testAction([p.content, p]); + } + finally { + helper.goBack(); + } +} \ No newline at end of file diff --git a/ui/builder/builder.ts b/ui/builder/builder.ts index b35b284dd..494ee1b43 100644 --- a/ui/builder/builder.ts +++ b/ui/builder/builder.ts @@ -32,10 +32,10 @@ function parseInternal(value: string, exports: any): componentBuilder.ComponentM if (templateBuilder) { if (args.eventType === xml.ParserEventType.StartElement) { - templateBuilder.addStartElement(args.elementName, args.attributes); + templateBuilder.addStartElement(args.prefix, args.namespace, args.elementName, args.attributes); } else if (args.eventType === xml.ParserEventType.EndElement) { if (templateBuilder.elementName !== args.elementName) { - templateBuilder.addEndElement(args.elementName); + templateBuilder.addEndElement(args.prefix, args.elementName); } else { templateBuilder.build(); templateBuilder = undefined; @@ -72,35 +72,40 @@ function parseInternal(value: string, exports: any): componentBuilder.ComponentM var componentModule: componentBuilder.ComponentModule; - if (args.namespace) { + if (args.prefix) { // Custom components - var xmlPath = fs.path.join(fs.knownFolders.currentApp().path, args.namespace, args.elementName) + ".xml"; - if (fs.File.exists(xmlPath)) { - // Custom components with XML - var jsPath = xmlPath.replace(".xml", ".js"); - var subExports; - if (fs.File.exists(jsPath)) { - // Custom components with XML and code - subExports = require(jsPath.replace(".js", "")) - } - componentModule = loadInternal(xmlPath, subExports); + var ns = args.namespace; - // Attributes will be transfered to the custom component - if (types.isDefined(componentModule) && types.isDefined(componentModule.component)) { - var attr: string; - for (attr in args.attributes) { - componentBuilder.setPropertyValue(componentModule.component, subExports, exports, attr, args.attributes[attr]); + if (ns) { + var xmlPath = fs.path.join(fs.knownFolders.currentApp().path, ns, args.elementName) + ".xml"; + + if (fs.File.exists(xmlPath)) { + // Custom components with XML + var jsPath = xmlPath.replace(".xml", ".js"); + var subExports; + if (fs.File.exists(jsPath)) { + // Custom components with XML and code + subExports = require(jsPath.replace(".js", "")) } - } - } else { - // Custom components without XML - componentModule = componentBuilder.getComponentModule(args.elementName, args.namespace, args.attributes, exports); + componentModule = loadInternal(xmlPath, subExports); + + // Attributes will be transfered to the custom component + if (types.isDefined(componentModule) && types.isDefined(componentModule.component)) { + var attr: string; + for (attr in args.attributes) { + componentBuilder.setPropertyValue(componentModule.component, subExports, exports, attr, args.attributes[attr]); + } + } + } else { + // Custom components without XML + componentModule = componentBuilder.getComponentModule(args.elementName, ns, args.attributes, exports); + } } } else { // Default components - componentModule = componentBuilder.getComponentModule(args.elementName, args.namespace, args.attributes, exports); + componentModule = componentBuilder.getComponentModule(args.elementName, ns, args.attributes, exports); } if (componentModule) { diff --git a/ui/builder/template-builder.d.ts b/ui/builder/template-builder.d.ts index b0ed9130c..49aa369dc 100644 --- a/ui/builder/template-builder.d.ts +++ b/ui/builder/template-builder.d.ts @@ -6,8 +6,8 @@ declare module "ui/builder/template-builder" { constructor(templateProperty: TemplateProperty); elementName: string; - addStartElement(elementName: string, attributes: Object); - addEndElement(elementName: string); + addStartElement(prefix: string, namespace: string, elementName: string, attributes: Object); + addEndElement(prefix: string, elementName: string); build(); } diff --git a/ui/builder/template-builder.ts b/ui/builder/template-builder.ts index 40e518a7c..4510ba2fd 100644 --- a/ui/builder/template-builder.ts +++ b/ui/builder/template-builder.ts @@ -15,12 +15,16 @@ export class TemplateBuilder { return this._templateProperty.elementName; } - public addStartElement(elementName: string, attributes: Object) { - this._items.push("<" + elementName + (attributes ? " " + getAttributesAsString(attributes) + ">" : ">")); + public addStartElement(prefix: string, namespace: string, elementName: string, attributes: Object) { + this._items.push("<" + + getElementNameWithPrefix(prefix, elementName) + + (namespace ? " " + getNamespace(prefix, namespace) : "") + + (attributes ? " " + getAttributesAsString(attributes) : "") + + ">"); } - public addEndElement(elementName: string) { - this._items.push(""); + public addEndElement(prefix: string, elementName: string) { + this._items.push(""); } public build() { @@ -42,4 +46,12 @@ function getAttributesAsString(attributes: Object): string { } 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