@caspingus/lt
Version:
A utility library of helpers and extensions useful when working with Learnosity APIs.
717 lines (716 loc) • 17.2 kB
JavaScript
import { n as e, t } from "../../player-BsvIsWXI.js";
import { r as n, t as r } from "../../extensionsFactory-hk5ijx1G.js";
import { networkStatus as i } from "./networkStatus.js";
//#region src/utils/userAgent.js
var a = {
edge: /Edg(?:A|iOS)?\/([\d.]+)/,
opr: /OPR\/([\d.]+)/,
samsung: /SamsungBrowser\/([\d.]+)/,
chrome: /Chrome\/([\d.]+)/,
firefox: /Firefox\/([\d.]+)/,
safariTail: /\bSafari\/[\d.]+$/,
version: /Version\/([\d.]+)/,
win: /Windows NT ([\d.]+)/,
mac: /Mac OS X (\d+[_.]\d+(?:[_.]\d+)?)/,
ios: /(?:iPhone|iPad|iPod).*OS (\d+[_.]\d+(?:[_.]\d+)?)/,
android: /Android ([\d.]+)/,
cros: /CrOS [\w_]+ ([\d.]+)/,
linux: /\bLinux\b/,
mobileHint: /\bMobi\b/,
ipad: /\biPad\b/,
tablet: /\bTablet\b/,
bot: /\b(bot|crawler|spider|crawling)\b/i,
webkit: /AppleWebKit\/([\d.]+)/
};
function o(e) {
return a.edge.test(e) ? _({
name: "Edge",
version: m(a.edge, e)
}) : a.opr.test(e) ? _({
name: "Opera",
version: m(a.opr, e)
}) : a.samsung.test(e) ? _({
name: "Samsung Internet",
version: m(a.samsung, e)
}) : /Chrome\//.test(e) && !a.edge.test(e) && !a.opr.test(e) && !a.samsung.test(e) ? _({
name: "Chrome",
version: m(a.chrome, e)
}) : a.firefox.test(e) ? _({
name: "Firefox",
version: m(a.firefox, e)
}) : !/Chrome|Chromium|Edg|OPR|SamsungBrowser/.test(e) && a.safariTail.test(e) ? _({
name: "Safari",
version: m(a.version, e)
}) : {};
}
function s(e) {
return /Macintosh/.test(e) && /Mobile\//.test(e) && /Safari/.test(e) ? {
name: "iOS",
version: void 0
} : a.win.test(e) ? {
name: "Windows",
version: m(a.win, e) || void 0
} : /iPhone|iPad|iPod/.test(e) ? {
name: "iOS",
version: g(m(a.ios, e))
} : a.android.test(e) ? {
name: "Android",
version: m(a.android, e)
} : a.cros.test(e) ? {
name: "Chrome OS",
version: m(a.cros, e)
} : a.mac.test(e) ? {
name: "macOS",
version: g(m(a.mac, e))
} : a.linux.test(e) ? {
name: "Linux",
version: void 0
} : {};
}
function c(e) {
return a.bot.test(e) ? "bot" : a.ipad.test(e) || a.tablet.test(e) ? "tablet" : a.mobileHint.test(e) || /Android/.test(e) && !/Tablet|iPad/.test(e) ? "mobile" : "desktop";
}
function l(e) {
return a.webkit.test(e) ? {
name: "WebKit",
version: m(a.webkit, e)
} : /Gecko\/\d/.test(e) && /Firefox\/([\d.]+)/.test(e) ? {
name: "Gecko",
version: m(a.firefox, e)
} : /Chrome\/|Edg\/|OPR\/|SamsungBrowser\//.test(e) ? { name: "Blink" } : {};
}
function u(e, t) {
try {
let n = t && (t.brands || t.getBrands?.());
if (!n || !n.length) return e;
let r = n.filter((e) => !/Not.?A.?Brand/i.test(e.brand)).sort((e, t) => parseInt(t.version, 10) - parseInt(e.version, 10))[0];
if (r && r.brand) return _({
name: r.brand,
version: e.version
});
} catch {}
return e;
}
function d(e) {
return e ||= "", {
ua: e,
browser: o(e),
os: s(e),
deviceType: c(e),
engine: l(e),
reducedUA: /\bChrome\/\d+\.0\.0\.0\b/.test(e) || /\bEdg\/\d+\.0\.0\.0\b/.test(e) || !1
};
}
function f() {
let e = typeof navigator < "u" && navigator.userAgent ? navigator.userAgent : "", t = typeof navigator < "u" ? navigator.userAgentData : void 0, n = d(e);
return t && (t.brands || t.getBrands) && (n.browser = u(n.browser, t)), n.meta = {
source: t && (t.brands || t.getBrands) ? "ua-ch-low" : "ua",
usedHighEntropy: !1,
isReducedUA: h(e)
}, delete n.reducedUA, n;
}
async function p() {
let e = typeof navigator < "u" && navigator.userAgent ? navigator.userAgent : "", t = typeof navigator < "u" ? navigator.userAgentData : void 0;
if (t && typeof t.getHighEntropyValues == "function") try {
let n = await t.getHighEntropyValues([
"platform",
"platformVersion",
"uaFullVersion",
"architecture",
"bitness",
"model",
"fullVersionList"
]), r = n.fullVersionList || t.brands || t.getBrands?.() || [], i = [
"Chrome",
"Google Chrome",
"Microsoft Edge",
"Edge",
"Chromium",
"Opera",
"OPR",
"Samsung Internet",
"Firefox"
], a = r.find((e) => i.some((t) => e.brand.toLowerCase().includes(t.toLowerCase()))) || r.find((e) => !/Not.?A.?Brand/i.test(e.brand)) || null, o = a?.brand || r[0] && r[0].brand || void 0, s = a?.version || n.uaFullVersion || void 0, c = n.platform || void 0, l = n.platformVersion || void 0, u;
return /Android/i.test(c) ? u = "mobile" : /Windows|macOS|Chrome OS|Linux|iOS/i.test(c) && (u = "desktop"), {
ua: e,
browser: _({
name: o,
version: s
}),
os: {
name: c,
version: l
},
deviceType: u,
engine: void 0,
arch: n.architecture,
bitness: n.bitness,
model: n.model,
meta: {
source: "ua-ch-high",
usedHighEntropy: !0,
isReducedUA: h(e)
}
};
} catch {}
let n = f();
return n.meta.source = n.meta && n.meta.source || "ua", n;
}
function m(e, t) {
let n = t.match(e);
return n ? n[1] : void 0;
}
function h(e) {
return /\bChrome\/\d+\.0\.0\.0\b/.test(e) || /\bEdg\/\d+\.0\.0\.0\b/.test(e);
}
function g(e) {
return e ? e.replace(/_/g, ".") : void 0;
}
function _(e) {
if (e && e.version && typeof e.version == "string") {
let t = e.version.split(".")[0];
t && (e.versionMajor = t);
}
return e;
}
//#endregion
//#region src/assessment/extensions/events/index.js
var v = {
initialised: !1,
events: {
events: [],
network: {
speed: null,
status: "online"
},
session: null,
user: null
}
}, y = null, b = /* @__PURE__ */ new Set(), x = {
lastX: null,
lastY: null,
prevX: null,
prevY: null,
hasTouch: !1
};
function S() {
if (r.isVerticalLayout()) {
r.utils.logger.warn("Event log is not currently supported in vertical layout.");
return;
}
v.initialised ||= (C(), r.eventBus.on("item:load", w, "events"), t() || queueMicrotask(w), E(), T(), M(), A(), j(), k(), !0);
}
function C() {
t() ? N({
type: "test:ready",
timestamp: L()
}) : (N({
type: "test:start",
timestamp: L()
}), e() && N({
type: "test:reading:start",
timestamp: L()
}));
}
function w() {
let e = r.itemReference();
if (!e || e === y) return;
y = e;
let t = L();
P(t), b.has(e) || (b.add(e), D(e, t), O(e));
}
async function T() {
v.events.user = r.userId(), v.events.session = r.sessionId(), v.events.environment = await R(), v.events.network.speed = i.checkSpeed();
}
function E() {
r.eventBus.on("test:start", () => {
N({
type: "test:start",
timestamp: L()
});
}), r.eventBus.on("unfocused", () => {
N({
type: "unfocused",
item: r.itemReference(),
timestamp: L()
});
}), r.eventBus.on("focused", () => {
N({
type: "focused",
item: r.itemReference(),
timestamp: L()
});
}), r.eventBus.on("test:reading:start", () => {
N({
type: "test:reading:start",
timestamp: L()
});
}), r.eventBus.on("test:reading:end", () => {
N({
type: "test:reading:end",
timestamp: L()
});
}), r.eventBus.on("item:warningOnChange", () => {
N({
type: "item:warningOnChange",
item: r.itemReference(),
timestamp: L()
});
}), r.eventBus.on("items:fetch:done", () => {
N({
type: "items:fetch:done",
item: r.itemReference(),
timestamp: L()
});
}), r.eventBus.on("section:changed", () => {
N({
type: "section:changed",
timestamp: L()
});
}), r.eventBus.on("test:panel:show", async () => {
let e = await F();
["dialog:pause"].includes(e) || N({
type: e,
timestamp: L()
});
}), r.eventBus.on("test:pause", () => {
N({
type: "test:pause",
timestamp: L()
});
}), r.eventBus.on("test:resume", () => {
N({
type: "test:resume",
timestamp: L()
});
}), r.eventBus.on("test:save", () => {
N({
type: "test:save",
timestamp: L()
});
}), r.eventBus.on("test:save:success", () => {
N({
type: "test:save:success",
timestamp: L()
});
}), r.eventBus.on("test:save:error", () => {
N({
type: "test:save:error",
timestamp: L()
});
}), r.eventBus.on("test:submit", () => {
N({
type: "test:submit",
timestamp: L()
});
}), r.eventBus.on("test:submit:success", () => {
N({
type: "test:submit:success",
timestamp: L()
});
}), r.eventBus.on("test:submit:error", () => {
N({
type: "test:submit:error",
timestamp: L()
});
}), r.eventBus.on("test:finished:save", () => {
N({
type: "test:finished:save",
timestamp: L()
});
}), r.eventBus.on("test:finished:submit", () => {
N({
type: "test:finished:submit",
timestamp: L()
});
}), r.eventBus.on("test:finished:discard", () => {
N({
type: "test:finished:discard",
timestamp: L()
});
}), r.eventBus.on("time:end", () => {
N({
type: "time:end",
timestamp: L()
});
});
}
function D(e, t) {
let n = [
"audio",
"chemistryessayV2",
"drawing",
"fileupload",
"formulaessayV2",
"imageupload",
"longtext",
"longtextV2",
"plaintext",
"video"
], i = [
"association",
"bowtie",
"classification",
"clozeassociation",
"clozedropdown",
"clozetext",
"graphplotting",
"gridded",
"hotspot",
"imageclozeassociation",
"imageclozedropdown",
"imageclozetext",
"numberline",
"numberlineplot",
"orderlist",
"shorttext",
"simplechart",
"simpleshading",
"tokenhighlight"
], a = {}, o = [
"formulaessayV2",
"longtextV2",
"plaintext",
"shorttext"
], s = {}, c = {}, l = ["mcq"], u = r.item(e);
(u && u.questions ? u.questions.map((e) => e.response_id) : []).forEach((u) => {
let d = r.itemsApp().question(u), f = d.getQuestion(), p = f.type, m = f.metadata.widget_reference;
if (["audio", "video"].includes(p) && (d.on("recording:started", () => {
N({
type: "recording:started",
item: e,
question: m,
timestamp: L()
});
}), d.on("recording:paused", () => {
N({
type: "recording:paused",
item: e,
question: m,
timestamp: L()
});
}), d.on("recording:resumed", () => {
N({
type: "recording:resumed",
item: e,
question: m,
timestamp: L()
});
}), d.on("recording:stopped", () => {
N({
type: "recording:stopped",
item: e,
question: m,
timestamp: L()
});
})), o.includes(p)) {
s[u] = {
wordCount: 0,
timestamp: L()
};
let t = document.getElementById(u);
t && t.addEventListener("paste", () => {
N({
type: "question:paste",
item: e,
question: m,
responseId: u,
timestamp: L()
});
});
}
if (l.includes(p)) {
let t = document.getElementById(u);
t && t.addEventListener("click", (t) => {
if (t.detail === 0) return;
if (x.lastX === null) {
x.hasTouch || queueMicrotask(() => {
N({
type: "question:suspiciousClick",
item: e,
question: m,
responseId: u,
data: { reason: "noMouseMovement" },
timestamp: L()
});
});
return;
}
let n = Math.round(Math.sqrt((t.clientX - x.lastX) ** 2 + (t.clientY - x.lastY) ** 2)) <= 20;
if (x.prevX === null && n && !x.hasTouch) {
queueMicrotask(() => {
N({
type: "question:suspiciousClick",
item: e,
question: m,
responseId: u,
data: { reason: "noMouseMovement" },
timestamp: L()
});
});
return;
}
if (x.prevX !== null && n) {
let t = Math.round(Math.sqrt((x.lastX - x.prevX) ** 2 + (x.lastY - x.prevY) ** 2));
t > 150 && queueMicrotask(() => {
N({
type: "question:suspiciousClick",
item: e,
question: m,
responseId: u,
data: {
reason: "mouseTeleport",
jumpDistance: t
},
timestamp: L()
});
});
}
});
}
d.on("changed", () => {
let l = a[u] || 0, { revision: d, value: f } = r.questionResponse(u);
if (n.includes(p) || i.includes(p) ? L() - l >= 3e4 && (a[u] = L(), N({
type: "question:changed",
item: e,
question: m,
responseId: u,
data: i.includes(p) ? {
revision: d,
value: f
} : {},
timestamp: L()
})) : N({
type: "question:changed",
item: e,
question: m,
responseId: u,
data: {
revision: d,
value: f
},
timestamp: L()
}), !c[u]) {
c[u] = !0;
let n = L() - t;
n < 5e3 && N({
type: "question:suspiciousResponseSpeed",
item: e,
question: m,
responseId: u,
data: {
reason: "fastResponse",
ms: n
},
timestamp: L()
});
}
if (o.includes(p) && f) {
let t = I(f, p), n = s[u], r = L() - n.timestamp, i = t - n.wordCount;
if (r > 0 && i > 0) {
let t = Math.round(i / r * 6e4);
t > 300 && N({
type: "question:suspiciousInput",
item: e,
question: m,
responseId: u,
data: {
wpm: t,
wordsDelta: i
},
timestamp: L()
});
}
s[u] = {
wordCount: t,
timestamp: L()
};
}
}), d.on("masked", () => {
N({
type: "question:masked",
item: e,
question: m,
timestamp: L()
});
}), d.on("validated", () => {
N({
type: "question:validated",
item: e,
question: m,
timestamp: L()
});
});
});
}
function O(e) {
let t = r.item(e);
if (!t) return;
let n = [...new Set([...t.feature_ids || [], ...t.simplefeature_ids || []])], i = (t.features || []).reduce((e, t) => (e[t.feature_id] = t.type, e), {});
n.forEach((t) => {
let n = r.itemsApp().feature(t), a = ["audio", "video"].includes(i[t]);
n && a && (n.on("begin", () => {
N({
type: "media:begin",
item: e,
timestamp: L()
});
}), n.on("complete", () => {
N({
type: "media:complete",
item: e,
timestamp: L()
});
}), n.on("playback:started", () => {
N({
type: "playback:started",
item: e,
timestamp: L()
});
}), n.on("playback:paused", () => {
N({
type: "playback:paused",
item: e,
timestamp: L()
});
}), n.on("playback:resumed", () => {
N({
type: "playback:resumed",
item: e,
timestamp: L()
});
}), n.on("playback:stopped", () => {
N({
type: "playback:stopped",
item: e,
timestamp: L()
});
}), n.on("playback:complete", () => {
N({
type: "playback:complete",
item: e,
timestamp: L()
});
}));
});
}
function k() {
if (typeof BroadcastChannel > "u") return;
let e = new BroadcastChannel(`lt_session_${r.sessionId()}`);
e.onmessage = (t) => {
t.data.type === "tab:ping" && e.postMessage({ type: "tab:pong" }), t.data.type === "tab:pong" && N({
type: "tab:duplicate",
item: r.itemReference(),
timestamp: L()
});
}, e.postMessage({ type: "tab:ping" }), window.addEventListener("beforeunload", () => e.close());
}
function A() {
document.addEventListener("visibilitychange", () => {
document.visibilityState === "hidden" ? N({
type: "page:blur",
item: r.itemReference(),
timestamp: L()
}) : N({
type: "page:focus",
item: r.itemReference(),
timestamp: L()
});
});
}
function j() {
document.addEventListener("mousemove", (e) => {
x.prevX = x.lastX, x.prevY = x.lastY, x.lastX = e.clientX, x.lastY = e.clientY;
}, { passive: !0 }), document.addEventListener("touchstart", () => {
x.hasTouch = !0;
}, {
once: !0,
passive: !0
});
}
function M() {
document.addEventListener("LTNetworkOnline", () => {
v.events.network.status === "offline" && (v.events.network.status = "online", N({
type: "network:online",
item: r.itemReference(),
timestamp: L()
}));
}), document.addEventListener("LTNetworkOffline", () => {
v.events.network.status === "online" && (v.events.network.status = "offline", N({
type: "network:offline",
item: r.itemReference(),
timestamp: L()
}));
});
}
function N(e) {
v.events.events.push(e);
}
function P(e) {
N({
type: "item:load",
item: r.itemReference(),
data: { num: r.itemPosition() },
timestamp: e
});
}
function F() {
return new Promise((e) => {
setTimeout(() => {
let t = document.querySelectorAll(".lrn-assess-dialogs > .lrn-dialog-default"), n = "", r = "", i = Array.from(t).filter((e) => e.style.display === "block").map((e) => ({
id: e.id,
class: e.className
}));
if (i.length === 0) {
e("");
return;
}
let a = i[0];
switch (a?.id ? n = a.id.replace(/\d+/g, "") : a?.class.includes("review-screen") && (n = "review-screen"), n) {
case "accessibility-panel":
r = "dialog:accessibility";
break;
case "custom-dialog":
r = "dialog:custom-dialog";
break;
case "module-load-error-dialog":
r = "dialog:module-load-error";
break;
case "review-screen":
r = "dialog:review-screen";
break;
case "test-asset-upload-error-dialog":
r = "dialog:asset-upload-error";
break;
case "test-error-dialog":
r = "dialog:error";
break;
case "test-pause-dialog":
r = "dialog:pause";
break;
case "test-save-submit":
r = "dialog:save-submit";
break;
default: break;
}
e(r);
}, 500);
});
}
function I(e, t) {
if (!e) return 0;
let n = e;
return ["formulaessayV2", "longtextV2"].includes(t) && (n = e.replace(/<[^>]+>/g, " ")), n.trim().split(/\s+/).filter((e) => e.length > 0).length;
}
function L() {
return Date.now();
}
async function R() {
return p();
}
function z() {
return v.events;
}
var B = n("events", S, { getEvents: z });
//#endregion
export { B as events };