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}}
' +
+ '
{{button.text}} ' +
+ '
' +
+ '
' +
+ '{{destructiveText}} ' +
+ '
' +
+ '
' +
+ '{{cancelText}} ' +
+ '
' +
+ '
'
+ }
+});
+;
+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}}
' +
+ '
{{button.text}} ' +
+ '
' +
+ '
' +
+ '{{destructiveText}} ' +
+ '
' +
+ '
' +
+ '{{cancelText}} ' +
+ '
' +
+ '
'
+ }
+});
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",