Initial commit: Atomaste website

This commit is contained in:
2025-12-10 12:17:30 -05:00
commit 0b9e5d1605
19260 changed files with 5206382 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
<?php
// Silence is golden.

View File

@@ -0,0 +1,57 @@
<?php
// DO NOT EDIT THIS FILE - IT IS GENERATED BY constant_generator.php
namespace burst\UserAgent;
interface Browsers {
const ADSBOT_GOOGLE = 'AdsBot-Google';
const ANDROID_BROWSER = 'Android Browser';
const APPLEBOT = 'Applebot';
const BAIDUSPIDER = 'Baiduspider';
const BINGBOT = 'bingbot';
const BLACKBERRY_BROWSER = 'BlackBerry Browser';
const BROWSER = 'Browser';
const BUNJALLOO = 'Bunjalloo';
const CAMINO = 'Camino';
const CHROME = 'Chrome';
const CURL = 'curl';
const EDGE = 'Edge';
const FACEBOOKEXTERNALHIT = 'facebookexternalhit';
const FEEDVALIDATOR = 'FeedValidator';
const FIREFOX = 'Firefox';
const GOOGLEBOT = 'Googlebot';
const GOOGLEBOT_IMAGE = 'Googlebot-Image';
const GOOGLEBOT_VIDEO = 'Googlebot-Video';
const HEADLESSCHROME = 'HeadlessChrome';
const IEMOBILE = 'IEMobile';
const IMESSAGEBOT = 'iMessageBot';
const KINDLE = 'Kindle';
const LYNX = 'Lynx';
const MIDORI = 'Midori';
const MIUIBROWSER = 'MiuiBrowser';
const MSIE = 'MSIE';
const MSNBOT_MEDIA = 'msnbot-media';
const NETFRONT = 'NetFront';
const NINTENDOBROWSER = 'NintendoBrowser';
const OCULUSBROWSER = 'OculusBrowser';
const OPERA = 'Opera';
const PUFFIN = 'Puffin';
const SAFARI = 'Safari';
const SAILFISHBROWSER = 'SailfishBrowser';
const SAMSUNGBROWSER = 'SamsungBrowser';
const SILK = 'Silk';
const TELEGRAMBOT = 'TelegramBot';
const TIZENBROWSER = 'TizenBrowser';
const TWITTERBOT = 'Twitterbot';
const UC_BROWSER = 'UC Browser';
const VALVE_STEAM_TENFOOT = 'Valve Steam Tenfoot';
const VIVALDI = 'Vivaldi';
const WGET = 'Wget';
const WORDPRESS = 'WordPress';
const YANDEX = 'Yandex';
const YANDEXBOT = 'YandexBot';
}

View File

@@ -0,0 +1,42 @@
<?php
// DO NOT EDIT THIS FILE - IT IS GENERATED BY constant_generator.php
namespace burst\UserAgent;
interface Platforms {
const MACINTOSH = 'Macintosh';
const CHROME_OS = 'Chrome OS';
const LINUX = 'Linux';
const WINDOWS = 'Windows';
const ANDROID = 'Android';
const BLACKBERRY = 'BlackBerry';
const FREEBSD = 'FreeBSD';
const IPAD = 'iPad';
const IPHONE = 'iPhone';
const IPOD = 'iPod';
const KINDLE = 'Kindle';
const KINDLE_FIRE = 'Kindle Fire';
const NETBSD = 'NetBSD';
const NEW_NINTENDO_3DS = 'New Nintendo 3DS';
const NINTENDO_3DS = 'Nintendo 3DS';
const NINTENDO_DS = 'Nintendo DS';
const NINTENDO_SWITCH = 'Nintendo Switch';
const NINTENDO_WII = 'Nintendo Wii';
const NINTENDO_WIIU = 'Nintendo WiiU';
const OPENBSD = 'OpenBSD';
const PLAYBOOK = 'PlayBook';
const PLAYSTATION_3 = 'PlayStation 3';
const PLAYSTATION_4 = 'PlayStation 4';
const PLAYSTATION_5 = 'PlayStation 5';
const PLAYSTATION_VITA = 'PlayStation Vita';
const SAILFISH = 'Sailfish';
const SYMBIAN = 'Symbian';
const TIZEN = 'Tizen';
const WINDOWS_PHONE = 'Windows Phone';
const XBOX = 'Xbox';
const XBOX_ONE = 'Xbox One';
}

