mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-17 04:41:36 +08:00
Merge pull request #407 from NativeScript/custom-components-css
CSS support for custom components added
This commit is contained in:
@ -211,7 +211,7 @@
|
|||||||
<TypeScriptCompile Include="apps\ui-tests-app\bindings\xmlbasics.ts">
|
<TypeScriptCompile Include="apps\ui-tests-app\bindings\xmlbasics.ts">
|
||||||
<DependentUpon>xmlbasics.xml</DependentUpon>
|
<DependentUpon>xmlbasics.xml</DependentUpon>
|
||||||
</TypeScriptCompile>
|
</TypeScriptCompile>
|
||||||
<TypeScriptCompile Include="apps\ui-tests-app\bindings\basics.ts" />
|
<TypeScriptCompile Include="apps\ui-tests-app\bindings\basics.ts" />
|
||||||
<TypeScriptCompile Include="apps\ui-tests-app\layouts\absolute.ts" />
|
<TypeScriptCompile Include="apps\ui-tests-app\layouts\absolute.ts" />
|
||||||
<TypeScriptCompile Include="apps\ui-tests-app\layouts\dock.ts" />
|
<TypeScriptCompile Include="apps\ui-tests-app\layouts\dock.ts" />
|
||||||
<TypeScriptCompile Include="apps\ui-tests-app\layouts\grid.ts" />
|
<TypeScriptCompile Include="apps\ui-tests-app\layouts\grid.ts" />
|
||||||
@ -706,6 +706,8 @@
|
|||||||
<Content Include="apps\tests\xml-declaration\mymodulewithxml\my-control-no-js.xml">
|
<Content Include="apps\tests\xml-declaration\mymodulewithxml\my-control-no-js.xml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Include="apps\tests\xml-declaration\mymodulewithxml\MyControl.css" />
|
||||||
|
<Content Include="apps\tests\xml-declaration\mymodule\MyControl.css" />
|
||||||
<Content Include="apps\ui-tests-app\bindings\xmlbasics.xml" />
|
<Content Include="apps\ui-tests-app\bindings\xmlbasics.xml" />
|
||||||
<Content Include="apps\ui-tests-app\layouts\absolute.xml" />
|
<Content Include="apps\ui-tests-app\layouts\absolute.xml" />
|
||||||
<Content Include="apps\ui-tests-app\layouts\dock.xml" />
|
<Content Include="apps\ui-tests-app\layouts\dock.xml" />
|
||||||
|
@ -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<viewModule.View>) {
|
||||||
|
var page: pageModule.Page = <pageModule.Page> views[1];
|
||||||
|
page.addCssFile("~/ui/style/test.css");
|
||||||
|
helper.assertViewBackgroundColor(page, "#FF0000");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// <snippet module="ui/styling" title="styling">
|
// <snippet module="ui/styling" title="styling">
|
||||||
// For information and example how to use style properties please refer to special [**Styling**](../../../styling.md) topic.
|
// For information and example how to use style properties please refer to special [**Styling**](../../../styling.md) topic.
|
||||||
// </snippet>
|
// </snippet>
|
||||||
|
3
apps/tests/xml-declaration/mymodule/MyControl.css
Normal file
3
apps/tests/xml-declaration/mymodule/MyControl.css
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.MyStackLayout {
|
||||||
|
background-color: red;
|
||||||
|
}
|
@ -18,5 +18,7 @@ export class MyControl extends stackLayoutModule.StackLayout {
|
|||||||
|
|
||||||
this.addChild(lbl);
|
this.addChild(lbl);
|
||||||
this.addChild(btn);
|
this.addChild(btn);
|
||||||
|
|
||||||
|
this.cssClass = "MyStackLayout";
|
||||||
}
|
}
|
||||||
}
|
}
|
3
apps/tests/xml-declaration/mymodulewithxml/MyControl.css
Normal file
3
apps/tests/xml-declaration/mymodulewithxml/MyControl.css
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.MySecondCustomStackLayout {
|
||||||
|
background-color: green;
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
<StackLayout xmlns:customControls="xml-declaration/mymodule">
|
<StackLayout xmlns:customControls="xml-declaration/mymodule" cssClass="MySecondCustomStackLayout">
|
||||||
<Label id="Label1" text="mymodulewithxml" />
|
<Label id="Label1" text="mymodulewithxml" />
|
||||||
<Button text="Click!" tap="buttonTap2" />
|
<Button text="Click!" tap="buttonTap2" />
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
|
@ -50,6 +50,31 @@ export function test_loadWithOptionsNoXML() {
|
|||||||
TKUnit.assert(v instanceof view.View, "Expected result: View; Actual result: " + v + ";");
|
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() {
|
export function test_loadWithOptionsWithXML() {
|
||||||
var v = builder.load({
|
var v = builder.load({
|
||||||
path: "~/xml-declaration/mymodulewithxml",
|
path: "~/xml-declaration/mymodulewithxml",
|
||||||
@ -59,6 +84,31 @@ export function test_loadWithOptionsWithXML() {
|
|||||||
TKUnit.assert(v instanceof view.View, "Expected result: View; Actual result: " + v + ";");
|
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() {
|
export function test_loadWithOptionsFromTNS() {
|
||||||
var v = builder.load({
|
var v = builder.load({
|
||||||
path: "ui/label",
|
path: "ui/label",
|
||||||
|
2
ui/builder/builder.d.ts
vendored
2
ui/builder/builder.d.ts
vendored
@ -1,6 +1,7 @@
|
|||||||
//@private
|
//@private
|
||||||
declare module "ui/builder" {
|
declare module "ui/builder" {
|
||||||
import view = require("ui/core/view");
|
import view = require("ui/core/view");
|
||||||
|
import page = require("ui/page");
|
||||||
|
|
||||||
export function load(fileName: string, exports?: any): view.View;
|
export function load(fileName: string, exports?: any): view.View;
|
||||||
export function load(options: LoadOptions): view.View;
|
export function load(options: LoadOptions): view.View;
|
||||||
@ -10,5 +11,6 @@ declare module "ui/builder" {
|
|||||||
path: string;
|
path: string;
|
||||||
name: string;
|
name: string;
|
||||||
exports?: any;
|
exports?: any;
|
||||||
|
page?: page.Page;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,9 @@ import componentBuilder = require("ui/builder/component-builder");
|
|||||||
import templateBuilderDef = require("ui/builder/template-builder");
|
import templateBuilderDef = require("ui/builder/template-builder");
|
||||||
import platform = require("platform");
|
import platform = require("platform");
|
||||||
import definition = require("ui/builder");
|
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";
|
var KNOWNCOLLECTIONS = "knownCollections";
|
||||||
|
|
||||||
@ -36,6 +39,7 @@ export function parse(value: string, context: any): view.View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function parseInternal(value: string, context: any): componentBuilder.ComponentModule {
|
function parseInternal(value: string, context: any): componentBuilder.ComponentModule {
|
||||||
|
var currentPage: page.Page;
|
||||||
var rootComponentModule: componentBuilder.ComponentModule;
|
var rootComponentModule: componentBuilder.ComponentModule;
|
||||||
// Temporary collection used for parent scope.
|
// Temporary collection used for parent scope.
|
||||||
var parents = new Array<componentBuilder.ComponentModule>();
|
var parents = new Array<componentBuilder.ComponentModule>();
|
||||||
@ -115,7 +119,7 @@ function parseInternal(value: string, context: any): componentBuilder.ComponentM
|
|||||||
|
|
||||||
if (args.prefix && args.namespace) {
|
if (args.prefix && args.namespace) {
|
||||||
// Custom components
|
// Custom components
|
||||||
componentModule = loadCustomComponent(args.namespace, args.elementName, args.attributes, context);
|
componentModule = loadCustomComponent(args.namespace, args.elementName, args.attributes, context, currentPage);
|
||||||
} else {
|
} else {
|
||||||
// Default components
|
// Default components
|
||||||
componentModule = componentBuilder.getComponentModule(args.elementName, args.namespace, args.attributes, context);
|
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) {
|
} else if (parents.length === 0) {
|
||||||
// Set root component.
|
// Set root component.
|
||||||
rootComponentModule = componentModule;
|
rootComponentModule = componentModule;
|
||||||
|
|
||||||
|
if (rootComponentModule && rootComponentModule.component instanceof page.Page) {
|
||||||
|
currentPage = <page.Page>rootComponentModule.component;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the component instance to the parents scope collection.
|
// Add the component instance to the parents scope collection.
|
||||||
@ -175,26 +183,29 @@ function parseInternal(value: string, context: any): componentBuilder.ComponentM
|
|||||||
return rootComponentModule;
|
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;
|
var result: componentBuilder.ComponentModule;
|
||||||
componentPath = componentPath.replace("~/", "");
|
componentPath = componentPath.replace("~/", "");
|
||||||
|
|
||||||
var fileName = componentPath;
|
var fullComponentPathFilePathWithoutExt = componentPath;
|
||||||
|
|
||||||
if (!fs.File.exists(fileName)) {
|
if (!fs.File.exists(componentPath)) {
|
||||||
fileName = fs.path.join(fs.knownFolders.currentApp().path, componentPath, componentName) + ".xml";
|
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
|
// Custom components with XML
|
||||||
var jsPath = fileName.replace(".xml", ".js");
|
var jsFilePath = resolveFilePath(fullComponentPathFilePathWithoutExt, "js");
|
||||||
|
|
||||||
var subExports;
|
var subExports;
|
||||||
if (fs.File.exists(jsPath)) {
|
if (jsFilePath) {
|
||||||
// Custom components with XML and code
|
// 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
|
// Attributes will be transfered to the custom component
|
||||||
if (types.isDefined(result) && types.isDefined(result.component) && types.isDefined(attributes)) {
|
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);
|
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;
|
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 viewToReturn: view.View;
|
||||||
var componentModule: componentBuilder.ComponentModule;
|
var componentModule: componentBuilder.ComponentModule;
|
||||||
|
|
||||||
if (arguments.length === 1) {
|
if (!context) {
|
||||||
if (!types.isString(arguments[0])) {
|
if (!types.isString(pathOrOptions)) {
|
||||||
var options = <definition.LoadOptions>arguments[0];
|
let options = <definition.LoadOptions>pathOrOptions;
|
||||||
componentModule = loadCustomComponent(options.path, options.name, undefined, options.exports);
|
componentModule = loadCustomComponent(options.path, options.name, undefined, options.exports, options.page);
|
||||||
} else {
|
} else {
|
||||||
componentModule = loadInternal(<string>arguments[0]);
|
let path = <string>pathOrOptions;
|
||||||
|
componentModule = loadInternal(path);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
componentModule = loadInternal(<string>arguments[0], arguments[1]);
|
let path = <string>pathOrOptions;
|
||||||
|
componentModule = loadInternal(path, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (componentModule) {
|
if (componentModule) {
|
||||||
|
@ -20,7 +20,6 @@ var navigationBarHiddenProperty = new dependencyObservable.Property(
|
|||||||
);
|
);
|
||||||
|
|
||||||
function onNavigationBarHiddenPropertyChanged(data: dependencyObservable.PropertyChangeData) {
|
function onNavigationBarHiddenPropertyChanged(data: dependencyObservable.PropertyChangeData) {
|
||||||
console.log("onNavigationBarHiddenPropertyChanged("+data.newValue+")");
|
|
||||||
var page = <Page>data.object;
|
var page = <Page>data.object;
|
||||||
if (page.isLoaded) {
|
if (page.isLoaded) {
|
||||||
page._updateNavigationBar(data.newValue);
|
page._updateNavigationBar(data.newValue);
|
||||||
@ -116,15 +115,18 @@ export class Page extends contentView.ContentView implements dts.Page, view.AddA
|
|||||||
this._refreshCss();
|
this._refreshCss();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _cssFiles = {};
|
||||||
public addCssFile(cssFileName: string) {
|
public addCssFile(cssFileName: string) {
|
||||||
if (cssFileName.indexOf(fs.knownFolders.currentApp().path) !== 0) {
|
if (cssFileName.indexOf("~/") === 0) {
|
||||||
cssFileName = fs.path.join(fs.knownFolders.currentApp().path, cssFileName);
|
cssFileName = fs.path.join(fs.knownFolders.currentApp().path, cssFileName.replace("~/", ""));
|
||||||
}
|
}
|
||||||
|
if (!this._cssFiles[cssFileName]) {
|
||||||
var cssString;
|
if (fs.File.exists(cssFileName)) {
|
||||||
if (fs.File.exists(cssFileName)) {
|
new fileSystemAccess.FileSystemAccess().readText(cssFileName, r => {
|
||||||
new fileSystemAccess.FileSystemAccess().readText(cssFileName, r => { cssString = r; });
|
this._addCssInternal(r, cssFileName);
|
||||||
this._addCssInternal(cssString, cssFileName);
|
this._cssFiles[cssFileName] = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,18 +33,17 @@ export class StyleScope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public addCss(cssString: string, cssFileName: string): void {
|
public addCss(cssString: string, cssFileName: string): void {
|
||||||
if (this._css === undefined) {
|
this._css = this._css ? this._css + cssString : cssString;
|
||||||
this._css = cssString;
|
this._cssFileName = cssFileName
|
||||||
}
|
|
||||||
else {
|
|
||||||
this._css += cssString;
|
|
||||||
}
|
|
||||||
this._cssFileName = cssFileName;
|
|
||||||
this._reset();
|
this._reset();
|
||||||
if (this._cssSelectors) {
|
|
||||||
var addedSelectors = StyleScope.createSelectorsFromCss(cssString, cssFileName);
|
if (!this._cssSelectors) {
|
||||||
this._cssSelectors = StyleScope._joinCssSelectorsArrays([this._cssSelectors, addedSelectors]);
|
this._cssSelectors = new Array<cssSelector.CssSelector>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var selectorsFromFile = StyleScope.createSelectorsFromCss(cssString, cssFileName);
|
||||||
|
this._cssSelectors = StyleScope._joinCssSelectorsArrays([this._cssSelectors, selectorsFromFile]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static createSelectorsFromCss(css: string, cssFileName: string): cssSelector.CssSelector[] {
|
public static createSelectorsFromCss(css: string, cssFileName: string): cssSelector.CssSelector[] {
|
||||||
|
Reference in New Issue
Block a user