definitions fixed

This commit is contained in:
Erjan Gavalji
2015-03-03 10:34:40 +02:00
parent a03ce4ca1d
commit cc829e0152
705 changed files with 321431 additions and 148812 deletions

7
ui/builder/builder.d.ts vendored Normal file
View File

@@ -0,0 +1,7 @@
//@private
declare module "ui/builder" {
import view = require("ui/core/view");
export function load(fileName: string, exports?: any): view.View;
export function parse(value: string, exports?: any): view.View;
}

219
ui/builder/builder.ts Normal file
View File

@@ -0,0 +1,219 @@
import view = require("ui/core/view");
import fs = require("file-system");
import xml = require("xml");
import file_access_module = require("file-system/file-system-access");
import types = require("utils/types");
import componentBuilder = require("ui/builder/component-builder");
import templateBuilderDef = require("ui/builder/template-builder");
var KNOWNCOLLECTIONS = "knownCollections";
export function parse(value: string, exports: any): view.View {
var viewToReturn: view.View;
var componentModule = parseInternal(value, exports);
if (componentModule) {
viewToReturn = componentModule.component;
}
return viewToReturn;
}
function parseInternal(value: string, exports: any): componentBuilder.ComponentModule {
var rootComponentModule: componentBuilder.ComponentModule;
// Temporary collection used for parent scope.
var parents = new Array<componentBuilder.ComponentModule>();
var complexProperties = new Array<ComplexProperty>();
var templateBuilder: templateBuilderDef.TemplateBuilder;
// Parse the XML.
var xmlParser = new xml.XmlParser((args: xml.ParserEvent) => {
if (templateBuilder) {
if (args.eventType === xml.ParserEventType.StartElement) {
templateBuilder.addStartElement(args.elementName, args.attributes);
} else if (args.eventType === xml.ParserEventType.EndElement) {
if (templateBuilder.elementName !== args.elementName) {
templateBuilder.addEndElement(args.elementName);
} else {
templateBuilder.build();
templateBuilder = undefined;
}
}
}
// 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({
parent: parent,
name: name,
elementName: args.elementName,
templateItems: []
});
}
} else {
var componentModule: componentBuilder.ComponentModule;
if (args.namespace) {
// 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);
} else {
// Custom components without XML
componentModule = componentBuilder.getComponentModule(args.elementName, args.namespace, args.attributes, exports);
}
} else {
// Default components
componentModule = componentBuilder.getComponentModule(args.elementName, args.namespace, args.attributes, exports);
}
if (componentModule) {
if (parent) {
if (componentModule.component instanceof view.View) {
if (complexProperty) {
// Add to complex property to component.
addToComplexProperty(parent, complexProperty, componentModule)
} else if ((<any>parent.component)._addChildFromBuilder) {
// Add component to visual tree
(<any>parent.component)._addChildFromBuilder(args.elementName, componentModule.component);
}
} else if (complexProperty) {
// Add component to complex property of parent component.
addToComplexProperty(parent, complexProperty, componentModule);
}
} else if (parents.length === 0) {
// Set root component.
rootComponentModule = componentModule;
}
// 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 && (<any>parent.component)._addArrayFromBuilder) {
// If parent is AddArrayFromBuilder call the interface method to populate the array property.
(<any>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();
}
}
}, (e) => {
throw new Error("XML parse error: " + e.message);
}, true);
xmlParser.parse(value.replace('xmlns="http://www.nativescript.org/tns.xsd"', "").replace("xmlns='http://www.nativescript.org/tns.xsd'", ""));
return rootComponentModule;
}
export function load(fileName: string, exports: any): view.View {
var viewToReturn: view.View;
var componentModule = loadInternal(fileName, exports);
if (componentModule) {
viewToReturn = componentModule.component;
}
return viewToReturn;
}
function loadInternal(fileName: string, exports: any): componentBuilder.ComponentModule {
var componentModule: componentBuilder.ComponentModule;
// Check if the XML file exists.
if (fileName && fs.File.exists(fileName)) {
var fileAccess = new file_access_module.FileSystemAccess();
// Read the XML file.
fileAccess.readText(fileName, result => {
componentModule = parseInternal(result, exports);
}, (e) => {
throw new Error("Error loading file " + fileName + " :" + e.message);
});
}
if (componentModule && componentModule.component) {
// Save exports to root component (will be used for templates).
(<any>componentModule.component).exports = exports;
}
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, exports: any): boolean {
return KNOWNCOLLECTIONS in exports && exports[KNOWNCOLLECTIONS] && name in exports[KNOWNCOLLECTIONS];
}
function addToComplexProperty(parent: componentBuilder.ComponentModule, complexProperty, elementModule: componentBuilder.ComponentModule) {
// If property name is known collection we populate array with elements.
var parentComponent = <any>parent.component;
if (isKnownCollection(complexProperty.name, parent.exports)) {
complexProperty.items.push(elementModule.component);
} else if (parentComponent._addChildFromBuilder) {
parentComponent._addChildFromBuilder("", elementModule.component);
} else {
// Or simply assign the value;
parentComponent[complexProperty.name] = elementModule.component;
}
}
interface ComplexProperty {
parent: componentBuilder.ComponentModule;
name: string;
items?: Array<any>;
}

