Skip to content
This repository has been archived by the owner on Sep 5, 2024. It is now read-only.

Commit

Permalink
feat($mdDialog): add prompt
Browse files Browse the repository at this point in the history
Add preconfigured dialog for prompt.

Fixes #4995. Closes #6769.
  • Loading branch information
zbjornson authored and ThomasBurleson committed Jan 31, 2016
1 parent 3f41ae2 commit 4d535e2
Show file tree
Hide file tree
Showing 5 changed files with 182 additions and 4 deletions.
3 changes: 3 additions & 0 deletions src/components/dialog/demoBasicUsage/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
<md-button class="md-primary md-raised" ng-click="showConfirm($event)" flex="100" flex-gt-md="auto">
Confirm Dialog
</md-button>
<md-button class="md-primary md-raised" ng-click="showPrompt($event)" flex="100" flex-gt-md="auto">
Prompt Dialog
</md-button>
<md-button class="md-primary md-raised" ng-click="showAdvanced($event)" flex="100" flex-gt-md="auto">
Custom Dialog
</md-button>
Expand Down
18 changes: 18 additions & 0 deletions src/components/dialog/demoBasicUsage/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,24 @@ angular.module('dialogDemo1', ['ngMaterial'])
});
};

$scope.showPrompt = function(ev) {
// Appending dialog to document.body to cover sidenav in docs app
var confirm = $mdDialog.prompt()
.title('What would you name your dog?')
.textContent('Bowser is a common name.')
.placeholder('dog name')
.ariaLabel('Dog name')
.targetEvent(ev)
.ok('Okay!')
.cancel('I\'m a cat person');

$mdDialog.show(confirm).then(function(result) {
$scope.status = 'You decided to name your dog ' + result + '.';
}, function() {
$scope.status = 'You didn\'t name your dog.';
});
};

