PageSourceSearch

https://webportal2.somamedical.com/libs/angular/angular-idle/angular-idle.js

js somamedical.com collected 2026-10-06 08:24:10 UTC 17,655 bytes, 564 lines download raw bytes

vendor: 17,655 bytes, lines 1-564
1/*** Directives and services for responding to idle users in AngularJS
2* @author Mike Grabski <[email protected]>
3* @version v1.3.2
4* @link https://github.com/HackedByChinese/ng-idle.git
5* @license MIT
6*/
7(function(window, angular, undefined) {
8'use strict';
9angular.module('ngIdle', ['ngIdle.keepalive', 'ngIdle.idle', 'ngIdle.countdown', 'ngIdle.title', 'ngIdle.localStorage']);
10angular.module('ngIdle.keepalive', [])
11  .provider('Keepalive', function() {
12    var options = {
13      http: null,
14      interval: 10 * 60
15    };
16
17    this.http = function(value) {
18      if (!value) throw new Error('Argument must be a string containing a URL, or an object containing the HTTP request configuration.');
19      if (angular.isString(value)) {
20        value = {
21          url: value,
22          method: 'GET'
23        };
24      }
25
26      value.cache = false;
27
28      options.http = value;
29    };
30
31    var setInterval = this.interval = function(seconds) {
32      seconds = parseInt(seconds);
33
34      if (isNaN(seconds) || seconds <= 0) throw new Error('Interval must be expressed in seconds and be greater than 0.');
35      options.interval = seconds;
36    };
37
38    this.$get = ['$rootScope', '$log', '$interval', '$http',
39      function($rootScope, $log, $interval, $http) {
40
41        var state = {
42          ping: null
43        };
44
45        function handleResponse(response) {
46          $rootScope.$broadcast('KeepaliveResponse', response.data, response.status);
47        }
48
49        function ping() {
50          $rootScope.$broadcast('Keepalive');
51
52          if (angular.isObject(options.http)) {
53            $http(options.http)
54              .then(handleResponse)
55              .catch(handleResponse);
56          }
57        }
58
59        return {
60          _options: function() {
61            return options;
62          },
63          setInterval: setInterval,
64          start: function() {
65            $interval.cancel(state.ping);
66
67            state.ping = $interval(ping, options.interval * 1000);
68            return state.ping;
69          },
70          stop: function() {
71            $interval.cancel(state.ping);
72          },
73          ping: function() {
74            ping();
75          }
76        };
77      }
78    ];
79  });
80
81angular.module('ngIdle.idle', ['ngIdle.keepalive', 'ngIdle.localStorage'])
82  .provider('Idle', function() {
83    var options = {
84      idle: 20 * 60, // in seconds (default is 20min)
85      timeout: 30, // in seconds (default is 30sec)
86      autoResume: 'idle', // lets events automatically resume (unsets idle state/resets warning)
87      interrupt: 'mousemove keydown DOMMouseScroll mousewheel mousedown touchstart touchmove scroll',
88      windowInterrupt: null,
89      keepalive: true
90    };
91
92    /**
93     *  Sets the number of seconds a user can be idle before they are considered timed out.
94     *  @param {Number|Boolean} seconds A positive number representing seconds OR 0 or false to disable this feature.
95     */
96    var setTimeout = this.timeout = function(seconds) {
97      if (seconds === false) options.timeout = 0;
98      else if (angular.isNumber(seconds) && seconds >= 0) options.timeout = seconds;
99      else throw new Error('Timeout must be zero or false to disable the feature, or a positive integer (in seconds) to enable it.');
100    };
101
102    this.interrupt = function(events) {
103      options.interrupt = events;
104    };
105
106    this.windowInterrupt = function(events) {
107      options.windowInterrupt = events;
108    };
109
110    var setIdle = this.idle = function(seconds) {
111      if (seconds <= 0) throw new Error('Idle must be a value in seconds, greater than 0.');
112
113      options.idle = seconds;
114    };
115
116    this.autoResume = function(value) {
117      if (value === true) options.autoResume = 'idle';
118      else if (value === false) options.autoResume = 'off';
119      else options.autoResume = value;
120    };
121
122    this.keepalive = function(enabled) {
123      options.keepalive = enabled === true;
124    };
125
126    this.$get = ['$interval', '$log', '$rootScope', '$document', 'Keepalive', 'IdleLocalStorage', '$window',
127      function($interval, $log, $rootScope, $document, Keepalive, LocalStorage, $window) {
128        var state = {
129          idle: null,
130          timeout: null,
131          idling: false,
132          running: false,
133          countdown: null,
134          idleIntervalStarted: null
135        };
136
137        var id = new Date().getTime();
138
139        function startKeepalive() {
140          if (!options.keepalive) return;
141
142          if (state.running) Keepalive.ping();
143
144          Keepalive.start();
145        }
146
147        function stopKeepalive() {
148          if (!options.keepalive) return;
149
150          Keepalive.stop();
151        }
152
153        function toggleState() {
154          state.idling = !state.idling;
155          var name = state.idling ? 'IdleStart' : 'IdleEnd';
156
157          if (state.idling) {
158            $rootScope.$broadcast(name);
159            stopKeepalive();
160            if (options.timeout) {
161              state.countdown = options.timeout;
162              countdown();
163              state.timeout = $interval(countdown, 1000, options.timeout, false);
164            }
165          } else {
166            startKeepalive();
167            $rootScope.$broadcast(name);
168          }
169
170          $interval.cancel(state.idle);
171        }
172
173        function countdown() {
174
175          // check not called when no longer idling
176          // possible with multiple tabs
177          if(!state.idling){
178            return;
179          }
180
181          // countdown has expired, so signal timeout
182          if (state.countdown <= 0) {
183            timeout();
184            return;
185          }
186
187          // countdown hasn't reached zero, so warn and decrement
188          $rootScope.$broadcast('IdleWarn', state.countdown);
189          state.countdown--;
190        }
191
192        function interrupted(anotherTab) {
193          $rootScope.$broadcast('IdleInterrupt', anotherTab);
194        }
195
196        function timeout() {
197          stopKeepalive();
198          $interval.cancel(state.idle);
199          $interval.cancel(state.timeout);
200
201          state.idling = true;
202          state.running = false;
203          state.countdown = 0;
204
205          $rootScope.$broadcast('IdleTimeout');
206        }
207
208        function changeOption(self, fn, value) {
209          var reset = self.running();
210
211          self.unwatch();
212          fn(value);
213          if (reset) self.watch();
214        }
215
216        function getExpiry() {
217          var obj = LocalStorage.get('expiry');
218
219          return obj && obj.time ? new Date(obj.time) : null;
220        }
221
222        function setExpiry(date) {
223          if (!date) LocalStorage.remove('expiry');
224          else LocalStorage.set('expiry', {id: id, time: date});
225        }
226
227        var svc = {
228          _options: function() {
229            return options;
230          },
231          _getNow: function() {
232            return new Date();
233          },
234          getIdle: function(){
235            return options.idle;
236          },
237          getTimeout: function(){
238            return options.timeout;
239          },
240          setIdle: function(seconds) {
241            changeOption(this, setIdle, seconds);
242          },
243          setTimeout: function(seconds) {
244            changeOption(this, setTimeout, seconds);
245          },
246          isExpired: function() {
247            var expiry = getExpiry();
248            return expiry !== null && expiry <= this._getNow();
249          },
250          running: function() {
251            return state.running;
252          },
253          getTimeUntilIdle: function () {
254            if (state.idleIntervalStarted) {
255              var endTime = state.idleIntervalStarted.getTime() + (options.idle * 1000);
256              return endTime - (new Date()).getTime();
257            } else {
258              return null;
259            }
260          },
261          lastActivity: function () {
262            return state.idleIntervalStarted;
263          },
264          idling: function() {
265            return state.idling;
266          },
267          watch: function(noExpiryUpdate) {
268            $interval.cancel(state.idle);
269            $interval.cancel(state.timeout);
270
271            // calculate the absolute expiry date, as added insurance against a browser sleeping or paused in the background
272            var timeout = !options.timeout ? 0 : options.timeout;
273            if (!noExpiryUpdate) setExpiry(new Date(new Date().getTime() + ((options.idle + timeout) * 1000)));
274
275
276            if (state.idling) toggleState(); // clears the idle state if currently idling
277            else if (!state.running) startKeepalive(); // if about to run, start keep alive
278
279            state.running = true;
280            state.idleIntervalStarted = new Date();
281            state.idle = $interval(toggleState, options.idle * 1000, 0, false);
282          },
283          unwatch: function() {
284            $interval.cancel(state.idle);
285            $interval.cancel(state.timeout);
286
287            state.idling = false;
288            state.running = false;
289            setExpiry(null);
290
291            stopKeepalive();
292          },
293          interrupt: function(anotherTab) {
294            if (!state.running) return;
295
296            if (options.timeout && this.isExpired()) {
297              timeout();
298              return;
299            } else {
300              interrupted(anotherTab);
301            }
302
303            // note: you can no longer auto resume once we exceed the expiry; you will reset state by calling watch() manually
304            if (anotherTab || options.autoResume === 'idle' || (options.autoResume === 'notIdle' && !state.idling)) this.watch(anotherTab);
305          }
306        };
307
308        var lastMove = {
309          clientX: null,
310          clientY: null,
311          swap: function(event) {
312            var last = {clientX: this.clientX, clientY: this.clientY};
313            this.clientX = event.clientX;
314            this.clientY = event.clientY;
315            return last;
316          },
317          hasMoved: function(event) {
318            var last = this.swap(event);
319            if (this.clientX === null || event.movementX || event.movementY) return true;
320            else if (last.clientX != event.clientX || last.clientY != event.clientY) return true;
321            else return false;
322          }
323        };
324
325        $document.find('html').on(options.interrupt, function(event) {
326          if (event.type === 'mousemove' && event.originalEvent && event.originalEvent.movementX === 0 && event.originalEvent.movementY === 0) {
327            return; // Fix for Chrome desktop notifications, triggering mousemove event.
328          }
329
330          if (event.type !== 'mousemove' || lastMove.hasMoved(event)) {
331            svc.interrupt();
332          }
333        });
334
335        if(options.windowInterrupt) {
336          var eventList = options.windowInterrupt.split(' ');
337          var fn = function() {
338            svc.interrupt();
339          };
340
341          for(var i=0; i<eventList.length; i++) {
342            if ($window.addEventListener) {
343              $window.addEventListener(eventList[i], fn, false);
344              $rootScope.$on('$destroy', function () {
345                $window.removeEventListener(eventList[i], fn, false);
346              });
347            } else {
348              $window.attachEvent(eventList[i], fn);
349              $rootScope.$on('$destroy', function () {
350                $window.detachEvent(eventList[i], fn);
351              });
352            }
353          }
354        }
355
356        var wrap = function(event) {
357          if (event.key === 'ngIdle.expiry' && event.newValue && event.newValue !== event.oldValue) {
358            var val = angular.fromJson(event.newValue);
359            if (val.id === id) return;
360            svc.interrupt(true);
361          }
362        };
363
364        if ($window.addEventListener) {
365          $window.addEventListener('storage', wrap, false);
366          $rootScope.$on('$destroy', function () {
367            $window.removeEventListener('storage', wrap, false);
368          });
369        } else if ($window.attachEvent){
370          $window.attachEvent('onstorage', wrap);
371          $rootScope.$on('$destroy', function () {
372            $window.detachEvent('onstorage', wrap);
373          });
374        }
375
376        return svc;
377      }
378    ];
379  });
380
381angular.module('ngIdle.countdown', ['ngIdle.idle'])
382  .directive('idleCountdown', ['Idle', function(Idle) {
383    return {
384      restrict: 'A',
385      scope: {
386        value: '=idleCountdown'
387      },
388      link: function($scope) {
389        // Initialize the scope's value to the configured timeout.
390        $scope.value = Idle.getTimeout();
391
392        $scope.$on('IdleWarn', function(e, countdown) {
393          $scope.$evalAsync(function() {
394            $scope.value = countdown;
395          });
396        });
397
398        $scope.$on('IdleTimeout', function() {
399          $scope.$evalAsync(function() {
400            $scope.value = 0;
401          });
402        });
403      }
404    };
405  }]);
406
407angular.module('ngIdle.title', [])
408  .provider('Title', function() {
409    var options = {
410      enabled: true
411    };
412
413    var setEnabled = this.enabled = function(enabled) {
414      options.enabled = enabled === true;
415    };
416
417    function padLeft(nr, n, str){
418      return new Array(n-String(nr).length+1).join(str||'0')+nr;
419    }
420
421    this.$get = ['$document', '$interpolate', function($document, $interpolate) {
422      var state = {
423        original: null,
424        idle: '{{minutes}}:{{seconds}} until your session times out!',
425        timedout: 'Your session has expired.'
426      };
427
428      return {
429        setEnabled: setEnabled,
430        isEnabled: function() {
431          return options.enabled;
432        },
433        original: function(val) {
434          if (angular.isUndefined(val)) return state.original;
435
436          state.original = val;
437        },
438        store: function(overwrite) {
439          if (overwrite || !state.original) state.original = this.value();
440        },
441        value: function(val) {
442          if (angular.isUndefined(val)) return $document[0].title;
443
444          $document[0].title = val;
445        },
446        idleMessage: function(val) {
447          if (angular.isUndefined(val)) return state.idle;
448
449          state.idle = val;
450        },
451        timedOutMessage: function(val) {
452          if (angular.isUndefined(val)) return state.timedout;
453
454          state.timedout = val;
455        },
456        setAsIdle: function(countdown) {
457          this.store();
458
459          var remaining = { totalSeconds: countdown };
460          remaining.minutes = Math.floor(countdown/60);
461          remaining.seconds = padLeft(countdown - remaining.minutes * 60, 2);
462
463          this.value($interpolate(this.idleMessage())(remaining));
464        },
465        setAsTimedOut: function() {
466          this.store();
467
468          this.value(this.timedOutMessage());
469        },
470        restore: function() {
471          if (this.original()) this.value(this.original());
472        }
473      };
474    }];
475  })
476  .directive('title', ['Title', function(Title) {
477      return {
478        restrict: 'E',
479        link: function($scope, $element, $attr) {
480          if (!Title.isEnabled() || $attr.idleDisabled) return;
481
482          Title.store(true);
483
484          $scope.$on('IdleStart', function() {
485            Title.original($element[0].innerText);
486          });
487
488          $scope.$on('IdleWarn', function(e, countdown) {
489            Title.setAsIdle(countdown);
490          });
491
492          $scope.$on('IdleEnd', function() {
493            Title.restore();
494          });
495
496          $scope.$on('IdleTimeout', function() {
497            Title.setAsTimedOut();
498          });
499        }
500      };
501  }]);
502
503angular.module('ngIdle.localStorage', [])
504  .service('IdleStorageAccessor', ['$window', function($window) {
505    return {
506      get: function() {
507        return $window.localStorage;
508      }
509    }
510  }])
511  .service('IdleLocalStorage', ['IdleStorageAccessor', function(IdleStorageAccessor) {
512    function AlternativeStorage() {
513      var storageMap = {};
514
515      this.setItem = function (key, value) {
516          storageMap[key] = value;
517      };
518
519      this.getItem = function (key) {
520          if(typeof storageMap[key] !== 'undefined' ) {
521              return storageMap[key];
522          }
523          return null;
524      };
525
526      this.removeItem = function (key) {
527          storageMap[key] = undefined;
528      };
529    }
530
531    function getStorage() {
532       try {
533          var s = IdleStorageAccessor.get();
534          s.setItem('ngIdleStorage', '');
535          s.removeItem('ngIdleStorage');
536
537          return s;
538       } catch(err) {
539          return new AlternativeStorage();
540       }
541    }
542
543    // Safari, in Private Browsing Mode, looks like it supports localStorage but all calls to setItem
544    // throw QuotaExceededError. We're going to detect this and just silently drop any calls to setItem
545    // to avoid the entire page breaking, without having to do a check at each usage of Storage.
546    var storage = getStorage();
547
548    return {
549      set: function(key, value) {
550        storage.setItem('ngIdle.'+key, angular.toJson(value));
551      },
552      get: function(key) {
553        return angular.fromJson(storage.getItem('ngIdle.'+key));
554      },
555      remove: function(key) {
556        storage.removeItem('ngIdle.'+key);
557      },
558      _wrapped: function() {
559        return storage;
560      }
561    };
562}]);
563
564})(window, window.angular);

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.