From fbe053d2fc936a23db73a0b79bf2613b8edb7026 Mon Sep 17 00:00:00 2001 From: vakrilov Date: Wed, 24 Feb 2016 15:28:32 +0200 Subject: [PATCH 1/2] Action bar directives --- ng-sample/.vscode/launch.json | 89 ++++++++++++ ng-sample/.vscode/settings.json | 11 ++ ng-sample/app/app.ts | 19 ++- .../examples/action-bar/action-bar-test.ts | 90 ++++++++++++ src/nativescript-angular/application.d.ts | 5 + src/nativescript-angular/application.ts | 22 ++- .../directives/action-bar.ts | 137 ++++++++++++++++++ .../directives/ns-directives.ts | 8 +- .../element-registry.d.ts | 17 +++ src/nativescript-angular/element-registry.ts | 117 +++++++++------ .../router/page-router-outlet.ts | 11 +- src/nativescript-angular/view-util.ts | 39 +++-- 12 files changed, 489 insertions(+), 76 deletions(-) create mode 100644 ng-sample/.vscode/launch.json create mode 100644 ng-sample/.vscode/settings.json create mode 100644 ng-sample/app/examples/action-bar/action-bar-test.ts create mode 100644 src/nativescript-angular/directives/action-bar.ts diff --git a/ng-sample/.vscode/launch.json b/ng-sample/.vscode/launch.json new file mode 100644 index 000000000..7d0ec5702 --- /dev/null +++ b/ng-sample/.vscode/launch.json @@ -0,0 +1,89 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Launch on iOS Device", + "type": "nativescript", + "platform": "ios", + "request": "launch", + "appRoot": ".", + "sourceMaps": true, + "diagnosticLogging": true, + "stopOnEntry": true, + "emulator": false + }, + { + "name": "Attach on iOS Device", + "type": "nativescript", + "platform": "ios", + "request": "attach", + "appRoot": ".", + "sourceMaps": true, + "diagnosticLogging": true, + "emulator": false + }, + { + "name": "Launch on iOS Emulator", + "type": "nativescript", + "platform": "ios", + "request": "launch", + "appRoot": ".", + "sourceMaps": true, + "diagnosticLogging": true, + "stopOnEntry": true, + "emulator": true + }, + { + "name": "Attach on iOS Emulator", + "type": "nativescript", + "platform": "ios", + "request": "attach", + "appRoot": ".", + "sourceMaps": true, + "diagnosticLogging": true, + "emulator": true + }, + { + "name": "Launch on Android Device", + "type": "nativescript", + "platform": "android", + "request": "launch", + "appRoot": ".", + "sourceMaps": true, + "diagnosticLogging": true, + "stopOnEntry": true, + "emulator": false + }, + { + "name": "Launch on Android Emulator", + "type": "nativescript", + "platform": "android", + "request": "launch", + "appRoot": ".", + "sourceMaps": true, + "diagnosticLogging": true, + "stopOnEntry": true, + "emulator": true + }, + { + "name": "Attach on Android Device", + "type": "nativescript", + "platform": "android", + "request": "attach", + "appRoot": ".", + "sourceMaps": false, + "diagnosticLogging": true, + "emulator": false + }, + { + "name": "Attach on Android Emulator", + "type": "nativescript", + "platform": "android", + "request": "attach", + "appRoot": ".", + "sourceMaps": false, + "diagnosticLogging": true, + "emulator": true + } + ] +} \ No newline at end of file diff --git a/ng-sample/.vscode/settings.json b/ng-sample/.vscode/settings.json new file mode 100644 index 000000000..c3899ddb9 --- /dev/null +++ b/ng-sample/.vscode/settings.json @@ -0,0 +1,11 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.exclude": { + "**/*.js": { + "when": "$(basename).ts" + }, + "**/*.js.map": {}, + "platforms/**": {}, + "hooks/**": {} + } +} \ No newline at end of file diff --git a/ng-sample/app/app.ts b/ng-sample/app/app.ts index 4e5f5edd2..3dde0b20d 100644 --- a/ng-sample/app/app.ts +++ b/ng-sample/app/app.ts @@ -11,7 +11,9 @@ import { NS_ROUTER_PROVIDERS, routerTraceCategory } from "./nativescript-angular import { rendererTraceCategory } from "./nativescript-angular/renderer"; import trace = require("trace"); -trace.setCategories(routerTraceCategory + ", " + rendererTraceCategory); +// trace.setCategories(routerTraceCategory + ", " + rendererTraceCategory); +// trace.setCategories(rendererTraceCategory); +// trace.setCategories(routerTraceCategory); trace.enable(); import {RendererTest} from './examples/renderer-test'; @@ -20,11 +22,16 @@ import {ListTest} from './examples/list/list-test'; import {ListTestAsync} from "./examples/list/list-test-async"; import {ImageTest} from "./examples/image/image-test"; import {NavigationTest} from "./examples/navigation/navigation-test"; +import {ActionBarTest} from "./examples/action-bar/action-bar-test"; -//nativeScriptBootstrap(RendererTest); -//nativeScriptBootstrap(Benchmark); -//nativeScriptBootstrap(ListTest); -nativeScriptBootstrap(ListTestAsync); +// nativeScriptBootstrap(RendererTest); +// nativeScriptBootstrap(Benchmark); +// nativeScriptBootstrap(ListTest); +// nativeScriptBootstrap(ListTestAsync); +// nativeScriptBootstrap(Benchmark); +// nativeScriptBootstrap(ListTest); +// nativeScriptBootstrap(ListTestAsync); // nativeScriptBootstrap(ImageTest); -//nativeScriptBootstrap(NavigationTest, [NS_ROUTER_PROVIDERS]); +// nativeScriptBootstrap(NavigationTest, [NS_ROUTER_PROVIDERS]); +nativeScriptBootstrap(ActionBarTest, [NS_ROUTER_PROVIDERS], { startPageActionBarHidden: false }); diff --git a/ng-sample/app/examples/action-bar/action-bar-test.ts b/ng-sample/app/examples/action-bar/action-bar-test.ts new file mode 100644 index 000000000..39c4749c3 --- /dev/null +++ b/ng-sample/app/examples/action-bar/action-bar-test.ts @@ -0,0 +1,90 @@ +import {Component} from 'angular2/core'; +import {RouteConfig} from 'angular2/router'; +import { Page} from "ui/page"; +import {NS_ROUTER_DIRECTIVES, NS_ROUTER_PROVIDERS} from "../../nativescript-angular/router/ns-router"; +import {NS_DIRECTIVES} from "../../nativescript-angular/directives/ns-directives"; + +@Component({ + selector: "first", + directives: [NS_ROUTER_DIRECTIVES, NS_DIRECTIVES], + template: ` + + + + + + + + + `, +}) +class FirstComponent { + public show: boolean = true; + onTap() { + console.log("FirstComponent.Tapped!"); + } +} + + +@Component({ + selector: "nested-componenet", + directives: [NS_ROUTER_DIRECTIVES, NS_DIRECTIVES], + template: ` + + + + + + + + + `, +}) +class NestedComponent { + public show: boolean = true; + + onTap() { + console.log("NestedComponent.Tapped!"); + } +} + +@Component({ + selector: "second", + directives: [NS_ROUTER_DIRECTIVES, NS_DIRECTIVES, NestedComponent], + template: ` + + + + + + + + + + `, +}) +class SecondComponent { + onTap() { + console.log("SecondComponent.Tapped!"); + } +} + + + +@Component({ + selector: 'action-bar-test', + directives: [NS_ROUTER_DIRECTIVES], + template: ` + + + + ` +}) +@RouteConfig([ + { path: '/', component: FirstComponent, as: 'First' }, + { path: '/second', component: SecondComponent, as: 'Second' }, +]) +export class ActionBarTest { +} + + diff --git a/src/nativescript-angular/application.d.ts b/src/nativescript-angular/application.d.ts index 89d8035eb..58f0af33d 100644 --- a/src/nativescript-angular/application.d.ts +++ b/src/nativescript-angular/application.d.ts @@ -1,5 +1,10 @@ import { Type, ApplicationRef, Provider } from 'angular2/core'; +export interface AppOptions { + cssFile?: string; + startPageActionBarHidden?: boolean; +} + export type BindingArray = Array>; export function bootstrap(appComponentType: any, componentInjectableBindings?: BindingArray): Promise; export function nativeScriptBootstrap(appComponentType: any, customProviders?: BindingArray, appOptions?: any): void; diff --git a/src/nativescript-angular/application.ts b/src/nativescript-angular/application.ts index eddf3f24a..cdb1aca84 100644 --- a/src/nativescript-angular/application.ts +++ b/src/nativescript-angular/application.ts @@ -43,8 +43,13 @@ import {defaultPageProvider} from "./platform-providers"; let _platform = null; +export interface AppOptions { + cssFile?: string; + startPageActionBarHidden?: boolean; +} + export function bootstrap(appComponentType: any, - customProviders: ProviderArray = null) : Promise { + customProviders: ProviderArray = null): Promise { NativeScriptDomAdapter.makeCurrent(); let platformProviders: ProviderArray = [ @@ -72,21 +77,24 @@ export function bootstrap(appComponentType: any, if (isPresent(customProviders)) { appProviders.push(customProviders); } - + if (!_platform) { _platform = platform(platformProviders); } return _platform.application(appProviders).bootstrap(appComponentType); } -export function nativeScriptBootstrap(appComponentType: any, customProviders?: ProviderArray, appOptions?: any) { +export function nativeScriptBootstrap(appComponentType: any, customProviders?: ProviderArray, appOptions?: AppOptions) { if (appOptions && appOptions.cssFile) { application.cssFile = appOptions.cssFile; } application.start({ create: (): Page => { let page = new Page(); - + if (appOptions) { + page.actionBarHidden = appOptions.startPageActionBarHidden; + } + let onLoadedHandler = function(args) { page.off('loaded', onLoadedHandler); //profiling.stop('application-start'); @@ -97,7 +105,7 @@ export function nativeScriptBootstrap(appComponentType: any, customProviders?: P bootstrap(appComponentType, customProviders).then((appRef) => { //profiling.stop('ng-bootstrap'); console.log('ANGULAR BOOTSTRAP DONE.'); - }, (err) =>{ + }, (err) => { console.log('ERROR BOOTSTRAPPING ANGULAR'); let errorMessage = err.message + "\n\n" + err.stack; console.log(errorMessage); @@ -107,9 +115,9 @@ export function nativeScriptBootstrap(appComponentType: any, customProviders?: P page.content = view; }); } - + page.on('loaded', onLoadedHandler); - + return page; } }); diff --git a/src/nativescript-angular/directives/action-bar.ts b/src/nativescript-angular/directives/action-bar.ts new file mode 100644 index 000000000..f7abd60cc --- /dev/null +++ b/src/nativescript-angular/directives/action-bar.ts @@ -0,0 +1,137 @@ +import {Directive, Component, ContentChildren, ElementRef, Optional} from 'angular2/core'; +import {ActionItem, ActionBar, NavigationButton} from "ui/action-bar"; +import {Page} from "ui/page"; +import {View} from 'ui/core/view'; +import {registerElement, ViewClassMeta, NgView } from '../element-registry'; + +var actionBarMeta: ViewClassMeta = { + skipAddToDom: true, + insertChild: (parent: NgView, child: NgView, atIndex: number) => { + const bar = (parent); + const childView = child; + + if (child instanceof NavigationButton) { + bar.navigationButton = childView; + childView.parent = bar; + } else if (child instanceof ActionItem) { + bar.actionItems.addItem(childView); + childView.parent = bar; + } else if (child.nodeName === "template") { + child.templateParent = parent; + } else if (child.nodeName !== "#text" && child instanceof View) { + bar.titleView = childView; + } + }, + removeChild: (parent: NgView, child: NgView) => { + const bar = (parent); + const childView = child; + if (child instanceof NavigationButton) { + if (bar.navigationButton === childView) { + bar.navigationButton = null; + } + childView.parent = null; + } else if (child instanceof ActionItem) { + bar.actionItems.removeItem(childView); + childView.parent = null; + } else if (child.nodeName !== "template" && child instanceof View && bar.titleView && bar.titleView === childView) { + bar.titleView = null; + } + }, +} + +registerElement("ActionBar", () => require("ui/action-bar").ActionBar, actionBarMeta); +registerElement("ActionItem", () => require("ui/action-bar").ActionItem); +registerElement("NavigationButton", () => require("ui/action-bar").NavigationButton); + +@Component({ + selector: "ActionBar", + template: "" +}) +export class ActionBarDirective { + constructor(public element: ElementRef, private page: Page) { + console.log("ActionBarDirective.constructor: " + element.nativeElement) + console.log("ActionBarDirective.constructor.parent: " + element.nativeElement.parent) + } + + ngOnInit() { + console.log('ActionBarDirective.ngOnInit'); + this.page.actionBarHidden = false; + this.page.actionBar = this.element.nativeElement; + this.page.actionBar.update(); + } + ngOnDestroy() { + console.log('ActionBarDirective.ngOnDestroy'); + } +} + +@Component({ + selector: "action-bar-scope", + template: "" +}) +export class ActionBarScope { + constructor(private page: Page) { + } + + public onNavButtonInit(navBtn: NavigationButtonDirective) { + this.page.actionBar.navigationButton = navBtn.element.nativeElement; + } + + public onNavButtonDestroy(navBtn: NavigationButtonDirective) { + const nav = navBtn.element.nativeElement; + if (nav && this.page.actionBar.navigationButton === nav) { + this.page.actionBar.navigationButton = null; + } + } + + public onActionInit(item: ActionItemDirective) { + this.page.actionBar.actionItems.addItem(item.element.nativeElement); + } + + public onActionDestroy(item: ActionItemDirective) { + this.page.actionBar.actionItems.removeItem(item.element.nativeElement); + } +} + +@Directive({ + selector: "ActionItem" +}) +export class ActionItemDirective { + constructor(public element: ElementRef, @Optional() private ownerScope: ActionBarScope) { + console.log("ActionItemDirective.constructor: " + element) + } + + ngOnInit() { + console.log('ActionItemDirective.ngOnInit owner: ' + this.ownerScope); + if (this.ownerScope) { + this.ownerScope.onActionInit(this); + } + } + ngOnDestroy() { + console.log('ActionItemDirective.ngOnDestroy' + this.ownerScope); + if (this.ownerScope) { + this.ownerScope.onActionDestroy(this); + } + } +} + +@Directive({ + selector: "NavigationButton" +}) +export class NavigationButtonDirective { + constructor(public element: ElementRef, @Optional() private ownerScope: ActionBarScope) { + console.log("NavigationButtonDirective.constructor: " + element) + } + + ngOnInit() { + console.log('NavigationButtonDirective.ngOnInit owner: ' + this.ownerScope); + if (this.ownerScope) { + this.ownerScope.onNavButtonInit(this); + } + } + ngOnDestroy() { + console.log('NavigationButtonDirective.ngOnDestroy' + this.ownerScope); + if (this.ownerScope) { + this.ownerScope.onNavButtonDestroy(this); + } + } +} diff --git a/src/nativescript-angular/directives/ns-directives.ts b/src/nativescript-angular/directives/ns-directives.ts index 7fc4e467b..09654b7bc 100644 --- a/src/nativescript-angular/directives/ns-directives.ts +++ b/src/nativescript-angular/directives/ns-directives.ts @@ -3,6 +3,7 @@ import {ListViewComponent} from './list-view-comp'; import {TextValueAccessor} from '../value-accessors/text-value-accessor'; import {CheckedValueAccessor} from '../value-accessors/checked-value-accessor'; import {TabViewDirective, TabViewItemDirective} from './tab-view'; +import {ActionBarDirective, ActionBarScope, ActionItemDirective, NavigationButtonDirective} from './action-bar'; export const NS_DIRECTIVES: Type[] = [ ListViewComponent, @@ -11,5 +12,10 @@ export const NS_DIRECTIVES: Type[] = [ TabViewItemDirective, TextValueAccessor, - CheckedValueAccessor + CheckedValueAccessor, + + ActionBarDirective, + ActionBarScope, + ActionItemDirective, + NavigationButtonDirective ]; diff --git a/src/nativescript-angular/element-registry.d.ts b/src/nativescript-angular/element-registry.d.ts index 5f2581fa4..6fda71a9b 100644 --- a/src/nativescript-angular/element-registry.d.ts +++ b/src/nativescript-angular/element-registry.d.ts @@ -2,10 +2,27 @@ import {View} from 'ui/core/view'; export type ViewResolver = () => ViewClass; +export type NgView = View & ViewExtensions; + +export interface ViewExtensions { + nodeName: string; + templateParent: NgView; + cssClasses: Map; + meta: ViewClassMeta; +} + +export interface ViewClassMeta { + skipAddToDom?: boolean; + insertChild?: (parent: NgView, child: NgView, atIndex: number) => void; + removeChild?: (parent: NgView, child: NgView) => void; +} + export interface ViewClass { new(): View } + export function registerElement(elementName: string, resolver: ViewResolver): void; export function getViewClass(elementName: string): ViewClass; export function isKnownView(elementName: string): boolean; +export function getViewMeta(nodeName: string): ViewClassMeta; \ No newline at end of file diff --git a/src/nativescript-angular/element-registry.ts b/src/nativescript-angular/element-registry.ts index f1726be60..7e78c6aa7 100644 --- a/src/nativescript-angular/element-registry.ts +++ b/src/nativescript-angular/element-registry.ts @@ -1,74 +1,101 @@ import {View} from 'ui/core/view'; +export type ViewResolver = () => ViewClass; +export type NgView = View & ViewExtensions; + +export interface ViewClassMeta { + skipAddToDom?: boolean; + insertChild?: (parent: NgView, child: NgView, atIndex: number) => void; + removeChild?: (parent: NgView, child: NgView) => void; +} + +export interface ViewExtensions { + nodeName: string; + templateParent: NgView; + cssClasses: Map; + meta: ViewClassMeta; +} + export interface ViewClass { - new(): View + new (): View } -export type ViewResolver = () => ViewClass; +var defaultViewMeta: ViewClassMeta = { + skipAddToDom: false, +} -var elementMap: Map = new Map(); +var elementMap: Map = new Map(); -export function registerElement(elementName: string, resolver: ViewResolver): void { +export function registerElement(elementName: string, resolver: ViewResolver, meta?: ViewClassMeta): void { if (elementMap.has(elementName)) { throw new Error(`Element for ${elementName} already registered.`); } else { - elementMap.set(elementName, resolver); - elementMap.set(elementName.toLowerCase(), resolver); + const entry = { resolver: resolver, meta: meta }; + elementMap.set(elementName, entry); + elementMap.set(elementName.toLowerCase(), entry); } } export function getViewClass(elementName: string): ViewClass { - const resolver = elementMap.get(elementName) || - elementMap.get(elementName.toLowerCase()); - if (!resolver) { + const entry = elementMap.get(elementName) || + elementMap.get(elementName.toLowerCase()); + if (!entry) { throw new TypeError(`No known component for element ${elementName}.`); } try { - return resolver(); + return entry.resolver(); } catch (e) { - throw new TypeError(`Could not load view for: ${elementName}. + throw new TypeError(`Could not load view for: ${elementName}.${e}`); + } +} -${e}`); +export function getViewMeta(nodeName: string): ViewClassMeta { + let meta = defaultViewMeta; + const entry = elementMap.get(nodeName) || elementMap.get(nodeName.toLowerCase()); + if (entry && entry.meta) { + meta = entry.meta; } + return meta; } export function isKnownView(elementName: string): boolean { return elementMap.has(elementName) || - elementMap.has(elementName.toLowerCase()); + elementMap.has(elementName.toLowerCase()); } + + //Register default NativeScript components +//Note: ActionBar related components are registerd together with action-bar directives. registerElement("AbsoluteLayout", () => require("ui/layouts/absolute-layout").AbsoluteLayout); -registerElement("ActionBar", () => require("ui/action-bar").ActionBar); -registerElement("ActionItem", () => require("ui/action-bar").ActionItem); -registerElement("ActivityIndicator", () => require("ui/activity-indicator").ActivityIndicator); -registerElement("Border", () => require("ui/border").Border); -registerElement("Button", () => require("ui/button").Button); -registerElement("ContentView", () => require("ui/content-view").ContentView); -registerElement("DatePicker", () => require("ui/date-picker").DatePicker); -registerElement("DockLayout", () => require("ui/layouts/dock-layout").DockLayout); -registerElement("GridLayout", () => require("ui/layouts/grid-layout").GridLayout); -registerElement("HtmlView", () => require("ui/html-view").HtmlView); -registerElement("Image", () => require("ui/image").Image); +registerElement("ActivityIndicator", () => require("ui/activity-indicator").ActivityIndicator); +registerElement("Border", () => require("ui/border").Border); +registerElement("Button", () => require("ui/button").Button); +registerElement("ContentView", () => require("ui/content-view").ContentView); +registerElement("DatePicker", () => require("ui/date-picker").DatePicker); +registerElement("DockLayout", () => require("ui/layouts/dock-layout").DockLayout); +registerElement("GridLayout", () => require("ui/layouts/grid-layout").GridLayout); +registerElement("HtmlView", () => require("ui/html-view").HtmlView); +registerElement("Image", () => require("ui/image").Image); // Parse5 changes tags to . WTF! -registerElement("img", () => require("ui/image").Image); -registerElement("Label", () => require("ui/label").Label); -registerElement("ListPicker", () => require("ui/list-picker").ListPicker); -registerElement("ListView", () => require("ui/list-view").ListView); -registerElement("Page", () => require("ui/page").Page); -registerElement("Placeholder", () => require("ui/placeholder").Placeholder); -registerElement("Progress", () => require("ui/progress").Progress); -registerElement("Repeater", () => require("ui/repeater").Repeater); -registerElement("ScrollView", () => require("ui/scroll-view").ScrollView); -registerElement("SearchBar", () => require("ui/search-bar").SearchBar); -registerElement("SegmentedBar", () => require("ui/segmented-bar").SegmentedBar); -registerElement("Slider", () => require("ui/slider").Slider); -registerElement("StackLayout", () => require("ui/layouts/stack-layout").StackLayout); -registerElement("Switch", () => require("ui/switch").Switch); -registerElement("TabView", () => require("ui/tab-view").TabView); -registerElement("TextField", () => require("ui/text-field").TextField); -registerElement("TextView", () => require("ui/text-view").TextView); -registerElement("TimePicker", () => require("ui/time-picker").TimePicker); -registerElement("WebView", () => require("ui/web-view").WebView); -registerElement("WrapLayout", () => require("ui/layouts/wrap-layout").WrapLayout); -registerElement("ProxyViewContainer", () => require("ui/proxy-view-container").ProxyViewContainer); +registerElement("img", () => require("ui/image").Image); +registerElement("Label", () => require("ui/label").Label); +registerElement("ListPicker", () => require("ui/list-picker").ListPicker); +registerElement("ListView", () => require("ui/list-view").ListView); +registerElement("Page", () => require("ui/page").Page); +registerElement("Placeholder", () => require("ui/placeholder").Placeholder); +registerElement("Progress", () => require("ui/progress").Progress); +registerElement("ProxyViewContainer", () => require("ui/proxy-view-container").ProxyViewContainer); +registerElement("Repeater", () => require("ui/repeater").Repeater); +registerElement("ScrollView", () => require("ui/scroll-view").ScrollView); +registerElement("SearchBar", () => require("ui/search-bar").SearchBar); +registerElement("SegmentedBar", () => require("ui/segmented-bar").SegmentedBar); +registerElement("Slider", () => require("ui/slider").Slider); +registerElement("StackLayout", () => require("ui/layouts/stack-layout").StackLayout); +registerElement("Switch", () => require("ui/switch").Switch); +registerElement("TabView", () => require("ui/tab-view").TabView); +registerElement("TextField", () => require("ui/text-field").TextField); +registerElement("TextView", () => require("ui/text-view").TextView); +registerElement("TimePicker", () => require("ui/time-picker").TimePicker); +registerElement("WebView", () => require("ui/web-view").WebView); +registerElement("WrapLayout", () => require("ui/layouts/wrap-layout").WrapLayout); diff --git a/src/nativescript-angular/router/page-router-outlet.ts b/src/nativescript-angular/router/page-router-outlet.ts index 28d7e967b..9a4175f62 100644 --- a/src/nativescript-angular/router/page-router-outlet.ts +++ b/src/nativescript-angular/router/page-router-outlet.ts @@ -273,6 +273,7 @@ class PageShim implements OnActivate, OnDeactivate, CanReuse, OnReuse { private id: number; private isInitialized: boolean; private componentRef: ComponentRef; + private page: Page; constructor( private element: ElementRef, @@ -282,6 +283,7 @@ class PageShim implements OnActivate, OnDeactivate, CanReuse, OnReuse { ) { this.id = PageShim.pageShimCount++; this.log("constructor"); + this.page = new Page(); } routerOnActivate(nextInstruction: ComponentInstruction, prevInstruction: ComponentInstruction): any { @@ -295,7 +297,12 @@ class PageShim implements OnActivate, OnDeactivate, CanReuse, OnReuse { if (!this.isInitialized) { result = new Promise((resolve, reject) => { this.isInitialized = true; - this.loader.loadIntoLocation(this.componentType, this.element, 'content') + + let providers = Injector.resolve([ + provide(Page, { useValue: this.page }), + ]); + + this.loader.loadIntoLocation(this.componentType, this.element, 'content', providers) .then((componentRef) => { this.componentRef = componentRef; @@ -309,7 +316,7 @@ class PageShim implements OnActivate, OnDeactivate, CanReuse, OnReuse { topmost().navigate({ animated: true, create: () => { - const page = new Page(); + const page = this.page; page.on('loaded', () => { // Finish activation when page is fully loaded. resolve() diff --git a/src/nativescript-angular/view-util.ts b/src/nativescript-angular/view-util.ts index d38d0b16a..bf6a6b99a 100644 --- a/src/nativescript-angular/view-util.ts +++ b/src/nativescript-angular/view-util.ts @@ -3,22 +3,20 @@ import {View} from "ui/core/view"; import {Placeholder} from "ui/placeholder"; import {ContentView} from 'ui/content-view'; import {LayoutBase} from 'ui/layouts/layout-base'; -import {ViewClass, getViewClass, isKnownView} from './element-registry'; +import {ViewClass, getViewClass, getViewMeta, isKnownView, ViewExtensions, NgView, ViewClassMeta} from './element-registry'; import {getSpecialPropertySetter} from "ui/builder/special-properties"; +import { ActionBar, ActionItem, NavigationButton } from "ui/action-bar"; import trace = require("trace"); + export const rendererTraceCategory = "ns-renderer"; export function traceLog(msg) { trace.write(msg, rendererTraceCategory); } -export interface ViewExtensions { - nodeName: string; - templateParent: NgView; - cssClasses: Map; -} +export type ViewExtensions = ViewExtensions; +export type NgView = NgView; -export type NgView = View & ViewExtensions; export type NgLayoutBase = LayoutBase & ViewExtensions; export type NgContentView = ContentView & ViewExtensions; @@ -34,13 +32,14 @@ export function isContentView(view: any): view is NgContentView { return view instanceof ContentView; } -function isComplexProperty(view: NgView) { - const name = view.nodeName - return isString(name) && name.indexOf(".") !== -1; -} - export function insertChild(parent: any, child: NgView, atIndex = -1) { - if (isLayout(parent)) { + if (!parent || child.meta.skipAddToDom) { + return; + } + + if (parent.meta && parent.meta.insertChild) { + parent.meta.insertChild(parent, child, atIndex); + } else if (isLayout(parent)) { if (atIndex !== -1) { parent.insertChild(child, atIndex); } else { @@ -48,13 +47,21 @@ export function insertChild(parent: any, child: NgView, atIndex = -1) { } } else if (isContentView(parent)) { parent.content = child; + } else if (parent && parent._addChildFromBuilder) { + parent._addChildFromBuilder(child.nodeName, child); } else { //throw new Error("Parent can't contain children: " + parent.nodeName + ', ' + parent); } } export function removeChild(parent: any, child: NgView) { - if (isLayout(parent)) { + if (!parent || child.meta.skipAddToDom) { + return; + } + + if (parent.meta && parent.meta.removeChild) { + parent.meta.removeChild(parent, child); + } else if (isLayout(parent)) { parent.removeChild(child); } else if (isContentView(parent)) { if (parent.content === child) { @@ -80,6 +87,7 @@ export function getChildIndex(parent: any, child: NgView) { function createAndAttach(name: string, viewClass: ViewClass, parent: NgView): NgView { const view = new viewClass(); view.nodeName = name; + view.meta = getViewMeta(name); if (parent) { insertChild(parent, view); } @@ -99,6 +107,7 @@ export function createText(value: string): NgView { const text = new Placeholder(); text.nodeName = "#text"; text.visibility = "collapse"; + text.meta = getViewMeta("Placeholder"); return text; } @@ -113,7 +122,7 @@ export function createViewContainer(name: string, parentElement: NgView) { export function createTemplateAnchor(parentElement: NgView) { //HACK: Using a ContentView here, so that it creates a native View object - const anchor = createAndAttach('ContentView', ContentView, parentElement); + const anchor = createAndAttach('template', ContentView, parentElement); anchor.visibility = "collapse"; anchor.templateParent = parentElement; return anchor; From 20f3eee33f8ebca1e5294a6393cc5adeac3c2db6 Mon Sep 17 00:00:00 2001 From: vakrilov Date: Thu, 10 Mar 2016 15:42:15 +0200 Subject: [PATCH 2/2] Cleanup and fix tests --- .../examples/action-bar/action-bar-test.ts | 8 ++++--- .../directives/action-bar.ts | 21 ++++++------------- .../directives/ns-directives.ts | 4 ++-- tests/app/tests/property-sets.ts | 4 +++- 4 files changed, 16 insertions(+), 21 deletions(-) diff --git a/ng-sample/app/examples/action-bar/action-bar-test.ts b/ng-sample/app/examples/action-bar/action-bar-test.ts index 39c4749c3..3572fa82b 100644 --- a/ng-sample/app/examples/action-bar/action-bar-test.ts +++ b/ng-sample/app/examples/action-bar/action-bar-test.ts @@ -31,9 +31,11 @@ class FirstComponent { directives: [NS_ROUTER_DIRECTIVES, NS_DIRECTIVES], template: ` - - - + + + + + diff --git a/src/nativescript-angular/directives/action-bar.ts b/src/nativescript-angular/directives/action-bar.ts index f7abd60cc..b861defdf 100644 --- a/src/nativescript-angular/directives/action-bar.ts +++ b/src/nativescript-angular/directives/action-bar.ts @@ -1,5 +1,6 @@ import {Directive, Component, ContentChildren, ElementRef, Optional} from 'angular2/core'; import {ActionItem, ActionBar, NavigationButton} from "ui/action-bar"; +import {isBlank} from "angular2/src/facade/lang"; import {Page} from "ui/page"; import {View} from 'ui/core/view'; import {registerElement, ViewClassMeta, NgView } from '../element-registry'; @@ -47,25 +48,21 @@ registerElement("NavigationButton", () => require("ui/action-bar").NavigationBut selector: "ActionBar", template: "" }) -export class ActionBarDirective { +export class ActionBarComponent { constructor(public element: ElementRef, private page: Page) { - console.log("ActionBarDirective.constructor: " + element.nativeElement) - console.log("ActionBarDirective.constructor.parent: " + element.nativeElement.parent) } ngOnInit() { - console.log('ActionBarDirective.ngOnInit'); - this.page.actionBarHidden = false; + if (isBlank(this.page.actionBarHidden)) { + this.page.actionBarHidden = false; + } this.page.actionBar = this.element.nativeElement; this.page.actionBar.update(); } - ngOnDestroy() { - console.log('ActionBarDirective.ngOnDestroy'); - } } @Component({ - selector: "action-bar-scope", + selector: "ActionBarExtension", template: "" }) export class ActionBarScope { @@ -97,17 +94,14 @@ export class ActionBarScope { }) export class ActionItemDirective { constructor(public element: ElementRef, @Optional() private ownerScope: ActionBarScope) { - console.log("ActionItemDirective.constructor: " + element) } ngOnInit() { - console.log('ActionItemDirective.ngOnInit owner: ' + this.ownerScope); if (this.ownerScope) { this.ownerScope.onActionInit(this); } } ngOnDestroy() { - console.log('ActionItemDirective.ngOnDestroy' + this.ownerScope); if (this.ownerScope) { this.ownerScope.onActionDestroy(this); } @@ -119,17 +113,14 @@ export class ActionItemDirective { }) export class NavigationButtonDirective { constructor(public element: ElementRef, @Optional() private ownerScope: ActionBarScope) { - console.log("NavigationButtonDirective.constructor: " + element) } ngOnInit() { - console.log('NavigationButtonDirective.ngOnInit owner: ' + this.ownerScope); if (this.ownerScope) { this.ownerScope.onNavButtonInit(this); } } ngOnDestroy() { - console.log('NavigationButtonDirective.ngOnDestroy' + this.ownerScope); if (this.ownerScope) { this.ownerScope.onNavButtonDestroy(this); } diff --git a/src/nativescript-angular/directives/ns-directives.ts b/src/nativescript-angular/directives/ns-directives.ts index 09654b7bc..031f599d2 100644 --- a/src/nativescript-angular/directives/ns-directives.ts +++ b/src/nativescript-angular/directives/ns-directives.ts @@ -3,7 +3,7 @@ import {ListViewComponent} from './list-view-comp'; import {TextValueAccessor} from '../value-accessors/text-value-accessor'; import {CheckedValueAccessor} from '../value-accessors/checked-value-accessor'; import {TabViewDirective, TabViewItemDirective} from './tab-view'; -import {ActionBarDirective, ActionBarScope, ActionItemDirective, NavigationButtonDirective} from './action-bar'; +import {ActionBarComponent, ActionBarScope, ActionItemDirective, NavigationButtonDirective} from './action-bar'; export const NS_DIRECTIVES: Type[] = [ ListViewComponent, @@ -14,7 +14,7 @@ export const NS_DIRECTIVES: Type[] = [ TextValueAccessor, CheckedValueAccessor, - ActionBarDirective, + ActionBarComponent, ActionBarScope, ActionItemDirective, NavigationButtonDirective diff --git a/tests/app/tests/property-sets.ts b/tests/app/tests/property-sets.ts index b39b73d49..168e800e4 100644 --- a/tests/app/tests/property-sets.ts +++ b/tests/app/tests/property-sets.ts @@ -3,12 +3,14 @@ import {assert} from "./test-config"; import {bootstrap} from "../nativescript-angular/application"; import {Component} from "angular2/core"; import {View} from "ui/core/view"; -import {NgView, ViewExtensions, setProperty} from "../nativescript-angular/view-util"; +import {setProperty} from "../nativescript-angular/view-util"; +import {NgView, ViewExtensions, ViewClassMeta} from "../nativescript-angular/element-registry"; import {Red} from "color/known-colors"; class TestView extends View implements ViewExtensions { public nodeName: string = "TestView"; public templateParent: NgView = null; + public meta: ViewClassMeta = { skipAddToDom: false }; public cssClasses: Map = new Map(); public stringValue: string = "";