PageSourceSearch

https://portaleducacional.unibrasil.com.br/FrameHTML/web/js/libs/AngularJS-Toaster/toaster.js

js unibrasil.com.br collected 2026-09-24 09:18:30 UTC 26,651 bytes, 507 lines download raw bytes

1/* global angular */
2(function(window, document) {
3    'use strict';
4
5    /*
6     * AngularJS Toaster
7     * Version: 2.0.0
8     *
9     * Copyright 2013-2016 Jiri Kavulak.
10     * All Rights Reserved.
11     * Use, reproduction, distribution, and modification of this code is subject to the terms and
12     * conditions of the MIT license, available at http://www.opensource.org/licenses/mit-license.php
13     *
14     * Author: Jiri Kavulak
15     * Related to project of John Papa, Hans Fjällemark and Nguyễn Thiện Hùng (thienhung1989)
16     */
17
18    angular.module('toaster', []).constant(
19        'toasterConfig', {
20            'limit': 0,                   // limits max number of toasts
21            'tap-to-dismiss': true,
22            'close-button': false,
23            'close-html': '<button class="toast-close-button" type="button">&times;</button>',
24            'newest-on-top': true,
25            'time-out': 5000,
26            'icon-classes': {
27                error: 'toast-error',
28                info: 'toast-info',
29                wait: 'toast-wait',
30                success: 'toast-success',
31                warning: 'toast-warning'
32            },
33            'body-output-type': '', // Options: '', 'trustedHtml', 'template', 'templateWithData', 'directive'
34            'body-template': 'toasterBodyTmpl.html',
35            'icon-class': 'toast-info',
36            'position-class': 'toast-top-right', // Options (see CSS):
37            // 'toast-top-full-width', 'toast-bottom-full-width', 'toast-center',
38            // 'toast-top-left', 'toast-top-center', 'toast-top-right',
39            // 'toast-bottom-left', 'toast-bottom-center', 'toast-bottom-right',
40            'title-class': 'toast-title',
41            'message-class': 'toast-message',
42            'prevent-duplicates': false,
43            'mouseover-timer-stop': true // stop timeout on mouseover and restart timer on mouseout
44        }
45    ).service(
46        'toaster', [
47            '$rootScope', 'toasterConfig', function($rootScope, toasterConfig) {
48                // http://stackoverflow.com/questions/26501688/a-typescript-guid-class
49                var Guid = (function() {
50                    var Guid = {};
51                    Guid.newGuid = function() {
52                        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
53                            var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
54                            return v.toString(16);
55                        });
56                    };
57                    return Guid;
58                }());
59
60                this.pop = function(type, title, body, timeout, bodyOutputType, clickHandler, toasterId, showCloseButton, toastId, onHideCallback) {
61                    if (angular.isObject(type)) {
62                        var params = type; // Enable named parameters as pop argument
63                        this.toast = {
64                            type: params.type,
65                            title: params.title,
66                            body: params.body,
67                            timeout: params.timeout,
68                            bodyOutputType: params.bodyOutputType,
69                            clickHandler: params.clickHandler,
70                            showCloseButton: params.showCloseButton,
71                            closeHtml: params.closeHtml,
72                            toastId: params.toastId,
73                            onShowCallback: params.onShowCallback,
74                            onHideCallback: params.onHideCallback,
75                            directiveData: params.directiveData
76                        };
77                        toasterId = params.toasterId;
78                    } else {
79                        this.toast = {
80                            type: type,
81                            title: title,
82                            body: body,
83                            timeout: timeout,
84                            bodyOutputType: bodyOutputType,
85                            clickHandler: clickHandler,
86                            showCloseButton: showCloseButton,
87                            toastId: toastId,
88                            onHideCallback: onHideCallback
89                        };
90                    }
91
92                    if (!this.toast.toastId || !this.toast.toastId.length) {
93                        this.toast.toastId = Guid.newGuid();
94                    }
95
96                    $rootScope.$emit('toaster-newToast', toasterId, this.toast.toastId);
97                    
98                    return {
99                        toasterId: toasterId,
100                        toastId: this.toast.toastId
101                    };
102                };
103
104                this.clear = function(toasterId, toastId) {
105                    if (angular.isObject(toasterId)) {
106                        $rootScope.$emit('toaster-clearToasts', toasterId.toasterId, toasterId.toastId);
107                    } else {
108                        $rootScope.$emit('toaster-clearToasts', toasterId, toastId);
109                    }
110                };
111
112                // Create one method per icon class, to allow to call toaster.info() and similar
113                for (var type in toasterConfig['icon-classes']) {
114                    this[type] = createTypeMethod(type);
115                }
116
117                function createTypeMethod(toasterType) {
118                    return function(title, body, timeout, bodyOutputType, clickHandler, toasterId, showCloseButton, toastId, onHideCallback) {
119                        if (angular.isString(title)) {
120                            return this.pop(
121                                toasterType,
122                                title,
123                                body,
124                                timeout,
125                                bodyOutputType,
126                                clickHandler,
127                                toasterId,
128                                showCloseButton,
129                                toastId,
130                                onHideCallback);
131                        } else { // 'title' is actually an object with options
132                            return this.pop(angular.extend(title, { type: toasterType }));
133                        }
134                    };
135                }
136            }]
137        ).factory(
138        'toasterEventRegistry', [
139            '$rootScope', function($rootScope) {
140                var deregisterNewToast = null, deregisterClearToasts = null, newToastEventSubscribers = [], clearToastsEventSubscribers = [], toasterFactory;
141
142                toasterFactory = {
143                    setup: function() {
144                        if (!deregisterNewToast) {
145                            deregisterNewToast = $rootScope.$on(
146                                'toaster-newToast', function(event, toasterId, toastId) {
147                                    for (var i = 0, len = newToastEventSubscribers.length; i < len; i++) {
148                                        newToastEventSubscribers[i](event, toasterId, toastId);
149                                    }
150                                });
151                        }
152
153                        if (!deregisterClearToasts) {
154                            deregisterClearToasts = $rootScope.$on(
155                                'toaster-clearToasts', function(event, toasterId, toastId) {
156                                    for (var i = 0, len = clearToastsEventSubscribers.length; i < len; i++) {
157                                        clearToastsEventSubscribers[i](event, toasterId, toastId);
158                                    }
159                                });
160                        }
161                    },
162
163                    subscribeToNewToastEvent: function(onNewToast) {
164                        newToastEventSubscribers.push(onNewToast);
165                    },
166                    subscribeToClearToastsEvent: function(onClearToasts) {
167                        clearToastsEventSubscribers.push(onClearToasts);
168                    },
169                    unsubscribeToNewToastEvent: function(onNewToast) {
170                        var index = newToastEventSubscribers.indexOf(onNewToast);
171                        if (index >= 0) {
172                            newToastEventSubscribers.splice(index, 1);
173                        }
174
175                        if (newToastEventSubscribers.length === 0) {
176                            deregisterNewToast();
177                            deregisterNewToast = null;
178                        }
179                    },
180                    unsubscribeToClearToastsEvent: function(onClearToasts) {
181                        var index = clearToastsEventSubscribers.indexOf(onClearToasts);
182                        if (index >= 0) {
183                            clearToastsEventSubscribers.splice(index, 1);
184                        }
185
186                        if (clearToastsEventSubscribers.length === 0) {
187                            deregisterClearToasts();
188                            deregisterClearToasts = null;
189                        }
190                    }
191                };
192                return {
193                    setup: toasterFactory.setup,
194                    subscribeToNewToastEvent: toasterFactory.subscribeToNewToastEvent,
195                    subscribeToClearToastsEvent: toasterFactory.subscribeToClearToastsEvent,
196                    unsubscribeToNewToastEvent: toasterFactory.unsubscribeToNewToastEvent,
197                    unsubscribeToClearToastsEvent: toasterFactory.unsubscribeToClearToastsEvent
198                };
199            }]
200        )
201        .directive('directiveTemplate', ['$compile', '$injector', function($compile, $injector) {
202            return {
203                restrict: 'A',
204                scope: {
205                    directiveName: '@directiveName',
206                    directiveData: '@directiveData'
207                },
208                replace: true,
209                link: function(scope, elm, attrs) {
210                    scope.$watch('directiveName', function(directiveName) {
211                        if (angular.isUndefined(directiveName) || directiveName.length <= 0)
212                            throw new Error('A valid directive name must be provided via the toast body argument when using bodyOutputType: directive');
213
214                        var directive;
215
216                        try {
217                            directive = $injector.get(attrs.$normalize(directiveName) + 'Directive');
218                        } catch (e) {
219                            throw new Error(directiveName + ' could not be found. ' +
220                                'The name should appear as it exists in the markup, not camel
220Cased as it would appear in the directive declaration,' +
221                                ' e.g. directive-name not directiveName.');
222                        }
223
224
225                        var directiveDetails = directive[0];
226
227                        if (directiveDetails.scope !== true && directiveDetails.scope) {
228                            throw new Error('Cannot use a directive with an isolated scope. ' +
229                                'The scope must be either true or falsy (e.g. false/null/undefined). ' +
230                                'Occurred for directive ' + directiveName + '.');
231                        }
232
233                        if (directiveDetails.restrict.indexOf('A') < 0) {
234                            throw new Error('Directives must be usable as attributes. ' +
235                                'Add "A" to the restrict option (or remove the option entirely). Occurred for directive ' +
236                                directiveName + '.');
237                        }
238
239                        if (scope.directiveData)
240                            scope.directiveData = angular.fromJson(scope.directiveData);
241
242                        var template = $compile('<div ' + directiveName + '></div>')(scope);
243
244                        elm.append(template);
245                    });
246                }
247            };
248        }])
249        .directive(
250        'toasterContainer', [
251            '$parse', '$rootScope', '$interval', '$sce', 'toasterConfig', 'toaster', 'toasterEventRegistry',
252            function($parse, $rootScope, $interval, $sce, toasterConfig, toaster, toasterEventRegistry) {
253                return {
254                    replace: true,
255                    restrict: 'EA',
256                    scope: true, // creates an internal scope for this directive (one per directive instance)
257                    link: function(scope, elm, attrs) {
258                        var mergedConfig;
259
260                        // Merges configuration set in directive with default one
261                        mergedConfig = angular.extend({}, toasterConfig, scope.$eval(attrs.toasterOptions));
262
263                        scope.config = {
264                            toasterId: mergedConfig['toaster-id'],
265                            position: mergedConfig['position-class'],
266                            title: mergedConfig['title-class'],
267                            message: mergedConfig['message-class'],
268                            tap: mergedConfig['tap-to-dismiss'],
269                            closeButton: mergedConfig['close-button'],
270                            closeHtml: mergedConfig['close-html'],
271                            animation: mergedConfig['animation-class'],
272                            mouseoverTimer: mergedConfig['mouseover-timer-stop']
273                        };
274
275                        scope.$on(
276                            "$destroy", function() {
277                                toasterEventRegistry.unsubscribeToNewToastEvent(scope._onNewToast);
278                                toasterEventRegistry.unsubscribeToClearToastsEvent(scope._onClearToasts);
279                            }
280                        );
281
282                        function setTimeout(toast, time) {
283                            toast.timeoutPromise = $interval(
284                                function() {
285                                    scope.removeToast(toast.toastId);
286                                }, time, 1
287                            );
288                        }
289
290                        scope.configureTimer = function(toast) {
291                            var timeout = angular.isNumber(toast.timeout) ? toast.timeout : mergedConfig['time-out'];
292                            if (typeof timeout === "object") timeout = timeout[toast.type];
293                            if (timeout > 0) {
294                                setTimeout(toast, timeout);
295                            }
296                        };
297
298                        function addToast(toast, toastId) {
299                            toast.type = mergedConfig['icon-classes'][toast.type];
300                            if (!toast.type) {
301                                toast.type = mergedConfig['icon-class'];
302                            }
303
304                            if (mergedConfig['prevent-duplicates'] === true && scope.toasters.length) {
305                                if (scope.toasters[scope.toasters.length - 1].body === toast.body) {
306                                    return;
307                                } else {
308                                    var i, len, dupFound = false;
309                                    for (i = 0, len = scope.toasters.length; i < len; i++) {
310                                        if (scope.toasters[i].toastId === toastId) {
311                                            dupFound = true;
312                                            break;
313                                        }
314                                    }
315                                    
316                                    if (dupFound) return;
317                                }
318                            }
319
320
321                            // set the showCloseButton property on the toast so that
322                            // each template can bind directly to the property to show/hide
323                            // the close button
324                            var closeButton = mergedConfig['close-button'];
325
326                            // if toast.showCloseButton is a boolean value,
327                            // it was specifically overriden in the pop arguments
328                            if (typeof toast.showCloseButton === "boolean") {
329
330                            } else if (typeof closeButton === "boolean") {
331                                toast.showCloseButton = closeButton;
332                            } else if (typeof closeButton === "object") {
333                                var closeButtonForType = closeButton[toast.type];
334
335                                if (typeof closeButtonForType !== "undefined" && closeButtonForType !== null) {
336                                    toast.showCloseButton = closeButtonForType;
337                                }
338                            } else {
339                                // if an option was not set, default to false.
340                                toast.showCloseButton = false;
341                            }
342
343                            if (toast.showCloseButton) {
344                                toast.closeHtml = $sce.trustAsHtml(toast.closeHtml || scope.config.closeHtml);
345                            }
346
347                            // Set the toast.bodyOutputType to the default if it isn't set
348                            toast.bodyOutputType = toast.bodyOutputType || mergedConfig['body-output-type'];
349                            switch (toast.bodyOutputType) {
350                                case 'trustedHtml':
351                                    toast.html = $sce.trustAsHtml(toast.body);
352                                    break;
353                                case 'template':
354                                    toast.bodyTemplate = toast.body || mergedConfig['body-template'];
355                                    break;
356                                case 'templateWithData':
357                                    var fcGet = $parse(toast.body || mergedConfig['body-template']);
358                                    var templateWithData = fcGet(scope);
359                                    toast.bodyTemplate = templateWithData.template;
360                                    toast.data = templateWithData.data;
361                                    break;
362                                case 'directive':
363                                    toast.html = toast.body;
364                                    break;
365                            }
366
367                            scope.configureTimer(toast);
368
369                            if (mergedConfig['newest-on-top'] === true) {
370                                scope.toasters.unshift(toast);
371                                if (mergedConfig['limit'] > 0 && scope.toasters.length > mergedConfig['limit']) {
372                                    scope.toasters.pop();
373                                }
374                            } else {
375                                scope.toasters.push(toast);
376                                if (mergedConfig['limit'] > 0 && scope.toasters.length > mergedConfig['limit']) {
377                                    scope.toasters.shift();
378                                }
379                            }
380
381                            if (angular.isFunction(toast.onShowCallback)) {
382                                toast.onShowCallback();
383                            }
384                        }
385
386                        scope.removeToast = function(toastId) {
387                            var i, len;
388                            for (i = 0, len = scope.toasters.length; i < len; i++) {
389                                if (scope.toasters[i].toastId === toastId) {
390                                    removeToast(i);
391                                    break;
392                                }
393                            }
394                        };
395
396                        function removeToast(toastIndex) {
397                            var toast = scope.toasters[toastIndex];
398
399                            // toast is always defined since the index always has a match
400                            if (toast.timeoutPromise) {
401                                $interval.cancel(toast.timeoutPromise);
402                            }
403                            scope.toasters.splice(toastIndex, 1);
404
405                            if (angular.isFunction(toast.onHideCallback)) {
406                                toast.onHideCallback();
407                            }
408                        }
409
410                        function removeAllToasts(toastId) {
411                            for (var i = scope.toasters.length - 1; i >= 0; i--) {
412                                if (isUndefinedOrNull(toastId)) {
413                                    removeToast(i);
414                                } else {
415                                    if (scope.toasters[i].toastId == toastId) {
416                                        removeToast(i);
417                                    }
418                                }
419                            }
420                        }
421
422                        scope.toasters = [];
423
424                        function isUndefinedOrNull(val) {
425                            return angular.isUndefined(val) || val === null;
426                        }
427
428                        scope._onNewToast = function(event, toasterId, toastId) {
429                            // Compatibility: if toaster has no toasterId defined, and if call to display
430                            // hasn't either, then the request is for us
431
432                            if ((isUndefinedOrNull(scope.config.toasterId) && isUndefinedOrNull(toasterId)) || (!isUndefinedOrNull(scope.config.toasterId) && !isUndefinedOrNull(toasterId) && scope.config.toasterId == toasterId)) {
433                                addToast(toaster.toast, toastId);
434                            }
435                        };
436                        scope._onClearToasts = function(event, toasterId, toastId) {
437                            // Compatibility: if toaster has no toasterId defined, and if call to display
438                            // hasn't either, then the request is for us
439                            if (toasterId == '*' || (isUndefinedOrNull(scope.config.toasterId) && isUndefinedOrNull(toasterId)) || (!isUndefinedOrNull(scope.config.toasterId) && !isUndefinedOrNull(toasterId) && scope.config.toasterId == toasterId)) {
440                                removeAllToasts(toastId);
441                            }
442                        };
443
444                        toasterEventRegistry.setup();
445
446                        toasterEventRegistry.subscribeToNewToastEvent(scope._onNewToast);
447                        toasterEventRegistry.subscribeToClearToastsEvent(scope._onClearToasts);
448                    },
449                    controller: [
450                        '$scope', '$element', '$attrs', function($scope, $element, $attrs) {
451                            // Called on mouseover
452                            $scope.stopTimer = function(toast) {
453                                if ($scope.config.mouseoverTimer === true) {
454                                    if (toast.timeoutPromise) {
455                                        $interval.cancel(toast.timeoutPromise);
456                                        toast.timeoutPromise = null;
457                                    }
458                                }
459                            };
460
461                            // Called on mouseout
462                            $scope.restartTimer = function(toast) {
463                                if ($scope.config.mouseoverTimer === true) {
464                                    if (!toast.timeoutPromise) {
465                                        $scope.configureTimer(toast);
466                                    }
467                                } else if (toast.timeoutPromise === null) {
468                                    $scope.removeToast(toast.toastId);
469                                }
470                            };
471
472                            $scope.click = function(toast, isCloseButton) {
473                                if ($scope.config.tap === true || (toast.showCloseButton === true && isCloseButton === true)) {
474                                    var removeToast = true;
475                                    if (toast.clickHandler) {
476                                        if (angular.isFunction(toast.clickHandler)) {
477                                            removeToast = toast.clickHandler(toast, isCloseButton);
478                                        } else if (angular.isFunction($scope.$parent.$eval(toast.clickHandler))) {
479                                            removeToast = $scope.$parent.$eval(toast.clickHandler)(toast, isCloseButton);
480                                        } else {
481                                            console.log("TOAST-NOTE: Your click handler is not inside a parent scope of toaster-container.");
482                                        }
483                                    }
484                                    if (removeToast) {
485                                        $scope.removeToast(toast.toastId);
486                                    }
487                                }
488                            };
489                        }],
490                    template:
491                    '<div id="toast-container" ng-class="[config.position, config.animation]">' +
492                    '<div ng-repeat="toaster in toasters" class="toast" ng-class="toaster.type" ng-click="click(toaster)" ng-mouseover="stopTimer(toaster)" ng-mouseout="restartTimer(toaster)">' +
493                    '<div ng-if="toaster.showCloseButton" ng-click="click(toaster, true)" ng-bind-html="toaster.closeHtml"></div>' +
494                    '<div ng-class="config.title">{{toaster.title}}</div>' +
495                    '<div ng-class="config.message" ng-switch on="toaster.bodyOutputType">' +
496                    '<div ng-switch-when="trustedHtml" ng-bind-html="toaster.html"></div>' +
497                    '<div ng-switch-when="template"><div ng-include="toaster.bodyTemplate"></div></div>' +
498                    '<div ng-switch-when="templateWithData"><div ng-include="toaster.bodyTemplate"></div></div>' +
499                    '<div ng-switch-when="directive"><div directive-template directive-name="{{toaster.html}}" directive-data="{{toaster.directiveData}}"></div></div>' +
500                    '<div ng-switch-default >{{toaster.body}}</div>' +
501                    '</div>' +
502                    '</div>' +
503                    '</div>'
504                };
505            }]
506        );
507})(window, document);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.