mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
fix(menu): rtl support
Squashed commit of the following: commit57b59eb373Merge:dcf80e416f26c4b4feAuthor: Amit Moryossef <amitmoryossef@gmail.com> Date: Fri Apr 21 14:38:03 2017 +0300 merge 'master' commitdcf80e4161Author: Amit Moryossef <amitmoryossef@gmail.com> Date: Fri Apr 21 01:24:40 2017 +0300 tests(menu): add menu rtl tests commitd65575b9caAuthor: Amit Moryossef <amitmoryossef@gmail.com> Date: Fri Apr 21 01:24:00 2017 +0300 tests(mock): add platform to mockMenu commitfaad17ca32Author: Amit Moryossef <amitmoryossef@gmail.com> Date: Fri Apr 21 01:23:01 2017 +0300 fix(menu): update gesture only if it exists commite50eb184ecAuthor: Amit Moryossef <amitmoryossef@gmail.com> Date: Fri Apr 21 00:55:50 2017 +0300 refactor(menu): use magic get/set for side update commit89a1715661Author: Amit Moryossef <amitmoryossef@gmail.com> Date: Thu Apr 20 19:31:49 2017 +0300 revert(menu): revert removed dependency this PR is for a specific feature commit7c1263624cMerge:4465f82f6860567288Author: Amit Moryossef <amitmoryossef@gmail.com> Date: Thu Apr 20 19:26:10 2017 +0300 Merge remote-tracking branch 'upstream/master' into menu commit4465f82f64Author: Amit Moryossef <amitmoryossef@gmail.com> Date: Thu Apr 20 16:11:13 2017 +0300 style(backdrop): fix code style commitda4983a161Author: Amit Moryossef <amitmoryossef@gmail.com> Date: Thu Apr 20 16:09:18 2017 +0300 revert(renderer): back to renderer1 commit80ab0941d6Author: Amit Moryossef <amitmoryossef@gmail.com> Date: Sun Apr 16 11:34:34 2017 +0300 fix(swipe-back): change side according to dir commitf99cb9844fAuthor: Amit Moryossef <amitmoryossef@gmail.com> Date: Sun Apr 16 11:26:49 2017 +0300 feat(platform): add dir change event emitter commit90de5d1105Author: Amit Moryossef <amitmoryossef@gmail.com> Date: Sat Apr 15 20:13:09 2017 +0300 fix(menu): add gesture side real-time update migrated to Renderer2
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import { Animation } from '../../animations/animation';
|
||||
|
||||
export type Side = 'left' | 'right' | 'start' | 'end';
|
||||
|
||||
export interface Menu {
|
||||
setOpen(shouldOpen: boolean, animated: boolean): Promise<boolean>;
|
||||
open(): Promise<boolean>;
|
||||
@@ -9,7 +11,7 @@ export interface Menu {
|
||||
swipeEnable(shouldEnable: boolean): Menu;
|
||||
isOpen: boolean;
|
||||
enabled: boolean;
|
||||
side: string;
|
||||
side: Side;
|
||||
id: string;
|
||||
isAnimating(): boolean;
|
||||
width(): number;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ChangeDetectionStrategy, Component, ContentChild, ElementRef, EventEmitter, forwardRef, Input, NgZone, Output, Renderer, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||
import { OnInit, OnDestroy, ChangeDetectionStrategy, Component, ContentChild, ElementRef, EventEmitter, forwardRef, Input, NgZone, Output, Renderer, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||
|
||||
import { App } from '../app/app';
|
||||
import { Backdrop } from '../backdrop/backdrop';
|
||||
@@ -9,7 +9,7 @@ import { GestureController, GESTURE_GO_BACK_SWIPE, BlockerDelegate } from '../..
|
||||
import { isTrueProperty, assert } from '../../util/util';
|
||||
import { Keyboard } from '../../platform/keyboard';
|
||||
import { MenuContentGesture } from './menu-gestures';
|
||||
import { Menu as MenuInterface } from '../app/menu-interface';
|
||||
import {Menu as MenuInterface, Side} from '../app/menu-interface';
|
||||
import { MenuController } from '../app/menu-controller';
|
||||
import { MenuType } from './menu-types';
|
||||
import { Nav } from '../nav/nav';
|
||||
@@ -193,7 +193,7 @@ import { RootNode } from '../split-pane/split-pane';
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
providers: [{provide: RootNode, useExisting: forwardRef(() => Menu) }]
|
||||
})
|
||||
export class Menu implements RootNode, MenuInterface {
|
||||
export class Menu implements RootNode, MenuInterface, OnInit, OnDestroy {
|
||||
|
||||
private _cntEle: HTMLElement;
|
||||
private _gesture: MenuContentGesture;
|
||||
@@ -206,6 +206,7 @@ export class Menu implements RootNode, MenuInterface {
|
||||
private _events: UIEventManager;
|
||||
private _gestureBlocker: BlockerDelegate;
|
||||
private _isPane: boolean = false;
|
||||
private _side: Side = 'start';
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
@@ -237,11 +238,6 @@ export class Menu implements RootNode, MenuInterface {
|
||||
*/
|
||||
@Input() id: string;
|
||||
|
||||
/**
|
||||
* @input {string} Which side of the view the menu should be placed. Default `"left"`.
|
||||
*/
|
||||
@Input() side: string;
|
||||
|
||||
/**
|
||||
* @input {string} The display type of the menu. Default varies based on the mode,
|
||||
* see the `menuType` in the [config](../../config/Config). Available options:
|
||||
@@ -262,6 +258,24 @@ export class Menu implements RootNode, MenuInterface {
|
||||
this.enable(isEnabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* @input {string} Which side of the view the menu should be placed. Default `"left"`.
|
||||
*/
|
||||
@Input()
|
||||
get side() {
|
||||
if (this._side === 'right' || (this._side === 'start' && this._plt.isRTL()) || (this._side === 'end' && !this._plt.isRTL())) {
|
||||
return 'right';
|
||||
}
|
||||
return 'left';
|
||||
}
|
||||
|
||||
set side(val: Side) {
|
||||
this._side = val;
|
||||
// Update gesture edge
|
||||
if (this._gesture)
|
||||
this._gesture.setEdges(this.side);
|
||||
}
|
||||
|
||||
/**
|
||||
* @input {boolean} If true, swiping the menu is enabled. Default `true`.
|
||||
*/
|
||||
@@ -339,11 +353,7 @@ export class Menu implements RootNode, MenuInterface {
|
||||
return console.error('Menu: must have a [content] element to listen for drag events on. Example:\n\n<ion-menu [content]="content"></ion-menu>\n\n<ion-nav #content></ion-nav>');
|
||||
}
|
||||
|
||||
// normalize the "side"
|
||||
if (this.side !== 'left' && this.side !== 'right') {
|
||||
this.side = 'left';
|
||||
}
|
||||
this.setElementAttribute('side', this.side);
|
||||
this.setElementAttribute('side', this._side);
|
||||
|
||||
// normalize the "type"
|
||||
if (!this.type) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { MenuController } from '../../app/menu-controller';
|
||||
import { mockMenu } from '../../../util/mock-providers';
|
||||
|
||||
import {mockMenu, mockPlatform} from '../../../util/mock-providers';
|
||||
import {Side} from '../../app/menu-interface';
|
||||
|
||||
describe('MenuController', () => {
|
||||
|
||||
@@ -116,6 +116,30 @@ describe('MenuController', () => {
|
||||
expect(menu).toEqual(someMenu);
|
||||
});
|
||||
|
||||
it('should get the only left menu on start ltr', () => {
|
||||
let someMenu = mockMenu();
|
||||
someMenu.side = 'start';
|
||||
menuCtrl._register(someMenu);
|
||||
|
||||
let menu = menuCtrl.get('left');
|
||||
expect(menu).toEqual(someMenu);
|
||||
});
|
||||
|
||||
it('should get the only left menu on end rtl', () => {
|
||||
let platform = mockPlatform();
|
||||
platform.setDir('rtl', true);
|
||||
expect(platform.dir()).toEqual('rtl');
|
||||
|
||||
let someMenu = mockMenu(platform);
|
||||
someMenu.side = 'end';
|
||||
menuCtrl._register(someMenu);
|
||||
|
||||
expect(someMenu.side).toEqual('left');
|
||||
|
||||
let menu = menuCtrl.get('left');
|
||||
expect(menu).toEqual(someMenu);
|
||||
});
|
||||
|
||||
it('should get the enabled left menu', () => {
|
||||
let someMenu1 = mockMenu();
|
||||
someMenu1.side = 'left';
|
||||
@@ -155,6 +179,30 @@ describe('MenuController', () => {
|
||||
expect(menu).toEqual(someMenu);
|
||||
});
|
||||
|
||||
it('should get the only right menu on end ltr', () => {
|
||||
let someMenu = mockMenu();
|
||||
someMenu.side = 'end';
|
||||
menuCtrl._register(someMenu);
|
||||
|
||||
let menu = menuCtrl.get('right');
|
||||
expect(menu).toEqual(someMenu);
|
||||
});
|
||||
|
||||
it('should get the only right menu on start rtl', () => {
|
||||
let platform = mockPlatform();
|
||||
platform.setDir('rtl', true);
|
||||
expect(platform.dir()).toEqual('rtl');
|
||||
|
||||
let someMenu = mockMenu(platform);
|
||||
someMenu.side = 'start';
|
||||
menuCtrl._register(someMenu);
|
||||
|
||||
expect(someMenu.side).toEqual('right');
|
||||
|
||||
let menu = menuCtrl.get('right');
|
||||
expect(menu).toEqual(someMenu);
|
||||
});
|
||||
|
||||
it('should get the menu by left with id', () => {
|
||||
let someMenu = mockMenu();
|
||||
someMenu.id = 'myMenu';
|
||||
@@ -165,6 +213,40 @@ describe('MenuController', () => {
|
||||
expect(menu).toEqual(someMenu);
|
||||
});
|
||||
|
||||
it('should switch menu side in runtime', () => {
|
||||
let someMenu = mockMenu();
|
||||
menuCtrl._register(someMenu);
|
||||
|
||||
['left', 'right'].forEach((side: Side) => {
|
||||
someMenu.side = side;
|
||||
expect(someMenu.side).toEqual(side);
|
||||
|
||||
let menu = menuCtrl.get(side);
|
||||
expect(menu).toEqual(someMenu);
|
||||
});
|
||||
});
|
||||
|
||||
it('should switch menu side in runtime by direction', () => {
|
||||
let platform = mockPlatform();
|
||||
platform.setDir('ltr', true);
|
||||
expect(platform.dir()).toEqual('ltr');
|
||||
|
||||
let someMenu = mockMenu(platform);
|
||||
menuCtrl._register(someMenu);
|
||||
|
||||
expect(someMenu.side).toEqual('left');
|
||||
|
||||
let menu = menuCtrl.get('left');
|
||||
expect(menu).toEqual(someMenu);
|
||||
|
||||
platform.setDir('rtl', true);
|
||||
|
||||
expect(someMenu.side).toEqual('right');
|
||||
|
||||
let menu2 = menuCtrl.get('right');
|
||||
expect(menu2).toEqual(someMenu);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('enable()', () => {
|
||||
|
||||
@@ -18,10 +18,14 @@ export class SlideEdgeGesture extends SlideGesture {
|
||||
});
|
||||
super(plt, element, opts);
|
||||
// Can check corners through use of eg 'left top'
|
||||
this.edges = opts.edge.split(' ');
|
||||
this.setEdges(opts.edge);
|
||||
this.maxEdgeStart = opts.maxEdgeStart;
|
||||
}
|
||||
|
||||
setEdges(edges: string) {
|
||||
this.edges = edges.split(' ');
|
||||
}
|
||||
|
||||
canStart(ev: any): boolean {
|
||||
let coord = pointerCoord(ev);
|
||||
this._d = this.getContainerDimensions();
|
||||
|
||||
@@ -30,6 +30,14 @@ export class SwipeBackGesture extends SlideEdgeGesture {
|
||||
disableScroll: true
|
||||
})
|
||||
});
|
||||
|
||||
this.setSide(plt.dir());
|
||||
|
||||
Platform.dirChanged.subscribe(this.setSide.bind(this));
|
||||
}
|
||||
|
||||
private setSide(dir: string) {
|
||||
this.setEdges(dir === 'ltr' ? 'left' : 'right');
|
||||
}
|
||||
|
||||
canStart(ev: any): boolean {
|
||||
|
||||
@@ -50,6 +50,8 @@ export class Platform {
|
||||
private _isPortrait: boolean = null;
|
||||
private _uiEvtOpts = false;
|
||||
|
||||
static dirChanged: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
/** @hidden */
|
||||
zone: NgZone;
|
||||
|
||||
@@ -313,9 +315,12 @@ export class Platform {
|
||||
* direction needs to be dynamically changed per user/session.
|
||||
* [W3C: Structural markup and right-to-left text in HTML](http://www.w3.org/International/questions/qa-html-dir)
|
||||
* @param {string} dir Examples: `rtl`, `ltr`
|
||||
* @param {boolean} updateDocument
|
||||
*/
|
||||
setDir(dir: string, updateDocument: boolean) {
|
||||
this._dir = (dir || '').toLowerCase();
|
||||
Platform.dirChanged.emit(this._dir);
|
||||
|
||||
if (updateDocument !== false) {
|
||||
this._doc['documentElement'].setAttribute('dir', dir);
|
||||
}
|
||||
|
||||
@@ -543,13 +543,14 @@ export function mockTabs(app?: App): Tabs {
|
||||
return new Tabs(null, null, app, config, elementRef, platform, renderer, linker);
|
||||
}
|
||||
|
||||
export function mockMenu(): Menu {
|
||||
export function mockMenu(platform: MockPlatform = null): Menu {
|
||||
let app = mockApp();
|
||||
let gestureCtrl = new GestureController(app);
|
||||
let dom = mockDomController();
|
||||
let elementRef = mockElementRef();
|
||||
let renderer = mockRenderer();
|
||||
return new Menu(null, elementRef, null, null, renderer, null, null, gestureCtrl, dom, app);
|
||||
let plt = platform === null ? mockPlatform() : platform;
|
||||
return new Menu(null, elementRef, null, plt, renderer, null, null, gestureCtrl, dom, app);
|
||||
}
|
||||
|
||||
export function mockDeepLinkConfig(links?: any[]): DeepLinkConfig {
|
||||
|
||||
Reference in New Issue
Block a user