11
ui/builder/component-builder.d.ts vendored Normal file
View File

@@ -0,0 +1,11 @@
//@private
declare module "ui/builder/component-builder" {
import view = require("ui/core/view");
export function getComponentModule(elementName: string, namespace: string, attributes: Object, exports: Object): ComponentModule;
export interface ComponentModule {
component: view.View;
exports: any;
}
}

View File

@@ -0,0 +1,176 @@
import observable = require("data/observable");
import view = require("ui/core/view");
import bindable = require("ui/core/bindable");
import dockLayoutDef = require("ui/layouts/dock-layout");
import gridLayoutModule = require("ui/layouts/grid-layout");
import absoluteLayoutDef = require("ui/layouts/absolute-layout");
import types = require("utils/types");
import definition = require("ui/builder/component-builder");
import fs = require("file-system");
import gestures = require("ui/gestures");
var KNOWNEVENTS = "knownEvents";
var UI_PATH = "ui/";
var MODULES = {
"ActivityIndicator": "ui/activity-indicator",
"ListView": "ui/list-view",
"GridLayout": "ui/layouts/grid-layout",
"DockLayout": "ui/layouts/dock-layout",
"WrapLayout": "ui/layouts/wrap-layout",
"AbsoluteLayout": "ui/layouts/absolute-layout",
"StackLayout": "ui/layouts/stack-layout",
"ScrollView": "ui/scroll-view",
"SearchBar": "ui/search-bar",
"SlideOut": "ui/slide-out",
"TabView": "ui/tab-view",
"TabEntry": "ui/tab-view",
"TextField": "ui/text-field",
"TextView": "ui/text-view",
"FormattedString": "text/formatted-string",
"Span": "text/span",
"WebView": "ui/web-view",
"SegmentedBar": "ui/segmented-bar",
"SegmentedBarEntry": "ui/segmented-bar",
"TimePicker": "ui/time-picker",
"DatePicker": "ui/date-picker",
"ListPicker": "ui/list-picker",
};
var ROW = "row";
var COL = "col";
var COL_SPAN = "colSpan";
var ROW_SPAN = "rowSpan";
var DOCK = "dock";
var LEFT = "left";
var TOP = "top";
export function getComponentModule(elementName: string, namespace: string, attributes: Object, exports: Object): definition.ComponentModule {
var instance: view.View;
var instanceModule: Object;
var componentModule: definition.ComponentModule;
// Get module id.
var moduleId = MODULES[elementName] || UI_PATH + elementName.toLowerCase();
try {
// Require module by module id.
instanceModule = require(types.isString(namespace) && fs.path.join(fs.knownFolders.currentApp().path, namespace) || moduleId);
// Get the component type from module.
var instanceType = instanceModule[elementName] || Object;
// Create instance of the component.
instance = new instanceType();
} catch (ex) {
throw new Error("Cannot create module " + moduleId + ". " + ex);
}
if (instance && instanceModule) {
var bindings = new Array<bindable.BindingOptions>();
for (var attr in attributes) {
var attrValue = attributes[attr];
if (isBinding(attrValue) && instance.bind) {
if (isKnownEvent(attr, instanceModule)) {
// Get the event handler from instance.bindingContext.
var propertyChangeHandler = (args: observable.PropertyChangeData) => {
if (args.propertyName === "bindingContext") {
var handler = instance.bindingContext && instance.bindingContext[getPropertyNameFromBinding(attrValue)];
// Check if the handler is function and add it to the instance for specified event name.
if (types.isFunction(handler)) {
instance.on(attr, handler, instance.bindingContext);
}
instance.off(observable.knownEvents.propertyChange, propertyChangeHandler);
}
};
instance.on(observable.knownEvents.propertyChange, propertyChangeHandler);
} else {
instance.bind(getBinding(instance, attr, attrValue));
}
} else if (isKnownEvent(attr, instanceModule)) {
// Get the event handler from page module exports.
var handler = exports && exports[attrValue];
// Check if the handler is function and add it to the instance for specified event name.
if (types.isFunction(handler)) {
instance.on(attr, handler);
}
} else if (isGesture(attr, instance)) {
// Get the event handler from page module exports.
var gestureHandler = exports && exports[attrValue];
// Check if the handler is function and add it to the instance for specified gesture.
if (types.isFunction(gestureHandler)) {
instance.observe(gestures.fromString(attr.toLowerCase()), gestureHandler);
}
} else if (attr === ROW) {
gridLayoutModule.GridLayout.setRow(instance, !isNaN(+attrValue) && +attrValue);
} else if (attr === COL) {
gridLayoutModule.GridLayout.setColumn(instance, !isNaN(+attrValue) && +attrValue);
} else if (attr === COL_SPAN) {
gridLayoutModule.GridLayout.setColumnSpan(instance, !isNaN(+attrValue) && +attrValue);
} else if (attr === ROW_SPAN) {
gridLayoutModule.GridLayout.setRowSpan(instance, !isNaN(+attrValue) && +attrValue);
} if (attr === LEFT) {
absoluteLayoutDef.AbsoluteLayout.setLeft(instance, !isNaN(+attrValue) && +attrValue);
} else if (attr === TOP) {
absoluteLayoutDef.AbsoluteLayout.setTop(instance, !isNaN(+attrValue) && +attrValue);
} else if (attr === DOCK) {
dockLayoutDef.DockLayout.setDock(instance, attrValue);
} else {
var attrHandled = false;
if ((<any>instance).applyXmlAttribute) {
attrHandled = (<any>instance).applyXmlAttribute(attr, attrValue);
}
if (!attrHandled) {
// Try to convert value to number.
var valueAsNumber = +attrValue;
if (!isNaN(valueAsNumber)) {
instance[attr] = valueAsNumber;
} else if (attrValue && (attrValue.toLowerCase() === "true" || attrValue.toLowerCase() === "false")) {
instance[attr] = attrValue.toLowerCase() === "true" ? true : false;
} else {
instance[attr] = attrValue;
}
}
}
}
componentModule = { component: instance, exports: instanceModule, bindings: bindings };
}
return componentModule;
}
function isGesture(name: string, instance: any): boolean {
return gestures.fromString(name.toLowerCase()) !== undefined;
}
function isKnownEvent(name: string, exports: any): boolean {
return (KNOWNEVENTS in exports && name in exports[KNOWNEVENTS]) ||
(KNOWNEVENTS in view && name in view[KNOWNEVENTS]);
}
function getBinding(instance: view.View, name: string, value: string): bindable.BindingOptions {
return { targetProperty: name, sourceProperty: getPropertyNameFromBinding(value), twoWay: true };
}
function getPropertyNameFromBinding(value: string): string {
return value.replace("{{", "").replace("}}", "").trim();
}
function isBinding(value: string): boolean {
var isBinding;
if (types.isString(value)) {
var str = value.trim();
isBinding = str.indexOf("{{") === 0 && str.lastIndexOf("}}") === str.length - 2;
}
return isBinding;
}

