source: trip-planner-front/node_modules/angular-material/modules/closure/toast/toast.js@ 6a3a178

Last change on this file since 6a3a178 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 20.5 KB
Line 
1/*!
2 * AngularJS Material Design
3 * https://github.com/angular/material
4 * @license MIT
5 * v1.2.3
6 */
7goog.provide('ngmaterial.components.toast');
8goog.require('ngmaterial.components.button');
9goog.require('ngmaterial.core');
10/**
11 * @ngdoc module
12 * @name material.components.toast
13 * @description
14 * Toast and Snackbar component.
15 */
16MdToastDirective['$inject'] = ["$mdToast"];
17MdToastProvider['$inject'] = ["$$interimElementProvider"];
18angular.module('material.components.toast', [
19 'material.core',
20 'material.components.button'
21])
22 .directive('mdToast', MdToastDirective)
23 .provider('$mdToast', MdToastProvider);
24
25/* ngInject */
26function MdToastDirective($mdToast) {
27 return {
28 restrict: 'E',
29 link: function postLink(scope, element) {
30 element.addClass('_md'); // private md component indicator for styling
31
32 // When navigation force destroys an interimElement, then
33 // listen and $destroy() that interim instance...
34 scope.$on('$destroy', function() {
35 $mdToast.destroy();
36 });
37 }
38 };
39}
40
41/**
42 * @ngdoc service
43 * @name $mdToast
44 * @module material.components.toast
45 *
46 * @description
47 * `$mdToast` is a service to build a toast notification on any position
48 * on the screen with an optional duration, and provides a simple promise API.
49 *
50 * The toast will be always positioned at the `bottom`, when the screen size is
51 * between `600px` and `959px` (`sm` breakpoint)
52 *
53 * ## Restrictions on custom toasts
54 * - The toast's template must have an outer `<md-toast>` element.
55 * - For a toast action, use element with class `md-action`.
56 * - Add the class `md-capsule` for curved corners.
57 *
58 * ### Custom Presets
59 * Developers are also able to create their own preset, which can be easily used without repeating
60 * their options each time.
61 *
62 * <hljs lang="js">
63 * $mdToastProvider.addPreset('testPreset', {
64 * options: function() {
65 * return {
66 * template:
67 * '<md-toast>' +
68 * '<div class="md-toast-content">' +
69 * 'This is a custom preset' +
70 * '</div>' +
71 * '</md-toast>',
72 * controllerAs: 'toast',
73 * bindToController: true
74 * };
75 * }
76 * });
77 * </hljs>
78 *
79 * After you created your preset at config phase, you can easily access it.
80 *
81 * <hljs lang="js">
82 * $mdToast.show(
83 * $mdToast.testPreset()
84 * );
85 * </hljs>
86 *
87 * ## Parent container notes
88 *
89 * The toast is positioned using absolute positioning relative to its first non-static parent
90 * container. Thus, if the requested parent container uses static positioning, we will temporarily
91 * set its positioning to `relative` while the toast is visible and reset it when the toast is
92 * hidden.
93 *
94 * Because of this, it is usually best to ensure that the parent container has a fixed height and
95 * prevents scrolling by setting the `overflow: hidden;` style. Since the position is based off of
96 * the parent's height, the toast may be mispositioned if you allow the parent to scroll.
97 *
98 * You can, however, have a scrollable element inside of the container; just make sure the
99 * container itself does not scroll.
100 *
101 * <hljs lang="html">
102 * <div layout-fill id="toast-container">
103 * <md-content>
104 * I can have lots of content and scroll!
105 * </md-content>
106 * </div>
107 * </hljs>
108 *
109 * @usage
110 * <hljs lang="html">
111 * <div ng-controller="MyController">
112 * <md-button ng-click="openToast()">
113 * Open a Toast!
114 * </md-button>
115 * </div>
116 * </hljs>
117 *
118 * <hljs lang="js">
119 * var app = angular.module('app', ['ngMaterial']);
120 * app.controller('MyController', function($scope, $mdToast) {
121 * $scope.openToast = function($event) {
122 * $mdToast.show($mdToast.simple().textContent('Hello!'));
123 * // Could also do $mdToast.showSimple('Hello');
124 * };
125 * });
126 * </hljs>
127 */
128
129/**
130 * @ngdoc method
131 * @name $mdToast#showSimple
132 *
133 * @param {string} message The message to display inside the toast
134 * @description
135 * Convenience method which builds and shows a simple toast.
136 *
137 * @returns {promise} A promise that can be resolved with `$mdToast.hide()`.
138 */
139
140/**
141 * @ngdoc method
142 * @name $mdToast#simple
143 *
144 * @description
145 * Builds a preconfigured toast.
146 *
147 * @returns {obj} a `$mdToastPreset` with the following chainable configuration methods.
148 *
149 * _**Note:** These configuration methods are provided in addition to the methods provided by
150 * the `build()` and `show()` methods below._
151 *
152 * <table class="md-api-table methods">
153 * <thead>
154 * <tr>
155 * <th>Method</th>
156 * <th>Description</th>
157 * </tr>
158 * </thead>
159 * <tbody>
160 * <tr>
161 * <td>`.textContent(string)`</td>
162 * <td>Sets the toast content to the specified string</td>
163 * </tr>
164 * <tr>
165 * <td>`.action(string)`</td>
166 * <td>
167 * Adds an action button. <br/>
168 * If clicked, the promise (returned from `show()`) will resolve with the value `'ok'`;
169 * otherwise, it is resolved with `true` after a `hideDelay` timeout.
170 * </td>
171 * </tr>
172 * <tr>
173 * <td>`.actionKey(string)`</td>
174 * <td>
175 * Adds a hotkey for the action button to the page. <br/>
176 * If the `actionKey` and `Control` key are pressed, the toast's action will be triggered.
177 * </td>
178 * </tr>
179 * <tr>
180 * <td>`.actionHint(string)`</td>
181 * <td>
182 * Text that a screen reader will announce to let the user know how to activate the
183 * action. <br>
184 * If an `actionKey` is defined, this defaults to:
185 * 'Press Control-"`actionKey`" to ' followed by the `action`.
186 * </td>
187 * </tr>
188 * <tr>
189 * <td>`.dismissHint(string)`</td>
190 * <td>
191 * Text that a screen reader will announce to let the user know how to dismiss the toast.
192 * <br>Defaults to: "Press Escape to dismiss."
193 * </td>
194 * </tr>
195 * <tr>
196 * <td>`.highlightAction(boolean)`</td>
197 * <td>
198 * Whether or not the action button will have an additional highlight class.<br/>
199 * By default the `accent` color will be applied to the action button.
200 * </td>
201 * </tr>
202 * <tr>
203 * <td>`.highlightClass(string)`</td>
204 * <td>
205 * If set, the given class will be applied to the highlighted action button.<br/>
206 * This allows you to specify the highlight color easily. Highlight classes are
207 * `md-primary`, `md-warn`, and `md-accent`
208 * </td>
209 * </tr>
210 * <tr>
211 * <td>`.capsule(boolean)`</td>
212 * <td>
213 * Whether or not to add the `md-capsule` class to the toast to provide rounded corners
214 * </td>
215 * </tr>
216 * <tr>
217 * <td>`.theme(string)`</td>
218 * <td>
219 * Sets the theme on the toast to the requested theme. Default is `$mdThemingProvider`'s
220 * default.
221 * </td>
222 * </tr>
223 * <tr>
224 * <td>`.toastClass(string)`</td>
225 * <td>Sets a class on the toast element</td>
226 * </tr>
227 * </tbody>
228 * </table>
229 */
230
231/**
232 * @ngdoc method
233 * @name $mdToast#updateTextContent
234 *
235 * @description
236 * Updates the content of an existing toast. Useful for updating things like counts, etc.
237 */
238
239/**
240 * @ngdoc method
241 * @name $mdToast#build
242 *
243 * @description
244 * Creates a custom `$mdToastPreset` that you can configure.
245 *
246 * @returns {obj} a `$mdToastPreset` with the chainable configuration methods for shows' options
247 * (see below).
248 */
249
250/**
251 * @ngdoc method
252 * @name $mdToast#show
253 *
254 * @description Shows the toast.
255 *
256 * @param {Object} optionsOrPreset Either provide an `$mdToastPreset` returned from `simple()`
257 * and `build()`, or an options object with the following properties:
258 *
259 * - `templateUrl` - `{string=}`: The url of an html template file that will
260 * be used as the content of the toast. Restrictions: the template must
261 * have an outer `md-toast` element.
262 * - `template` - `{string=}`: Same as templateUrl, except this is an actual
263 * template string.
264 * - `autoWrap` - `{boolean=}`: Whether or not to automatically wrap the template content with a
265 * `<div class="md-toast-content">` if one is not provided. Defaults to true. Can be disabled
266 * if you provide a custom toast directive.
267 * - `scope` - `{Object=}`: the scope to link the template / controller to. If none is specified,
268 * it will create a new child scope. This scope will be destroyed when the toast is removed
269 * unless `preserveScope` is set to true.
270 * - `preserveScope` - `{boolean=}`: whether to preserve the scope when the element is removed.
271 * Default is false
272 * - `hideDelay` - `{number=}`: The number of milliseconds the toast should stay active before
273 * automatically closing. Set to `0` or `false` to have the toast stay open until closed
274 * manually via an action in the toast, a hotkey, or a swipe gesture. For accessibility, toasts
275 * should not automatically close when they contain an action.<br>
276 * Defaults to: `3000`.
277 * - `position` - `{string=}`: Sets the position of the toast. <br/>
278 * Available: any combination of `'bottom'`, `'left'`, `'top'`, `'right'`, `'end'`, and
279 * `'start'`. The properties `'end'` and `'start'` are dynamic and can be used for RTL support.
280 * <br/>
281 * Default combination: `'bottom left'`.
282 * - `toastClass` - `{string=}`: A class to set on the toast element.
283 * - `controller` - `{string=}`: The controller to associate with this toast.
284 * The controller will be injected the local `$mdToast.hide()`, which is a function
285 * used to hide the toast.
286 * - `locals` - `{Object=}`: An object containing key/value pairs. The keys will be used as names
287 * of values to inject into the controller. For example, `locals: {three: 3}` would inject
288 * `three` into the controller with the value of 3.
289 * - `bindToController` - `{boolean=}`: bind the locals to the controller, instead of passing
290 * them in.
291 * - `resolve` - `{Object=}`: Similar to locals, except it takes promises as values
292 * and the toast will not open until the promises resolve.
293 * - `controllerAs` - `{string=}`: An alias to assign the controller to on the scope.
294 * - `parent` - `{element=}`: The element to append the toast to. Defaults to appending
295 * to the root element of the application.
296 *
297 * @returns {promise} A promise that can be resolved with `$mdToast.hide()`. `$mdToast.hide()` will
298 * resolve either with the boolean value `true` or the value passed as an argument to
299 * `$mdToast.hide()`.
300 */
301
302/**
303 * @ngdoc method
304 * @name $mdToast#hide
305 *
306 * @description
307 * Hide an existing toast and resolve the promise returned from `$mdToast.show()`.
308 *
309 * @param {*=} response An argument for the resolved promise.
310 *
311 * @returns {promise} A promise that is called when the existing element is removed from the DOM.
312 * The promise is resolved with either the Boolean value `true` or the value passed as the
313 * argument to `$mdToast.hide()`.
314 */
315
316function MdToastProvider($$interimElementProvider) {
317 // Differentiate promise resolves: hide timeout (value == true) and hide action clicks
318 // (value == ok).
319 MdToastController['$inject'] = ["$mdToast", "$scope", "$log"];
320 toastDefaultOptions['$inject'] = ["$animate", "$mdToast", "$mdUtil", "$mdMedia", "$document", "$q"];
321 var ACTION_RESOLVE = 'ok';
322
323 var activeToastContent;
324 var $mdToast = $$interimElementProvider('$mdToast')
325 .setDefaults({
326 methods: ['position', 'hideDelay', 'capsule', 'parent', 'position', 'toastClass'],
327 options: toastDefaultOptions
328 })
329 .addPreset('simple', {
330 argOption: 'textContent',
331 methods: ['textContent', 'action', 'actionKey', 'actionHint', 'highlightAction',
332 'highlightClass', 'theme', 'parent', 'dismissHint'],
333 options: /* ngInject */ ["$mdToast", "$mdTheming", function($mdToast, $mdTheming) {
334 return {
335 template:
336 '<md-toast md-theme="{{ toast.theme }}" ng-class="{\'md-capsule\': toast.capsule}">' +
337 ' <div class="md-toast-content" aria-live="polite" aria-relevant="all">' +
338 ' <span class="md-toast-text">' +
339 ' {{ toast.content }}' +
340 ' </span>' +
341 ' <span class="md-visually-hidden">{{ toast.dismissHint }}</span>' +
342 ' <span class="md-visually-hidden" ng-if="toast.action && toast.actionKey">' +
343 ' {{ toast.actionHint }}' +
344 ' </span>' +
345 ' <md-button class="md-action" ng-if="toast.action" ng-click="toast.resolve()" ' +
346 ' ng-class="highlightClasses">' +
347 ' {{ toast.action }}' +
348 ' </md-button>' +
349 ' </div>' +
350 '</md-toast>',
351 controller: MdToastController,
352 theme: $mdTheming.defaultTheme(),
353 controllerAs: 'toast',
354 bindToController: true
355 };
356 }]
357 })
358 .addMethod('updateTextContent', updateTextContent);
359
360 function updateTextContent(newContent) {
361 activeToastContent = newContent;
362 }
363
364 return $mdToast;
365
366 /**
367 * Controller for the Toast interim elements.
368 * ngInject
369 */
370 function MdToastController($mdToast, $scope, $log) {
371 // For compatibility with AngularJS 1.6+, we should always use the $onInit hook in
372 // interimElements. The $mdCompiler simulates the $onInit hook for all versions.
373 this.$onInit = function() {
374 var self = this;
375
376 if (self.highlightAction) {
377 $scope.highlightClasses = [
378 'md-highlight',
379 self.highlightClass
380 ];
381 }
382
383 // If an action is defined and no actionKey is specified, then log a warning.
384 if (self.action && !self.actionKey) {
385 $log.warn('Toasts with actions should define an actionKey for accessibility.',
386 'Details: https://material.angularjs.org/latest/api/service/$mdToast#mdtoast-simple');
387 }
388
389 if (self.actionKey && !self.actionHint) {
390 self.actionHint = 'Press Control-"' + self.actionKey + '" to ';
391 }
392
393 if (!self.dismissHint) {
394 self.dismissHint = 'Press Escape to dismiss.';
395 }
396
397 $scope.$watch(function() { return activeToastContent; }, function() {
398 self.content = activeToastContent;
399 });
400
401 this.resolve = function() {
402 $mdToast.hide(ACTION_RESOLVE);
403 };
404 };
405 }
406
407 /* ngInject */
408 function toastDefaultOptions($animate, $mdToast, $mdUtil, $mdMedia, $document, $q) {
409 var SWIPE_EVENTS = '$md.swipeleft $md.swiperight $md.swipeup $md.swipedown';
410 return {
411 onShow: onShow,
412 onRemove: onRemove,
413 toastClass: '',
414 position: 'bottom left',
415 themable: true,
416 hideDelay: 3000,
417 autoWrap: true,
418 transformTemplate: function(template, options) {
419 var shouldAddWrapper = options.autoWrap && template && !/md-toast-content/g.test(template);
420
421 if (shouldAddWrapper) {
422 // Root element of template will be <md-toast>. We need to wrap all of its content inside
423 // of <div class="md-toast-content">. All templates provided here should be static,
424 // developer-controlled content (meaning we're not attempting to guard against XSS).
425 var templateRoot = document.createElement('md-template');
426 templateRoot.innerHTML = template;
427
428 // Iterate through all root children, to detect possible md-toast directives.
429 for (var i = 0; i < templateRoot.children.length; i++) {
430 if (templateRoot.children[i].nodeName === 'MD-TOAST') {
431 var wrapper = angular.element('<div class="md-toast-content">');
432
433 // Wrap the children of the `md-toast` directive in jqLite, to be able to append
434 // multiple nodes with the same execution.
435 wrapper.append(angular.element(templateRoot.children[i].childNodes));
436
437 // Append the new wrapped element to the `md-toast` directive.
438 templateRoot.children[i].appendChild(wrapper[0]);
439 }
440 }
441
442 // We have to return the innerHTML, because we do not want to have the `md-template`
443 // element to be the root element of our interimElement.
444 return templateRoot.innerHTML;
445 }
446
447 return template || '';
448 }
449 };
450
451 /**
452 * @param {{toast: {actionKey: string=}}=} scope
453 * @param {JQLite} element
454 * @param {Object.<string, string>} options
455 * @return {*}
456 */
457 function onShow(scope, element, options) {
458 activeToastContent = options.textContent;
459
460 var isSmScreen = !$mdMedia('gt-sm');
461
462 element = $mdUtil.extractElementByName(element, 'md-toast', true);
463 options.element = element;
464
465 options.onSwipe = function(ev) {
466 // Add the relevant swipe class to the element so it can animate correctly
467 var swipe = ev.type.replace('$md.','');
468 var direction = swipe.replace('swipe', '');
469
470 // If the swipe direction is down/up but the toast came from top/bottom don't fade away
471 // Unless the screen is small, then the toast always on bottom
472 if ((direction === 'down' && options.position.indexOf('top') !== -1 && !isSmScreen) ||
473 (direction === 'up' && (options.position.indexOf('bottom') !== -1 || isSmScreen))) {
474 return;
475 }
476
477 if ((direction === 'left' || direction === 'right') && isSmScreen) {
478 return;
479 }
480
481 element.addClass('md-' + swipe);
482 $mdUtil.nextTick($mdToast.cancel);
483 };
484 options.openClass = toastOpenClass(options.position);
485
486 element.addClass(options.toastClass);
487
488 // 'top left' -> 'md-top md-left'
489 options.parent.addClass(options.openClass);
490
491 // static is the default position
492 if ($mdUtil.hasComputedStyle(options.parent, 'position', 'static')) {
493 options.parent.css('position', 'relative');
494 }
495
496 setupActionKeyListener(scope.toast && scope.toast.actionKey ?
497 scope.toast.actionKey : undefined);
498
499 element.on(SWIPE_EVENTS, options.onSwipe);
500
501 var verticalPositionDefined = false;
502 var positionClasses = options.position.split(' ').map(function (position) {
503 if (position) {
504 var className = 'md-' + position;
505 if (className === 'md-top' || className === 'md-bottom') {
506 verticalPositionDefined = true;
507 }
508 return className;
509 }
510 return 'md-bottom';
511 });
512 // If only "right" or "left" are defined, default to a vertical position of "bottom"
513 // as documented.
514 if (!verticalPositionDefined) {
515 positionClasses.push('md-bottom');
516 }
517 element.addClass(isSmScreen ? 'md-bottom' : positionClasses.join(' '));
518
519 if (options.parent) {
520 options.parent.addClass('md-toast-animating');
521 }
522 return $animate.enter(element, options.parent).then(function() {
523 if (options.parent) {
524 options.parent.removeClass('md-toast-animating');
525 }
526 });
527 }
528
529 /**
530 * @param {Object} scope the toast's scope
531 * @param {JQLite} element the toast to be removed
532 * @param {Object} options
533 * @return {Promise<*>} a Promise to remove the element immediately or to animate it out.
534 */
535 function onRemove(scope, element, options) {
536 if (scope.toast && scope.toast.actionKey) {
537 removeActionKeyListener();
538 }
539 element.off(SWIPE_EVENTS, options.onSwipe);
540 if (options.parent) options.parent.addClass('md-toast-animating');
541 if (options.openClass) options.parent.removeClass(options.openClass);
542
543 // Don't run the leave animation if the element has already been destroyed.
544 return ((options.$destroy === true) ? $q.when(element.remove()) : $animate.leave(element))
545 .then(function () {
546 if (options.parent) options.parent.removeClass('md-toast-animating');
547 if ($mdUtil.hasComputedStyle(options.parent, 'position', 'static')) {
548 options.parent.css('position', '');
549 }
550 });
551 }
552
553 function toastOpenClass(position) {
554 // For mobile, always open full-width on bottom
555 if (!$mdMedia('gt-xs')) {
556 return 'md-toast-open-bottom';
557 }
558
559 return 'md-toast-open-' + (position.indexOf('top') > -1 ? 'top' : 'bottom');
560 }
561
562 /**
563 * @param {string} actionKey
564 */
565 function setupActionKeyListener(actionKey) {
566 /**
567 * @param {KeyboardEvent} event
568 */
569 var handleKeyDown = function(event) {
570 if (event.key === 'Escape') {
571 $mdToast.hide(false);
572 }
573 if (actionKey && event.key === actionKey && event.ctrlKey) {
574 $mdToast.hide(ACTION_RESOLVE);
575 }
576 };
577 $document.on('keydown', handleKeyDown);
578 }
579
580 function removeActionKeyListener() {
581 $document.off('keydown');
582 }
583 }
584}
585
586ngmaterial.components.toast = angular.module("material.components.toast");
Note: See TracBrowser for help on using the repository browser.