View File

@@ -0,0 +1,57 @@
<?php
namespace burst\UserAgent;
class UserAgent implements UserAgentInterface {
/**
* @var string|null
*/
private $platform;
/**
* @var string|null
*/
private $browser;
/**
* @var string|null
*/
private $browserVersion;
/**
* UserAgent constructor.
*
* @param string|null $platform
* @param string|null $browser
* @param string|null $browserVersion
*/
public function __construct( $platform, $browser, $browserVersion ) {
$this->platform = $platform;
$this->browser = $browser;
$this->browserVersion = $browserVersion;
}
/**
* @return string|null
* @see \donatj\UserAgent\Platforms for a list of tested platforms
*/
public function platform() {
return $this->platform;
}
/**
* @return string|null
* @see \donatj\UserAgent\Browsers for a list of tested browsers.
*/
public function browser() {
return $this->browser;
}
/**
* The version string. Formatting depends on the browser.
*
* @return string|null
*/
public function browserVersion() {
return $this->browserVersion;
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace burst\UserAgent;
interface UserAgentInterface {
/**
* @return string|null
* @see \donatj\UserAgent\Platforms for a list of tested platforms
*/
public function platform();
/**
* @return string|null
* @see \donatj\UserAgent\Browsers for a list of tested browsers.
*/
public function browser();
/**
* The version string. Formatting depends on the browser.
*
* @return string|null
*/
public function browserVersion();
}

View File

@@ -0,0 +1,39 @@
<?php
namespace burst\UserAgent;
class UserAgentParser {
/**
* Parses a user agent string into its important parts, provide an object
*
* @param string|null $u_agent User agent string to parse or null. Uses $_SERVER['HTTP_USER_AGENT'] on NULL
* @return UserAgent an object with 'browser', 'browserVersion' and 'platform' methods
* @throws \InvalidArgumentException on not having a proper user agent to parse.
* @see \donatj\UserAgent\parse_user_agent()
*
*/
public function parse( $u_agent = null ) {
$parsed = parse_user_agent($u_agent);
return new UserAgent(
$parsed[PLATFORM],
$parsed[BROWSER],
$parsed[BROWSER_VERSION]
);
}
/**
* Parses a user agent string into its important parts
*
* @param string|null $u_agent User agent string to parse or null. Uses $_SERVER['HTTP_USER_AGENT'] on NULL
* @return UserAgent an object with 'browser', 'browserVersion' and 'platform' methods
* @throws \InvalidArgumentException on not having a proper user agent to parse.
* @see \donatj\UserAgent\parse_user_agent()
*
*/
public function __invoke( $u_agent = null ) {
return $this->parse($u_agent);
}
}

View File

@@ -0,0 +1,201 @@
<?php
/**
* @author Jesse G. Donat <donatj@gmail.com>
*
* @link https://donatstudios.com/PHP-Parser-HTTP_USER_AGENT
* @link https://github.com/donatj/PhpUserAgent
*
* @license MIT https://github.com/donatj/PhpUserAgent/blob/master/LICENSE.md
*/
namespace burst\UserAgent {
const PLATFORM = 'platform';
const BROWSER = 'browser';
const BROWSER_VERSION = 'version';
/**
* Parses a user agent string into its important parts
*
* @param string|null $u_agent User agent string to parse or null. Uses $_SERVER['HTTP_USER_AGENT'] on NULL
* @return string[] an array with 'browser', 'version' and 'platform' keys
* @throws \InvalidArgumentException on not having a proper user agent to parse.
*/
function parse_user_agent( $u_agent = null ) {
if( $u_agent === null && isset($_SERVER['HTTP_USER_AGENT']) ) {
$u_agent = (string)$_SERVER['HTTP_USER_AGENT'];
}
if( $u_agent === null ) {
throw new \InvalidArgumentException('parse_user_agent requires a user agent');
}
$platform = null;
$browser = null;
$version = null;
$return = [ PLATFORM => &$platform, BROWSER => &$browser, BROWSER_VERSION => &$version ];
if( !$u_agent ) {
return $return;
}
if( preg_match('/\((.*?)\)/m', $u_agent, $parent_matches) ) {
preg_match_all(<<<'REGEX'
/(?P<platform>BB\d+;|Android|Adr|Symbian|Sailfish|CrOS|Tizen|iPhone|iPad|iPod|Linux|(Open|Net|Free)BSD|Macintosh|Windows(\ Phone)?|Silk|linux-gnu|BlackBerry|PlayBook|X11|(New\ )?Nintendo\ (WiiU?|3?DS|Switch)|Xbox(\ One)?)
(?:\ [^;]*)?
(?:;|$)/imx
REGEX
, $parent_matches[1], $result);
$priority = [ 'Xbox One', 'Xbox', 'Windows Phone', 'Tizen', 'Android', 'FreeBSD', 'NetBSD', 'OpenBSD', 'CrOS', 'X11', 'Sailfish' ];
$result[PLATFORM] = array_unique($result[PLATFORM]);
if( count($result[PLATFORM]) > 1 ) {
if( $keys = array_intersect($priority, $result[PLATFORM]) ) {
$platform = reset($keys);
} else {
$platform = $result[PLATFORM][0];
}
} elseif( isset($result[PLATFORM][0]) ) {
$platform = $result[PLATFORM][0];
}
}
if( $platform == 'linux-gnu' || $platform == 'X11' ) {
$platform = 'Linux';
} elseif( $platform == 'CrOS' ) {
$platform = 'Chrome OS';
} elseif( $platform == 'Adr' ) {
$platform = 'Android';
}
preg_match_all(<<<'REGEX'
%(?P<browser>Camino|Kindle(\ Fire)?|Firefox|Iceweasel|IceCat|Safari|MSIE|Trident|AppleWebKit|
TizenBrowser|(?:Headless)?Chrome|YaBrowser|Vivaldi|IEMobile|Opera|OPR|Silk|Midori|Edge|Edg|CriOS|UCBrowser|Puffin|
OculusBrowser|SamsungBrowser|SailfishBrowser|XiaoMi/MiuiBrowser|
Baiduspider|Applebot|Facebot|Googlebot|YandexBot|bingbot|Lynx|Version|Wget|curl|
Valve\ Steam\ Tenfoot|
NintendoBrowser|PLAYSTATION\ (\d|Vita)+)
\)?;?
(?:[:/ ](?P<version>[0-9A-Z.]+)|/[A-Z]*)%ix
REGEX
, $u_agent, $result);
// If nothing matched, return null (to avoid undefined index errors)
if( !isset($result[BROWSER][0]) || !isset($result[BROWSER_VERSION][0]) ) {
if( preg_match('%^(?!Mozilla)(?P<browser>[A-Z0-9\-]+)(/(?P<version>[0-9A-Z.]+))?%ix', $u_agent, $result) ) {
return [ PLATFORM => $platform ?: null, BROWSER => $result[BROWSER], BROWSER_VERSION => empty($result[BROWSER_VERSION]) ? null : $result[BROWSER_VERSION] ];
}
return $return;
}
if( preg_match('/rv:(?P<version>[0-9A-Z.]+)/i', $u_agent, $rv_result) ) {
$rv_result = $rv_result[BROWSER_VERSION];
}
$browser = $result[BROWSER][0];
$version = $result[BROWSER_VERSION][0];
$lowerBrowser = array_map('strtolower', $result[BROWSER]);
$find = function ( $search, &$key = null, &$value = null ) use ( $lowerBrowser ) {
$search = (array)$search;
foreach( $search as $val ) {
$xkey = array_search(strtolower($val), $lowerBrowser);
if( $xkey !== false ) {
$value = $val;
$key = $xkey;
return true;
}
}
return false;
};
$findT = function ( array $search, &$key = null, &$value = null ) use ( $find ) {
$value2 = null;
if( $find(array_keys($search), $key, $value2) ) {
$value = $search[$value2];
return true;
}
return false;
};
$key = 0;
$val = '';
if( $findT([ 'OPR' => 'Opera', 'Facebot' => 'iMessageBot', 'UCBrowser' => 'UC Browser', 'YaBrowser' => 'Yandex', 'Iceweasel' => 'Firefox', 'Icecat' => 'Firefox', 'CriOS' => 'Chrome', 'Edg' => 'Edge', 'XiaoMi/MiuiBrowser' => 'MiuiBrowser' ], $key, $browser) ) {
$version = is_numeric(substr($result[BROWSER_VERSION][$key], 0, 1)) ? $result[BROWSER_VERSION][$key] : null;
} elseif( $find('Playstation Vita', $key, $platform) ) {
$platform = 'PlayStation Vita';
$browser = 'Browser';
} elseif( $find([ 'Kindle Fire', 'Silk' ], $key, $val) ) {
$browser = $val == 'Silk' ? 'Silk' : 'Kindle';
$platform = 'Kindle Fire';
if( !($version = $result[BROWSER_VERSION][$key]) || !is_numeric($version[0]) ) {
$version = $result[BROWSER_VERSION][array_search('Version', $result[BROWSER])];
}
} elseif( $find('NintendoBrowser', $key) || $platform == 'Nintendo 3DS' ) {
$browser = 'NintendoBrowser';
$version = $result[BROWSER_VERSION][$key];
} elseif( $find('Kindle', $key, $platform) ) {
$browser = $result[BROWSER][$key];
$version = $result[BROWSER_VERSION][$key];
} elseif( $find('Opera', $key, $browser) ) {
$find('Version', $key);
$version = $result[BROWSER_VERSION][$key];
} elseif( $find('Puffin', $key, $browser) ) {
$version = $result[BROWSER_VERSION][$key];
if( strlen($version) > 3 ) {
$part = substr($version, -2);
if( ctype_upper($part) ) {
$version = substr($version, 0, -2);
$flags = [ 'IP' => 'iPhone', 'IT' => 'iPad', 'AP' => 'Android', 'AT' => 'Android', 'WP' => 'Windows Phone', 'WT' => 'Windows' ];
if( isset($flags[$part]) ) {
$platform = $flags[$part];
}
}
}
} elseif( $find([ 'Applebot', 'IEMobile', 'Edge', 'Midori', 'Vivaldi', 'OculusBrowser', 'SamsungBrowser', 'Valve Steam Tenfoot', 'Chrome', 'HeadlessChrome', 'SailfishBrowser' ], $key, $browser) ) {
$version = $result[BROWSER_VERSION][$key];
} elseif( $rv_result && $find('Trident') ) {
$browser = 'MSIE';
$version = $rv_result;
} elseif( $browser == 'AppleWebKit' ) {
if( $platform == 'Android' ) {
$browser = 'Android Browser';
} elseif( strpos($platform, 'BB') === 0 ) {
$browser = 'BlackBerry Browser';
$platform = 'BlackBerry';
} elseif( $platform == 'BlackBerry' || $platform == 'PlayBook' ) {
$browser = 'BlackBerry Browser';
} else {
$find('Safari', $key, $browser) || $find('TizenBrowser', $key, $browser);
}
$find('Version', $key);
$version = $result[BROWSER_VERSION][$key];
} elseif( $pKey = preg_grep('/playstation \d/i', $result[BROWSER]) ) {
$pKey = reset($pKey);
$platform = 'PlayStation ' . preg_replace('/\D/', '', $pKey);
$browser = 'NetFront';
}
if (strpos($u_agent, 'Tesla') !== false) {
$platform = 'Tesla';
}
if (strpos($u_agent, 'Polestar') !== false) {
$platform = 'Polestar';
}
return $return;
}
}

View File

@@ -0,0 +1,2 @@
<?php
// Silence is golden.

View File

@@ -0,0 +1,2 @@
<?php
// Silence is golden.

View File

@@ -0,0 +1,2 @@
<?php
// Silence is golden.

View File

@@ -0,0 +1,438 @@
/*Copyright (c) 2020 Jason Zissman
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
(() => {
((root, factory) => {
if (typeof module !== 'undefined' && module.exports) {
// CommonJS
return module.exports = factory();
} else if (typeof define === 'function' && define.amd) {
// AMD
define([], () => {
return (root.TimeMe = factory());
});
} else {
// Global Variables
return root.TimeMe = factory();
}
})(this, () => {
let TimeMe = {
startStopTimes: {},
idleTimeoutMs: 30 * 1000,
currentIdleTimeMs: 0,
checkIdleStateRateMs: 250,
isUserCurrentlyOnPage: true,
isUserCurrentlyIdle: false,
currentPageName: "default-page-name",
timeElapsedCallbacks: [],
userLeftCallbacks: [],
userReturnCallbacks: [],
trackTimeOnElement: (elementId) => {
let element = document.getElementById(elementId);
if (element) {
element.addEventListener("mouseover", () => {
TimeMe.startTimer(elementId);
});
element.addEventListener("mousemove", () => {
TimeMe.startTimer(elementId);
});
element.addEventListener("mouseleave", () => {
TimeMe.stopTimer(elementId);
});
element.addEventListener("keypress", () => {
TimeMe.startTimer(elementId);
});
element.addEventListener("focus", () => {
TimeMe.startTimer(elementId);
});
}
},
getTimeOnElementInSeconds: (elementId) => {
let time = TimeMe.getTimeOnPageInSeconds(elementId);
if (time) {
return time;
} else {
return 0;
}
},
// startTime is optional. If provided, must be of type Date(). By providing
// startTime, you are overriding the internal timing mechanism and manually
// indicating the start time.
startTimer: (pageName, startTime) => {
if (!pageName) {
pageName = TimeMe.currentPageName;
}
if (TimeMe.startStopTimes[pageName] === undefined) {
TimeMe.startStopTimes[pageName] = [];
} else {
let arrayOfTimes = TimeMe.startStopTimes[pageName];
let latestStartStopEntry = arrayOfTimes[arrayOfTimes.length - 1];
if (latestStartStopEntry !== undefined && latestStartStopEntry.stopTime === undefined) {
// Can't start new timer until previous finishes.
return;
}
}
TimeMe.startStopTimes[pageName].push({
"startTime": startTime || new Date(),
"stopTime": undefined
});
},
stopAllTimers: () => {
let pageNames = Object.keys(TimeMe.startStopTimes);
for (let i = 0; i < pageNames.length; i++) {
TimeMe.stopTimer(pageNames[i]);
}
},
// stopTime is optional. If provided, must be of type Date(). By providing
// stopTime, you are overriding the internal timing mechanism and manually
// indicating the stop time.
stopTimer: (pageName, stopTime) => {
if (!pageName) {
pageName = TimeMe.currentPageName;
}
let arrayOfTimes = TimeMe.startStopTimes[pageName];
if (arrayOfTimes === undefined || arrayOfTimes.length === 0) {
// Can't stop timer before you've started it.
return;
}
if (arrayOfTimes[arrayOfTimes.length - 1].stopTime === undefined) {
arrayOfTimes[arrayOfTimes.length - 1].stopTime = stopTime || new Date();
}
},
getTimeOnCurrentPageInSeconds: () => {
return TimeMe.getTimeOnPageInSeconds(TimeMe.currentPageName);
},
getTimeOnPageInSeconds: (pageName) => {
let timeInMs = TimeMe.getTimeOnPageInMilliseconds(pageName);
if (timeInMs === undefined) {
return undefined;
} else {
return timeInMs / 1000;
}
},
getTimeOnCurrentPageInMilliseconds: () => {
return TimeMe.getTimeOnPageInMilliseconds(TimeMe.currentPageName);
},
getTimeOnPageInMilliseconds: (pageName) => {
let totalTimeOnPage = 0;
let arrayOfTimes = TimeMe.startStopTimes[pageName];
if (arrayOfTimes === undefined) {
// Can't get time on page before you've started the timer.
return;
}
let timeSpentOnPageInSeconds = 0;
for (let i = 0; i < arrayOfTimes.length; i++) {
let startTime = arrayOfTimes[i].startTime;
let stopTime = arrayOfTimes[i].stopTime;
if (stopTime === undefined) {
stopTime = new Date();
}
let difference = stopTime - startTime;
timeSpentOnPageInSeconds += (difference);
}
totalTimeOnPage = Number(timeSpentOnPageInSeconds);
return totalTimeOnPage;
},
getTimeOnAllPagesInSeconds: () => {
let allTimes = [];
let pageNames = Object.keys(TimeMe.startStopTimes);
for (let i = 0; i < pageNames.length; i++) {
let pageName = pageNames[i];
let timeOnPage = TimeMe.getTimeOnPageInSeconds(pageName);
allTimes.push({
"pageName": pageName,
"timeOnPage": timeOnPage
});
}
return allTimes;
},
setIdleDurationInSeconds: (duration) => {
let durationFloat = parseFloat(duration);
if (isNaN(durationFloat) === false) {
TimeMe.idleTimeoutMs = duration * 1000;
} else {
throw {
name: "InvalidDurationException",
message: "An invalid duration time (" + duration + ") was provided."
};
}
},
setCurrentPageName: (pageName) => {
TimeMe.currentPageName = pageName;
},
resetRecordedPageTime: (pageName) => {
delete TimeMe.startStopTimes[pageName];
},
resetAllRecordedPageTimes: () => {
let pageNames = Object.keys(TimeMe.startStopTimes);
for (let i = 0; i < pageNames.length; i++) {
TimeMe.resetRecordedPageTime(pageNames[i]);
}
},
userActivityDetected: () => {
if (TimeMe.isUserCurrentlyIdle) {
TimeMe.triggerUserHasReturned();
}
TimeMe.resetIdleCountdown();
},
resetIdleCountdown: () => {
TimeMe.isUserCurrentlyIdle = false;
TimeMe.currentIdleTimeMs = 0;
},
callWhenUserLeaves: (callback, numberOfTimesToInvoke) => {
TimeMe.userLeftCallbacks.push({
callback: callback,
numberOfTimesToInvoke: numberOfTimesToInvoke
})
},
callWhenUserReturns: (callback, numberOfTimesToInvoke) => {
TimeMe.userReturnCallbacks.push({
callback: callback,
numberOfTimesToInvoke: numberOfTimesToInvoke
})
},
triggerUserHasReturned: () => {
if (!TimeMe.isUserCurrentlyOnPage) {
TimeMe.isUserCurrentlyOnPage = true;
TimeMe.resetIdleCountdown();
for (let i = 0; i < TimeMe.userReturnCallbacks.length; i++) {
let userReturnedCallback = TimeMe.userReturnCallbacks[i];
let numberTimes = userReturnedCallback.numberOfTimesToInvoke;
if (isNaN(numberTimes) || (numberTimes === undefined) || numberTimes > 0) {
userReturnedCallback.numberOfTimesToInvoke -= 1;
userReturnedCallback.callback();
}
}
}
TimeMe.startTimer();
},
triggerUserHasLeftPageOrGoneIdle: () => {
if (TimeMe.isUserCurrentlyOnPage) {
TimeMe.isUserCurrentlyOnPage = false;
for (let i = 0; i < TimeMe.userLeftCallbacks.length; i++) {
let userHasLeftCallback = TimeMe.userLeftCallbacks[i];
let numberTimes = userHasLeftCallback.numberOfTimesToInvoke;
if (isNaN(numberTimes) || (numberTimes === undefined) || numberTimes > 0) {
userHasLeftCallback.numberOfTimesToInvoke -= 1;
userHasLeftCallback.callback();
}
}
}
TimeMe.stopAllTimers();
},
callAfterTimeElapsedInSeconds: (timeInSeconds, callback) => {
TimeMe.timeElapsedCallbacks.push({
timeInSeconds: timeInSeconds,
callback: callback,
pending: true
});
},
checkIdleState: () => {
for (let i = 0; i < TimeMe.timeElapsedCallbacks.length; i++) {
if (TimeMe.timeElapsedCallbacks[i].pending && TimeMe.getTimeOnCurrentPageInSeconds() > TimeMe.timeElapsedCallbacks[i].timeInSeconds) {
TimeMe.timeElapsedCallbacks[i].callback();
TimeMe.timeElapsedCallbacks[i].pending = false;
}
}
if (TimeMe.isUserCurrentlyIdle === false && TimeMe.currentIdleTimeMs > TimeMe.idleTimeoutMs) {
TimeMe.isUserCurrentlyIdle = true;
TimeMe.triggerUserHasLeftPageOrGoneIdle();
} else {
TimeMe.currentIdleTimeMs += TimeMe.checkIdleStateRateMs;
}
},
visibilityChangeEventName: undefined,
hiddenPropName: undefined,
listenForVisibilityEvents: (trackWhenUserLeavesPage, trackWhenUserGoesIdle) => {
if (trackWhenUserLeavesPage) {
TimeMe.listenForUserLeavesOrReturnsEvents();
}
if (trackWhenUserGoesIdle) {
TimeMe.listForIdleEvents();
}
},
listenForUserLeavesOrReturnsEvents: () => {
if (typeof document.hidden !== "undefined") {
TimeMe.hiddenPropName = "hidden";
TimeMe.visibilityChangeEventName = "visibilitychange";
} else if (typeof document.mozHidden !== "undefined") {
TimeMe.hiddenPropName = "mozHidden";
TimeMe.visibilityChangeEventName = "mozvisibilitychange";
} else if (typeof document.msHidden !== "undefined") {
TimeMe.hiddenPropName = "msHidden";
TimeMe.visibilityChangeEventName = "msvisibilitychange";
} else if (typeof document.webkitHidden !== "undefined") {
TimeMe.hiddenPropName = "webkitHidden";
TimeMe.visibilityChangeEventName = "webkitvisibilitychange";
}
document.addEventListener(TimeMe.visibilityChangeEventName, () => {
if (document[TimeMe.hiddenPropName]) {
TimeMe.triggerUserHasLeftPageOrGoneIdle();
} else {
TimeMe.triggerUserHasReturned();
}
}, false);
window.addEventListener('blur', () => {
TimeMe.triggerUserHasLeftPageOrGoneIdle();
});
window.addEventListener('focus', () => {
TimeMe.triggerUserHasReturned();
});
},
listForIdleEvents: () => {
document.addEventListener("mousemove", () => { TimeMe.userActivityDetected(); });
document.addEventListener("keyup", () => { TimeMe.userActivityDetected(); });
document.addEventListener("touchstart", () => { TimeMe.userActivityDetected(); });
window.addEventListener("scroll", () => { TimeMe.userActivityDetected(); });
setInterval(() => {
if (TimeMe.isUserCurrentlyIdle !== true) {
TimeMe.checkIdleState();
}
}, TimeMe.checkIdleStateRateMs);
},
websocket: undefined,
websocketHost: undefined,
setUpWebsocket: (websocketOptions) => {
if (window.WebSocket && websocketOptions) {
let websocketHost = websocketOptions.websocketHost; // "ws://hostname:port"
try {
TimeMe.websocket = new WebSocket(websocketHost);
window.onbeforeunload = () => {
TimeMe.sendCurrentTime(websocketOptions.appId);
};
TimeMe.websocket.onopen = () => {
TimeMe.sendInitWsRequest(websocketOptions.appId);
}
TimeMe.websocket.onerror = (error) => {
if (console) {
console.log("Error occurred in websocket connection: " + error);
}
}
TimeMe.websocket.onmessage = (event) => {
if (console) {
console.log(event.data);
}
}
} catch (error) {
if (console) {
console.error("Failed to connect to websocket host. Error:" + error);
}
}
}
},
websocketSend: (data) => {
TimeMe.websocket.send(JSON.stringify(data));
},
sendCurrentTime: (appId) => {
let timeSpentOnPage = TimeMe.getTimeOnCurrentPageInMilliseconds();
let data = {
type: "INSERT_TIME",
appId: appId,
timeOnPageMs: timeSpentOnPage,
pageName: TimeMe.currentPageName
};
TimeMe.websocketSend(data);
},
sendInitWsRequest: (appId) => {
let data = {
type: "INIT",
appId: appId
};
TimeMe.websocketSend(data);
},
initialize: (options) => {
let idleTimeoutInSeconds = TimeMe.idleTimeoutMs || 30;
let currentPageName = TimeMe.currentPageName || "default-page-name";
let websocketOptions = undefined;
let initialStartTime = undefined;
let trackWhenUserLeavesPage = true;
let trackWhenUserGoesIdle = true;
if (options) {
idleTimeoutInSeconds = options.idleTimeoutInSeconds || idleTimeoutInSeconds;
currentPageName = options.currentPageName || currentPageName;
websocketOptions = options.websocketOptions;
initialStartTime = options.initialStartTime;
if (options.trackWhenUserLeavesPage === false) {
trackWhenUserLeavesPage = false;
}
if (options.trackWhenUserGoesIdle === false) {
trackWhenUserGoesIdle = false;
}
}
TimeMe.setIdleDurationInSeconds(idleTimeoutInSeconds)
TimeMe.setCurrentPageName(currentPageName)
TimeMe.setUpWebsocket(websocketOptions)
TimeMe.listenForVisibilityEvents(trackWhenUserLeavesPage, trackWhenUserGoesIdle);
TimeMe.startTimer(undefined, initialStartTime);
}
};
return TimeMe;
});
}).call(this);
// Initialize library and start tracking time
TimeMe.initialize({
idleTimeoutInSeconds: 30 // seconds
});

File diff suppressed because one or more lines are too long