Action bar progress

This commit is contained in:
vakrilov
2015-06-10 15:14:28 +03:00
parent e9fa23d845
commit e52b0c4556
38 changed files with 1105 additions and 370 deletions

View File

@@ -3,7 +3,7 @@
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">12.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<TypeScriptToolsVersion>1.4</TypeScriptToolsVersion>
<TypeScriptToolsVersion>1.5</TypeScriptToolsVersion>
<ProjectGuid>{2313F1BF-1F2D-4F11-806A-87927FA6A7C0}</ProjectGuid>
<ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
<OutputType>Library</OutputType>
@@ -71,6 +71,14 @@
<TypeScriptCompile Include="apps\cuteness.unoptimized\reddit-app-view-model.ts" />
<Content Include="apps\cuteness.unoptimized\reddit-item-view-model.ts" />
<TypeScriptCompile Include="apps\cuteness.unoptimized\reddit-model.d.ts" />
<TypeScriptCompile Include="apps\action-bar-demo\app.ts" />
<TypeScriptCompile Include="apps\action-bar-demo\main-page.ts">
<DependentUpon>main-page.xml</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="apps\action-bar-demo\pages\action-items-text.ts" />
<TypeScriptCompile Include="apps\action-bar-demo\pages\navigation-button.ts" />
<TypeScriptCompile Include="apps\action-bar-demo\pages\action-items-icon.ts" />
<TypeScriptCompile Include="apps\action-bar-demo\pages\page-title-icon.ts" />
<TypeScriptCompile Include="apps\gallery-app\views\list-picker.ts">
<DependentUpon>list-picker.xml</DependentUpon>
</TypeScriptCompile>
@@ -391,6 +399,16 @@
<TypeScriptCompile Include="ui\border\border.ts">
<DependentUpon>border.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="ui\action-bar\action-bar-common.ts">
<DependentUpon>action-bar.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="ui\action-bar\action-bar.android.ts">
<DependentUpon>action-bar.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="ui\action-bar\action-bar.d.ts" />
<TypeScriptCompile Include="ui\action-bar\action-bar.ios.ts">
<DependentUpon>action-bar.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="ui\repeater\repeater.ts">
<DependentUpon>repeater.d.ts</DependentUpon>
</TypeScriptCompile>
@@ -657,6 +675,19 @@
<Content Include="apps\cuteness.unoptimized\res\reddit-logo-transparent.png" />
<Content Include="apps\cuteness.unoptimized\res\reddit-logo.png" />
<Content Include="apps\cuteness.unoptimized\res\telerik-logo.png" />
<Content Include="apps\action-bar-demo\app.css" />
<Content Include="apps\action-bar-demo\main-page.xml" />
<Content Include="apps\action-bar-demo\pages\action-items-text.xml">
<SubType>Designer</SubType>
</Content>
<Content Include="apps\action-bar-demo\pages\action-items-icon.xml">
<SubType>Designer</SubType>
</Content>
<Content Include="apps\action-bar-demo\pages\page-title-icon.xml">
<SubType>Designer</SubType>
</Content>
<Content Include="apps\action-bar-demo\pages\navigation-button.xml" />
<Content Include="apps\action-bar-demo\test-icon.png" />
<Content Include="apps\gallery-app\content\border.xml" />
<Content Include="apps\gallery-app\app.css" />
<Content Include="apps\gallery-app\views\list-picker.xml" />
@@ -1600,6 +1631,7 @@
<Content Include="apps\cuteness.unoptimized\package.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="apps\action-bar-demo\package.json" />
<None Include="js-libs\esprima\LICENSE.BSD" />
<Content Include="source-control.md" />
<Content Include="ui\segmented-bar\package.json">
@@ -1623,6 +1655,9 @@
<Content Include="js-libs\reworkcss-value\LICENSE" />
<Content Include="js-libs\reworkcss-value\package.json" />
<Content Include="js-libs\reworkcss-value\Readme.md" />
<Content Include="ui\action-bar\package.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<None Include="build\tslint.json" />

View File

@@ -0,0 +1,13 @@
Page {
background-color: white;
}
ScrollView {
margin: 10;
}
.title {
horizontal-align: center;
font-size: 24;
margin: 6 0;
}

View File

@@ -0,0 +1,7 @@
import application = require("application");
application.mainModule = "main-page";
// Needed only for build infrastructure
application.cssFile = "app.css";
application.start();

View File

@@ -0,0 +1,9 @@
import observable = require("data/observable");
import frame = require("ui/frame");
export function itemTap(args: observable.EventData) {
frame.topmost().navigate({
moduleName: "pages/" + args.object.get("tag"),
});
}

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Page>
<ScrollView>
<StackLayout>
<Button tap="itemTap" text="page title and icon" tag="page-title-icon" />
<Button tap="itemTap" text="navigation button" tag="navigation-button" />
<Button tap="itemTap" text="action items icons" tag="action-items-icon" />
<Button tap="itemTap" text="action items text" tag="action-items-text" />
</StackLayout>
</ScrollView>
</Page>

View File

@@ -0,0 +1,2 @@
{ "name" : "action-bar-demo",
"main" : "app.js" }

View File

@@ -0,0 +1,12 @@
export function leftTap(args) {
console.log("Left item tapped!");
}
export function rightTap(args) {
console.log("Right item tapped!");
}
export function popTap(args) {
console.log("Popup item tapped!");
}

View File

@@ -0,0 +1,14 @@
<Page>
<Page.actionBar>
<ActionBar title="Title">
<ActionBar.actionItems>
<ActionItem tap="leftTap" icon="~/test-icon.png" iosPosition="left"/>
<ActionItem tap="rightTap" icon="~/test-icon.png" iosPosition="right"/>
<ActionItem tap="popTap" icon="res://ic_test" iosPosition="right" androidPosition="popup" text="pop"/>
</ActionBar.actionItems>
</ActionBar>
</Page.actionBar>
<StackLayout>
<Button text="button" />
</StackLayout>
</Page>

View File

@@ -0,0 +1,11 @@
export function leftTap(args) {
console.log("Left item tapped!");
}
export function rightTap(args) {
console.log("Right item tapped!");
}
export function popTap(args) {
console.log("Popup item tapped!");
}

View File

@@ -0,0 +1,14 @@
<Page>
<Page.actionBar>
<ActionBar title="Title">
<ActionBar.actionItems>
<ActionItem text="left" tap="leftTap" iosPosition="left"/>
<ActionItem text="right" tap="rightTap" iosPosition="right"/>
<ActionItem text="pop" tap="popTap" iosPosition="right" androidPosition="popup"/>
</ActionBar.actionItems>
</ActionBar>
</Page.actionBar>
<StackLayout>
<Button text="button" />
</StackLayout>
</Page>

View File

@@ -0,0 +1,46 @@
import observable = require("data/observable");
import pages = require("ui/page");
import action = require("ui/action-bar");
import view = require("ui/core/view");
var i = 0;
export function buttonTap(args: observable.EventData) {
var page = <pages.Page>view.getAncestor(<view.View>args.object, "Page")
var navBtn = new action.NavigationButton();
navBtn.text = "nav " + i++;
if (i % 3 === 0) {
navBtn.icon = "res://ic_test";
}
else if (i % 3 === 1) {
navBtn.icon = "~/test-icon.png";
}
else if (i % 3 === 2) {
// no icon
}
navBtn.on("tap", navTap);
page.actionBar.navigationButton = navBtn;
}
var j = 0;
export function visibilityTap(args: observable.EventData) {
var page = <pages.Page>view.getAncestor(<view.View>args.object, "Page")
if (j % 3 === 0) {
page.actionBar.androidIconVisibility = "always";
}
else if (j % 3 === 1) {
page.actionBar.androidIconVisibility = "never";
}
else if (j % 3 === 2) {
page.actionBar.androidIconVisibility = "auto";
}
j++;
console.log("Visibility changed to: " + page.actionBar.androidIconVisibility);
}
export function navTap(args: observable.EventData) {
console.log("navigation button tapped");
}

