support for custom components inside templates with tests

This commit is contained in:
Vladimir Enchev
2015-04-24 14:44:12 +03:00
parent e75b14f609
commit efcc0d0ddf
4 changed files with 78 additions and 29 deletions

View File

@ -13,6 +13,10 @@ import observable = require("data/observable");
import stackLayoutModule = require("ui/layouts/stack-layout"); import stackLayoutModule = require("ui/layouts/stack-layout");
import labelModule = require("ui/label"); import labelModule = require("ui/label");
import myCustomControlWithoutXml = require("./mymodule/MyControl"); 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 () { export var test_load_IsDefined = function () {
TKUnit.assert(types.isFunction(builder.load), "ui/builder should have load method!"); 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); TKUnit.assert(panel.visibility === "collapsed", "Expected result: 'collapsed'; Actual result: " + panel.visibility);
}; };
export function test_parse_ShouldParseCustomComponentWithoutXmlInListViewTemplate() {
var p = <page.Page>builder.parse('<Page xmlns:customControls="xml-declaration/mymodule"><ListView items="{{ items }}" itemLoading="{{ itemLoading }}"><ListView.itemTemplate><customControls:MyControl /></ListView.itemTemplate></ListView></Page>');
function testAction(views: Array<viewModule.View>) {
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();
}
}

View File

@ -32,10 +32,10 @@ function parseInternal(value: string, exports: any): componentBuilder.ComponentM
if (templateBuilder) { if (templateBuilder) {
if (args.eventType === xml.ParserEventType.StartElement) { 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) { } else if (args.eventType === xml.ParserEventType.EndElement) {
if (templateBuilder.elementName !== args.elementName) { if (templateBuilder.elementName !== args.elementName) {
templateBuilder.addEndElement(args.elementName); templateBuilder.addEndElement(args.prefix, args.elementName);
} else { } else {
templateBuilder.build(); templateBuilder.build();
templateBuilder = undefined; templateBuilder = undefined;
@ -72,35 +72,40 @@ function parseInternal(value: string, exports: any): componentBuilder.ComponentM
var componentModule: componentBuilder.ComponentModule; var componentModule: componentBuilder.ComponentModule;
if (args.namespace) { if (args.prefix) {
// Custom components // 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 (ns) {
if (types.isDefined(componentModule) && types.isDefined(componentModule.component)) { var xmlPath = fs.path.join(fs.knownFolders.currentApp().path, ns, args.elementName) + ".xml";
var attr: string;
for (attr in args.attributes) { if (fs.File.exists(xmlPath)) {
componentBuilder.setPropertyValue(componentModule.component, subExports, exports, attr, args.attributes[attr]); // 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 { componentModule = loadInternal(xmlPath, subExports);
// Custom components without XML
componentModule = componentBuilder.getComponentModule(args.elementName, args.namespace, args.attributes, exports); // 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 { } else {
// Default components // Default components
componentModule = componentBuilder.getComponentModule(args.elementName, args.namespace, args.attributes, exports); componentModule = componentBuilder.getComponentModule(args.elementName, ns, args.attributes, exports);
} }
if (componentModule) { if (componentModule) {

View File

@ -6,8 +6,8 @@ declare module "ui/builder/template-builder" {
constructor(templateProperty: TemplateProperty); constructor(templateProperty: TemplateProperty);
elementName: string; elementName: string;
addStartElement(elementName: string, attributes: Object); addStartElement(prefix: string, namespace: string, elementName: string, attributes: Object);
addEndElement(elementName: string); addEndElement(prefix: string, elementName: string);
build(); build();
} }

View File

@ -15,12 +15,16 @@ export class TemplateBuilder {
return this._templateProperty.elementName; return this._templateProperty.elementName;
} }
public addStartElement(elementName: string, attributes: Object) { public addStartElement(prefix: string, namespace: string, elementName: string, attributes: Object) {
this._items.push("<" + elementName + (attributes ? " " + getAttributesAsString(attributes) + ">" : ">")); this._items.push("<" +
getElementNameWithPrefix(prefix, elementName) +
(namespace ? " " + getNamespace(prefix, namespace) : "") +
(attributes ? " " + getAttributesAsString(attributes) : "") +
">");
} }
public addEndElement(elementName: string) { public addEndElement(prefix: string, elementName: string) {
this._items.push("</" + elementName + ">"); this._items.push("</" + getElementNameWithPrefix(prefix, elementName) + ">");
} }
public build() { public build() {
@ -43,3 +47,11 @@ function getAttributesAsString(attributes: Object): string {
return result.join(" "); 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 + '"';
}