ionic-angular
Version:
[](https://circleci.com/gh/driftyco/ionic)
207 lines (185 loc) • 6.68 kB
JavaScript
/**
* @ngdoc service
* @name $ionicActionSheet
* @module ionic
* @description
* The Action Sheet is a slide-up pane that lets the user choose from a set of options.
* Dangerous options are highlighted in red and made obvious.
*
* There are easy ways to cancel out of the action sheet, such as tapping the backdrop or even
* hitting escape on the keyboard for desktop testing.
*
* 
*
* @usage
* To trigger an Action Sheet in your code, use the $ionicActionSheet service in your angular controllers:
*
* ```js
* angular.module('mySuperApp', ['ionic'])
* .controller(function($scope, $ionicActionSheet, $timeout) {
*
* // Triggered on a button click, or some other target
* $scope.show = function() {
*
* // Show the action sheet
* var hideSheet = $ionicActionSheet.show({
* buttons: [
* { text: '<b>Share</b> This' },
* { text: 'Move' }
* ],
* destructiveText: 'Delete',
* titleText: 'Modify your album',
* cancelText: 'Cancel',
* cancel: function() {
// add cancel code..
},
* buttonClicked: function(index) {
* return true;
* }
* });
*
* // For example's sake, hide the sheet after two seconds
* $timeout(function() {
* hideSheet();
* }, 2000);
*
* };
* });
* ```
*
*/
IonicModule
.factory('$ionicActionSheet', [
'$rootScope',
'$compile',
'$animate',
'$timeout',
'$ionicTemplateLoader',
'$ionicPlatform',
'$ionicBody',
'IONIC_BACK_PRIORITY',
function($rootScope, $compile, $animate, $timeout, $ionicTemplateLoader, $ionicPlatform, $ionicBody, IONIC_BACK_PRIORITY) {
return {
show: actionSheet
};
/**
* @ngdoc method
* @name $ionicActionSheet#show
* @description
* Load and return a new action sheet.
*
* A new isolated scope will be created for the
* action sheet and the new element will be appended into the body.
*
* @param {object} options The options for this ActionSheet. Properties:
*
* - `[Object]` `buttons` Which buttons to show. Each button is an object with a `text` field.
* - `{string}` `titleText` The title to show on the action sheet.
* - `{string=}` `cancelText` the text for a 'cancel' button on the action sheet.
* - `{string=}` `destructiveText` The text for a 'danger' on the action sheet.
* - `{function=}` `cancel` Called if the cancel button is pressed, the backdrop is tapped or
* the hardware back button is pressed.
* - `{function=}` `buttonClicked` Called when one of the non-destructive buttons is clicked,
* with the index of the button that was clicked and the button object. Return true to close
* the action sheet, or false to keep it opened.
* - `{function=}` `destructiveButtonClicked` Called when the destructive button is clicked.
* Return true to close the action sheet, or false to keep it opened.
* - `{boolean=}` `cancelOnStateChange` Whether to cancel the actionSheet when navigating
* to a new state. Default true.
* - `{string}` `cssClass` The custom CSS class name.
*
* @returns {function} `hideSheet` A function which, when called, hides & cancels the action sheet.
*/
function actionSheet(opts) {
var scope = $rootScope.$new(true);
extend(scope, {
cancel: noop,
destructiveButtonClicked: noop,
buttonClicked: noop,
$deregisterBackButton: noop,
buttons: [],
cancelOnStateChange: true
}, opts || {});
function textForIcon(text) {
if (text && /icon/.test(text)) {
scope.$actionSheetHasIcon = true;
}
}
for (var x = 0; x < scope.buttons.length; x++) {
textForIcon(scope.buttons[x].text);
}
textForIcon(scope.cancelText);
textForIcon(scope.destructiveText);
// Compile the template
var element = scope.element = $compile('<ion-action-sheet ng-class="cssClass" buttons="buttons"></ion-action-sheet>')(scope);
// Grab the sheet element for animation
var sheetEl = jqLite(element[0].querySelector('.action-sheet-wrapper'));
var stateChangeListenDone = scope.cancelOnStateChange ?
$rootScope.$on('$stateChangeSuccess', function() { scope.cancel(); }) :
noop;
// removes the actionSheet from the screen
scope.removeSheet = function(done) {
if (scope.removed) return;
scope.removed = true;
sheetEl.removeClass('action-sheet-up');
$timeout(function() {
// wait to remove this due to a 300ms delay native
// click which would trigging whatever was underneath this
$ionicBody.removeClass('action-sheet-open');
}, 400);
scope.$deregisterBackButton();
stateChangeListenDone();
$animate.removeClass(element, 'active').then(function() {
scope.$destroy();
element.remove();
// scope.cancel.$scope is defined near the bottom
scope.cancel.$scope = sheetEl = null;
(done || noop)(opts.buttons);
});
};
scope.showSheet = function(done) {
if (scope.removed) return;
$ionicBody.append(element)
.addClass('action-sheet-open');
$animate.addClass(element, 'active').then(function() {
if (scope.removed) return;
(done || noop)();
});
$timeout(function() {
if (scope.removed) return;
sheetEl.addClass('action-sheet-up');
}, 20, false);
};
// registerBackButtonAction returns a callback to deregister the action
scope.$deregisterBackButton = $ionicPlatform.registerBackButtonAction(
function() {
$timeout(scope.cancel);
},
IONIC_BACK_PRIORITY.actionSheet
);
// called when the user presses the cancel button
scope.cancel = function() {
// after the animation is out, call the cancel callback
scope.removeSheet(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(index, opts.buttons[index]) === true) {
scope.removeSheet();
}
};
scope.destructiveButtonClicked = function() {
// Check if the destructive button click event returned true, which means
// we can close the action sheet
if (opts.destructiveButtonClicked() === true) {
scope.removeSheet();
}
};
scope.showSheet();
// Expose the scope on $ionicActionSheet's return value for the sake
// of testing it.
scope.cancel.$scope = scope;
return scope.cancel;
}
}]);