diff --git a/demos/component-docs/actionSheet/actionSheet.html b/demos/component-docs/actionSheet/actionSheet.html new file mode 100644 index 0000000000..8d6d280d64 --- /dev/null +++ b/demos/component-docs/actionSheet/actionSheet.html @@ -0,0 +1,9 @@ + + Action Sheet + + + + + diff --git a/demos/component-docs/actionSheet/actionSheet.ts b/demos/component-docs/actionSheet/actionSheet.ts new file mode 100644 index 0000000000..be3b284c63 --- /dev/null +++ b/demos/component-docs/actionSheet/actionSheet.ts @@ -0,0 +1,65 @@ +import {IonicPlatform, Page, ActionSheet} from 'ionic/ionic'; + +@Page({ + templateUrl: 'actionSheet/actionSheet.html', +}) +export class ActionSheetPage { + + constructor(actionSheet: ActionSheet, platform: IonicPlatform) { + this.actionSheet = actionSheet; + this.platform = platform; + } + + openMenu() { + if (this.platform.is('android')) { + var androidSheet = { + + buttons: [ + { text: 'Share', icon: 'share' }, + { text: 'Play', icon: 'arrow-dropright-circle'}, + { text: 'Favorite', icon: 'ion-md-heart-outline'} + ], + destructiveText: 'Delete', + titleText: 'Albums', + cancelText: 'Cancel', + cancel: function() { + console.log('Canceled'); + }, + destructiveButtonClicked: () => { + console.log('Destructive clicked'); + }, + buttonClicked: function(index) { + console.log('Button clicked', index); + if (index == 1) { return false; } + return true; + } + }; + } + + this.actionSheet.open(androidSheet || { + buttons: [ + { text: 'Share'}, + { text: 'Play'}, + { text: 'Favorite'} + ], + destructiveText: 'Delete', + titleText: 'Albums', + cancelText: 'Cancel', + cancel: function() { + console.log('Canceled'); + }, + destructiveButtonClicked: () => { + console.log('Destructive clicked'); + }, + buttonClicked: function(index) { + console.log('Button clicked', index); + if (index == 1) { return false; } + return true; + } + + }).then(actionSheetRef => { + this.actionSheetRef = actionSheetRef; + }); + } + +} \ No newline at end of file diff --git a/demos/component-docs/app.css b/demos/component-docs/app.css index 0c961e226d..1768e2be98 100644 --- a/demos/component-docs/app.css +++ b/demos/component-docs/app.css @@ -83,3 +83,13 @@ scroll-content { color: #31D55F; } +.md .action-sheet-destructive { + border-top: 1px solid rgba(204, 204, 204, 0.32); + margin-top: 8px; + padding-top: 4px; +} + +.md .action-sheet-cancel icon, .md .action-sheet-destructive icon { + color: #757575; +} + diff --git a/demos/component-docs/buttons/block.html b/demos/component-docs/buttons/block.html new file mode 100644 index 0000000000..75bda108b3 --- /dev/null +++ b/demos/component-docs/buttons/block.html @@ -0,0 +1,25 @@ + + Block Buttons + + + +

+ +

+ +

+ +

+ +

+ +

+ +

+ +

+ +

+ +

+
diff --git a/demos/component-docs/buttons/buttons.html b/demos/component-docs/buttons/buttons.html new file mode 100644 index 0000000000..bb2582ec93 --- /dev/null +++ b/demos/component-docs/buttons/buttons.html @@ -0,0 +1,25 @@ + + Buttons + + + +

+ +

+ +

+ +

+ +

+ +

+ +

+ +

+ +

+ +

+
diff --git a/demos/component-docs/buttons/buttons.ts b/demos/component-docs/buttons/buttons.ts new file mode 100644 index 0000000000..dcf0084f9a --- /dev/null +++ b/demos/component-docs/buttons/buttons.ts @@ -0,0 +1,73 @@ +import {IonicPlatform, Page} from 'ionic/ionic'; + +@Page({ + templateUrl: 'buttons/buttons.html', +}) +export class ButtonsPage { + constructor() { + + } +} + +@Page({ + templateUrl: 'buttons/block.html', +}) +export class BlockButtonsPage { + constructor() { + + } +} + +@Page({ + templateUrl: 'buttons/full.html', +}) +export class FullButtonsPage { + constructor() { + + } +} + +@Page({ + templateUrl: 'buttons/outline.html', +}) +export class OutlineButtonsPage { + constructor() { + + } +} + +@Page({ + templateUrl: 'buttons/round.html', +}) +export class RoundButtonsPage { + constructor() { + + } +} + +@Page({ + templateUrl: 'buttons/fab.html', +}) +export class FabPage { + constructor() { + + } +} + +@Page({ + templateUrl: 'buttons/sizes.html', +}) +export class ButtonSizesPage { + constructor() { + + } +} + +@Page({ + templateUrl: 'buttons/icons.html', +}) +export class IconButtonsPage { + constructor() { + + } +} \ No newline at end of file diff --git a/demos/component-docs/buttons/fab.html b/demos/component-docs/buttons/fab.html new file mode 100644 index 0000000000..15b7396b66 --- /dev/null +++ b/demos/component-docs/buttons/fab.html @@ -0,0 +1,15 @@ + + Floating Action Buttons + + + +

+ +

+
+ + + + diff --git a/demos/component-docs/buttons/full.html b/demos/component-docs/buttons/full.html new file mode 100644 index 0000000000..8c4efb0a51 --- /dev/null +++ b/demos/component-docs/buttons/full.html @@ -0,0 +1,29 @@ + + Full Buttons + + + +

+ +

+ +

+ +

+ +

+ +

+ +

+ +

+ +

+ +

+
+ + + + diff --git a/demos/component-docs/buttons/icons.html b/demos/component-docs/buttons/icons.html new file mode 100644 index 0000000000..5a86bcb036 --- /dev/null +++ b/demos/component-docs/buttons/icons.html @@ -0,0 +1,40 @@ + + + Icon Buttons + + + +

+ +

+ +

+ +

+ +

+ +

+ +

+ +

+ +

+ +

+ +
diff --git a/demos/component-docs/buttons/outline.html b/demos/component-docs/buttons/outline.html new file mode 100644 index 0000000000..18a689b69f --- /dev/null +++ b/demos/component-docs/buttons/outline.html @@ -0,0 +1,25 @@ + + Outline Buttons + + + +

+ +

+ +

+ +

+ +

+ +

+ +

+ +

+ +

+ +

+
diff --git a/demos/component-docs/buttons/round.html b/demos/component-docs/buttons/round.html new file mode 100644 index 0000000000..bb1bbaf3e2 --- /dev/null +++ b/demos/component-docs/buttons/round.html @@ -0,0 +1,25 @@ + + Round Buttons + + + +

+ +

+ +

+ +

+ +

+ +

+ +

+ +

+ +

+ +

+
diff --git a/demos/component-docs/buttons/sizes.html b/demos/component-docs/buttons/sizes.html new file mode 100644 index 0000000000..bf1cf01908 --- /dev/null +++ b/demos/component-docs/buttons/sizes.html @@ -0,0 +1,25 @@ + + Button Sizes + + + +

+ +

+ +

+ +

+ +

+ +

+ +

+ +

+ +

+ +

+
diff --git a/demos/component-docs/cards/cards.html b/demos/component-docs/cards/cards.html new file mode 100644 index 0000000000..f0de786baa --- /dev/null +++ b/demos/component-docs/cards/cards.html @@ -0,0 +1,62 @@ + + + Cards + + + + + + + Menu + + + + + + Home + + + + + Friends + + + + + + + + + + + + + + + Schedule + + + + + + + + + + Trophies + + + + + + + + + + diff --git a/demos/component-docs/cards/cards.ts b/demos/component-docs/cards/cards.ts new file mode 100644 index 0000000000..03fb88e988 --- /dev/null +++ b/demos/component-docs/cards/cards.ts @@ -0,0 +1,10 @@ +import {IonicPlatform, Page} from 'ionic/ionic'; + +@Page({ + templateUrl: 'cards/cards.html', +}) +export class CardsPage { + constructor() { + + } +} \ No newline at end of file diff --git a/demos/component-docs/forms/forms.html b/demos/component-docs/forms/forms.html new file mode 100644 index 0000000000..3a2ac65291 --- /dev/null +++ b/demos/component-docs/forms/forms.html @@ -0,0 +1,19 @@ + + Forms + + + +
+ + + + + + + + +
+ +
+
+
diff --git a/demos/component-docs/forms/forms.ts b/demos/component-docs/forms/forms.ts new file mode 100644 index 0000000000..78dda384ca --- /dev/null +++ b/demos/component-docs/forms/forms.ts @@ -0,0 +1,25 @@ +import {FORM_DIRECTIVES, FormBuilder, Validators, Control, ControlGroup} from 'angular2/angular2'; +import {Page} from 'ionic/ionic'; + + +@Page({ + templateUrl: 'forms/forms.html', + bindings: [FormBuilder] +}) +export class FormsPage { + + constructor() { + this.form = new ControlGroup({ + firstName: new Control("", Validators.required), + lastName: new Control("", Validators.required) + }); + } + + processForm(event) { + // TODO: display input in a popup + console.log(event); + } + + +} + diff --git a/demos/component-docs/helpers.ts b/demos/component-docs/helpers.ts index 1f0bd7a166..e65f250883 100644 --- a/demos/component-docs/helpers.ts +++ b/demos/component-docs/helpers.ts @@ -1,3 +1,52 @@ +import {ActionSheetPage} from 'actionSheet/actionSheet'; + +import {ButtonsPage, + BlockButtonsPage, + FullButtonsPage, + OutlineButtonsPage, + RoundButtonsPage, + FabPage, + ButtonSizesPage, + IconButtonsPage} from 'buttons/buttons'; + +import {CardsPage} from 'cards/cards'; +import {FormsPage} from 'forms/forms'; +import {IconsPage} from 'icons/icons'; +import {ListsPage} from 'lists/lists'; +import {MenusPage} from 'menus/menus'; +import {ModalsPage} from 'modals/modals'; +import {NavigationPage} from 'navigation/navigation'; +import {PopupsPage} from 'popups/popups'; +import {SlidesPage} from 'slides/slides'; +import {TabsPage} from 'tabs/tabs'; + + export function toTitleCase(str) { return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();}); -} \ No newline at end of file +} + +export function getPageFor(hash) { + return { + 'action-sheets': ActionSheetPage, + 'buttons': ButtonsPage, + 'block-buttons': BlockButtonsPage, + 'full-buttons': FullButtonsPage, + 'outline-buttons': OutlineButtonsPage, + 'round-buttons': RoundButtonsPage, + 'floating-action-buttons': FabPage, + 'button-sizes': ButtonSizesPage, + 'icon-buttons': IconButtonsPage, + 'cards': CardsPage, + 'forms': FormsPage, + 'icons': IconsPage, + 'lists': ListsPage, + 'menus': MenusPage, + 'modals': ModalsPage, + 'navigation': NavigationPage, + 'popups': PopupsPage, + 'slides': SlidesPage, + 'tabs': TabsPage + }[hash] +} + + diff --git a/demos/component-docs/icons/icons.html b/demos/component-docs/icons/icons.html new file mode 100644 index 0000000000..67b4570a41 --- /dev/null +++ b/demos/component-docs/icons/icons.html @@ -0,0 +1,74 @@ + + + Icons + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demos/component-docs/icons/icons.ts b/demos/component-docs/icons/icons.ts new file mode 100644 index 0000000000..830b067e9c --- /dev/null +++ b/demos/component-docs/icons/icons.ts @@ -0,0 +1,10 @@ +import {IonicPlatform, Page} from 'ionic/ionic'; + +@Page({ + templateUrl: 'icons/icons.html', +}) +export class IconsPage { + constructor() { + + } +} \ No newline at end of file diff --git a/demos/component-docs/index.ts b/demos/component-docs/index.ts index 46226cc577..a4a054f8b9 100644 --- a/demos/component-docs/index.ts +++ b/demos/component-docs/index.ts @@ -1,186 +1,37 @@ -import {FORM_DIRECTIVES, FormBuilder, Validators, Control, ControlGroup} from 'angular2/forms'; -import {App, IonicApp, IonicPlatform, ActionSheet, NavController, NavParams} from 'ionic/ionic'; -import {Popup, Modal, IonicView, IonicConfig, Events, Animation} from 'ionic/ionic'; -import {NavigationDetailsPage} from 'navigation'; - -import {TabsPage} from 'tabs'; -import {DemoModal} from 'modal'; +import {App, IonicApp, IonicPlatform, ActionSheet} from 'ionic/ionic'; +import {Page, IonicConfig, Events} from 'ionic/ionic'; +import {ActionSheetPage} from 'actionSheet/actionSheet'; import * as helpers from 'helpers'; -@IonicView({ - templateUrl: 'main.html', - bindings: [FormBuilder] -}) -export class MainPage { - - component: any = { title: 'Action Sheets' }; - - constructor(app: IonicApp, - nav: NavController, - actionSheet: ActionSheet, - params: NavParams, - popup: Popup, - platform: IonicPlatform, - modal: Modal, - events: Events) { - this.params = params; - this.nav = nav; - this.platform = platform; - this.modal = modal; - this.popup = popup; - this.actionSheet = actionSheet; - this.navDetailsPage = NavigationDetailsPage; - this.demoModal = DemoModal; - this.form = new ControlGroup({ - firstName: new Control("", Validators.required), - lastName: new Control("", Validators.required) - }); - - if (params.data.location) { this.component.title = params.data.location; } - else if (window.location.hash) { this.component.title = window.location.hash; } - - window.addEventListener('message', (e) => { - zone.run(() => { - if (e.data) { - var data = JSON.parse(e.data); - this.component.title = helpers.toTitleCase(data.hash.replace(/-/g, ' ')); - if (this.component.title === 'Tabs') { - this.nav.setRoot(TabsPage); - } - } - }); - }); - - events.subscribe('page:locationChange', (data) => { - this.component.title = data[0].componentName; - }); - } - - // ************************** - // Action Sheets - // ************************** - openMenu() { - if (this.platform.is('android')) { - var androidSheet = { - - buttons: [ - { text: 'Share', icon: 'share' }, - { text: 'Play', icon: 'arrow-dropright-circle'}, - { text: 'Favorite', icon: 'ion-md-heart-outline'} - ], - destructiveText: 'Delete', - titleText: 'Purchased', - cancelText: 'Cancel', - cancel: function() { - console.log('Canceled'); - }, - destructiveButtonClicked: () => { - console.log('Destructive clicked'); - }, - buttonClicked: function(index) { - console.log('Button clicked', index); - if (index == 1) { return false; } - return true; - } - }; - } - - this.actionSheet.open(androidSheet || { - buttons: [ - { text: 'Share This' }, - { text: 'Move' } - ], - destructiveText: 'Delete', - titleText: 'You Opened Action Sheet', - cancelText: 'Cancel', - cancel: function() { - console.log('Canceled'); - }, - destructiveButtonClicked: () => { - console.log('Destructive clicked'); - }, - buttonClicked: function(index) { - console.log('Button clicked', index); - if (index == 1) { return false; } - return true; - } - - }).then(actionSheetRef => { - this.actionSheetRef = actionSheetRef; - }); - } - - // ************************** - // Navigation - // ************************** - openNavDetailsPage(item) { - this.nav.push(NavigationDetailsPage, { name: item }); - } - - - // ************************** - // Modal - // ************************** - openModal() { - this.modal.open(this.demoModal, { - handle: 'my-awesome-modal', - enterAnimation: 'my-fade-in', - leaveAnimation: 'my-fade-out' - }); - } - - // ************************** - // Popup - // ************************** - showPopup() { - this.popup.alert("Popup Title").then(() => { - }); - } - - - // ************************** - // Form - // ************************** - processForm(event) { - // TODO: display input in a popup - console.log(event); - } - -} - -class FadeIn extends Animation { - constructor(element) { - super(element); - this - .easing('ease') - .duration(450) - .fadeIn(); - } -} - -Animation.register('my-fade-in', FadeIn); - -class FadeOut extends Animation { - constructor(element) { - super(element); - this - .easing('ease') - .duration(250) - .fadeOut(); - } -} - -Animation.register('my-fade-out', FadeOut); - - @App({ - template: '' + template: '' }) class DemoApp { - constructor() { - this.rootPage = MainPage; - } + rootPage: any; + constructor(app: IonicApp, platform: IonicPlatform) { + this.app = app; + this.platform = platform; + + this.platform.ready().then( () => { + window.addEventListener('message', (e) => { + zone.run(() => { + if (e.data) { + var data = JSON.parse(e.data); + if (data.hash) { + this.nextPage = helpers.getPageFor(data.hash.replace('#', '')); + } else { + this.nextPage = ActionSheetPage; + } + let nav = this.app.getComponent('nav'); + nav.setRoot(this.nextPage); + } + }); + }); + window.parent.postMessage(this.platform.is('ios')? "ios":"android", "*"); + }); + + } } diff --git a/demos/component-docs/lists/lists.html b/demos/component-docs/lists/lists.html new file mode 100644 index 0000000000..b8dc74a791 --- /dev/null +++ b/demos/component-docs/lists/lists.html @@ -0,0 +1,58 @@ + + + Lists + + + + + + + Classes + + + + + Dark Arts + + + + + Astronomy + + + + + Potions + + + + + Charms + + + + + + + + + Menu + + + + + Invisibility Cloak + + + + + Call Ron + Maybe later + + + + + + + + diff --git a/demos/component-docs/lists/lists.ts b/demos/component-docs/lists/lists.ts new file mode 100644 index 0000000000..a4426af62e --- /dev/null +++ b/demos/component-docs/lists/lists.ts @@ -0,0 +1,10 @@ +import {IonicPlatform, Page} from 'ionic/ionic'; + +@Page({ + templateUrl: 'lists/lists.html', +}) +export class ListsPage { + constructor() { + + } +} \ No newline at end of file diff --git a/demos/component-docs/main.html b/demos/component-docs/main.html index 607d451811..b183b3c6c4 100644 --- a/demos/component-docs/main.html +++ b/demos/component-docs/main.html @@ -123,7 +123,7 @@

- +
@@ -158,7 +158,7 @@

- +
@@ -220,7 +220,7 @@

- +
@@ -476,7 +476,7 @@ -
+
diff --git a/demos/component-docs/menus/menu-events.html b/demos/component-docs/menus/menu-events.html new file mode 100644 index 0000000000..d95d163938 --- /dev/null +++ b/demos/component-docs/menus/menu-events.html @@ -0,0 +1,15 @@ + + + + + + + + Events + + + + + + + diff --git a/demos/component-docs/menus/menu-friends.html b/demos/component-docs/menus/menu-friends.html new file mode 100644 index 0000000000..10a030378b --- /dev/null +++ b/demos/component-docs/menus/menu-friends.html @@ -0,0 +1,15 @@ + + + + + + + + Friends + + + + + + + diff --git a/demos/component-docs/menus/menu-home.html b/demos/component-docs/menus/menu-home.html new file mode 100644 index 0000000000..4696694445 --- /dev/null +++ b/demos/component-docs/menus/menu-home.html @@ -0,0 +1,16 @@ + + + + + + + + Menus + + + + + + + + diff --git a/demos/component-docs/menus/menu-places.html b/demos/component-docs/menus/menu-places.html new file mode 100644 index 0000000000..e69de29bb2 diff --git a/demos/component-docs/menus/menus.html b/demos/component-docs/menus/menus.html new file mode 100644 index 0000000000..999f6b0ade --- /dev/null +++ b/demos/component-docs/menus/menus.html @@ -0,0 +1,24 @@ + + + + Menu + + + + + + + + + + + + + + + + diff --git a/demos/component-docs/menus/menus.ts b/demos/component-docs/menus/menus.ts new file mode 100644 index 0000000000..bd3a7c7845 --- /dev/null +++ b/demos/component-docs/menus/menus.ts @@ -0,0 +1,58 @@ +import {App, IonicApp, Page, NavController, NavParams} from 'ionic/ionic'; +import {Page, Events} from 'ionic/ionic'; +import * as helpers from 'helpers'; + +@Page({ + templateUrl: 'menus/menu-home.html' +}) +class PageOne{ + constructor(nav: NavController, events: Events) { + this.nav = nav; + this.events = events; + } +} + +@Page({ + templateUrl: 'menus/menu-friends.html' +}) +class PageTwo{ +} + +@Page({ + templateUrl: 'menus/menu-events.html' +}) +class PageThree{ +} + +@Page({ + templateUrl: 'menus/menus.html' +}) +export class MenusPage { + + constructor(app: IonicApp, events: Events, nav: NavController) { + this.nav = nav; + this.app = app; + this.rootView = PageOne; + this.pages = [ + { title: 'Home', component: PageOne }, + { title: 'Friends', component: PageTwo }, + { title: 'Events', component: PageThree } + ]; + + } + + onViewWillUnload() { + } + + openPage(menu, page) { + // close the menu when clicking a link from the menu + menu.close(); + + // Reset the content nav to have just this page + // we wouldn't want the back button to show in this scenario + // let nav = this.app.getComponent('nav'); + this.nav.setRoot(page.component); + } +} + + diff --git a/demos/component-docs/modal.html b/demos/component-docs/modal.html deleted file mode 100644 index dc34228232..0000000000 --- a/demos/component-docs/modal.html +++ /dev/null @@ -1 +0,0 @@ -

TODO

diff --git a/demos/component-docs/modal.ts b/demos/component-docs/modal.ts deleted file mode 100644 index 94089f578e..0000000000 --- a/demos/component-docs/modal.ts +++ /dev/null @@ -1,46 +0,0 @@ -import {App, IonicApp, Modal, NavController, IonicView, Events} from 'ionic/ionic'; -import * as helpers from 'helpers'; - -@IonicView({ - templateUrl: 'modal.html' -}) -class ModalFirstPage { - - constructor( - nav: NavController, - modal: Modal, - events: Events - ) { - this.nav = nav; - this.modal = modal; - window.onmessage = (e) => { - zone.run(() => { - if (e.data) { - var data = JSON.parse(e.data); - var componentTitle = helpers.toTitleCase(data.hash.replace('-', ' ')); - events.publish('page:locationChange', { componentName: componentTitle }); - this.closeModal(); - } - }); - }; - } - - closeModal() { - let modal = this.modal.get(); - if (modal) { - modal.close(); - } - } - -} - -@IonicView({ - template: '' -}) -export class DemoModal { - constructor() { - this.rootView = ModalFirstPage; - } -} - - diff --git a/demos/component-docs/modals/modals-content.html b/demos/component-docs/modals/modals-content.html new file mode 100644 index 0000000000..8d9c8d52d0 --- /dev/null +++ b/demos/component-docs/modals/modals-content.html @@ -0,0 +1,13 @@ + + + + + + + + + + diff --git a/demos/component-docs/modals/modals.html b/demos/component-docs/modals/modals.html new file mode 100644 index 0000000000..d24cbb9ab1 --- /dev/null +++ b/demos/component-docs/modals/modals.html @@ -0,0 +1,10 @@ + + + Modals + + + + + diff --git a/demos/component-docs/modals/modals.ts b/demos/component-docs/modals/modals.ts new file mode 100644 index 0000000000..2c7c0b86f2 --- /dev/null +++ b/demos/component-docs/modals/modals.ts @@ -0,0 +1,80 @@ +import {App, IonicApp, Animation, Modal, NavController, Page, Events} from 'ionic/ionic'; +import * as helpers from 'helpers'; + + +@Page({ + templateUrl: 'modals/modals.html' +}) +class ModalsFirstPage { + + constructor( + nav: NavController, + modal: Modal, + events: Events + ) { + this.nav = nav; + this.modal = modal; + } + + openModal() { + this.modal.open(ModalsContentPage, { + handle: 'my-awesome-modal', + enterAnimation: 'my-fade-in', + leaveAnimation: 'my-fade-out' + }); + } + +} + +@Page({ + templateUrl: 'modals/modals-content.html' +}) +class ModalsContentPage { + + constructor( + modal: Modal, + events: Events + ) { + this.modal = modal; + } + + closeModal() { + let modal = this.modal.get(); + if (modal) { + modal.close(); + } + } +} + +@Page({ + template: '' +}) +export class ModalsPage { + constructor() { + this.rootView = ModalsFirstPage; + } +} + +class FadeIn extends Animation { + constructor(element) { + super(element); + this + .easing('ease') + .duration(450) + .fadeIn(); + } +} + +Animation.register('my-fade-in', FadeIn); + +class FadeOut extends Animation { + constructor(element) { + super(element); + this + .easing('ease') + .duration(250) + .fadeOut(); + } +} + +Animation.register('my-fade-out', FadeOut); diff --git a/demos/component-docs/navigation.html b/demos/component-docs/navigation.html deleted file mode 100644 index 5d734ef310..0000000000 --- a/demos/component-docs/navigation.html +++ /dev/null @@ -1,8 +0,0 @@ - - - {{ selection.title }} - - - -{{ selection.content }} - \ No newline at end of file diff --git a/demos/component-docs/navigation/navigation-details.html b/demos/component-docs/navigation/navigation-details.html new file mode 100644 index 0000000000..d278f76b49 --- /dev/null +++ b/demos/component-docs/navigation/navigation-details.html @@ -0,0 +1,8 @@ + + + {{selection.title}} + + + + {{selection.content}} + \ No newline at end of file diff --git a/demos/component-docs/navigation/navigation.html b/demos/component-docs/navigation/navigation.html new file mode 100644 index 0000000000..3263158fdf --- /dev/null +++ b/demos/component-docs/navigation/navigation.html @@ -0,0 +1,30 @@ + + + Navigation + + + + + + + + Angular + + + + + CSS3 + + + + + + + + \ No newline at end of file diff --git a/demos/component-docs/navigation.ts b/demos/component-docs/navigation/navigation.ts similarity index 67% rename from demos/component-docs/navigation.ts rename to demos/component-docs/navigation/navigation.ts index 60f6a8b36c..be2bca4162 100644 --- a/demos/component-docs/navigation.ts +++ b/demos/component-docs/navigation/navigation.ts @@ -1,11 +1,11 @@ import {NavController, NavParams} from 'ionic/ionic'; -import {IonicView, Events} from 'ionic/ionic'; +import {Page, Events} from 'ionic/ionic'; import * as helpers from 'helpers'; -@IonicView({ - templateUrl: 'navigation.html' +@Page({ + templateUrl: 'navigation/navigation-details.html' }) -export class NavigationDetailsPage { +class NavigationDetailsPage { constructor(nav: NavController, params: NavParams, events: Events) { this.nav = nav; this.selection = { title: params.data.name }; @@ -23,16 +23,20 @@ export class NavigationDetailsPage { }; this.selection['content'] = navData[this.selection.title]; this.selection['icon'] = navIcons[this.selection.title]; - window.onmessage = (e) => { - zone.run(() => { - if (e.data) { - var data = JSON.parse(e.data); - var componentTitle = helpers.toTitleCase(data.hash.replace('-', ' ')); - events.publish('page:locationChange', { componentName: componentTitle }); - this.nav.pop(); - } - }); - }; - } +} + +@Page({ + templateUrl: 'navigation/navigation.html', +}) +export class NavigationPage { + + constructor(nav: NavController) { + this.nav = nav; + } + + openNavDetailsPage(item) { + this.nav.push(NavigationDetailsPage, { name: item }); + } + } \ No newline at end of file diff --git a/demos/component-docs/popups/popups.html b/demos/component-docs/popups/popups.html new file mode 100644 index 0000000000..3babd71e5f --- /dev/null +++ b/demos/component-docs/popups/popups.html @@ -0,0 +1,10 @@ + + + Popups + + + + + diff --git a/demos/component-docs/popups/popups.ts b/demos/component-docs/popups/popups.ts new file mode 100644 index 0000000000..8744fbb3c0 --- /dev/null +++ b/demos/component-docs/popups/popups.ts @@ -0,0 +1,16 @@ +import {IonicPlatform, Page, Popup} from 'ionic/ionic'; + +@Page({ + templateUrl: 'popups/popups.html', +}) +export class PopupsPage { + + constructor(popup: Popup) { + this.popup = popup; + } + + showPopup() { + this.popup.alert("Popup Title").then(() => { + }); + } +} \ No newline at end of file diff --git a/demos/component-docs/slides/slides.html b/demos/component-docs/slides/slides.html new file mode 100644 index 0000000000..08d81d2e51 --- /dev/null +++ b/demos/component-docs/slides/slides.html @@ -0,0 +1,24 @@ + + + Slides + + + + + +
+ Slide 1 +
+
+ +
+ Slide 2 +
+
+ +
+ Slide 3 +
+
+
+
diff --git a/demos/component-docs/slides/slides.ts b/demos/component-docs/slides/slides.ts new file mode 100644 index 0000000000..d817c341c9 --- /dev/null +++ b/demos/component-docs/slides/slides.ts @@ -0,0 +1,10 @@ +import {IonicPlatform, Page} from 'ionic/ionic'; + +@Page({ + templateUrl: 'slides/slides.html', +}) +export class SlidesPage { + constructor() { + + } +} \ No newline at end of file diff --git a/demos/component-docs/tabs.ts b/demos/component-docs/tabs.ts deleted file mode 100644 index 357ab55d72..0000000000 --- a/demos/component-docs/tabs.ts +++ /dev/null @@ -1,35 +0,0 @@ -import {NavController, NavParams} from 'ionic/ionic'; -import {IonicView, ViewController, Events} from 'ionic/ionic'; -import {MainPage} from 'index'; -import * as helpers from 'helpers'; - -@IonicView({ - template: 'Hello 1', -}) -class TabOneCtrl { - constructor(nav: NavController, view: ViewController) { - this.nav = nav; - this.view = view; - } -} - -@IonicView({ - templateUrl: 'tabs.html' -}) -export class TabsPage { - constructor(nav: NavController, params: NavParams, events: Events) { - this.nav = nav; - this.TabOneRoot = TabOneCtrl; - window.onmessage = (e) => { - zone.run(() => { - if (e.data) { - var data = JSON.parse(e.data); - var componentTitle = helpers.toTitleCase(data.hash.replace('-', ' ')); - this.nav.setRoot(MainPage, {location: componentTitle}); - events.publish('page:locationChange', { componentName: componentTitle }); - } - }); - }; - - } -} \ No newline at end of file diff --git a/demos/component-docs/tabs.html b/demos/component-docs/tabs/tabs.html similarity index 82% rename from demos/component-docs/tabs.html rename to demos/component-docs/tabs/tabs.html index c6566ddd7f..f69ce0c9d0 100644 --- a/demos/component-docs/tabs.html +++ b/demos/component-docs/tabs/tabs.html @@ -4,7 +4,7 @@ - + diff --git a/demos/component-docs/tabs/tabs.ts b/demos/component-docs/tabs/tabs.ts new file mode 100644 index 0000000000..e69eae67cd --- /dev/null +++ b/demos/component-docs/tabs/tabs.ts @@ -0,0 +1,22 @@ +import {NavController, NavParams} from 'ionic/ionic'; +import {Page, ViewController} from 'ionic/ionic'; +import * as helpers from 'helpers'; + +@Page({ + template: 'Hello 1', +}) +class TabOneCtrl { + constructor(nav: NavController, view: ViewController) { + this.nav = nav; + this.view = view; + } +} + +@Page({ + templateUrl: 'tabs.html' +}) +export class TabsPage { + constructor(nav: NavController, params: NavParams) { + this.nav = nav; + } +} \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index 808c405ff8..5333b45dde 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -416,8 +416,8 @@ gulp.task('demos', function(){ gulp.task('demos:all', ['demos'], function() { return gulp - .src('dist/demos/component-docs/*') - .pipe(gulp.dest('dist/ionic-site/docs/v2/components/demo/')) + .src('dist/demos/component-docs/**/*') + .pipe(gulp.dest('dist/ionic-site/docs/v2/components/demo/')) }); gulp.task('publish', function(done) { diff --git a/ionic/components.ts b/ionic/components.ts index a4ff6ecc97..cde02aa715 100644 --- a/ionic/components.ts +++ b/ionic/components.ts @@ -6,7 +6,7 @@ export * from 'ionic/components/blur/blur' export * from 'ionic/components/button/button' export * from 'ionic/components/checkbox/checkbox' export * from 'ionic/components/content/content' -export * from 'ionic/components/form/input' +export * from 'ionic/components/form/form' export * from 'ionic/components/icon/icon' export * from 'ionic/components/item/item' export * from 'ionic/components/item/item-group' diff --git a/ionic/components/button/button.scss b/ionic/components/button/button.scss index a89c8b3f2a..eeb28cb16d 100644 --- a/ionic/components/button/button.scss +++ b/ionic/components/button/button.scss @@ -121,8 +121,8 @@ a[button] { text-decoration: none; } -.padding > button[block]:first-child, -.padding > [button][block]:first-child { +[padding] > button[block]:first-child, +[padding] > [button][block]:first-child { margin-top: 0; } diff --git a/ionic/components/checkbox/checkbox.ts b/ionic/components/checkbox/checkbox.ts index d9814214d5..de763f43de 100644 --- a/ionic/components/checkbox/checkbox.ts +++ b/ionic/components/checkbox/checkbox.ts @@ -1,8 +1,7 @@ -import {Component, View, Directive, ElementRef, Optional, NgControl} from 'angular2/angular2'; +import {Component, View, Directive, Optional, NgControl} from 'angular2/angular2'; import {Ion} from '../ion'; -import {IonInput} from '../form/input'; -import {IonicConfig} from '../../config/config'; +import {IonicForm} from '../form/form'; /** * The checkbox is no different than the HTML checkbox input, except it's styled differently @@ -44,21 +43,14 @@ import {IonicConfig} from '../../config/config'; '' + '' }) -export class Checkbox extends Ion { - /** - * TODO - * @param {ElementRef} elementRef TODO - * @param {IonicConfig} ionicConfig TODO - * @param {NgControl=} ngControl TODO - */ +export class Checkbox { + constructor( - elementRef: ElementRef, - config: IonicConfig, + form: IonicForm, @Optional() ngControl: NgControl ) { - super(elementRef, config); - this.tabIndex = 0; - this.id = IonInput.nextId(); + this.form = form; + form.register(this); this.onChange = (_) => {}; this.onTouched = (_) => {}; @@ -72,8 +64,7 @@ export class Checkbox extends Ion { * TODO */ onInit() { - super.onInit(); - this.labelId = 'label-' + this.id; + this.labelId = 'label-' + this.inputId; } /** @@ -121,4 +112,8 @@ export class Checkbox extends Ion { * @param {Function} fn onTouched event handler. */ registerOnTouched(fn) { this.onTouched = fn; } + + onDestroy() { + this.form.deregister(this); + } } diff --git a/ionic/components/content/content.scss b/ionic/components/content/content.scss index 35c1f0278a..e6b71c8744 100644 --- a/ionic/components/content/content.scss +++ b/ionic/components/content/content.scss @@ -33,35 +33,33 @@ scroll-content { $content-padding: 16px !default; -.padding, [padding], -.padding > scroll-content, [padding] > scroll-content { padding: $content-padding; } -.padding-top { +[padding-top] { padding-top: $content-padding; } -.padding-right { +[padding-right] { padding-right: $content-padding; } -.padding-bottom { +[padding-bottom] { padding-bottom: $content-padding; } -.padding-left { +[padding-left] { padding-left: $content-padding; } -.padding-vertical { +[padding-vertical] { padding-top: $content-padding; padding-bottom: $content-padding; } -.padding-horizontal { +[padding-horizontal] { padding-right: $content-padding; padding-left: $content-padding; } diff --git a/ionic/components/content/modes/md.scss b/ionic/components/content/modes/md.scss index 64e33ab07b..e45f52027c 100644 --- a/ionic/components/content/modes/md.scss +++ b/ionic/components/content/modes/md.scss @@ -5,35 +5,33 @@ $content-padding-md: 16px !default; -.padding, [padding], -.padding > scroll-content, [padding] > scroll-content { padding: $content-padding-md; } -.padding-top { +[padding-top] { padding-top: $content-padding-md; } -.padding-right { +[padding-right] { padding-right: $content-padding-md; } -.padding-bottom { +[padding-bottom] { padding-bottom: $content-padding-md; } -.padding-left { +[padding-left] { padding-left: $content-padding-md; } -.padding-vertical { +[padding-vertical] { padding-top: $content-padding-md; padding-bottom: $content-padding-md; } -.padding-horizontal { +[padding-horizontal] { padding-right: $content-padding-md; padding-left: $content-padding-md; } diff --git a/ionic/components/form/focus-holder.ts b/ionic/components/form/focus-holder.ts deleted file mode 100644 index e93124adc1..0000000000 --- a/ionic/components/form/focus-holder.ts +++ /dev/null @@ -1,96 +0,0 @@ -import {Component, Directive, View, Host, Attribute, ElementRef, forwardRef} from 'angular2/angular2'; - -import {IonicConfig} from '../../config/config'; -import {IonInput} from './input'; - -/** - * TODO - */ -@Component({ - selector: 'focus-holder' -}) -@View({ - template: '', - directives: [forwardRef(() => FocusInput)] -}) -export class FocusHolder { - /** - * TODO - */ - constructor() { - this.i = []; - } - - /** - * TODO - * @param {TODO} inputType TODO - */ - setFocusHolder(inputType) { - this.i[2].type = inputType; - this.i[2].setFocus(); - } - - /** - * TODO - * @param {TODO} tabIndex TODO - */ - receivedFocus(tabIndex) { - if (tabIndex === '999') { - // focus on the previous input - IonInput.focusPrevious(); - - } else if (tabIndex === '1001') { - // focus on the next input - IonInput.focusNext(); - } - } - - /** - * TODO - * @param {TODO} input TODO - */ - register(input) { - this.i.push(input); - } -} - - -@Directive({ - selector: 'input', - host: { - '[type]': 'type', - '(focus)': 'holder.receivedFocus(tabindex)', - '(keydown)': 'keydown($event)' - } -}) -class FocusInput { - constructor( - elementRef: ElementRef, - @Host() holder: FocusHolder, - @Attribute('tabindex') tabindex: string - ) { - this.elementRef = elementRef; - this.holder = holder; - this.tabindex = tabindex; - this.holder.register(this); - } - - setFocus() { - this.elementRef.nativeElement.focus(); - } - - keydown(ev) { - // prevent any keyboard typing when a holder has focus - ev.preventDefault(); - ev.stopPropagation(); - } - - get type() { - // default to text type if unknown - return this._t || 'text'; - } - - set type(val) { - this._t = val; - } -} diff --git a/ionic/components/form/form.ts b/ionic/components/form/form.ts new file mode 100644 index 0000000000..98f6ff648c --- /dev/null +++ b/ionic/components/form/form.ts @@ -0,0 +1,235 @@ +import {Injectable, NgZone} from 'angular2/angular2'; + +import {IonicConfig} from '../../config/config'; +import {raf} from '../../util/dom'; + +/** + * The Input component is used to focus text input elements. + * + * The `focusNext()` and `focusPrevious()` methods make it easy to focus input elements across all devices. + * + * @usage + * ```html + * + * Name + * + * + * ``` + */ + @Injectable() +export class IonicForm { + + constructor(config: IonicConfig, zone: NgZone) { + this._config = config; + this._zone = zone; + + this._inputs = []; + this._ids = -1; + this._focused = null; + + zone.runOutsideAngular(() => { + if (this._config.get('keyboardScrollAssist')) { + this.initHolders(document); + } + + if (this._config.get('keyboardInputListener') !== false) { + this.initKeyInput(document); + } + }); + + } + + initKeyInput(document) { + /* Focus Outline + * -------------------------------------------------- + * When a keydown event happens, from a tab key, then the + * 'key-input' class is added to the body element so focusable + * elements have an outline. On a mousedown or touchstart + * event then the 'key-input' class is removed. + */ + + let isKeyInputEnabled = false; + + function keyDown(ev) { + if (!isKeyInputEnabled && ev.keyCode == 9) { + isKeyInputEnabled = true; + raf(enableKeyInput); + } + } + + function pointerDown() { + isKeyInputEnabled = false; + raf(enableKeyInput); + } + + + function enableKeyInput() { + document.body.classList[isKeyInputEnabled ? 'add' : 'remove']('key-input'); + + document.removeEventListener('mousedown', pointerDown); + document.removeEventListener('touchstart', pointerDown); + + if (isKeyInputEnabled) { + document.addEventListener('mousedown', pointerDown); + document.addEventListener('touchstart', pointerDown); + } + } + + document.addEventListener('keydown', keyDown); + } + + initHolders(document) { + // raw DOM fun + this._holder = document.createElement('focus-holder'); + + this._prev = document.createElement('input'); + this._prev.tabIndex = NO_FOCUS_TAB_INDEX; + this._holder.appendChild(this._prev); + + this._next = document.createElement('input'); + this._next.tabIndex = NO_FOCUS_TAB_INDEX; + this._holder.appendChild(this._next); + + this._temp = document.createElement('input'); + this._temp.tabIndex = NO_FOCUS_TAB_INDEX; + this._holder.appendChild(this._temp); + + document.body.appendChild(this._holder); + + function preventDefault(ev) { + ev.preventDefault(); + ev.stopPropagation(); + } + + this._prev.addEventListener('keydown', preventDefault); + this._next.addEventListener('keydown', preventDefault); + this._temp.addEventListener('keydown', preventDefault); + + this._prev.addEventListener('focus', () => { + this.focusPrevious(); + }); + + this._next.addEventListener('focus', () => { + this.focusNext(); + }); + + let self = this; + let resetTimer; + function queueReset() { + clearTimeout(resetTimer); + + resetTimer = setTimeout(function() { + self._zone.run(() => { + self.resetInputs(); + }); + }, 100); + } + + document.addEventListener('focusin', queueReset); + document.addEventListener('focusout', queueReset); + } + + setFocusHolder(type) { + if (this._temp) { + this._temp.tabIndex = TEMP_TAB_INDEX; + + this._temp.type = type || 'text'; + console.debug('setFocusHolder', this._temp.type); + this._temp.focus(); + } + } + + /** + * @param {TODO} input TODO + */ + register(input) { + console.debug('register input', input); + + input.inputId = ++this._ids; + input.tabIndex = NORMAL_FOCUS_TAB_INDEX; + this._inputs.push(input); + } + + deregister(input) { + console.debug('deregister input', input); + + let index = this._inputs.indexOf(input); + if (index > -1) { + this._inputs.splice(index, 1); + } + if (input === this._focused) { + this._focused = null; + } + } + + resetInputs() { + this._focused = null; + + for (let i = 0, ii = this._inputs.length; i < ii; i++) { + if (!this._focused && this._inputs[i].hasFocus) { + this._focused = this._inputs[i]; + this._focused.tabIndex = ACTIVE_FOCUS_TAB_INDEX; + + } else { + this._inputs[i].tabIndex = NORMAL_FOCUS_TAB_INDEX; + } + } + + if (this._temp) { + this._temp.tabIndex = NO_FOCUS_TAB_INDEX; + + if (this._focused) { + // there's a focused input + this._prev.tabIndex = PREV_TAB_INDEX; + this._next.tabIndex = NEXT_TAB_INDEX; + + } else { + this._prev.tabIndex = this._next.tabIndex = NO_FOCUS_TAB_INDEX; + } + } + + } + + /** + * Focuses the previous input element, if it exists. + */ + focusPrevious() { + console.debug('focusPrevious'); + this.focusMove(-1); + } + + /** + * Focuses the next input element, if it exists. + */ + focusNext() { + console.debug('focusNext'); + this.focusMove(1); + } + + /** + * @param {Number} inc TODO + */ + focusMove(inc) { + let input = this._focused; + if (input) { + let index = this._inputs.indexOf(input); + if (index > -1 && (index + inc) < this._inputs.length) { + let siblingInput = this._inputs[index + inc]; + if (siblingInput) { + siblingInput.initFocus(); + return; + } + } + this._focused.initFocus(); + } + } + +} + +const NO_FOCUS_TAB_INDEX = -1; +const NORMAL_FOCUS_TAB_INDEX = 0; +const PREV_TAB_INDEX = 999; +const ACTIVE_FOCUS_TAB_INDEX = 1000; +const NEXT_TAB_INDEX = 1001; +const TEMP_TAB_INDEX = 2000; + diff --git a/ionic/components/form/input.ts b/ionic/components/form/input.ts deleted file mode 100644 index 6449beabb6..0000000000 --- a/ionic/components/form/input.ts +++ /dev/null @@ -1,87 +0,0 @@ -import {Directive, ElementRef, Query, QueryList} from 'angular2/angular2'; - -import {Ion} from '../ion'; -import {IonicApp} from '../app/app'; -import {IonicConfig} from '../../config/config'; - - -let inputRegistry = []; -let inputItemIds = -1; -let activeInput = null; -let lastInput = null; - -/** - * The Input component is used to focus text input elements. - * - * The `focusNext()` and `focusPrevious()` methods make it easy to focus input elements across all devices. - * - * @usage - * ```html - * - * Name - * - * - * ``` - */ -export class IonInput extends Ion { - /** - * @param {TODO} input TODO - */ - static registerInput(input) { - inputRegistry.push(input); - } - - /** - * TODO - * @param {TODO} input TODO - */ - static setAsLastInput(input) { - lastInput = input; - } - - /** - * Focuses the previous input element, if it exists. - */ - static focusPrevious() { - this.focusMove(-1); - } - - /** - * Focuses the next input element, if it exists. - */ - static focusNext() { - this.focusMove(1); - } - - /** - * @param {Number} inc TODO - */ - static focusMove(inc) { - let input = activeInput || lastInput; - if (input) { - - let index = inputRegistry.indexOf(input); - if (index > -1 && (index + inc) < inputRegistry.length) { - let siblingInput = inputRegistry[index + inc]; - siblingInput && siblingInput.initFocus(); - } - } - } - - /** - * @returns {Number} The ID of the next input element. - */ - static nextId() { - return ++inputItemIds; - } - - /** - * TODO - */ - static clearTabIndexes() { - for (let i = 0; i < inputRegistry.length; i++) { - inputRegistry[i].tabIndex = -1; - } - } - -} diff --git a/ionic/components/nav/nav-controller.ts b/ionic/components/nav/nav-controller.ts index 495381e92e..d1e6d52343 100644 --- a/ionic/components/nav/nav-controller.ts +++ b/ionic/components/nav/nav-controller.ts @@ -505,7 +505,7 @@ export class NavController extends Ion { * @private * TODO */ - createViewComponetRef(type, hostProtoViewRef, viewContainer, viewCtrlBindings) { + createViewComponentRef(type, hostProtoViewRef, viewContainer, viewCtrlBindings) { let bindings = this.bindings.concat(viewCtrlBindings); // the same guts as DynamicComponentLoader.loadNextToLocation diff --git a/ionic/components/nav/nav.ts b/ionic/components/nav/nav.ts index e110d6c813..5aa2b388a9 100644 --- a/ionic/components/nav/nav.ts +++ b/ionic/components/nav/nav.ts @@ -195,11 +195,11 @@ export class Nav extends NavController { // the component being loaded is an // Tabs is essentially a pane, cuz it has its own navbar and content containers let contentContainerRef = this._viewManager.getViewContainer(this.anchorElementRef()); - let viewComponetRef = this.createViewComponetRef(componentType, hostProtoViewRef, contentContainerRef, this.getBindings(viewCtrl)); - viewComponetRef.instance._paneView = true; + let viewComponentRef = this.createViewComponentRef(componentType, hostProtoViewRef, contentContainerRef, this.getBindings(viewCtrl)); + viewComponentRef.instance._paneView = true; viewCtrl.disposals.push(() => { - viewComponetRef.dispose(); + viewComponentRef.dispose(); }); viewCtrl.onReady().then(() => { @@ -210,9 +210,9 @@ export class Nav extends NavController { // normal ion-view going into pane this.getPane(structure, viewCtrl, (pane) => { // add the content of the view into the pane's content area - let viewComponetRef = this.createViewComponetRef(componentType, hostProtoViewRef, pane.contentContainerRef, this.getBindings(viewCtrl)); + let viewComponentRef = this.createViewComponentRef(componentType, hostProtoViewRef, pane.contentContainerRef, this.getBindings(viewCtrl)); viewCtrl.disposals.push(() => { - viewComponetRef.dispose(); + viewComponentRef.dispose(); // remove the pane if there are no view items left pane.totalViews--; @@ -226,10 +226,10 @@ export class Nav extends NavController { // a new ComponentRef has been created // set the ComponentRef's instance to this ViewController - viewCtrl.setInstance(viewComponetRef.instance); + viewCtrl.setInstance(viewComponentRef.instance); // remember the ElementRef to the content that was just created - viewCtrl.viewElementRef(viewComponetRef.location); + viewCtrl.viewElementRef(viewComponentRef.location); // get the NavController's container for navbars, which is // the place this NavController will add each ViewController's navbar diff --git a/ionic/components/nav/test/nav-controller.spec.ts b/ionic/components/nav/test/nav-controller.spec.ts index 2a41a025ae..cfcafec3c3 100644 --- a/ionic/components/nav/test/nav-controller.spec.ts +++ b/ionic/components/nav/test/nav-controller.spec.ts @@ -1,42 +1,101 @@ +// import { +// ddescribe, +// describe, +// xdescribe, +// it, +// iit, +// xit, +// expect, +// beforeEach, +// afterEach, +// AsyncTestCompleter, +// inject, +// beforeEachBindings +// } from 'angular2/test'; + +// import {Compiler} from 'angular2/angular2'; + import { NavController, IonicConfig, + Page, ViewController } from 'ionic/ionic'; + export function run() { - describe("NavController", function(){ - beforeEach( function(){ - this.nav = new NavController(null, null, new IonicConfig(), null, null, null, null, null); + describe("NavController", () => { + let nav; + + class FirstPage {} + class SecondPage {} + class ThirdPage {} + + function mockTransitionFn(enteringView, leavingView, opts, cb) { + let destroys = []; + + nav._views.forEach(view => { + if (view) { + if (view.shouldDestroy) { + destroys.push(view); + + } else if (view.state === 2 && view.shouldCache) { + view.shouldCache = false; + } + } + }); + + destroys.forEach(view => { + nav.remove(view); + view.destroy(); + }); + cb(); + } + + function mockCanGoBackFn() { + return true; + } + + // beforeEach(inject([Compiler], compiler => { + beforeEach(() => { + nav = new NavController(null, null, new IonicConfig(), null, null, null, null, null); }); - it('should exist', function(){ - expect(this.nav).not.toBeUndefined(); + it('should exist', () => { + expect(nav).not.toBeUndefined(); }); - describe("getActive", function(){ - it('should return null if there is no active view', function(){ - var active = this.nav.getActive(); + describe("getActive", () => { + it('should return null if there is no active view', () => { + var active = nav.getActive(); expect(active).toBe(null); }); - it('should return the first active page', function(){ + it('should return the first active page', () => { let activeView = new ViewController(); activeView.state = 1; // ACTIVE_STATE - this.nav.add(activeView); - var active = this.nav.getActive(); + nav.add(activeView); + var active = nav.getActive(); + + expect(active).toBe(activeView); + + let secondActiveView = new ViewController(); + secondActiveView.state = 1; // ACTIVE_STATE + + nav.add(secondActiveView); + active = nav.getActive(); expect(active).toBe(activeView); }); }); - describe("push", function(){ - it('should return a rejected Promise if componentType is falsy', function(done){ + describe("push", () => { + it('should return a rejected Promise if componentType is falsy', done => { let s = jasmine.createSpy('success'); let f = jasmine.createSpy('fail'); - let promise = this.nav.push(undefined, {}, {}); + let promise = nav.push(undefined, {}, {}); promise.then(s, f).then(() => { expect(s).not.toHaveBeenCalled(); @@ -45,21 +104,108 @@ export function run() { }); }); - it('should throw an error if componentType truthy, but is not a function', function(){ - let push = () => this.nav.push({}, {}, {}); + it('should throw an error if componentType truthy, but is not a function', () => { + let push = () => nav.push({}, {}, {}); expect(push).toThrow(); - push = () => this.nav.push("string", {}, {}); + push = () => nav.push("string", {}, {}); expect(push).toThrow(); - push = () => this.nav.push(42, {}, {}); + push = () => nav.push(42, {}, {}); expect(push).toThrow(); - push = () => this.nav.push(true, {}, {}); + push = () => nav.push(true, {}, {}); expect(push).toThrow(); }); - }) - }); + it('to add the pushed page to the nav stack', (done) => { + expect(FirstPage).toBeDefined(); + expect(nav._views.length).toBe(0); + spyOn(nav, 'add').and.callThrough(); + + nav.transition = mockTransitionFn; + nav.push(FirstPage, {}, {}).then(() => { + expect(nav.add).toHaveBeenCalled(); + expect(nav._views.length).toBe(1); + done(); + }); + }); + }); + + describe("setViews", () => { + it('should return a resolved Promise if components is falsy', done => { + let s = jasmine.createSpy('success'); + let f = jasmine.createSpy('fail'); + + let promise = nav.setViews(); + + promise.then(s, f).then(() => { + expect(s).toHaveBeenCalled(); + expect(f).not.toHaveBeenCalled(); + done(); + }); + }); + + it('replace views with the supplied views', () => { + let vc1 = new ViewController(), + vc2 = new ViewController(), + vc3 = new ViewController(); + nav._views = [vc1, vc2, vc3]; + let arr = [FirstPage, SecondPage, ThirdPage]; + + nav.transition = mockTransitionFn; + nav.setViews(arr); + + //_views[0] will be transitioned out of + expect(nav._views[1].componentType).toBe(FirstPage); + expect(nav._views[2].componentType).toBe(SecondPage); + expect(nav._views[3].componentType).toBe(ThirdPage); + }); + + }); + + describe("insert", () => { + it('insert page at the specified index', () => { + nav._views = [{}, {}, {}]; + expect(nav._views[2].componentType).toBeUndefined(); + nav.insert(FirstPage, 2); + expect(nav._views[2].componentType).toBe(FirstPage); + }); + + it('push page if index >= _views.length', () => { + nav._views = [{}, {}, {}]; + spyOn(nav, 'push').and.callThrough(); + nav.insert(FirstPage, 2); + expect(nav.push).not.toHaveBeenCalled(); + + nav.transition = mockTransitionFn; + nav.insert(FirstPage, 4); + expect(nav._views[4].componentType).toBe(FirstPage); + expect(nav.push).toHaveBeenCalled(); + + nav.insert(FirstPage, 10); + expect(nav._views[5].componentType).toBe(FirstPage); + expect(nav.push.calls.count()).toBe(2); + }); + + }); + + describe("setRoot", () => { + it('remove previous views and set root', () => { + let vc1 = new ViewController(), + vc2 = new ViewController(), + vc3 = new ViewController(); + nav._views = [vc1, vc2, vc3]; + expect(nav._views.length).toBe(3); + + nav.transition = mockTransitionFn; + nav.setRoot(FirstPage); + //_views[0] will be transitioned out of + expect(nav._views.length).toBe(2); + expect(nav._views[1].componentType).toBe(FirstPage); + }); + }); + + }); } diff --git a/ionic/components/nav/view-controller.ts b/ionic/components/nav/view-controller.ts index 7169e22e39..38707e2bc6 100644 --- a/ionic/components/nav/view-controller.ts +++ b/ionic/components/nav/view-controller.ts @@ -36,7 +36,7 @@ export class ViewController { return done(); } - // compile the componenet and create a ProtoViewRef + // compile the component and create a ProtoViewRef navCtrl.compileView(this.componentType).then(hostProtoViewRef => { // get the pane the NavController wants to use diff --git a/ionic/components/search-bar/modes/ios.scss b/ionic/components/search-bar/modes/ios.scss index 2e702ce67a..c7f9d10922 100644 --- a/ionic/components/search-bar/modes/ios.scss +++ b/ionic/components/search-bar/modes/ios.scss @@ -15,8 +15,9 @@ $search-bar-ios-input-height: 28px !default; $search-bar-ios-input-placeholder-color: #9D9D9D !default; $search-bar-ios-input-text-color: #000 !default; $search-bar-ios-input-background-color: #FFFFFF !default; -$search-bar-ios-input-transition: all 0.3s linear !default; -//cubic-bezier(.25, .45, .05, 1) +$search-bar-ios-input-transition: all 400ms cubic-bezier(.25, .45, .05, 1) !default; +$search-bar-ios-cancel-transition: all 400ms cubic-bezier(.25, .45, .05, 1) !default; + $search-bar-ios-input-close-icon-color: #8F8E94 !default; $search-bar-ios-input-close-icon-svg: "" !default; $search-bar-ios-input-close-icon-size: 17px !default; @@ -88,19 +89,9 @@ $search-bar-ios-input-close-icon-size: 17px !default; .search-bar-cancel { @extend button[clear]; - // transition: all 2s cubic-bezier(.25, .45, .05, 1); - transition: $search-bar-ios-input-transition; - transition-duration: 3s !important; - margin-right: calc(-100%); - // transform: translate3d(100px,0,0); - // max-width: 0; - min-height: 0; -} - -.search-bar-cancel.left-align { - max-width: initial; - margin-right: 0; + transition: $search-bar-ios-cancel-transition; padding-left: 8px; + min-height: 0; padding-right: 0; } diff --git a/ionic/components/search-bar/modes/md.scss b/ionic/components/search-bar/modes/md.scss index 4605baf186..84a1c244bd 100644 --- a/ionic/components/search-bar/modes/md.scss +++ b/ionic/components/search-bar/modes/md.scss @@ -69,3 +69,7 @@ $search-bar-md-input-close-icon-size: 22px !default; right: 13px; top: 13px; } + +.search-bar-cancel { + display: none; +} diff --git a/ionic/components/search-bar/search-bar.ts b/ionic/components/search-bar/search-bar.ts index 7bc2933142..766fe60c6d 100644 --- a/ionic/components/search-bar/search-bar.ts +++ b/ionic/components/search-bar/search-bar.ts @@ -74,6 +74,16 @@ export class SearchBar extends Ion { this.query = ''; } + // Add the margin for iOS + afterViewInit() { + this.cancelButton = this.elementRef.nativeElement.querySelector('.search-bar-cancel'); + + if (this.cancelButton) { + this.cancelWidth = this.cancelButton.offsetWidth; + this.cancelButton.style.marginRight = "-" + this.cancelWidth + "px"; + } + } + /** * Much like ngModel, this is called from our valueAccessor for the attached * ControlDirective to update the value internally. @@ -99,10 +109,18 @@ export class SearchBar extends Ion { inputFocused() { this.isFocused = true; this.shouldLeftAlign = true; + + if (this.cancelButton) { + this.cancelButton.style.marginRight = "0px"; + } } inputBlurred() { this.isFocused = false; this.shouldLeftAlign = this.value.trim() != ''; + + if (this.cancelButton) { + this.cancelButton.style.marginRight = "-" + this.cancelWidth + "px"; + } } clearInput() { diff --git a/ionic/components/search-bar/test/floating/main.html b/ionic/components/search-bar/test/floating/main.html index da43d4f498..9d04b18b29 100644 --- a/ionic/components/search-bar/test/floating/main.html +++ b/ionic/components/search-bar/test/floating/main.html @@ -13,6 +13,8 @@ + + diff --git a/ionic/components/switch/switch.ts b/ionic/components/switch/switch.ts index 306f57622a..a5da0d74cf 100644 --- a/ionic/components/switch/switch.ts +++ b/ionic/components/switch/switch.ts @@ -10,8 +10,7 @@ import { forwardRef } from 'angular2/angular2'; -import {Ion} from '../ion'; -import {IonInput} from '../form/input'; +import {IonicForm} from '../form/form'; import {IonicConfig} from '../../config/config'; import {pointerCoord} from '../../util/dom'; @@ -109,7 +108,7 @@ class MediaSwitch { '', directives: [MediaSwitch] }) -export class Switch extends Ion { +export class Switch { /** * TODO * @param {ElementRef} elementRef TODO @@ -117,24 +116,24 @@ export class Switch extends Ion { * @param {NgControl=} ngControl TODO */ constructor( + form: IonicForm, elementRef: ElementRef, config: IonicConfig, @Optional() private ngControl: NgControl ) { - super(elementRef, config); - let self = this; + this.form = form; + form.register(this); - self.id = IonInput.nextId(); - self.tabIndex = 0; - self.lastTouch = 0; - self.mode = config.get('mode'); + this.lastTouch = 0; + this.mode = config.get('mode'); - self.onChange = (_) => {}; - self.onTouched = (_) => {}; + this.onChange = (_) => {}; + this.onTouched = (_) => {}; if (ngControl) ngControl.valueAccessor = this; + let self = this; function pointerMove(ev) { let currentX = pointerCoord(ev).x; @@ -156,21 +155,20 @@ export class Switch extends Ion { } this.addMoveListener = function() { - this.switchEle.addEventListener('touchmove', pointerMove); - this.switchEle.addEventListener('mousemove', pointerMove); + self.switchEle.addEventListener('touchmove', pointerMove); + self.switchEle.addEventListener('mousemove', pointerMove); elementRef.nativeElement.addEventListener('mouseout', pointerOut); }; this.removeMoveListener = function() { - this.switchEle.removeEventListener('touchmove', pointerMove); - this.switchEle.removeEventListener('mousemove', pointerMove); + self.switchEle.removeEventListener('touchmove', pointerMove); + self.switchEle.removeEventListener('mousemove', pointerMove); elementRef.nativeElement.removeEventListener('mouseout', pointerOut); }; } onInit() { - super.onInit(); - this.labelId = 'label-' + this.id; + this.labelId = 'label-' + this.inputId; } /** @@ -234,6 +232,7 @@ export class Switch extends Ion { onDestroy() { this.removeMoveListener(); this.switchEle = this.addMoveListener = this.removeMoveListener = null; + this.form.deregister(this); } isDisabled(ev) { diff --git a/ionic/components/tabs/tab.ts b/ionic/components/tabs/tab.ts index d680c7ac0d..2bee3ab38d 100644 --- a/ionic/components/tabs/tab.ts +++ b/ionic/components/tabs/tab.ts @@ -155,17 +155,17 @@ export class Tab extends NavController { loadContainer(componentType, hostProtoViewRef, viewCtrl, done) { - let viewComponetRef = this.createViewComponetRef(componentType, hostProtoViewRef, this.contentContainerRef, this.getBindings(viewCtrl)); + let viewComponentRef = this.createViewComponentRef(componentType, hostProtoViewRef, this.contentContainerRef, this.getBindings(viewCtrl)); viewCtrl.disposals.push(() => { - viewComponetRef.dispose(); + viewComponentRef.dispose(); }); // a new ComponentRef has been created // set the ComponentRef's instance to this ViewController - viewCtrl.setInstance(viewComponetRef.instance); + viewCtrl.setInstance(viewComponentRef.instance); // remember the ElementRef to the content that was just created - viewCtrl.viewElementRef(viewComponetRef.location); + viewCtrl.viewElementRef(viewComponentRef.location); // get the NavController's container for navbars, which is // the place this NavController will add each ViewController's navbar diff --git a/ionic/components/text-input/text-input.ts b/ionic/components/text-input/text-input.ts index 3db3e6bfb4..343552f943 100644 --- a/ionic/components/text-input/text-input.ts +++ b/ionic/components/text-input/text-input.ts @@ -1,9 +1,8 @@ import {Directive, View, Host, Optional, ElementRef, Attribute, Query, QueryList, NgZone} from 'angular2/angular2'; import {IonicConfig} from '../../config/config'; -import {IonInput} from '../form/input'; +import {IonicForm} from '../form/form'; import {Label} from './label'; -import {Ion} from '../ion'; import {IonicApp} from '../app/app'; import {Content} from '../content/content'; import * as dom from '../../util/dom'; @@ -15,22 +14,18 @@ import {IonicPlatform} from '../../platform/platform'; */ @Directive({ selector: 'ion-input', - inputs: [ - 'tabIndex' - ], host: { '(focus)': 'receivedFocus(true)', '(blur)': 'receivedFocus(false)', '(touchstart)': 'pointerStart($event)', '(touchend)': 'pointerEnd($event)', '(mouseup)': 'pointerEnd($event)', - '[class.has-focus]': 'inputHasFocus', - '[class.has-value]': 'inputHasValue', - '[tabIndex]': 'activeTabIndex', + '[class.has-focus]': 'hasFocus', + '[class.has-value]': 'hasValue', 'class': 'item' } }) -export class TextInput extends Ion { +export class TextInput { /** * TODO * @param {ElementRef} elementRef TODO @@ -42,31 +37,30 @@ export class TextInput extends Ion { * @param {QueryList