From 2938e104c2e1b11a7a0743577eb29e5365b02d19 Mon Sep 17 00:00:00 2001 From: Max Lynch Date: Fri, 4 Oct 2013 23:20:18 -0500 Subject: [PATCH] Action sheet working --- dist/ionic-angular.js | 80 ++++++++++++++++++- dist/ionic.css | 28 +++++++ dist/ionic.js | 22 +++++ example/toderp2/js/app.js | 8 +- example/toderp2/js/controllers.js | 26 +++++- .../angular/src/directive/ionicActionSheet.js | 26 ++++++ js/ext/angular/src/directive/ionicContent.js | 2 +- .../angular/src/service/ionicActionSheet.js | 51 ++++++++++++ .../test/service/ionicActionSheet.unit.js | 0 js/ext/angular/tmpl/ionicTabBar.tmpl.html | 2 - js/ext/angular/tmpl/ionicTabs.tmpl.html | 12 --- js/views/actionSheetView.js | 21 +++++ scss/ionic/_actionSheet.scss | 40 ++++++++++ scss/ionic/_modal.scss | 1 - scss/ionic/_variables.scss | 5 ++ scss/ionic/ionic.scss | 3 + 16 files changed, 306 insertions(+), 21 deletions(-) create mode 100644 js/ext/angular/src/directive/ionicActionSheet.js create mode 100644 js/ext/angular/test/service/ionicActionSheet.unit.js delete mode 100644 js/ext/angular/tmpl/ionicTabBar.tmpl.html delete mode 100644 js/ext/angular/tmpl/ionicTabs.tmpl.html create mode 100644 js/views/actionSheetView.js create mode 100644 scss/ionic/_actionSheet.scss diff --git a/dist/ionic-angular.js b/dist/ionic-angular.js index 57daab4207..b47a576f89 100644 --- a/dist/ionic-angular.js +++ b/dist/ionic-angular.js @@ -1,5 +1,56 @@ angular.module('ionic.ui', ['ionic.ui.content', 'ionic.ui.tabs', 'ionic.ui.nav', 'ionic.ui.sideMenu']); ; +angular.module('ionic.service.actionSheet', ['ionic.service', 'ionic.ui.actionSheet']) + +.factory('ActionSheet', ['$rootScope', '$document', '$compile', 'TemplateLoader', function($rootScope, $document, $compile, TemplateLoader) { + return { + /** + * Load an action sheet with the given template string. + * + * A new isolated scope will be created for the + * action sheet and the new element will be appended into the body. + * + * @param {object} opts the options for this ActionSheet (see docs) + */ + show: function(opts) { + var scope = $rootScope.$new(true); + + angular.extend(scope, opts); + + scope.cancel = function() { + scope.$destroy(); + opts.cancel(); + } + + scope.buttonClicked = function(index) { + // Check if the button click event returned true, which means + // we can close the action sheet + if((opts.buttonClicked && opts.buttonClicked(index)) === true) { + scope.$destroy(); + } + }; + + scope.destructiveButtonClicked = function() { + // Check if the destructive button click event returned true, which means + // we can close the action sheet + if((opts.destructiveButtonClicked && opts.destructiveButtonClicked()) === true) { + scope.$destroy(); + } + } + + // Compile the template + var element = $compile('')(scope); + + var scope = element.scope(); + + $document[0].body.appendChild(element[0]); + + var sheet = ionic.views.ActionSheet({el: element[0] }); + scope.sheet = sheet; + return sheet; + } + }; +}]); ; ; angular.module('ionic.service.modal', ['ionic.service']) @@ -59,7 +110,34 @@ angular.module('ionic.service', []) } }]); ; -angular.module('ionic.ui.content', {}) +angular.module('ionic.ui.actionSheet', []) + +.directive('actionSheet', function() { + return { + restrict: 'E', + scope: true, + replace: true, + link: function($scope, $element){ + $scope.$on('$destroy', function() { + $element.remove(); + }); + }, + template: '
' + + '
' + + '
{{titleText}}
' + + '' + + '
' + + '
' + + '' + + '
' + + '
' + + '' + + '
' + + '
' + } +}); +; +angular.module('ionic.ui.content', []) // The content directive is a core scrollable content area // that is part of many View hierarchies diff --git a/dist/ionic.css b/dist/ionic.css index ebd708049a..585bb47ed9 100644 --- a/dist/ionic.css +++ b/dist/ionic.css @@ -1166,6 +1166,34 @@ address { font-style: normal; line-height: 1.42857; } +.action-sheet { + position: fixed; + z-index: 10; + width: calc(100% - 30px); + bottom: 0; + left: 15px; + overflow: hidden; } + .action-sheet .button { + display: block; + width: 100%; + padding: 10px; + border-radius: none; + background-color: transparent; + font-size: 18px; + color: #4a87ee; } + .action-sheet .button.destructive { + color: #ef4e3a; } + +.action-sheet-title { + font-size: 12px; + padding: 10px; + text-align: center; } + +.action-sheet-group { + border-radius: 3px; + background-color: rgba(255, 255, 255, 0.95); + margin-bottom: 10px; } + .bar { position: absolute; left: 0; diff --git a/dist/ionic.js b/dist/ionic.js index 28a441f154..f2f64732a3 100644 --- a/dist/ionic.js +++ b/dist/ionic.js @@ -1730,6 +1730,28 @@ window.ionic = { } })(window.ionic); ; +(function(ionic) { + /** + * An ActionSheet is the slide up menu popularized on iOS. + * + * You see it all over iOS apps, where it offers a set of options + * triggered after an action. + */ + ionic.views.ActionSheet = function(opts) { + this.el = opts.el; + }; + + ionic.views.ActionSheet.prototype = { + show: function() { + this.el.classList.add('active'); + }, + hide: function() { + this.el.classList.remove('active'); + } + }; + +})(ionic); +; (function(ionic) { diff --git a/example/toderp2/js/app.js b/example/toderp2/js/app.js index 5dea6d87ce..b0f3611b65 100644 --- a/example/toderp2/js/app.js +++ b/example/toderp2/js/app.js @@ -2,10 +2,16 @@ angular.module('ionic.todo', [ 'ionic.todo.services', 'ionic.todo.controllers', + 'ionic.service.modal', + 'ionic.service.actionSheet', + 'ionic.ui.nav', 'ionic.ui.sideMenu', + 'ionic.ui.actionSheet', - 'firebase', 'ngRoute', 'ngAnimate']) + 'firebase', + 'ngRoute', + 'ngAnimate']) // Our Firebase URL .constant('FIREBASE_URL', 'https://ionic-todo-demo.firebaseio.com/'); diff --git a/example/toderp2/js/controllers.js b/example/toderp2/js/controllers.js index e89390eb86..0f57763786 100644 --- a/example/toderp2/js/controllers.js +++ b/example/toderp2/js/controllers.js @@ -1,4 +1,4 @@ -angular.module('ionic.todo.controllers', ['ionic.todo', 'ionic.service.modal', 'firebase']) +angular.module('ionic.todo.controllers', ['ionic.todo']) // The main controller for the application .controller('TodoCtrl', function($scope, $rootScope, AuthService) { @@ -45,7 +45,7 @@ angular.module('ionic.todo.controllers', ['ionic.todo', 'ionic.service.modal', ' }) // The signup form controller -.controller('SignupCtrl', function($scope, AuthService, Modal) { +.controller('SignupCtrl', function($scope, AuthService, Modal, ActionSheet) { $scope.signupForm = {}; Modal.fromTemplateUrl('login.html', function(modal) { @@ -57,7 +57,27 @@ angular.module('ionic.todo.controllers', ['ionic.todo', 'ionic.service.modal', ' }; $scope.showLogin = function() { - $scope.loginModal && $scope.loginModal.show(); + //$scope.loginModal && $scope.loginModal.show(); + ActionSheet.show({ + buttons: [ + { text: 'Option 1' }, + { text: 'Option 2' }, + { text: 'Option 3' }, + ], + destructiveText: 'Delete life', + titleText: 'Are you sure about life?', + cancelText: 'Cancel', + cancel: function() { + console.log('CANCELLED'); + }, + buttonClicked: function(index) { + console.log('BUTTON CLICKED', index); + return true; + }, + destructiveButtonClicked: function() { + return true; + } + }); }; }) diff --git a/js/ext/angular/src/directive/ionicActionSheet.js b/js/ext/angular/src/directive/ionicActionSheet.js new file mode 100644 index 0000000000..6e247d5c3e --- /dev/null +++ b/js/ext/angular/src/directive/ionicActionSheet.js @@ -0,0 +1,26 @@ +angular.module('ionic.ui.actionSheet', []) + +.directive('actionSheet', function() { + return { + restrict: 'E', + scope: true, + replace: true, + link: function($scope, $element){ + $scope.$on('$destroy', function() { + $element.remove(); + }); + }, + template: '
' + + '
' + + '
{{titleText}}
' + + '' + + '
' + + '
' + + '' + + '
' + + '
' + + '' + + '
' + + '
' + } +}); diff --git a/js/ext/angular/src/directive/ionicContent.js b/js/ext/angular/src/directive/ionicContent.js index 424a988221..8bc10ce319 100644 --- a/js/ext/angular/src/directive/ionicContent.js +++ b/js/ext/angular/src/directive/ionicContent.js @@ -1,4 +1,4 @@ -angular.module('ionic.ui.content', {}) +angular.module('ionic.ui.content', []) // The content directive is a core scrollable content area // that is part of many View hierarchies diff --git a/js/ext/angular/src/service/ionicActionSheet.js b/js/ext/angular/src/service/ionicActionSheet.js index e69de29bb2..cc8d101e90 100644 --- a/js/ext/angular/src/service/ionicActionSheet.js +++ b/js/ext/angular/src/service/ionicActionSheet.js @@ -0,0 +1,51 @@ +angular.module('ionic.service.actionSheet', ['ionic.service', 'ionic.ui.actionSheet']) + +.factory('ActionSheet', ['$rootScope', '$document', '$compile', 'TemplateLoader', function($rootScope, $document, $compile, TemplateLoader) { + return { + /** + * Load an action sheet with the given template string. + * + * A new isolated scope will be created for the + * action sheet and the new element will be appended into the body. + * + * @param {object} opts the options for this ActionSheet (see docs) + */ + show: function(opts) { + var scope = $rootScope.$new(true); + + angular.extend(scope, opts); + + scope.cancel = function() { + scope.$destroy(); + opts.cancel(); + } + + scope.buttonClicked = function(index) { + // Check if the button click event returned true, which means + // we can close the action sheet + if((opts.buttonClicked && opts.buttonClicked(index)) === true) { + scope.$destroy(); + } + }; + + scope.destructiveButtonClicked = function() { + // Check if the destructive button click event returned true, which means + // we can close the action sheet + if((opts.destructiveButtonClicked && opts.destructiveButtonClicked()) === true) { + scope.$destroy(); + } + } + + // Compile the template + var element = $compile('')(scope); + + var scope = element.scope(); + + $document[0].body.appendChild(element[0]); + + var sheet = ionic.views.ActionSheet({el: element[0] }); + scope.sheet = sheet; + return sheet; + } + }; +}]); diff --git a/js/ext/angular/test/service/ionicActionSheet.unit.js b/js/ext/angular/test/service/ionicActionSheet.unit.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/js/ext/angular/tmpl/ionicTabBar.tmpl.html b/js/ext/angular/tmpl/ionicTabBar.tmpl.html deleted file mode 100644 index 92e4a57eb7..0000000000 --- a/js/ext/angular/tmpl/ionicTabBar.tmpl.html +++ /dev/null @@ -1,2 +0,0 @@ -
-
diff --git a/js/ext/angular/tmpl/ionicTabs.tmpl.html b/js/ext/angular/tmpl/ionicTabs.tmpl.html deleted file mode 100644 index 0eda98c893..0000000000 --- a/js/ext/angular/tmpl/ionicTabs.tmpl.html +++ /dev/null @@ -1,12 +0,0 @@ - diff --git a/js/views/actionSheetView.js b/js/views/actionSheetView.js new file mode 100644 index 0000000000..75900ba3d3 --- /dev/null +++ b/js/views/actionSheetView.js @@ -0,0 +1,21 @@ +(function(ionic) { + /** + * An ActionSheet is the slide up menu popularized on iOS. + * + * You see it all over iOS apps, where it offers a set of options + * triggered after an action. + */ + ionic.views.ActionSheet = function(opts) { + this.el = opts.el; + }; + + ionic.views.ActionSheet.prototype = { + show: function() { + this.el.classList.add('active'); + }, + hide: function() { + this.el.classList.remove('active'); + } + }; + +})(ionic); diff --git a/scss/ionic/_actionSheet.scss b/scss/ionic/_actionSheet.scss new file mode 100644 index 0000000000..7ed3129a61 --- /dev/null +++ b/scss/ionic/_actionSheet.scss @@ -0,0 +1,40 @@ +.action-sheet { + position: fixed; + + z-index: $zindex-modal; + + width: calc(100% - 30px); + + bottom: 0; + left: 15px; + + overflow: hidden; + + + .button { + display: block; + width: 100%; + padding: 10px; + border-radius: none; + background-color: transparent; + font-size: 18px; + + color: $brand-primary; + + &.destructive { + color: $brand-danger; + } + } +} + +.action-sheet-title { + font-size: 12px; + padding: 10px; + text-align: center; +} + +.action-sheet-group { + border-radius: $sheet-border-radius; + background-color: rgba($sheet-bg-color, $sheet-opacity); + margin-bottom: 10px; +} diff --git a/scss/ionic/_modal.scss b/scss/ionic/_modal.scss index 6fb7f9384b..aef5d51c70 100644 --- a/scss/ionic/_modal.scss +++ b/scss/ionic/_modal.scss @@ -16,7 +16,6 @@ background-color: $modal-bg-color; - // Active modal &.active { height: 100%; diff --git a/scss/ionic/_variables.scss b/scss/ionic/_variables.scss index 37365711a8..aabd82e3a4 100644 --- a/scss/ionic/_variables.scss +++ b/scss/ionic/_variables.scss @@ -361,6 +361,11 @@ $menu-animation-speed: 200ms; $modal-bg-color: #fff !default; +// Action Sheets +// ------------------------------- +$sheet-bg-color: rgba(255, 255, 255, 0.6) !default; +$sheet-opacity: 0.95 !default; +$sheet-border-radius: 3px !default; // Badges // ------------------------- diff --git a/scss/ionic/ionic.scss b/scss/ionic/ionic.scss index 198f51c0a6..d9547ae3a0 100644 --- a/scss/ionic/ionic.scss +++ b/scss/ionic/ionic.scss @@ -14,6 +14,9 @@ "grid", "type", + // Action Sheet + "actionSheet", + // Nav "bar", "tabs",