diff --git a/CrossPlatformModules.csproj b/CrossPlatformModules.csproj
index 79b57e3d8..507e2c7a3 100644
--- a/CrossPlatformModules.csproj
+++ b/CrossPlatformModules.csproj
@@ -79,6 +79,7 @@
data-binding.xml
+
@@ -110,6 +111,7 @@
+
Designer
@@ -1982,8 +1984,6 @@
False
-
-
diff --git a/apps/tests/xml-declaration/custom-code-file.ts b/apps/tests/xml-declaration/custom-code-file.ts
new file mode 100644
index 000000000..b6e82d9d5
--- /dev/null
+++ b/apps/tests/xml-declaration/custom-code-file.ts
@@ -0,0 +1,3 @@
+export function loaded(args) {
+ args.object.customCodeLoaded = true;
+}
diff --git a/apps/tests/xml-declaration/custom-css-file.css b/apps/tests/xml-declaration/custom-css-file.css
new file mode 100644
index 000000000..6b7785523
--- /dev/null
+++ b/apps/tests/xml-declaration/custom-css-file.css
@@ -0,0 +1,3 @@
+.MyClass {
+ background-color: green;
+}
diff --git a/apps/tests/xml-declaration/xml-declaration-tests.ts b/apps/tests/xml-declaration/xml-declaration-tests.ts
index 83b639bbf..9d0079a1c 100644
--- a/apps/tests/xml-declaration/xml-declaration-tests.ts
+++ b/apps/tests/xml-declaration/xml-declaration-tests.ts
@@ -148,10 +148,91 @@ export function test_parse_ShouldNotCrashWithoutExports() {
var file = fs.File.fromPath(fs.path.join(__dirname, "mainPage.xml"));
var text = file.readTextSync();
- var v: view.View = builder.parse(text);
+ var v: view.View = builder.parse(text);
TKUnit.assert(v instanceof view.View, "Expected result: View; Actual result: " + v + ";");
};
+export function test_parse_ShouldResolveExportsFromCodeFile() {
+ var page = builder.parse("");
+ page._emit("loaded");
+
+ TKUnit.assert((page).customCodeLoaded, "Parse should resolve exports from custom code file.");
+}
+
+export function test_parse_ShouldThrowErrorWhenInvalidCodeFileIsSpecified() {
+ var e: Error;
+ try {
+ builder.parse("");
+ } catch (ex) {
+ e = ex;
+ }
+
+ TKUnit.assert(e, "Expected result: Error; Actual result: " + e);
+};
+
+export function test_parse_ShouldResolveExportsFromCodeFileForTemplates() {
+ 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).customCodeLoaded, "Parse should resolve exports for templates from custom code file.");
+ };
+
+ helper.navigate(function () { return p; });
+
+ try {
+ testAction([p.content, p]);
+ }
+ finally {
+ helper.goBack();
+ }
+}
+
+export function test_parse_ShouldApplyCssFromCssFile() {
+ var newPage: Page;
+ var pageFactory = function (): Page {
+ newPage = builder.parse("");
+ 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_parse_ShouldResolveExportsFromCodeFileAndApplyCssFile() {
+ var newPage: Page;
+ var pageFactory = function (): Page {
+ newPage = builder.parse("");
+ return newPage;
+ };
+
+ helper.navigate(pageFactory);
+ TKUnit.assert(newPage.isLoaded, "The page should be loaded here.");
+ TKUnit.assert((newPage).customCodeLoaded, "Parse should resolve exports from custom code file.");
+ try {
+ helper.assertViewBackgroundColor(newPage.content, "#008000");
+ }
+ finally {
+ helper.goBack();
+ }
+};
+
export function test_parse_ShouldFindEventHandlersInExports() {
var loaded;
var page = builder.parse("", {
diff --git a/ui/builder/component-builder.ts b/ui/builder/component-builder.ts
index 5730a6a2d..c94788ec8 100644
--- a/ui/builder/component-builder.ts
+++ b/ui/builder/component-builder.ts
@@ -10,6 +10,7 @@ import fs = require("file-system");
import gestures = require("ui/gestures");
import bindingBuilder = require("ui/builder/binding-builder");
import platform = require("platform");
+import pages = require("ui/page");
var UI_PATH = "ui/";
var MODULES = {
@@ -28,6 +29,8 @@ var ROW_SPAN = "rowSpan";
var DOCK = "dock";
var LEFT = "left";
var TOP = "top";
+var CODEFILE = "codeFile";
+var CSSFILE = "cssFile";
export var specialProperties: Array = [
ROW,
@@ -37,6 +40,8 @@ export var specialProperties: Array = [
DOCK,
LEFT,
TOP,
+ CODEFILE,
+ CSSFILE
]
var eventHandlers = {};
@@ -78,6 +83,42 @@ export function getComponentModule(elementName: string, namespace: string, attri
throw new Error("Cannot create module " + moduleId + ". " + ex + ". StackTrace: " + ex.stack);
}
+ if (attributes) {
+ if (attributes[CODEFILE]) {
+ if (instance instanceof pages.Page) {
+ var codeFilePath = attributes[CODEFILE].trim();
+ if (codeFilePath.indexOf("~/") === 0) {
+ codeFilePath = fs.path.join(fs.knownFolders.currentApp().path, codeFilePath.replace("~/", ""));
+ }
+ try {
+ exports = require(codeFilePath);
+ (instance).exports = exports;
+ } catch (ex) {
+ throw new Error(`Code file with path "${codeFilePath}" cannot be found!`);
+ }
+ } else {
+ throw new Error("Code file atribute is valid only for pages!");
+ }
+ }
+
+ if (attributes[CSSFILE]) {
+ if (instance instanceof pages.Page) {
+ var cssFilePath = attributes[CSSFILE].trim();
+ if (cssFilePath.indexOf("~/") === 0) {
+ cssFilePath = fs.path.join(fs.knownFolders.currentApp().path, cssFilePath.replace("~/", ""));
+ }
+ if (fs.File.exists(cssFilePath)) {
+ (instance).addCssFile(cssFilePath);
+ instance[CSSFILE] = true;
+ } else {
+ throw new Error(`Css file with path "${cssFilePath}" cannot be found!`);
+ }
+ } else {
+ throw new Error("Css file atribute is valid only for pages!");
+ }
+ }
+ }
+
if (instance && instanceModule) {
var bindings = new Array();
diff --git a/ui/frame/frame-common.ts b/ui/frame/frame-common.ts
index 4c1f52d7a..6450fc2b5 100644
--- a/ui/frame/frame-common.ts
+++ b/ui/frame/frame-common.ts
@@ -66,9 +66,9 @@ export function resolvePageFromEntry(entry: definition.NavigationEntry): pages.P
throw new Error("Failed to load Page from entry.moduleName: " + entry.moduleName);
}
- // Possible CSS file path.
+ // Possible CSS file path. Add it only if CSS not already specified and loaded from cssFile Page attribute in XML.
var cssFileName = fileResolverModule.resolveFileName(moduleNamePath, "css");
- if (cssFileName) {
+ if (cssFileName && !page["cssFile"]) {
page.addCssFile(cssFileName);
}
}