forked from sean3z/angular-activity-monitor
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathactivity-monitor.js
168 lines (137 loc) · 6.02 KB
/
activity-monitor.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
/*jshint -W116, -W030, latedef: false */
'use strict';
(function (root, factory) {
if (typeof module !== 'undefined' && module.exports) {
// CommonJS
if (typeof angular === 'undefined') {
factory(require('angular'));
} else {
factory(angular);
}
module.exports = 'ActivityMonitor';
} else if (typeof define === 'function' && define.amd) {
// AMD
define(['angular'], factory);
} else {
// Global variables
factory(root.angular);
}
}(this, function (angular) {
var m = angular
.module('ActivityMonitor', [])
.service('ActivityMonitor', ActivityMonitor);
var MILLISECOND = 1000;
var EVENT_KEEPALIVE = 'keepAlive';
var EVENT_INACTIVE = 'inactive';
var EVENT_WARNING = 'warning';
var EVENT_ACTIVITY = 'activity';
ActivityMonitor.$inject = ['$document'];
function ActivityMonitor($document) {
var service = this;
/* configuration */
service.options = {
enabled: false, /* is the ActivityMonitor enabled? */
keepAlive: 800, /* keepAlive ping invterval (seconds) */
inactive: 900, /* how long until user is considered inactive? (seconds) */
warning: 60, /* when to warn user when nearing inactive state (deducted from inactive in seconds) */
monitor: 3, /* how frequently to check if the user is inactive (seconds) */
DOMevents: ['mousemove', 'mousedown', 'mouseup', 'keypress', 'wheel', 'touchstart', 'scroll'] /* list of DOM events to determine user's activity */
};
var DOMevents = service.options.DOMevents.join(' ');
/* user activity */
service.user = {
action: Date.now(), /* timestamp of the users' last action */
active: true, /* is the user considered active? */
warning: false /* is the user in warning state? */
};
service.activity = activity; /* method consumers can use to supply activity */
service.on = service.bind = subscribe; /* expose method to subscribe to events */
service.off = service.unbind = unsubscribe; /* expose method to unsubscribe from events */
var events = {};
events[EVENT_KEEPALIVE] = {}; /* functions to invoke along with ping (options.frequency) */
events[EVENT_INACTIVE] = {}; /* functions to invoke when user goes inactive (options.threshold) */
events[EVENT_WARNING] = {}; /* functions to invoke when warning user about inactivity (options.warning) */
events[EVENT_ACTIVITY] = {}; /* functions to invoke any time a user makes a move */
var timer = {
inactivity: null, /* setInterval handle to determine whether the user is inactive */
keepAlive: null /* setInterval handle for ping handler (options.frequency) */
};
return service;
///////////////
function disable() {
service.options.enabled = false;
clearInterval(timer.inactivity);
clearInterval(timer.keepAlive);
$document.off(DOMevents, activity);
}
function enable() {
$document.on(DOMevents, activity);
service.options.enabled = true;
service.user.warning = false;
timer.keepAlive = setInterval(function () {
publish(EVENT_KEEPALIVE);
}, service.options.keepAlive * MILLISECOND);
timer.inactivity = setInterval(function () {
var now = Date.now();
var warning = now - (service.options.inactive - service.options.warning) * MILLISECOND;
var inactive = now - service.options.inactive * MILLISECOND;
/* should we display warning */
if (!service.user.warning && service.user.action <= warning) {
service.user.warning = true;
publish(EVENT_WARNING);
}
/* should user be considered inactive? */
if (service.user.active && service.user.action <= inactive) {
service.user.active = false;
publish(EVENT_INACTIVE);
disable();
}
}, service.options.monitor * MILLISECOND);
}
/* invoked on every user action */
function activity() {
service.user.active = true;
service.user.action = Date.now();
publish(EVENT_ACTIVITY);
if (service.user.warning) {
service.user.warning = false;
publish(EVENT_KEEPALIVE);
}
}
function publish(event) {
if (!service.options.enabled) return;
var spaces = Object.keys(events[event]);
if (!event || !spaces.length) return;
spaces.forEach(function (space) {
events[event][space] && events[event][space]();
});
}
function subscribe(event, callback) {
if (!event || typeof callback !== 'function') return;
event = _namespace(event, callback);
events[event.name][event.space] = callback;
!service.options.enabled && enable();
}
function unsubscribe(event, callback) {
event = _namespace(event, callback);
if (!event.space) {
events[event.name] = {};
return;
}
events[event.name][event.space] = null;
}
/* method to return event namespace */
function _namespace(event, callback) {
event = event.split('.');
if (!event[1] && typeof callback === 'function') {
/* if no namespace, use callback and strip all linebreaks and spaces */
event[1] = callback.toString().substr(0, 150).replace(/\r?\n|\r|\s+/gm, '');
}
return {
name: event[0],
space: event[1]
};
}
}
return m;
}));