$scope.showAdvanced = function(ev) {
var useFullScreen = ($mdMedia('sm') || $mdMedia('xs')) && $scope.customFullscreen;

Expand Down
47 changes: 43 additions & 4 deletions src/components/dialog/dialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,32 @@ function MdDialogDirective($$rAF, $mdTheming, $mdDialog) {
*
*/

/**
* @ngdoc method
* @name $mdDialog#prompt
*
* @description
* Builds a preconfigured dialog with the specified message and input box. You can call show and the promise returned
* will be resolved only if the user clicks the prompt action on the dialog, passing the input value as the first argument.
*
* @returns {obj} an `$mdDialogPreset` with the chainable configuration methods:
*
* Additionally, it supports the following methods:
*
* - $mdDialogPreset#title(string) - Sets the prompt title.
* - $mdDialogPreset#textContent(string) - Sets the prompt message.
* - $mdDialogPreset#htmlContent(string) - Sets the prompt message as HTML. Requires ngSanitize
* module to be loaded. HTML is not run through Angular's compiler.
* - $mdDialogPreset#placeholder(string) - Sets the placeholder text for the input.
* - $mdDialogPreset#ok(string) - Sets the prompt "Okay" button text.
* - $mdDialogPreset#cancel(string) - Sets the prompt "Cancel" button text.
* - $mdDialogPreset#theme(string) - Sets the theme of the prompt dialog.
* - $mdDialogPreset#targetEvent(DOMClickEvent=) - A click's event object. When passed in as an option,
* the location of the click will be used as the starting point for the opening animation
* of the the dialog.
*
*/

/**
* @ngdoc method
* @name $mdDialog#show
Expand Down Expand Up @@ -472,10 +498,15 @@ function MdDialogProvider($$interimElementProvider) {
methods: ['title', 'htmlContent', 'textContent', 'content', 'ariaLabel', 'ok', 'cancel',
'theme', 'css'],
options: advancedDialogOptions
})
.addPreset('prompt', {
methods: ['title', 'htmlContent', 'textContent', 'content', 'placeholder', 'ariaLabel',
'ok', 'cancel', 'theme', 'css'],
options: advancedDialogOptions
});

/* @ngInject */
function advancedDialogOptions($mdDialog, $mdTheming) {
function advancedDialogOptions($mdDialog, $mdTheming, $mdConstant) {
return {
template: [
'<md-dialog md-theme="{{ dialog.theme }}" aria-label="{{ dialog.ariaLabel }}" ng-class="dialog.css">',
Expand All @@ -486,25 +517,33 @@ function MdDialogProvider($$interimElementProvider) {
' <div ng-if="::!dialog.mdHtmlContent" class="md-dialog-content-body">',
' <p>{{::dialog.mdTextContent}}</p>',
' </div>',
' <md-input-container md-no-float ng-if="::dialog.$type == \'prompt\'" class="md-prompt-input-container">',
' <input ng-keypress="dialog.keypress($event)" md-autofocus ng-model="dialog.result" placeholder="{{::dialog.placeholder}}">',
' </md-input-container>',
' </md-dialog-content>',
' <md-dialog-actions>',
' <md-button ng-if="dialog.$type == \'confirm\'"' +
' <md-button ng-if="dialog.$type === \'confirm\' || dialog.$type === \'prompt\'"' +
' ng-click="dialog.abort()" class="md-primary">',
' {{ dialog.cancel }}',
' </md-button>',
' <md-button ng-click="dialog.hide()" class="md-primary" md-autofocus="dialog.$type!=\'confirm\'">',
' <md-button ng-click="dialog.hide()" class="md-primary" md-autofocus="dialog.$type===\'alert\'">',
' {{ dialog.ok }}',
' </md-button>',
' </md-dialog-actions>',
'</md-dialog>'
].join('').replace(/\s\s+/g, ''),
controller: function mdDialogCtrl() {
this.hide = function() {
$mdDialog.hide(true);
$mdDialog.hide(this.$type === 'prompt' ? this.result : true);
};
this.abort = function() {
$mdDialog.cancel();
};
this.keypress = function($event) {
if ($event.keyCode === $mdConstant.KEY_CODE.ENTER) {
$mdDialog.hide(this.result)
}
}
},
controllerAs: 'dialog',
bindToController: true,
Expand Down
5 changes: 5 additions & 0 deletions src/components/dialog/dialog.scss
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ md-dialog {
.md-dialog-content-body {
width:100%;
}

.md-prompt-input-container {
width: 100%;
box-sizing: border-box;
}
}

.md-actions, md-dialog-actions {
Expand Down
113 changes: 113 additions & 0 deletions src/components/dialog/dialog.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,119 @@ describe('$mdDialog', function() {
}));
});

describe('#prompt()', function() {
hasConfigurationMethods('prompt', ['title', 'htmlContent', 'textContent',
'content', 'placeholder', 'ariaLabel', 'ok', 'cancel', 'theme', 'css'
]);

it('shows a basic prompt dialog', inject(function($animate, $rootScope, $mdDialog) {
var parent = angular.element('<div>');
var resolved = false;
var promptAnswer;

$mdDialog.show(
$mdDialog
.prompt()
.parent(parent)
.title('Title')
.textContent('Hello world')
.placeholder('placeholder text')
.theme('some-theme')
.css('someClass anotherClass')
.ok('Next')
.cancel('Cancel')
).then(function(answer) {
resolved = true;
promptAnswer = answer;
});

$rootScope.$apply();
runAnimation();

var mdContainer = angular.element(parent[0].querySelector('.md-dialog-container'));
var mdDialog = mdContainer.find('md-dialog');
var mdContent = mdDialog.find('md-dialog-content');
var title = mdContent.find('h2');
var contentBody = mdContent[0].querySelector('.md-dialog-content-body');
var inputElement = mdContent.find('input');
var buttons = parent.find('md-button');
var theme = mdDialog.attr('md-theme');
var css = mdDialog.attr('class').split(' ');

expect(title.text()).toBe('Title');
expect(contentBody.textContent).toBe('Hello world');
expect(inputElement[0].placeholder).toBe('placeholder text')
expect(buttons.length).toBe(2);
expect(buttons.eq(0).text()).toBe('Next');
expect(theme).toBe('some-theme');
expect(css).toContain('someClass');
expect(css).toContain('anotherClass');
expect(mdDialog.attr('role')).toBe('dialog');

inputElement.eq(0).text('responsetext');
inputElement.scope().$apply("dialog.result = 'responsetext'")

buttons.eq(0).triggerHandler('click');

$rootScope.$apply();
runAnimation();

expect(resolved).toBe(true);
expect(promptAnswer).toBe('responsetext');
}));

it('should focus the input element on open', inject(function($mdDialog, $rootScope, $document) {
jasmine.mockElementFocus(this);

var parent = angular.element('<div>');

$mdDialog.show(
$mdDialog
.prompt()
.parent(parent)
.textContent('Hello world')
.placeholder('placeholder text')
)

runAnimation(parent.find('md-dialog'));

expect($document.activeElement).toBe(parent[0].querySelector('input'));
}));

it('should submit after ENTER key', inject(function($mdDialog, $rootScope, $timeout, $mdConstant) {
jasmine.mockElementFocus(this);
var parent = angular.element('<div>');
var response;

$mdDialog.show(
$mdDialog
.prompt()
.parent(parent)
.textContent('Hello world')
.placeholder('placeholder text')
).then(function(answer) {
response = answer;
});
runAnimation();

var container = angular.element(parent[0].querySelector('.md-dialog-container'));
var mdDialog = container.find('md-dialog');
var mdContent = mdDialog.find('md-dialog-content');
var inputElement = mdContent.find('input');

inputElement.scope().$apply("dialog.result = 'responsetext'")

inputElement.eq(0).triggerHandler({
type: 'keypress',
keyCode: $mdConstant.KEY_CODE.ENTER
});
runAnimation();
runAnimation();

expect(response).toBe('responsetext');
}));
});

describe('#build()', function() {
it('should support onShowing callbacks before `show()` starts', inject(function($mdDialog, $rootScope) {

Expand Down

0 comments on commit 4d535e2

Please sign in to comment.