diff --git a/CrossPlatformModules.csproj b/CrossPlatformModules.csproj
index 1e8e0aeef..a44d0d1e4 100644
--- a/CrossPlatformModules.csproj
+++ b/CrossPlatformModules.csproj
@@ -211,7 +211,7 @@
xmlbasics.xml
-
+
@@ -706,6 +706,8 @@
Designer
+
+
diff --git a/apps/tests/ui/style/style-tests.ts b/apps/tests/ui/style/style-tests.ts
index 66a35a762..9bc6ba6a9 100644
--- a/apps/tests/ui/style/style-tests.ts
+++ b/apps/tests/ui/style/style-tests.ts
@@ -778,6 +778,17 @@ export var test_CSS_isAppliedOnPage_From_Import = function () {
});
}
+export var test_CSS_isAppliedOnPage_From_addCssFile = function () {
+ var testButton = new buttonModule.Button();
+ testButton.text = "Test";
+
+ helper.buildUIAndRunTest(testButton, function (views: Array) {
+ var page: pageModule.Page = views[1];
+ page.addCssFile("~/ui/style/test.css");
+ helper.assertViewBackgroundColor(page, "#FF0000");
+ });
+}
+
//
// For information and example how to use style properties please refer to special [**Styling**](../../../styling.md) topic.
//
diff --git a/apps/tests/xml-declaration/mymodule/MyControl.css b/apps/tests/xml-declaration/mymodule/MyControl.css
new file mode 100644
index 000000000..d701672c7
--- /dev/null
+++ b/apps/tests/xml-declaration/mymodule/MyControl.css
@@ -0,0 +1,3 @@
+.MyStackLayout {
+ background-color: red;
+}
diff --git a/apps/tests/xml-declaration/mymodule/MyControl.ts b/apps/tests/xml-declaration/mymodule/MyControl.ts
index 53ba3b697..aca0396d3 100644
--- a/apps/tests/xml-declaration/mymodule/MyControl.ts
+++ b/apps/tests/xml-declaration/mymodule/MyControl.ts
@@ -18,5 +18,7 @@ export class MyControl extends stackLayoutModule.StackLayout {
this.addChild(lbl);
this.addChild(btn);
+
+ this.cssClass = "MyStackLayout";
}
}
\ No newline at end of file
diff --git a/apps/tests/xml-declaration/mymodulewithxml/MyControl.css b/apps/tests/xml-declaration/mymodulewithxml/MyControl.css
new file mode 100644
index 000000000..dd3ccf653
--- /dev/null
+++ b/apps/tests/xml-declaration/mymodulewithxml/MyControl.css
@@ -0,0 +1,3 @@
+.MySecondCustomStackLayout {
+ background-color: green;
+}
diff --git a/apps/tests/xml-declaration/mymodulewithxml/MyControl.xml b/apps/tests/xml-declaration/mymodulewithxml/MyControl.xml
index 016a2736c..4fe8e30f7 100644
--- a/apps/tests/xml-declaration/mymodulewithxml/MyControl.xml
+++ b/apps/tests/xml-declaration/mymodulewithxml/MyControl.xml
@@ -1,4 +1,4 @@
-
+
diff --git a/apps/tests/xml-declaration/xml-declaration-tests.ts b/apps/tests/xml-declaration/xml-declaration-tests.ts
index 5fbc4de33..8d9f20354 100644
--- a/apps/tests/xml-declaration/xml-declaration-tests.ts
+++ b/apps/tests/xml-declaration/xml-declaration-tests.ts
@@ -50,6 +50,31 @@ export function test_loadWithOptionsNoXML() {
TKUnit.assert(v instanceof view.View, "Expected result: View; Actual result: " + v + ";");
};
+export function test_loadWithOptionsNoXML_CSSIsApplied() {
+ var newPage: page.Page;
+ var pageFactory = function (): page.Page {
+ newPage = new page.Page();
+
+ newPage.content = builder.load({
+ path: "~/xml-declaration/mymodule",
+ name: "MyControl",
+ exports: exports,
+ page: newPage
+ });
+
+ return newPage;
+ };
+
+ helper.navigate(pageFactory);
+ TKUnit.assert(newPage.isLoaded, "The page should be loaded here.");
+ try {
+ helper.assertViewBackgroundColor(newPage.content, "#FF0000");
+ }
+ finally {
+ helper.goBack();
+ }
+};
+
export function test_loadWithOptionsWithXML() {
var v = builder.load({
path: "~/xml-declaration/mymodulewithxml",
@@ -59,6 +84,31 @@ export function test_loadWithOptionsWithXML() {
TKUnit.assert(v instanceof view.View, "Expected result: View; Actual result: " + v + ";");
};
+export function test_loadWithOptionsWithXML_CSSIsApplied() {
+ var newPage: page.Page;
+ var pageFactory = function (): page.Page {
+ newPage = new page.Page();
+
+ newPage.content = builder.load({
+ path: "~/xml-declaration/mymodulewithxml",
+ name: "MyControl",
+ exports: exports,
+ page: newPage
+ });
+
+ return newPage;
+ };
+
+ helper.navigate(pageFactory);
+ TKUnit.assert(newPage.isLoaded, "The page should be loaded here.");
+ try {
+ helper.assertViewBackgroundColor(newPage.content, "#008000");
+ }
+ finally {
+ helper.goBack();
+ }
+};
+
export function test_loadWithOptionsFromTNS() {
var v = builder.load({
path: "ui/label",
diff --git a/ui/builder/builder.d.ts b/ui/builder/builder.d.ts
index 9834658f5..9328be659 100644
--- a/ui/builder/builder.d.ts
+++ b/ui/builder/builder.d.ts
@@ -1,6 +1,7 @@
//@private
declare module "ui/builder" {
import view = require("ui/core/view");
+ import page = require("ui/page");
export function load(fileName: string, exports?: any): view.View;
export function load(options: LoadOptions): view.View;
@@ -10,5 +11,6 @@ declare module "ui/builder" {
path: string;
name: string;
exports?: any;
+ page?: page.Page;
}
}
diff --git a/ui/builder/builder.ts b/ui/builder/builder.ts
index 1942552e7..4d2f05bef 100644
--- a/ui/builder/builder.ts
+++ b/ui/builder/builder.ts
@@ -7,6 +7,9 @@ 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");
var KNOWNCOLLECTIONS = "knownCollections";
@@ -36,6 +39,7 @@ export function parse(value: string, context: any): view.View {
}
function parseInternal(value: string, context: any): componentBuilder.ComponentModule {
+ var currentPage: page.Page;
var rootComponentModule: componentBuilder.ComponentModule;
// Temporary collection used for parent scope.
var parents = new Array();
@@ -115,7 +119,7 @@ function parseInternal(value: string, context: any): componentBuilder.ComponentM
if (args.prefix && args.namespace) {
// Custom components
- componentModule = loadCustomComponent(args.namespace, args.elementName, args.attributes, context);
+ componentModule = loadCustomComponent(args.namespace, args.elementName, args.attributes, context, currentPage);
} else {
// Default components
componentModule = componentBuilder.getComponentModule(args.elementName, args.namespace, args.attributes, context);
@@ -138,6 +142,10 @@ function parseInternal(value: string, context: any): componentBuilder.ComponentM
} 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.
@@ -175,26 +183,29 @@ function parseInternal(value: string, context: any): componentBuilder.ComponentM
return rootComponentModule;
}
-function loadCustomComponent(componentPath: string, componentName?: string, attributes?: Object, context?: Object): componentBuilder.ComponentModule {
+function loadCustomComponent(componentPath: string, componentName?: string, attributes?: Object, context?: Object, parentPage?: page.Page): componentBuilder.ComponentModule {
var result: componentBuilder.ComponentModule;
componentPath = componentPath.replace("~/", "");
- var fileName = componentPath;
+ var fullComponentPathFilePathWithoutExt = componentPath;
- if (!fs.File.exists(fileName)) {
- fileName = fs.path.join(fs.knownFolders.currentApp().path, componentPath, componentName) + ".xml";
+ if (!fs.File.exists(componentPath)) {
+ fullComponentPathFilePathWithoutExt = fs.path.join(fs.knownFolders.currentApp().path, componentPath, componentName);
}
- if (fs.File.exists(fileName)) {
+ var xmlFilePath = resolveFilePath(fullComponentPathFilePathWithoutExt, "xml");
+
+ if (xmlFilePath) {
// Custom components with XML
- var jsPath = fileName.replace(".xml", ".js");
+ var jsFilePath = resolveFilePath(fullComponentPathFilePathWithoutExt, "js");
+
var subExports;
- if (fs.File.exists(jsPath)) {
+ if (jsFilePath) {
// Custom components with XML and code
- subExports = require(jsPath.replace(".js", ""))
+ subExports = require(jsFilePath)
}
- result = loadInternal(fileName, subExports);
+ result = loadInternal(xmlFilePath, subExports);
// Attributes will be transfered to the custom component
if (types.isDefined(result) && types.isDefined(result.component) && types.isDefined(attributes)) {
@@ -208,22 +219,47 @@ function loadCustomComponent(componentPath: string, componentName?: string, attr
result = componentBuilder.getComponentModule(componentName, componentPath, attributes, context);
}
+ // Add component CSS file if exists.
+ var cssFilePath = resolveFilePath(fullComponentPathFilePathWithoutExt, "css");
+ if (cssFilePath) {
+ if (parentPage) {
+ parentPage.addCssFile(cssFilePath);
+ } else {
+ trace.write("CSS file found but no page specified. Please specify page in the options!", trace.categories.Error, trace.messageType.error);
+ }
+ }
+
return result;
}
-export function load(arg: any): view.View {
+var fileNameResolver: fileResolverModule.FileNameResolver;
+function resolveFilePath(path, ext): string {
+ if (!fileNameResolver) {
+ fileNameResolver = new fileResolverModule.FileNameResolver({
+ width: platform.screen.mainScreen.widthDIPs,
+ height: platform.screen.mainScreen.heightDIPs,
+ os: platform.device.os,
+ deviceType: platform.device.deviceType
+ });
+ }
+ return fileNameResolver.resolveFileName(path, ext);
+}
+
+export function load(pathOrOptions: string | definition.LoadOptions, context?: any): view.View {
var viewToReturn: view.View;
var componentModule: componentBuilder.ComponentModule;
- if (arguments.length === 1) {
- if (!types.isString(arguments[0])) {
- var options = arguments[0];
- componentModule = loadCustomComponent(options.path, options.name, undefined, options.exports);
+ if (!context) {
+ if (!types.isString(pathOrOptions)) {
+ let options = pathOrOptions;
+ componentModule = loadCustomComponent(options.path, options.name, undefined, options.exports, options.page);
} else {
- componentModule = loadInternal(arguments[0]);
+ let path = pathOrOptions;
+ componentModule = loadInternal(path);
}
} else {
- componentModule = loadInternal(arguments[0], arguments[1]);
+ let path = pathOrOptions;
+ componentModule = loadInternal(path, context);
}
if (componentModule) {
@@ -303,4 +339,4 @@ function getExports(instance: view.View): any {
}
return parent ? (parent).exports : undefined;
-}
\ No newline at end of file
+}
diff --git a/ui/page/page-common.ts b/ui/page/page-common.ts
index e056dc8a4..486ff033e 100644
--- a/ui/page/page-common.ts
+++ b/ui/page/page-common.ts
@@ -20,7 +20,6 @@ var navigationBarHiddenProperty = new dependencyObservable.Property(
);
function onNavigationBarHiddenPropertyChanged(data: dependencyObservable.PropertyChangeData) {
- console.log("onNavigationBarHiddenPropertyChanged("+data.newValue+")");
var page = data.object;
if (page.isLoaded) {
page._updateNavigationBar(data.newValue);
@@ -116,15 +115,18 @@ export class Page extends contentView.ContentView implements dts.Page, view.AddA
this._refreshCss();
}
+ private _cssFiles = {};
public addCssFile(cssFileName: string) {
- if (cssFileName.indexOf(fs.knownFolders.currentApp().path) !== 0) {
- cssFileName = fs.path.join(fs.knownFolders.currentApp().path, cssFileName);
+ if (cssFileName.indexOf("~/") === 0) {
+ cssFileName = fs.path.join(fs.knownFolders.currentApp().path, cssFileName.replace("~/", ""));
}
-
- var cssString;
- if (fs.File.exists(cssFileName)) {
- new fileSystemAccess.FileSystemAccess().readText(cssFileName, r => { cssString = r; });
- this._addCssInternal(cssString, cssFileName);
+ if (!this._cssFiles[cssFileName]) {
+ if (fs.File.exists(cssFileName)) {
+ new fileSystemAccess.FileSystemAccess().readText(cssFileName, r => {
+ this._addCssInternal(r, cssFileName);
+ this._cssFiles[cssFileName] = true;
+ });
+ }
}
}
diff --git a/ui/styling/style-scope.ts b/ui/styling/style-scope.ts
index 05c69cb96..3015b6d45 100644
--- a/ui/styling/style-scope.ts
+++ b/ui/styling/style-scope.ts
@@ -33,18 +33,17 @@ export class StyleScope {
}
public addCss(cssString: string, cssFileName: string): void {
- if (this._css === undefined) {
- this._css = cssString;
- }
- else {
- this._css += cssString;
- }
- this._cssFileName = cssFileName;
+ this._css = this._css ? this._css + cssString : cssString;
+ this._cssFileName = cssFileName
+
this._reset();
- if (this._cssSelectors) {
- var addedSelectors = StyleScope.createSelectorsFromCss(cssString, cssFileName);
- this._cssSelectors = StyleScope._joinCssSelectorsArrays([this._cssSelectors, addedSelectors]);
+
+ if (!this._cssSelectors) {
+ this._cssSelectors = new Array();
}
+
+ var selectorsFromFile = StyleScope.createSelectorsFromCss(cssString, cssFileName);
+ this._cssSelectors = StyleScope._joinCssSelectorsArrays([this._cssSelectors, selectorsFromFile]);
}
public static createSelectorsFromCss(css: string, cssFileName: string): cssSelector.CssSelector[] {