View File

@@ -0,0 +1,12 @@
<Page>
<Page.actionBar>
<ActionBar title="Navigation Button">
<NavigationButton text="go back" icon="res://ic_test" tap="navTap"/>
</ActionBar>
</Page.actionBar>
<StackLayout>
<Button text="button" tap="buttonTap"/>
<Button text="change icon visibility" tap="visibilityTap"/>
</StackLayout>
</Page>

View File

@@ -0,0 +1,20 @@
import observable = require("data/observable");
import pages = require("ui/page");
import view = require("ui/core/view");
var i = 0;
export function buttonTap(args: observable.EventData) {
var page = <pages.Page>view.getAncestor(<view.View>args.object, "Page")
page.actionBar.title = "Title changed " + i++;
if (i % 3 === 0) {
page.actionBar.icon = "res://ic_test";
}
else if (i % 3 === 1) {
page.actionBar.icon = "~/test-icon.png";
}
else if (i % 3 === 2) {
page.actionBar.icon = undefined;
}
}

View File

@@ -0,0 +1,8 @@
<Page>
<Page.actionBar>
<ActionBar title="Page Title" icon="res://ic_test"/>
</Page.actionBar>
<StackLayout>
<Button text="button" tap="buttonTap"/>
</StackLayout>
</Page>

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -6,38 +6,38 @@ import frame = require("ui/frame");
export function createPage() {
var page = new pageModule.Page();
var iconItem = new pageModule.MenuItem();
iconItem.text = "TEST";
//var iconItem = new pageModule.MenuItem();
//iconItem.text = "TEST";
iconItem.icon = "~/app" + "/tests" + "/test-icon.png"; // use + to stop regex replace during build
iconItem.on("tap", () => {
console.log("Icon item tapped");
});
page.optionsMenu.addItem(iconItem);
//iconItem.icon = "~/app" + "/tests" + "/test-icon.png"; // use + to stop regex replace during build
//iconItem.on("tap", () => {
// console.log("Icon item tapped");
//});
//page.optionsMenu.addItem(iconItem);
var textItem = new pageModule.MenuItem();
textItem.text = "SAVE";
textItem.on("tap", () => {
console.log("Save item tapped");
});
page.optionsMenu.addItem(textItem);
//var textItem = new pageModule.MenuItem();
//textItem.text = "SAVE";
//textItem.on("tap", () => {
// console.log("Save item tapped");
//});
//page.optionsMenu.addItem(textItem);
var stackLayout = new stackModule.StackLayout();
var count = 0;
//var count = 0;
var btn1 = new buttonModule.Button();
btn1.text = "add item";
btn1.on("tap", () => {
console.log("adding menu item");
//btn1.on("tap", () => {
// console.log("adding menu item");
var newItem = new pageModule.MenuItem();
var text = "item " + count;
newItem.text = text
newItem.on("tap", () => {
console.log("ITEM [" + text + "] tapped");
});
page.optionsMenu.addItem(newItem);
count++;
});
// var newItem = new pageModule.MenuItem();
// var text = "item " + count;
// newItem.text = text
// newItem.on("tap", () => {
// console.log("ITEM [" + text + "] tapped");
// });
// page.optionsMenu.addItem(newItem);
// count++;
//});
stackLayout.addChild(btn1);

View File

@@ -1,20 +1,36 @@
import observable = require("data/observable");
import action = require("ui/action-bar");
import pages = require("ui/page");
var currentPage:pages.Page;
// Event handler for Page "loaded" event attached in main-page.xml
export function pageLoaded(args: observable.EventData) {
// Get the event sender
var page = <pages.Page>args.object;
var textItem = new pages.MenuItem();
currentPage = page;
var textItem = new action.ActionItem();
textItem.text = "from loaded";
textItem.on("tap", () => {
console.log("item added in page.loaded tapped!!!");
});
page.optionsMenu.addItem(textItem);
page.actionBar.actionItems.addItem(textItem);
}
export function optionTap(args) {
console.log("item added form XML tapped!!!");
}
var i = 0;
export function buttonTap(args: observable.EventData) {
currentPage.actionBar.title = "hi " + i++;
if (i % 3 === 0) {
currentPage.actionBar.icon = "res://ic_test";
}
else if (i % 3 === 1) {
currentPage.actionBar.icon = "~/test-icon.png";
}
else if (i % 3 === 2) {
currentPage.actionBar.icon = undefined;
}
}

View File

@@ -1,9 +1,6 @@
<Page loaded="pageLoaded">
<Page.optionsMenu>
<MenuItem text="test" tap="optionTap" android.position="popup" />
<MenuItem text="with icon" tap="optionTap" icon="~/app/test-icon.png" android.position="actionBar" />
</Page.optionsMenu>
<Page loaded="pageLoaded" title="MyPageTitle" icon="res://icon">
<StackLayout>
<Button text="button" />
<Button text="button" tap="buttonTap"/>
</StackLayout>
</Page>

View File

@@ -28,6 +28,7 @@ import stackLayoutModule = require("ui/layouts/stack-layout");
import helper = require("../helper");
import view = require("ui/core/view");
import builder = require("ui/builder");
import actionBar = require("ui/action-bar");
export function addLabelToPage(page: PageModule.Page, text?: string) {
var label = new LabelModule.Label();
@@ -44,14 +45,14 @@ export function test_menuItem_inherit_bindingContext() {
var pageFactory = function (): PageModule.Page {
page = new PageModule.Page();
page.bindingContext = context;
var menuItem = new PageModule.MenuItem();
var menuItem = new actionBar.ActionItem();
menuItem.bind({
sourceProperty: "text",
targetProperty: "text"
});
page.optionsMenu.addItem(menuItem);
page.actionBar.actionItems.addItem(menuItem);
label = new LabelModule.Label();
label.text = "Text";
@@ -62,7 +63,7 @@ export function test_menuItem_inherit_bindingContext() {
helper.navigate(pageFactory);
try {
TKUnit.assertEqual(page.optionsMenu.getItemAt(0).text, "item", "menuItem.text should equal to 'item'");
TKUnit.assertEqual(page.actionBar.actionItems.getItemAt(0).text, "item", "menuItem.text should equal to 'item'");
}
finally {
helper.goBack();
@@ -70,15 +71,15 @@ export function test_menuItem_inherit_bindingContext() {
}
export function test_menuItem_inherit_bindingContext_inXML() {
var p = <PageModule.Page>builder.parse("<Page><Page.optionsMenu><MenuItem text=\"{{ myProp }} \" /></Page.optionsMenu></Page>");
var p = <PageModule.Page>builder.parse("<Page><Page.actionItems><ActionItem text=\"{{ myProp }} \" /></Page.actionItems></Page>");
p.bindingContext = { myProp: "success" };
var menuItem = p.optionsMenu.getItemAt(0);
var menuItem = p.actionBar.actionItems.getItemAt(0);
TKUnit.assertEqual(menuItem.text, "success", "menuItem.text");
};
export function test_Setting_OptionsMenu_doesnt_thrown() {
export function test_Setting_ActionItems_doesnt_thrown() {
var page: PageModule.Page;
var label: LabelModule.Label;
@@ -86,9 +87,9 @@ export function test_Setting_OptionsMenu_doesnt_thrown() {
var pageFactory = function (): PageModule.Page {
page = new PageModule.Page();
var menuItem = new PageModule.MenuItem();
var menuItem = new actionBar.ActionItem();
menuItem.text = "Item";
page.optionsMenu.addItem(menuItem);
page.actionBar.actionItems.addItem(menuItem);
label = new LabelModule.Label();
label.text = "Text";

View File

@@ -4,6 +4,7 @@ import TKUnit = require("../../TKUnit");
import LabelModule = require("ui/label");
import helper = require("../helper");
import view = require("ui/core/view");
import actionBar = require("ui/action-bar");
declare var exports;
require("utils/module-merge").merge(PageTestCommon, exports);
@@ -41,9 +42,9 @@ export function test_NavBar_isVisible_when_MenuItems_areSet() {
page = new PageModule.Page();
page.on(PageModule.Page.navigatedToEvent, handler);
var mi = new PageModule.MenuItem();
var mi = new actionBar.ActionItem();
mi.text = "B";
page.optionsMenu.addItem(mi);
page.actionBar.actionItems.addItem(mi);
label = new LabelModule.Label();
label.text = "Text";
page.content = label;
@@ -67,10 +68,10 @@ export function test_NavBarItemsAreClearedFromNativeWhenClearedFromNativeScript(
var handler = function (data) {
page.off(PageModule.Page.navigatedToEvent, handler);
var menuItems = page.optionsMenu.getItems();
var menuItems = page.actionBar.actionItems.getItems();
var i;
for (i = menuItems.length - 1; i >= 0; i--) {
page.optionsMenu.removeItem(menuItems[i]);
page.actionBar.actionItems.removeItem(menuItems[i]);
}
}
@@ -78,9 +79,9 @@ export function test_NavBarItemsAreClearedFromNativeWhenClearedFromNativeScript(
page = new PageModule.Page();
page.on(PageModule.Page.navigatedToEvent, handler);
var mi = new PageModule.MenuItem();
var mi = new actionBar.ActionItem();
mi.text = "B";
page.optionsMenu.addItem(mi);
page.actionBar.actionItems.addItem(mi);
label = new LabelModule.Label();
label.text = "Text";
page.content = label;

View File

@@ -0,0 +1,286 @@
import dts = require("ui/action-bar");
import pages = require("ui/page");
import bindable = require("ui/core/bindable");
import dependencyObservable = require("ui/core/dependency-observable");
import enums = require("ui/enums");
import proxy = require("ui/core/proxy");
var ACTION_ITEMS = "actionItems";
export module knownCollections {
export var actionItems = "actionItems";
}
function onTitlePropertyChanged(data: dependencyObservable.PropertyChangeData) {
var actionBar = <ActionBar>data.object;
actionBar._onTitlePropertyChanged();
}
function onIconPropertyChanged(data: dependencyObservable.PropertyChangeData) {
var actionBar = <ActionBar>data.object;
actionBar._onIconPropertyChanged();
}
export class ActionBar extends bindable.Bindable implements dts.ActionBar {
public static titleProperty = new dependencyObservable.Property("title", "ActionBar", new proxy.PropertyMetadata(undefined, dependencyObservable.PropertyMetadataSettings.None, onTitlePropertyChanged));
public static iconProperty = new dependencyObservable.Property("icon", "ActionBar", new proxy.PropertyMetadata(undefined, dependencyObservable.PropertyMetadataSettings.None, onIconPropertyChanged));
public static androidIconVisibilityProperty = new dependencyObservable.Property("androidIconVisibility", "ActionBar", new proxy.PropertyMetadata("auto", dependencyObservable.PropertyMetadataSettings.None, onIconPropertyChanged));
private _actionItems: ActionItems;
private _navigationButton: NavigationButton;
private _page: pages.Page;
get title(): string {
return this._getValue(ActionBar.titleProperty);
}
set title(value: string) {
this._setValue(ActionBar.titleProperty, value);
}
get icon(): string {
return this._getValue(ActionBar.iconProperty);
}
set icon(value: string) {
this._setValue(ActionBar.iconProperty, value);
}
get androidIconVisibility(): string {
return this._getValue(ActionBar.androidIconVisibilityProperty);
}
set androidIconVisibility(value: string) {
this._setValue(ActionBar.androidIconVisibilityProperty, value);
}
get navigationButton(): NavigationButton {
return this._navigationButton;
}
set navigationButton(value: NavigationButton) {
if (this._navigationButton !== value) {
if (this._navigationButton) {
detachActionItem(this._navigationButton);
}
this._navigationButton = value;
if (this._navigationButton) {
attachActionItem(this._navigationButton, this);
}
this.updateActionBar();
}
}
get actionItems(): ActionItems {
return this._actionItems;
}
set actionItems(value: ActionItems) {
throw new Error("actionItems property is read-only");
}
get page(): pages.Page {
return this._page;
}
set page(value: pages.Page) {
this._page = value;
this.unbind("bindingContext");
this.bind({
sourceProperty: "bindingContext",
targetProperty: "bindingContext"
}, this._page);
}
constructor() {
super();
this._actionItems = new ActionItems(this);
}
public static onTitleChanged
public updateActionBar() {
//
}
public _onTitlePropertyChanged() {
//
}
public _onIconPropertyChanged() {
//
}
public _updateAndroidActionBar(menu: android.view.IMenu) {
//
}
public _onAndroidItemSelected(itemId: number): boolean {
return false;
}
public _addArrayFromBuilder(name: string, value: Array<any>) {
if (name === ACTION_ITEMS) {
this.actionItems.setItems(value);
}
}
public _addChildFromBuilder(name: string, value: any) {
if (value instanceof NavigationButton) {
this.navigationButton = value;
}
}
public shouldShow(): boolean {
if (this.title ||
this.icon ||
this.navigationButton ||
this.actionItems.getItems().length > 0) {
return true;
}
return false;
}
}
export class ActionItems implements dts.ActionItems {
private _items: Array<ActionItem> = new Array<ActionItem>();
private _actionBar: ActionBar;
constructor(actionBar: ActionBar) {
this._actionBar = actionBar;
}
public addItem(item: ActionItem): void {
if (!item) {
throw new Error("Cannot add empty item");
}
this._items.push(item);
attachActionItem(item, this._actionBar);
this.invalidate();
}
public removeItem(item: ActionItem): void {
if (!item) {
throw new Error("Cannot remove empty item");
}
var itemIndex = this._items.indexOf(item);
if (itemIndex < 0) {
throw new Error("Cannot find item to remove");
}
detachActionItem(item);
this._items.splice(itemIndex, 1);
this.invalidate();
}
public getItems(): Array<ActionItem> {
return this._items.slice();
}
public getItemAt(index: number): ActionItem {
if (index < 0 || index >= this._items.length) {
return undefined;
}
return this._items[index];
}
public setItems(items: Array<ActionItem>) {
// Remove all existing items
while (this._items.length > 0) {
this.removeItem(this._items[this._items.length - 1]);
}
// Add new items
for (var i = 0; i < items.length; i++) {
this.addItem(items[i]);
}
this.invalidate();
}
private invalidate() {
if (this._actionBar) {
this._actionBar.updateActionBar();
}
}
}
export class ActionItemBase extends bindable.Bindable implements dts.ActionItemBase {
public static tapEvent = "tap";
public static textProperty = new dependencyObservable.Property(
"text", "ActionItemBase", new dependencyObservable.PropertyMetadata("", null, ActionItemBase.onItemChanged));
public static iconProperty = new dependencyObservable.Property(
"icon", "ActionItemBase", new dependencyObservable.PropertyMetadata(null, null, ActionItemBase.onItemChanged));
private static onItemChanged(data: dependencyObservable.PropertyChangeData) {
var menuItem = <ActionItem>data.object;
if (menuItem.actionBar) {
menuItem.actionBar.updateActionBar();
}
}
get text(): string {
return this._getValue(ActionItemBase.textProperty);
}
set text(value: string) {
this._setValue(ActionItemBase.textProperty, value);
}
get icon(): string {
return this._getValue(ActionItemBase.iconProperty);
}
set icon(value: string) {
this._setValue(ActionItemBase.iconProperty, value);
}
public _raiseTap() {
this._emit(ActionItem.tapEvent);
}
actionBar: ActionBar;
}
export class ActionItem extends ActionItemBase {
private _androidPosition: string = enums.AndroidActionItemPosition.actionBar;
private _iosPosition: string = enums.IOSActionItemPosition.right;
get androidPosition(): string {
return this._androidPosition;
}
set androidPosition(value: string) {
this._androidPosition = value;
}
get iosPosition(): string {
return this._iosPosition;
}
set iosPosition(value: string) {
this._iosPosition = value;
}
}
export class NavigationButton extends ActionItemBase {
}
function attachActionItem(item: ActionItemBase, bar: ActionBar) {
item.actionBar = this._actionBar;
item.bind({
sourceProperty: "bindingContext",
targetProperty: "bindingContext"
}, this._actionBar);
}
function detachActionItem(item: ActionItemBase) {
item.actionBar = undefined;
item.unbind("bindingContext");
}

View File

@@ -0,0 +1,219 @@
import common = require("ui/action-bar/action-bar-common");
import trace = require("trace");
import frame = require("ui/frame");
import types = require("utils/types");
import utils = require("utils/utils");
import imageSource = require("image-source");
import enums = require("ui/enums");
import application = require("application");
var ACTION_ITEM_ID_OFFSET = 1000;
var API_LVL = android.os.Build.VERSION.SDK_INT;
declare var exports;
require("utils/module-merge").merge(common, exports);
export class ActionBar extends common.ActionBar {
private _appResources: android.content.res.Resources;
constructor() {
super();
this._appResources = application.android.context.getResources();
this.actionItems
}
public updateActionBar() {
if (this.page && this.page.frame && this.page.frame.android && this.page.frame.android.activity) {
this.page.frame.android.activity.invalidateOptionsMenu();
}
}
public _onAndroidItemSelected(itemId: number): boolean{
var menuItem = this.actionItems.getItemAt(itemId - ACTION_ITEM_ID_OFFSET);
if (menuItem) {
menuItem._raiseTap();
return true;
}
if (this.navigationButton && itemId === (<any>android).R.id.home) {
this.navigationButton._raiseTap();
return true;
}
return false;
}
public _updateAndroidActionBar(menu: android.view.IMenu) {
var actionBar: android.app.ActionBar = frame.topmost().android.actionBar;
this._addActionItems(menu);
// Set title
this._updateTitle(actionBar);
// Set home icon
this._updateIcon(actionBar);
// Set navigation button
this._updateNavigationButton(actionBar);
}
public _updateNavigationButton(actionBar: android.app.ActionBar) {
var navButton = this.navigationButton;
if (navButton) {
// No API to set the icon in pre-lvl 18
if (API_LVL >= 18) {
try {
// TODO: Find a better way to set the icon instead of using reflection
var drawableOrId = getDrawableOrResourceId(navButton.icon, this._appResources);
if (!drawableOrId) {
drawableOrId = 0;
}
var arr, arr2, method;
if (types.isNumber(drawableOrId)) {
arr[0] = java.lang.Integer.TYPE;
method = actionBar.getClass().getMethod("setHomeAsUpIndicator", arr);
arr2 = java.lang.reflect.Array.newInstance(java.lang.Object.class, 1);
arr2[0] = new java.lang.Integer(drawableOrId);
method.invoke(actionBar, arr2);
} else {
arr = java.lang.reflect.Array.newInstance(java.lang.Class.class, 1);
arr[0] = android.graphics.drawable.Drawable.class;
method = actionBar.getClass().getMethod("setHomeAsUpIndicator", arr);
arr2 = java.lang.reflect.Array.newInstance(java.lang.Object.class, 1);
arr2[0] = drawableOrId;
method.invoke(actionBar, arr2);
}
}
catch (e) {
trace.write("Failed to set navigation icon: " + e, trace.categories.Error, trace.messageType.error);
}
}
actionBar.setDisplayHomeAsUpEnabled(true);
}
else {
actionBar.setDisplayHomeAsUpEnabled(false);
}
}
public _updateIcon(actionBar: android.app.ActionBar) {
var icon = this.icon;
if (types.isDefined(icon)) {
var drawableOrId = getDrawableOrResourceId(icon, this._appResources);
if (drawableOrId) {
actionBar.setIcon(drawableOrId);
}
}
else {
var defaultIcon = application.android.nativeApp.getApplicationInfo().icon;
actionBar.setIcon(defaultIcon);
}
var iconVisibility: boolean;
if (this.androidIconVisibility === enums.AndroidActionBarIconVisibility.always) {
iconVisibility = true;
}
var visibility = getIconVisibility(this.androidIconVisibility);
actionBar.setDisplayShowHomeEnabled(visibility);
}
public _updateTitle(actionBar: android.app.ActionBar) {
var title = this.title;
if (types.isDefined(title)) {
actionBar.setTitle(title);
} else {
var defaultLabel = application.android.nativeApp.getApplicationInfo().labelRes;
actionBar.setTitle(defaultLabel);
}
}
public _addActionItems(menu: android.view.IMenu) {
var items = this.actionItems.getItems();
for (var i = 0; i < items.length; i++) {
var item = items[i];
var menuItem = menu.add(android.view.Menu.NONE, i + ACTION_ITEM_ID_OFFSET, android.view.Menu.NONE, item.text);
if (item.icon) {
var drawableOrId = getDrawableOrResourceId(item.icon, this._appResources);
if (drawableOrId) {
menuItem.setIcon(drawableOrId);
}
}
var showAsAction = getShowAsAction(item);
menuItem.setShowAsAction(showAsAction);
}
}
public _onTitlePropertyChanged() {
if (frame.topmost().currentPage === this.page) {
this._updateTitle(frame.topmost().android.actionBar);
}
}
public _onIconPropertyChanged() {
if (frame.topmost().currentPage === this.page) {
this._updateIcon(frame.topmost().android.actionBar);
}
}
}
function getDrawableOrResourceId(icon: string, resources: android.content.res.Resources): any {
if (!types.isString(icon)) {
return undefined;
}
if (icon.indexOf(utils.RESOURCE_PREFIX) === 0) {
var resourceId: number = resources.getIdentifier(icon.substr(utils.RESOURCE_PREFIX.length), 'drawable', application.android.packageName);
if (resourceId > 0) {
return resourceId;
}
}
else {
var drawable: android.graphics.drawable.BitmapDrawable;
var is = imageSource.fromFileOrResource(icon);
if (is) {
drawable = new android.graphics.drawable.BitmapDrawable(is.android);
}
return drawable;
}
return undefined;
}
function getShowAsAction(menuItem: common.ActionItem): number {
switch (menuItem.androidPosition) {
case enums.AndroidActionItemPosition.actionBarIfRoom:
return android.view.MenuItem.SHOW_AS_ACTION_IF_ROOM;
case enums.AndroidActionItemPosition.popup:
return android.view.MenuItem.SHOW_AS_ACTION_NEVER;
case enums.AndroidActionItemPosition.actionBar:
default:
return android.view.MenuItem.SHOW_AS_ACTION_ALWAYS;
}
}
function getIconVisibility(iconVisibility: string): boolean {
switch (iconVisibility) {
case enums.AndroidActionBarIconVisibility.always:
return true;
case enums.AndroidActionBarIconVisibility.never:
return false;
case enums.AndroidActionBarIconVisibility.auto:
default:
return API_LVL <= 20;
}
}

84
ui/action-bar/action-bar.d.ts vendored Normal file
View File

@@ -0,0 +1,84 @@
declare module "ui/action-bar" {
import observable = require("data/observable");
import view = require("ui/core/view");
import dependencyObservable = require("ui/core/dependency-observable");
import bindable = require("ui/core/bindable");
import pages = require("ui/page");
export class ActionBar extends bindable.Bindable implements view.AddArrayFromBuilder, view.AddChildFromBuilder {
title: string;
icon: string;
androidIconVisibility: string;
navigationButton: NavigationButton;
actionItems: ActionItems;
page: pages.Page;
shouldShow(): boolean
updateActionBar();
//@private
_updateAndroidActionBar(menu: android.view.IMenu);
_onAndroidItemSelected(itemId: number): boolean
_addArrayFromBuilder(name: string, value: Array<any>): void;
_addChildFromBuilder(name: string, value: any): void;
//@endprivate
}
export class ActionItems {
addItem(item: ActionItem): void;
removeItem(item: ActionItem): void;
getItems(): Array<ActionItem>;
getItemAt(index: number): ActionItem;
}
export class ActionItemBase extends bindable.Bindable {
/**
* String value used when hooking to tap event.
*/
public static tapEvent: string;
/**
* Represents the observable property backing the text property.
*/
public static textProperty: dependencyObservable.Property;
/**
* Represents the observable property backing the icon property.
*/
public static iconProperty: dependencyObservable.Property;
text: string;
icon: string;
/**
* A basic method signature to hook an event listener (shortcut alias to the addEventListener method).
* @param eventNames - String corresponding to events (e.g. "propertyChange"). Optionally could be used more events separated by `,` (e.g. "propertyChange", "change").
* @param callback - Callback function which will be executed when event is raised.
* @param thisArg - An optional parameter which will be used as `this` context for callback execution.
*/
on(eventNames: string, callback: (data: observable.EventData) => void);
/**
* Raised when a tap event occurs.
*/
on(event: "tap", callback: (args: observable.EventData) => void);
//@private
_raiseTap(): void;
//@endprivate
}
export class ActionItem extends ActionItemBase {
androidPosition: string;
iosPosition: string;
}
export class NavigationButton extends ActionItemBase {
}
}

View File

@@ -0,0 +1,140 @@
import common = require("ui/action-bar/action-bar-common");
import definition = require("ui/action-bar");
import imageSource = require("image-source");
import frameModule = require("ui/frame");
import enums = require("ui/enums");
declare var exports;
require("utils/module-merge").merge(common, exports);
export class ActionBar extends common.ActionBar {
public updateActionBar() {
// Page should be attached to frame to update the action bar.
if (!(this.page && this.page.parent)) {
return;
}
var viewController = (<UIViewController>this.page.ios);
var navigationItem: UINavigationItem = viewController.navigationItem;
var navController = frameModule.topmost().ios.controller;
var navigationBar = navController.navigationBar;
var previousController: UIViewController;
// Set Title
navigationItem.title = this.title;
// Find previous ViewController in the navigation stack
var indexOfViewController = navController.viewControllers.indexOfObject(viewController);
if (indexOfViewController !== NSNotFound && indexOfViewController > 0) {
previousController = navController.viewControllers[indexOfViewController - 1];
}
// Set back button text
if (previousController) {
if (this.navigationButton) {
var tapHandler = TapBarItemHandlerImpl.new().initWithOwner(this.navigationButton);
var barButtonItem = UIBarButtonItem.alloc().initWithTitleStyleTargetAction(this.navigationButton.text, UIBarButtonItemStyle.UIBarButtonItemStylePlain, tapHandler, "tap");
previousController.navigationItem.backBarButtonItem = barButtonItem;
}
else {
previousController.navigationItem.backBarButtonItem = null;
}
}
// Set back button image
var img: imageSource.ImageSource;
if (this.navigationButton && this.navigationButton.icon) {
img = imageSource.fromFileOrResource(this.navigationButton.icon);
}
if (img && img.ios) {
var image = img.ios.imageWithRenderingMode(UIImageRenderingMode.UIImageRenderingModeAlwaysOriginal)
navigationBar.backIndicatorImage = image;
navigationBar.backIndicatorTransitionMaskImage = image;
}
else {
navigationBar.backIndicatorImage = null;
navigationBar.backIndicatorTransitionMaskImage = null;
}
// Populate action items
this.populateMenuItems(navigationItem);
}
private populateMenuItems(navigationItem: UINavigationItem) {
var items = this.actionItems.getItems();
var leftBarItems = [];
var rightBarItems = [];
for (var i = 0; i < items.length; i++) {
var barButtonItem = this.createBarButtonItem(items[i]);
if (items[i].iosPosition === enums.IOSActionItemPosition.left) {
leftBarItems.push(barButtonItem);
}
else {
rightBarItems.push(barButtonItem);
}
}
var leftArray: NSMutableArray = leftBarItems.length > 0 ? NSMutableArray.new() : null;
leftBarItems.forEach((barItem, i, a) => leftArray.addObject(barItem));
// Right items should be added in reverse because they are added from right to left
var rightArray: NSMutableArray = rightBarItems.length > 0 ? NSMutableArray.new() : null;
rightBarItems.reverse();
rightBarItems.forEach((barItem, i, a) => rightArray.addObject(barItem));
navigationItem.leftItemsSupplementBackButton = true;
navigationItem.setLeftBarButtonItemsAnimated(leftArray, true);
navigationItem.setRightBarButtonItemsAnimated(rightArray, true);
}
private createBarButtonItem(item: common.ActionItemBase): UIBarButtonItem {
var tapHandler = TapBarItemHandlerImpl.new().initWithOwner(item);
// associate handler with menuItem or it will get collected by JSC.
(<any>item).handler = tapHandler;
var barButtonItem: UIBarButtonItem;
if (item.icon) {
var img = imageSource.fromFileOrResource(item.icon);
if (img && img.ios) {
barButtonItem = UIBarButtonItem.alloc().initWithImageStyleTargetAction(img.ios, UIBarButtonItemStyle.UIBarButtonItemStylePlain, tapHandler, "tap");
}
}
else {
barButtonItem = UIBarButtonItem.alloc().initWithTitleStyleTargetAction(item.text, UIBarButtonItemStyle.UIBarButtonItemStylePlain, tapHandler, "tap");
}
return barButtonItem;
}
public _onTitlePropertyChanged() {
if (!this.page) {
return;
}
var navigationItem: UINavigationItem = (<UIViewController>this.page.ios).navigationItem;
navigationItem.title = this.title;
}
}
class TapBarItemHandlerImpl extends NSObject {
static new(): TapBarItemHandlerImpl {
return <TapBarItemHandlerImpl>super.new();
}
private _owner: definition.ActionItemBase;
public initWithOwner(owner: definition.ActionItemBase): TapBarItemHandlerImpl {
this._owner = owner;
return this;
}
public tap(args) {
this._owner._raiseTap();
}
public static ObjCExposedMethods = {
"tap": { returns: interop.types.void, params: [interop.types.id] }
};
}

View File

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

View File

@@ -312,7 +312,7 @@ function isKnownCollection(name: string, context: any): boolean {
return KNOWNCOLLECTIONS in context && context[KNOWNCOLLECTIONS] && name in context[KNOWNCOLLECTIONS];
}
function addToComplexProperty(parent: componentBuilder.ComponentModule, complexProperty, elementModule: componentBuilder.ComponentModule) {
function addToComplexProperty(parent: componentBuilder.ComponentModule, complexProperty: 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)) {

View File

@@ -38,7 +38,9 @@ var MODULES = {
"TimePicker": "ui/time-picker",
"DatePicker": "ui/date-picker",
"ListPicker": "ui/list-picker",
"MenuItem": "ui/page",
"ActionBar": "ui/action-bar",
"ActionItem": "ui/action-bar",
"NavigationButton": "ui/action-bar",
};
var ROW = "row";

View File

@@ -8,7 +8,7 @@ declare module "ui/content-view" {
* Represents a View that has a single child - content.
* The View itself does not have visual representation and serves as a placeholder for its content in the logical tree.
*/
class ContentView extends view.View {
class ContentView extends view.View implements view.AddChildFromBuilder {
/**
* Gets or sets the single child of the view.
*/
@@ -21,6 +21,8 @@ declare module "ui/content-view" {
* @param newView The new content.
*/
_onContentChanged(oldView: view.View, newView: view.View);
_addChildFromBuilder(name: string, value: any): void;
//@endprivate
}
}

2
ui/core/proxy.d.ts vendored
View File

@@ -53,7 +53,7 @@
public _onPropertyChangedFromNative(property: dependencyObservable.Property, newValue: any): void;
/**
* Syncronizes all properties with native values.
* Synchronizes all properties with native values.
*/
public _syncNativeProperties(): void;
}

27
ui/enums/enums.d.ts vendored
View File

@@ -351,10 +351,19 @@
export var always: string;
}
/**
* Specifies the visibility of the application bar icon
*/
export module AndroidActionBarIconVisibility {
export var auto: string;
export var never: string;
export var always: string;
}
/**
* Specifies android MenuItem position.
*/
module MenuItemPosition {
module AndroidActionItemPosition {
/**
* Always show this item as a button in an Action Bar.
*/
@@ -402,7 +411,6 @@
export var bold: string;
}
/**
* Specifies background repeat.
*/
@@ -412,4 +420,19 @@
export var repeatY: string;
export var noRepeat: string;
}
/**
* Specifies android MenuItem position.
*/
module IOSActionItemPosition {
/**
* Show this item at the left of the navigation bar.
*/
export var left: string;
/**
* Show this item at the right of the action bar.
*/
export var right: string;
}
}

View File

@@ -93,12 +93,23 @@ export module NavigationBarVisibility {
export var always: string = "always";
}
export module MenuItemPosition {
export module AndroidActionBarIconVisibility {
export var auto: string = "auto";
export var never: string = "never";
export var always: string = "always";
}
export module AndroidActionItemPosition {
export var actionBar: string = "actionBar";
export var actionBarIfRoom: string = "actionBarIfRoom";
export var popup: string = "popup";
}
export module IOSActionItemPosition {
export var left: string = "left";
export var right: string = "right";
}
export module ImageFormat {
export var png: string = "png";
export var jpeg: string = "jpeg";
@@ -119,4 +130,4 @@ export module BackgroundRepeat {
export var repeatX: string = "repeat-x";
export var repeatY: string = "repeat-y";
export var noRepeat: string = "no-repeat";
}
}

View File

@@ -6,7 +6,6 @@ import observable = require("data/observable");
import utils = require("utils/utils");
import view = require("ui/core/view");
import application = require("application");
import enums = require("ui/enums");
declare var exports;
require("utils/module-merge").merge(frameCommon, exports);
@@ -140,49 +139,18 @@ class PageFragmentBody extends android.app.Fragment {
super.onCreateOptionsMenu(menu, inflater);
var page: pages.Page = this.entry.resolvedPage;
var items = page.optionsMenu.getItems();
for (var i = 0; i < items.length; i++) {
var item = items[i];
var menuItem = menu.add(android.view.Menu.NONE, i, android.view.Menu.NONE, item.text);
if (item.icon) {
var androidApp = application.android;
var res = androidApp.context.getResources();
var id = res.getIdentifier(item.icon, 'drawable', androidApp.packageName);
if (id) {
menuItem.setIcon(id);
}
}
var showAsAction = PageFragmentBody.getShowAsAction(item);
menuItem.setShowAsAction(showAsAction);
}
}
private static getShowAsAction(menuItem: pages.MenuItem): number {
switch (menuItem.android.position) {
case enums.MenuItemPosition.actionBarIfRoom:
return android.view.MenuItem.SHOW_AS_ACTION_IF_ROOM;
case enums.MenuItemPosition.popup:
return android.view.MenuItem.SHOW_AS_ACTION_NEVER;
case enums.MenuItemPosition.actionBar:
default:
return android.view.MenuItem.SHOW_AS_ACTION_ALWAYS;
}
page.actionBar._updateAndroidActionBar(menu);
}
onOptionsItemSelected(item: android.view.IMenuItem) {
var page: pages.Page = this.entry.resolvedPage;
var itemId = item.getItemId();
var menuItem = page.optionsMenu.getItemAt(itemId);
if (menuItem) {
menuItem._raiseTap();
if (page.actionBar._onAndroidItemSelected(itemId)) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
@@ -696,4 +664,5 @@ function startActivity(activity: android.app.Activity, entry: definition.Navigat
intent.setAction(android.content.Intent.ACTION_DEFAULT);
// TODO: Put the navigation context (if any) in the intent
activity.startActivity(intent);
}
}

View File

@@ -84,7 +84,7 @@ export class Frame extends frameCommon.Frame {
case enums.NavigationBarVisibility.auto:
var pageInstance: pages.Page = page || this.currentPage;
newValue = this.backStack.length > 0 || (pageInstance && pageInstance.optionsMenu.getItems().length > 0);
newValue = this.backStack.length > 0 || (pageInstance && pageInstance.actionBar.shouldShow());
newValue = !!newValue; // Make sure it is boolean
break;
}
@@ -191,11 +191,12 @@ class UINavigationControllerImpl extends UINavigationController implements UINav
}
frame._addView(newPage);
newPage._invalidateOptionsMenu();
}
else if (newPage.parent !== frame) {
throw new Error("Page is already shown on another frame.");
}
newPage.actionBar.updateActionBar();
}
public navigationControllerDidShowViewControllerAnimated(navigationController: UINavigationController, viewController: UIViewController, animated: boolean): void {
@@ -227,6 +228,8 @@ class UINavigationControllerImpl extends UINavigationController implements UINav
frame._currentEntry = newEntry;
frame.updateNavigationBar();
frame.ios.controller.navigationBar.backIndicatorImage
var newPage = newEntry.resolvedPage;
// notify the page

View File

@@ -39,7 +39,7 @@ function onSrcPropertyChanged(data: dependencyObservable.PropertyChangeData) {
}
}
else if (value instanceof imageSource.ImageSource) {
// Support binding the imageSource trough the src propoerty
// Support binding the imageSource trough the src property
image.imageSource = value;
}
else {

View File

@@ -5,10 +5,9 @@ import frame = require("ui/frame");
import styleScope = require("ui/styling/style-scope");
import fs = require("file-system");
import fileSystemAccess = require("file-system/file-system-access");
import bindable = require("ui/core/bindable");
import dependencyObservable = require("ui/core/dependency-observable");
import enums = require("ui/enums");
import frameCommon = require("ui/frame/frame-common");
import actionBar = require("ui/action-bar");
import dependencyObservable = require("ui/core/dependency-observable");
import proxy = require("ui/core/proxy");
var OPTIONS_MENU = "optionsMenu";
@@ -28,11 +27,7 @@ function onNavigationBarHiddenPropertyChanged(data: dependencyObservable.Propert
(<proxy.PropertyMetadata>navigationBarHiddenProperty.metadata).onSetNativeValue = onNavigationBarHiddenPropertyChanged;
export module knownCollections {
export var optionsMenu = "optionsMenu";
}
export class Page extends contentView.ContentView implements dts.Page, view.AddArrayFromBuilder {
export class Page extends contentView.ContentView implements dts.Page {
public static navigationBarHiddenProperty = navigationBarHiddenProperty;
public static navigatingToEvent = "navigatingTo";
public static navigatedToEvent = "navigatedTo";
@@ -44,11 +39,11 @@ export class Page extends contentView.ContentView implements dts.Page, view.AddA
private _cssApplied: boolean;
private _styleScope: styleScope.StyleScope = new styleScope.StyleScope();
private _optionsMenu: OptionsMenu;
private _actionBar: actionBar.ActionBar;
constructor(options?: dts.Options) {
super(options);
this._optionsMenu = new OptionsMenu(this);
this.actionBar = new actionBar.ActionBar();
}
public onLoaded() {
@@ -88,11 +83,21 @@ export class Page extends contentView.ContentView implements dts.Page, view.AddA
this._refreshCss();
}
get optionsMenu(): OptionsMenu {
return this._optionsMenu;
get actionBar(): actionBar.ActionBar {
return this._actionBar;
}
set optionsMenu(value: OptionsMenu) {
throw new Error("optionsMenu property is read-only");
set actionBar(value: actionBar.ActionBar) {
if (!value) {
throw new Error("ActionBar cannot be null or undefined.");
}
if (this._actionBar !== value) {
if (this._actionBar) {
this._actionBar.page = undefined;
}
this._actionBar = value;
this._actionBar.page = this;
}
}
private _refreshCss(): void {
@@ -175,6 +180,15 @@ export class Page extends contentView.ContentView implements dts.Page, view.AddA
(<Page>page)._showNativeModalView(this, context, closeCallback, fullscreen);
}
public _addChildFromBuilder(name: string, value: any) {
if (value instanceof actionBar.ActionBar) {
this.actionBar = value;
}
else {
super._addChildFromBuilder(name, value);
}
}
protected _showNativeModalView(parent: Page, context: any, closeCallback: Function, fullscreen?: boolean) {
//
}
@@ -202,10 +216,6 @@ export class Page extends contentView.ContentView implements dts.Page, view.AddA
return this._styleScope;
}
public _invalidateOptionsMenu() {
//
}
private _applyCss() {
if (this._cssApplied) {
return;
@@ -233,133 +243,5 @@ export class Page extends contentView.ContentView implements dts.Page, view.AddA
resetCssValuesFunc(this);
view.eachDescendant(this, resetCssValuesFunc);
}
public _addArrayFromBuilder(name: string, value: Array<any>) {
if (name === OPTIONS_MENU) {
this.optionsMenu.setItems(value);
}
}
}
export class OptionsMenu implements dts.OptionsMenu {
private _items: Array<MenuItem> = new Array<MenuItem>();
private _page: Page;
constructor(page: Page) {
this._page = page;
}
public addItem(item: MenuItem): void {
if (!item) {
throw new Error("Cannot add empty item");
}
this._items.push(item);
item.menu = this;
item.bind({
sourceProperty: "bindingContext",
targetProperty: "bindingContext"
}, this._page);
this.invalidate();
}
public removeItem(item: MenuItem): void {
if (!item) {
throw new Error("Cannot remove empty item");
}
var itemIndex = this._items.indexOf(item);
if (itemIndex < 0) {
throw new Error("Cannot find item to remove");
}
item.menu = undefined;
item.unbind("bindingContext");
this._items.splice(itemIndex, 1);
this.invalidate();
}
public getItems(): Array<MenuItem> {
return this._items.slice();
}
public getItemAt(index: number): MenuItem {
return this._items[index];
}
public setItems(items: Array<MenuItem>) {
// Remove all existing items
while (this._items.length > 0) {
this.removeItem(this._items[this._items.length - 1]);
}
// Add new items
for (var i = 0; i < items.length; i++) {
this.addItem(items[i]);
}
this.invalidate();
}
invalidate() {
if (this._page) {
this._page._invalidateOptionsMenu();
}
}
}
export class MenuItem extends bindable.Bindable implements dts.MenuItem {
public static tapEvent = "tap";
public static textProperty = new dependencyObservable.Property(
"text", "MenuItem", new dependencyObservable.PropertyMetadata("", null, MenuItem.onItemChanged));
public static iconProperty = new dependencyObservable.Property(
"icon", "MenuItem", new dependencyObservable.PropertyMetadata(null, null, MenuItem.onItemChanged));
private static onItemChanged(data: dependencyObservable.PropertyChangeData) {
var menuItem = <MenuItem>data.object;
if (menuItem.menu) {
menuItem.menu.invalidate();
}
}
private _android: dts.AndroidMenuItemOptions;
constructor() {
super();
if (global.android) {
this._android = {
position: enums.MenuItemPosition.actionBar
};
}
}
get android(): dts.AndroidMenuItemOptions {
return this._android;
}
get text(): string {
return this._getValue(MenuItem.textProperty);
}
set text(value: string) {
this._setValue(MenuItem.textProperty, value);
}
get icon(): string {
return this._getValue(MenuItem.iconProperty);
}
set icon(value: string) {
this._setValue(MenuItem.iconProperty, value);
}
public _raiseTap() {
this._emit(MenuItem.tapEvent);
}
menu: OptionsMenu;
}

View File

@@ -26,13 +26,12 @@ class DialogFragmentClass extends android.app.DialogFragment {
window.setBackgroundDrawable(new android.graphics.drawable.ColorDrawable(android.graphics.Color.TRANSPARENT));
if (this._fullscreen) {
window.setLayout(android.view.ViewGroup.LayoutParams.FILL_PARENT, android.view.ViewGroup.LayoutParams.FILL_PARENT);
window.setLayout(android.view.ViewGroup.LayoutParams.FILL_PARENT, android.view.ViewGroup.LayoutParams.FILL_PARENT);
}
return dialog;
}
};
export class Page extends pageCommon.Page {
private _isBackNavigation = false;
@@ -57,12 +56,6 @@ export class Page extends pageCommon.Page {
super.onNavigatedFrom(isBackNavigation);
}
public _invalidateOptionsMenu() {
if (this.frame && this.frame.android && this.frame.android.activity) {
this.frame.android.activity.invalidateOptionsMenu();
}
}
/* tslint:disable */
private _dialogFragment: DialogFragmentClass;
/* tslint:enable */

70
ui/page/page.d.ts vendored
View File

@@ -6,8 +6,8 @@ declare module "ui/page" {
import view = require("ui/core/view");
import contentView = require("ui/content-view");
import frame = require("ui/frame");
import actionBar = require("ui/action-bar");
import dependencyObservable = require("ui/core/dependency-observable");
import bindable = require("ui/core/bindable");
//@private
import styleScope = require("ui/styling/style-scope");
@@ -18,7 +18,7 @@ declare module "ui/page" {
*/
export interface NavigatedData extends observable.EventData {
/**
* The navigation context (optional, may be undefined) passed to the page navigation evetns method.
* The navigation context (optional, may be undefined) passed to the page navigation events method.
*/
context: any;
}
@@ -39,13 +39,13 @@ declare module "ui/page" {
}
export module knownCollections {
export var optionsMenu: string;
export var actionItems: string;
}
/**
* Represents a logical unit for navigation (inside Frame).
*/
export class Page extends contentView.ContentView implements view.AddArrayFromBuilder {
export class Page extends contentView.ContentView {
/**
* Dependency property used to hide the Navigation Bar in iOS and the Action Bar in Android.
*/
@@ -111,9 +111,9 @@ declare module "ui/page" {
frame: frame.Frame;
/**
* Gets the OptionsMenu for this page.
* Gets the ActionBar for this page.
*/
optionsMenu: OptionsMenu;
actionBar: actionBar.ActionBar;
/**
* A basic method signature to hook an event listener (shortcut alias to the addEventListener method).
@@ -157,8 +157,6 @@ declare module "ui/page" {
*/
showModal(moduleName: string, context: any, closeCallback: Function, fullscreen?: boolean);
_addArrayFromBuilder(name: string, value: Array<any>): void;
//@private
/**
@@ -184,7 +182,6 @@ declare module "ui/page" {
onNavigatedFrom(isBackNavigation: boolean): void;
_getStyleScope(): styleScope.StyleScope;
_invalidateOptionsMenu();
//@endprivate
}
@@ -207,59 +204,4 @@ declare module "ui/page" {
*/
exports?: any;
}
export class OptionsMenu {
addItem(item: MenuItem): void;
removeItem(item: MenuItem): void;
getItems(): Array<MenuItem>;
getItemAt(index: number): MenuItem;
}
export class MenuItem extends bindable.Bindable {
/**
* String value used when hooking to tap event.
*/
public static tapEvent: string;
/**
* Represents the observable property backing the text property.
*/
public static textProperty: dependencyObservable.Property;
/**
* Represents the observable property backing the icon property.
*/
public static iconProperty: dependencyObservable.Property;
text: string;
icon: string;
android: AndroidMenuItemOptions;
/**
* A basic method signature to hook an event listener (shortcut alias to the addEventListener method).
* @param eventNames - String corresponding to events (e.g. "propertyChange"). Optionally could be used more events separated by `,` (e.g. "propertyChange", "change").
* @param callback - Callback function which will be executed when event is raised.
* @param thisArg - An optional parameter which will be used as `this` context for callback execution.
*/
on(eventNames: string, callback: (data: observable.EventData) => void);
/**
* Raised when a tap event occurs.
*/
on(event: "tap", callback: (args: observable.EventData) => void);
//@private
_raiseTap(): void;
//@endprivate
}
interface AndroidMenuItemOptions {
/**
* Specify if android menuItem should appear in the actionBar or in the popup.
* Use values from enums MenuItemPosition.
* Changes after menuItem is created are not supported.
*/
position: string;
}
}

View File

@@ -1,7 +1,6 @@
import pageCommon = require("ui/page/page-common");
import definition = require("ui/page");
import viewModule = require("ui/core/view");
import imageSource = require("image-source");
import trace = require("trace");
import utils = require("utils/utils");
@@ -22,7 +21,7 @@ class UIViewControllerImpl extends UIViewController {
}
public didRotateFromInterfaceOrientation(fromInterfaceOrientation: number) {
trace.write(this._owner + " didRotateFromInterfaceOrientation(" + fromInterfaceOrientation+ ")", trace.categories.ViewHierarchy);
trace.write(this._owner + " didRotateFromInterfaceOrientation(" + fromInterfaceOrientation + ")", trace.categories.ViewHierarchy);
if ((<any>this._owner)._isModal) {
var parentBounds = (<any>this._owner)._UIModalPresentationFormSheet ? (<UIView>this._owner._nativeView).superview.bounds : UIScreen.mainScreen().bounds;
utils.ios._layoutRootView(this._owner, parentBounds);
@@ -71,14 +70,14 @@ export class Page extends pageCommon.Page {
}
public onLoaded() {
// loaded/unloaded events are handeled in page viewWillAppear/viewDidDisappear
// loaded/unloaded events are handled in page viewWillAppear/viewDidDisappear
if (this._enableLoadedEvents) {
super.onLoaded();
}
}
public onUnloaded() {
// loaded/unloaded events are handeled in page viewWillAppear/viewDidDisappear
// loaded/unloaded events are handled in page viewWillAppear/viewDidDisappear
if (this._enableLoadedEvents) {
super.onUnloaded();
}
@@ -116,36 +115,6 @@ export class Page extends pageCommon.Page {
return this.ios.view;
}
public _invalidateOptionsMenu() {
this.populateMenuItems();
}
public populateMenuItems() {
var items = this.optionsMenu.getItems();
var navigationItem: UINavigationItem = (<UIViewController>this.ios).navigationItem;
var array: NSMutableArray = items.length > 0 ? NSMutableArray.new() : null;
for (var i = 0; i < items.length; i++) {
var item = items[i];
var tapHandler = TapBarItemHandlerImpl.new().initWithOwner(item);
// associate handler with menuItem or it will get collected by JSC.
(<any>item).handler = tapHandler;
var barButtonItem: UIBarButtonItem;
if (item.icon) {
var img = imageSource.fromResource(item.icon);
barButtonItem = UIBarButtonItem.alloc().initWithImageStyleTargetAction(img.ios, UIBarButtonItemStyle.UIBarButtonItemStylePlain, tapHandler, "tap");
}
else {
barButtonItem = UIBarButtonItem.alloc().initWithTitleStyleTargetAction(item.text, UIBarButtonItemStyle.UIBarButtonItemStylePlain, tapHandler, "tap");
}
array.addObject(barButtonItem);
}
navigationItem.setRightBarButtonItemsAnimated(array, true);
}
protected _showNativeModalView(parent: Page, context: any, closeCallback: Function, fullscreen?: boolean) {
(<any>this)._isModal = true;
@@ -187,24 +156,3 @@ export class Page extends pageCommon.Page {
}
}
}
class TapBarItemHandlerImpl extends NSObject {
static new(): TapBarItemHandlerImpl {
return <TapBarItemHandlerImpl>super.new();
}
private _owner: definition.MenuItem;
public initWithOwner(owner: definition.MenuItem): TapBarItemHandlerImpl {
this._owner = owner;
return this;
}
public tap(args) {
this._owner._raiseTap();
}
public static ObjCExposedMethods = {
"tap": { returns: interop.types.void, params: [interop.types.id] }
};
}