2
ui/builder/package.json Normal file
View File

@@ -0,0 +1,2 @@
{ "name" : "builder",
"main" : "builder.js" }

22
ui/builder/template-builder.d.ts vendored Normal file
View File

@@ -0,0 +1,22 @@
//@private
declare module "ui/builder/template-builder" {
import componentBuilder = require("ui/builder/component-builder");
class TemplateBuilder {
constructor(templateProperty: TemplateProperty);
elementName: string;
addStartElement(elementName: string, attributes: Object);
addEndElement(elementName: string);
build();
}
export function isKnownTemplate(name: string, exports: any): boolean;
interface TemplateProperty {
parent: componentBuilder.ComponentModule;
name: string;
elementName: string;
templateItems: Array<string>
}
}

View File

@@ -0,0 +1,45 @@
import definition = require("ui/builder/template-builder");
var KNOWNTEMPLATES = "knownTemplates";
export class TemplateBuilder {
private _items: Array<string>;
private _templateProperty: definition.TemplateProperty;
constructor(templateProperty: definition.TemplateProperty) {
this._items = new Array<string>();
this._templateProperty = templateProperty;
}
public get elementName(): string {
return this._templateProperty.elementName;
}
public addStartElement(elementName: string, attributes: Object) {
this._items.push("<" + elementName + (attributes ? " " + getAttributesAsString(attributes) + ">" : ">"));
}
public addEndElement(elementName: string) {
this._items.push("</" + elementName + ">");
}
public build() {
if (this._templateProperty.name in this._templateProperty.parent.component) {
this._templateProperty.parent.component[this._templateProperty.name] = this._items.join("");
}
}
}
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(" ");
}