// ==UserScript==
// @name Easy 网课学习助手
// @namespace Aaron
// @version 1.1.2
// @author Aaron
// @description 💻 超星/学习通、智慧树等网课平台学习助手|视频学习 · 课程作业 · 章节测验 · 智能题库查询|界面简洁,操作高效,持续更新。
// @icon data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/PjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+PHN2ZyB0PSIxNzU3MDcxNDYxMDkyIiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjI3NTMiIGlkPSJteF9uXzE3NTcwNzE0NjEwOTMiIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCI+PHBhdGggZD0iTTUxMiAwQzIyOS4yMDYgMCAwLjAyIDIyOS4yMjYgMC4wMiA1MTIuMDIgMC4wMiA3OTQuNzc1IDIyOS4yMDcgMTAyNCA1MTIgMTAyNHM1MTEuOTgtMjI5LjIyNiA1MTEuOTgtNTExLjk4QzEwMjMuOTggMjI5LjIyNyA3OTQuNzkzIDAgNTEyIDB6IG0zMDMuMzcyIDMxOC45NUw0NjguNzIgNzgwLjE1NGMtMTAuODMgMTQuMzctMjcuMzI2IDIzLjQxLTQ1LjI4IDI0Ljc0M2E1OC44OSA1OC44OSAwIDAgMS00LjY2NCAwLjE2NmMtMTYuMzMgMC0zMi4wNzUtNi4zNzMtNDMuNzgtMTcuOTExTDE4Mi4wOTQgNTk3LjcwNWMtMjQuNjE4LTI0LjIwMi0yNC45OTMtNjMuNzMyLTAuNzkxLTg4LjM1IDI0LjIwMS0yNC42NiA2My43MzEtMjQuOTUxIDg4LjM1LTAuODMzbDE0Mi4wNDIgMTM5LjUwMiAzMDMuNzg5LTQwNC4yMThjMjAuNzQ0LTI3LjU3NiA1OS45LTMzLjExNiA4Ny41MTYtMTIuNDE0IDI3LjUzNCAyMC44MjggMzMuMTE2IDU5Ljk4MyAxMi4zNzIgODcuNTU5eiIgcC1pZD0iMjc1NCIgZmlsbD0iIzEyOTZkYiI+PC9wYXRoPjwvc3ZnPg==
// @match *://*.chaoxing.com/*
// @match *://*.edu.cn/*
// @match *://*.nbdlib.cn/*
// @match *://*.hnsyu.net/*
// @match *://*.gdhkmooc.com/*
// @match *://*.zhihuishu.com/*
// @match *://hike-teaching-center.polymas.com/*
// @require https://cdn.jsdelivr.net/npm/vue@3.5.42/dist/vue.global.prod.js
// @require data:application/javascript,%3Bwindow.Vue%3DVue%3B
// @require https://cdn.jsdelivr.net/npm/dayjs@1.11.13/dayjs.min.js
// @require https://cdn.jsdelivr.net/npm/dayjs@1.11.13/plugin/advancedFormat.js
// @require https://cdn.jsdelivr.net/npm/dayjs@1.11.13/plugin/customParseFormat.js
// @require https://cdn.jsdelivr.net/npm/dayjs@1.11.13/plugin/localeData.js
// @require https://cdn.jsdelivr.net/npm/dayjs@1.11.13/plugin/quarterOfYear.js
// @require https://cdn.jsdelivr.net/npm/dayjs@1.11.13/plugin/weekOfYear.js
// @require https://cdn.jsdelivr.net/npm/dayjs@1.11.13/plugin/weekYear.js
// @require https://cdn.jsdelivr.net/npm/dayjs@1.11.13/plugin/weekday.js
// @require data:application/javascript,%3Bwindow.dayjs%3Ddayjs%3Bwindow.dayjs_plugin_advancedFormat%3Ddayjs_plugin_advancedFormat%3Bwindow.dayjs_plugin_customParseFormat%3Ddayjs_plugin_customParseFormat%3Bwindow.dayjs_plugin_localeData%3Ddayjs_plugin_localeData%3Bwindow.dayjs_plugin_quarterOfYear%3Ddayjs_plugin_quarterOfYear%3Bwindow.dayjs_plugin_weekOfYear%3Ddayjs_plugin_weekOfYear%3Bwindow.dayjs_plugin_weekYear%3Ddayjs_plugin_weekYear%3Bwindow.dayjs_plugin_weekday%3Ddayjs_plugin_weekday%3B
// @require https://cdn.jsdelivr.net/npm/pinia@3.0.3/dist/pinia.iife.prod.js
// @require data:application/javascript,%3Bwindow.Pinia%3DPinia%3B
// @require https://cdn.jsdelivr.net/npm/ant-design-vue@3.2.20/dist/antd.min.js
// @require data:application/javascript,%3Bwindow.antd%3Dantd%3B
// @require https://cdn.jsdelivr.net/npm/crypto-js@4.2.0/crypto-js.js
// @require data:application/javascript,%3Bwindow.CryptoJS%3DCryptoJS%3B
// @require https://cdn.jsdelivr.net/npm/blueimp-md5@2.19.0/js/md5.min.js
// @require data:application/javascript,%3Bwindow.md5%3Dmd5%3B
// @resource antdCss https://cdn.jsdelivr.net/npm/ant-design-vue@3.2.20/dist/antd.min.css
// @resource ttf https://www.forestpolice.org/ttf/2.0/table.json
// @connect cx.icodef.com
// @connect www.aiask.site
// @connect scriptcat.org
// @grant GM_deleteValue
// @grant GM_getResourceText
// @grant GM_getValue
// @grant GM_info
// @grant GM_setValue
// @grant GM_xmlhttpRequest
// @grant unsafeWindow
// @run-at document-end
// @antifeature ads
// @antifeature payment
// ==/UserScript==
(function (vue, pinia, antDesignVue, CryptoJS, md5) {
'use strict';
const SCRIPT_META = {
name: "Easy 网课学习助手",
author: "Aaron",
version: "1.1.2"
};
const BRIDGE_CHANNEL = "cx-extension-platform-v1";
function isRecord(value) {
return value !== null && typeof value === "object" && !Array.isArray(value);
}
let clientId;
let counter = 0;
Promise.resolve();
const pending = /* @__PURE__ */ new Map();
function listen() {
if (clientId) return;
clientId = Array.from(crypto.getRandomValues(new Uint8Array(16)), (value) => value.toString(16).padStart(2, "0")).join("");
window.addEventListener("message", (event) => {
const message = event.data;
if (event.source !== window || event.origin !== location.origin || !isRecord(message) || message.channel !== BRIDGE_CHANNEL || message.direction !== "response" || message.clientId !== clientId) return;
const request = pending.get(message.id);
if (!request) return;
pending.delete(message.id);
clearTimeout(request.timer);
if (message.ok) request.resolve(message.payload);
else request.reject(new Error(message.error || "Extension request failed"));
});
}
function send(operation, payload, timeout = 1e4, id = `${++counter}`) {
listen();
return new Promise((resolve, reject) => {
const timer = setTimeout(() => {
pending.delete(id);
reject(new Error("Extension bridge did not respond"));
}, timeout);
pending.set(id, { resolve, reject, timer });
window.postMessage({ channel: BRIDGE_CHANNEL, direction: "request", clientId, id, operation, payload }, location.origin);
});
}
function extensionTrustedClick(attribute) {
return send("input:click", { attribute, url: location.href }, 1e4);
}
function extensionReadQuestion(attribute) {
return send("question:read", { attribute, url: location.href }, 2e3);
}
async function initPlatform() {
return true;
}
const _GM_info = typeof GM_info !== "undefined" ? GM_info : { script: SCRIPT_META };
const _unsafeWindow = typeof unsafeWindow !== "undefined" ? unsafeWindow : globalThis.window;
const _GM_getResourceText = typeof GM_getResourceText !== "undefined" ? GM_getResourceText : () => "";
const _GM_xmlhttpRequest = typeof GM_xmlhttpRequest !== "undefined" ? GM_xmlhttpRequest : () => {
throw new Error("GM_xmlhttpRequest is unavailable");
};
const _GM_getValue = typeof GM_getValue !== "undefined" ? GM_getValue : (_key, fallback) => fallback;
const _GM_setValue = typeof GM_setValue !== "undefined" ? GM_setValue : () => {
throw new Error("GM_setValue is unavailable");
};
function getAntdCss() {
return _GM_getResourceText("antdCss");
}
const componentCss = '.floating-modal{position:fixed;z-index:1000;overflow:hidden;pointer-events:none}.floating-modal .ant-modal{position:absolute;top:12px;right:12px;max-width:calc(100vw - 24px);margin:0;padding:0;font-size:12px;pointer-events:none}.floating-panel{touch-action:auto;pointer-events:auto}.floating-modal .ant-modal-content{overflow:hidden;border:1px solid #dce3ed;border-radius:12px;background:#fff;box-shadow:0 8px 32px #20345424,0 2px 6px #2034540d}.floating-modal .ant-modal-header{margin:0;padding:8px 10px;border-bottom:1px solid #e8edf4;background:#f8fafc}.floating-modal .ant-modal-title{font-size:12px;line-height:24px}.floating-modal .ant-modal-body{max-height:min(480px,calc(100vh - 80px));max-height:min(480px,calc(100dvh - 80px));overflow:auto;overscroll-behavior:contain;padding:10px;color:#334155;font-size:12px;line-height:1.6}.floating-title{display:flex;align-items:center;gap:8px;min-width:0;cursor:grab;touch-action:none;user-select:none}.floating-title.is-dragging{cursor:grabbing}.floating-brand{flex:0 1 auto;color:#273b66;font-size:13px;font-weight:700}.card-status{flex-shrink:0;min-width:0;max-width:100%;overflow:hidden;margin-left:auto;padding:1px 7px;border:1px solid transparent;border-radius:5px;font:inherit;font-size:11px;line-height:20px;text-overflow:ellipsis;white-space:nowrap;cursor:pointer}.card-status:hover{filter:brightness(.97)}.card-status:focus-visible{outline:2px solid #3b82f6;outline-offset:2px}.card-status-valid{border-color:#dbe6fc;background:#edf3ff;color:#365ca3}.card-status-warning{border-color:#f6e0ad;background:#fff8e8;color:#98620c}.floating-modal .minimize-button{flex-shrink:0;width:24px;height:24px;padding:0;border-radius:5px;color:#64748b}.floating-modal .is-minimized .ant-modal-header{border-bottom:0}.notice-wrapper{overflow-wrap:anywhere}.notice-wrapper:empty{display:none}.notice-wrapper *,.log-message *,.answer-question *,.answer-value *{max-width:100%;overflow-wrap:anywhere}.notice-wrapper img,.log-message img,.answer-question img,.answer-value img{max-width:100%;height:auto;vertical-align:middle}.notice-wrapper pre,.log-message pre,.answer-question pre,.answer-value pre{white-space:pre-wrap}.floating-tabs.ant-tabs{min-width:0;margin-top:3px;font-size:12px}.floating-tabs>.ant-tabs-nav{margin-bottom:8px}.floating-tabs.ant-tabs-small>.ant-tabs-nav .ant-tabs-tab{padding:7px 0;font-size:12px}.floating-tabs .ant-tabs-tab+.ant-tabs-tab{margin-left:22px}.floating-tabs .ant-tabs-tabpane,.floating-tabs .ant-tabs-content-holder{min-width:0}.log-viewer,.answer-viewer{max-height:252px;overflow-x:hidden;overflow-y:auto;overscroll-behavior:contain;overflow-wrap:anywhere}.log-item{padding:4px 5px;border-bottom:1px solid #f0f3f8;line-height:1.65}.log-item:last-child{border-bottom:0}.log-time{margin-right:5px;color:#94a3b8;font-size:10px;font-variant-numeric:tabular-nums}.log-icon{margin-right:4px;font-size:11px}.log-message{word-break:break-word}.log-message p{display:inline;margin:0}.empty-message{padding:25px 8px;color:#94a3b8;text-align:center}.answer-item{margin-bottom:7px;padding:8px;border:1px solid #e9edf4;border-radius:7px;background:#f8fafc}.answer-item:last-child{margin-bottom:0}.answer-number{margin-bottom:4px;color:#64748b;font-size:11px}.answer-question,.answer-value{margin-top:3px;overflow-wrap:anywhere}.answer-value{margin-top:6px;padding-top:5px;border-top:1px solid #e9edf4}.answer-item .label{color:#64748b}.answer-question p,.answer-value p{display:inline;margin:2px 0}.settings-panel{min-width:0}.settings-section{margin-bottom:8px;padding:9px;border:1px solid #e9edf4;border-radius:7px;background:#f8fafc}.settings-heading{margin:0 0 7px;padding-bottom:5px;border-bottom:1px solid #e6ebf2;color:#3e5277;font-size:12px;font-weight:600}.setting-row{display:grid;grid-template-columns:minmax(0,1fr) 80px;align-items:center;gap:6px;margin-bottom:6px}.setting-row:last-child{margin-bottom:0}.setting-label{min-width:0;overflow-wrap:anywhere;line-height:1.5}.setting-row .setting-control{width:80px}.setting-row>.ant-checkbox-wrapper{grid-column:1 / -1;margin:0;font-size:12px;line-height:1.6}.setting-row .ant-checkbox+span{padding-right:0}.settings-panel .ant-select,.settings-panel .ant-input,.settings-panel .ant-input-number,.settings-panel .ant-input-group-addon,.settings-panel .ant-btn{font-size:12px}.setting-token{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:center;gap:8px;min-width:0;margin-bottom:8px}.setting-token-label{margin-bottom:0;white-space:nowrap}.setting-token .ant-input-password{width:100%;min-width:0}.required-marker{margin-right:4px;color:#ff4d4f}.settings-actions{display:flex;justify-content:center;padding:2px 0 4px}.project-footer{margin-top:8px;padding-top:7px;border-top:1px solid #edf0f5;font-size:10px;text-align:center;overflow-wrap:anywhere}.project-footer a{color:#7a8aab;text-decoration:none}.project-footer a:hover{color:#365ca3}.floating-modal ::-webkit-scrollbar{width:5px;height:5px}.floating-modal ::-webkit-scrollbar-thumb{border-radius:6px;background:#cbd5e1}.floating-modal ::-webkit-scrollbar-track{background:transparent}.floating-modal,.floating-modal *{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji"}.floating-modal .ant-modal{color:#000000d9;font-size:13px;line-height:1.5715}.floating-modal .ant-modal-content{border:0;border-radius:2px;box-shadow:0 3px 6px -4px #0000001f,0 6px 16px #00000014,0 9px 28px 8px #0000000d}.floating-modal .ant-modal-header{padding:12px 14px;border-bottom:1px solid #f0f0f0;background:#fff}.floating-modal .ant-modal-body{padding:12px 14px;color:#000000d9;font-size:13px;line-height:1.5715}.floating-brand{display:flex;flex:1 1 auto;align-items:center;gap:7px;min-width:0;overflow:hidden;line-height:24px;color:#000000d9;font-size:13px;font-weight:400;white-space:nowrap;text-overflow:ellipsis}.brand-mark{display:inline-flex;flex:0 0 20px;align-items:center;justify-content:center;width:20px;height:20px;border-radius:6px;background:linear-gradient(135deg,#1677ff,#69b1ff);box-shadow:0 2px 6px #1677ff3d}.brand-mark{color:#fff;font-size:12px;font-weight:700;line-height:1}.brand-copy{display:flex;min-width:0;align-items:baseline;gap:5px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.brand-name{flex:0 0 auto;color:#1f2937;font-weight:600;letter-spacing:.1px}.brand-subtitle{min-width:0;overflow:hidden;color:#6b7280;font-size:12px;font-weight:400;text-overflow:ellipsis}.card-status{border-color:var(--status-border, transparent);background:var(--status-background, transparent);color:var(--status-color, rgba(0, 0, 0, .65));font-size:11px;font-weight:400;border-radius:4px;padding:2px 5px}.card-status[data-state=valid]{--status-color: #389e0d;--status-background: #f6ffed;--status-border: #d9f7be}.card-status[data-state=invalid]{--status-color: #cf1322;--status-background: #fff1f0;--status-border: #ffccc7}.card-status[data-state=exhausted],.card-status[data-state=checking]{--status-color: #ad6800;--status-background: #fffbe6;--status-border: #ffe58f}.card-status[data-state=error]{--status-color: #d46b08;--status-background: #fff7e6;--status-border: #ffd591}.card-status:hover,.card-status:active{border-color:var(--status-border, #e8e8e8);background:var(--status-background, #f5f5f5);color:var(--status-color, rgba(0,0,0,.75));filter:none}.card-status:focus-visible{outline:1px solid #8c8c8c;outline-offset:2px}.card-status-icon{margin-right:3px;vertical-align:-1px}.floating-modal .minimize-button{color:#00000073}.floating-modal .minimize-button:hover{color:#1890ff;background:transparent}.floating-modal .is-minimized .floating-brand{flex:0 0 20px}.floating-modal .is-minimized .brand-copy{display:none}.notice-wrapper{display:block;margin:0 0 2px;padding:0 0 6px;border:0;background:transparent;color:#0000008c;font-size:12px;line-height:20px;overflow-wrap:anywhere}.notice-content{min-width:0;max-height:72px;overflow:auto;overscroll-behavior:contain;overflow-wrap:anywhere;outline:0}.notice-content:focus-visible{border-radius:2px;box-shadow:0 0 0 2px #1890ff2e}.notice-content,.notice-content *{font-size:12px!important;line-height:20px!important}.notice-content p,.notice-content ul,.notice-content ol,.notice-content blockquote,.notice-content pre{margin:0 0 4px}.notice-content>:first-child{margin-top:0!important}.notice-content>:last-child{margin-bottom:0!important}.floating-tabs.ant-tabs{margin-top:0;font-size:13px}.floating-tabs.ant-tabs-small>.ant-tabs-nav .ant-tabs-tab{padding:7px 0;font-size:13px}.floating-tabs .ant-tabs-tab+.ant-tabs-tab{margin-left:24px}.floating-tabs .ant-tabs-tab:hover{color:#1890ff}.floating-tabs .ant-tabs-ink-bar{background:#1890ff}.log-item{padding:4px 5px;color:#000000a6}.log-time{color:#00000073;font-size:12px}.log-message{color:#000000d9}.empty-message{color:#00000073;font-size:13px}.answer-item,.settings-section{border-color:#f0f0f0;border-radius:2px;background:#fff;box-shadow:none}.answer-item{padding:10px}.answer-item .label,.answer-number,.setting-label{color:#000000a6}.answer-value{border-top-color:#f0f0f0}.settings-section{margin-bottom:10px;padding:12px}.settings-heading{margin-bottom:10px;padding-bottom:8px;border-bottom-color:#f0f0f0;color:#000000d9;font-size:13px;font-weight:500}.setting-row{gap:8px;margin-bottom:8px}.setting-label,.setting-row>.ant-checkbox-wrapper,.setting-token-label{font-size:13px;line-height:1.5715}.setting-token{gap:5px 10px;margin-bottom:12px}.setting-token-label{color:#000000a6;font-size:12px}.setting-token-hint{grid-column:2;font-size:10px;line-height:1.5;color:#0006}.setting-token .ant-input-affix-wrapper{min-height:30px;padding:4px 8px;border-radius:4px;background:#fafafa;border-color:#e0e0e0}.setting-token .ant-input-affix-wrapper:hover{border-color:#bfbfbf}.setting-token .ant-input-affix-wrapper-focused{border-color:#91b9e5;background:#fff;box-shadow:0 0 0 2px #1890ff0d}.setting-token .ant-input-affix-wrapper .ant-input{background:transparent;font-size:12px}.setting-token .ant-input-prefix{margin-right:7px}.token-key-icon{color:#b0b0b0;font-size:12px}.settings-panel .ant-input,.settings-panel .ant-input-number,.settings-panel .ant-input-group-addon,.settings-panel .ant-select,.settings-panel .ant-btn{font-size:13px}.settings-panel .ant-btn-primary{border-radius:2px;background:#1890ff;box-shadow:none}.settings-panel .ant-btn-primary:hover{background:#40a9ff}.project-footer{border-top-color:#f0f0f0;font-size:12px}.project-footer a{color:#00000073}.project-footer a:hover{color:#1890ff}';
function bound01(n, max) {
if (isOnePointZero(n)) {
n = "100%";
}
var isPercent = isPercentage(n);
n = max === 360 ? n : Math.min(max, Math.max(0, parseFloat(n)));
if (isPercent) {
n = parseInt(String(n * max), 10) / 100;
}
if (Math.abs(n - max) < 1e-6) {
return 1;
}
if (max === 360) {
n = (n < 0 ? n % max + max : n % max) / parseFloat(String(max));
} else {
n = n % max / parseFloat(String(max));
}
return n;
}
function isOnePointZero(n) {
return typeof n === "string" && n.indexOf(".") !== -1 && parseFloat(n) === 1;
}
function isPercentage(n) {
return typeof n === "string" && n.indexOf("%") !== -1;
}
function boundAlpha(a) {
a = parseFloat(a);
if (isNaN(a) || a < 0 || a > 1) {
a = 1;
}
return a;
}
function convertToPercentage(n) {
if (n <= 1) {
return "".concat(Number(n) * 100, "%");
}
return n;
}
function pad2(c) {
return c.length === 1 ? "0" + c : String(c);
}
function rgbToRgb(r, g, b) {
return {
r: bound01(r, 255) * 255,
g: bound01(g, 255) * 255,
b: bound01(b, 255) * 255
};
}
function hue2rgb(p, q, t) {
if (t < 0) {
t += 1;
}
if (t > 1) {
t -= 1;
}
if (t < 1 / 6) {
return p + (q - p) * (6 * t);
}
if (t < 1 / 2) {
return q;
}
if (t < 2 / 3) {
return p + (q - p) * (2 / 3 - t) * 6;
}
return p;
}
function hslToRgb(h2, s, l) {
var r;
var g;
var b;
h2 = bound01(h2, 360);
s = bound01(s, 100);
l = bound01(l, 100);
if (s === 0) {
g = l;
b = l;
r = l;
} else {
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = hue2rgb(p, q, h2 + 1 / 3);
g = hue2rgb(p, q, h2);
b = hue2rgb(p, q, h2 - 1 / 3);
}
return { r: r * 255, g: g * 255, b: b * 255 };
}
function rgbToHsv(r, g, b) {
r = bound01(r, 255);
g = bound01(g, 255);
b = bound01(b, 255);
var max = Math.max(r, g, b);
var min = Math.min(r, g, b);
var h2 = 0;
var v = max;
var d = max - min;
var s = max === 0 ? 0 : d / max;
if (max === min) {
h2 = 0;
} else {
switch (max) {
case r:
h2 = (g - b) / d + (g < b ? 6 : 0);
break;
case g:
h2 = (b - r) / d + 2;
break;
case b:
h2 = (r - g) / d + 4;
break;
}
h2 /= 6;
}
return { h: h2, s, v };
}
function hsvToRgb(h2, s, v) {
h2 = bound01(h2, 360) * 6;
s = bound01(s, 100);
v = bound01(v, 100);
var i = Math.floor(h2);
var f = h2 - i;
var p = v * (1 - s);
var q = v * (1 - f * s);
var t = v * (1 - (1 - f) * s);
var mod = i % 6;
var r = [v, q, p, p, t, v][mod];
var g = [t, v, v, q, p, p][mod];
var b = [p, p, t, v, v, q][mod];
return { r: r * 255, g: g * 255, b: b * 255 };
}
function rgbToHex(r, g, b, allow3Char) {
var hex = [
pad2(Math.round(r).toString(16)),
pad2(Math.round(g).toString(16)),
pad2(Math.round(b).toString(16))
];
return hex.join("");
}
function convertHexToDecimal(h2) {
return parseIntFromHex(h2) / 255;
}
function parseIntFromHex(val) {
return parseInt(val, 16);
}
var names = {
aliceblue: "#f0f8ff",
antiquewhite: "#faebd7",
aqua: "#00ffff",
aquamarine: "#7fffd4",
azure: "#f0ffff",
beige: "#f5f5dc",
bisque: "#ffe4c4",
black: "#000000",
blanchedalmond: "#ffebcd",
blue: "#0000ff",
blueviolet: "#8a2be2",
brown: "#a52a2a",
burlywood: "#deb887",
cadetblue: "#5f9ea0",
chartreuse: "#7fff00",
chocolate: "#d2691e",
coral: "#ff7f50",
cornflowerblue: "#6495ed",
cornsilk: "#fff8dc",
crimson: "#dc143c",
cyan: "#00ffff",
darkblue: "#00008b",
darkcyan: "#008b8b",
darkgoldenrod: "#b8860b",
darkgray: "#a9a9a9",
darkgreen: "#006400",
darkgrey: "#a9a9a9",
darkkhaki: "#bdb76b",
darkmagenta: "#8b008b",
darkolivegreen: "#556b2f",
darkorange: "#ff8c00",
darkorchid: "#9932cc",
darkred: "#8b0000",
darksalmon: "#e9967a",
darkseagreen: "#8fbc8f",
darkslateblue: "#483d8b",
darkslategray: "#2f4f4f",
darkslategrey: "#2f4f4f",
darkturquoise: "#00ced1",
darkviolet: "#9400d3",
deeppink: "#ff1493",
deepskyblue: "#00bfff",
dimgray: "#696969",
dimgrey: "#696969",
dodgerblue: "#1e90ff",
firebrick: "#b22222",
floralwhite: "#fffaf0",
forestgreen: "#228b22",
fuchsia: "#ff00ff",
gainsboro: "#dcdcdc",
ghostwhite: "#f8f8ff",
goldenrod: "#daa520",
gold: "#ffd700",
gray: "#808080",
green: "#008000",
greenyellow: "#adff2f",
grey: "#808080",
honeydew: "#f0fff0",
hotpink: "#ff69b4",
indianred: "#cd5c5c",
indigo: "#4b0082",
ivory: "#fffff0",
khaki: "#f0e68c",
lavenderblush: "#fff0f5",
lavender: "#e6e6fa",
lawngreen: "#7cfc00",
lemonchiffon: "#fffacd",
lightblue: "#add8e6",
lightcoral: "#f08080",
lightcyan: "#e0ffff",
lightgoldenrodyellow: "#fafad2",
lightgray: "#d3d3d3",
lightgreen: "#90ee90",
lightgrey: "#d3d3d3",
lightpink: "#ffb6c1",
lightsalmon: "#ffa07a",
lightseagreen: "#20b2aa",
lightskyblue: "#87cefa",
lightslategray: "#778899",
lightslategrey: "#778899",
lightsteelblue: "#b0c4de",
lightyellow: "#ffffe0",
lime: "#00ff00",
limegreen: "#32cd32",
linen: "#faf0e6",
magenta: "#ff00ff",
maroon: "#800000",
mediumaquamarine: "#66cdaa",
mediumblue: "#0000cd",
mediumorchid: "#ba55d3",
mediumpurple: "#9370db",
mediumseagreen: "#3cb371",
mediumslateblue: "#7b68ee",
mediumspringgreen: "#00fa9a",
mediumturquoise: "#48d1cc",
mediumvioletred: "#c71585",
midnightblue: "#191970",
mintcream: "#f5fffa",
mistyrose: "#ffe4e1",
moccasin: "#ffe4b5",
navajowhite: "#ffdead",
navy: "#000080",
oldlace: "#fdf5e6",
olive: "#808000",
olivedrab: "#6b8e23",
orange: "#ffa500",
orangered: "#ff4500",
orchid: "#da70d6",
palegoldenrod: "#eee8aa",
palegreen: "#98fb98",
paleturquoise: "#afeeee",
palevioletred: "#db7093",
papayawhip: "#ffefd5",
peachpuff: "#ffdab9",
peru: "#cd853f",
pink: "#ffc0cb",
plum: "#dda0dd",
powderblue: "#b0e0e6",
purple: "#800080",
rebeccapurple: "#663399",
red: "#ff0000",
rosybrown: "#bc8f8f",
royalblue: "#4169e1",
saddlebrown: "#8b4513",
salmon: "#fa8072",
sandybrown: "#f4a460",
seagreen: "#2e8b57",
seashell: "#fff5ee",
sienna: "#a0522d",
silver: "#c0c0c0",
skyblue: "#87ceeb",
slateblue: "#6a5acd",
slategray: "#708090",
slategrey: "#708090",
snow: "#fffafa",
springgreen: "#00ff7f",
steelblue: "#4682b4",
tan: "#d2b48c",
teal: "#008080",
thistle: "#d8bfd8",
tomato: "#ff6347",
turquoise: "#40e0d0",
violet: "#ee82ee",
wheat: "#f5deb3",
white: "#ffffff",
whitesmoke: "#f5f5f5",
yellow: "#ffff00",
yellowgreen: "#9acd32"
};
function inputToRGB(color) {
var rgb = { r: 0, g: 0, b: 0 };
var a = 1;
var s = null;
var v = null;
var l = null;
var ok = false;
var format = false;
if (typeof color === "string") {
color = stringInputToObject(color);
}
if (typeof color === "object") {
if (isValidCSSUnit(color.r) && isValidCSSUnit(color.g) && isValidCSSUnit(color.b)) {
rgb = rgbToRgb(color.r, color.g, color.b);
ok = true;
format = String(color.r).substr(-1) === "%" ? "prgb" : "rgb";
} else if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.v)) {
s = convertToPercentage(color.s);
v = convertToPercentage(color.v);
rgb = hsvToRgb(color.h, s, v);
ok = true;
format = "hsv";
} else if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.l)) {
s = convertToPercentage(color.s);
l = convertToPercentage(color.l);
rgb = hslToRgb(color.h, s, l);
ok = true;
format = "hsl";
}
if (Object.prototype.hasOwnProperty.call(color, "a")) {
a = color.a;
}
}
a = boundAlpha(a);
return {
ok,
format: color.format || format,
r: Math.min(255, Math.max(rgb.r, 0)),
g: Math.min(255, Math.max(rgb.g, 0)),
b: Math.min(255, Math.max(rgb.b, 0)),
a
};
}
var CSS_INTEGER = "[-\\+]?\\d+%?";
var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?";
var CSS_UNIT = "(?:".concat(CSS_NUMBER, ")|(?:").concat(CSS_INTEGER, ")");
var PERMISSIVE_MATCH3 = "[\\s|\\(]+(".concat(CSS_UNIT, ")[,|\\s]+(").concat(CSS_UNIT, ")[,|\\s]+(").concat(CSS_UNIT, ")\\s*\\)?");
var PERMISSIVE_MATCH4 = "[\\s|\\(]+(".concat(CSS_UNIT, ")[,|\\s]+(").concat(CSS_UNIT, ")[,|\\s]+(").concat(CSS_UNIT, ")[,|\\s]+(").concat(CSS_UNIT, ")\\s*\\)?");
var matchers = {
CSS_UNIT: new RegExp(CSS_UNIT),
rgb: new RegExp("rgb" + PERMISSIVE_MATCH3),
rgba: new RegExp("rgba" + PERMISSIVE_MATCH4),
hsl: new RegExp("hsl" + PERMISSIVE_MATCH3),
hsla: new RegExp("hsla" + PERMISSIVE_MATCH4),
hsv: new RegExp("hsv" + PERMISSIVE_MATCH3),
hsva: new RegExp("hsva" + PERMISSIVE_MATCH4),
hex3: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
hex6: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,
hex4: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
hex8: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/
};
function stringInputToObject(color) {
color = color.trim().toLowerCase();
if (color.length === 0) {
return false;
}
var named = false;
if (names[color]) {
color = names[color];
named = true;
} else if (color === "transparent") {
return { r: 0, g: 0, b: 0, a: 0, format: "name" };
}
var match = matchers.rgb.exec(color);
if (match) {
return { r: match[1], g: match[2], b: match[3] };
}
match = matchers.rgba.exec(color);
if (match) {
return { r: match[1], g: match[2], b: match[3], a: match[4] };
}
match = matchers.hsl.exec(color);
if (match) {
return { h: match[1], s: match[2], l: match[3] };
}
match = matchers.hsla.exec(color);
if (match) {
return { h: match[1], s: match[2], l: match[3], a: match[4] };
}
match = matchers.hsv.exec(color);
if (match) {
return { h: match[1], s: match[2], v: match[3] };
}
match = matchers.hsva.exec(color);
if (match) {
return { h: match[1], s: match[2], v: match[3], a: match[4] };
}
match = matchers.hex8.exec(color);
if (match) {
return {
r: parseIntFromHex(match[1]),
g: parseIntFromHex(match[2]),
b: parseIntFromHex(match[3]),
a: convertHexToDecimal(match[4]),
format: named ? "name" : "hex8"
};
}
match = matchers.hex6.exec(color);
if (match) {
return {
r: parseIntFromHex(match[1]),
g: parseIntFromHex(match[2]),
b: parseIntFromHex(match[3]),
format: named ? "name" : "hex"
};
}
match = matchers.hex4.exec(color);
if (match) {
return {
r: parseIntFromHex(match[1] + match[1]),
g: parseIntFromHex(match[2] + match[2]),
b: parseIntFromHex(match[3] + match[3]),
a: convertHexToDecimal(match[4] + match[4]),
format: named ? "name" : "hex8"
};
}
match = matchers.hex3.exec(color);
if (match) {
return {
r: parseIntFromHex(match[1] + match[1]),
g: parseIntFromHex(match[2] + match[2]),
b: parseIntFromHex(match[3] + match[3]),
format: named ? "name" : "hex"
};
}
return false;
}
function isValidCSSUnit(color) {
return Boolean(matchers.CSS_UNIT.exec(String(color)));
}
var hueStep = 2;
var saturationStep = 0.16;
var saturationStep2 = 0.05;
var brightnessStep1 = 0.05;
var brightnessStep2 = 0.15;
var lightColorCount = 5;
var darkColorCount = 4;
var darkColorMap = [{
index: 7,
opacity: 0.15
}, {
index: 6,
opacity: 0.25
}, {
index: 5,
opacity: 0.3
}, {
index: 5,
opacity: 0.45
}, {
index: 5,
opacity: 0.65
}, {
index: 5,
opacity: 0.85
}, {
index: 4,
opacity: 0.9
}, {
index: 3,
opacity: 0.95
}, {
index: 2,
opacity: 0.97
}, {
index: 1,
opacity: 0.98
}];
function toHsv(_ref) {
var r = _ref.r, g = _ref.g, b = _ref.b;
var hsv = rgbToHsv(r, g, b);
return {
h: hsv.h * 360,
s: hsv.s,
v: hsv.v
};
}
function toHex(_ref2) {
var r = _ref2.r, g = _ref2.g, b = _ref2.b;
return "#".concat(rgbToHex(r, g, b));
}
function mix(rgb1, rgb2, amount) {
var p = amount / 100;
var rgb = {
r: (rgb2.r - rgb1.r) * p + rgb1.r,
g: (rgb2.g - rgb1.g) * p + rgb1.g,
b: (rgb2.b - rgb1.b) * p + rgb1.b
};
return rgb;
}
function getHue(hsv, i, light) {
var hue;
if (Math.round(hsv.h) >= 60 && Math.round(hsv.h) <= 240) {
hue = light ? Math.round(hsv.h) - hueStep * i : Math.round(hsv.h) + hueStep * i;
} else {
hue = light ? Math.round(hsv.h) + hueStep * i : Math.round(hsv.h) - hueStep * i;
}
if (hue < 0) {
hue += 360;
} else if (hue >= 360) {
hue -= 360;
}
return hue;
}
function getSaturation(hsv, i, light) {
if (hsv.h === 0 && hsv.s === 0) {
return hsv.s;
}
var saturation;
if (light) {
saturation = hsv.s - saturationStep * i;
} else if (i === darkColorCount) {
saturation = hsv.s + saturationStep;
} else {
saturation = hsv.s + saturationStep2 * i;
}
if (saturation > 1) {
saturation = 1;
}
if (light && i === lightColorCount && saturation > 0.1) {
saturation = 0.1;
}
if (saturation < 0.06) {
saturation = 0.06;
}
return Number(saturation.toFixed(2));
}
function getValue$1(hsv, i, light) {
var value;
if (light) {
value = hsv.v + brightnessStep1 * i;
} else {
value = hsv.v - brightnessStep2 * i;
}
if (value > 1) {
value = 1;
}
return Number(value.toFixed(2));
}
function generate$1(color) {
var opts = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
var patterns = [];
var pColor = inputToRGB(color);
for (var i = lightColorCount; i > 0; i -= 1) {
var hsv = toHsv(pColor);
var colorString = toHex(inputToRGB({
h: getHue(hsv, i, true),
s: getSaturation(hsv, i, true),
v: getValue$1(hsv, i, true)
}));
patterns.push(colorString);
}
patterns.push(toHex(pColor));
for (var _i = 1; _i <= darkColorCount; _i += 1) {
var _hsv = toHsv(pColor);
var _colorString = toHex(inputToRGB({
h: getHue(_hsv, _i),
s: getSaturation(_hsv, _i),
v: getValue$1(_hsv, _i)
}));
patterns.push(_colorString);
}
if (opts.theme === "dark") {
return darkColorMap.map(function(_ref3) {
var index = _ref3.index, opacity = _ref3.opacity;
var darkColorString = toHex(mix(inputToRGB(opts.backgroundColor || "#141414"), inputToRGB(patterns[index]), opacity * 100));
return darkColorString;
});
}
return patterns;
}
var presetPrimaryColors = {
red: "#F5222D",
volcano: "#FA541C",
orange: "#FA8C16",
gold: "#FAAD14",
yellow: "#FADB14",
lime: "#A0D911",
green: "#52C41A",
cyan: "#13C2C2",
blue: "#1890FF",
geekblue: "#2F54EB",
purple: "#722ED1",
magenta: "#EB2F96",
grey: "#666666"
};
var presetPalettes = {};
var presetDarkPalettes = {};
Object.keys(presetPrimaryColors).forEach(function(key) {
presetPalettes[key] = generate$1(presetPrimaryColors[key]);
presetPalettes[key].primary = presetPalettes[key][5];
presetDarkPalettes[key] = generate$1(presetPrimaryColors[key], {
theme: "dark",
backgroundColor: "#141414"
});
presetDarkPalettes[key].primary = presetDarkPalettes[key][5];
});
var blue = presetPalettes.blue;
var contextKey = Symbol("iconContext");
var useInjectIconContext = function useInjectIconContext2() {
return vue.inject(contextKey, {
prefixCls: vue.ref("anticon"),
rootClassName: vue.ref(""),
csp: vue.ref()
});
};
function canUseDom() {
return !!(typeof window !== "undefined" && window.document && window.document.createElement);
}
function contains(root, n) {
if (!root) {
return false;
}
if (root.contains) {
return root.contains(n);
}
return false;
}
var APPEND_ORDER = "data-vc-order";
var MARK_KEY = "vc-icon-key";
var containerCache = /* @__PURE__ */ new Map();
function getMark() {
var _ref = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {}, mark = _ref.mark;
if (mark) {
return mark.startsWith("data-") ? mark : "data-".concat(mark);
}
return MARK_KEY;
}
function getContainer(option) {
if (option.attachTo) {
return option.attachTo;
}
var head = document.querySelector("head");
return head || document.body;
}
function getOrder(prepend) {
if (prepend === "queue") {
return "prependQueue";
}
return prepend ? "prepend" : "append";
}
function findStyles(container) {
return Array.from((containerCache.get(container) || container).children).filter(function(node) {
return node.tagName === "STYLE";
});
}
function injectCSS(css) {
var option = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
if (!canUseDom()) {
return null;
}
var csp = option.csp, prepend = option.prepend;
var styleNode = document.createElement("style");
styleNode.setAttribute(APPEND_ORDER, getOrder(prepend));
if (csp && csp.nonce) {
styleNode.nonce = csp.nonce;
}
styleNode.innerHTML = css;
var container = getContainer(option);
var firstChild = container.firstChild;
if (prepend) {
if (prepend === "queue") {
var existStyle = findStyles(container).filter(function(node) {
return ["prepend", "prependQueue"].includes(node.getAttribute(APPEND_ORDER));
});
if (existStyle.length) {
container.insertBefore(styleNode, existStyle[existStyle.length - 1].nextSibling);
return styleNode;
}
}
container.insertBefore(styleNode, firstChild);
} else {
container.appendChild(styleNode);
}
return styleNode;
}
function findExistNode(key) {
var option = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
var container = getContainer(option);
return findStyles(container).find(function(node) {
return node.getAttribute(getMark(option)) === key;
});
}
function syncRealContainer(container, option) {
var cachedRealContainer = containerCache.get(container);
if (!cachedRealContainer || !contains(document, cachedRealContainer)) {
var placeholderStyle = injectCSS("", option);
var parentNode = placeholderStyle.parentNode;
containerCache.set(container, parentNode);
container.removeChild(placeholderStyle);
}
}
function updateCSS(css, key) {
var option = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : {};
var container = getContainer(option);
syncRealContainer(container, option);
var existNode = findExistNode(key, option);
if (existNode) {
if (option.csp && option.csp.nonce && existNode.nonce !== option.csp.nonce) {
existNode.nonce = option.csp.nonce;
}
if (existNode.innerHTML !== css) {
existNode.innerHTML = css;
}
return existNode;
}
var newNode = injectCSS(css, option);
newNode.setAttribute(getMark(option), key);
return newNode;
}
function _objectSpread$8(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? Object(arguments[i]) : {};
var ownKeys = Object.keys(source);
if (typeof Object.getOwnPropertySymbols === "function") {
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
}));
}
ownKeys.forEach(function(key) {
_defineProperty$8(target, key, source[key]);
});
}
return target;
}
function _defineProperty$8(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, { value, enumerable: true, configurable: true, writable: true });
} else {
obj[key] = value;
}
return obj;
}
function warning(valid, message) {
}
function isIconDefinition(target) {
return typeof target === "object" && typeof target.name === "string" && typeof target.theme === "string" && (typeof target.icon === "object" || typeof target.icon === "function");
}
function generate(node, key, rootProps) {
if (!rootProps) {
return vue.h(node.tag, _objectSpread$8({
key
}, node.attrs), (node.children || []).map(function(child, index) {
return generate(child, "".concat(key, "-").concat(node.tag, "-").concat(index));
}));
}
return vue.h(node.tag, _objectSpread$8({
key
}, rootProps, node.attrs), (node.children || []).map(function(child, index) {
return generate(child, "".concat(key, "-").concat(node.tag, "-").concat(index));
}));
}
function getSecondaryColor(primaryColor) {
return generate$1(primaryColor)[0];
}
function normalizeTwoToneColors(twoToneColor) {
if (!twoToneColor) {
return [];
}
return Array.isArray(twoToneColor) ? twoToneColor : [twoToneColor];
}
var iconStyles = "\n.anticon {\n display: inline-block;\n color: inherit;\n font-style: normal;\n line-height: 0;\n text-align: center;\n text-transform: none;\n vertical-align: -0.125em;\n text-rendering: optimizeLegibility;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n.anticon > * {\n line-height: 1;\n}\n\n.anticon svg {\n display: inline-block;\n}\n\n.anticon::before {\n display: none;\n}\n\n.anticon .anticon-icon {\n display: block;\n}\n\n.anticon[tabindex] {\n cursor: pointer;\n}\n\n.anticon-spin::before,\n.anticon-spin {\n display: inline-block;\n -webkit-animation: loadingCircle 1s infinite linear;\n animation: loadingCircle 1s infinite linear;\n}\n\n@-webkit-keyframes loadingCircle {\n 100% {\n -webkit-transform: rotate(360deg);\n transform: rotate(360deg);\n }\n}\n\n@keyframes loadingCircle {\n 100% {\n -webkit-transform: rotate(360deg);\n transform: rotate(360deg);\n }\n}\n";
function getRoot(ele) {
return ele && ele.getRootNode && ele.getRootNode();
}
function inShadow(ele) {
if (!canUseDom()) {
return false;
}
return getRoot(ele) instanceof ShadowRoot;
}
function getShadowRoot(ele) {
return inShadow(ele) ? getRoot(ele) : null;
}
var useInsertStyles = function useInsertStyles2() {
var _useInjectIconContext = useInjectIconContext(), prefixCls = _useInjectIconContext.prefixCls, csp = _useInjectIconContext.csp;
var instance = vue.getCurrentInstance();
var mergedStyleStr = iconStyles;
if (prefixCls) {
mergedStyleStr = mergedStyleStr.replace(/anticon/g, prefixCls.value);
}
vue.nextTick(function() {
if (!canUseDom()) {
return;
}
var ele = instance.vnode.el;
var shadowRoot = getShadowRoot(ele);
updateCSS(mergedStyleStr, "@ant-design-vue-icons", {
prepend: true,
csp: csp.value,
attachTo: shadowRoot
});
});
};
var _excluded$1 = ["icon", "primaryColor", "secondaryColor"];
function _objectWithoutProperties$1(source, excluded) {
if (source == null) return {};
var target = _objectWithoutPropertiesLoose$1(source, excluded);
var key, i;
if (Object.getOwnPropertySymbols) {
var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
for (i = 0; i < sourceSymbolKeys.length; i++) {
key = sourceSymbolKeys[i];
if (excluded.indexOf(key) >= 0) continue;
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
target[key] = source[key];
}
}
return target;
}
function _objectWithoutPropertiesLoose$1(source, excluded) {
if (source == null) return {};
var target = {};
var sourceKeys = Object.keys(source);
var key, i;
for (i = 0; i < sourceKeys.length; i++) {
key = sourceKeys[i];
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
function _objectSpread$7(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? Object(arguments[i]) : {};
var ownKeys = Object.keys(source);
if (typeof Object.getOwnPropertySymbols === "function") {
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
}));
}
ownKeys.forEach(function(key) {
_defineProperty$7(target, key, source[key]);
});
}
return target;
}
function _defineProperty$7(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, { value, enumerable: true, configurable: true, writable: true });
} else {
obj[key] = value;
}
return obj;
}
var twoToneColorPalette = vue.reactive({
primaryColor: "#333",
secondaryColor: "#E6E6E6",
calculated: false
});
function setTwoToneColors(_ref) {
var primaryColor = _ref.primaryColor, secondaryColor = _ref.secondaryColor;
twoToneColorPalette.primaryColor = primaryColor;
twoToneColorPalette.secondaryColor = secondaryColor || getSecondaryColor(primaryColor);
twoToneColorPalette.calculated = !!secondaryColor;
}
function getTwoToneColors() {
return _objectSpread$7({}, twoToneColorPalette);
}
var IconBase = function IconBase2(props, context) {
var _props$context$attrs = _objectSpread$7({}, props, context.attrs), icon = _props$context$attrs.icon, primaryColor = _props$context$attrs.primaryColor, secondaryColor = _props$context$attrs.secondaryColor, restProps = _objectWithoutProperties$1(_props$context$attrs, _excluded$1);
var colors = twoToneColorPalette;
if (primaryColor) {
colors = {
primaryColor,
secondaryColor: secondaryColor || getSecondaryColor(primaryColor)
};
}
warning(isIconDefinition(icon));
if (!isIconDefinition(icon)) {
return null;
}
var target = icon;
if (target && typeof target.icon === "function") {
target = _objectSpread$7({}, target, {
icon: target.icon(colors.primaryColor, colors.secondaryColor)
});
}
return generate(target.icon, "svg-".concat(target.name), _objectSpread$7({}, restProps, {
"data-icon": target.name,
width: "1em",
height: "1em",
fill: "currentColor",
"aria-hidden": "true"
}));
};
IconBase.props = {
icon: Object,
primaryColor: String,
secondaryColor: String,
focusable: String
};
IconBase.inheritAttrs = false;
IconBase.displayName = "IconBase";
IconBase.getTwoToneColors = getTwoToneColors;
IconBase.setTwoToneColors = setTwoToneColors;
function _slicedToArray$1(arr, i) {
return _arrayWithHoles$1(arr) || _iterableToArrayLimit$1(arr, i) || _unsupportedIterableToArray$1(arr, i) || _nonIterableRest$1();
}
function _nonIterableRest$1() {
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _unsupportedIterableToArray$1(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray$1(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(o);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$1(o, minLen);
}
function _arrayLikeToArray$1(arr, len) {
if (len == null || len > arr.length) len = arr.length;
for (var i = 0, arr2 = new Array(len); i < len; i++) {
arr2[i] = arr[i];
}
return arr2;
}
function _iterableToArrayLimit$1(arr, i) {
var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
if (_i == null) return;
var _arr = [];
var _n = true;
var _d = false;
var _s, _e;
try {
for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) {
_arr.push(_s.value);
if (i && _arr.length === i) break;
}
} catch (err) {
_d = true;
_e = err;
} finally {
try {
if (!_n && _i["return"] != null) _i["return"]();
} finally {
if (_d) throw _e;
}
}
return _arr;
}
function _arrayWithHoles$1(arr) {
if (Array.isArray(arr)) return arr;
}
function setTwoToneColor(twoToneColor) {
var _normalizeTwoToneColo = normalizeTwoToneColors(twoToneColor), _normalizeTwoToneColo2 = _slicedToArray$1(_normalizeTwoToneColo, 2), primaryColor = _normalizeTwoToneColo2[0], secondaryColor = _normalizeTwoToneColo2[1];
return IconBase.setTwoToneColors({
primaryColor,
secondaryColor
});
}
function getTwoToneColor() {
var colors = IconBase.getTwoToneColors();
if (!colors.calculated) {
return colors.primaryColor;
}
return [colors.primaryColor, colors.secondaryColor];
}
var InsertStyles = vue.defineComponent({
name: "InsertStyles",
setup: function setup() {
useInsertStyles();
return function() {
return null;
};
}
});
var _excluded = ["class", "icon", "spin", "rotate", "tabindex", "twoToneColor", "onClick"];
function _slicedToArray(arr, i) {
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
}
function _nonIterableRest() {
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _unsupportedIterableToArray(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(o);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length) len = arr.length;
for (var i = 0, arr2 = new Array(len); i < len; i++) {
arr2[i] = arr[i];
}
return arr2;
}
function _iterableToArrayLimit(arr, i) {
var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
if (_i == null) return;
var _arr = [];
var _n = true;
var _d = false;
var _s, _e;
try {
for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) {
_arr.push(_s.value);
if (i && _arr.length === i) break;
}
} catch (err) {
_d = true;
_e = err;
} finally {
try {
if (!_n && _i["return"] != null) _i["return"]();
} finally {
if (_d) throw _e;
}
}
return _arr;
}
function _arrayWithHoles(arr) {
if (Array.isArray(arr)) return arr;
}
function _objectSpread$6(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? Object(arguments[i]) : {};
var ownKeys = Object.keys(source);
if (typeof Object.getOwnPropertySymbols === "function") {
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
}));
}
ownKeys.forEach(function(key) {
_defineProperty$6(target, key, source[key]);
});
}
return target;
}
function _defineProperty$6(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, { value, enumerable: true, configurable: true, writable: true });
} else {
obj[key] = value;
}
return obj;
}
function _objectWithoutProperties(source, excluded) {
if (source == null) return {};
var target = _objectWithoutPropertiesLoose(source, excluded);
var key, i;
if (Object.getOwnPropertySymbols) {
var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
for (i = 0; i < sourceSymbolKeys.length; i++) {
key = sourceSymbolKeys[i];
if (excluded.indexOf(key) >= 0) continue;
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
target[key] = source[key];
}
}
return target;
}
function _objectWithoutPropertiesLoose(source, excluded) {
if (source == null) return {};
var target = {};
var sourceKeys = Object.keys(source);
var key, i;
for (i = 0; i < sourceKeys.length; i++) {
key = sourceKeys[i];
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
setTwoToneColor(blue.primary);
var Icon = function Icon2(props, context) {
var _classObj;
var _props$context$attrs = _objectSpread$6({}, props, context.attrs), cls = _props$context$attrs["class"], icon = _props$context$attrs.icon, spin = _props$context$attrs.spin, rotate = _props$context$attrs.rotate, tabindex = _props$context$attrs.tabindex, twoToneColor = _props$context$attrs.twoToneColor, onClick = _props$context$attrs.onClick, restProps = _objectWithoutProperties(_props$context$attrs, _excluded);
var _useInjectIconContext = useInjectIconContext(), prefixCls = _useInjectIconContext.prefixCls, rootClassName = _useInjectIconContext.rootClassName;
var classObj = (_classObj = {}, _defineProperty$6(_classObj, rootClassName.value, !!rootClassName.value), _defineProperty$6(_classObj, prefixCls.value, true), _defineProperty$6(_classObj, "".concat(prefixCls.value, "-").concat(icon.name), Boolean(icon.name)), _defineProperty$6(_classObj, "".concat(prefixCls.value, "-spin"), !!spin || icon.name === "loading"), _classObj);
var iconTabIndex = tabindex;
if (iconTabIndex === void 0 && onClick) {
iconTabIndex = -1;
}
var svgStyle = rotate ? {
msTransform: "rotate(".concat(rotate, "deg)"),
transform: "rotate(".concat(rotate, "deg)")
} : void 0;
var _normalizeTwoToneColo = normalizeTwoToneColors(twoToneColor), _normalizeTwoToneColo2 = _slicedToArray(_normalizeTwoToneColo, 2), primaryColor = _normalizeTwoToneColo2[0], secondaryColor = _normalizeTwoToneColo2[1];
return vue.createVNode("span", _objectSpread$6({
"role": "img",
"aria-label": icon.name
}, restProps, {
"onClick": onClick,
"class": [classObj, cls],
"tabindex": iconTabIndex
}), [vue.createVNode(IconBase, {
"icon": icon,
"primaryColor": primaryColor,
"secondaryColor": secondaryColor,
"style": svgStyle
}, null), vue.createVNode(InsertStyles, null, null)]);
};
Icon.props = {
spin: Boolean,
rotate: Number,
icon: Object,
twoToneColor: [String, Array]
};
Icon.displayName = "AntdIcon";
Icon.inheritAttrs = false;
Icon.getTwoToneColor = getTwoToneColor;
Icon.setTwoToneColor = setTwoToneColor;
var CheckCircleFilled$1 = { "icon": { "tag": "svg", "attrs": { "viewBox": "64 64 896 896", "focusable": "false" }, "children": [{ "tag": "path", "attrs": { "d": "M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm193.5 301.7l-210.6 292a31.8 31.8 0 01-51.7 0L318.5 484.9c-3.8-5.3 0-12.7 6.5-12.7h46.9c10.2 0 19.9 4.9 25.9 13.3l71.2 98.8 157.2-218c6-8.3 15.6-13.3 25.9-13.3H699c6.5 0 10.3 7.4 6.5 12.7z" } }] }, "name": "check-circle", "theme": "filled" };
function _objectSpread$5(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? Object(arguments[i]) : {};
var ownKeys = Object.keys(source);
if (typeof Object.getOwnPropertySymbols === "function") {
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
}));
}
ownKeys.forEach(function(key) {
_defineProperty$5(target, key, source[key]);
});
}
return target;
}
function _defineProperty$5(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, { value, enumerable: true, configurable: true, writable: true });
} else {
obj[key] = value;
}
return obj;
}
var CheckCircleFilled = function CheckCircleFilled2(props, context) {
var p = _objectSpread$5({}, props, context.attrs);
return vue.createVNode(Icon, _objectSpread$5({}, p, {
"icon": CheckCircleFilled$1
}), null);
};
CheckCircleFilled.displayName = "CheckCircleFilled";
CheckCircleFilled.inheritAttrs = false;
var ExclamationCircleFilled$1 = { "icon": { "tag": "svg", "attrs": { "viewBox": "64 64 896 896", "focusable": "false" }, "children": [{ "tag": "path", "attrs": { "d": "M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm-32 232c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v272c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V296zm32 440a48.01 48.01 0 010-96 48.01 48.01 0 010 96z" } }] }, "name": "exclamation-circle", "theme": "filled" };
function _objectSpread$4(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? Object(arguments[i]) : {};
var ownKeys = Object.keys(source);
if (typeof Object.getOwnPropertySymbols === "function") {
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
}));
}
ownKeys.forEach(function(key) {
_defineProperty$4(target, key, source[key]);
});
}
return target;
}
function _defineProperty$4(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, { value, enumerable: true, configurable: true, writable: true });
} else {
obj[key] = value;
}
return obj;
}
var ExclamationCircleFilled = function ExclamationCircleFilled2(props, context) {
var p = _objectSpread$4({}, props, context.attrs);
return vue.createVNode(Icon, _objectSpread$4({}, p, {
"icon": ExclamationCircleFilled$1
}), null);
};
ExclamationCircleFilled.displayName = "ExclamationCircleFilled";
ExclamationCircleFilled.inheritAttrs = false;
var ExpandOutlined$1 = { "icon": { "tag": "svg", "attrs": { "viewBox": "64 64 896 896", "focusable": "false" }, "children": [{ "tag": "defs", "attrs": {}, "children": [{ "tag": "style", "attrs": {} }] }, { "tag": "path", "attrs": { "d": "M342 88H120c-17.7 0-32 14.3-32 32v224c0 8.8 7.2 16 16 16h48c8.8 0 16-7.2 16-16V168h174c8.8 0 16-7.2 16-16v-48c0-8.8-7.2-16-16-16zm578 576h-48c-8.8 0-16 7.2-16 16v176H682c-8.8 0-16 7.2-16 16v48c0 8.8 7.2 16 16 16h222c17.7 0 32-14.3 32-32V680c0-8.8-7.2-16-16-16zM342 856H168V680c0-8.8-7.2-16-16-16h-48c-8.8 0-16 7.2-16 16v224c0 17.7 14.3 32 32 32h222c8.8 0 16-7.2 16-16v-48c0-8.8-7.2-16-16-16zM904 88H682c-8.8 0-16 7.2-16 16v48c0 8.8 7.2 16 16 16h174v176c0 8.8 7.2 16 16 16h48c8.8 0 16-7.2 16-16V120c0-17.7-14.3-32-32-32z" } }] }, "name": "expand", "theme": "outlined" };
function _objectSpread$3(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? Object(arguments[i]) : {};
var ownKeys = Object.keys(source);
if (typeof Object.getOwnPropertySymbols === "function") {
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
}));
}
ownKeys.forEach(function(key) {
_defineProperty$3(target, key, source[key]);
});
}
return target;
}
function _defineProperty$3(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, { value, enumerable: true, configurable: true, writable: true });
} else {
obj[key] = value;
}
return obj;
}
var ExpandOutlined = function ExpandOutlined2(props, context) {
var p = _objectSpread$3({}, props, context.attrs);
return vue.createVNode(Icon, _objectSpread$3({}, p, {
"icon": ExpandOutlined$1
}), null);
};
ExpandOutlined.displayName = "ExpandOutlined";
ExpandOutlined.inheritAttrs = false;
var KeyOutlined$1 = { "icon": { "tag": "svg", "attrs": { "viewBox": "64 64 896 896", "focusable": "false" }, "children": [{ "tag": "path", "attrs": { "d": "M608 112c-167.9 0-304 136.1-304 304 0 70.3 23.9 135 63.9 186.5l-41.1 41.1-62.3-62.3a8.15 8.15 0 00-11.4 0l-39.8 39.8a8.15 8.15 0 000 11.4l62.3 62.3-44.9 44.9-62.3-62.3a8.15 8.15 0 00-11.4 0l-39.8 39.8a8.15 8.15 0 000 11.4l62.3 62.3-65.3 65.3a8.03 8.03 0 000 11.3l42.3 42.3c3.1 3.1 8.2 3.1 11.3 0l253.6-253.6A304.06 304.06 0 00608 720c167.9 0 304-136.1 304-304S775.9 112 608 112zm161.2 465.2C726.2 620.3 668.9 644 608 644c-60.9 0-118.2-23.7-161.2-66.8-43.1-43-66.8-100.3-66.8-161.2 0-60.9 23.7-118.2 66.8-161.2 43-43.1 100.3-66.8 161.2-66.8 60.9 0 118.2 23.7 161.2 66.8 43.1 43 66.8 100.3 66.8 161.2 0 60.9-23.7 118.2-66.8 161.2z" } }] }, "name": "key", "theme": "outlined" };
function _objectSpread$2(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? Object(arguments[i]) : {};
var ownKeys = Object.keys(source);
if (typeof Object.getOwnPropertySymbols === "function") {
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
}));
}
ownKeys.forEach(function(key) {
_defineProperty$2(target, key, source[key]);
});
}
return target;
}
function _defineProperty$2(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, { value, enumerable: true, configurable: true, writable: true });
} else {
obj[key] = value;
}
return obj;
}
var KeyOutlined = function KeyOutlined2(props, context) {
var p = _objectSpread$2({}, props, context.attrs);
return vue.createVNode(Icon, _objectSpread$2({}, p, {
"icon": KeyOutlined$1
}), null);
};
KeyOutlined.displayName = "KeyOutlined";
KeyOutlined.inheritAttrs = false;
var LoadingOutlined$1 = { "icon": { "tag": "svg", "attrs": { "viewBox": "0 0 1024 1024", "focusable": "false" }, "children": [{ "tag": "path", "attrs": { "d": "M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 00-94.3-139.9 437.71 437.71 0 00-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z" } }] }, "name": "loading", "theme": "outlined" };
function _objectSpread$1(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? Object(arguments[i]) : {};
var ownKeys = Object.keys(source);
if (typeof Object.getOwnPropertySymbols === "function") {
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
}));
}
ownKeys.forEach(function(key) {
_defineProperty$1(target, key, source[key]);
});
}
return target;
}
function _defineProperty$1(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, { value, enumerable: true, configurable: true, writable: true });
} else {
obj[key] = value;
}
return obj;
}
var LoadingOutlined = function LoadingOutlined2(props, context) {
var p = _objectSpread$1({}, props, context.attrs);
return vue.createVNode(Icon, _objectSpread$1({}, p, {
"icon": LoadingOutlined$1
}), null);
};
LoadingOutlined.displayName = "LoadingOutlined";
LoadingOutlined.inheritAttrs = false;
var MinusOutlined$1 = { "icon": { "tag": "svg", "attrs": { "viewBox": "64 64 896 896", "focusable": "false" }, "children": [{ "tag": "path", "attrs": { "d": "M872 474H152c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h720c4.4 0 8-3.6 8-8v-60c0-4.4-3.6-8-8-8z" } }] }, "name": "minus", "theme": "outlined" };
function _objectSpread(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? Object(arguments[i]) : {};
var ownKeys = Object.keys(source);
if (typeof Object.getOwnPropertySymbols === "function") {
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
}));
}
ownKeys.forEach(function(key) {
_defineProperty(target, key, source[key]);
});
}
return target;
}
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, { value, enumerable: true, configurable: true, writable: true });
} else {
obj[key] = value;
}
return obj;
}
var MinusOutlined = function MinusOutlined2(props, context) {
var p = _objectSpread({}, props, context.attrs);
return vue.createVNode(Icon, _objectSpread({}, p, {
"icon": MinusOutlined$1
}), null);
};
MinusOutlined.displayName = "MinusOutlined";
MinusOutlined.inheritAttrs = false;
const SCRIPT_INFO = {
name: _GM_info.script.name,
author: _GM_info.script.author,
version: _GM_info.script.version
};
const defaultSettings = {
version: "",
videoSettings: {
playbackRate: 1.5
},
submitSettings: {
autoSubmitChapter: true,
autoSubmitExam: false,
correctRateThreshold: 90
},
automationSettings: {
autoNextChapter: true,
onlyDoQuestions: false,
skipFinishedTasks: true,
autoNextExamQuestion: false
},
answerSettings: {
searchInterval: 3,
useAIWhenNoAnswer: false,
autoSaveAnswer: true,
token: "",
matchThreshold: 90
},
uiSettings: {
activeTab: "1",
position: {
x: 0,
y: 0
}
},
cardInfo: {
card_key: "",
score: 0,
total_score: 0,
last_use_time: "",
last_use_ip: "",
status: 0,
message: ""
}
};
const deepMerge = (target, source) => {
const result = { ...target };
for (const key in source) {
if (source.hasOwnProperty(key)) {
if (source[key] && typeof source[key] === "object" && !Array.isArray(source[key])) {
result[key] = deepMerge(target[key] || {}, source[key]);
} else {
result[key] = source[key];
}
}
}
return result;
};
const loadSettings = () => {
try {
const currentVersion = SCRIPT_INFO.version;
if (typeof _GM_getValue === "function") {
const savedSettingsStr = _GM_getValue("cxSettings");
if (savedSettingsStr) {
const savedSettings = JSON.parse(savedSettingsStr);
const savedVersion = savedSettings.version;
const mergedSettings = deepMerge(defaultSettings, savedSettings);
mergedSettings.version = currentVersion;
if (savedVersion !== currentVersion) {
console.log(`检测到版本变化: ${savedVersion || "未知"} -> ${currentVersion}`);
saveSettings(mergedSettings);
console.log("设置已更新到当前版本");
}
return mergedSettings;
}
}
} catch (error) {
console.error("读取设置失败:", error);
}
const initialSettings = { ...defaultSettings };
initialSettings.version = SCRIPT_INFO.version;
return initialSettings;
};
const saveSettings = (settings) => {
try {
const settingsWithVersion = {
...settings,
version: SCRIPT_INFO.version
};
const settingsStr = JSON.stringify(settingsWithVersion);
if (typeof _GM_setValue === "function") {
const result = _GM_setValue("cxSettings", settingsStr);
result?.catch?.((error) => console.error("保存设置失败:", error));
return true;
}
console.warn("GM_setValue 不可用,无法保存设置");
return false;
} catch (error) {
console.error("保存设置失败:", error);
return false;
}
};
const useSettingsStore = pinia.defineStore("settings", {
state: () => loadSettings(),
actions: {
updateSetting(category, key, value) {
if (this[category] && key in this[category]) {
this[category][key] = value;
this.saveSettings();
}
},
updateNestedSetting(category, parent, key, value) {
if (this[category] && this[category][parent] && key in this[category][parent]) {
this[category][parent][key] = value;
this.saveSettings();
}
},
updateToken(token) {
this.answerSettings.token = token;
this.saveSettings();
},
updatePosition(x, y) {
this.uiSettings.position.x = x;
this.uiSettings.position.y = y;
this.saveSettings();
},
resetSettings() {
const token = this.answerSettings.token;
const position = { ...this.uiSettings.position };
Object.keys(defaultSettings).forEach((category) => {
this[category] = { ...defaultSettings[category] };
});
this.answerSettings.token = token;
this.uiSettings.position = position;
this.saveSettings();
},
updateCardInfo(cardData) {
if (cardData) {
this.cardInfo = {
card_key: cardData.card_key || "",
score: cardData.score || 0,
total_score: cardData.total_score || 0,
last_use_time: cardData.last_use_time || "",
last_use_ip: cardData.last_use_ip || "",
status: cardData.status || 0,
message: cardData.message || ""
};
this.saveSettings();
}
},
decreaseCardScore() {
if (this.cardInfo.score > 0) {
this.cardInfo.score -= 1;
this.saveSettings();
}
},
saveSettings() {
saveSettings(this.$state);
}
}
});
function get_t(data) {
const { html, ...rest } = data;
const flatten = (value, prefix = "") => {
const pairs = [];
Object.keys(value).sort().forEach((key) => {
const fullKey = prefix ? `${prefix}.${key}` : key;
const item = value[key];
if (item === null || item === void 0) {
return;
}
if (Array.isArray(item) && item.length === 0) {
return;
}
if (typeof item === "object" && !Array.isArray(item) && Object.keys(item).length === 0) {
return;
}
if (Array.isArray(item)) {
if (item.every((entry) => typeof entry !== "object")) {
pairs.push(`${fullKey}=${item.sort().join(",")}`);
} else {
pairs.push(`${fullKey}=${JSON.stringify(item)}`);
}
return;
}
if (typeof item === "object") {
pairs.push(...flatten(item, fullKey));
return;
}
pairs.push(`${fullKey}=${item}`);
});
return pairs;
};
return CryptoJS.MD5(flatten(rest).join("&")).toString();
}
async function encrypt(data = "", key = "asdgdfghfghfghfg", iv = "1234567890123456") {
try {
if (!data) {
return "";
}
key = key.substring(0, 16);
iv = iv.substring(0, 16);
if (!window.crypto || !window.crypto.subtle) {
console.log("Web Crypto API 不可用,使用 crypto-js 降级方案");
const keyUtf8 = CryptoJS.enc.Utf8.parse(key);
const ivUtf8 = CryptoJS.enc.Utf8.parse(iv);
const encrypted = CryptoJS.AES.encrypt(data, keyUtf8, {
iv: ivUtf8,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return encrypted.toString();
}
const encoder = new TextEncoder();
const dataBuffer = encoder.encode(data);
const keyBuffer = encoder.encode(key);
const ivBuffer = encoder.encode(iv);
const cryptoKey = await crypto.subtle.importKey(
"raw",
keyBuffer,
{ name: "AES-CBC" },
false,
["encrypt"]
);
const encryptedBuffer = await crypto.subtle.encrypt(
{
name: "AES-CBC",
iv: ivBuffer
},
cryptoKey,
dataBuffer
);
const encryptedArray = new Uint8Array(encryptedBuffer);
const chunkSize = 1024;
let binaryString = "";
for (let index = 0; index < encryptedArray.length; index += chunkSize) {
const chunk = encryptedArray.slice(index, Math.min(index + chunkSize, encryptedArray.length));
binaryString += String.fromCharCode.apply(null, Array.from(chunk));
}
try {
return btoa(binaryString);
} catch (error) {
console.error("btoa 失败,尝试备用方法", error);
return binaryString.split("").map((char) => `0${char.charCodeAt(0).toString(16)}`.slice(-2)).join("");
}
} catch (error) {
console.error("加密异常详情", error);
return "";
}
}
async function decrypt$1(data = "", key = "asdgdfghfghfghfg", iv = "1234567890123456") {
try {
if (!data) {
return "";
}
key = key.substring(0, 16);
iv = iv.substring(0, 16);
if (!window.crypto || !window.crypto.subtle) {
console.log("Web Crypto API 不可用,使用 crypto-js 降级方案");
const keyUtf8 = CryptoJS.enc.Utf8.parse(key);
const ivUtf8 = CryptoJS.enc.Utf8.parse(iv);
const decrypted = CryptoJS.AES.decrypt(data, keyUtf8, {
iv: ivUtf8,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return decrypted.toString(CryptoJS.enc.Utf8);
}
const encoder = new TextEncoder();
const keyBuffer = encoder.encode(key);
const ivBuffer = encoder.encode(iv);
let binaryString;
try {
binaryString = atob(data);
} catch (error) {
console.error("atob 解码失败", error);
throw new Error("Base64 解码失败,数据格式不正确");
}
const dataBuffer = new Uint8Array(binaryString.length);
for (let index = 0; index < binaryString.length; index += 1) {
dataBuffer[index] = binaryString.charCodeAt(index);
}
if (dataBuffer.length % 16 !== 0) {
throw new Error("加密数据长度不正确,不是16的倍数");
}
const cryptoKey = await crypto.subtle.importKey(
"raw",
keyBuffer,
{ name: "AES-CBC" },
false,
["decrypt"]
);
const decryptedBuffer = await crypto.subtle.decrypt(
{
name: "AES-CBC",
iv: ivBuffer
},
cryptoKey,
dataBuffer
);
return new TextDecoder("utf-8", { fatal: true }).decode(decryptedBuffer);
} catch (error) {
console.error("解密异常详情", error);
return "";
}
}
async function parseResponse(response) {
let data = JSON.parse(response.responseText);
if (data.encrypted) {
const decryptedData = await decrypt$1(data.data);
data = JSON.parse(decryptedData);
}
return data;
}
const NOTICE_CACHE_TTL = 60 * 1e3;
let noticeCache = {
value: "",
expiresAt: 0,
promise: null
};
function fetchCardInfo(token) {
return new Promise((resolve) => {
if (!token) {
resolve({
status: 0,
message: "未配置授权码"
});
return;
}
const requestData = { api: true };
const t = get_t(requestData);
_GM_xmlhttpRequest({
method: "GET",
url: "https://www.aiask.site/v1/cardTimes",
headers: {
Accept: "*/*",
referer: location.href,
"X-Script-Version": SCRIPT_INFO.version,
aka: t,
Authorization: `Bearer ${token}`
},
timeout: 5e3,
onload: async (response) => {
try {
if (response.status < 200 || response.status >= 300) {
resolve({
status: 0,
message: "获取授权码信息失败"
});
return;
}
const data = await parseResponse(response);
if (data.code === 200 && data.data) {
resolve({
...data.data,
status: 1,
message: "授权码有效"
});
return;
}
resolve({
status: 0,
message: data.message || "授权码验证失败"
});
} catch (error) {
console.error("解析授权码响应失败:", error);
resolve({
status: 0,
message: "解析授权码信息失败"
});
}
},
onerror: (error) => {
console.error("Failed to fetch card info:", error);
resolve({
status: 0,
message: "网络错误,无法获取授权码信息"
});
},
ontimeout: () => {
resolve({
status: 0,
message: "获取授权码信息超时"
});
}
});
});
}
function fetchNotice({ force = false } = {}) {
const now = Date.now();
if (!force && noticeCache.value && noticeCache.expiresAt > now) return Promise.resolve(noticeCache.value);
if (!force && noticeCache.promise) return noticeCache.promise;
noticeCache.promise = new Promise((resolve) => {
const finish = (value) => {
noticeCache = { value, expiresAt: Date.now() + NOTICE_CACHE_TTL, promise: null };
resolve(value);
};
const t = get_t({ api: true });
_GM_xmlhttpRequest({
method: "GET",
url: "https://www.aiask.site/v1/notice",
headers: { Accept: "*/*", referer: location.href, "X-Script-Version": SCRIPT_INFO.version, aka: t },
timeout: 5e3,
onload: async (response) => {
try {
if (response.status < 200 || response.status >= 300) {
finish("获取公告失败,请稍后重试");
return;
}
const data = await parseResponse(response);
finish(data.code === 200 && data.data?.notice ? data.data.notice : "暂无公告");
} catch (error) {
console.error("解析公告响应失败:", error);
finish("获取公告失败,请稍后重试");
}
},
onerror: () => finish("获取公告失败,请检查网络连接"),
ontimeout: () => finish("获取公告超时")
});
});
return noticeCache.promise;
}
const useAnswerStore = pinia.defineStore("answer", {
state: () => ({
answers: [],
maxAnswers: 100
}),
actions: {
addAnswer(question, answer, type, status = "success", originalAnswer = null) {
const answerRecord = {
id: Date.now(),
question,
answer,
type,
status,
originalAnswer,
timestamp: (/* @__PURE__ */ new Date()).toLocaleTimeString()
};
this.answers.push(answerRecord);
if (this.answers.length > this.maxAnswers) {
this.answers.shift();
}
},
clearAnswers() {
this.answers = [];
}
},
getters: {
getAnswers: (state) => state.answers,
getAnswersByType: (state) => (type) => state.answers.filter((answer) => answer.type === type),
totalAnswers: (state) => state.answers.length
}
});
function observeRoutes(pageWindow, onChange) {
let currentUrl;
let stopped = false;
const check = () => {
if (stopped || currentUrl === pageWindow.location.href) return;
currentUrl = pageWindow.location.href;
onChange(currentUrl);
};
pageWindow.addEventListener("hashchange", check);
pageWindow.addEventListener("popstate", check);
const navigation = pageWindow.navigation;
navigation?.addEventListener("currententrychange", check);
const timer = pageWindow.setInterval(check, 750);
check();
return () => {
stopped = true;
pageWindow.clearInterval(timer);
pageWindow.removeEventListener("hashchange", check);
pageWindow.removeEventListener("popstate", check);
navigation?.removeEventListener("currententrychange", check);
};
}
function observeAnswerTab({ answerStore: answerStore2, activeKey, pageWindow }) {
const selectTab = (key) => {
if (activeKey.value !== "3") activeKey.value = key;
};
selectTab("1");
let currentUrl = pageWindow.location.href;
const syncPage = (url) => {
if (currentUrl === url) return;
currentUrl = url;
selectTab("1");
};
const stopRoutes = observeRoutes(pageWindow, syncPage);
const stopAnswers = vue.watch(() => answerStore2.answers.at(-1), (record2) => {
syncPage(pageWindow.location.href);
selectTab(record2 ? "2" : "1");
}, { flush: "sync" });
return () => {
stopAnswers();
stopRoutes();
};
}
const LOG_TYPES = {
INFO: "info",
SUCCESS: "success",
ERROR: "error",
WARNING: "warning"
};
const useLogStore = pinia.defineStore("log", {
state: () => ({
logs: [],
maxLogs: 100
}),
actions: {
addLog(message, type = LOG_TYPES.INFO) {
const log2 = {
id: Date.now(),
message,
type,
timestamp: (/* @__PURE__ */ new Date()).toLocaleTimeString()
};
this.logs.push(log2);
if (this.logs.length > this.maxLogs) {
this.logs.shift();
}
console.log(`${type} ${message}`);
},
clearLogs() {
this.logs = [];
},
getLogsByType(type) {
return this.logs.filter((log2) => log2.type === type);
}
},
getters: {
getLogs: (state) => state.logs,
errorLogs: (state) => state.logs.filter((log2) => log2.type === LOG_TYPES.ERROR),
successLogs: (state) => state.logs.filter((log2) => log2.type === LOG_TYPES.SUCCESS),
totalLogs: (state) => state.logs.length
}
});
const _export_sfc = (sfc, props) => {
const target = sfc.__vccOpts || sfc;
for (const [key, val] of props) {
target[key] = val;
}
return target;
};
const _sfc_main$5 = vue.defineComponent({
setup() {
const logStore2 = useLogStore();
const getTypeIcon = (type) => {
switch (type) {
case LOG_TYPES.SUCCESS:
return "✅";
case LOG_TYPES.ERROR:
return "❌";
case LOG_TYPES.WARNING:
return "⚠️";
case LOG_TYPES.INFO:
default:
return "ℹ️";
}
};
return {
logStore: logStore2,
getTypeIcon
};
}
});
const _hoisted_1$5 = { class: "log-viewer" };
const _hoisted_2$5 = {
key: 0,
class: "empty-message"
};
const _hoisted_3$3 = {
key: 1,
class: "log-content"
};
const _hoisted_4$3 = { class: "log-time" };
const _hoisted_5$3 = { class: "log-icon" };
const _hoisted_6$3 = ["innerHTML"];
function _sfc_render$3(_ctx, _cache, $props, $setup, $data, $options) {
return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$5, [
_ctx.logStore.getLogs.length === 0 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_2$5, "暂无运行日志")) : (vue.openBlock(), vue.createElementBlock("div", _hoisted_3$3, [
(vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(_ctx.logStore.getLogs, (log2, index) => {
return vue.openBlock(), vue.createElementBlock("div", {
key: index,
class: vue.normalizeClass(["log-item", log2.type])
}, [
vue.createElementVNode("span", _hoisted_4$3, vue.toDisplayString(log2.timestamp), 1),
vue.createElementVNode("span", _hoisted_5$3, vue.toDisplayString(_ctx.getTypeIcon(log2.type)), 1),
vue.createElementVNode("span", {
class: "log-message",
innerHTML: log2.message
}, null, 8, _hoisted_6$3)
], 2);
}), 128))
]))
]);
}
const LogViewer = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["render", _sfc_render$3]]);
const _sfc_main$4 = vue.defineComponent({
setup() {
const answerStore2 = useAnswerStore();
const formatAnswer = (answer) => {
if (Array.isArray(answer)) {
return answer.join("、");
} else if (answer === "true") {
return "✓ 正确";
} else if (answer === "false") {
return "✗ 错误";
}
return answer || "无答案";
};
const getStatusIcon = (status) => {
switch (status) {
case "success":
return "✅";
case "partial":
return "⚠️";
case "not_found":
return "❌";
case "error":
return "❌";
default:
return "✅";
}
};
return {
answerStore: answerStore2,
formatAnswer,
getStatusIcon
};
}
});
const _hoisted_1$4 = { class: "answer-viewer" };
const _hoisted_2$4 = {
key: 0,
class: "empty-message"
};
const _hoisted_3$2 = {
key: 1,
class: "answer-content"
};
const _hoisted_4$2 = { class: "answer-number" };
const _hoisted_5$2 = { class: "answer-question" };
const _hoisted_6$2 = ["innerHTML"];
const _hoisted_7$1 = { class: "answer-value" };
const _hoisted_8$1 = ["innerHTML"];
function _sfc_render$2(_ctx, _cache, $props, $setup, $data, $options) {
return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$4, [
_ctx.answerStore.totalAnswers === 0 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_2$4, "暂无答题记录")) : (vue.openBlock(), vue.createElementBlock("div", _hoisted_3$2, [
(vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(_ctx.answerStore.getAnswers, (item, index) => {
return vue.openBlock(), vue.createElementBlock("div", {
key: item.id,
class: "answer-item"
}, [
vue.createElementVNode("div", _hoisted_4$2, "题号 " + vue.toDisplayString(index + 1), 1),
vue.createElementVNode("div", _hoisted_5$2, [
_cache[0] || (_cache[0] = vue.createElementVNode("span", { class: "label" }, "题目:", -1)),
vue.createElementVNode("span", {
innerHTML: item.question
}, null, 8, _hoisted_6$2)
]),
vue.createElementVNode("div", _hoisted_7$1, [
_cache[1] || (_cache[1] = vue.createElementVNode("span", { class: "label" }, "答案:", -1)),
vue.createElementVNode("span", null, [
vue.createTextVNode(vue.toDisplayString(_ctx.getStatusIcon(item.status)) + " ", 1),
vue.createElementVNode("span", {
innerHTML: _ctx.formatAnswer(item.answer)
}, null, 8, _hoisted_8$1)
])
])
]);
}), 128))
]))
]);
}
const AnswerViewer = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["render", _sfc_render$2]]);
const _sfc_main$3 = vue.defineComponent({
components: {
KeyOutlined
},
setup() {
const settingsStore2 = useSettingsStore();
const state = vue.reactive({
videoSettings: { ...settingsStore2.videoSettings },
submitSettings: { ...settingsStore2.submitSettings },
automationSettings: { ...settingsStore2.automationSettings },
answerSettings: { ...settingsStore2.answerSettings }
});
const updateVideoSetting = (key) => {
settingsStore2.updateSetting("videoSettings", key, state.videoSettings[key]);
};
const updateSubmitSetting = (key) => {
settingsStore2.updateSetting("submitSettings", key, state.submitSettings[key]);
};
const updateAutomationSetting = (key) => {
settingsStore2.updateSetting("automationSettings", key, state.automationSettings[key]);
};
const updateAnswerSetting = (key) => {
settingsStore2.updateSetting("answerSettings", key, state.answerSettings[key]);
};
const resetSettings = () => {
settingsStore2.resetSettings();
Object.assign(state.videoSettings, settingsStore2.videoSettings);
Object.assign(state.submitSettings, settingsStore2.submitSettings);
Object.assign(state.automationSettings, settingsStore2.automationSettings);
Object.assign(state.answerSettings, settingsStore2.answerSettings);
};
const rootRef = vue.ref(null);
const getModalContainer = () => {
return rootRef.value?.getRootNode();
};
return {
...vue.toRefs(state),
updateVideoSetting,
updateSubmitSetting,
updateAutomationSetting,
updateAnswerSetting,
resetSettings,
rootRef,
getModalContainer
};
}
});
const _hoisted_1$3 = {
ref: "rootRef",
class: "settings-panel"
};
const _hoisted_2$3 = { class: "settings-section" };
const _hoisted_3$1 = { class: "setting-row" };
const _hoisted_4$1 = { class: "settings-section" };
const _hoisted_5$1 = { class: "setting-token" };
const _hoisted_6$1 = { class: "setting-row" };
const _hoisted_7 = { class: "setting-row" };
const _hoisted_8 = { class: "setting-row" };
const _hoisted_9 = { class: "setting-row" };
const _hoisted_10 = { class: "settings-section" };
const _hoisted_11 = { class: "setting-row" };
const _hoisted_12 = { class: "setting-row" };
const _hoisted_13 = { class: "setting-row" };
const _hoisted_14 = { class: "setting-row" };
const _hoisted_15 = { class: "settings-section" };
const _hoisted_16 = { class: "setting-row" };
const _hoisted_17 = { class: "setting-row" };
const _hoisted_18 = { class: "setting-row" };
const _hoisted_19 = { class: "setting-row" };
const _hoisted_20 = { class: "settings-actions" };
function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) {
const _component_a_select_option = vue.resolveComponent("a-select-option");
const _component_a_select = vue.resolveComponent("a-select");
const _component_KeyOutlined = vue.resolveComponent("KeyOutlined");
const _component_a_input_password = vue.resolveComponent("a-input-password");
const _component_a_input_number = vue.resolveComponent("a-input-number");
const _component_a_checkbox = vue.resolveComponent("a-checkbox");
const _component_a_button = vue.resolveComponent("a-button");
return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$3, [
vue.createElementVNode("section", _hoisted_2$3, [
_cache[32] || (_cache[32] = vue.createElementVNode("h3", { class: "settings-heading" }, " 视频设置 ", -1)),
vue.createElementVNode("div", _hoisted_3$1, [
_cache[31] || (_cache[31] = vue.createElementVNode("span", { class: "setting-label" }, "视频倍速(后果自负)", -1)),
vue.createVNode(_component_a_select, {
value: _ctx.videoSettings.playbackRate,
"onUpdate:value": _cache[0] || (_cache[0] = ($event) => _ctx.videoSettings.playbackRate = $event),
getPopupContainer: _ctx.getModalContainer,
class: "setting-control",
size: "small",
onChange: _cache[1] || (_cache[1] = ($event) => _ctx.updateVideoSetting("playbackRate"))
}, {
default: vue.withCtx(() => [
vue.createVNode(_component_a_select_option, { value: 1 }, {
default: vue.withCtx(() => [..._cache[28] || (_cache[28] = [
vue.createTextVNode("1倍速", -1)
])]),
_: 1
}),
vue.createVNode(_component_a_select_option, { value: 1.5 }, {
default: vue.withCtx(() => [..._cache[29] || (_cache[29] = [
vue.createTextVNode("1.5倍速", -1)
])]),
_: 1
}),
vue.createVNode(_component_a_select_option, { value: 2 }, {
default: vue.withCtx(() => [..._cache[30] || (_cache[30] = [
vue.createTextVNode("2倍速", -1)
])]),
_: 1
})
]),
_: 1
}, 8, ["value", "getPopupContainer"])
])
]),
vue.createElementVNode("section", _hoisted_4$1, [
_cache[39] || (_cache[39] = vue.createElementVNode("h3", { class: "settings-heading" }, " 答题设置 ", -1)),
vue.createElementVNode("div", _hoisted_5$1, [
_cache[33] || (_cache[33] = vue.createElementVNode("label", {
class: "setting-token-label",
for: "cx-authorization-code"
}, "授权码", -1)),
vue.createVNode(_component_a_input_password, {
value: _ctx.answerSettings.token,
"onUpdate:value": _cache[2] || (_cache[2] = ($event) => _ctx.answerSettings.token = $event),
id: "cx-authorization-code",
placeholder: "粘贴授权码",
autocomplete: "off",
size: "small",
onChange: _cache[3] || (_cache[3] = ($event) => _ctx.updateAnswerSetting("token"))
}, {
prefix: vue.withCtx(() => [
vue.createVNode(_component_KeyOutlined, { class: "token-key-icon" })
]),
_: 1
}, 8, ["value"]),
_cache[34] || (_cache[34] = vue.createElementVNode("span", { class: "setting-token-hint" }, "用于题库查询,输入后自动保存", -1))
]),
vue.createElementVNode("div", _hoisted_6$1, [
_cache[35] || (_cache[35] = vue.createElementVNode("span", { class: "setting-label" }, "搜题间隔(秒)", -1)),
vue.createVNode(_component_a_input_number, {
value: _ctx.answerSettings.searchInterval,
"onUpdate:value": _cache[4] || (_cache[4] = ($event) => _ctx.answerSettings.searchInterval = $event),
min: 1,
max: 10,
class: "setting-control",
size: "small",
onChange: _cache[5] || (_cache[5] = ($event) => _ctx.updateAnswerSetting("searchInterval"))
}, null, 8, ["value"])
]),
vue.createElementVNode("div", _hoisted_7, [
_cache[36] || (_cache[36] = vue.createElementVNode("span", { class: "setting-label" }, "答案匹配度阈值(%)", -1)),
vue.createVNode(_component_a_input_number, {
value: _ctx.answerSettings.matchThreshold,
"onUpdate:value": _cache[6] || (_cache[6] = ($event) => _ctx.answerSettings.matchThreshold = $event),
min: 0,
max: 100,
class: "setting-control",
size: "small",
onChange: _cache[7] || (_cache[7] = ($event) => _ctx.updateAnswerSetting("matchThreshold"))
}, null, 8, ["value"])
]),
vue.createElementVNode("div", _hoisted_8, [
vue.createVNode(_component_a_checkbox, {
checked: _ctx.answerSettings.autoSaveAnswer,
"onUpdate:checked": _cache[8] || (_cache[8] = ($event) => _ctx.answerSettings.autoSaveAnswer = $event),
onChange: _cache[9] || (_cache[9] = ($event) => _ctx.updateAnswerSetting("autoSaveAnswer"))
}, {
default: vue.withCtx(() => [..._cache[37] || (_cache[37] = [
vue.createTextVNode(" 自动保存答案 ", -1)
])]),
_: 1
}, 8, ["checked"])
]),
vue.createElementVNode("div", _hoisted_9, [
vue.createVNode(_component_a_checkbox, {
checked: _ctx.answerSettings.useAIWhenNoAnswer,
"onUpdate:checked": _cache[10] || (_cache[10] = ($event) => _ctx.answerSettings.useAIWhenNoAnswer = $event),
disabled: "",
onChange: _cache[11] || (_cache[11] = ($event) => _ctx.updateAnswerSetting("useAIWhenNoAnswer"))
}, {
default: vue.withCtx(() => [..._cache[38] || (_cache[38] = [
vue.createTextVNode(" 无答案时使用AI答题(等待开发) ", -1)
])]),
_: 1
}, 8, ["checked"])
])
]),
vue.createElementVNode("section", _hoisted_10, [
_cache[44] || (_cache[44] = vue.createElementVNode("h3", { class: "settings-heading" }, " 任务提交设置 ", -1)),
vue.createElementVNode("div", _hoisted_11, [
vue.createVNode(_component_a_checkbox, {
checked: _ctx.submitSettings.autoSubmitChapter,
"onUpdate:checked": _cache[12] || (_cache[12] = ($event) => _ctx.submitSettings.autoSubmitChapter = $event),
onChange: _cache[13] || (_cache[13] = ($event) => _ctx.updateSubmitSetting("autoSubmitChapter"))
}, {
default: vue.withCtx(() => [..._cache[40] || (_cache[40] = [
vue.createTextVNode(" 自动提交章节作业 ", -1)
])]),
_: 1
}, 8, ["checked"])
]),
vue.createElementVNode("div", _hoisted_12, [
vue.createVNode(_component_a_checkbox, {
checked: _ctx.submitSettings.autoSubmitHomework,
"onUpdate:checked": _cache[14] || (_cache[14] = ($event) => _ctx.submitSettings.autoSubmitHomework = $event),
disabled: "",
onChange: _cache[15] || (_cache[15] = ($event) => _ctx.updateSubmitSetting("autoSubmitHomework"))
}, {
default: vue.withCtx(() => [..._cache[41] || (_cache[41] = [
vue.createTextVNode(" 自动提交课后作业(请自行提交) ", -1)
])]),
_: 1
}, 8, ["checked"])
]),
vue.createElementVNode("div", _hoisted_13, [
vue.createVNode(_component_a_checkbox, {
checked: _ctx.submitSettings.autoSubmitExam,
"onUpdate:checked": _cache[16] || (_cache[16] = ($event) => _ctx.submitSettings.autoSubmitExam = $event),
disabled: "",
onChange: _cache[17] || (_cache[17] = ($event) => _ctx.updateSubmitSetting("autoSubmitExam"))
}, {
default: vue.withCtx(() => [..._cache[42] || (_cache[42] = [
vue.createTextVNode(" 自动提交考试(请自行提交) ", -1)
])]),
_: 1
}, 8, ["checked"])
]),
vue.createElementVNode("div", _hoisted_14, [
_cache[43] || (_cache[43] = vue.createElementVNode("span", { class: "setting-label" }, "自动提交最低准确率(%)", -1)),
vue.createVNode(_component_a_input_number, {
value: _ctx.submitSettings.correctRateThreshold,
"onUpdate:value": _cache[18] || (_cache[18] = ($event) => _ctx.submitSettings.correctRateThreshold = $event),
min: 0,
max: 100,
class: "setting-control",
size: "small",
onChange: _cache[19] || (_cache[19] = ($event) => _ctx.updateSubmitSetting("correctRateThreshold"))
}, null, 8, ["value"])
])
]),
vue.createElementVNode("section", _hoisted_15, [
_cache[49] || (_cache[49] = vue.createElementVNode("h3", { class: "settings-heading" }, " 自动化设置 ", -1)),
vue.createElementVNode("div", _hoisted_16, [
vue.createVNode(_component_a_checkbox, {
checked: _ctx.automationSettings.autoNextChapter,
"onUpdate:checked": _cache[20] || (_cache[20] = ($event) => _ctx.automationSettings.autoNextChapter = $event),
onChange: _cache[21] || (_cache[21] = ($event) => _ctx.updateAutomationSetting("autoNextChapter"))
}, {
default: vue.withCtx(() => [..._cache[45] || (_cache[45] = [
vue.createTextVNode(" 自动跳转下一章节 ", -1)
])]),
_: 1
}, 8, ["checked"])
]),
vue.createElementVNode("div", _hoisted_17, [
vue.createVNode(_component_a_checkbox, {
checked: _ctx.automationSettings.onlyDoQuestions,
"onUpdate:checked": _cache[22] || (_cache[22] = ($event) => _ctx.automationSettings.onlyDoQuestions = $event),
onChange: _cache[23] || (_cache[23] = ($event) => _ctx.updateAutomationSetting("onlyDoQuestions"))
}, {
default: vue.withCtx(() => [..._cache[46] || (_cache[46] = [
vue.createTextVNode(" 只完成答题类任务 ", -1)
])]),
_: 1
}, 8, ["checked"])
]),
vue.createElementVNode("div", _hoisted_18, [
vue.createVNode(_component_a_checkbox, {
checked: _ctx.automationSettings.skipFinishedTasks,
"onUpdate:checked": _cache[24] || (_cache[24] = ($event) => _ctx.automationSettings.skipFinishedTasks = $event),
onChange: _cache[25] || (_cache[25] = ($event) => _ctx.updateAutomationSetting("skipFinishedTasks"))
}, {
default: vue.withCtx(() => [..._cache[47] || (_cache[47] = [
vue.createTextVNode(" 自动跳过已完成任务点 ", -1)
])]),
_: 1
}, 8, ["checked"])
]),
vue.createElementVNode("div", _hoisted_19, [
vue.createVNode(_component_a_checkbox, {
checked: _ctx.automationSettings.autoNextExamQuestion,
"onUpdate:checked": _cache[26] || (_cache[26] = ($event) => _ctx.automationSettings.autoNextExamQuestion = $event),
onChange: _cache[27] || (_cache[27] = ($event) => _ctx.updateAutomationSetting("autoNextExamQuestion"))
}, {
default: vue.withCtx(() => [..._cache[48] || (_cache[48] = [
vue.createTextVNode(" 考试自动进入下一题 ", -1)
])]),
_: 1
}, 8, ["checked"])
])
]),
vue.createElementVNode("div", _hoisted_20, [
vue.createVNode(_component_a_button, {
type: "primary",
size: "small",
onClick: _ctx.resetSettings
}, {
default: vue.withCtx(() => [..._cache[50] || (_cache[50] = [
vue.createTextVNode("恢复默认设置", -1)
])]),
_: 1
}, 8, ["onClick"])
])
], 512);
}
const SettingsPanel = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["render", _sfc_render$1]]);
const _sfc_main$2 = vue.defineComponent({
components: {
LogViewer,
AnswerViewer,
SettingsPanel,
MinusOutlined,
ExpandOutlined,
CheckCircleFilled,
ExclamationCircleFilled,
LoadingOutlined
},
setup() {
const settingsStore2 = useSettingsStore();
const answerStore2 = useAnswerStore();
const visible2 = vue.ref(true);
const modalTitleRef = vue.ref(null);
const panelRef = vue.ref(null);
const rootRef = vue.ref(null);
const getModalContainer = () => rootRef.value;
const activeKey = vue.ref(settingsStore2.uiSettings.activeTab);
const stopAutoTab = observeAnswerTab({ answerStore: answerStore2, activeKey, pageWindow: window });
const token = vue.ref(settingsStore2.answerSettings.token || "");
const isMinimized = vue.ref(false);
const notice = vue.ref("");
const cardInfo = vue.computed(() => settingsStore2.cardInfo);
const checkingCard = vue.ref(false);
let cardRequestId = 0;
let cardCheckTimer;
const cardState = vue.computed(() => {
if (!settingsStore2.answerSettings.token) return "empty";
if (checkingCard.value) return "checking";
if (cardInfo.value.status === 1) return Number(cardInfo.value.score) > 0 ? "valid" : "exhausted";
return /网络|超时|解析|获取授权码信息失败/.test(cardInfo.value.message) ? "error" : "invalid";
});
const cardLabel = vue.computed(() => ({
empty: "点击配置授权码",
checking: "检测授权码…",
valid: `${cardInfo.value.score}/${cardInfo.value.total_score} 次`,
exhausted: "次数已用完",
invalid: "无效 · 点击配置",
error: "检测失败 · 重试"
})[cardState.value]);
const cardTitle = vue.computed(() => {
if (cardState.value === "valid") return `授权码有效,剩余 ${cardInfo.value.score}/${cardInfo.value.total_score} 次,点击配置`;
if (cardState.value === "exhausted") return `授权码有效,剩余 0/${cardInfo.value.total_score} 次,点击配置`;
return `${cardInfo.value.message || "未配置授权码"},点击${cardState.value === "error" ? "重试" : "配置"}`;
});
const toggleMinimize = () => {
isMinimized.value = !isMinimized.value;
};
const updateToken = () => {
settingsStore2.updateToken(token.value);
};
const goToSettings = () => {
activeKey.value = "3";
if (cardState.value === "error") scheduleCardCheck(0);
};
function scheduleCardCheck(delay = 350) {
clearTimeout(cardCheckTimer);
const requestId = ++cardRequestId;
const tokenValue = settingsStore2.answerSettings.token;
checkingCard.value = !!tokenValue;
settingsStore2.updateCardInfo({ status: 0, message: tokenValue ? "正在检测授权码" : "未配置授权码" });
if (!tokenValue) return;
cardCheckTimer = setTimeout(async () => {
let result;
try {
result = await fetchCardInfo(tokenValue);
} catch {
result = { status: 0, message: "网络错误,无法获取授权码信息" };
}
if (requestId !== cardRequestId || tokenValue !== settingsStore2.answerSettings.token) return;
settingsStore2.updateCardInfo(result);
checkingCard.value = false;
}, delay);
}
const fetchNotice$1 = async () => {
try {
notice.value = await fetchNotice();
} catch (error) {
console.error("Failed to fetch notice:", error);
notice.value = "获取公告失败,请检查网络或项目地址";
}
};
const handleOk = (event) => {
console.log(event);
visible2.value = false;
};
const transformX = vue.ref(0);
const transformY = vue.ref(0);
const preTransformX = vue.ref(0);
const preTransformY = vue.ref(0);
const isDragging = vue.ref(false);
const dragRect = {
left: 0,
right: 0,
top: 0,
bottom: 0
};
let dragStartClientX = 0;
let dragStartClientY = 0;
let dragStartLeft = 0;
let dragStartTop = 0;
let pendingTransformX = 0;
let pendingTransformY = 0;
let dragFrameId = 0;
let previousBodyUserSelect = "";
let resizeObserver;
let boundsFrameId = 0;
const cancelDragFrame = () => {
if (dragFrameId) {
window.cancelAnimationFrame(dragFrameId);
dragFrameId = 0;
}
};
const flushTransform = () => {
if (!dragFrameId) {
return;
}
cancelDragFrame();
transformX.value = pendingTransformX;
transformY.value = pendingTransformY;
};
const scheduleTransform = (nextX, nextY) => {
pendingTransformX = nextX;
pendingTransformY = nextY;
if (dragFrameId) {
return;
}
dragFrameId = window.requestAnimationFrame(() => {
dragFrameId = 0;
transformX.value = pendingTransformX;
transformY.value = pendingTransformY;
});
};
const clamp = (value, min, max) => {
return Math.min(Math.max(value, min), max);
};
const restoreBodyUserSelect = () => {
document.body.style.userSelect = previousBodyUserSelect;
};
const constrainToViewport = () => {
if (!panelRef.value || isDragging.value) return;
const rect = panelRef.value.getBoundingClientRect();
if (!rect.width || !rect.height) return;
const margin = 8;
const left = clamp(rect.left, margin, Math.max(margin, window.innerWidth - rect.width - margin));
const top = clamp(rect.top, margin, Math.max(margin, window.innerHeight - rect.height - margin));
transformX.value += left - rect.left;
transformY.value += top - rect.top;
};
const scheduleBoundsCheck = () => {
if (boundsFrameId) window.cancelAnimationFrame(boundsFrameId);
boundsFrameId = window.requestAnimationFrame(() => {
boundsFrameId = 0;
constrainToViewport();
});
};
function onDragPointerDown(event) {
if (event.button !== 0) return;
if (!modalTitleRef.value || !panelRef.value) {
return;
}
flushTransform();
const panelRect = panelRef.value.getBoundingClientRect();
dragStartClientX = event.clientX;
dragStartClientY = event.clientY;
dragStartLeft = panelRect.left;
dragStartTop = panelRect.top;
dragRect.left = 8;
dragRect.top = 8;
dragRect.right = Math.max(8, window.innerWidth - panelRect.width - 8);
dragRect.bottom = Math.max(8, window.innerHeight - panelRect.height - 8);
preTransformX.value = transformX.value;
preTransformY.value = transformY.value;
pendingTransformX = transformX.value;
pendingTransformY = transformY.value;
previousBodyUserSelect = document.body.style.userSelect;
document.body.style.userSelect = "none";
isDragging.value = true;
modalTitleRef.value.setPointerCapture(event.pointerId);
event.preventDefault();
}
function onDragPointerMove(event) {
if (!isDragging.value) return;
const minTransformX = preTransformX.value + dragRect.left - dragStartLeft;
const maxTransformX = preTransformX.value + dragRect.right - dragStartLeft;
const minTransformY = preTransformY.value + dragRect.top - dragStartTop;
const maxTransformY = preTransformY.value + dragRect.bottom - dragStartTop;
const nextTransformX = clamp(
preTransformX.value + event.clientX - dragStartClientX,
minTransformX,
maxTransformX
);
const nextTransformY = clamp(
preTransformY.value + event.clientY - dragStartClientY,
minTransformY,
maxTransformY
);
scheduleTransform(nextTransformX, nextTransformY);
}
function onDragPointerUp(event) {
if (!isDragging.value) return;
isDragging.value = false;
flushTransform();
restoreBodyUserSelect();
if (modalTitleRef.value) {
try {
modalTitleRef.value.releasePointerCapture(event.pointerId);
} catch (_) {
}
}
constrainToViewport();
settingsStore2.updatePosition(transformX.value, transformY.value);
}
function preventDragContextMenu(e) {
if (isDragging.value) {
e.preventDefault();
}
}
vue.onMounted(async () => {
if (settingsStore2.uiSettings.position) {
transformX.value = Number(settingsStore2.uiSettings.position.x) || 0;
transformY.value = Number(settingsStore2.uiSettings.position.y) || 0;
}
window.addEventListener("pointermove", onDragPointerMove, { capture: true });
window.addEventListener("pointerup", onDragPointerUp, { capture: true });
window.addEventListener("pointercancel", onDragPointerUp, { capture: true });
document.addEventListener("contextmenu", preventDragContextMenu);
window.addEventListener("resize", scheduleBoundsCheck);
fetchNotice$1();
await vue.nextTick();
if (panelRef.value) {
resizeObserver = new ResizeObserver(scheduleBoundsCheck);
resizeObserver.observe(panelRef.value);
}
scheduleBoundsCheck();
});
vue.onBeforeUnmount(() => {
stopAutoTab();
cardRequestId++;
clearTimeout(cardCheckTimer);
cancelDragFrame();
if (isDragging.value) restoreBodyUserSelect();
resizeObserver?.disconnect();
if (boundsFrameId) window.cancelAnimationFrame(boundsFrameId);
window.removeEventListener("resize", scheduleBoundsCheck);
window.removeEventListener("pointermove", onDragPointerMove, { capture: true });
window.removeEventListener("pointerup", onDragPointerUp, { capture: true });
window.removeEventListener("pointercancel", onDragPointerUp, { capture: true });
document.removeEventListener("contextmenu", preventDragContextMenu);
});
const transformStyle = vue.computed(() => {
return {
transform: `translate(${transformX.value}px, ${transformY.value}px)`
};
});
vue.watch(isMinimized, () => vue.nextTick(scheduleBoundsCheck));
vue.watch(activeKey, (newVal) => {
settingsStore2.updateSetting("uiSettings", "activeTab", newVal);
});
vue.watch(() => settingsStore2.answerSettings.token, (_token, previous) => scheduleCardCheck(previous === void 0 ? 0 : 350), { immediate: true });
vue.watch(cardInfo, (info) => {
if (settingsStore2.answerSettings.token && !checkingCard.value && info.status === 0 && !info.message) scheduleCardCheck(0);
});
return {
visible: visible2,
handleOk,
modalTitleRef,
transformStyle,
panelRef,
rootRef,
getModalContainer,
activeKey,
token,
updateToken,
toggleMinimize,
isMinimized,
notice,
cardInfo,
cardState,
cardLabel,
cardTitle,
settingsStore: settingsStore2,
goToSettings,
isDragging,
onDragPointerDown
};
}
});
const _hoisted_1$2 = { ref: "rootRef" };
const _hoisted_2$2 = {
class: "floating-brand",
title: "Easy 网课学习助手"
};
const _hoisted_3 = {
key: 0,
class: "brand-copy"
};
const _hoisted_4 = ["data-state", "title", "aria-label"];
const _hoisted_5 = {
key: 0,
class: "notice-wrapper",
"aria-label": "公告"
};
const _hoisted_6 = ["innerHTML"];
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
const _component_LoadingOutlined = vue.resolveComponent("LoadingOutlined");
const _component_CheckCircleFilled = vue.resolveComponent("CheckCircleFilled");
const _component_ExclamationCircleFilled = vue.resolveComponent("ExclamationCircleFilled");
const _component_ExpandOutlined = vue.resolveComponent("ExpandOutlined");
const _component_MinusOutlined = vue.resolveComponent("MinusOutlined");
const _component_a_button = vue.resolveComponent("a-button");
const _component_LogViewer = vue.resolveComponent("LogViewer");
const _component_a_tab_pane = vue.resolveComponent("a-tab-pane");
const _component_AnswerViewer = vue.resolveComponent("AnswerViewer");
const _component_SettingsPanel = vue.resolveComponent("SettingsPanel");
const _component_a_tabs = vue.resolveComponent("a-tabs");
const _component_a_modal = vue.resolveComponent("a-modal");
return vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [
vue.createElementVNode("div", _hoisted_1$2, null, 512),
_ctx.rootRef ? (vue.openBlock(), vue.createBlock(_component_a_modal, {
key: 0,
visible: _ctx.visible,
"onUpdate:visible": _cache[5] || (_cache[5] = ($event) => _ctx.visible = $event),
wrapClassName: "floating-modal",
class: vue.normalizeClass({ "is-minimized": _ctx.isMinimized }),
width: _ctx.isMinimized ? 232 : 352,
getContainer: _ctx.getModalContainer,
transitionName: "",
mask: false,
maskClosable: false,
closable: false,
footer: null,
bodyStyle: _ctx.isMinimized ? { display: "none" } : {},
onOk: _ctx.handleOk
}, {
title: vue.withCtx(() => [
vue.createElementVNode("div", {
ref: "modalTitleRef",
class: vue.normalizeClass(["floating-title", { "is-dragging": _ctx.isDragging }]),
onPointerdown: _cache[3] || (_cache[3] = (...args) => _ctx.onDragPointerDown && _ctx.onDragPointerDown(...args))
}, [
vue.createElementVNode("span", _hoisted_2$2, [
_cache[7] || (_cache[7] = vue.createElementVNode("span", {
class: "brand-mark",
"aria-hidden": "true"
}, "E", -1)),
!_ctx.isMinimized ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_3, [..._cache[6] || (_cache[6] = [
vue.createElementVNode("span", { class: "brand-name" }, "asy", -1),
vue.createElementVNode("span", { class: "brand-subtitle" }, "网课学习助手", -1)
])])) : vue.createCommentVNode("", true)
]),
vue.createElementVNode("button", {
type: "button",
class: "card-status",
"data-state": _ctx.cardState,
title: _ctx.cardTitle,
"aria-label": _ctx.cardTitle,
"aria-live": "polite",
onPointerdown: _cache[0] || (_cache[0] = vue.withModifiers(() => {
}, ["stop"])),
onClick: _cache[1] || (_cache[1] = (...args) => _ctx.goToSettings && _ctx.goToSettings(...args))
}, [
_ctx.cardState === "checking" ? (vue.openBlock(), vue.createBlock(_component_LoadingOutlined, {
key: 0,
class: "card-status-icon",
"aria-hidden": "true"
})) : _ctx.cardState === "valid" ? (vue.openBlock(), vue.createBlock(_component_CheckCircleFilled, {
key: 1,
class: "card-status-icon",
"aria-hidden": "true"
})) : (vue.openBlock(), vue.createBlock(_component_ExclamationCircleFilled, {
key: 2,
class: "card-status-icon",
"aria-hidden": "true"
})),
vue.createTextVNode(" " + vue.toDisplayString(_ctx.cardLabel), 1)
], 40, _hoisted_4),
vue.createVNode(_component_a_button, {
class: "minimize-button",
type: "text",
size: "small",
title: _ctx.isMinimized ? "展开面板" : "最小化面板",
"aria-label": _ctx.isMinimized ? "展开面板" : "最小化面板",
"aria-expanded": !_ctx.isMinimized,
onPointerdown: _cache[2] || (_cache[2] = vue.withModifiers(() => {
}, ["stop"])),
onClick: _ctx.toggleMinimize
}, {
icon: vue.withCtx(() => [
_ctx.isMinimized ? (vue.openBlock(), vue.createBlock(_component_ExpandOutlined, { key: 0 })) : (vue.openBlock(), vue.createBlock(_component_MinusOutlined, { key: 1 }))
]),
_: 1
}, 8, ["title", "aria-label", "aria-expanded", "onClick"])
], 34)
]),
modalRender: vue.withCtx(({ originVNode }) => [
vue.createElementVNode("div", {
ref: "panelRef",
class: "floating-panel",
style: vue.normalizeStyle(_ctx.transformStyle)
}, [
(vue.openBlock(), vue.createBlock(vue.resolveDynamicComponent(originVNode)))
], 4)
]),
default: vue.withCtx(() => [
_ctx.notice ? (vue.openBlock(), vue.createElementBlock("section", _hoisted_5, [
vue.createElementVNode("div", {
class: "notice-content",
role: "region",
tabindex: "0",
"aria-label": "公告内容",
innerHTML: _ctx.notice
}, null, 8, _hoisted_6)
])) : vue.createCommentVNode("", true),
vue.createVNode(_component_a_tabs, {
activeKey: _ctx.activeKey,
"onUpdate:activeKey": _cache[4] || (_cache[4] = ($event) => _ctx.activeKey = $event),
class: "floating-tabs",
type: "line",
size: "small"
}, {
default: vue.withCtx(() => [
vue.createVNode(_component_a_tab_pane, {
key: "1",
tab: "日志"
}, {
default: vue.withCtx(() => [
vue.createVNode(_component_LogViewer)
]),
_: 1
}),
vue.createVNode(_component_a_tab_pane, {
key: "2",
tab: "答题记录"
}, {
default: vue.withCtx(() => [
vue.createVNode(_component_AnswerViewer)
]),
_: 1
}),
vue.createVNode(_component_a_tab_pane, {
key: "3",
tab: "高级设置"
}, {
default: vue.withCtx(() => [
vue.createVNode(_component_SettingsPanel)
]),
_: 1
})
]),
_: 1
}, 8, ["activeKey"]),
_cache[8] || (_cache[8] = vue.createElementVNode("div", { class: "project-footer" }, [
vue.createElementVNode("a", {
href: "https://github.com/你的项目地址",
target: "_blank",
rel: "noopener noreferrer"
}, " Easy · 项目主页 ↗ ")
], -1))
]),
_: 1
}, 8, ["visible", "class", "width", "getContainer", "bodyStyle", "onOk"])) : vue.createCommentVNode("", true)
], 64);
}
const FloatingWindow = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["render", _sfc_render]]);
const scriptRel = /* @__PURE__ */ function detectScriptRel() {
const relList = typeof document !== "undefined" && document.createElement("link").relList;
return relList && relList.supports && relList.supports("modulepreload") ? "modulepreload" : "preload";
}();
const assetsURL = function(dep) {
return "/" + dep;
};
const seen = {};
const __vitePreload = function preload(baseModule, deps, importerUrl) {
let promise = Promise.resolve();
if (deps && deps.length > 0) {
let allSettled2 = function(promises) {
return Promise.all(
promises.map(
(p) => Promise.resolve(p).then(
(value) => ({ status: "fulfilled", value }),
(reason) => ({ status: "rejected", reason })
)
)
);
};
document.getElementsByTagName("link");
const cspNonceMeta = document.querySelector(
"meta[property=csp-nonce]"
);
const cspNonce = cspNonceMeta?.nonce || cspNonceMeta?.getAttribute("nonce");
promise = allSettled2(
deps.map((dep) => {
dep = assetsURL(dep);
if (dep in seen) return;
seen[dep] = true;
const isCss = dep.endsWith(".css");
const cssSelector = isCss ? '[rel="stylesheet"]' : "";
if (document.querySelector(`link[href="${dep}"]${cssSelector}`)) {
return;
}
const link = document.createElement("link");
link.rel = isCss ? "stylesheet" : scriptRel;
if (!isCss) {
link.as = "script";
}
link.crossOrigin = "";
link.href = dep;
if (cspNonce) {
link.setAttribute("nonce", cspNonce);
}
document.head.appendChild(link);
if (isCss) {
return new Promise((res, rej) => {
link.addEventListener("load", res);
link.addEventListener(
"error",
() => rej(new Error(`Unable to preload CSS for ${dep}`))
);
});
}
})
);
}
function handlePreloadError(err) {
const e = new Event("vite:preloadError", {
cancelable: true
});
e.payload = err;
window.dispatchEvent(e);
if (!e.defaultPrevented) {
throw err;
}
}
return promise.then((res) => {
for (const item of res || []) {
if (item.status !== "rejected") continue;
handlePreloadError(item.reason);
}
return baseModule().catch(handlePreloadError);
});
};
const QUESTION_TYPES = {
SINGLE: "单选题",
MULTI: "多选题",
JUDGE: "判断题",
FILL: "填空题",
ESSAY: "简答题"
};
const JUDGE_TRUE_WORDS = [
"对",
"正确",
"√",
"true",
"True",
"T",
"yes",
"1"
];
const JUDGE_FALSE_WORDS = [
"错",
"错误",
"×",
"false",
"False",
"F",
"no",
"0"
];
function removeHtml(html) {
if (html == null) {
return "";
}
return html.replace(/<((?!img|sub|sup|br)[^>]+)>/g, "").replace(/ /g, " ").replace(/\s+/g, " ").replace(/
/g, "\n").replace(//g, '
').trim();
}
function cleanQuestionText(text2) {
return String(text2 || "").replace(/^【.*?】\s*/, "").replace(/\s*(\d+\.\d+分)$/, "");
}
function sleep$2(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
function handleError(message) {
return {
code: -1,
message
};
}
async function getAnswer(question, options) {
try {
const settingsStore2 = useSettingsStore();
const searchInterval = settingsStore2.answerSettings.searchInterval;
if (searchInterval > 0) {
await sleep$2(searchInterval * 1e3);
}
const optionsText = options.map((option) => option.text);
let type = 1;
if (question.type.includes(QUESTION_TYPES.JUDGE)) {
type = 2;
} else if (question.type.includes(QUESTION_TYPES.FILL)) {
type = 3;
} else if (question.type.includes(QUESTION_TYPES.ESSAY)) {
type = 4;
}
const requestData = {
type,
question: question.title,
options: optionsText,
api: true
};
const t = get_t(requestData);
const encryptedData = await encrypt(JSON.stringify(requestData), t);
const headers = {
Accept: "*/*",
"Content-Type": "application/json",
Connection: "keep-alive",
aka: t,
referer: location.href,
"X-Script-Version": SCRIPT_INFO.version
};
const token = settingsStore2.answerSettings.token;
if (token && token.trim() !== "") {
headers.Authorization = `Bearer ${token}`;
}
return new Promise((resolve) => {
_GM_xmlhttpRequest({
method: "POST",
url: "https://www.aiask.site/v1/question/precise",
headers,
data: JSON.stringify({ data: encryptedData }),
timeout: 1e4,
onload: async (response) => {
try {
if (response.status >= 200 && response.status < 300) {
let data = JSON.parse(response.responseText);
if (data.encrypted) {
const decryptedData = await decrypt$1(data.data);
data = JSON.parse(decryptedData);
}
if (data.code === 200) {
settingsStore2.decreaseCardScore();
resolve(data);
return;
}
resolve(handleError(`请求失败: ${data.message}`));
return;
}
resolve(handleError(`请求失败: ${response.status}`));
} catch (error) {
resolve(handleError(`解析响应失败: ${error.message}`));
}
},
onerror: () => resolve(handleError("请求出错")),
ontimeout: () => resolve(handleError("请求超时"))
});
});
} catch (error) {
console.error("获取答案失败:", error);
return handleError(`请求异常: ${error.message}`);
}
}
function calculateSimilarity(str1, str2) {
if (!str1 || !str2) {
return 0;
}
if (str1 === str2) {
return 100;
}
const left = str1.replace(/\s+/g, "").toLowerCase();
const right = str2.replace(/\s+/g, "").toLowerCase();
if (left === right) {
return 100;
}
if (left.length === 0 || right.length === 0) {
return 0;
}
const shorter = left.length < right.length ? left : right;
const longerChars = (left.length < right.length ? right : left).split("");
let matchCount = 0;
for (const char of shorter.split("")) {
const index = longerChars.indexOf(char);
if (index !== -1) {
matchCount += 1;
longerChars.splice(index, 1);
}
}
return Math.round(matchCount / Math.max(left.length, right.length) * 100);
}
function findMatchingOption(answerText, options, threshold) {
if (!answerText || !options || options.length === 0) {
return null;
}
let bestMatch = null;
let highestSimilarity = 0;
for (const option of options) {
const similarity = calculateSimilarity(answerText, option.text);
if (similarity > highestSimilarity) {
highestSimilarity = similarity;
bestMatch = option;
}
}
if (highestSimilarity >= threshold) {
return {
option: bestMatch,
similarity: highestSimilarity
};
}
return null;
}
async function checkAnswer(question, options) {
try {
if (window._taskCancelled) {
throw new Error("Task cancelled");
}
const logStore2 = useLogStore();
const settingsStore2 = useSettingsStore();
const formattedTitle = cleanQuestionText(question.title);
const apiResponse = await getAnswer(question, options);
if (window._taskCancelled) {
throw new Error("Task cancelled");
}
if (apiResponse.code === -1) {
logStore2.addLog(apiResponse.message, LOG_TYPES.ERROR);
return {
isCorrect: false,
answer: null,
message: apiResponse.message,
status: "error",
title: formattedTitle
};
}
if (apiResponse.code === 200 && apiResponse.data && apiResponse.data.answer) {
if (Array.isArray(apiResponse.data.answer) && apiResponse.data.answer.length > 0) {
logStore2.addLog("找到答案", LOG_TYPES.SUCCESS);
}
const matchThreshold = settingsStore2.answerSettings.matchThreshold || 90;
if (question.type.includes(QUESTION_TYPES.MULTI)) {
const matchResults = apiResponse.data.answer.map((answerText) => {
const exactMatch = options.find((option) => option.text === answerText);
if (exactMatch) {
return { value: exactMatch.value, similarity: 100, text: answerText };
}
const fuzzyMatch = findMatchingOption(answerText, options, matchThreshold);
if (fuzzyMatch) {
return {
value: fuzzyMatch.option.value,
similarity: fuzzyMatch.similarity,
text: answerText
};
}
return { value: null, similarity: 0, text: answerText };
});
const answerValues = matchResults.filter((item) => item.value).map((item) => item.value);
const hasUnmatched = answerValues.length < apiResponse.data.answer.length;
const originalAnswers = apiResponse.data.answer.join("、");
const matchInfo = matchResults.map((item) => item.value ? `${item.text}(${item.similarity}%)` : `${item.text}(未匹配)`).join("、");
if (answerValues.length === 0) {
logStore2.addLog(`匹配失败: ${matchInfo}`, LOG_TYPES.WARNING);
return {
isCorrect: false,
answer: null,
message: `找到答案但无法匹配选项?{originalAnswers}`,
originalAnswer: originalAnswers,
status: "partial",
title: formattedTitle
};
}
if (hasUnmatched) {
logStore2.addLog(`部分匹配: ${matchInfo}`, LOG_TYPES.WARNING);
return {
isCorrect: true,
answer: answerValues,
message: `原始答案?{originalAnswers}`,
originalAnswer: originalAnswers,
status: "partial",
title: formattedTitle
};
}
logStore2.addLog(`匹配成功: ${matchInfo}`, LOG_TYPES.SUCCESS);
return {
isCorrect: true,
answer: answerValues,
status: "success",
title: formattedTitle
};
}
if (question.type.includes(QUESTION_TYPES.SINGLE)) {
const answerText = Array.isArray(apiResponse.data.answer) ? apiResponse.data.answer[0] : apiResponse.data.answer;
let option = options.find((item) => item.text === answerText);
let similarity = 100;
if (!option) {
const fuzzyMatch = findMatchingOption(answerText, options, matchThreshold);
if (fuzzyMatch) {
option = fuzzyMatch.option;
similarity = fuzzyMatch.similarity;
}
}
if (!option?.value) {
logStore2.addLog(`匹配失败: ${answerText}`, LOG_TYPES.WARNING);
return {
isCorrect: false,
answer: null,
message: `找到答案但无法匹配选项?{answerText}`,
originalAnswer: answerText,
status: "partial",
title: formattedTitle
};
}
logStore2.addLog(`匹配成功: ${answerText}(${similarity}%)`, LOG_TYPES.SUCCESS);
return {
isCorrect: true,
answer: option.value,
status: "success",
title: formattedTitle
};
}
if (question.type.includes(QUESTION_TYPES.JUDGE)) {
const answerText = String(
Array.isArray(apiResponse.data.answer) ? apiResponse.data.answer[0] : apiResponse.data.answer
).trim();
let answerValue = null;
for (const word of JUDGE_FALSE_WORDS.slice().sort((left, right) => right.length - left.length)) {
if (answerText.includes(word)) {
answerValue = "false";
break;
}
}
if (answerValue === null) {
for (const word of JUDGE_TRUE_WORDS.slice().sort((left, right) => right.length - left.length)) {
if (answerText.includes(word)) {
answerValue = "true";
break;
}
}
}
if (answerValue === null) {
return {
isCorrect: false,
answer: null,
message: `找到答案但无法解析:${answerText}`,
originalAnswer: answerText,
status: "partial",
title: formattedTitle
};
}
return {
isCorrect: true,
answer: answerValue,
status: "success",
title: formattedTitle
};
}
if (question.type.includes(QUESTION_TYPES.FILL)) {
return {
isCorrect: true,
answer: apiResponse.data.answer,
status: "success",
title: formattedTitle
};
}
if (question.type.includes(QUESTION_TYPES.ESSAY)) {
const answerText = Array.isArray(apiResponse.data.answer) ? apiResponse.data.answer[0] : apiResponse.data.answer;
return {
isCorrect: true,
answer: answerText,
status: "success",
title: formattedTitle
};
}
}
return {
isCorrect: false,
answer: null,
message: apiResponse.message || "未找到答案",
status: "not_found",
title: formattedTitle
};
} catch (error) {
if (error.message === "Task cancelled" || window._taskCancelled) {
throw new Error("Task cancelled");
}
console.error("答案判断失败:", error);
return {
isCorrect: false,
answer: null,
message: error.message || "答案判断失败",
status: "error",
title: question.title
};
}
}
function normalizeAnswers(answer) {
const answers = Array.isArray(answer) ? answer : [answer];
return answers.filter((item) => item !== void 0 && item !== null && String(item).trim() !== "").map(String);
}
function getAnswerValueAt(answer, index = 0) {
const value = Array.isArray(answer) ? answer[index] : answer;
return value === void 0 || value === null ? "" : String(value);
}
function hasAnswerValue(answer) {
return String(answer ?? "").trim() !== "";
}
function getOptionValue(option, valueSelector = "[data]") {
return option?.querySelector(valueSelector)?.getAttribute("data") || "";
}
function isOptionSelected(option) {
return Boolean(option?.matches?.(".check_answer, .check_answer_dx") || option?.querySelector(".check_answer, .check_answer_dx"));
}
async function clearSelectedOptions(options, keepValues = [], valueSelector = "[data]") {
const keepSet = new Set(keepValues.map(String));
for (const option of options) {
const value = getOptionValue(option, valueSelector);
if (isOptionSelected(option) && !keepSet.has(value)) {
option.click();
await sleep$2(100);
}
}
}
function areOptionsSelected(options, answers, valueSelector = "[data]") {
const normalizedAnswers = normalizeAnswers(answers);
if (!normalizedAnswers.length) {
return false;
}
const selectedValues = options.filter(isOptionSelected).map((option) => getOptionValue(option, valueSelector));
return normalizedAnswers.every((answer) => selectedValues.includes(answer)) && selectedValues.every((selected2) => normalizedAnswers.includes(selected2));
}
function getUE(contentWindow) {
return contentWindow?.UE || window.UE || _unsafeWindow?.UE || null;
}
function dispatchTextEvents(element) {
element.dispatchEvent(new Event("input", { bubbles: true }));
element.dispatchEvent(new Event("change", { bubbles: true }));
}
function setTextControlValue(element, answer) {
if (!element || !("value" in element)) {
return false;
}
element.value = "";
dispatchTextEvents(element);
element.value = String(answer);
dispatchTextEvents(element);
return true;
}
async function waitEditorReady(editor) {
if (!editor || editor.isReady || editor.ready === true) {
return;
}
if (typeof editor.ready === "function") {
await Promise.race([
new Promise((resolve) => {
editor.ready(resolve);
}),
sleep$2(800)
]);
return;
}
if (typeof editor.addListener !== "function") {
return;
}
await Promise.race([
new Promise((resolve) => {
editor.addListener("ready", resolve);
}),
sleep$2(800)
]);
}
async function setRichTextAnswer({ element, editorId, answer, contentWindow }) {
const value = String(answer ?? "");
const targetEditorId = editorId || element?.id || "";
const UE = getUE(contentWindow);
if (targetEditorId && UE?.getEditor) {
try {
const editor = UE.getEditor(targetEditorId);
if (editor?.setContent) {
await waitEditorReady(editor);
editor.setContent("");
editor.setContent(value);
if (typeof editor.sync === "function") {
editor.sync();
}
if (element && "value" in element) {
element.value = value;
dispatchTextEvents(element);
}
return true;
}
} catch (error) {
console.warn("写入富文本编辑器失败,改用普通输入框:", error);
}
}
return setTextControlValue(element, value);
}
function findAnswerInputs(questionElement) {
return Array.from(
new Set(
Array.from(questionElement.querySelectorAll('textarea, input[type="text"], [id^="answerEditor"]')).filter(Boolean)
)
);
}
async function fillRichTextAnswers(questionElement, answers, contentWindow) {
const inputs = findAnswerInputs(questionElement);
if (!inputs.length) {
return false;
}
let wrote = false;
for (let index = 0; index < inputs.length; index += 1) {
const answer = getAnswerValueAt(answers, index);
if (!hasAnswerValue(answer)) {
continue;
}
wrote = await setRichTextAnswer({ element: inputs[index], answer, contentWindow }) || wrote;
await sleep$2(100);
}
return wrote;
}
function getQuestionOptions(questionElement, questionId, optionSelector) {
return Array.from(questionElement.querySelectorAll(`li[qid="${questionId}"]`)).filter(
(option) => option.querySelector(optionSelector)
);
}
async function clickOptionIfNeeded(option) {
if (!option) {
return false;
}
if (!isOptionSelected(option)) {
option.click();
await sleep$2(200);
}
return true;
}
async function submitAnswer(questionElement, questionId, answers) {
try {
if (window._taskCancelled) {
return false;
}
const questionType = questionElement.querySelector(".newZy_TItle").textContent;
const hasAnswered = checkIfAlreadyAnswered(questionElement, questionId, questionType, answers);
if (hasAnswered) {
console.log("此题已正确作答,跳过提交");
return true;
}
if (Array.isArray(answers)) {
const normalizedAnswers = normalizeAnswers(answers);
if (!normalizedAnswers.length) {
return false;
}
const options = getQuestionOptions(questionElement, questionId, ".num_option_dx");
await clearSelectedOptions(options, normalizedAnswers, ".num_option_dx");
for (const answer of normalizedAnswers) {
if (window._taskCancelled) {
return false;
}
const optionLi = options.find((option) => getOptionValue(option, ".num_option_dx") === answer);
if (!await clickOptionIfNeeded(optionLi)) {
return false;
}
}
return areOptionsSelected(options, normalizedAnswers, ".num_option_dx");
}
if (questionType.includes("单选题")) {
const answer = getAnswerValueAt(answers);
if (!hasAnswerValue(answer)) {
return false;
}
const optionElement = questionElement.querySelector(`li[qid="${questionId}"][qtype="0"] .num_option[data="${answer}"]`) || questionElement.querySelector(`li[qid="${questionId}"] .num_option[data="${answer}"]`);
return clickOptionIfNeeded(optionElement?.closest("li"));
}
if (questionType.includes("判断题")) {
const dataValue = answers === "true" ? "true" : "false";
const optionElement = questionElement.querySelector(`li[qid="${questionId}"][qtype="3"] .num_option[data="${dataValue}"]`) || questionElement.querySelector(`li[qid="${questionId}"] .num_option[data="${dataValue}"]`);
return clickOptionIfNeeded(optionElement?.closest("li"));
}
return true;
} catch (error) {
console.error("提交答案失败:", error);
return false;
}
}
function checkIfAlreadyAnswered(questionElement, questionId, questionType, answers) {
try {
if (questionType.includes("多选题") && Array.isArray(answers)) {
const normalizedAnswers = normalizeAnswers(answers);
if (!normalizedAnswers.length) {
return false;
}
return areOptionsSelected(getQuestionOptions(questionElement, questionId, ".num_option_dx"), normalizedAnswers, ".num_option_dx");
}
if (questionType.includes("单选题")) {
const selectedOption = questionElement.querySelector(`li[qid="${questionId}"][qtype="0"] .check_answer`);
if (selectedOption) {
const selectedValue = selectedOption.closest("li")?.querySelector(".num_option")?.getAttribute("data");
return selectedValue === answers;
}
}
if (questionType.includes("判断题")) {
const dataValue = answers === "true" ? "true" : "false";
const selectedOption = questionElement.querySelector(`li[qid="${questionId}"][qtype="3"] .check_answer`);
if (selectedOption) {
const selectedValue = selectedOption.closest("li")?.querySelector(".num_option")?.getAttribute("data");
return selectedValue === dataValue;
}
}
return false;
} catch (error) {
console.error("检查已答题状态失败:", error);
return false;
}
}
async function submitEssayAnswer(questionElement, questionId, answer, contentWindow) {
try {
if (window._taskCancelled) {
return false;
}
const formattedAnswer = getAnswerValueAt(answer);
if (!hasAnswerValue(formattedAnswer) || window._taskCancelled) {
return false;
}
const textarea = questionElement.querySelector("textarea");
const editorId = textarea?.id || `answer${questionId}`;
const wrote = await setRichTextAnswer({ element: textarea, editorId, answer: formattedAnswer, contentWindow });
await sleep$2(200);
return wrote;
} catch (error) {
console.error("提交简答题答案失败:", error);
return false;
}
}
async function submitFillBlankAnswer(questionElement, questionId, answers, contentWindow) {
try {
if (window._taskCancelled) {
return false;
}
return fillRichTextAnswers(questionElement, answers, contentWindow);
} catch (error) {
console.error("提交填空答案失败:", error);
return false;
}
}
let logStore$2;
let answerStore$2;
let settingsStore$2;
function initStores$2() {
if (!logStore$2) {
logStore$2 = useLogStore();
}
if (!answerStore$2) {
answerStore$2 = useAnswerStore();
}
if (!settingsStore$2) {
settingsStore$2 = useSettingsStore();
}
}
async function waitForPageLoad() {
return new Promise((resolve) => {
if (document.readyState === "complete") {
resolve();
return;
}
const checkState = async () => {
if (document.readyState === "complete") {
resolve();
return;
}
await sleep$2(500);
checkState();
};
checkState();
});
}
async function waitForElement(doc, selector, maxAttempts = 20) {
return new Promise((resolve) => {
let attempts = 0;
const checkElement = async () => {
const element = doc.querySelector(selector);
if (element) {
resolve(element);
return;
}
if (attempts < maxAttempts) {
attempts += 1;
await sleep$2(500);
checkElement();
return;
}
resolve(null);
};
checkElement();
});
}
async function waitForIframeLoad(iframe) {
return new Promise((resolve) => {
if (!iframe.src || iframe.src === "about:blank" || iframe.src.includes("javascript:")) {
resolve(null);
return;
}
const checkIframe = async () => {
try {
const doc = iframe.contentDocument || iframe.contentWindow?.document;
if (doc) {
if (doc.readyState === "complete") {
resolve(doc);
return;
}
await sleep$2(500);
checkIframe();
return;
}
await sleep$2(500);
checkIframe();
} catch {
resolve(null);
}
};
checkIframe();
});
}
async function handleMedia(mediaElement, mediaType) {
initStores$2();
return new Promise(async (resolve) => {
try {
logStore$2.addLog("正在处理一个视频/音频任务,请耐心等待", LOG_TYPES.INFO);
const { playbackRate } = settingsStore$2.videoSettings;
mediaElement.playbackRate = playbackRate;
const unwatch = vue.watch(
() => settingsStore$2.videoSettings.playbackRate,
(newRate) => {
if (mediaElement && !mediaElement.ended) {
mediaElement.playbackRate = newRate;
logStore$2.addLog(`已将播放速率更改为 ${newRate} 倍速`, LOG_TYPES.INFO);
}
}
);
mediaElement.muted = true;
await mediaElement.pause();
try {
await mediaElement.play();
} catch (error) {
console.error("媒体播放初始化失败:", error);
logStore$2.addLog("视频被禁止倍速播放,如能继续播放请忽略", LOG_TYPES.ERROR);
setTimeout(async () => {
try {
await mediaElement.play();
} catch (retryError) {
console.error("重试播放失败:", retryError);
}
}, 1e3);
}
let lastPlayTime = Date.now();
let isPlaying = true;
const monitorPlayback = setInterval(() => {
if (window._taskCancelled) {
clearInterval(monitorPlayback);
mediaElement.removeEventListener("pause", mediaElement._handlePause);
mediaElement.removeEventListener("ended", mediaElement._handleEnded);
unwatch();
resolve();
return;
}
if (!mediaElement.ended && !mediaElement.paused) {
lastPlayTime = Date.now();
isPlaying = true;
return;
}
if (!mediaElement.ended && mediaElement.paused && isPlaying) {
const currentTime = Date.now();
if (currentTime - lastPlayTime > 1e3) {
logStore$2.addLog("已被暂停,尝试继续播放", LOG_TYPES.WARNING);
mediaElement.play().catch((error) => {
console.error("自动继续播放失败:", error);
});
}
isPlaying = false;
}
}, 1e3);
const handlePause = async () => {
if (window._taskCancelled) {
return;
}
try {
await mediaElement.play();
} catch (error) {
console.error(`${mediaType}重新播放失败:`, error);
setTimeout(async () => {
if (window._taskCancelled) {
return;
}
try {
await mediaElement.play();
} catch (retryError) {
console.error("重试播放失败:", retryError);
}
}, 1e3);
}
};
const handleEnded = () => {
clearInterval(monitorPlayback);
mediaElement.removeEventListener("pause", mediaElement._handlePause);
mediaElement.removeEventListener("ended", mediaElement._handleEnded);
unwatch();
logStore$2.addLog("处理完成", LOG_TYPES.SUCCESS);
resolve();
};
mediaElement._handlePause = handlePause;
mediaElement._handleEnded = handleEnded;
mediaElement._monitorInterval = monitorPlayback;
mediaElement._unwatchFn = unwatch;
mediaElement.addEventListener("pause", handlePause);
mediaElement.addEventListener("ended", handleEnded);
} catch (error) {
console.error(`播放${mediaType}时出错:`, error);
resolve();
}
});
}
async function handleDocument(panviewElement) {
initStores$2();
return new Promise(async (resolve) => {
try {
logStore$2.addLog("正在处理一个文档任务,滚动到底部", LOG_TYPES.INFO);
if (window._taskCancelled) {
resolve();
return;
}
let scrollElements = [panviewElement];
if (panviewElement.tagName === "IFRAME") {
try {
const iframeDoc = panviewElement.contentDocument || panviewElement.contentWindow?.document;
if (iframeDoc) {
const possibleScrollers = [
iframeDoc.documentElement,
iframeDoc.body,
iframeDoc.querySelector(".doc-container"),
iframeDoc.querySelector(".document"),
iframeDoc.querySelector('[class*="scroll"]'),
iframeDoc.querySelector('[class*="content"]')
].filter(Boolean);
scrollElements = possibleScrollers.length > 0 ? possibleScrollers : [iframeDoc.body];
}
} catch {
console.warn("无法访问iframe内容,使用iframe本身");
}
}
let scrolled = false;
for (const scrollElement of scrollElements) {
if (!scrollElement) {
continue;
}
const scrollHeight = scrollElement.scrollHeight;
const clientHeight = scrollElement.clientHeight;
const scrollDistance = scrollHeight - clientHeight;
if (scrollDistance > 0) {
const scrollStep = Math.ceil(scrollDistance / 20);
let currentScroll = scrollElement.scrollTop;
while (currentScroll < scrollHeight) {
if (window._taskCancelled) {
resolve();
return;
}
currentScroll = Math.min(currentScroll + scrollStep, scrollHeight);
scrollElement.scrollTop = currentScroll;
await sleep$2(100);
}
scrolled = true;
continue;
}
scrollElement.scrollTop = scrollHeight;
}
if (scrolled) {
logStore$2.addLog("文档阅读成功", LOG_TYPES.SUCCESS);
}
if (window._taskCancelled) {
resolve();
return;
}
logStore$2.addLog("文档处理完成", LOG_TYPES.SUCCESS);
resolve();
} catch (error) {
console.error("处理文档时出错:", error);
logStore$2.addLog(`文档处理出错: ${error.message}`, LOG_TYPES.ERROR);
resolve();
}
});
}
function parseQuestion$2(questionElement) {
const type = questionElement.querySelector(".newZy_TItle")?.textContent || "";
const titleDiv = questionElement.querySelector(".Zy_TItle .fontLabel");
const titleHtml = titleDiv?.innerHTML || "";
return {
type: type.replace(/[【】]/g, ""),
title: cleanQuestionText(removeHtml(titleHtml))
};
}
function parseOptions$2(questionElement) {
const questionType = questionElement.querySelector(".newZy_TItle")?.textContent || "";
const options = Array.from(questionElement.querySelectorAll(".Zy_ulTop li"));
return options.map((option) => {
const label = option.querySelector(".after");
let valueElement = null;
if (questionType.includes("多选题")) {
valueElement = option.querySelector(".num_option_dx");
} else if (questionType.includes("单选题") || questionType.includes("判断题")) {
valueElement = option.querySelector(".num_option");
}
return {
text: label ? cleanQuestionText(removeHtml(label.innerHTML)).trim() : "",
value: valueElement ? valueElement.getAttribute("data") : ""
};
});
}
function getQuestionId(questionElement) {
return questionElement.closest(".singleQuesId")?.getAttribute("data") || "";
}
async function handleSingleChoice$2(question, questionId, answer) {
initStores$2();
try {
if (await submitAnswer(question, questionId, answer)) {
logStore$2.addLog("单选题已完成", LOG_TYPES.SUCCESS);
}
} catch {
logStore$2.addLog("单选题答题失败", LOG_TYPES.ERROR);
}
}
async function handleMultipleChoice$2(question, questionId, answers) {
initStores$2();
try {
if (await submitAnswer(question, questionId, answers)) {
logStore$2.addLog("多选题已完成", LOG_TYPES.SUCCESS);
}
} catch {
logStore$2.addLog("多选题答题失败", LOG_TYPES.ERROR);
}
}
async function handleJudgment$2(question, questionId, answer) {
initStores$2();
try {
if (await submitAnswer(question, questionId, answer)) {
logStore$2.addLog("判断题已完成", LOG_TYPES.SUCCESS);
}
} catch {
logStore$2.addLog("判断题答题失败", LOG_TYPES.ERROR);
}
}
async function handleFillBlank$2(question, questionId, answer, contentWindow) {
initStores$2();
try {
if (await submitFillBlankAnswer(question, questionId, answer, contentWindow)) {
logStore$2.addLog("填空题已完成", LOG_TYPES.SUCCESS);
}
} catch {
logStore$2.addLog("填空题答题失败", LOG_TYPES.ERROR);
}
}
async function handleEssay$2(question, questionId, answer, contentWindow) {
initStores$2();
try {
if (await submitEssayAnswer(question, questionId, answer, contentWindow)) {
logStore$2.addLog("简答题已完成", LOG_TYPES.SUCCESS);
}
} catch {
logStore$2.addLog("简答题答题失败", LOG_TYPES.ERROR);
}
}
function getSearchDocuments(doc, contentWindow) {
const documents = [];
const addDocument = (documentLike) => {
if (documentLike && !documents.includes(documentLike)) {
documents.push(documentLike);
}
};
addDocument(doc);
try {
addDocument(contentWindow?.document);
} catch {
}
try {
addDocument(contentWindow?.parent?.document);
} catch {
}
try {
addDocument(contentWindow?.top?.document);
} catch {
}
addDocument(document);
return documents;
}
function isVisibleElement(element) {
if (!element) {
return false;
}
const rect = element.getBoundingClientRect();
const style = element.ownerDocument?.defaultView?.getComputedStyle(element);
return rect.width > 0 && rect.height > 0 && style?.display !== "none" && style?.visibility !== "hidden" && element.getAttribute("aria-hidden") !== "true" && !element.disabled;
}
function findFirstElement(documents, selectors, predicate = () => true) {
for (const currentDoc of documents) {
for (const selector of selectors) {
try {
const elements = Array.from(currentDoc.querySelectorAll(selector));
const element = elements.find(predicate);
if (element) {
return element;
}
} catch {
}
}
}
return null;
}
async function waitForFirstElement(getDocuments, selectors, timeout = 5e3, interval = 150, predicate = () => true) {
const deadline = Date.now() + timeout;
while (Date.now() <= deadline) {
const element = findFirstElement(getDocuments(), selectors, predicate);
if (element) {
return element;
}
await sleep$2(interval);
}
return null;
}
async function submitChapterWork(doc, contentWindow) {
let triggered = false;
if (typeof contentWindow?.btnBlueSubmit === "function") {
try {
contentWindow.btnBlueSubmit.call(contentWindow);
triggered = true;
} catch (error) {
console.warn("调用章节提交函数失败,尝试点击提交按钮:", error);
}
} else if (typeof window.btnBlueSubmit === "function") {
try {
window.btnBlueSubmit();
triggered = true;
} catch (error) {
console.warn("调用全局章节提交函数失败,尝试点击提交按钮:", error);
}
}
if (!triggered) {
const submitTrigger = findFirstElement(getSearchDocuments(doc, contentWindow), [
"#btnBlueSubmit",
"[onclick*='btnBlueSubmit']",
"[onclick*='btnBlue_submit']"
]);
if (!submitTrigger) {
return { submitted: false, confirmed: false };
}
submitTrigger.click();
triggered = true;
}
await sleep$2(1800);
const confirmButton = await waitForFirstElement(
() => getSearchDocuments(doc, contentWindow),
[
".popBottom #popok",
".popBottom a#popok",
"a#popok[aria-label='确定']"
],
8e3,
200,
isVisibleElement
);
if (confirmButton) {
confirmButton.focus?.();
confirmButton.click();
return { submitted: true, confirmed: true };
}
return { submitted: true, confirmed: false };
}
async function handleWork$1(doc) {
initStores$2();
if (!settingsStore$2.cardInfo || settingsStore$2.cardInfo.status !== 1) {
logStore$2.addLog("授权码未配置或已失效,跳过答题", LOG_TYPES.ERROR);
logStore$2.addLog("请在「高级设置」中配置有效的授权码", LOG_TYPES.WARNING);
return;
}
if (window._taskCancelled) {
return;
}
const questions = doc.querySelectorAll(".TiMu");
if (!questions.length) {
return;
}
const contentWindow = doc.defaultView || doc.parentWindow;
if (!contentWindow) {
logStore$2.addLog("无法获取iframe的contentWindow", LOG_TYPES.ERROR);
return;
}
logStore$2.addLog(`正在完成一个作业,共${questions.length}道题目`, LOG_TYPES.INFO);
let correctCount = 0;
for (const [index, question] of questions.entries()) {
if (window._taskCancelled) {
logStore$2.addLog("答题任务被终止", LOG_TYPES.WARNING);
break;
}
try {
const { type, title } = parseQuestion$2(question);
const questionId = getQuestionId(question);
const options = parseOptions$2(question);
logStore$2.addLog(`正在完成第${index + 1}题,题型:${type}`, LOG_TYPES.INFO);
const { isCorrect, answer, title: fullTitle, message, status, originalAnswer } = await checkAnswer(
{ type, title },
options
);
if (window._taskCancelled) {
logStore$2.addLog("答题任务被终止", LOG_TYPES.WARNING);
break;
}
const displayAnswer = isCorrect ? answer : originalAnswer || message;
answerStore$2.addAnswer(fullTitle, displayAnswer, type, status, originalAnswer);
if (!isCorrect) {
if (status === "not_found") {
logStore$2.addLog("未找到答案,跳过此题", LOG_TYPES.WARNING);
}
continue;
}
correctCount += 1;
if (type.includes("单选题")) {
await handleSingleChoice$2(question, questionId, answer, contentWindow);
} else if (type.includes("多选题")) {
await handleMultipleChoice$2(question, questionId, answer, contentWindow);
} else if (type.includes("判断题")) {
await handleJudgment$2(question, questionId, answer, contentWindow);
} else if (type.includes("填空题")) {
await handleFillBlank$2(question, questionId, answer, contentWindow);
} else if (type.includes("简答题")) {
await handleEssay$2(question, questionId, answer, contentWindow);
}
} catch (error) {
if (window._taskCancelled || error.message === "Task cancelled") {
logStore$2.addLog("答题任务被终止", LOG_TYPES.WARNING);
break;
}
logStore$2.addLog(`处理题目出错: ${error.message}`, LOG_TYPES.ERROR);
}
}
if (window._taskCancelled) {
return;
}
const correctRate = correctCount / questions.length * 100;
logStore$2.addLog(`答题完成,正确率: ${correctRate.toFixed(2)}%`, LOG_TYPES.SUCCESS);
const shouldAutoSubmit = settingsStore$2.submitSettings.autoSubmitChapter && correctRate >= settingsStore$2.submitSettings.correctRateThreshold;
if (shouldAutoSubmit) {
try {
if (window._taskCancelled) {
logStore$2.addLog("任务已取消,不进行提交", LOG_TYPES.WARNING);
return;
}
logStore$2.addLog("自动提交作业", LOG_TYPES.INFO);
const { submitted, confirmed } = await submitChapterWork(doc, contentWindow);
if (!submitted) {
throw new Error("未找到章节提交函数或提交入口");
}
if (!confirmed) {
throw new Error("提交确认弹窗未出现或未找到提交按钮");
}
logStore$2.addLog("已点击提交确认按钮", LOG_TYPES.INFO);
logStore$2.addLog("作业提交成功", LOG_TYPES.SUCCESS);
} catch (error) {
if (window._taskCancelled) {
logStore$2.addLog("提交操作被取消", LOG_TYPES.WARNING);
return;
}
logStore$2.addLog(`提交出错: ${error.message}`, LOG_TYPES.ERROR);
}
return;
}
if (settingsStore$2.answerSettings.autoSaveAnswer) {
try {
if (typeof contentWindow.noSubmit === "function") {
const iframes = document.querySelectorAll("iframe");
iframes.forEach((iframe) => {
if (iframe.contentWindow === contentWindow) {
iframe.removeEventListener("load", handleIframeLoad);
logStore$2.addLog("已移除iframe监听器,防止重复处理", LOG_TYPES.INFO);
}
});
logStore$2.addLog("正在保存章节答案...", LOG_TYPES.INFO);
contentWindow.noSubmit();
await sleep$2(500);
logStore$2.addLog("章节答案已保存", LOG_TYPES.SUCCESS);
}
} catch (error) {
logStore$2.addLog(`保存章节答案失败: ${error.message}`, LOG_TYPES.ERROR);
}
} else {
logStore$2.addLog("已完成答题,请手动保存章节答案", LOG_TYPES.INFO);
}
if (!settingsStore$2.submitSettings.autoSubmitChapter) {
logStore$2.addLog("自动提交已禁用,请手动提交", LOG_TYPES.INFO);
} else {
logStore$2.addLog("正确率不足,不进行提交,请检查答案后手动提交", LOG_TYPES.WARNING);
}
if (!settingsStore$2.submitSettings.autoSubmitChapter) {
try {
if (window._taskCancelled) {
logStore$2.addLog("任务已取消,不执行阻止提交操作", LOG_TYPES.WARNING);
return;
}
if (contentWindow?.document?.forms.length > 0) {
const forms = contentWindow.document.forms;
for (let index = 0; index < forms.length; index += 1) {
forms[index]._originalSubmit = forms[index].submit;
forms[index].submit = function submitDisabled() {
logStore$2.addLog("已阻止自动提交", LOG_TYPES.WARNING);
return false;
};
}
logStore$2.addLog("已禁用自动提交功能", LOG_TYPES.SUCCESS);
if (window._processedIframes) {
const iframes = document.querySelectorAll("iframe");
iframes.forEach((iframe) => {
if (iframe.contentWindow === contentWindow) {
window._processedIframes.delete(iframe);
logStore$2.addLog("已移除iframe处理记录,防止重复处理", LOG_TYPES.INFO);
}
});
}
}
} catch (error) {
if (window._taskCancelled) {
logStore$2.addLog("任务已取消", LOG_TYPES.WARNING);
return;
}
logStore$2.addLog(`执行不提交操作失败: ${error.message}`, LOG_TYPES.WARNING);
}
}
}
async function checkForMedia(iframe) {
initStores$2();
return new Promise(async (resolve) => {
try {
if (window._taskCancelled) {
resolve();
return;
}
const signal = window._cancelController?.signal;
signal?.addEventListener("abort", () => resolve(), { once: true });
const doc = await waitForIframeLoad(iframe);
if (!doc || window._taskCancelled) {
resolve();
return;
}
if (iframe.src.includes("api/work")) {
try {
const { decrypt: decrypt2 } = await __vitePreload(async () => {
const { decrypt: decrypt3 } = await Promise.resolve().then(() => fontDecrypt);
return { decrypt: decrypt3 };
}, true ? void 0 : void 0);
if (window._taskCancelled) {
resolve();
return;
}
decrypt2(doc);
logStore$2.addLog("字体解密完成", LOG_TYPES.SUCCESS);
} catch (error) {
logStore$2.addLog(`字体解密失败: ${error.message}`, LOG_TYPES.ERROR);
}
if (window._taskCancelled) {
resolve();
return;
}
try {
await handleWork$1(doc);
} catch (error) {
if (error.message === "Task cancelled" || window._taskCancelled) {
logStore$2.addLog("答题任务已取消", LOG_TYPES.WARNING);
} else {
logStore$2.addLog(`处理作业时出错: ${error.message}`, LOG_TYPES.ERROR);
}
}
resolve();
return;
}
if (settingsStore$2.automationSettings.onlyDoQuestions && !iframe.src.includes("api/work") && !iframe.src.includes("exam")) {
resolve();
return;
}
const hasVideo = iframe.src.includes("video");
const hasAudio = iframe.src.includes("audio");
if ((hasVideo || hasAudio) && !window._taskCancelled) {
const mediaType = hasVideo ? "video" : "audio";
const mediaElement = await waitForElement(doc, mediaType);
if (window._taskCancelled) {
resolve();
return;
}
if (mediaElement) {
await handleMedia(mediaElement, mediaType);
}
}
const docKeywords = ["ppt", "doc", "pptx", "docx", "pdf", "txt", "ppt文档"];
const hasDocument = docKeywords.some((keyword) => iframe.src.includes(keyword));
if (hasDocument && !window._taskCancelled) {
const panviewElement = await waitForElement(doc, "#panView");
if (window._taskCancelled) {
resolve();
return;
}
if (panviewElement) {
await handleDocument(panviewElement);
}
}
resolve();
} catch (error) {
console.error("处理iframe时出错:", error);
resolve();
}
});
}
async function getAllIframes(doc, processedFrames = /* @__PURE__ */ new Set()) {
initStores$2();
if (window._taskCancelled || !doc) {
return [];
}
await waitForPageLoad();
const iframes = Array.from(doc.getElementsByTagName("iframe"));
const allIframes = [];
for (const iframe of iframes) {
if (window._taskCancelled) {
break;
}
if (processedFrames.has(iframe)) {
continue;
}
processedFrames.add(iframe);
const parentClass = iframe.parentElement?.className || "";
if (parentClass.includes("ans-job-finished") && settingsStore$2.automationSettings.skipFinishedTasks) {
continue;
}
allIframes.push(iframe);
try {
const iframeDoc = await waitForIframeLoad(iframe);
if (iframeDoc) {
await waitForPageLoad();
const innerIframes = await getAllIframes(iframeDoc, processedFrames);
allIframes.push(...innerIframes);
}
} catch (error) {
console.error("获取子iframe失败:", error);
}
}
return allIframes;
}
function addIframeLoadListener(iframe) {
iframe.removeEventListener("load", handleIframeLoad);
iframe.addEventListener("load", handleIframeLoad);
}
function cancelCurrentTask() {
initStores$2();
window._taskCancelled = true;
window._isProcessing = false;
if (window._cancelController) {
try {
window._cancelController.abort("Task cancelled");
window._cancelController = new AbortController();
} catch {
}
}
try {
const mediaElements = document.querySelectorAll("video, audio");
mediaElements.forEach((media) => {
try {
if (!media.paused) {
media.pause();
}
if (media._handlePause) {
media.removeEventListener("pause", media._handlePause);
delete media._handlePause;
}
if (media._handleEnded) {
media.removeEventListener("ended", media._handleEnded);
delete media._handleEnded;
}
if (media._monitorInterval) {
clearInterval(media._monitorInterval);
delete media._monitorInterval;
}
if (media._unwatchFn) {
media._unwatchFn();
delete media._unwatchFn;
}
} catch {
}
});
} catch {
}
if (answerStore$2) {
answerStore$2.clearAnswers();
logStore$2.addLog("已清空答题记录", LOG_TYPES.INFO);
}
if (window.gc) {
try {
window.gc();
} catch {
}
}
logStore$2.addLog("已终止之前的任务", LOG_TYPES.WARNING);
}
function checkCancelled() {
if (window._taskCancelled) {
logStore$2.addLog("检测到任务已被取消,终止处理", LOG_TYPES.WARNING);
throw new Error("Task cancelled");
}
}
async function checkAndNavigateToNextChapter() {
initStores$2();
try {
if (window._taskCancelled) {
logStore$2.addLog("任务已被取消,不执行章节跳转", LOG_TYPES.WARNING);
return;
}
if (!settingsStore$2.automationSettings.autoNextChapter) {
return;
}
const nextButton2 = document.querySelector(".nextChapter") || document.querySelector(".next_chapternew") || document.querySelector('[title="下一章"]');
if (!nextButton2) {
logStore$2.addLog("当前已是最后一章,所有任务已完成", LOG_TYPES.SUCCESS);
return;
}
logStore$2.addLog("所有任务完成,准备进入下一章节", LOG_TYPES.INFO);
try {
const signal = window._cancelController?.signal;
await Promise.race([
sleep$2(5e3),
new Promise((_, reject) => {
signal?.addEventListener("abort", () => reject(new Error("Wait aborted")), { once: true });
})
]);
if (window._taskCancelled) {
logStore$2.addLog("任务已取消,取消跳转到下一章", LOG_TYPES.WARNING);
return;
}
nextButton2.click();
logStore$2.addLog("已跳转到下一章节", LOG_TYPES.SUCCESS);
} catch (error) {
if (window._taskCancelled || error.message === "Wait aborted") {
logStore$2.addLog("章节跳转已取消", LOG_TYPES.WARNING);
} else {
logStore$2.addLog(`章节跳转出错: ${error.message}`, LOG_TYPES.ERROR);
}
}
} catch (error) {
if (error.message === "Task cancelled" || window._taskCancelled) {
logStore$2.addLog("跳转操作已取消", LOG_TYPES.WARNING);
return;
}
console.error("跳转到下一章节时出错:", error);
logStore$2.addLog(`跳转到下一章节出错: ${error.message}`, LOG_TYPES.ERROR);
}
}
function clearAllIframeEventListeners() {
try {
const allIframes = Array.from(document.getElementsByTagName("iframe"));
for (const iframe of allIframes) {
iframe.removeEventListener("load", handleIframeLoad);
try {
const doc = iframe.contentDocument || iframe.contentWindow?.document;
if (!doc?.forms) {
continue;
}
for (let index = 0; index < doc.forms.length; index += 1) {
if (doc.forms[index]._originalSubmit) {
doc.forms[index].submit = doc.forms[index]._originalSubmit;
delete doc.forms[index]._originalSubmit;
}
}
} catch {
}
}
} catch (error) {
console.error("清理iframe事件监听器时出错:", error);
}
}
function handlePageChange() {
logStore$2.addLog("页面切换,终止当前任务并重新处理页面", LOG_TYPES.INFO);
cancelCurrentTask();
clearAllIframeEventListeners();
if (window._processedIframes) {
window._processedIframes.clear();
}
if (window._cancelController) {
window._cancelController.abort("Page changed");
window._cancelController = new AbortController();
}
window._taskCancelled = true;
window._isProcessing = false;
setTimeout(() => {
window._taskCancelled = false;
window._isProcessing = false;
try {
const mediaElements = document.querySelectorAll("video, audio");
mediaElements.forEach((media) => {
try {
media.pause();
media.removeEventListener("pause", media._handlePause);
media.removeEventListener("ended", media._handleEnded);
} catch {
}
});
} catch {
}
processPage$2();
}, 3e3);
}
function setupUrlChangeListener() {
window._lastUrl = window.location.href;
window.addEventListener("popstate", () => {
if (window._lastUrl !== window.location.href) {
window._lastUrl = window.location.href;
handlePageChange();
}
});
const urlObserver = new MutationObserver(() => {
if (window._lastUrl !== window.location.href) {
window._lastUrl = window.location.href;
logStore$2.addLog("检测到URL变化,终止当前任务", LOG_TYPES.INFO);
handlePageChange();
}
});
urlObserver.observe(document, {
subtree: true,
childList: true,
attributes: true,
characterData: false
});
window._urlObserver = urlObserver;
window.addEventListener("hashchange", () => {
if (window._lastUrl !== window.location.href) {
window._lastUrl = window.location.href;
logStore$2.addLog("检测到hash变化,终止当前任务", LOG_TYPES.INFO);
handlePageChange();
}
});
}
async function handleIframeLoad(event) {
initStores$2();
if (window._taskCancelled) {
return;
}
const iframe = event.target;
try {
if (iframe.src && iframe.src.includes("api/work")) {
iframe.removeEventListener("load", handleIframeLoad);
return;
}
} catch {
}
logStore$2.addLog("检测到iframe加载,终止当前任务", LOG_TYPES.INFO);
handlePageChange();
}
async function processIframe(iframe) {
initStores$2();
try {
if (window._taskCancelled) {
logStore$2.addLog("任务已被终止,不处理此iframe", LOG_TYPES.WARNING);
return;
}
const parentClass = iframe.parentElement?.className || "";
if (parentClass.includes("ans-job-finished") && settingsStore$2.automationSettings.skipFinishedTasks) {
logStore$2.addLog("发现一个已完成任务点", LOG_TYPES.SUCCESS);
return;
}
addIframeLoadListener(iframe);
if (window._taskCancelled) {
logStore$2.addLog("任务已被终止,不处理媒体", LOG_TYPES.WARNING);
return;
}
await checkForMedia(iframe);
} catch (error) {
if (window._taskCancelled || error.message === "Task cancelled") {
logStore$2.addLog("iframe处理已取消", LOG_TYPES.WARNING);
return;
}
console.error("处理iframe时出错:", error);
}
}
async function processPage$2() {
try {
initStores$2();
const currentUrl = window.location.href;
if (!currentUrl.includes("&mooc2=1") && !currentUrl.includes("?mooc2=1")) {
const separator = currentUrl.includes("?") ? "&" : "?";
window.location.href = `${currentUrl}${separator}mooc2=1`;
return;
}
if (!window._processedIframes) {
window._processedIframes = /* @__PURE__ */ new Set();
}
if (!window._urlObserver) {
setupUrlChangeListener();
}
if (!window._cancelController) {
window._cancelController = new AbortController();
}
if (window._isProcessing) {
logStore$2.addLog("检测到有正在进行的任务,先终止它", LOG_TYPES.WARNING);
cancelCurrentTask();
await sleep$2(1e3);
}
window._taskCancelled = false;
window._isProcessing = true;
answerStore$2?.clearAnswers();
logStore$2.addLog("正在解析任务", LOG_TYPES.INFO);
await waitForPageLoad();
checkCancelled();
const allIframes = await getAllIframes(document);
checkCancelled();
for (const iframe of allIframes) {
if (window._taskCancelled) {
logStore$2.addLog("任务已被取消,终止处理", LOG_TYPES.WARNING);
break;
}
if (!window._processedIframes.has(iframe)) {
window._processedIframes.add(iframe);
await processIframe(iframe);
}
}
if (!window._taskCancelled) {
await checkAndNavigateToNextChapter();
}
window.addEventListener(
"beforeunload",
() => {
cancelCurrentTask();
},
{ once: true }
);
} catch (error) {
if (error.message === "Task cancelled") {
logStore$2?.addLog("页面处理已取消", LOG_TYPES.WARNING);
return;
}
console.error("处理页面时出错:", error);
} finally {
if (window._taskCancelled) {
window._isProcessing = false;
}
}
}
function handleChapterPage() {
initStores$2();
return processPage$2();
}
const TEXT_EXPERIENCE_NEW = "体验新版";
function experienceNewHandler() {
const experienceLinks = Array.from(document.querySelectorAll(".experience")).filter(
(element) => element.textContent.includes(TEXT_EXPERIENCE_NEW)
);
if (experienceLinks.length > 0) {
experienceLinks[0].click();
console.log('已点击"体验新版"按钮');
} else {
console.log('未找到"体验新版"按钮');
}
}
function myCourseHandler() {
const logStore2 = useLogStore();
logStore2.addLog("请进入相关页面学习");
console.log("超星课程页面处理器已执行");
}
let logStore$1;
let answerStore$1;
let settingsStore$1;
const TEXT$1 = {
authInvalid: "授权码未配置或已失效,跳过答题",
authHint: "请在「高级设置」中配置有效的授权码",
noCurrentQuestion: "未找到当前题目",
startQuestion: "开始处理当前题目",
emptyQuestion: "题目内容为空,跳过",
questionType: (type) => `题型:${type}`,
questionTitle: (title) => `题目:${title.substring(0, 50)}${title.length > 50 ? "..." : ""}`,
foundAnswer: (answer) => `找到答案: ${Array.isArray(answer) ? answer.join(",") : answer}`,
notFound: (message) => `未找到答案: ${message}`,
taskStopped: "答题过程中任务被终止",
nextQuestion: "正在进入下一题...",
lastQuestion: "已是最后一道题目",
currentDone: "当前题目已完成(自动进入下一题已关闭)",
questionError: (message) => `处理题目出错: ${message}`,
parsing: "正在解析考试页面",
processed: "当前题目处理完成",
cancelled: "页面处理已取消",
pageError: (message) => `处理错误: ${message}`,
start: "开始处理考试页面",
answered: "已选择答案"
};
function initStores$1() {
if (!logStore$1) {
logStore$1 = useLogStore();
}
if (!answerStore$1) {
answerStore$1 = useAnswerStore();
}
if (!settingsStore$1) {
settingsStore$1 = useSettingsStore();
}
}
function parseQuestion$1(questionElement) {
try {
const titleElement = questionElement.querySelector(".mark_name");
const typeSpan = titleElement?.querySelector(".colorShallow");
if (!titleElement) {
return { type: "", title: "" };
}
let type = "";
if (typeSpan) {
const typeText = typeSpan.textContent;
if (typeText.includes(QUESTION_TYPES.SINGLE)) {
type = QUESTION_TYPES.SINGLE;
} else if (typeText.includes(QUESTION_TYPES.MULTI)) {
type = QUESTION_TYPES.MULTI;
} else if (typeText.includes(QUESTION_TYPES.FILL)) {
type = QUESTION_TYPES.FILL;
} else if (typeText.includes(QUESTION_TYPES.JUDGE)) {
type = QUESTION_TYPES.JUDGE;
} else if (typeText.includes(QUESTION_TYPES.ESSAY)) {
type = QUESTION_TYPES.ESSAY;
}
}
let title = titleElement.innerHTML.replace(/^\d+\./, "").replace(/]*class="colorShallow"[^>]*>[\s\S]*?<\/span>/g, "").trim();
title = removeHtml(title);
return { type, title };
} catch {
return { type: "", title: "" };
}
}
function parseOptions$1(questionElement) {
try {
const { type } = parseQuestion$1(questionElement);
const stemAnswer = questionElement.querySelector(".stem_answer");
if (!stemAnswer) {
return [];
}
if (type === QUESTION_TYPES.SINGLE || type === QUESTION_TYPES.MULTI || type === QUESTION_TYPES.JUDGE) {
return Array.from(stemAnswer.querySelectorAll(".clearfix.answerBg, .clearfix.singleoption")).map((option) => ({
value: option.querySelector("[data]")?.getAttribute("data") || "",
text: option.querySelector(".answer_p") ? removeHtml(option.querySelector(".answer_p").innerHTML) : ""
}));
}
return [];
} catch {
return [];
}
}
async function handleSingleChoice$1(questionElement, answer) {
const stemAnswer = questionElement.querySelector(".stem_answer");
const options = Array.from(stemAnswer?.querySelectorAll(".clearfix.answerBg, .clearfix.singleoption") || []);
const target = options.find((option) => getOptionValue(option) === answer);
if (target && !isOptionSelected(target)) {
target.click();
logStore$1.addLog(`${TEXT$1.answered}: ${answer}`, LOG_TYPES.SUCCESS);
}
}
async function handleMultipleChoice$1(questionElement, answer) {
const answers = normalizeAnswers(answer);
if (!answers.length) {
return;
}
const stemAnswer = questionElement.querySelector(".stem_answer");
const options = Array.from(stemAnswer?.querySelectorAll(".clearfix.answerBg") || []);
await clearSelectedOptions(options, answers);
for (const option of options) {
const value = getOptionValue(option);
if (answers.includes(value) && !isOptionSelected(option)) {
option.click();
}
}
if (areOptionsSelected(options, answers)) {
logStore$1.addLog(`${TEXT$1.answered}: ${answers.join(",")}`, LOG_TYPES.SUCCESS);
}
}
async function handleJudgment$1(questionElement, answer) {
const stemAnswer = questionElement.querySelector(".stem_answer");
const options = Array.from(stemAnswer?.querySelectorAll(".clearfix.answerBg, .clearfix.singleoption") || []);
const target = options.find((option) => {
const value = getOptionValue(option);
const text2 = option.querySelector(".answer_p")?.textContent?.trim() || "";
return answer === value || answer === "true" && (value === "true" || JUDGE_TRUE_WORDS.some((word) => text2.includes(word))) || answer === "false" && (value === "false" || JUDGE_FALSE_WORDS.some((word) => text2.includes(word)));
});
if (target && !isOptionSelected(target)) {
target.click();
logStore$1.addLog(`${TEXT$1.answered}: ${answer}`, LOG_TYPES.SUCCESS);
}
}
async function handleFillBlank$1(questionElement, answer) {
const wrote = await fillRichTextAnswers(questionElement, answer);
if (wrote) {
logStore$1.addLog(TEXT$1.answered, LOG_TYPES.SUCCESS);
}
}
async function handleEssay$1(questionElement, answer) {
const formattedAnswer = getAnswerValueAt(answer);
if (!hasAnswerValue(formattedAnswer)) {
return;
}
const target = questionElement.querySelector("textarea, [id^='answerEditor']");
if (!target) {
return;
}
const wrote = await setRichTextAnswer({ element: target, answer: formattedAnswer });
if (wrote) {
logStore$1.addLog(TEXT$1.answered, LOG_TYPES.SUCCESS);
}
}
async function goToNextExamQuestion(doc) {
if (!settingsStore$1.automationSettings.autoNextExamQuestion) {
logStore$1.addLog(TEXT$1.currentDone, LOG_TYPES.INFO);
return false;
}
const nextButton2 = doc.querySelector(".nextDiv a.jb_btn");
if (nextButton2) {
const buttonText = nextButton2.textContent.trim();
const onclickText = nextButton2.getAttribute("onclick") || "";
const isNextButton = buttonText.includes("下一题") || buttonText.includes("下一") || /next|goNext|questionNext/i.test(onclickText);
if (isNextButton) {
logStore$1.addLog(TEXT$1.nextQuestion, LOG_TYPES.INFO);
await new Promise((resolve) => setTimeout(resolve, 1e3));
nextButton2.click();
return true;
}
}
logStore$1.addLog(TEXT$1.lastQuestion, LOG_TYPES.INFO);
return false;
}
async function handleExam(doc) {
initStores$1();
if (!settingsStore$1.cardInfo || settingsStore$1.cardInfo.status !== 1) {
logStore$1.addLog(TEXT$1.authInvalid, LOG_TYPES.ERROR);
logStore$1.addLog(TEXT$1.authHint, LOG_TYPES.WARNING);
return;
}
if (window._taskCancelled) {
return;
}
const currentQuestion = doc.querySelector(".whiteDiv.questionLi");
if (!currentQuestion) {
logStore$1.addLog(TEXT$1.noCurrentQuestion, LOG_TYPES.WARNING);
return;
}
logStore$1.addLog(TEXT$1.startQuestion, LOG_TYPES.INFO);
try {
const { type, title } = parseQuestion$1(currentQuestion);
if (!title) {
logStore$1.addLog(TEXT$1.emptyQuestion, LOG_TYPES.WARNING);
return;
}
const options = parseOptions$1(currentQuestion);
logStore$1.addLog(TEXT$1.questionType(type), LOG_TYPES.INFO);
logStore$1.addLog(TEXT$1.questionTitle(title), LOG_TYPES.INFO);
const { isCorrect, answer, title: fullTitle, message, status, originalAnswer } = await checkAnswer(
{ type, title },
options
);
if (window._taskCancelled) {
return;
}
const displayAnswer = isCorrect ? answer : originalAnswer || message;
answerStore$1.addAnswer(fullTitle, displayAnswer, type, status, originalAnswer);
if (!isCorrect) {
if (status === "not_found") {
logStore$1.addLog(TEXT$1.notFound(message), LOG_TYPES.WARNING);
}
await goToNextExamQuestion(doc);
return;
}
logStore$1.addLog(TEXT$1.foundAnswer(answer), LOG_TYPES.SUCCESS);
if (type === QUESTION_TYPES.SINGLE) {
await handleSingleChoice$1(currentQuestion, answer);
} else if (type === QUESTION_TYPES.MULTI) {
await handleMultipleChoice$1(currentQuestion, answer);
} else if (type === QUESTION_TYPES.JUDGE) {
await handleJudgment$1(currentQuestion, answer);
} else if (type === QUESTION_TYPES.FILL) {
await handleFillBlank$1(currentQuestion, answer);
} else if (type === QUESTION_TYPES.ESSAY) {
await handleEssay$1(currentQuestion, answer);
}
if (window._taskCancelled) {
logStore$1.addLog(TEXT$1.taskStopped, LOG_TYPES.WARNING);
return;
}
await new Promise((resolve) => setTimeout(resolve, 800));
await goToNextExamQuestion(doc);
} catch (error) {
logStore$1.addLog(TEXT$1.questionError(error.message), LOG_TYPES.ERROR);
if (window._taskCancelled || error.message === "Task cancelled") {
return;
}
}
}
async function processPage$1() {
try {
initStores$1();
if (!window._cancelController) {
window._cancelController = new AbortController();
}
if (window._isProcessing) {
window._cancelController.abort("Task cancelled");
window._cancelController = new AbortController();
window._taskCancelled = false;
await new Promise((resolve) => setTimeout(resolve, 500));
}
window._taskCancelled = false;
window._isProcessing = true;
logStore$1.addLog(TEXT$1.parsing, LOG_TYPES.INFO);
await handleExam(document);
window._isProcessing = false;
logStore$1.addLog(TEXT$1.processed, LOG_TYPES.SUCCESS);
} catch (error) {
if (error.message === "Task cancelled") {
logStore$1?.addLog(TEXT$1.cancelled, LOG_TYPES.WARNING);
} else {
console.error("Exam page error:", error);
logStore$1?.addLog(TEXT$1.pageError(error.message), LOG_TYPES.ERROR);
}
window._isProcessing = false;
}
}
function handleExamPage() {
initStores$1();
logStore$1.addLog(TEXT$1.start, LOG_TYPES.INFO);
processPage$1().catch((error) => {
console.error("Exam page runner error:", error);
logStore$1.addLog(TEXT$1.pageError(error.message), LOG_TYPES.ERROR);
});
}
let logStore;
let answerStore;
let settingsStore;
const TEXT = {
authInvalid: "授权码未配置或已失效,跳过答题",
authHint: "请在「高级设置」中配置有效的授权码",
questionAreaMissing: "未找到题目区域",
questionsFound: (groupCount, totalCount) => `找到${groupCount}个题目类型,共${totalCount}道题`,
questionProgress: (index, type) => `正在完成第${index}题,题型:${type}`,
notFound: "未找到答案,跳过此题",
questionError: (message) => `处理题目出错: ${message}`,
completeRate: (rate) => `答题完成,正确率: ${rate}%`,
savingHomework: "正在保存作业...",
saveButtonMissing: "未找到保存函数或按钮",
saved: "作业已保存",
saveFailed: (message) => `保存作业失败: ${message}`,
saveManual: "已完成答题,请手动保存作业",
submiting: "正在提交作业...",
submitButtonMissing: "未找到提交按钮",
submitFailed: (message) => `提交失败: ${message}`,
parsing: "正在解析作业页面",
processed: "作业页面处理完成",
cancelled: "页面处理已取消",
pageError: (message) => `处理错误: ${message}`,
start: "开始处理作业页面"
};
function initStores() {
if (!logStore) {
logStore = useLogStore();
}
if (!answerStore) {
answerStore = useAnswerStore();
}
if (!settingsStore) {
settingsStore = useSettingsStore();
}
}
function parseQuestion(questionElement) {
try {
const titleElement = questionElement.querySelector(".mark_name");
const typeElement = questionElement.getAttribute("typeName");
if (!titleElement) {
return { type: "", title: "" };
}
let title = titleElement.innerHTML.replace(/^\d+\./, "").replace(/]*>\([^)]+\)<\/span>/g, "").trim();
title = removeHtml(title);
return {
type: typeElement || "",
title
};
} catch {
return { type: "", title: "" };
}
}
function parseOptions(questionElement) {
try {
const type = questionElement.getAttribute("typeName");
const stemAnswer = questionElement.querySelector(".stem_answer");
if (!stemAnswer) {
return [];
}
if (type === QUESTION_TYPES.SINGLE || type === QUESTION_TYPES.JUDGE) {
return Array.from(stemAnswer.querySelectorAll(".clearfix.answerBg")).map((option) => ({
value: option.querySelector(".num_option")?.getAttribute("data") || "",
text: option.querySelector(".answer_p") ? removeHtml(option.querySelector(".answer_p").innerHTML) : ""
}));
}
if (type === QUESTION_TYPES.MULTI) {
return Array.from(stemAnswer.querySelectorAll(".clearfix.answerBg")).map((option) => ({
value: option.querySelector(".num_option_dx")?.getAttribute("data") || "",
text: option.querySelector(".answer_p") ? removeHtml(option.querySelector(".answer_p").innerHTML) : ""
}));
}
return [];
} catch {
return [];
}
}
async function handleSingleChoice(questionElement, answer) {
if (!answer) {
return;
}
const stemAnswer = questionElement.querySelector(".stem_answer");
if (!stemAnswer) {
return;
}
const options = Array.from(stemAnswer.querySelectorAll(".clearfix.answerBg"));
const target = options.find((option) => getOptionValue(option, ".num_option") === answer);
if (target && !isOptionSelected(target)) {
target.click();
}
}
async function handleMultipleChoice(questionElement, answer) {
const answers = normalizeAnswers(answer);
if (!answers.length) {
return;
}
const stemAnswer = questionElement.querySelector(".stem_answer");
if (!stemAnswer) {
return;
}
const options = Array.from(stemAnswer.querySelectorAll(".clearfix.answerBg"));
await clearSelectedOptions(options, answers, ".num_option_dx");
for (const option of options) {
const value = getOptionValue(option, ".num_option_dx");
if (answers.includes(value) && !isOptionSelected(option)) {
option.click();
}
}
return areOptionsSelected(options, answers, ".num_option_dx");
}
async function handleJudgment(questionElement, answer) {
if (!answer) {
return;
}
const stemAnswer = questionElement.querySelector(".stem_answer");
if (!stemAnswer) {
return;
}
const options = Array.from(stemAnswer.querySelectorAll(".clearfix.answerBg"));
const target = options.find((option) => {
const value = getOptionValue(option, ".num_option");
const text2 = option.querySelector(".answer_p")?.textContent?.trim() || "";
return answer === value || answer === "true" && (value === "true" || value === "A" || JUDGE_TRUE_WORDS.some((word) => text2.includes(word))) || answer === "false" && (value === "false" || value === "B" || JUDGE_FALSE_WORDS.some((word) => text2.includes(word)));
});
if (target && !isOptionSelected(target)) {
target.click();
}
}
async function handleFillBlank(questionElement, answer) {
await fillRichTextAnswers(questionElement, answer);
}
async function handleEssay(questionElement, answer) {
const formattedAnswer = getAnswerValueAt(answer);
if (!hasAnswerValue(formattedAnswer)) {
return;
}
const target = questionElement.querySelector("textarea, [id^='answerEditor']");
if (!target) {
return;
}
await setRichTextAnswer({ element: target, answer: formattedAnswer });
}
async function handleWork(doc) {
initStores();
if (!settingsStore.cardInfo || settingsStore.cardInfo.status !== 1) {
logStore.addLog(TEXT.authInvalid, LOG_TYPES.ERROR);
logStore.addLog(TEXT.authHint, LOG_TYPES.WARNING);
return;
}
if (window._taskCancelled) {
return;
}
const questionSections = doc.querySelectorAll(".whiteDiv");
if (!questionSections.length) {
logStore.addLog(TEXT.questionAreaMissing, LOG_TYPES.WARNING);
return;
}
let totalQuestions = 0;
questionSections.forEach((section) => {
totalQuestions += section.querySelectorAll(".questionLi").length;
});
logStore.addLog(TEXT.questionsFound(questionSections.length, totalQuestions), LOG_TYPES.INFO);
let correctCount = 0;
let totalProcessed = 0;
for (const section of questionSections) {
if (window._taskCancelled) {
break;
}
const questions = section.querySelectorAll(".questionLi");
for (const question of questions) {
if (window._taskCancelled) {
break;
}
totalProcessed += 1;
try {
const { type, title } = parseQuestion(question);
if (!title) {
continue;
}
const options = parseOptions(question);
logStore.addLog(TEXT.questionProgress(totalProcessed, type), LOG_TYPES.INFO);
const { isCorrect, answer, title: fullTitle, message, status, originalAnswer } = await checkAnswer(
{ type, title },
options
);
if (window._taskCancelled) {
break;
}
const displayAnswer = isCorrect ? answer : originalAnswer || message;
answerStore.addAnswer(fullTitle, displayAnswer, type, status, originalAnswer);
if (!isCorrect) {
if (status === "not_found") {
logStore.addLog(TEXT.notFound, LOG_TYPES.WARNING);
}
continue;
}
if (type === QUESTION_TYPES.SINGLE) {
await handleSingleChoice(question, answer);
} else if (type === QUESTION_TYPES.MULTI) {
await handleMultipleChoice(question, answer);
} else if (type === QUESTION_TYPES.JUDGE) {
await handleJudgment(question, answer);
} else if (type === QUESTION_TYPES.FILL) {
await handleFillBlank(question, answer);
} else if (type === QUESTION_TYPES.ESSAY) {
await handleEssay(question, answer);
}
correctCount += 1;
} catch (error) {
logStore.addLog(TEXT.questionError(error.message), LOG_TYPES.ERROR);
if (window._taskCancelled || error.message === "Task cancelled") {
break;
}
}
}
}
if (window._taskCancelled) {
return;
}
const correctRate = totalProcessed > 0 ? correctCount / totalProcessed * 100 : 0;
logStore.addLog(TEXT.completeRate(correctRate.toFixed(2)), LOG_TYPES.SUCCESS);
if (settingsStore.answerSettings.autoSaveAnswer) {
try {
logStore.addLog(TEXT.savingHomework, LOG_TYPES.INFO);
await new Promise((resolve) => setTimeout(resolve, 1e3));
if (typeof window.saveWork === "function") {
window.saveWork();
} else if (typeof saveWork === "function") {
saveWork();
} else {
const saveButton = doc.querySelector('a[onclick*="saveWork"]');
if (!saveButton) {
throw new Error(TEXT.saveButtonMissing);
}
saveButton.click();
}
logStore.addLog(TEXT.saved, LOG_TYPES.SUCCESS);
} catch (error) {
logStore.addLog(TEXT.saveFailed(error.message), LOG_TYPES.ERROR);
}
} else {
logStore.addLog(TEXT.saveManual, LOG_TYPES.INFO);
}
if (settingsStore.submitSettings.autoSubmitHomework && correctRate >= settingsStore.submitSettings.correctRateThreshold) {
try {
const submitButton = doc.querySelector(".Btn_blue_1");
if (submitButton) {
logStore.addLog(TEXT.submiting, LOG_TYPES.INFO);
submitButton.click();
} else {
logStore.addLog(TEXT.submitButtonMissing, LOG_TYPES.WARNING);
}
} catch (error) {
logStore.addLog(TEXT.submitFailed(error.message), LOG_TYPES.ERROR);
}
}
}
async function processPage() {
try {
initStores();
if (!window._cancelController) {
window._cancelController = new AbortController();
}
if (window._isProcessing) {
window._cancelController.abort("Task cancelled");
window._cancelController = new AbortController();
window._taskCancelled = false;
await new Promise((resolve) => setTimeout(resolve, 500));
}
window._taskCancelled = false;
window._isProcessing = true;
answerStore?.clearAnswers();
logStore.addLog(TEXT.parsing, LOG_TYPES.INFO);
await handleWork(document);
window._isProcessing = false;
logStore.addLog(TEXT.processed, LOG_TYPES.SUCCESS);
} catch (error) {
if (error.message === "Task cancelled") {
logStore?.addLog(TEXT.cancelled, LOG_TYPES.WARNING);
} else {
console.error("Homework page error:", error);
logStore?.addLog(TEXT.pageError(error.message), LOG_TYPES.ERROR);
}
window._isProcessing = false;
}
}
function handleHomeworkPage() {
initStores();
logStore.addLog(TEXT.start, LOG_TYPES.INFO);
processPage().catch((error) => {
console.error("Homework page runner error:", error);
logStore.addLog(TEXT.pageError(error.message), LOG_TYPES.ERROR);
});
}
const routes = [
{
pattern: /\.chaoxing\.com\/(mooc-ans\/)?mycourse\/studentstudy/,
handler: handleChapterPage,
description: "超星章节"
},
{
pattern: /\.chaoxing\.com\/mooc-ans\/mooc2\/work\/dowork/,
handler: handleHomeworkPage,
description: "超星作业"
},
{
pattern: /mooc1\.chaoxing\.com\/mycourse\/studentcourse/,
handler: experienceNewHandler,
description: "点击体验新版"
},
{
pattern: /\.chaoxing\.com\/mooc2-ans\/mycourse\/stu\?/,
handler: myCourseHandler,
description: "超星课程页面"
},
{
pattern: /\.chaoxing\.com\/exam-ans\/exam\/test\/reVersionTestStartNew/,
handler: handleExamPage,
description: "超星考试"
}
];
function isMatchingUrl(pattern) {
const currentUrl = _unsafeWindow.location.href;
console.log("currentUrl", currentUrl);
if (pattern instanceof RegExp) {
return pattern.test(currentUrl);
}
return currentUrl.includes(pattern);
}
const _hoisted_1$1 = { id: "app" };
const _hoisted_2$1 = { class: "app-container" };
const _sfc_main$1 = {
__name: "App",
setup(__props) {
const visible2 = vue.ref(false);
const processedUrls = /* @__PURE__ */ new Set();
async function checkRouteMatch() {
const currentUrl = window.location.href;
if (processedUrls.has(currentUrl)) {
console.log(`URL已处理过,跳过: ${currentUrl}`);
return;
}
for (const route of routes) {
if (isMatchingUrl(route.pattern)) {
console.log(`匹配到路由: ${route.description},显示浮窗`);
visible2.value = true;
processedUrls.add(currentUrl);
try {
if (typeof route.handler === "function") {
await route.handler();
}
} catch (error) {
console.error("执行页面处理器失败:", error);
}
return;
}
}
console.log("未匹配到任何路由,隐藏浮窗");
visible2.value = false;
}
function setupUrlObserver() {
const observer = new MutationObserver(() => {
const currentUrl = window.location.href;
if (window._lastUrl !== currentUrl) {
window._lastUrl = currentUrl;
console.log("URL已变化,重新检查路由匹配");
checkRouteMatch();
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
window._urlChangeObserver = observer;
window._lastUrl = window.location.href;
}
vue.onMounted(() => {
checkRouteMatch();
setupUrlObserver();
});
vue.onUnmounted(() => {
window._urlChangeObserver?.disconnect();
});
return (_ctx, _cache) => {
return vue.openBlock(), vue.createElementBlock("div", _hoisted_1$1, [
vue.createElementVNode("div", _hoisted_2$1, [
visible2.value ? (vue.openBlock(), vue.createBlock(FloatingWindow, { key: 0 })) : vue.createCommentVNode("", true)
])
]);
};
}
};
function isZhihuishuHost(hostname) {
const host = String(hostname).toLowerCase();
return host === "zhihuishu.com" || host.endsWith(".zhihuishu.com") || host === "hike-teaching-center.polymas.com";
}
function isStudyGuide(url) {
try {
const parsed = new URL(url);
if (!isZhihuishuHost(parsed.hostname)) return false;
return parsed.hostname === "www.zhihuishu.com" && parsed.pathname === "/" || parsed.hostname === "onlineweb.zhihuishu.com" && parsed.pathname.startsWith("/onlinestuh5") || parsed.hostname === "wisdom-mooc.zhihuishu.com" && parsed.pathname.startsWith("/study/analysis");
} catch {
return false;
}
}
function createRuntime({ controller = new AbortController(), settings, log: log2, pageWindow = window, document: document2 = pageWindow.document, answerPopup: answerPopup2 }) {
const { signal } = controller;
const taskUrl = pageWindow.location.href;
const cleanups = /* @__PURE__ */ new Set();
const checkActive = () => {
if (pageWindow.location.href !== taskUrl) controller.abort();
if (signal.aborted) throw new DOMException("页面任务已停止", "AbortError");
};
function onCleanup(fn) {
if (signal.aborted) fn();
else cleanups.add(fn);
return () => cleanups.delete(fn);
}
signal.addEventListener("abort", () => {
for (const cleanup of cleanups) {
try {
cleanup();
} catch (error) {
console.warn("智慧树任务清理失败", error);
}
}
cleanups.clear();
}, { once: true });
function sleep2(ms) {
checkActive();
return new Promise((resolve, reject) => {
const abort = () => {
clearTimeout(timer);
reject(new DOMException("页面任务已停止", "AbortError"));
};
const timer = setTimeout(() => {
signal.removeEventListener("abort", abort);
try {
checkActive();
resolve();
} catch (error) {
reject(error);
}
}, Math.max(0, ms));
signal.addEventListener("abort", abort, { once: true });
});
}
async function waitFor(predicate, { timeout = 2e4, interval = 250 } = {}) {
const deadline = Date.now() + timeout;
while (true) {
checkActive();
const result = await predicate();
checkActive();
if (result) return result;
if (Date.now() >= deadline) return null;
await sleep2(Math.min(interval, Math.max(0, deadline - Date.now())));
}
}
function isVisible(element) {
if (!element?.isConnected || element.hidden) return false;
const style = pageWindow.getComputedStyle(element);
if (style.display === "none" || style.visibility === "hidden") return false;
return element.getClientRects().length > 0;
}
const hasCaptcha = () => [...document2.querySelectorAll(".yidun_popup")].some(isVisible);
let captchaNotified = false;
const writeLog = (message, type = "info") => {
if (signal.aborted) return;
const escaped = String(message).replace(/[&<>"']/g, (char) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[char]);
log2(escaped, type === "warn" ? "warning" : type);
};
async function waitForCaptcha() {
checkActive();
if (!hasCaptcha()) return;
if (!captchaNotified) {
captchaNotified = true;
writeLog("智慧树出现验证码,请在网页中完成验证,完成后继续。", "warning");
}
while (hasCaptcha()) await sleep2(500);
checkActive();
if (captchaNotified) {
captchaNotified = false;
writeLog("验证已完成,继续当前任务。");
}
}
const ctx = { signal, cancel: () => controller.abort(), settings, log: writeLog, pageWindow, document: document2, sleep: sleep2, waitFor, onCleanup, checkActive, isVisible, waitForCaptcha };
ctx.answerPopup = (root, profile) => answerPopup2?.(ctx, root, profile) ?? Promise.resolve(false);
return ctx;
}
const profiles = [
{ id: "hike-v2", name: "AI 教学空间", hosts: ["hike-teaching-center.polymas.com"], test: (u) => /\/stu-hike\/agent-course-full\/.*\/stu\/(course-home|study)/.test(u.pathname), task: ".el-tree-node", current: ".is-current", done: "label.success", media: "video" },
{ id: "hike", name: "AI 教学中心", hosts: ["hike-teaching-center.polymas.com"], test: (u) => /\/tools-hike\/studentStudyResource|\/stu-hike\/agent-course-hike\//.test(u.pathname), task: ".source-icon", current: ".active-file", done: "i.select", media: "video" },
{ id: "fusion", name: "智慧课程", hosts: ["fusioncourseh5.zhihuishu.com"], test: (u) => /\/stuStudy/.test(u.pathname), task: ".resources-item,.clearfix.video", current: ".active,.activeNode,.current_play", done: ".isFinish,.progress-num", media: "video" },
{ id: "wisdom", name: "新智慧共享课", hosts: ["studywisdomh5.zhihuishu.com"], test: (u) => /\/study\/index/.test(u.pathname), task: ".chapter-content .chapter-item", current: ".current", done: ".finish-icon", media: "video" },
{ id: "wisdom-v2", name: "新智慧学习", hosts: ["wisdom-mooc.zhihuishu.com"], test: (u) => /\/study\/(index|analysis)/.test(u.pathname), task: ".chapter-content .chapter-item", current: ".current", done: ".finish-icon", media: "video" },
{ id: "smart", name: "新形态课程", hosts: ["smartcoursestudent.zhihuishu.com", "ai-smart-course-student-pro.zhihuishu.com"], test: (u) => /\/(learnPage|singleCourse)/.test(u.pathname), task: "[class*='card-container']", current: ".active", done: ".finished-icon", media: "video" },
{ id: "plus", name: "新共享课", hosts: ["studyplush5.zhihuishu.com"], test: () => true, task: ".child-main", current: ".current", done: ".finish-icon", media: "video" },
{ id: "xnk", name: "校内课", hosts: ["www.zhihuishu.com", "zhihuishu.com"], test: (u) => /\/aidedteaching\/sourceLearning/.test(u.pathname), task: ".file-item", current: ".active", done: ".icon-finish", media: "#mediaPlayer,video", noRate: true },
{ id: "legacy", name: "共享课", hosts: ["studyvideoh5.zhihuishu.com"], test: () => true, task: ".clearfix.video", current: ".current_play", done: ".time_icofinish", media: "video" }
];
function resolveStudyProfile(input = globalThis.location?.href) {
if (!input) return null;
let url;
try {
url = new URL(input, globalThis.location?.href);
} catch {
return null;
}
const host = url.hostname.toLowerCase();
return profiles.find((p) => (p.hosts.includes(host) || p.id === "xnk" && host.endsWith(".zhihuishu.com")) && p.test(url)) || null;
}
async function clickElement(ctx, element) {
ctx.checkActive?.();
if (!element || element.disabled || element.isConnected === false) return false;
if (ctx.click) await ctx.click(element);
else element.click();
ctx.checkActive?.();
return true;
}
const sleep$1 = (ctx, ms) => ctx.sleep ? ctx.sleep(ms) : new Promise((r) => setTimeout(r, ms));
const visible$2 = (ctx, el) => !!el && (ctx.isVisible ? ctx.isVisible(el) : el.isConnected);
const text = (el) => (el?.textContent || "").replace(/\s+/g, " ").trim();
function mediaOf(ctx, selector = "video") {
const root = ctx.document || document;
return Array.from(root.querySelectorAll(selector)).find((m) => typeof m.play === "function" && typeof m.pause === "function" && (m.currentSrc || m.src) && visible$2(ctx, m)) || null;
}
function taskElements(doc, profile) {
let list = Array.from(doc.querySelectorAll(profile.task));
if (profile.id === "hike" && profile.task === ".source-icon") list = list.map((e) => e.parentElement?.parentElement).filter(Boolean);
if (profile.id === "hike-v2") list = list.filter((e) => !e.querySelector(".el-tree-node__children") || e.querySelector(".el-tree-node__children")?.children.length === 0);
if (profile.id === "fusion") {
const resources = Array.from(doc.querySelectorAll(".resources-item"));
if (resources.length) list = resources;
}
if (profile.id === "wisdom" || profile.id === "wisdom-v2") {
const expanded = [];
for (const item of list) {
const children = item.querySelectorAll(".chapter-content-second");
expanded.push(...children.length ? Array.from(children) : [item]);
}
list = expanded;
}
if (profile.id === "plus") list = list.filter((e) => e.querySelector(".child-time") || e.parentElement?.querySelector(".child-time"));
if (profile.id === "smart") {
const cards = Array.from(doc.querySelectorAll("[class*='card-container']"));
if (cards.length) list = cards;
}
if (profile.id === "wisdom-v2") {
doc.querySelectorAll(".chapter-wrapper.hidden .collapse-box").forEach((el) => el.click());
doc.querySelectorAll(".el-collapse-item__wrap").forEach((el) => {
el.style.display = "";
});
}
return [...new Set(list)];
}
function isCurrent(el, profile) {
return el.matches(profile.current) || !!el.querySelector(profile.current);
}
function isDone(el, profile) {
if (!profile.done) return false;
if (profile.id === "fusion" && el.querySelector(".progress-num")) return /100%/.test(text(el.querySelector(".progress-num")));
if (profile.id === "fusion") {
const progress = text(el.querySelector(".resource-text"));
const match = progress.replace("必学", "").match(/(\d+)\s*\/\s*(\d+)/);
if (match) return Number(match[1]) >= Number(match[2]);
}
return !!el.querySelector(profile.done) || el.matches(profile.done) || profile.id === "plus" && !!el.parentElement?.querySelector(profile.done);
}
function isQuestionTask(el) {
const value = `${text(el)} ${el.className || ""}`;
return /题|作业|测试|考试|问答|exercise|exam|question/i.test(value);
}
function nextTask(ctx, profile, settings, advance) {
const doc = ctx.document || document;
const original = taskElements(doc, profile);
const currentIndex = original.findIndex((e) => isCurrent(e, profile));
let list = original;
if (settings?.automationSettings?.onlyDoQuestions) list = list.filter(isQuestionTask);
if (settings?.automationSettings?.skipFinishedTasks !== false) list = list.filter((e) => !isDone(e, profile));
if (currentIndex >= 0) {
const next = list.find((e) => original.indexOf(e) >= currentIndex + (advance ? 1 : 0));
if (next) return next;
if (profile.id === "fusion") {
const chapters = Array.from(doc.querySelectorAll(".clearfix.video"));
const chapterIndex = chapters.findIndex((e) => isCurrent(e, profile));
const nextChapter = chapters.slice(Math.max(0, chapterIndex + 1)).find((e) => !isDone(e, profile));
if (nextChapter) return nextChapter;
}
if (profile.id === "smart") {
const sections = Array.from(doc.querySelectorAll(".section-item-collapse-info"));
const currentSection = sections.find((e) => e.classList.contains("active") || e.closest(".active"));
const start = Math.max(0, sections.indexOf(currentSection));
for (const section of sections.slice(start + 1)) {
const p = text(section.querySelector(".collapse-info-progress .progress-text"));
const m = p.replace("必学", "").match(/(\d+)\s*\/\s*(\d+)/);
if (m && Number(m[1]) < Number(m[2])) return section;
}
}
return null;
}
if (list.length) return list[0];
if (profile.id === "smart") {
const sections = Array.from(doc.querySelectorAll(".section-item-collapse-info"));
const currentSection = sections.find((e) => e.classList.contains("active") || e.closest(".active"));
const start = Math.max(-1, sections.indexOf(currentSection));
for (const section of sections.slice(start + 1)) {
const p = text(section.querySelector(".collapse-info-progress .progress-text"));
const m = p.replace("必学", "").match(/(\d+)\s*\/\s*(\d+)/);
if (m && Number(m[1]) < Number(m[2])) return section;
}
}
return null;
}
async function clickTask(ctx, task) {
if (!task) return false;
const clickable = task.matches("button,a,[role=button]") ? task : task.querySelector(".common-text,.file-name,.child-main,.title-box,[role=button],a,button") || task;
clickable.scrollIntoView?.({ block: "center" });
await clickElement(ctx, clickable);
return true;
}
function popup(ctx) {
const doc = ctx.document || document;
return [".yidun_popup", "#playTopic-dialog", ".ai-test-question-wrapper", ".ai-class-exercise-dialog", ".masterylevel-body"].map((s) => doc.querySelector(s)).find((e) => visible$2(ctx, e));
}
function scriptWarning(ctx) {
const doc = ctx.document || document;
const candidates = [
".el-message-box__wrapper[role=alertdialog]",
"[role=alertdialog]",
".el-message-box__wrapper",
".el-message-box"
];
return candidates.flatMap((selector) => [...doc.querySelectorAll(selector)]).find((el) => {
if (!visible$2(ctx, el)) return false;
const value = text(el);
return /异常脚本|检测到脚本|关闭脚本|脚本异常/.test(value);
}) || null;
}
function blockForScriptWarning(ctx, video) {
ctx.studyBlocked = true;
video?.pause();
ctx.log?.("页面提示检测到异常脚本,已暂停自动学习;请处理页面提示后刷新或重新进入章节。", "warn");
ctx.cancel?.();
}
function rateSelector(rate) {
const parsed = Number(rate);
if (!Number.isFinite(parsed) || parsed <= 0) return [];
const normalized2 = String(parsed);
return parsed === 1 ? ["1.0", "1"] : [normalized2, String(rate)];
}
async function switchPlaybackRate(ctx, profile, rate) {
if (profile.noRate) return false;
const doc = ctx.document || document;
const values = rateSelector(rate);
if (!values.length) return false;
if (["legacy", "plus"].includes(profile.id) && Number(rate) > 1.8) {
ctx.log?.("此共享课检测超过 1.8 倍的播放速度,保留页面当前倍速。", "warn");
return false;
}
let controlsBar = doc.querySelector(".controlsBar");
let speedList = doc.querySelector(".speedList");
if ((!controlsBar || !speedList) && ctx.waitFor) {
await ctx.waitFor(() => doc.querySelector(".controlsBar") && doc.querySelector(".speedList"), {
timeout: 2e3,
interval: 150
});
controlsBar = doc.querySelector(".controlsBar");
speedList = doc.querySelector(".speedList");
}
if (!controlsBar || !speedList) {
if (Number(rate) !== 1) ctx.log?.(`页面未提供可用倍速菜单,保留页面当前倍速(请求 ${rate} 倍)。`, "warn");
return false;
}
const controlsDisplay = controlsBar.style.display;
const speedDisplay = speedList.style.display;
controlsBar.style.display = "block";
speedList.style.display = "block";
try {
let option = null;
for (const value of values) {
option = speedList.querySelector(`[rate="${value}"]`);
if (option) break;
}
if (!option) {
ctx.log?.(`倍速菜单未提供 ${rate} 倍,保留页面当前倍速。`, "warn");
return false;
}
if (!option.classList.contains("active")) await clickElement(ctx, option);
return true;
} finally {
controlsBar.style.display = controlsDisplay;
speedList.style.display = speedDisplay;
}
}
async function pauseForPopup(ctx, profile, video) {
const root = popup(ctx);
if (!root) return true;
video?.pause();
ctx.log?.("检测到学习弹窗/验证码,已暂停;请完成后继续。", "warn");
let handled = false;
if (typeof ctx.answerPopup === "function" && !root.matches(".yidun_popup")) {
try {
handled = !!await ctx.answerPopup(root, profile);
} catch (error) {
ctx.log?.(`弹窗处理失败:${error.message}`, "warn");
}
}
if (!handled && typeof ctx.waitForCaptcha === "function" && root.matches(".yidun_popup")) await ctx.waitForCaptcha();
while (!ctx.signal?.aborted && popup(ctx)) await sleep$1(ctx, 300);
return !popup(ctx);
}
async function playCurrent(ctx, profile, settings, onEnded) {
const rate = profile.noRate ? 1 : Number(settings?.videoSettings?.playbackRate || 1);
const video = await (ctx.waitFor ? ctx.waitFor(() => mediaOf(ctx, profile.media), { timeout: 15e3, interval: 250 }) : mediaOf(ctx, profile.media));
if (!video) return false;
if (scriptWarning(ctx)) {
blockForScriptWarning(ctx, video);
return false;
}
await switchPlaybackRate(ctx, profile, Number.isFinite(rate) && rate > 0 ? rate : 1);
video.volume = Math.min(1, Math.max(0, Number(settings?.videoSettings?.volume ?? video.volume)));
if (video.ended || video.currentTime >= video.duration) {
try {
video.currentTime = Math.min(1, Math.max(0, video.duration - 0.1));
} catch {
}
}
const signal = ctx.signal;
let done = false;
let popupBusy = false;
let replaced = false;
let blocked = false;
let appliedRate = profile.noRate ? 1 : Number.isFinite(rate) && rate > 0 ? rate : 1;
let rateBusy = false;
let manualPauseUntil = 0;
const markManualPause = (event) => {
if (event.isTrusted) manualPauseUntil = Date.now() + 1200;
};
let removeCleanup = () => {
};
const finish = () => {
if (done) return;
done = true;
cleanup();
};
const onPause = async () => {
if (done || popupBusy || signal?.aborted || video.ended || blocked || replaced) return;
if (scriptWarning(ctx)) {
blocked = true;
blockForScriptWarning(ctx, video);
finish();
return;
}
if (!popup(ctx) && Date.now() < manualPauseUntil) {
manualPauseUntil = 0;
return;
}
popupBusy = true;
try {
if (await pauseForPopup(ctx, profile, video)) {
await sleep$1(ctx, popup(ctx) ? 400 : 1e3);
if (!done && !signal?.aborted && !popup(ctx) && !scriptWarning(ctx)) video.play().catch(() => ctx.log?.("浏览器阻止了自动播放,请手动点击播放。", "warn"));
}
} catch (error) {
if (!signal?.aborted) ctx.log?.(`播放暂停处理失败:${error.message}`, "warn");
} finally {
popupBusy = false;
}
};
const onVideoEnded = () => finish();
const onAbort = () => finish();
const poll = setInterval(() => {
if (signal?.aborted) finish();
else if (!video.isConnected) {
replaced = true;
ctx.studyMediaReplaced = true;
ctx.log?.("检测到视频元素已切换,正在重新读取当前任务。", "info");
finish();
} else if (scriptWarning(ctx)) {
blocked = true;
blockForScriptWarning(ctx, video);
finish();
} else if (popup(ctx) && !popupBusy) {
onPause().catch(() => {
});
} else if (!profile.noRate) {
const nextRateValue = Number(settings?.videoSettings?.playbackRate || 1);
const nextRate = Number.isFinite(nextRateValue) && nextRateValue > 0 ? nextRateValue : 1;
if (nextRate !== appliedRate && !rateBusy) {
appliedRate = nextRate;
rateBusy = true;
switchPlaybackRate(ctx, profile, nextRate).catch((error) => {
if (!signal?.aborted) {
ctx.log?.(`切换倍速失败:${error.message}`, "warn");
blocked = true;
ctx.studyBlocked = true;
video.pause();
ctx.cancel?.();
finish();
}
}).finally(() => {
rateBusy = false;
});
}
}
}, 500);
const player = video.closest?.(".video-player-wrapper,.videoArea,.video-box,.controlsBar") || video;
player.addEventListener("pointerdown", markManualPause, { capture: true });
const cleanup = () => {
clearInterval(poll);
player.removeEventListener("pointerdown", markManualPause, { capture: true });
video.removeEventListener("pause", onPause);
video.removeEventListener("ended", onVideoEnded);
signal?.removeEventListener("abort", onAbort);
removeCleanup();
};
video.addEventListener("pause", onPause);
video.addEventListener("ended", onVideoEnded);
signal?.addEventListener("abort", onAbort, { once: true });
removeCleanup = ctx.onCleanup?.(cleanup) || (() => {
});
popupBusy = true;
try {
await pauseForPopup(ctx, profile, video);
if (!done && !blocked && !replaced && !signal?.aborted && !scriptWarning(ctx)) {
video.play().catch(() => ctx.log?.("浏览器阻止了自动播放,请手动点击播放。", "warn"));
} else if (scriptWarning(ctx)) {
blocked = true;
blockForScriptWarning(ctx, video);
finish();
}
} catch (error) {
cleanup();
throw error;
} finally {
popupBusy = false;
}
await new Promise((resolve) => {
const check = () => done || signal?.aborted ? resolve() : setTimeout(check, 250);
check();
});
if (blocked) return false;
if (replaced) return false;
return true;
}
async function startStudy(ctx, profile = resolveStudyProfile(ctx?.pageWindow?.location?.href || globalThis.location?.href)) {
if (!ctx || !profile) return;
ctx.studyBlocked = false;
ctx.studyMediaReplaced = false;
const pathname = ctx.pageWindow?.location?.pathname || globalThis.location?.pathname || "";
if (profile.id === "wisdom-v2" && /\/study\/analysis/.test(pathname)) {
ctx.log?.("请手动进入学习页面后再开始自动学习。", "info");
return;
}
const settings = ctx.settings || {};
ctx.document || document;
if (profile.id === "smart" && /singleCourse/.test(pathname)) {
ctx.log?.("请先手动点击任意章节,进入学习页面后再开始。", "info");
return;
}
let advance = false;
while (!ctx.signal?.aborted) {
let task = nextTask(ctx, profile, settings, advance);
if (!task && !advance && ctx.waitFor) {
task = await ctx.waitFor(() => nextTask(ctx, profile, settings, false), { timeout: 2e4, interval: 250 });
}
if (!task) {
ctx.log?.("没有检测到可学习的未完成任务。", "info");
return;
}
const currentHasMedia = isCurrent(task, profile) && mediaOf(ctx, profile.media);
if (!currentHasMedia && !await clickTask(ctx, task)) {
ctx.log?.("当前任务无法点击,请手动打开。", "warn");
return;
}
await sleep$1(ctx, 500);
if (profile.id === "smart" && task.matches?.(".section-item-collapse-info")) {
await sleep$1(ctx, 800);
if (settings?.automationSettings?.autoNextChapter === false) return;
advance = false;
continue;
}
const material = [".doc-box", ".ppt-box", ".icon-box.text", ".icon-box.book", ".icon-box.other"].some((s) => {
try {
return !!task.querySelector(s);
} catch {
return false;
}
});
if (material && ["smart", "fusion", "hike", "hike-v2"].includes(profile.id)) {
ctx.log?.("资料任务已打开,准备继续下一任务。", "info");
if (settings?.automationSettings?.autoNextChapter === false) return;
advance = true;
continue;
}
const played = await playCurrent(ctx, profile, settings);
if (!played) {
if (ctx.studyBlocked) return;
if (ctx.studyMediaReplaced) {
ctx.studyMediaReplaced = false;
advance = false;
await sleep$1(ctx, 300);
continue;
}
if (["smart", "fusion", "hike", "hike-v2"].includes(profile.id)) {
ctx.log?.("资料任务已打开,准备继续下一任务。", "info");
if (settings?.automationSettings?.autoNextChapter === false) return;
await sleep$1(ctx, 800);
advance = true;
continue;
}
ctx.log?.("当前任务没有可访问的视频,请手动打开媒体任务后继续。", "warn");
return;
}
if (ctx.signal?.aborted) return;
if (settings?.automationSettings?.autoNextChapter === false) return;
advance = true;
await sleep$1(ctx, 300);
}
}
function isTrustedClickPage(value) {
try {
const url = new URL(value);
return ["https:", "http:"].includes(url.protocol) && !url.username && !url.password && !url.port && ["studyvideoh5.zhihuishu.com", "studyplush5.zhihuishu.com"].includes(url.hostname);
} catch {
return false;
}
}
function createPageClick(ctx, send2 = extensionTrustedClick) {
let queue = Promise.resolve();
async function perform(element) {
ctx.checkActive();
if (!isTrustedClickPage(ctx.pageWindow.location.href)) {
element.click();
return;
}
if (ctx.pageWindow.top !== ctx.pageWindow) throw new Error("请在浏览器顶层页面打开共享课后使用真实点击");
if (!element.isConnected || !ctx.isVisible(element)) throw new Error("点击目标已变化,请刷新课程后重试");
const attribute = `data-cx-click-${Array.from(ctx.pageWindow.crypto.getRandomValues(new Uint8Array(12)), (x) => x.toString(16).padStart(2, "0")).join("")}`;
let observed = false;
const observe = (event) => {
if (event.isTrusted && (event.target === element || element.contains(event.target))) observed = true;
};
const cleanup = () => {
element.removeAttribute(attribute);
ctx.document.removeEventListener("click", observe, true);
};
element.setAttribute(attribute, "");
ctx.document.addEventListener("click", observe, true);
const removeCleanup = ctx.onCleanup(cleanup);
try {
await send2(attribute);
ctx.checkActive();
if (!observed) throw new Error("页面未收到真实点击,请检查目标是否被遮挡");
} catch (error) {
ctx.checkActive();
throw new Error(`真实点击未完成:${error.message}。请安装或更新 CX 扩展并刷新;油猴模式需同时启用扩展`, { cause: error });
} finally {
cleanup();
removeCleanup();
}
}
return (element) => {
const result = queue.catch(() => {
}).then(() => perform(element));
queue = result;
return result;
};
}
const PROFILES = [
{
id: "gxk",
name: "共享课作业/考试",
guide: true,
hosts: ["zhihuishu.com"],
test: (url) => /stuExamWeb\.html#\/webExamList\/(?:do homework|dohomework|doexamination)/i.test(url.replace(/\s+/g, "")) || /stuExamWeb\.html#\/webExamList(?:\?|$)/i.test(url),
root: ".examPaper_subject",
title: ".subject_describe > div,.smallStem_describe > div:nth-child(2)",
options: ".subject_node .nodeLab, textarea, input[type='text'], input:not([type])",
type: ".subject_type",
next: ".examPaper_box .switch-btn-box button, button",
save: "button, a,[onclick*='save']"
},
{
id: "smart-work",
name: "新形态课程作业",
hosts: ["smartcourseexam.zhihuishu.com"],
test: (url) => /smartcourseexam\.zhihuishu\.com\/ReviewExam/i.test(url),
root: ".questionContent",
title: ".questionName .centent-pre",
options: ".radio-view li.clearfix,.checkbox-views label.el-checkbox,.fillAnswer,input[type='text'],textarea",
type: ".letterSortNum",
next: ".next-topic.next-t,button",
save: "button,a"
},
{
id: "smart-mastery",
name: "新形态课程掌握度",
hosts: ["studentexamcomh5.zhihuishu.com", "fusioncourseh5.zhihuishu.com", "studywisdomh5.zhihuishu.com", "wisdom-mooc.zhihuishu.com"],
test: (url) => /(?:studywisdomh5|wisdom-mooc)\.zhihuishu\.com\/exam/i.test(url),
root: ".exam-item",
title: ".quest-title .option-name",
options: ".quest-title ~ label,label,div.real-editor,input[type='text'],textarea",
type: ".quest-type",
next: "button",
save: "button,a"
},
{
id: "fusion-mastery",
name: "AI助教掌握度",
hosts: ["fusioncourseh5.zhihuishu.com"],
test: (url) => /fusioncourseh5\.zhihuishu\.com\/exam/i.test(url),
root: ".exam-item,.question-area-content",
title: ".quest-title .option-name,div.flex-1 .mb-\\[32px\\] .text-mainText.font-medium,.question-title",
options: "label,div.real-editor,input[type='text'],textarea",
type: ".quest-type,div.flex.items-center.mb-\\[16px\\],.question-type",
next: "button",
save: "button,a"
},
{
id: "smart-review",
name: "新形态课程掌握提升",
hosts: ["studentexamcomh5.zhihuishu.com"],
test: (url) => /studentexamcomh5\.zhihuishu\.com\/studentReviewTestOrExam/i.test(url),
root: ".questionContent,.question-area-content",
title: ".questionName .centent-pre,.question-title,.questionName",
options: ".radio-view li.clearfix,.checkbox-views label.el-checkbox,label,input[type='text'],textarea",
type: ".letterSortNum,.question-type",
next: ".next-topic.next-t,button",
save: "button,a"
},
{
id: "xnk-work",
name: "校内课作业/考试",
hosts: ["zhihuishu.com", "hike.zhihuishu.com"],
test: (url) => /zhihuishu\.com\/atHomeworkExam\/stu\/(?:homeworkQ\/exerciseList|examQ\/examexercise)/i.test(url),
root: "div:has(> .questionContent)",
title: ".questionContent,.questionTit",
options: ".optionUl label,input[type='text'],textarea",
type: ".questionTit,.question-type",
next: "span.Topicswitchingbtn:nth-child(2),button",
save: "button,a"
},
{
id: "smart-examloop",
name: "新形态课程考试",
hosts: ["examloop.zhihuishu.com"],
test: (url) => /examloop\.zhihuishu\.com\/exam/i.test(url),
root: ".question-area-content",
title: "div.flex-1 .mb-\\[32px\\] .text-mainText.font-medium,.question-title,.questionName",
options: "label.user-select.group,div.real-editor,input[type='text'],textarea",
type: "div.flex.items-center.mb-\\[16px\\],.question-type",
next: "button",
save: "button,a"
},
{
id: "hike-work",
name: "AI教学中心作业",
hosts: ["hike-teaching-center.polymas.com"],
test: (url) => /polymas\.com\/stu-hike\/stuHomeworkDo/i.test(url),
root: ".q_main",
title: ".question-topic",
options: "label,input[type='text'],textarea",
type: ".question_score",
next: ".check_btn:not(.is-disabled),button",
save: "button,a"
},
{
id: "hike-homework",
name: "AI教学中心新作业",
hosts: ["hike-teaching-center.polymas.com"],
test: (url) => /\/(?:stu-exam\/answer-exam|stu\/answer-homework)(?:[/?#]|$)/i.test(url),
root: ".question-item",
title: ".qeustion-content,.combination-content,.question-topic",
options: ".option-item,.vditor-content,input[type='text'],textarea",
type: ".title-box,.combination-title,.question-type",
next: "button",
save: "button,a"
}
];
function resolveWorkProfile(url = globalThis.location?.href || "") {
let parsed;
try {
parsed = new URL(String(url));
} catch {
return null;
}
if (!["http:", "https:"].includes(parsed.protocol)) return null;
const host = parsed.hostname.toLowerCase();
const value = `${parsed.origin}${parsed.pathname}${parsed.hash}`;
return PROFILES.find((profile) => {
const hostAllowed = profile.hosts.some((candidate) => host === candidate || candidate === "zhihuishu.com" && host.endsWith(`.${candidate}`));
return hostAllowed && profile.test(value);
}) || null;
}
const DATA_KEYS = ["workInfo", "examInfo", "homeworkInfo", "examBase", "examinationArr", "workExamParts", "questionDtos", "questions", "questionList", "questionDto", "rt", "data", "$data", "setupState", "props", "$props", "proxy", "ctx", "value"];
const INSTANCE_KEYS = ["__vue__", "__vueParentComponent"];
function getValue(object, key) {
try {
return object?.[key];
} catch {
return void 0;
}
}
function findQuestionLists(roots) {
const visited = /* @__PURE__ */ new Set();
const lists = [];
let budget = 1500;
function visit(value, depth) {
if (!value || typeof value !== "object" || visited.has(value) || depth > 9 || budget-- <= 0) return;
visited.add(value);
if (Array.isArray(value)) {
if (value.length && value.every((item) => item && typeof item === "object" && typeof getValue(item, "name") === "string")) lists.push(value);
if (value.length && value.every((item) => Array.isArray(getValue(item, "questionDtos")))) lists.push(value.flatMap((item) => getValue(item, "questionDtos")));
for (const item of value) visit(item, depth + 1);
} else {
for (const key of DATA_KEYS) visit(getValue(value, key), depth + 1);
}
}
for (const root of roots) visit(root, 0);
return lists.sort((left, right) => right.length - left.length);
}
function readSharedQuestionData(doc, element, index) {
const questionId = element?.getAttribute("data-question-id") || element?.getAttribute("questionid") || element?.querySelector?.(".subject_num [id^='anchor_']")?.id.slice("anchor_".length);
const matchesId = (question) => !questionId || ["questionId", "id", "strId"].some((key) => String(getValue(question, key) ?? "") === questionId);
for (const key of INSTANCE_KEYS) {
const instance = getValue(element, key);
const candidates = [
getValue(getValue(instance, "$props"), "data"),
getValue(getValue(instance, "props"), "data"),
getValue(instance, "data"),
getValue(getValue(instance, "$data"), "dataArr")
];
for (const question of candidates) {
if (typeof getValue(question, "name") === "string" && getValue(question, "questionType") && matchesId(question)) return question;
}
}
const roots = [];
const elements = /* @__PURE__ */ new Set([element, ...doc.querySelectorAll(".examPaper_box,#app")]);
for (let ancestor = element?.parentElement, depth = 0; ancestor && depth < 8; ancestor = ancestor.parentElement, depth++) elements.add(ancestor);
for (const node of elements) {
for (const key of INSTANCE_KEYS) {
let instance = getValue(node, key);
for (let depth = 0; instance && depth < 5; depth++) {
roots.push(instance);
instance = getValue(instance, "$parent") || getValue(instance, "parent");
}
}
}
const lists = findQuestionLists(roots);
if (questionId) {
for (const list of lists) {
const question = list.find(matchesId);
if (question) return question;
}
return null;
}
if (!Number.isInteger(index) || index < 0) return null;
return lists[0]?.[index] || null;
}
function identity(element, profile) {
return [
profile.questionIndex,
element.getAttribute("data-question-id"),
element.getAttribute("questionid"),
element.querySelector(".subject_num [id^='anchor_']")?.id
].join(":");
}
function sharedShadowTitle(ctx, question, profile) {
const result = ctx.sharedQuestionContent?.get(question);
return result?.identity === identity(question, profile) ? result.title : "";
}
async function refreshSharedQuestion(ctx, question, profile, send2 = extensionReadQuestion) {
ctx.checkActive();
ctx.sharedQuestionContent ??= /* @__PURE__ */ new WeakMap();
if (ctx.sharedQuestionBridgeUnavailable) return;
const before = identity(question, profile);
const attribute = `data-cx-question-${Array.from(ctx.pageWindow.crypto.getRandomValues(new Uint8Array(12)), (byte) => byte.toString(16).padStart(2, "0")).join("")}`;
const cleanup = () => question.removeAttribute(attribute);
question.setAttribute(attribute, "");
const removeCleanup = ctx.onCleanup(cleanup);
try {
const result = await send2(attribute);
ctx.checkActive();
if (question.isConnected && before === identity(question, profile) && result?.url === ctx.pageWindow.location.href && typeof result.title === "string") {
ctx.sharedQuestionContent.set(question, { title: result.title, identity: before });
}
} catch (error) {
ctx.checkActive();
ctx.sharedQuestionContent.delete(question);
ctx.sharedQuestionBridgeUnavailable = true;
ctx.log("封闭题干读取服务不可用,请同时重新安装本次扩展和油猴脚本,再刷新页面。", "warning");
} finally {
cleanup();
removeCleanup();
}
}
const sleep = (ctx, ms) => ctx?.sleep ? ctx.sleep(ms) : new Promise((resolve) => setTimeout(resolve, ms));
const visible$1 = (ctx, element) => {
if (!element || !element.isConnected || element.hidden) return false;
return typeof ctx?.isVisible === "function" ? ctx.isVisible(element) : true;
};
const textOf$1 = (element) => (element?.innerText || element?.textContent || "").replace(/\s+/g, " ").trim();
const POPUP_PROFILES = {
playTopic: {
id: "study-play-topic",
root: "#playTopic-dialog",
// The legacy dialog has changed its stem class over time. Keep the
// fallback selectors stem-specific and leave the popup for manual work
// when no reliable stem can be found.
title: ".topic-title,.question-title,.topic-name,.stem,.subject-title",
type: ".topic-type,.question-type,.subject-type,.subject_type",
options: ".topic .radio ul > li,.topic-item"
},
aiTest: {
id: "study-ai-test",
root: ".ai-test-question-wrapper",
title: ".question-title,.topic-title,.question-name,.stem,.subject-title",
type: ".question-type,.topic-type,.type",
options: ".options .option"
},
aiClassExercise: {
id: "study-ai-class-exercise",
root: ".ai-class-exercise-dialog",
title: ".question-title,.topic-title,.question-name,.stem,.subject-title",
type: ".question-type,.topic-type,.type",
options: ".ques-list .item .option"
}
};
function firstVisible(root, selector, ctx) {
return Array.from(root.querySelectorAll(selector)).find((element) => visible$1(ctx, element)) || null;
}
function popupRoot(doc, root, selector, ctx) {
if (root && root.matches?.(selector)) return root;
return firstVisible(doc, selector, ctx);
}
function questionRoot(root, profile, ctx) {
const candidate = firstVisible(root, ".topic,.question,.question-content,.topic-content", ctx);
return candidate || root;
}
async function waitCaptcha(ctx) {
if (ctx?.signal?.aborted) return false;
if (typeof ctx?.waitForCaptcha === "function") await ctx.waitForCaptcha();
return !ctx?.signal?.aborted;
}
function active(ctx) {
if (ctx?.signal?.aborted) return false;
try {
if (typeof ctx?.checkActive === "function") ctx.checkActive();
} catch (error) {
if (error?.name === "AbortError") return false;
throw error;
}
return !ctx?.signal?.aborted;
}
function log(ctx, message, type = "info") {
try {
ctx?.log?.(message, type);
} catch {
}
}
async function closeWithin(ctx, root, selector) {
const button = root.querySelector(selector);
if (!button || button.disabled) return false;
await clickElement(ctx, button);
return true;
}
async function answerOne(ctx, root, profile, answerQuestion2) {
if (typeof answerQuestion2 !== "function") {
log(ctx, "学习弹题暂未接入答题器,请手动完成。", "warning");
return false;
}
const question = questionRoot(root, profile, ctx);
const title = firstVisible(question, profile.title, ctx);
if (!title || !textOf$1(title)) {
log(ctx, "学习弹题未找到可靠题干,已保留弹窗供手动处理。", "warning");
return false;
}
if (!firstVisible(question, profile.options, ctx)) {
log(ctx, "学习弹题未找到选项,已保留弹窗供手动处理。", "warning");
return false;
}
if (!await waitCaptcha(ctx)) return false;
try {
return !!await answerQuestion2(ctx, question, profile);
} catch (error) {
if (error?.name === "AbortError" || ctx?.signal?.aborted) return false;
log(ctx, `学习弹题处理失败:${error?.message || error}`, "warning");
return false;
}
}
async function handlePlayTopic(ctx, root, answerQuestion2) {
const profile = POPUP_PROFILES.playTopic;
const pages = Array.from(root.querySelectorAll(".el-pager .number"));
const items = pages.length ? pages : [null];
let allAnswered = true;
for (const page of items) {
if (!await waitCaptcha(ctx) || !active(ctx)) return false;
if (page && !page.classList.contains("active")) {
await clickElement(ctx, page);
await sleep(ctx, 500);
if (!active(ctx)) return false;
}
allAnswered = await answerOne(ctx, root, profile, answerQuestion2) && allAnswered;
if (pages.length) await sleep(ctx, 300);
}
if (!allAnswered) {
log(ctx, "学习弹题未能全部作答,请手动检查后关闭。", "warning");
return false;
}
if (ctx?.settings?.submitSettings?.autoSubmitChapter === false) {
log(ctx, "学习弹题已完成,请手动提交。", "info");
return false;
}
if (!await waitCaptcha(ctx) || !active(ctx)) return false;
const closed = await closeWithin(ctx, root, ".close-btn") || await closeWithin(ctx, root, ".btn");
if (!closed) {
log(ctx, "学习弹题未找到关闭按钮,请手动关闭。", "warning");
return false;
}
await sleep(ctx, 300);
return !visible$1(ctx, root);
}
async function handleAiTest(ctx, root, answerQuestion2) {
const profile = POPUP_PROFILES.aiTest;
if (visible$1(ctx, root.querySelector(".done"))) {
if (!await waitCaptcha(ctx) || !active(ctx)) return false;
if (!await closeWithin(ctx, root, ".close-box")) {
log(ctx, "学习弹题未找到关闭按钮,请手动关闭。", "warning");
return false;
}
await sleep(ctx, 300);
return !visible$1(ctx, root);
}
const answered = await answerOne(ctx, root, profile, answerQuestion2);
if (!answered) return false;
if (ctx?.settings?.submitSettings?.autoSubmitChapter === false) {
log(ctx, "学习弹题已完成,请手动提交。", "info");
return false;
}
if (!await waitCaptcha(ctx) || !active(ctx)) return false;
const submit = root.querySelector(".submit-btn .submits");
if (!submit) {
log(ctx, "学习弹题未找到提交按钮,请手动提交。", "warning");
return false;
}
await clickElement(ctx, submit);
await sleep(ctx, 500);
if (!visible$1(ctx, root.querySelector(".done"))) {
log(ctx, "学习弹题提交结果未确认,请手动检查。", "warning");
return false;
}
if (!await waitCaptcha(ctx) || !active(ctx)) return false;
if (!await closeWithin(ctx, root, ".close-box")) {
log(ctx, "学习弹题未找到关闭按钮,请手动关闭。", "warning");
return false;
}
await sleep(ctx, 300);
return !visible$1(ctx, root);
}
async function handleAiClassExercise(ctx, root, answerQuestion2) {
const profile = POPUP_PROFILES.aiClassExercise;
const items = Array.from(root.querySelectorAll(".ques-list .item")).filter((item) => visible$1(ctx, item));
const questions = items.length ? items : [root];
let allAnswered = true;
for (const item of questions) {
const itemProfile = { ...profile, options: ".option" };
allAnswered = await answerOne(ctx, item, itemProfile, answerQuestion2) && allAnswered;
if (!await waitCaptcha(ctx) || !active(ctx)) return false;
}
if (!allAnswered) {
log(ctx, "学习弹题未能全部作答,请手动检查后提交。", "warning");
return false;
}
if (ctx?.settings?.submitSettings?.autoSubmitChapter === false) {
log(ctx, "学习弹题已完成,请手动提交。", "info");
return false;
}
const submit = root.querySelector(".el-dialog__footer .el-button.btn");
if (!submit) {
log(ctx, "学习弹题未找到提交按钮,请手动提交。", "warning");
return false;
}
if (!await waitCaptcha(ctx) || !active(ctx)) return false;
await clickElement(ctx, submit);
await sleep(ctx, 500);
if (!await waitCaptcha(ctx) || !active(ctx)) return false;
const errorPrompt = root.querySelector(".el-message--error,.el-alert-error,.error,.is-error");
if (visible$1(ctx, errorPrompt)) {
log(ctx, "学习弹题提交出现错误提示,请手动检查。", "warning");
return false;
}
if (!await waitCaptcha(ctx) || !active(ctx)) return false;
if (!await closeWithin(ctx, root, ".header-icon")) {
log(ctx, "学习弹题未找到关闭按钮,请手动关闭。", "warning");
return false;
}
await sleep(ctx, 300);
return !visible$1(ctx, root);
}
async function closeMasteryPrompt(ctx, root) {
if (!await waitCaptcha(ctx) || !active(ctx)) return false;
if (await closeWithin(ctx, root, ".header-box .close-box") || await closeWithin(ctx, root, ".close-box,.header-icon")) {
await sleep(ctx, 300);
log(ctx, "掌握度提示已关闭,继续学习。", "info");
return true;
}
log(ctx, "检测到掌握度提示,请手动关闭后继续。", "warning");
return false;
}
async function handleStudyPopup(ctx, root, studyProfile, answerQuestion2) {
const doc = ctx?.document || globalThis.document;
if (!doc || ctx?.signal?.aborted) return false;
const current = root || popupRoot(doc, ".ai-test-question-wrapper", ".ai-test-question-wrapper", ctx) || popupRoot(doc, ".ai-class-exercise-dialog", ".ai-class-exercise-dialog", ctx) || popupRoot(doc, "#playTopic-dialog", "#playTopic-dialog", ctx) || popupRoot(doc, ".masterylevel-body", ".masterylevel-body", ctx);
if (!current) return false;
if (current.matches(".masterylevel-body")) return closeMasteryPrompt(ctx, current);
if (current.matches("#playTopic-dialog")) return handlePlayTopic(ctx, current, answerQuestion2);
if (current.matches(".ai-test-question-wrapper")) return handleAiTest(ctx, current, answerQuestion2);
if (current.matches(".ai-class-exercise-dialog")) return handleAiClassExercise(ctx, current, answerQuestion2);
log(ctx, "检测到未知学习弹题,已保留页面供手动处理。", "warning");
return false;
}
const all = (root, selector) => selector ? [...root.querySelectorAll(selector)] : [];
const first = (root, selector) => selector ? selector.split(",").map((part) => root.querySelector(part.trim())).find(Boolean) || null : null;
const escapeHtml = (value) => String(value ?? "").replace(/[&<>"']/g, (char) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[char]);
const normalized = (value) => String(value ?? "").replace(/\s+/g, " ").trim();
const valuesOf = (value) => (Array.isArray(value) ? value : [value]).filter((value2) => value2 != null && String(value2).trim() !== "").map(String);
const visible = (ctx, element) => !!element && (!ctx || ctx.isVisible(element));
const selected = (element) => element.matches(".is-checked,.checked,.checkedIcon,[aria-checked='true']") || !!element.querySelector("input:checked,.is-checked,.checkedIcon,.bg-mainBg,[aria-checked='true']");
const readOnly = (doc) => !!doc.querySelector('[mode="REVIEW_MODE"]');
function textOf(element) {
if (!element) return "";
const clone = element.cloneNode(true);
clone.querySelectorAll(".viewer").forEach((node) => node.remove());
for (const image of clone.querySelectorAll("img")) {
image.replaceWith(image.ownerDocument.createTextNode(image.alt || `[图片:${image.getAttribute("data-src") || image.getAttribute("src") || ""}]`));
}
clone.querySelectorAll("script,style,input,textarea").forEach((node) => node.remove());
return normalized(clone.textContent);
}
function htmlText(doc, html) {
const template = doc.createElement("template");
template.innerHTML = String(html);
return textOf(template.content);
}
function matchingElements(root, selector) {
if (!root || !selector) return [];
const seen2 = /* @__PURE__ */ new Set();
for (const part of selector.split(",").map((value) => value.trim()).filter(Boolean)) {
const elements = [];
try {
if (root.matches?.(part)) elements.push(root);
elements.push(...root.querySelectorAll(part));
} catch {
continue;
}
const nonEmpty = elements.filter((element) => {
if (seen2.has(element)) return false;
seen2.add(element);
return !!textOf(element);
});
if (nonEmpty.length) return nonEmpty;
}
return [];
}
function firstTextElement(root, selector) {
return matchingElements(root, selector)[0] || null;
}
function textFromSelector(root, selector) {
const elements = matchingElements(root, selector);
if (!elements.length) return "";
const leaves = elements.filter((element) => !elements.some((other) => other !== element && other.contains(element)));
return normalized(leaves.map(textOf).filter(Boolean).join(" "));
}
function questionTitle(ctx, question, profile) {
if (profile.id === "gxk") {
const shadowTitle = sharedShadowTitle(ctx, question, profile);
if (shadowTitle) return shadowTitle;
const metadata = readSharedQuestionData(ctx.document, question, profile.questionIndex);
if (metadata?.name) return htmlText(ctx.document, metadata.name);
}
return textFromSelector(question, profile.title).replace(/^\d+[.、)]\s*/, "");
}
function typeFromText(value) {
const type = normalized(value);
if (/多选|multiple/i.test(type)) return QUESTION_TYPES.MULTI;
if (/单选|single/i.test(type)) return QUESTION_TYPES.SINGLE;
if (/判断|正误|true.?false/i.test(type)) return QUESTION_TYPES.JUDGE;
if (/填空|completion/i.test(type)) return QUESTION_TYPES.FILL;
if (/简答|问答|论述|essay/i.test(type)) return QUESTION_TYPES.ESSAY;
return null;
}
function typeElements(question, profile) {
const contexts = [];
const seen2 = /* @__PURE__ */ new Set();
const add = (element) => {
if (element && !seen2.has(element)) {
seen2.add(element);
contexts.push(element);
}
};
const title = firstTextElement(question, profile.title);
const parentDepth = profile.id === "gxk" ? 2 : ["smart-work", "smart-review"].includes(profile.id) ? 1 : 0;
if (title && parentDepth) {
let related = title;
for (let depth = 0; related && depth < parentDepth; depth++) related = related.parentElement;
const containsOtherQuestion = related && all(related, profile.root).some((root) => root !== question && !question.contains(root));
if (related && !containsOtherQuestion) add(related);
}
add(question);
const elements = [];
const elementSeen = /* @__PURE__ */ new Set();
for (const context of contexts) {
for (const element of matchingElements(context, profile.type)) {
if (!elementSeen.has(element)) {
elementSeen.add(element);
elements.push(element);
}
}
}
return elements;
}
function looksLikeJudgeOptions(options) {
if (options.length !== 2) return false;
const labels = options.map((option) => normalized(textOf(option)).replace(/^[A-Z][.、.))]\s*/, "").toLowerCase());
const trueWords = JUDGE_TRUE_WORDS.map((word) => String(word).toLowerCase()).filter((word) => !["1", "0"].includes(word));
const falseWords = JUDGE_FALSE_WORDS.map((word) => String(word).toLowerCase()).filter((word) => !["1", "0"].includes(word));
const known = /* @__PURE__ */ new Set([...trueWords, ...falseWords]);
return labels.every((label) => known.has(label)) && labels.some((label) => trueWords.includes(label)) && labels.some((label) => falseWords.includes(label));
}
function detectQuestionType(question, profile) {
for (const element of typeElements(question, profile)) {
const type = typeFromText(textOf(element));
if (type) return type;
}
if (question.querySelector('input[type="checkbox"],.checkbox-views,.el-checkbox,.el-checkbox__input,[role="checkbox"]')) return QUESTION_TYPES.MULTI;
if (question.querySelector('input[type="radio"],.radio-view,.radio,.el-radio,.el-radio__input,[role="radio"]')) {
const options = optionElements(null, question, profile);
if (looksLikeJudgeOptions(options)) return QUESTION_TYPES.JUDGE;
return QUESTION_TYPES.SINGLE;
}
if (question.querySelector('.real-editor,.vditor-content,[contenteditable="true"]')) return QUESTION_TYPES.ESSAY;
if (question.querySelector('input[type="text"],textarea,.fillAnswer')) return QUESTION_TYPES.FILL;
if (profile.id?.startsWith("study-") && question.querySelector(profile.options)) return QUESTION_TYPES.SINGLE;
return null;
}
function optionElements(ctx, question, profile) {
const candidates = all(question, profile.options).filter((element) => visible(ctx, element) && !element.matches("input,textarea,.real-editor,.vditor-content,.fillAnswer"));
return candidates.filter((element) => !candidates.some((parent) => parent !== element && parent.contains(element)));
}
function optionsOf(ctx, question, profile) {
return optionElements(ctx, question, profile).map((element, index) => ({
element,
value: String.fromCharCode(65 + index),
text: textOf(element.querySelector(".node_detail,.option-name,.option-content") || element).replace(/^[A-Z][.、.))]\s*/, "")
}));
}
function textControls(question) {
const elements = all(question, '.real-editor,.vditor-reset,[contenteditable="true"],textarea,input[type="text"],input:not([type])');
return elements.filter((element) => !elements.some((parent) => parent !== element && parent.contains(element)));
}
function questionHasContent(ctx, question, profile) {
if (!question || !visible(ctx, question)) return false;
const title = questionTitle(ctx, question, profile);
if (!title) return false;
const type = detectQuestionType(question, profile);
const options = optionElements(ctx, question, profile);
const controls = textControls(question);
if (!type) return !!(options.length || controls.length);
if ([QUESTION_TYPES.FILL, QUESTION_TYPES.ESSAY].includes(type)) return controls.length > 0;
return options.length > 0;
}
async function waitForHydratedQuestion(ctx, question, profile, rootIndex) {
const initialRoots = questionRoots(ctx, profile);
const initialIndex = initialRoots.indexOf(question) >= 0 ? initialRoots.indexOf(question) : rootIndex;
const questionId = question?.getAttribute?.("data-question-id") || question?.getAttribute?.("questionid");
return ctx.waitFor(async () => {
let current = question?.isConnected ? question : null;
if (!current) {
const roots = questionRoots(ctx, profile);
current = questionId ? roots.find((candidate) => candidate.getAttribute?.("data-question-id") === questionId || candidate.getAttribute?.("questionid") === questionId) : null;
if (!current && !questionId && Number.isInteger(initialIndex) && initialIndex >= 0) current = roots[initialIndex];
}
if (current && profile.id === "gxk" && (!questionTitle(ctx, current, profile) || ctx.sharedQuestionContent?.has(current))) {
await refreshSharedQuestion(ctx, current, profile);
}
return current && questionHasContent(ctx, current, profile) ? current : null;
}, { timeout: 12e3, interval: 200 });
}
function controlText(element) {
if (element.ckeditorInstance?.data?.get) return htmlText(element.ownerDocument, element.ckeditorInstance.data.get());
return normalized("value" in element ? element.value : element.textContent);
}
function questionKey(ctx, question, profile) {
return JSON.stringify([
question.getAttribute("data-question-id") || question.getAttribute("questionid") || question.id,
textOf(first(question, profile.type)),
detectQuestionType(question, profile),
questionTitle(ctx, question, profile),
optionsOf(ctx, question, profile).map((option) => option.text)
]);
}
async function ready(ctx, question, profile, key) {
ctx.checkActive();
await ctx.waitForCaptcha();
ctx.checkActive();
if (readOnly(ctx.document)) throw new Error("当前试卷已经完成,停止填写");
if (question && profile?.id === "gxk" && ctx.sharedQuestionContent?.has(question)) await refreshSharedQuestion(ctx, question, profile);
if (question && (!visible(ctx, question) || questionKey(ctx, question, profile) !== key)) throw new Error("题目已发生变化,停止填写旧题答案");
}
function record(title, answer, type, status, original) {
const safeAnswer = Array.isArray(answer) ? answer.map(escapeHtml) : escapeHtml(answer);
useAnswerStore().addAnswer(escapeHtml(title), safeAnswer, type, status, original == null ? null : escapeHtml(original));
}
function isCompleteAnswerResult(result) {
return result?.isCorrect === true && result.status === "success" && valuesOf(result.answer).length > 0;
}
async function writeText(ctx, question, profile, key, element, value) {
await ready(ctx, question, profile, key);
const text2 = String(value);
if (controlText(element) && controlText(element) !== normalized(text2)) return false;
if (element.classList.contains("real-editor")) {
if (!element.ckeditorInstance?.data?.set || !element.ckeditorInstance?.data?.get) return false;
element.ckeditorInstance.data.set(escapeHtml(text2).replace(/\n/g, "
"));
} else if ("value" in element) {
const prototype = element instanceof ctx.pageWindow.HTMLTextAreaElement ? ctx.pageWindow.HTMLTextAreaElement.prototype : ctx.pageWindow.HTMLInputElement.prototype;
Object.getOwnPropertyDescriptor(prototype, "value").set.call(element, text2);
element.dispatchEvent(new ctx.pageWindow.Event("input", { bubbles: true }));
element.dispatchEvent(new ctx.pageWindow.Event("change", { bubbles: true }));
} else {
if (element.classList.contains("vditor-reset")) element.innerHTML = `${escapeHtml(text2)}
`;
else element.textContent = text2;
element.dispatchEvent(new ctx.pageWindow.InputEvent("input", { bubbles: true, inputType: "insertText", data: text2 }));
element.dispatchEvent(new ctx.pageWindow.Event("change", { bubbles: true }));
}
await ctx.sleep(100);
await ready(ctx, question, profile, key);
return controlText(element) === normalized(text2);
}
async function fillText(ctx, question, profile, key, answer) {
const controls = textControls(question);
const answers = valuesOf(answer);
if (!controls.length || controls.length !== answers.length) return false;
for (let index = 0; index < controls.length; index++) {
if (!await writeText(ctx, question, profile, key, controls[index], answers[index])) return false;
}
return controls.every((element, index) => controlText(element) === normalized(answers[index]));
}
function judgeValue(option) {
const label = normalized(option.text).replace(/^[A-Z][.、.))]\s*/, "").toLowerCase();
if (JUDGE_FALSE_WORDS.some((word) => word.toLowerCase() === label)) return "false";
if (JUDGE_TRUE_WORDS.some((word) => word.toLowerCase() === label)) return "true";
return null;
}
async function fillOptions(ctx, question, profile, key, type, options, answer) {
const answers = valuesOf(answer);
const expected = type === QUESTION_TYPES.JUDGE ? options.filter((option) => judgeValue(option) === answers[0]) : options.filter((option) => answers.includes(option.value));
if (!expected.length || type !== QUESTION_TYPES.MULTI && expected.length !== 1 || type === QUESTION_TYPES.MULTI && expected.length !== new Set(answers).size) return false;
for (const option of expected) {
await ready(ctx, question, profile, key);
if (options.some((item) => selected(item.element) && !expected.includes(item))) return false;
if (selected(option.element)) continue;
const target = option.element.querySelector(".el-radio__input,.el-checkbox__input,i.iconfont") || option.element;
await clickElement(ctx, target);
const accepted = await ctx.waitFor(() => selected(option.element), { timeout: 1200, interval: 100 });
if (!accepted) return false;
}
await ready(ctx, question, profile, key);
return options.every((option) => !!selected(option.element) === expected.includes(option));
}
async function answerQuestion(ctx, question, profile) {
const hydrated = await waitForHydratedQuestion(ctx, question, profile);
if (!hydrated) {
ctx.log("未找到完整题目内容,请确认题目已加载后手动处理。", "warning");
return false;
}
question = hydrated;
const key = questionKey(ctx, question, profile);
await ready(ctx, question, profile, key);
const type = detectQuestionType(question, profile);
const title = questionTitle(ctx, question, profile);
if (!title || !type) {
ctx.log("题目没有可识别的题干或题型,请手动处理。", "warning");
return false;
}
const options = optionsOf(ctx, question, profile);
const controls = textControls(question);
if (options.some((option) => selected(option.element)) || controls.some((element) => controlText(element))) {
ctx.log(`保留已有答案:${title.slice(0, 48)}`);
return true;
}
const result = await checkAnswer({ type, title }, options.map(({ value, text: text2 }) => ({ value, text: text2 })));
await ready(ctx, question, profile, key);
if (options.some((option) => selected(option.element)) || controls.some((element) => controlText(element))) {
ctx.log(`搜题期间已手动作答,保留页面答案:${title.slice(0, 48)}`);
return true;
}
if (!isCompleteAnswerResult(result)) {
record(title, result.originalAnswer || result.answer || result.message || "未找到答案", type, result.status || "not_found", result.originalAnswer);
ctx.log(`未获得完整匹配,保留此题供核对:${title.slice(0, 48)}`, "warning");
return false;
}
const written = [QUESTION_TYPES.FILL, QUESTION_TYPES.ESSAY].includes(type) ? await fillText(ctx, question, profile, key, result.answer) : await fillOptions(ctx, question, profile, key, type, options, result.answer);
const displayAnswer = [QUESTION_TYPES.SINGLE, QUESTION_TYPES.MULTI].includes(type) ? options.filter((option) => valuesOf(result.answer).includes(option.value)).map((option) => option.text) : result.answer;
record(title, displayAnswer, type, written ? "success" : "partial", result.originalAnswer);
ctx.log(written ? `已填写:${title.slice(0, 48)}` : `页面未确认填写,请手动检查:${title.slice(0, 48)}`, written ? "success" : "warning");
return written;
}
function questionRoots(ctx, profile) {
const roots = all(ctx.document, profile.root).filter((element) => visible(ctx, element));
return roots.filter((element) => !roots.some((child) => child !== element && element.contains(child)));
}
function usableButton(ctx, element) {
return visible(ctx, element) && !element.disabled && !element.matches('.is-disabled,.disabled,[aria-disabled="true"]') && !/提交|交卷|结束|完成考试|submit/i.test(textOf(element));
}
function nextButton(ctx, profile) {
return all(ctx.document, profile.next).find((element) => usableButton(ctx, element) && (/^(下一题|下一页|下题|next(?: question)?)[\s>›→]*$/i.test(textOf(element)) || element.matches(".next-topic.next-t,span.Topicswitchingbtn:nth-child(2),.check_btn")));
}
async function savePaper(ctx, profile) {
if (ctx.settings.answerSettings.autoSaveAnswer === false) return;
const button = all(ctx.document, profile.save).find((element) => usableButton(ctx, element) && /^(保存|暂存)(?:答案|作业)?$|^save$/i.test(textOf(element)));
if (button) {
await ready(ctx);
await clickElement(ctx, button);
ctx.log("已触发页面保存,请核对网页的保存结果。");
}
}
async function sharedPaper(ctx, profile, cards) {
for (let index = 0; index < cards.length; index++) {
await ready(ctx);
const card = all(ctx.document, ".answerCard_list ul li")[index];
if (!card?.isConnected) break;
await clickElement(ctx, card);
await ctx.sleep(250);
const roots = await ctx.waitFor(() => {
const items = questionRoots(ctx, profile);
return items.length ? items : null;
}, { timeout: 15e3, interval: 200 });
if (!roots) throw new Error("切题后未找到题目内容");
const question = roots.length === cards.length ? roots[index] : roots[0];
await answerQuestion(ctx, question, { ...profile, questionIndex: index });
if (ctx.settings.answerSettings.autoSaveAnswer !== false) {
await ready(ctx);
const button = ctx.document.querySelector(".examPaper_box > .switch-btn-box > button:nth-child(2)") || nextButton(ctx, profile);
if (usableButton(ctx, button)) {
await clickElement(ctx, button);
await ctx.sleep(350);
} else ctx.log(`第 ${index + 1} 题未找到安全的保存/下一题按钮,请手动保存。`, "warning");
}
}
ctx.log("共享课题目处理结束,请核对保存结果后自行交卷。");
}
function answerPopup(ctx, root, studyProfile) {
return handleStudyPopup(ctx, root, studyProfile, answerQuestion);
}
async function startWork(ctx, profile = resolveWorkProfile(ctx.pageWindow.location.href)) {
if (!profile) return;
if (profile.id === "gxk" && !/\/(dohomework|doexamination)/i.test(ctx.pageWindow.location.hash)) {
ctx.log("请打开共享课的具体作业或考试,进入后自动开始。");
return;
}
if (readOnly(ctx.document)) {
ctx.log("当前为已完成试卷的查看页面,停止自动填写。");
return;
}
ctx.log(`开始${profile.name}`);
const loaded = await ctx.waitFor(async () => {
const roots = questionRoots(ctx, profile);
if (profile.id === "gxk" && all(ctx.document, ".answerCard_list ul li").length) return roots.length > 0;
if (profile.id === "gxk") {
for (const [index, question] of roots.entries()) {
const activeProfile = { ...profile, questionIndex: index };
if (!questionTitle(ctx, question, activeProfile)) await refreshSharedQuestion(ctx, question, activeProfile);
}
}
return roots.some((question, index) => questionHasContent(
ctx,
question,
profile.id === "gxk" ? { ...profile, questionIndex: index } : profile
));
}, { timeout: 2e4, interval: 250 });
if (!loaded) {
ctx.log("未找到智慧树题目区域,请确认试卷已打开。", "warning");
return;
}
await ready(ctx);
const cards = all(ctx.document, ".answerCard_list ul li");
if (profile.id === "gxk" && cards.length) return sharedPaper(ctx, profile, cards);
const firstSelector = { "smart-work": '[role="treeitem"] .font-sec-style-node', "smart-review": '[role="treeitem"] .font-sec-style-node', "smart-examloop": ".grid.grid-cols-7 > button", "hike-work": ".card_ul .card_li" }[profile.id];
const firstItem = firstSelector && first(ctx.document, firstSelector);
if (firstItem && usableButton(ctx, firstItem)) {
await clickElement(ctx, firstItem);
await ctx.sleep(350);
}
const seen2 = /* @__PURE__ */ new Set();
const batchKey = () => questionRoots(ctx, profile).map((question) => questionKey(ctx, question, profile)).join("\n");
for (let round = 0; round < 500; round++) {
await ready(ctx);
const roots = questionRoots(ctx, profile);
if (!roots.length) break;
let fresh = false;
for (const [index, question] of roots.entries()) {
const activeProfile = profile.id === "gxk" ? { ...profile, questionIndex: index } : profile;
const hydrated = await waitForHydratedQuestion(ctx, question, activeProfile, index);
if (!hydrated) continue;
const key = questionKey(ctx, hydrated, activeProfile);
if (seen2.has(key)) continue;
seen2.add(key);
fresh = true;
await answerQuestion(ctx, hydrated, activeProfile);
}
if (!fresh) break;
const next = nextButton(ctx, profile);
if (!next) break;
const before = batchKey();
await ready(ctx);
await clickElement(ctx, next);
const changed = await ctx.waitFor(() => batchKey() && batchKey() !== before, { timeout: 8e3, interval: 200 });
if (!changed) {
ctx.log("题目没有切换,停止自动翻页,请手动检查。");
break;
}
}
await savePaper(ctx, profile);
ctx.log("题目处理结束,请检查答案和保存状态,最终交卷需手动完成。");
}
const _hoisted_1 = { id: "app" };
const _hoisted_2 = { class: "app-container" };
const _sfc_main = {
__name: "ZhihuishuApp",
setup(__props) {
const visible2 = vue.ref(false);
const settings = useSettingsStore();
const logs = useLogStore();
let controller;
let stopObserving;
async function routeChanged(url) {
controller?.abort();
controller = new AbortController();
const ctx = createRuntime({ controller, settings, log: logs.addLog, pageWindow: _unsafeWindow, document, answerPopup });
ctx.click = createPageClick(ctx);
const work = resolveWorkProfile(url);
const study = work ? null : resolveStudyProfile(url);
visible2.value = !!(work || study || isStudyGuide(url));
if (!visible2.value) return;
if (!work && !study) {
ctx.log("智慧树助手已就绪,请打开课程学习、作业或考试页面。");
return;
}
ctx.log(`智慧树:${(work || study).name}`);
try {
await ctx.sleep(300);
if (work) await startWork(ctx, work);
else await startStudy(ctx, study);
} catch (error) {
if (error?.name === "AbortError" || ctx.signal.aborted) return;
ctx.log(`智慧树当前任务停止:${error?.message || error}。请检查页面后刷新重试。`, "error");
console.error("智慧树页面处理失败", error);
}
}
function start() {
stopObserving?.();
stopObserving = observeRoutes(_unsafeWindow, routeChanged);
}
function stop() {
controller?.abort();
stopObserving?.();
stopObserving = void 0;
}
function resume(event) {
if (event.persisted) start();
}
vue.onMounted(() => {
start();
window.addEventListener("pagehide", stop);
window.addEventListener("pageshow", resume);
});
vue.onUnmounted(() => {
stop();
window.removeEventListener("pagehide", stop);
window.removeEventListener("pageshow", resume);
});
return (_ctx, _cache) => {
return vue.openBlock(), vue.createElementBlock("div", _hoisted_1, [
vue.createElementVNode("div", _hoisted_2, [
visible2.value ? (vue.openBlock(), vue.createBlock(FloatingWindow, { key: 0 })) : vue.createCommentVNode("", true)
])
]);
};
}
};
const EDIT_EVENTS = [
"copy",
"cut",
"paste",
"contextmenu",
"selectstart",
"keydown",
"keypress",
"keyup",
"beforeinput",
"input",
"change",
"compositionstart",
"compositionupdate",
"compositionend"
];
const NON_TEXT_INPUTS = /* @__PURE__ */ new Set(["button", "checkbox", "color", "file", "hidden", "image", "radio", "range", "reset", "submit"]);
function isTextField(element) {
if (!element || element.nodeType !== 1 || element.disabled) return false;
return element.localName === "textarea" || element.localName === "input" && !NON_TEXT_INPUTS.has(element.type) || element.isContentEditable;
}
function isolatePanelInputs(shadow) {
const host = shadow.host;
const doc = host.ownerDocument;
const win = doc.defaultView;
const isMounted = () => host.isConnected && host.shadowRoot === shadow;
const stopEditingBubble = (event) => {
if (!isMounted()) return;
for (const target of event.composedPath()) {
if (target === shadow) break;
if (isTextField(target)) {
event.stopPropagation();
break;
}
}
};
const stopPanelSelectionChange = (event) => {
if (event.target !== doc || !isMounted() || doc.activeElement !== host) return;
let active2 = shadow.activeElement;
while (active2?.shadowRoot?.activeElement) active2 = active2.shadowRoot.activeElement;
if (isTextField(active2)) event.stopPropagation();
};
for (const type of EDIT_EVENTS) shadow.addEventListener(type, stopEditingBubble);
win?.addEventListener("selectionchange", stopPanelSelectionChange, true);
return () => {
for (const type of EDIT_EVENTS) shadow.removeEventListener(type, stopEditingBubble);
win?.removeEventListener("selectionchange", stopPanelSelectionChange, true);
};
}
async function mount() {
if (await initPlatform() === false) return;
if (document.getElementById("cx-assistant-host")) return;
const host = document.createElement("div");
host.id = "cx-assistant-host";
document.documentElement.appendChild(host);
let removeInputIsolation;
try {
if (!document.body) {
await new Promise((resolve) => document.addEventListener("DOMContentLoaded", resolve, { once: true }));
}
const shadow = host.attachShadow({ mode: "open" });
removeInputIsolation = isolatePanelInputs(shadow);
const sheet = new CSSStyleSheet();
sheet.replaceSync(`:host{all:initial;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:13px;line-height:1.5715;color:rgba(0,0,0,.85)} ${getAntdCss()} ${componentCss}`);
shadow.adoptedStyleSheets = [sheet];
const container = document.createElement("div");
shadow.appendChild(container);
const app = vue.createApp(isZhihuishuHost(location.hostname) ? _sfc_main : _sfc_main$1).use(pinia.createPinia());
for (const component of [antDesignVue.Button, antDesignVue.Checkbox, antDesignVue.ConfigProvider, antDesignVue.Input, antDesignVue.InputNumber, antDesignVue.Modal, antDesignVue.Select, antDesignVue.Tabs]) app.use(component);
app.onUnmount(removeInputIsolation);
app.mount(container);
} catch (error) {
removeInputIsolation?.();
host.remove();
console.error("CX 助手启动失败:", error);
}
}
mount().catch((error) => console.error("CX 助手启动失败:", error));
function getDefaultExportFromCjs(x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
}
var dist = {};
var Typr = {};
var hasRequiredTypr;
function requireTypr() {
if (hasRequiredTypr) return Typr;
hasRequiredTypr = 1;
var Typr$1 = {};
Typr$1.parse = function(buff) {
var bin = Typr$1._bin;
var data = new Uint8Array(buff);
var tag = bin.readASCII(data, 0, 4);
if (tag == "ttcf") {
var offset = 4;
bin.readUshort(data, offset);
offset += 2;
bin.readUshort(data, offset);
offset += 2;
var numF = bin.readUint(data, offset);
offset += 4;
var fnts = [];
for (var i = 0; i < numF; i++) {
var foff = bin.readUint(data, offset);
offset += 4;
fnts.push(Typr$1._readFont(data, foff));
}
return fnts;
} else
return [Typr$1._readFont(data, 0)];
};
Typr$1._readFont = function(data, offset) {
var bin = Typr$1._bin;
var ooff = offset;
bin.readFixed(data, offset);
offset += 4;
var numTables = bin.readUshort(data, offset);
offset += 2;
bin.readUshort(data, offset);
offset += 2;
bin.readUshort(data, offset);
offset += 2;
bin.readUshort(data, offset);
offset += 2;
var tags = [
"cmap",
"head",
"hhea",
"maxp",
"hmtx",
"name",
"OS/2",
"post",
//"cvt",
//"fpgm",
"loca",
"glyf",
"kern",
//"prep"
//"gasp"
"CFF ",
"GPOS",
"GSUB",
"SVG "
//"VORG",
];
var obj = { _data: data, _offset: ooff };
var tabs = {};
for (var i = 0; i < numTables; i++) {
var tag = bin.readASCII(data, offset, 4);
offset += 4;
bin.readUint(data, offset);
offset += 4;
var toffset = bin.readUint(data, offset);
offset += 4;
var length = bin.readUint(data, offset);
offset += 4;
tabs[tag] = { offset: toffset, length };
}
for (var i = 0; i < tags.length; i++) {
var t = tags[i];
if (tabs[t])
obj[t.trim()] = Typr$1[t.trim()].parse(data, tabs[t].offset, tabs[t].length, obj);
}
return obj;
};
Typr$1._tabOffset = function(data, tab, foff) {
var bin = Typr$1._bin;
var numTables = bin.readUshort(data, foff + 4);
var offset = foff + 12;
for (var i = 0; i < numTables; i++) {
var tag = bin.readASCII(data, offset, 4);
offset += 4;
bin.readUint(data, offset);
offset += 4;
var toffset = bin.readUint(data, offset);
offset += 4;
bin.readUint(data, offset);
offset += 4;
if (tag == tab)
return toffset;
}
return 0;
};
Typr$1._bin = {
readFixed: function(data, o) {
return (data[o] << 8 | data[o + 1]) + (data[o + 2] << 8 | data[o + 3]) / (256 * 256 + 4);
},
readF2dot14: function(data, o) {
var num = Typr$1._bin.readShort(data, o);
return num / 16384;
},
readInt: function(buff, p) {
return Typr$1._bin._view(buff).getInt32(p);
},
readInt8: function(buff, p) {
return Typr$1._bin._view(buff).getInt8(p);
},
readShort: function(buff, p) {
return Typr$1._bin._view(buff).getInt16(p);
},
readUshort: function(buff, p) {
return Typr$1._bin._view(buff).getUint16(p);
},
readUshorts: function(buff, p, len) {
var arr = [];
for (var i = 0; i < len; i++)
arr.push(Typr$1._bin.readUshort(buff, p + i * 2));
return arr;
},
readUint: function(buff, p) {
return Typr$1._bin._view(buff).getUint32(p);
},
readUint64: function(buff, p) {
return Typr$1._bin.readUint(buff, p) * (4294967295 + 1) + Typr$1._bin.readUint(buff, p + 4);
},
readASCII: function(buff, p, l) {
var s = "";
for (var i = 0; i < l; i++)
s += String.fromCharCode(buff[p + i]);
return s;
},
readUnicode: function(buff, p, l) {
var s = "";
for (var i = 0; i < l; i++) {
var c = buff[p++] << 8 | buff[p++];
s += String.fromCharCode(c);
}
return s;
},
_tdec: typeof window !== "undefined" && window["TextDecoder"] ? new window["TextDecoder"]() : null,
readUTF8: function(buff, p, l) {
var tdec = Typr$1._bin._tdec;
if (tdec && p == 0 && l == buff.length)
return tdec["decode"](buff);
return Typr$1._bin.readASCII(buff, p, l);
},
readBytes: function(buff, p, l) {
var arr = [];
for (var i = 0; i < l; i++)
arr.push(buff[p + i]);
return arr;
},
readASCIIArray: function(buff, p, l) {
var s = [];
for (var i = 0; i < l; i++)
s.push(String.fromCharCode(buff[p + i]));
return s;
},
_view: function(buff) {
return buff._dataView || (buff._dataView = buff.buffer ? new DataView(buff.buffer, buff.byteOffset, buff.byteLength) : new DataView(new Uint8Array(buff).buffer));
}
};
Typr$1._lctf = {};
Typr$1._lctf.parse = function(data, offset, length, font, subt) {
var bin = Typr$1._bin;
var obj = {};
var offset0 = offset;
bin.readFixed(data, offset);
offset += 4;
var offScriptList = bin.readUshort(data, offset);
offset += 2;
var offFeatureList = bin.readUshort(data, offset);
offset += 2;
var offLookupList = bin.readUshort(data, offset);
offset += 2;
obj.scriptList = Typr$1._lctf.readScriptList(data, offset0 + offScriptList);
obj.featureList = Typr$1._lctf.readFeatureList(data, offset0 + offFeatureList);
obj.lookupList = Typr$1._lctf.readLookupList(data, offset0 + offLookupList, subt);
return obj;
};
Typr$1._lctf.readLookupList = function(data, offset, subt) {
var bin = Typr$1._bin;
var offset0 = offset;
var obj = [];
var count = bin.readUshort(data, offset);
offset += 2;
for (var i = 0; i < count; i++) {
var noff = bin.readUshort(data, offset);
offset += 2;
var lut = Typr$1._lctf.readLookupTable(data, offset0 + noff, subt);
obj.push(lut);
}
return obj;
};
Typr$1._lctf.readLookupTable = function(data, offset, subt) {
var bin = Typr$1._bin;
var offset0 = offset;
var obj = { tabs: [] };
obj.ltype = bin.readUshort(data, offset);
offset += 2;
obj.flag = bin.readUshort(data, offset);
offset += 2;
var cnt = bin.readUshort(data, offset);
offset += 2;
var ltype = obj.ltype;
for (var i = 0; i < cnt; i++) {
var noff = bin.readUshort(data, offset);
offset += 2;
var tab = subt(data, ltype, offset0 + noff, obj);
obj.tabs.push(tab);
}
return obj;
};
Typr$1._lctf.numOfOnes = function(n) {
var num = 0;
for (var i = 0; i < 32; i++)
if ((n >>> i & 1) != 0)
num++;
return num;
};
Typr$1._lctf.readClassDef = function(data, offset) {
var bin = Typr$1._bin;
var obj = [];
var format = bin.readUshort(data, offset);
offset += 2;
if (format == 1) {
var startGlyph = bin.readUshort(data, offset);
offset += 2;
var glyphCount = bin.readUshort(data, offset);
offset += 2;
for (var i = 0; i < glyphCount; i++) {
obj.push(startGlyph + i);
obj.push(startGlyph + i);
obj.push(bin.readUshort(data, offset));
offset += 2;
}
}
if (format == 2) {
var count = bin.readUshort(data, offset);
offset += 2;
for (var i = 0; i < count; i++) {
obj.push(bin.readUshort(data, offset));
offset += 2;
obj.push(bin.readUshort(data, offset));
offset += 2;
obj.push(bin.readUshort(data, offset));
offset += 2;
}
}
return obj;
};
Typr$1._lctf.getInterval = function(tab, val) {
for (var i = 0; i < tab.length; i += 3) {
var start = tab[i], end = tab[i + 1];
tab[i + 2];
if (start <= val && val <= end)
return i;
}
return -1;
};
Typr$1._lctf.readCoverage = function(data, offset) {
var bin = Typr$1._bin;
var cvg = {};
cvg.fmt = bin.readUshort(data, offset);
offset += 2;
var count = bin.readUshort(data, offset);
offset += 2;
if (cvg.fmt == 1)
cvg.tab = bin.readUshorts(data, offset, count);
if (cvg.fmt == 2)
cvg.tab = bin.readUshorts(data, offset, count * 3);
return cvg;
};
Typr$1._lctf.coverageIndex = function(cvg, val) {
var tab = cvg.tab;
if (cvg.fmt == 1)
return tab.indexOf(val);
if (cvg.fmt == 2) {
var ind = Typr$1._lctf.getInterval(tab, val);
if (ind != -1)
return tab[ind + 2] + (val - tab[ind]);
}
return -1;
};
Typr$1._lctf.readFeatureList = function(data, offset) {
var bin = Typr$1._bin;
var offset0 = offset;
var obj = [];
var count = bin.readUshort(data, offset);
offset += 2;
for (var i = 0; i < count; i++) {
var tag = bin.readASCII(data, offset, 4);
offset += 4;
var noff = bin.readUshort(data, offset);
offset += 2;
var feat = Typr$1._lctf.readFeatureTable(data, offset0 + noff);
feat.tag = tag.trim();
obj.push(feat);
}
return obj;
};
Typr$1._lctf.readFeatureTable = function(data, offset) {
var bin = Typr$1._bin;
var offset0 = offset;
var feat = {};
var featureParams = bin.readUshort(data, offset);
offset += 2;
if (featureParams > 0) {
feat.featureParams = offset0 + featureParams;
}
var lookupCount = bin.readUshort(data, offset);
offset += 2;
feat.tab = [];
for (var i = 0; i < lookupCount; i++)
feat.tab.push(bin.readUshort(data, offset + 2 * i));
return feat;
};
Typr$1._lctf.readScriptList = function(data, offset) {
var bin = Typr$1._bin;
var offset0 = offset;
var obj = {};
var count = bin.readUshort(data, offset);
offset += 2;
for (var i = 0; i < count; i++) {
var tag = bin.readASCII(data, offset, 4);
offset += 4;
var noff = bin.readUshort(data, offset);
offset += 2;
obj[tag.trim()] = Typr$1._lctf.readScriptTable(data, offset0 + noff);
}
return obj;
};
Typr$1._lctf.readScriptTable = function(data, offset) {
var bin = Typr$1._bin;
var offset0 = offset;
var obj = {};
var defLangSysOff = bin.readUshort(data, offset);
offset += 2;
if (defLangSysOff > 0) {
obj["default"] = Typr$1._lctf.readLangSysTable(data, offset0 + defLangSysOff);
}
var langSysCount = bin.readUshort(data, offset);
offset += 2;
for (var i = 0; i < langSysCount; i++) {
var tag = bin.readASCII(data, offset, 4);
offset += 4;
var langSysOff = bin.readUshort(data, offset);
offset += 2;
obj[tag.trim()] = Typr$1._lctf.readLangSysTable(data, offset0 + langSysOff);
}
return obj;
};
Typr$1._lctf.readLangSysTable = function(data, offset) {
var bin = Typr$1._bin;
var obj = {};
bin.readUshort(data, offset);
offset += 2;
obj.reqFeature = bin.readUshort(data, offset);
offset += 2;
var featureCount = bin.readUshort(data, offset);
offset += 2;
obj.features = bin.readUshorts(data, offset, featureCount);
return obj;
};
Typr$1.CFF = {};
Typr$1.CFF.parse = function(data, offset, length) {
var bin = Typr$1._bin;
data = new Uint8Array(data.buffer, offset, length);
offset = 0;
data[offset];
offset++;
data[offset];
offset++;
data[offset];
offset++;
data[offset];
offset++;
var ninds = [];
offset = Typr$1.CFF.readIndex(data, offset, ninds);
var names2 = [];
for (var i = 0; i < ninds.length - 1; i++)
names2.push(bin.readASCII(data, offset + ninds[i], ninds[i + 1] - ninds[i]));
offset += ninds[ninds.length - 1];
var tdinds = [];
offset = Typr$1.CFF.readIndex(data, offset, tdinds);
var topDicts = [];
for (var i = 0; i < tdinds.length - 1; i++)
topDicts.push(Typr$1.CFF.readDict(data, offset + tdinds[i], offset + tdinds[i + 1]));
offset += tdinds[tdinds.length - 1];
var topdict = topDicts[0];
var sinds = [];
offset = Typr$1.CFF.readIndex(data, offset, sinds);
var strings = [];
for (var i = 0; i < sinds.length - 1; i++)
strings.push(bin.readASCII(data, offset + sinds[i], sinds[i + 1] - sinds[i]));
offset += sinds[sinds.length - 1];
Typr$1.CFF.readSubrs(data, offset, topdict);
if (topdict.CharStrings) {
offset = topdict.CharStrings;
var sinds = [];
offset = Typr$1.CFF.readIndex(data, offset, sinds);
var cstr = [];
for (var i = 0; i < sinds.length - 1; i++)
cstr.push(bin.readBytes(data, offset + sinds[i], sinds[i + 1] - sinds[i]));
topdict.CharStrings = cstr;
}
if (topdict.ROS) {
offset = topdict.FDArray;
var fdind = [];
offset = Typr$1.CFF.readIndex(data, offset, fdind);
topdict.FDArray = [];
for (var i = 0; i < fdind.length - 1; i++) {
var dict = Typr$1.CFF.readDict(data, offset + fdind[i], offset + fdind[i + 1]);
Typr$1.CFF._readFDict(data, dict, strings);
topdict.FDArray.push(dict);
}
offset += fdind[fdind.length - 1];
offset = topdict.FDSelect;
topdict.FDSelect = [];
var fmt = data[offset];
offset++;
if (fmt == 3) {
var rns = bin.readUshort(data, offset);
offset += 2;
for (var i = 0; i < rns + 1; i++) {
topdict.FDSelect.push(bin.readUshort(data, offset), data[offset + 2]);
offset += 3;
}
} else
throw fmt;
}
if (topdict.Encoding)
topdict.Encoding = Typr$1.CFF.readEncoding(data, topdict.Encoding, topdict.CharStrings.length);
if (topdict.charset)
topdict.charset = Typr$1.CFF.readCharset(data, topdict.charset, topdict.CharStrings.length);
Typr$1.CFF._readFDict(data, topdict, strings);
return topdict;
};
Typr$1.CFF._readFDict = function(data, dict, ss) {
var offset;
if (dict.Private) {
offset = dict.Private[1];
dict.Private = Typr$1.CFF.readDict(data, offset, offset + dict.Private[0]);
if (dict.Private.Subrs)
Typr$1.CFF.readSubrs(data, offset + dict.Private.Subrs, dict.Private);
}
for (var p in dict)
if (["FamilyName", "FontName", "FullName", "Notice", "version", "Copyright"].indexOf(p) != -1)
dict[p] = ss[dict[p] - 426 + 35];
};
Typr$1.CFF.readSubrs = function(data, offset, obj) {
var bin = Typr$1._bin;
var gsubinds = [];
offset = Typr$1.CFF.readIndex(data, offset, gsubinds);
var bias, nSubrs = gsubinds.length;
if (nSubrs < 1240)
bias = 107;
else if (nSubrs < 33900)
bias = 1131;
else
bias = 32768;
obj.Bias = bias;
obj.Subrs = [];
for (var i = 0; i < gsubinds.length - 1; i++)
obj.Subrs.push(bin.readBytes(data, offset + gsubinds[i], gsubinds[i + 1] - gsubinds[i]));
};
Typr$1.CFF.tableSE = [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
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,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
96,
97,
98,
99,
100,
101,
102,
103,
104,
105,
106,
107,
108,
109,
110,
0,
111,
112,
113,
114,
0,
115,
116,
117,
118,
119,
120,
121,
122,
0,
123,
0,
124,
125,
126,
127,
128,
129,
130,
131,
0,
132,
133,
0,
134,
135,
136,
137,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
138,
0,
139,
0,
0,
0,
0,
140,
141,
142,
143,
0,
0,
0,
0,
0,
144,
0,
0,
0,
145,
0,
0,
146,
147,
148,
149,
0,
0,
0,
0
];
Typr$1.CFF.glyphByUnicode = function(cff, code) {
for (var i = 0; i < cff.charset.length; i++)
if (cff.charset[i] == code)
return i;
return -1;
};
Typr$1.CFF.glyphBySE = function(cff, charcode) {
if (charcode < 0 || charcode > 255)
return -1;
return Typr$1.CFF.glyphByUnicode(cff, Typr$1.CFF.tableSE[charcode]);
};
Typr$1.CFF.readEncoding = function(data, offset, num) {
Typr$1._bin;
var array = [".notdef"];
var format = data[offset];
offset++;
if (format == 0) {
var nCodes = data[offset];
offset++;
for (var i = 0; i < nCodes; i++)
array.push(data[offset + i]);
} else
throw "error: unknown encoding format: " + format;
return array;
};
Typr$1.CFF.readCharset = function(data, offset, num) {
var bin = Typr$1._bin;
var charset = [".notdef"];
var format = data[offset];
offset++;
if (format == 0) {
for (var i = 0; i < num; i++) {
var first2 = bin.readUshort(data, offset);
offset += 2;
charset.push(first2);
}
} else if (format == 1 || format == 2) {
while (charset.length < num) {
var first2 = bin.readUshort(data, offset);
offset += 2;
var nLeft = 0;
if (format == 1) {
nLeft = data[offset];
offset++;
} else {
nLeft = bin.readUshort(data, offset);
offset += 2;
}
for (var i = 0; i <= nLeft; i++) {
charset.push(first2);
first2++;
}
}
} else
throw "error: format: " + format;
return charset;
};
Typr$1.CFF.readIndex = function(data, offset, inds) {
var bin = Typr$1._bin;
var count = bin.readUshort(data, offset) + 1;
offset += 2;
var offsize = data[offset];
offset++;
if (offsize == 1)
for (var i = 0; i < count; i++)
inds.push(data[offset + i]);
else if (offsize == 2)
for (var i = 0; i < count; i++)
inds.push(bin.readUshort(data, offset + i * 2));
else if (offsize == 3)
for (var i = 0; i < count; i++)
inds.push(bin.readUint(data, offset + i * 3 - 1) & 16777215);
else if (count != 1)
throw "unsupported offset size: " + offsize + ", count: " + count;
offset += count * offsize;
return offset - 1;
};
Typr$1.CFF.getCharString = function(data, offset, o) {
var bin = Typr$1._bin;
var b0 = data[offset], b1 = data[offset + 1];
data[offset + 2];
data[offset + 3];
data[offset + 4];
var vs = 1;
var op = null, val = null;
if (b0 <= 20) {
op = b0;
vs = 1;
}
if (b0 == 12) {
op = b0 * 100 + b1;
vs = 2;
}
if (21 <= b0 && b0 <= 27) {
op = b0;
vs = 1;
}
if (b0 == 28) {
val = bin.readShort(data, offset + 1);
vs = 3;
}
if (29 <= b0 && b0 <= 31) {
op = b0;
vs = 1;
}
if (32 <= b0 && b0 <= 246) {
val = b0 - 139;
vs = 1;
}
if (247 <= b0 && b0 <= 250) {
val = (b0 - 247) * 256 + b1 + 108;
vs = 2;
}
if (251 <= b0 && b0 <= 254) {
val = -(b0 - 251) * 256 - b1 - 108;
vs = 2;
}
if (b0 == 255) {
val = bin.readInt(data, offset + 1) / 65535;
vs = 5;
}
o.val = val != null ? val : "o" + op;
o.size = vs;
};
Typr$1.CFF.readCharString = function(data, offset, length) {
var end = offset + length;
var bin = Typr$1._bin;
var arr = [];
while (offset < end) {
var b0 = data[offset], b1 = data[offset + 1];
data[offset + 2];
data[offset + 3];
data[offset + 4];
var vs = 1;
var op = null, val = null;
if (b0 <= 20) {
op = b0;
vs = 1;
}
if (b0 == 12) {
op = b0 * 100 + b1;
vs = 2;
}
if (b0 == 19 || b0 == 20) {
op = b0;
vs = 2;
}
if (21 <= b0 && b0 <= 27) {
op = b0;
vs = 1;
}
if (b0 == 28) {
val = bin.readShort(data, offset + 1);
vs = 3;
}
if (29 <= b0 && b0 <= 31) {
op = b0;
vs = 1;
}
if (32 <= b0 && b0 <= 246) {
val = b0 - 139;
vs = 1;
}
if (247 <= b0 && b0 <= 250) {
val = (b0 - 247) * 256 + b1 + 108;
vs = 2;
}
if (251 <= b0 && b0 <= 254) {
val = -(b0 - 251) * 256 - b1 - 108;
vs = 2;
}
if (b0 == 255) {
val = bin.readInt(data, offset + 1) / 65535;
vs = 5;
}
arr.push(val != null ? val : "o" + op);
offset += vs;
}
return arr;
};
Typr$1.CFF.readDict = function(data, offset, end) {
var bin = Typr$1._bin;
var dict = {};
var carr = [];
while (offset < end) {
var b0 = data[offset], b1 = data[offset + 1];
data[offset + 2];
data[offset + 3];
data[offset + 4];
var vs = 1;
var key = null, val = null;
if (b0 == 28) {
val = bin.readShort(data, offset + 1);
vs = 3;
}
if (b0 == 29) {
val = bin.readInt(data, offset + 1);
vs = 5;
}
if (32 <= b0 && b0 <= 246) {
val = b0 - 139;
vs = 1;
}
if (247 <= b0 && b0 <= 250) {
val = (b0 - 247) * 256 + b1 + 108;
vs = 2;
}
if (251 <= b0 && b0 <= 254) {
val = -(b0 - 251) * 256 - b1 - 108;
vs = 2;
}
if (b0 == 255) {
val = bin.readInt(data, offset + 1) / 65535;
vs = 5;
throw "unknown number";
}
if (b0 == 30) {
var nibs = [];
vs = 1;
while (true) {
var b = data[offset + vs];
vs++;
var nib0 = b >> 4, nib1 = b & 15;
if (nib0 != 15)
nibs.push(nib0);
if (nib1 != 15)
nibs.push(nib1);
if (nib1 == 15)
break;
}
var s = "";
var chars = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ".", "e", "e-", "reserved", "-", "endOfNumber"];
for (var i = 0; i < nibs.length; i++)
s += chars[nibs[i]];
val = parseFloat(s);
}
if (b0 <= 21) {
var keys = [
"version",
"Notice",
"FullName",
"FamilyName",
"Weight",
"FontBBox",
"BlueValues",
"OtherBlues",
"FamilyBlues",
"FamilyOtherBlues",
"StdHW",
"StdVW",
"escape",
"UniqueID",
"XUID",
"charset",
"Encoding",
"CharStrings",
"Private",
"Subrs",
"defaultWidthX",
"nominalWidthX"
];
key = keys[b0];
vs = 1;
if (b0 == 12) {
var keys = [
"Copyright",
"isFixedPitch",
"ItalicAngle",
"UnderlinePosition",
"UnderlineThickness",
"PaintType",
"CharstringType",
"FontMatrix",
"StrokeWidth",
"BlueScale",
"BlueShift",
"BlueFuzz",
"StemSnapH",
"StemSnapV",
"ForceBold",
0,
0,
"LanguageGroup",
"ExpansionFactor",
"initialRandomSeed",
"SyntheticBase",
"PostScript",
"BaseFontName",
"BaseFontBlend",
0,
0,
0,
0,
0,
0,
"ROS",
"CIDFontVersion",
"CIDFontRevision",
"CIDFontType",
"CIDCount",
"UIDBase",
"FDArray",
"FDSelect",
"FontName"
];
key = keys[b1];
vs = 2;
}
}
if (key != null) {
dict[key] = carr.length == 1 ? carr[0] : carr;
carr = [];
} else
carr.push(val);
offset += vs;
}
return dict;
};
Typr$1.cmap = {};
Typr$1.cmap.parse = function(data, offset, length) {
data = new Uint8Array(data.buffer, offset, length);
offset = 0;
var bin = Typr$1._bin;
var obj = {};
bin.readUshort(data, offset);
offset += 2;
var numTables = bin.readUshort(data, offset);
offset += 2;
var offs = [];
obj.tables = [];
for (var i = 0; i < numTables; i++) {
var platformID = bin.readUshort(data, offset);
offset += 2;
var encodingID = bin.readUshort(data, offset);
offset += 2;
var noffset = bin.readUint(data, offset);
offset += 4;
var id = "p" + platformID + "e" + encodingID;
var tind = offs.indexOf(noffset);
if (tind == -1) {
tind = obj.tables.length;
var subt;
offs.push(noffset);
var format = bin.readUshort(data, noffset);
if (format == 0)
subt = Typr$1.cmap.parse0(data, noffset);
else if (format == 4)
subt = Typr$1.cmap.parse4(data, noffset);
else if (format == 6)
subt = Typr$1.cmap.parse6(data, noffset);
else if (format == 12)
subt = Typr$1.cmap.parse12(data, noffset);
else
console.warn("unknown format: " + format, platformID, encodingID, noffset);
obj.tables.push(subt);
}
if (obj[id] != null)
throw "multiple tables for one platform+encoding";
obj[id] = tind;
}
return obj;
};
Typr$1.cmap.parse0 = function(data, offset) {
var bin = Typr$1._bin;
var obj = {};
obj.format = bin.readUshort(data, offset);
offset += 2;
var len = bin.readUshort(data, offset);
offset += 2;
bin.readUshort(data, offset);
offset += 2;
obj.map = [];
for (var i = 0; i < len - 6; i++)
obj.map.push(data[offset + i]);
return obj;
};
Typr$1.cmap.parse4 = function(data, offset) {
var bin = Typr$1._bin;
var offset0 = offset;
var obj = {};
obj.format = bin.readUshort(data, offset);
offset += 2;
var length = bin.readUshort(data, offset);
offset += 2;
bin.readUshort(data, offset);
offset += 2;
var segCountX2 = bin.readUshort(data, offset);
offset += 2;
var segCount = segCountX2 / 2;
obj.searchRange = bin.readUshort(data, offset);
offset += 2;
obj.entrySelector = bin.readUshort(data, offset);
offset += 2;
obj.rangeShift = bin.readUshort(data, offset);
offset += 2;
obj.endCount = bin.readUshorts(data, offset, segCount);
offset += segCount * 2;
offset += 2;
obj.startCount = bin.readUshorts(data, offset, segCount);
offset += segCount * 2;
obj.idDelta = [];
for (var i = 0; i < segCount; i++) {
obj.idDelta.push(bin.readShort(data, offset));
offset += 2;
}
obj.idRangeOffset = bin.readUshorts(data, offset, segCount);
offset += segCount * 2;
obj.glyphIdArray = [];
while (offset < offset0 + length) {
obj.glyphIdArray.push(bin.readUshort(data, offset));
offset += 2;
}
return obj;
};
Typr$1.cmap.parse6 = function(data, offset) {
var bin = Typr$1._bin;
var obj = {};
obj.format = bin.readUshort(data, offset);
offset += 2;
bin.readUshort(data, offset);
offset += 2;
bin.readUshort(data, offset);
offset += 2;
obj.firstCode = bin.readUshort(data, offset);
offset += 2;
var entryCount = bin.readUshort(data, offset);
offset += 2;
obj.glyphIdArray = [];
for (var i = 0; i < entryCount; i++) {
obj.glyphIdArray.push(bin.readUshort(data, offset));
offset += 2;
}
return obj;
};
Typr$1.cmap.parse12 = function(data, offset) {
var bin = Typr$1._bin;
var obj = {};
obj.format = bin.readUshort(data, offset);
offset += 2;
offset += 2;
bin.readUint(data, offset);
offset += 4;
bin.readUint(data, offset);
offset += 4;
var nGroups = bin.readUint(data, offset);
offset += 4;
obj.groups = [];
for (var i = 0; i < nGroups; i++) {
var off = offset + i * 12;
var startCharCode = bin.readUint(data, off + 0);
var endCharCode = bin.readUint(data, off + 4);
var startGlyphID = bin.readUint(data, off + 8);
obj.groups.push([startCharCode, endCharCode, startGlyphID]);
}
return obj;
};
Typr$1.glyf = {};
Typr$1.glyf.parse = function(data, offset, length, font) {
var obj = [];
for (var g = 0; g < font.maxp.numGlyphs; g++)
obj.push(null);
return obj;
};
Typr$1.glyf._parseGlyf = function(font, g) {
var bin = Typr$1._bin;
var data = font._data;
var offset = Typr$1._tabOffset(data, "glyf", font._offset) + font.loca[g];
if (font.loca[g] == font.loca[g + 1])
return null;
var gl = {};
gl.noc = bin.readShort(data, offset);
offset += 2;
gl.xMin = bin.readShort(data, offset);
offset += 2;
gl.yMin = bin.readShort(data, offset);
offset += 2;
gl.xMax = bin.readShort(data, offset);
offset += 2;
gl.yMax = bin.readShort(data, offset);
offset += 2;
if (gl.xMin >= gl.xMax || gl.yMin >= gl.yMax)
return null;
if (gl.noc > 0) {
gl.endPts = [];
for (var i = 0; i < gl.noc; i++) {
gl.endPts.push(bin.readUshort(data, offset));
offset += 2;
}
var instructionLength = bin.readUshort(data, offset);
offset += 2;
if (data.length - offset < instructionLength)
return null;
gl.instructions = bin.readBytes(data, offset, instructionLength);
offset += instructionLength;
var crdnum = gl.endPts[gl.noc - 1] + 1;
gl.flags = [];
for (var i = 0; i < crdnum; i++) {
var flag = data[offset];
offset++;
gl.flags.push(flag);
if ((flag & 8) != 0) {
var rep = data[offset];
offset++;
for (var j = 0; j < rep; j++) {
gl.flags.push(flag);
i++;
}
}
}
gl.xs = [];
for (var i = 0; i < crdnum; i++) {
var i8 = (gl.flags[i] & 2) != 0, same = (gl.flags[i] & 16) != 0;
if (i8) {
gl.xs.push(same ? data[offset] : -data[offset]);
offset++;
} else {
if (same)
gl.xs.push(0);
else {
gl.xs.push(bin.readShort(data, offset));
offset += 2;
}
}
}
gl.ys = [];
for (var i = 0; i < crdnum; i++) {
var i8 = (gl.flags[i] & 4) != 0, same = (gl.flags[i] & 32) != 0;
if (i8) {
gl.ys.push(same ? data[offset] : -data[offset]);
offset++;
} else {
if (same)
gl.ys.push(0);
else {
gl.ys.push(bin.readShort(data, offset));
offset += 2;
}
}
}
var x = 0, y = 0;
for (var i = 0; i < crdnum; i++) {
x += gl.xs[i];
y += gl.ys[i];
gl.xs[i] = x;
gl.ys[i] = y;
}
} else {
var ARG_1_AND_2_ARE_WORDS = 1 << 0;
var ARGS_ARE_XY_VALUES = 1 << 1;
var WE_HAVE_A_SCALE = 1 << 3;
var MORE_COMPONENTS = 1 << 5;
var WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6;
var WE_HAVE_A_TWO_BY_TWO = 1 << 7;
var WE_HAVE_INSTRUCTIONS = 1 << 8;
gl.parts = [];
var flags;
do {
flags = bin.readUshort(data, offset);
offset += 2;
var part = { m: { a: 1, b: 0, c: 0, d: 1, tx: 0, ty: 0 }, p1: -1, p2: -1 };
gl.parts.push(part);
part.glyphIndex = bin.readUshort(data, offset);
offset += 2;
if (flags & ARG_1_AND_2_ARE_WORDS) {
var arg1 = bin.readShort(data, offset);
offset += 2;
var arg2 = bin.readShort(data, offset);
offset += 2;
} else {
var arg1 = bin.readInt8(data, offset);
offset++;
var arg2 = bin.readInt8(data, offset);
offset++;
}
if (flags & ARGS_ARE_XY_VALUES) {
part.m.tx = arg1;
part.m.ty = arg2;
} else {
part.p1 = arg1;
part.p2 = arg2;
}
if (flags & WE_HAVE_A_SCALE) {
part.m.a = part.m.d = bin.readF2dot14(data, offset);
offset += 2;
} else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
part.m.a = bin.readF2dot14(data, offset);
offset += 2;
part.m.d = bin.readF2dot14(data, offset);
offset += 2;
} else if (flags & WE_HAVE_A_TWO_BY_TWO) {
part.m.a = bin.readF2dot14(data, offset);
offset += 2;
part.m.b = bin.readF2dot14(data, offset);
offset += 2;
part.m.c = bin.readF2dot14(data, offset);
offset += 2;
part.m.d = bin.readF2dot14(data, offset);
offset += 2;
}
} while (flags & MORE_COMPONENTS);
if (flags & WE_HAVE_INSTRUCTIONS) {
var numInstr = bin.readUshort(data, offset);
offset += 2;
gl.instr = [];
for (var i = 0; i < numInstr; i++) {
gl.instr.push(data[offset]);
offset++;
}
}
}
return gl;
};
Typr$1.GPOS = {};
Typr$1.GPOS.parse = function(data, offset, length, font) {
return Typr$1._lctf.parse(data, offset, length, font, Typr$1.GPOS.subt);
};
Typr$1.GPOS.subt = function(data, ltype, offset, ltable) {
var bin = Typr$1._bin, offset0 = offset, tab = {};
tab.fmt = bin.readUshort(data, offset);
offset += 2;
if (ltype == 1 || ltype == 2 || ltype == 3 || ltype == 7 || ltype == 8 && tab.fmt <= 2) {
var covOff = bin.readUshort(data, offset);
offset += 2;
tab.coverage = Typr$1._lctf.readCoverage(data, covOff + offset0);
}
if (ltype == 1 && tab.fmt == 1) {
var valFmt1 = bin.readUshort(data, offset);
offset += 2;
var ones1 = Typr$1._lctf.numOfOnes(valFmt1);
if (valFmt1 != 0)
tab.pos = Typr$1.GPOS.readValueRecord(data, offset, valFmt1);
} else if (ltype == 2 && tab.fmt >= 1 && tab.fmt <= 2) {
var valFmt1 = bin.readUshort(data, offset);
offset += 2;
var valFmt2 = bin.readUshort(data, offset);
offset += 2;
var ones1 = Typr$1._lctf.numOfOnes(valFmt1);
var ones2 = Typr$1._lctf.numOfOnes(valFmt2);
if (tab.fmt == 1) {
tab.pairsets = [];
var psc = bin.readUshort(data, offset);
offset += 2;
for (var i = 0; i < psc; i++) {
var psoff = offset0 + bin.readUshort(data, offset);
offset += 2;
var pvc = bin.readUshort(data, psoff);
psoff += 2;
var arr = [];
for (var j = 0; j < pvc; j++) {
var gid2 = bin.readUshort(data, psoff);
psoff += 2;
var value1, value2;
if (valFmt1 != 0) {
value1 = Typr$1.GPOS.readValueRecord(data, psoff, valFmt1);
psoff += ones1 * 2;
}
if (valFmt2 != 0) {
value2 = Typr$1.GPOS.readValueRecord(data, psoff, valFmt2);
psoff += ones2 * 2;
}
arr.push({ gid2, val1: value1, val2: value2 });
}
tab.pairsets.push(arr);
}
}
if (tab.fmt == 2) {
var classDef1 = bin.readUshort(data, offset);
offset += 2;
var classDef2 = bin.readUshort(data, offset);
offset += 2;
var class1Count = bin.readUshort(data, offset);
offset += 2;
var class2Count = bin.readUshort(data, offset);
offset += 2;
tab.classDef1 = Typr$1._lctf.readClassDef(data, offset0 + classDef1);
tab.classDef2 = Typr$1._lctf.readClassDef(data, offset0 + classDef2);
tab.matrix = [];
for (var i = 0; i < class1Count; i++) {
var row = [];
for (var j = 0; j < class2Count; j++) {
var value1 = null, value2 = null;
if (valFmt1 != 0) {
value1 = Typr$1.GPOS.readValueRecord(data, offset, valFmt1);
offset += ones1 * 2;
}
if (valFmt2 != 0) {
value2 = Typr$1.GPOS.readValueRecord(data, offset, valFmt2);
offset += ones2 * 2;
}
row.push({ val1: value1, val2: value2 });
}
tab.matrix.push(row);
}
}
} else if (ltype == 9 && tab.fmt == 1) {
var extType = bin.readUshort(data, offset);
offset += 2;
var extOffset = bin.readUint(data, offset);
offset += 4;
if (ltable.ltype == 9) {
ltable.ltype = extType;
} else if (ltable.ltype != extType) {
throw "invalid extension substitution";
}
return Typr$1.GPOS.subt(data, ltable.ltype, offset0 + extOffset);
} else
console.warn("unsupported GPOS table LookupType", ltype, "format", tab.fmt);
return tab;
};
Typr$1.GPOS.readValueRecord = function(data, offset, valFmt) {
var bin = Typr$1._bin;
var arr = [];
arr.push(valFmt & 1 ? bin.readShort(data, offset) : 0);
offset += valFmt & 1 ? 2 : 0;
arr.push(valFmt & 2 ? bin.readShort(data, offset) : 0);
offset += valFmt & 2 ? 2 : 0;
arr.push(valFmt & 4 ? bin.readShort(data, offset) : 0);
offset += valFmt & 4 ? 2 : 0;
arr.push(valFmt & 8 ? bin.readShort(data, offset) : 0);
offset += valFmt & 8 ? 2 : 0;
return arr;
};
Typr$1.GSUB = {};
Typr$1.GSUB.parse = function(data, offset, length, font) {
return Typr$1._lctf.parse(data, offset, length, font, Typr$1.GSUB.subt);
};
Typr$1.GSUB.subt = function(data, ltype, offset, ltable) {
var bin = Typr$1._bin, offset0 = offset, tab = {};
tab.fmt = bin.readUshort(data, offset);
offset += 2;
if (ltype != 1 && ltype != 4 && ltype != 5 && ltype != 6)
return null;
if (ltype == 1 || ltype == 4 || ltype == 5 && tab.fmt <= 2 || ltype == 6 && tab.fmt <= 2) {
var covOff = bin.readUshort(data, offset);
offset += 2;
tab.coverage = Typr$1._lctf.readCoverage(data, offset0 + covOff);
}
if (ltype == 1 && tab.fmt >= 1 && tab.fmt <= 2) {
if (tab.fmt == 1) {
tab.delta = bin.readShort(data, offset);
offset += 2;
} else if (tab.fmt == 2) {
var cnt = bin.readUshort(data, offset);
offset += 2;
tab.newg = bin.readUshorts(data, offset, cnt);
offset += tab.newg.length * 2;
}
} else if (ltype == 4) {
tab.vals = [];
var cnt = bin.readUshort(data, offset);
offset += 2;
for (var i = 0; i < cnt; i++) {
var loff = bin.readUshort(data, offset);
offset += 2;
tab.vals.push(Typr$1.GSUB.readLigatureSet(data, offset0 + loff));
}
} else if (ltype == 5 && tab.fmt == 2) {
if (tab.fmt == 2) {
var cDefOffset = bin.readUshort(data, offset);
offset += 2;
tab.cDef = Typr$1._lctf.readClassDef(data, offset0 + cDefOffset);
tab.scset = [];
var subClassSetCount = bin.readUshort(data, offset);
offset += 2;
for (var i = 0; i < subClassSetCount; i++) {
var scsOff = bin.readUshort(data, offset);
offset += 2;
tab.scset.push(scsOff == 0 ? null : Typr$1.GSUB.readSubClassSet(data, offset0 + scsOff));
}
}
} else if (ltype == 6 && tab.fmt == 3) {
if (tab.fmt == 3) {
for (var i = 0; i < 3; i++) {
var cnt = bin.readUshort(data, offset);
offset += 2;
var cvgs = [];
for (var j = 0; j < cnt; j++)
cvgs.push(Typr$1._lctf.readCoverage(data, offset0 + bin.readUshort(data, offset + j * 2)));
offset += cnt * 2;
if (i == 0)
tab.backCvg = cvgs;
if (i == 1)
tab.inptCvg = cvgs;
if (i == 2)
tab.ahedCvg = cvgs;
}
var cnt = bin.readUshort(data, offset);
offset += 2;
tab.lookupRec = Typr$1.GSUB.readSubstLookupRecords(data, offset, cnt);
}
} else if (ltype == 7 && tab.fmt == 1) {
var extType = bin.readUshort(data, offset);
offset += 2;
var extOffset = bin.readUint(data, offset);
offset += 4;
if (ltable.ltype == 9) {
ltable.ltype = extType;
} else if (ltable.ltype != extType) {
throw "invalid extension substitution";
}
return Typr$1.GSUB.subt(data, ltable.ltype, offset0 + extOffset);
} else
console.warn("unsupported GSUB table LookupType", ltype, "format", tab.fmt);
return tab;
};
Typr$1.GSUB.readSubClassSet = function(data, offset) {
var rUs = Typr$1._bin.readUshort, offset0 = offset, lset = [];
var cnt = rUs(data, offset);
offset += 2;
for (var i = 0; i < cnt; i++) {
var loff = rUs(data, offset);
offset += 2;
lset.push(Typr$1.GSUB.readSubClassRule(data, offset0 + loff));
}
return lset;
};
Typr$1.GSUB.readSubClassRule = function(data, offset) {
var rUs = Typr$1._bin.readUshort, rule = {};
var gcount = rUs(data, offset);
offset += 2;
var scount = rUs(data, offset);
offset += 2;
rule.input = [];
for (var i = 0; i < gcount - 1; i++) {
rule.input.push(rUs(data, offset));
offset += 2;
}
rule.substLookupRecords = Typr$1.GSUB.readSubstLookupRecords(data, offset, scount);
return rule;
};
Typr$1.GSUB.readSubstLookupRecords = function(data, offset, cnt) {
var rUs = Typr$1._bin.readUshort;
var out = [];
for (var i = 0; i < cnt; i++) {
out.push(rUs(data, offset), rUs(data, offset + 2));
offset += 4;
}
return out;
};
Typr$1.GSUB.readChainSubClassSet = function(data, offset) {
var bin = Typr$1._bin, offset0 = offset, lset = [];
var cnt = bin.readUshort(data, offset);
offset += 2;
for (var i = 0; i < cnt; i++) {
var loff = bin.readUshort(data, offset);
offset += 2;
lset.push(Typr$1.GSUB.readChainSubClassRule(data, offset0 + loff));
}
return lset;
};
Typr$1.GSUB.readChainSubClassRule = function(data, offset) {
var bin = Typr$1._bin, rule = {};
var pps = ["backtrack", "input", "lookahead"];
for (var pi = 0; pi < pps.length; pi++) {
var cnt = bin.readUshort(data, offset);
offset += 2;
if (pi == 1)
cnt--;
rule[pps[pi]] = bin.readUshorts(data, offset, cnt);
offset += rule[pps[pi]].length * 2;
}
var cnt = bin.readUshort(data, offset);
offset += 2;
rule.subst = bin.readUshorts(data, offset, cnt * 2);
offset += rule.subst.length * 2;
return rule;
};
Typr$1.GSUB.readLigatureSet = function(data, offset) {
var bin = Typr$1._bin, offset0 = offset, lset = [];
var lcnt = bin.readUshort(data, offset);
offset += 2;
for (var j = 0; j < lcnt; j++) {
var loff = bin.readUshort(data, offset);
offset += 2;
lset.push(Typr$1.GSUB.readLigature(data, offset0 + loff));
}
return lset;
};
Typr$1.GSUB.readLigature = function(data, offset) {
var bin = Typr$1._bin, lig = { chain: [] };
lig.nglyph = bin.readUshort(data, offset);
offset += 2;
var ccnt = bin.readUshort(data, offset);
offset += 2;
for (var k = 0; k < ccnt - 1; k++) {
lig.chain.push(bin.readUshort(data, offset));
offset += 2;
}
return lig;
};
Typr$1.head = {};
Typr$1.head.parse = function(data, offset, length) {
var bin = Typr$1._bin;
var obj = {};
bin.readFixed(data, offset);
offset += 4;
obj.fontRevision = bin.readFixed(data, offset);
offset += 4;
bin.readUint(data, offset);
offset += 4;
bin.readUint(data, offset);
offset += 4;
obj.flags = bin.readUshort(data, offset);
offset += 2;
obj.unitsPerEm = bin.readUshort(data, offset);
offset += 2;
obj.created = bin.readUint64(data, offset);
offset += 8;
obj.modified = bin.readUint64(data, offset);
offset += 8;
obj.xMin = bin.readShort(data, offset);
offset += 2;
obj.yMin = bin.readShort(data, offset);
offset += 2;
obj.xMax = bin.readShort(data, offset);
offset += 2;
obj.yMax = bin.readShort(data, offset);
offset += 2;
obj.macStyle = bin.readUshort(data, offset);
offset += 2;
obj.lowestRecPPEM = bin.readUshort(data, offset);
offset += 2;
obj.fontDirectionHint = bin.readShort(data, offset);
offset += 2;
obj.indexToLocFormat = bin.readShort(data, offset);
offset += 2;
obj.glyphDataFormat = bin.readShort(data, offset);
offset += 2;
return obj;
};
Typr$1.hhea = {};
Typr$1.hhea.parse = function(data, offset, length) {
var bin = Typr$1._bin;
var obj = {};
bin.readFixed(data, offset);
offset += 4;
obj.ascender = bin.readShort(data, offset);
offset += 2;
obj.descender = bin.readShort(data, offset);
offset += 2;
obj.lineGap = bin.readShort(data, offset);
offset += 2;
obj.advanceWidthMax = bin.readUshort(data, offset);
offset += 2;
obj.minLeftSideBearing = bin.readShort(data, offset);
offset += 2;
obj.minRightSideBearing = bin.readShort(data, offset);
offset += 2;
obj.xMaxExtent = bin.readShort(data, offset);
offset += 2;
obj.caretSlopeRise = bin.readShort(data, offset);
offset += 2;
obj.caretSlopeRun = bin.readShort(data, offset);
offset += 2;
obj.caretOffset = bin.readShort(data, offset);
offset += 2;
offset += 4 * 2;
obj.metricDataFormat = bin.readShort(data, offset);
offset += 2;
obj.numberOfHMetrics = bin.readUshort(data, offset);
offset += 2;
return obj;
};
Typr$1.hmtx = {};
Typr$1.hmtx.parse = function(data, offset, length, font) {
var bin = Typr$1._bin;
var obj = {};
obj.aWidth = [];
obj.lsBearing = [];
var aw = 0, lsb = 0;
for (var i = 0; i < font.maxp.numGlyphs; i++) {
if (i < font.hhea.numberOfHMetrics) {
aw = bin.readUshort(data, offset);
offset += 2;
lsb = bin.readShort(data, offset);
offset += 2;
}
obj.aWidth.push(aw);
obj.lsBearing.push(lsb);
}
return obj;
};
Typr$1.kern = {};
Typr$1.kern.parse = function(data, offset, length, font) {
var bin = Typr$1._bin;
var version = bin.readUshort(data, offset);
offset += 2;
if (version == 1)
return Typr$1.kern.parseV1(data, offset - 2, length, font);
var nTables = bin.readUshort(data, offset);
offset += 2;
var map = { glyph1: [], rval: [] };
for (var i = 0; i < nTables; i++) {
offset += 2;
var length = bin.readUshort(data, offset);
offset += 2;
var coverage = bin.readUshort(data, offset);
offset += 2;
var format = coverage >>> 8;
format &= 15;
if (format == 0)
offset = Typr$1.kern.readFormat0(data, offset, map);
else
throw "unknown kern table format: " + format;
}
return map;
};
Typr$1.kern.parseV1 = function(data, offset, length, font) {
var bin = Typr$1._bin;
bin.readFixed(data, offset);
offset += 4;
var nTables = bin.readUint(data, offset);
offset += 4;
var map = { glyph1: [], rval: [] };
for (var i = 0; i < nTables; i++) {
bin.readUint(data, offset);
offset += 4;
var coverage = bin.readUshort(data, offset);
offset += 2;
bin.readUshort(data, offset);
offset += 2;
var format = coverage >>> 8;
format &= 15;
if (format == 0)
offset = Typr$1.kern.readFormat0(data, offset, map);
else
throw "unknown kern table format: " + format;
}
return map;
};
Typr$1.kern.readFormat0 = function(data, offset, map) {
var bin = Typr$1._bin;
var pleft = -1;
var nPairs = bin.readUshort(data, offset);
offset += 2;
bin.readUshort(data, offset);
offset += 2;
bin.readUshort(data, offset);
offset += 2;
bin.readUshort(data, offset);
offset += 2;
for (var j = 0; j < nPairs; j++) {
var left = bin.readUshort(data, offset);
offset += 2;
var right = bin.readUshort(data, offset);
offset += 2;
var value = bin.readShort(data, offset);
offset += 2;
if (left != pleft) {
map.glyph1.push(left);
map.rval.push({ glyph2: [], vals: [] });
}
var rval = map.rval[map.rval.length - 1];
rval.glyph2.push(right);
rval.vals.push(value);
pleft = left;
}
return offset;
};
Typr$1.loca = {};
Typr$1.loca.parse = function(data, offset, length, font) {
var bin = Typr$1._bin;
var obj = [];
var ver = font.head.indexToLocFormat;
var len = font.maxp.numGlyphs + 1;
if (ver == 0)
for (var i = 0; i < len; i++)
obj.push(bin.readUshort(data, offset + (i << 1)) << 1);
if (ver == 1)
for (var i = 0; i < len; i++)
obj.push(bin.readUint(data, offset + (i << 2)));
return obj;
};
Typr$1.maxp = {};
Typr$1.maxp.parse = function(data, offset, length) {
var bin = Typr$1._bin;
var obj = {};
var ver = bin.readUint(data, offset);
offset += 4;
obj.numGlyphs = bin.readUshort(data, offset);
offset += 2;
if (ver == 65536) {
obj.maxPoints = bin.readUshort(data, offset);
offset += 2;
obj.maxContours = bin.readUshort(data, offset);
offset += 2;
obj.maxCompositePoints = bin.readUshort(data, offset);
offset += 2;
obj.maxCompositeContours = bin.readUshort(data, offset);
offset += 2;
obj.maxZones = bin.readUshort(data, offset);
offset += 2;
obj.maxTwilightPoints = bin.readUshort(data, offset);
offset += 2;
obj.maxStorage = bin.readUshort(data, offset);
offset += 2;
obj.maxFunctionDefs = bin.readUshort(data, offset);
offset += 2;
obj.maxInstructionDefs = bin.readUshort(data, offset);
offset += 2;
obj.maxStackElements = bin.readUshort(data, offset);
offset += 2;
obj.maxSizeOfInstructions = bin.readUshort(data, offset);
offset += 2;
obj.maxComponentElements = bin.readUshort(data, offset);
offset += 2;
obj.maxComponentDepth = bin.readUshort(data, offset);
offset += 2;
}
return obj;
};
Typr$1.name = {};
Typr$1.name.parse = function(data, offset, length) {
var bin = Typr$1._bin;
var obj = {};
bin.readUshort(data, offset);
offset += 2;
var count = bin.readUshort(data, offset);
offset += 2;
bin.readUshort(data, offset);
offset += 2;
var names2 = [
"copyright",
"fontFamily",
"fontSubfamily",
"ID",
"fullName",
"version",
"postScriptName",
"trademark",
"manufacturer",
"designer",
"description",
"urlVendor",
"urlDesigner",
"licence",
"licenceURL",
"---",
"typoFamilyName",
"typoSubfamilyName",
"compatibleFull",
"sampleText",
"postScriptCID",
"wwsFamilyName",
"wwsSubfamilyName",
"lightPalette",
"darkPalette"
];
var offset0 = offset;
for (var i = 0; i < count; i++) {
var platformID = bin.readUshort(data, offset);
offset += 2;
var encodingID = bin.readUshort(data, offset);
offset += 2;
var languageID = bin.readUshort(data, offset);
offset += 2;
var nameID = bin.readUshort(data, offset);
offset += 2;
var slen = bin.readUshort(data, offset);
offset += 2;
var noffset = bin.readUshort(data, offset);
offset += 2;
var cname = names2[nameID];
var soff = offset0 + count * 12 + noffset;
var str;
if (platformID == 0)
str = bin.readUnicode(data, soff, slen / 2);
else if (platformID == 3 && encodingID == 0)
str = bin.readUnicode(data, soff, slen / 2);
else if (encodingID == 0)
str = bin.readASCII(data, soff, slen);
else if (encodingID == 1)
str = bin.readUnicode(data, soff, slen / 2);
else if (encodingID == 3)
str = bin.readUnicode(data, soff, slen / 2);
else if (platformID == 1) {
str = bin.readASCII(data, soff, slen);
console.warn("reading unknown MAC encoding " + encodingID + " as ASCII");
} else
throw "unknown encoding " + encodingID + ", platformID: " + platformID;
var tid = "p" + platformID + "," + languageID.toString(16);
if (obj[tid] == null)
obj[tid] = {};
obj[tid][cname !== void 0 ? cname : nameID] = str;
obj[tid]._lang = languageID;
}
for (var p in obj)
if (obj[p].postScriptName != null && obj[p]._lang == 1033)
return obj[p];
for (var p in obj)
if (obj[p].postScriptName != null && obj[p]._lang == 0)
return obj[p];
for (var p in obj)
if (obj[p].postScriptName != null && obj[p]._lang == 3084)
return obj[p];
for (var p in obj)
if (obj[p].postScriptName != null)
return obj[p];
var tname;
for (var p in obj) {
tname = p;
break;
}
console.warn("returning name table with languageID " + obj[tname]._lang);
return obj[tname];
};
Typr$1["OS/2"] = {};
Typr$1["OS/2"].parse = function(data, offset, length) {
var bin = Typr$1._bin;
var ver = bin.readUshort(data, offset);
offset += 2;
var obj = {};
if (ver == 0)
Typr$1["OS/2"].version0(data, offset, obj);
else if (ver == 1)
Typr$1["OS/2"].version1(data, offset, obj);
else if (ver == 2 || ver == 3 || ver == 4)
Typr$1["OS/2"].version2(data, offset, obj);
else if (ver == 5)
Typr$1["OS/2"].version5(data, offset, obj);
else
throw "unknown OS/2 table version: " + ver;
return obj;
};
Typr$1["OS/2"].version0 = function(data, offset, obj) {
var bin = Typr$1._bin;
obj.xAvgCharWidth = bin.readShort(data, offset);
offset += 2;
obj.usWeightClass = bin.readUshort(data, offset);
offset += 2;
obj.usWidthClass = bin.readUshort(data, offset);
offset += 2;
obj.fsType = bin.readUshort(data, offset);
offset += 2;
obj.ySubscriptXSize = bin.readShort(data, offset);
offset += 2;
obj.ySubscriptYSize = bin.readShort(data, offset);
offset += 2;
obj.ySubscriptXOffset = bin.readShort(data, offset);
offset += 2;
obj.ySubscriptYOffset = bin.readShort(data, offset);
offset += 2;
obj.ySuperscriptXSize = bin.readShort(data, offset);
offset += 2;
obj.ySuperscriptYSize = bin.readShort(data, offset);
offset += 2;
obj.ySuperscriptXOffset = bin.readShort(data, offset);
offset += 2;
obj.ySuperscriptYOffset = bin.readShort(data, offset);
offset += 2;
obj.yStrikeoutSize = bin.readShort(data, offset);
offset += 2;
obj.yStrikeoutPosition = bin.readShort(data, offset);
offset += 2;
obj.sFamilyClass = bin.readShort(data, offset);
offset += 2;
obj.panose = bin.readBytes(data, offset, 10);
offset += 10;
obj.ulUnicodeRange1 = bin.readUint(data, offset);
offset += 4;
obj.ulUnicodeRange2 = bin.readUint(data, offset);
offset += 4;
obj.ulUnicodeRange3 = bin.readUint(data, offset);
offset += 4;
obj.ulUnicodeRange4 = bin.readUint(data, offset);
offset += 4;
obj.achVendID = [bin.readInt8(data, offset), bin.readInt8(data, offset + 1), bin.readInt8(data, offset + 2), bin.readInt8(data, offset + 3)];
offset += 4;
obj.fsSelection = bin.readUshort(data, offset);
offset += 2;
obj.usFirstCharIndex = bin.readUshort(data, offset);
offset += 2;
obj.usLastCharIndex = bin.readUshort(data, offset);
offset += 2;
obj.sTypoAscender = bin.readShort(data, offset);
offset += 2;
obj.sTypoDescender = bin.readShort(data, offset);
offset += 2;
obj.sTypoLineGap = bin.readShort(data, offset);
offset += 2;
obj.usWinAscent = bin.readUshort(data, offset);
offset += 2;
obj.usWinDescent = bin.readUshort(data, offset);
offset += 2;
return offset;
};
Typr$1["OS/2"].version1 = function(data, offset, obj) {
var bin = Typr$1._bin;
offset = Typr$1["OS/2"].version0(data, offset, obj);
obj.ulCodePageRange1 = bin.readUint(data, offset);
offset += 4;
obj.ulCodePageRange2 = bin.readUint(data, offset);
offset += 4;
return offset;
};
Typr$1["OS/2"].version2 = function(data, offset, obj) {
var bin = Typr$1._bin;
offset = Typr$1["OS/2"].version1(data, offset, obj);
obj.sxHeight = bin.readShort(data, offset);
offset += 2;
obj.sCapHeight = bin.readShort(data, offset);
offset += 2;
obj.usDefault = bin.readUshort(data, offset);
offset += 2;
obj.usBreak = bin.readUshort(data, offset);
offset += 2;
obj.usMaxContext = bin.readUshort(data, offset);
offset += 2;
return offset;
};
Typr$1["OS/2"].version5 = function(data, offset, obj) {
var bin = Typr$1._bin;
offset = Typr$1["OS/2"].version2(data, offset, obj);
obj.usLowerOpticalPointSize = bin.readUshort(data, offset);
offset += 2;
obj.usUpperOpticalPointSize = bin.readUshort(data, offset);
offset += 2;
return offset;
};
Typr$1.post = {};
Typr$1.post.parse = function(data, offset, length) {
var bin = Typr$1._bin;
var obj = {};
obj.version = bin.readFixed(data, offset);
offset += 4;
obj.italicAngle = bin.readFixed(data, offset);
offset += 4;
obj.underlinePosition = bin.readShort(data, offset);
offset += 2;
obj.underlineThickness = bin.readShort(data, offset);
offset += 2;
return obj;
};
Typr$1.SVG = {};
Typr$1.SVG.parse = function(data, offset, length) {
var bin = Typr$1._bin;
var obj = { entries: [] };
var offset0 = offset;
bin.readUshort(data, offset);
offset += 2;
var svgDocIndexOffset = bin.readUint(data, offset);
offset += 4;
bin.readUint(data, offset);
offset += 4;
offset = svgDocIndexOffset + offset0;
var numEntries = bin.readUshort(data, offset);
offset += 2;
for (var i = 0; i < numEntries; i++) {
var startGlyphID = bin.readUshort(data, offset);
offset += 2;
var endGlyphID = bin.readUshort(data, offset);
offset += 2;
var svgDocOffset = bin.readUint(data, offset);
offset += 4;
var svgDocLength = bin.readUint(data, offset);
offset += 4;
var sbuf = new Uint8Array(data.buffer, offset0 + svgDocOffset + svgDocIndexOffset, svgDocLength);
var svg = bin.readUTF8(sbuf, 0, sbuf.length);
for (var f = startGlyphID; f <= endGlyphID; f++) {
obj.entries[f] = svg;
}
}
return obj;
};
Typr$1.SVG.toPath = function(str) {
var pth = { cmds: [], crds: [] };
if (str == null)
return pth;
var prsr = new DOMParser();
var doc = prsr["parseFromString"](str, "image/svg+xml");
var svg = doc.firstChild;
while (svg.tagName != "svg")
svg = svg.nextSibling;
var vb = svg.getAttribute("viewBox");
if (vb)
vb = vb.trim().split(" ").map(parseFloat);
else
vb = [0, 0, 1e3, 1e3];
Typr$1.SVG._toPath(svg.children, pth);
for (var i = 0; i < pth.crds.length; i += 2) {
var x = pth.crds[i], y = pth.crds[i + 1];
x -= vb[0];
y -= vb[1];
y = -y;
pth.crds[i] = x;
pth.crds[i + 1] = y;
}
return pth;
};
Typr$1.SVG._toPath = function(nds, pth, fill) {
for (var ni = 0; ni < nds.length; ni++) {
var nd = nds[ni], tn = nd.tagName;
var cfl = nd.getAttribute("fill");
if (cfl == null)
cfl = fill;
if (tn == "g")
Typr$1.SVG._toPath(nd.children, pth, cfl);
else if (tn == "path") {
pth.cmds.push(cfl ? cfl : "#000000");
var d = nd.getAttribute("d");
var toks = Typr$1.SVG._tokens(d);
Typr$1.SVG._toksToPath(toks, pth);
pth.cmds.push("X");
} else if (tn == "defs") ;
else
console.warn(tn, nd);
}
};
Typr$1.SVG._tokens = function(d) {
var ts = [], off = 0, rn = false, cn = "";
while (off < d.length) {
var cc = d.charCodeAt(off), ch = d.charAt(off);
off++;
var isNum = 48 <= cc && cc <= 57 || ch == "." || ch == "-";
if (rn) {
if (ch == "-") {
ts.push(parseFloat(cn));
cn = ch;
} else if (isNum)
cn += ch;
else {
ts.push(parseFloat(cn));
if (ch != "," && ch != " ")
ts.push(ch);
rn = false;
}
} else {
if (isNum) {
cn = ch;
rn = true;
} else if (ch != "," && ch != " ")
ts.push(ch);
}
}
if (rn)
ts.push(parseFloat(cn));
return ts;
};
Typr$1.SVG._toksToPath = function(ts, pth) {
var i = 0, x = 0, y = 0, ox = 0, oy = 0;
var pc = { "M": 2, "L": 2, "H": 1, "V": 1, "S": 4, "C": 6 };
var cmds = pth.cmds, crds = pth.crds;
while (i < ts.length) {
var cmd = ts[i];
i++;
if (cmd == "z") {
cmds.push("Z");
x = ox;
y = oy;
} else {
var cmu = cmd.toUpperCase();
var ps = pc[cmu], reps = Typr$1.SVG._reps(ts, i, ps);
for (var j = 0; j < reps; j++) {
var xi = 0, yi = 0;
if (cmd != cmu) {
xi = x;
yi = y;
}
if (cmu == "M") {
x = xi + ts[i++];
y = yi + ts[i++];
cmds.push("M");
crds.push(x, y);
ox = x;
oy = y;
} else if (cmu == "L") {
x = xi + ts[i++];
y = yi + ts[i++];
cmds.push("L");
crds.push(x, y);
} else if (cmu == "H") {
x = xi + ts[i++];
cmds.push("L");
crds.push(x, y);
} else if (cmu == "V") {
y = yi + ts[i++];
cmds.push("L");
crds.push(x, y);
} else if (cmu == "C") {
var x1 = xi + ts[i++], y1 = yi + ts[i++], x2 = xi + ts[i++], y2 = yi + ts[i++], x3 = xi + ts[i++], y3 = yi + ts[i++];
cmds.push("C");
crds.push(x1, y1, x2, y2, x3, y3);
x = x3;
y = y3;
} else if (cmu == "S") {
var co = Math.max(crds.length - 4, 0);
var x1 = x + x - crds[co], y1 = y + y - crds[co + 1];
var x2 = xi + ts[i++], y2 = yi + ts[i++], x3 = xi + ts[i++], y3 = yi + ts[i++];
cmds.push("C");
crds.push(x1, y1, x2, y2, x3, y3);
x = x3;
y = y3;
} else
console.warn("Unknown SVG command " + cmd);
}
}
}
};
Typr$1.SVG._reps = function(ts, off, ps) {
var i = off;
while (i < ts.length) {
if (typeof ts[i] == "string")
break;
i += ps;
}
return (i - off) / ps;
};
if (Typr$1 == null)
Typr$1 = {};
if (Typr$1.U == null)
Typr$1.U = {};
Typr$1.U.codeToGlyph = function(font, code) {
var cmap = font.cmap;
for (var _i = 0, _a = [cmap.p0e4, cmap.p3e1, cmap.p3e10, cmap.p0e3, cmap.p1e0]; _i < _a.length; _i++) {
var tind = _a[_i];
if (tind == null)
continue;
var tab = cmap.tables[tind];
if (tab.format == 0) {
if (code >= tab.map.length)
continue;
return tab.map[code];
} else if (tab.format == 4) {
var sind = -1;
for (var i = 0; i < tab.endCount.length; i++) {
if (code <= tab.endCount[i]) {
sind = i;
break;
}
}
if (sind == -1)
continue;
if (tab.startCount[sind] > code)
continue;
var gli = 0;
if (tab.idRangeOffset[sind] != 0) {
gli = tab.glyphIdArray[code - tab.startCount[sind] + (tab.idRangeOffset[sind] >> 1) - (tab.idRangeOffset.length - sind)];
} else {
gli = code + tab.idDelta[sind];
}
return gli & 65535;
} else if (tab.format == 12) {
if (code > tab.groups[tab.groups.length - 1][1])
continue;
for (var i = 0; i < tab.groups.length; i++) {
var grp = tab.groups[i];
if (grp[0] <= code && code <= grp[1])
return grp[2] + (code - grp[0]);
}
continue;
} else {
throw "unknown cmap table format " + tab.format;
}
}
return 0;
};
Typr$1.U.glyphToPath = function(font, gid) {
var path = { cmds: [], crds: [] };
if (font.SVG && font.SVG.entries[gid]) {
var p = font.SVG.entries[gid];
if (p == null)
return path;
if (typeof p == "string") {
p = Typr$1.SVG.toPath(p);
font.SVG.entries[gid] = p;
}
return p;
} else if (font.CFF) {
var state = { x: 0, y: 0, stack: [], nStems: 0, haveWidth: false, width: font.CFF.Private ? font.CFF.Private.defaultWidthX : 0, open: false };
var cff = font.CFF, pdct = font.CFF.Private;
if (cff.ROS) {
var gi = 0;
while (cff.FDSelect[gi + 2] <= gid)
gi += 2;
pdct = cff.FDArray[cff.FDSelect[gi + 1]].Private;
}
Typr$1.U._drawCFF(font.CFF.CharStrings[gid], state, cff, pdct, path);
} else if (font.glyf) {
Typr$1.U._drawGlyf(gid, font, path);
}
return path;
};
Typr$1.U._drawGlyf = function(gid, font, path) {
var gl = font.glyf[gid];
if (gl == null)
gl = font.glyf[gid] = Typr$1.glyf._parseGlyf(font, gid);
if (gl != null) {
if (gl.noc > -1) {
Typr$1.U._simpleGlyph(gl, path);
} else {
Typr$1.U._compoGlyph(gl, font, path);
}
}
};
Typr$1.U._simpleGlyph = function(gl, p) {
for (var c = 0; c < gl.noc; c++) {
var i0 = c == 0 ? 0 : gl.endPts[c - 1] + 1;
var il = gl.endPts[c];
for (var i = i0; i <= il; i++) {
var pr = i == i0 ? il : i - 1;
var nx = i == il ? i0 : i + 1;
var onCurve = gl.flags[i] & 1;
var prOnCurve = gl.flags[pr] & 1;
var nxOnCurve = gl.flags[nx] & 1;
var x = gl.xs[i], y = gl.ys[i];
if (i == i0) {
if (onCurve) {
if (prOnCurve) {
Typr$1.U.P.moveTo(p, gl.xs[pr], gl.ys[pr]);
} else {
Typr$1.U.P.moveTo(p, x, y);
continue;
}
} else {
if (prOnCurve) {
Typr$1.U.P.moveTo(p, gl.xs[pr], gl.ys[pr]);
} else {
Typr$1.U.P.moveTo(p, (gl.xs[pr] + x) / 2, (gl.ys[pr] + y) / 2);
}
}
}
if (onCurve) {
if (prOnCurve)
Typr$1.U.P.lineTo(p, x, y);
} else {
if (nxOnCurve) {
Typr$1.U.P.qcurveTo(p, x, y, gl.xs[nx], gl.ys[nx]);
} else {
Typr$1.U.P.qcurveTo(p, x, y, (x + gl.xs[nx]) / 2, (y + gl.ys[nx]) / 2);
}
}
}
Typr$1.U.P.closePath(p);
}
};
Typr$1.U._compoGlyph = function(gl, font, p) {
for (var j = 0; j < gl.parts.length; j++) {
var path = { cmds: [], crds: [] };
var prt = gl.parts[j];
Typr$1.U._drawGlyf(prt.glyphIndex, font, path);
var m = prt.m;
for (var i = 0; i < path.crds.length; i += 2) {
var x = path.crds[i], y = path.crds[i + 1];
p.crds.push(x * m.a + y * m.b + m.tx);
p.crds.push(x * m.c + y * m.d + m.ty);
}
for (var i = 0; i < path.cmds.length; i++) {
p.cmds.push(path.cmds[i]);
}
}
};
Typr$1.U._getGlyphClass = function(g, cd) {
var intr = Typr$1._lctf.getInterval(cd, g);
return intr == -1 ? 0 : cd[intr + 2];
};
Typr$1.U.getPairAdjustment = function(font, g1, g2) {
var hasGPOSkern = false;
if (font.GPOS) {
var gpos = font["GPOS"];
var llist = gpos.lookupList, flist = gpos.featureList;
var tused = [];
for (var i = 0; i < flist.length; i++) {
var fl = flist[i];
if (fl.tag != "kern")
continue;
hasGPOSkern = true;
for (var ti = 0; ti < fl.tab.length; ti++) {
if (tused[fl.tab[ti]])
continue;
tused[fl.tab[ti]] = true;
var tab = llist[fl.tab[ti]];
for (var j = 0; j < tab.tabs.length; j++) {
if (tab.tabs[j] == null)
continue;
var ltab = tab.tabs[j], ind;
if (ltab.coverage) {
ind = Typr$1._lctf.coverageIndex(ltab.coverage, g1);
if (ind == -1)
continue;
}
if (tab.ltype == 1) ;
else if (tab.ltype == 2) {
var adj = null;
if (ltab.fmt == 1) {
var right = ltab.pairsets[ind];
for (var i = 0; i < right.length; i++) {
if (right[i].gid2 == g2)
adj = right[i];
}
} else if (ltab.fmt == 2) {
var c1 = Typr$1.U._getGlyphClass(g1, ltab.classDef1);
var c2 = Typr$1.U._getGlyphClass(g2, ltab.classDef2);
adj = ltab.matrix[c1][c2];
}
if (adj) {
var offset = 0;
if (adj.val1 && adj.val1[2])
offset += adj.val1[2];
if (adj.val2 && adj.val2[0])
offset += adj.val2[0];
return offset;
}
}
}
}
}
}
if (font.kern && !hasGPOSkern) {
var ind1 = font.kern.glyph1.indexOf(g1);
if (ind1 != -1) {
var ind2 = font.kern.rval[ind1].glyph2.indexOf(g2);
if (ind2 != -1)
return font.kern.rval[ind1].vals[ind2];
}
}
return 0;
};
Typr$1.U.stringToGlyphs = function(font, str) {
var gls = [];
for (var i = 0; i < str.length; i++) {
var cc = str.codePointAt(i);
if (cc > 65535)
i++;
gls.push(Typr$1.U.codeToGlyph(font, cc));
}
for (var i = 0; i < str.length; i++) {
var cc = str.codePointAt(i);
if (cc == 2367) {
var t = gls[i - 1];
gls[i - 1] = gls[i];
gls[i] = t;
}
if (cc > 65535)
i++;
}
var gsub = font["GSUB"];
if (gsub == null)
return gls;
var llist = gsub.lookupList, flist = gsub.featureList;
var cligs = [
"rlig",
"liga",
"mset",
"isol",
"init",
"fina",
"medi",
"half",
"pres",
"blws"
/* Tibetan fonts like Himalaya.ttf */
];
var tused = [];
for (var fi = 0; fi < flist.length; fi++) {
var fl = flist[fi];
if (cligs.indexOf(fl.tag) == -1)
continue;
for (var ti = 0; ti < fl.tab.length; ti++) {
if (tused[fl.tab[ti]])
continue;
tused[fl.tab[ti]] = true;
var tab = llist[fl.tab[ti]];
for (var ci = 0; ci < gls.length; ci++) {
var feat = Typr$1.U._getWPfeature(str, ci);
if ("isol,init,fina,medi".indexOf(fl.tag) != -1 && fl.tag != feat)
continue;
Typr$1.U._applySubs(gls, ci, tab, llist);
}
}
}
return gls;
};
Typr$1.U._getWPfeature = function(str, ci) {
var wsep = '\n " ,.:;!?() ،';
var R = "آأؤإاةدذرزوٱٲٳٵٶٷڈډڊڋڌڍڎڏڐڑڒړڔڕږڗژڙۀۃۄۅۆۇۈۉۊۋۍۏےۓەۮۯܐܕܖܗܘܙܞܨܪܬܯݍݙݚݛݫݬݱݳݴݸݹࡀࡆࡇࡉࡔࡧࡩࡪࢪࢫࢬࢮࢱࢲࢹૅેૉૐૡ૯ஃஅஉஎஏனப";
var L = "ꡲ્";
var slft = ci == 0 || wsep.indexOf(str[ci - 1]) != -1;
var srgt = ci == str.length - 1 || wsep.indexOf(str[ci + 1]) != -1;
if (!slft && R.indexOf(str[ci - 1]) != -1)
slft = true;
if (!srgt && R.indexOf(str[ci]) != -1)
srgt = true;
if (!srgt && L.indexOf(str[ci + 1]) != -1)
srgt = true;
if (!slft && L.indexOf(str[ci]) != -1)
slft = true;
var feat = null;
if (slft) {
feat = srgt ? "isol" : "init";
} else {
feat = srgt ? "fina" : "medi";
}
return feat;
};
Typr$1.U._applySubs = function(gls, ci, tab, llist) {
var rlim = gls.length - ci - 1;
for (var j = 0; j < tab.tabs.length; j++) {
if (tab.tabs[j] == null)
continue;
var ltab = tab.tabs[j], ind;
if (ltab.coverage) {
ind = Typr$1._lctf.coverageIndex(ltab.coverage, gls[ci]);
if (ind == -1)
continue;
}
if (tab.ltype == 1) {
gls[ci];
if (ltab.fmt == 1)
gls[ci] = gls[ci] + ltab.delta;
else
gls[ci] = ltab.newg[ind];
} else if (tab.ltype == 4) {
var vals = ltab.vals[ind];
for (var k = 0; k < vals.length; k++) {
var lig = vals[k], rl = lig.chain.length;
if (rl > rlim)
continue;
var good = true, em1 = 0;
for (var l = 0; l < rl; l++) {
while (gls[ci + em1 + (1 + l)] == -1)
em1++;
if (lig.chain[l] != gls[ci + em1 + (1 + l)])
good = false;
}
if (!good)
continue;
gls[ci] = lig.nglyph;
for (var l = 0; l < rl + em1; l++)
gls[ci + l + 1] = -1;
break;
}
} else if (tab.ltype == 5 && ltab.fmt == 2) {
var cind = Typr$1._lctf.getInterval(ltab.cDef, gls[ci]);
var cls = ltab.cDef[cind + 2], scs = ltab.scset[cls];
for (var i = 0; i < scs.length; i++) {
var sc = scs[i], inp = sc.input;
if (inp.length > rlim)
continue;
var good = true;
for (var l = 0; l < inp.length; l++) {
var cind2 = Typr$1._lctf.getInterval(ltab.cDef, gls[ci + 1 + l]);
if (cind == -1 && ltab.cDef[cind2 + 2] != inp[l]) {
good = false;
break;
}
}
if (!good)
continue;
var lrs = sc.substLookupRecords;
for (var k = 0; k < lrs.length; k += 2) {
lrs[k];
lrs[k + 1];
}
}
} else if (tab.ltype == 6 && ltab.fmt == 3) {
if (!Typr$1.U._glsCovered(gls, ltab.backCvg, ci - ltab.backCvg.length))
continue;
if (!Typr$1.U._glsCovered(gls, ltab.inptCvg, ci))
continue;
if (!Typr$1.U._glsCovered(gls, ltab.ahedCvg, ci + ltab.inptCvg.length))
continue;
var lr = ltab.lookupRec;
for (var i = 0; i < lr.length; i += 2) {
var cind = lr[i], tab2 = llist[lr[i + 1]];
Typr$1.U._applySubs(gls, ci + cind, tab2, llist);
}
}
}
};
Typr$1.U._glsCovered = function(gls, cvgs, ci) {
for (var i = 0; i < cvgs.length; i++) {
var ind = Typr$1._lctf.coverageIndex(cvgs[i], gls[ci + i]);
if (ind == -1)
return false;
}
return true;
};
Typr$1.U.glyphsToPath = function(font, gls, clr) {
var tpath = { cmds: [], crds: [] };
var x = 0;
for (var i = 0; i < gls.length; i++) {
var gid = gls[i];
if (gid == -1)
continue;
var gid2 = i < gls.length - 1 && gls[i + 1] != -1 ? gls[i + 1] : 0;
var path = Typr$1.U.glyphToPath(font, gid);
for (var j = 0; j < path.crds.length; j += 2) {
tpath.crds.push(path.crds[j] + x);
tpath.crds.push(path.crds[j + 1]);
}
if (clr)
tpath.cmds.push(clr);
for (var j = 0; j < path.cmds.length; j++)
tpath.cmds.push(path.cmds[j]);
if (clr)
tpath.cmds.push("X");
x += font.hmtx.aWidth[gid];
if (i < gls.length - 1)
x += Typr$1.U.getPairAdjustment(font, gid, gid2);
}
return tpath;
};
Typr$1.U.pathToSVG = function(path, prec) {
if (prec == null)
prec = 5;
var out = [], co = 0, lmap = { "M": 2, "L": 2, "Q": 4, "C": 6 };
for (var i = 0; i < path.cmds.length; i++) {
var cmd = path.cmds[i], cn = co + (lmap[cmd] ? lmap[cmd] : 0);
out.push(cmd);
while (co < cn) {
var c = path.crds[co++];
out.push(parseFloat(c.toFixed(prec)) + (co == cn ? "" : " "));
}
}
return out.join("");
};
Typr$1.U.pathToContext = function(path, ctx) {
var c = 0, crds = path.crds;
for (var j = 0; j < path.cmds.length; j++) {
var cmd = path.cmds[j];
if (cmd == "M") {
ctx.moveTo(crds[c], crds[c + 1]);
c += 2;
} else if (cmd == "L") {
ctx.lineTo(crds[c], crds[c + 1]);
c += 2;
} else if (cmd == "C") {
ctx.bezierCurveTo(crds[c], crds[c + 1], crds[c + 2], crds[c + 3], crds[c + 4], crds[c + 5]);
c += 6;
} else if (cmd == "Q") {
ctx.quadraticCurveTo(crds[c], crds[c + 1], crds[c + 2], crds[c + 3]);
c += 4;
} else if (cmd.charAt(0) == "#") {
ctx.beginPath();
ctx.fillStyle = cmd;
} else if (cmd == "Z") {
ctx.closePath();
} else if (cmd == "X") {
ctx.fill();
}
}
};
Typr$1.U.P = {};
Typr$1.U.P.moveTo = function(p, x, y) {
p.cmds.push("M");
p.crds.push(x, y);
};
Typr$1.U.P.lineTo = function(p, x, y) {
p.cmds.push("L");
p.crds.push(x, y);
};
Typr$1.U.P.curveTo = function(p, a, b, c, d, e, f) {
p.cmds.push("C");
p.crds.push(a, b, c, d, e, f);
};
Typr$1.U.P.qcurveTo = function(p, a, b, c, d) {
p.cmds.push("Q");
p.crds.push(a, b, c, d);
};
Typr$1.U.P.closePath = function(p) {
p.cmds.push("Z");
};
Typr$1.U._drawCFF = function(cmds, state, font, pdct, p) {
var stack = state.stack;
var nStems = state.nStems, haveWidth = state.haveWidth, width = state.width, open = state.open;
var i = 0;
var x = state.x, y = state.y, c1x = 0, c1y = 0, c2x = 0, c2y = 0, c3x = 0, c3y = 0, c4x = 0, c4y = 0, jpx = 0, jpy = 0;
var o = { val: 0, size: 0 };
while (i < cmds.length) {
Typr$1.CFF.getCharString(cmds, i, o);
var v = o.val;
i += o.size;
if (v == "o1" || v == "o18") {
var hasWidthArg;
hasWidthArg = stack.length % 2 !== 0;
if (hasWidthArg && !haveWidth) {
width = stack.shift() + pdct.nominalWidthX;
}
nStems += stack.length >> 1;
stack.length = 0;
haveWidth = true;
} else if (v == "o3" || v == "o23") {
var hasWidthArg;
hasWidthArg = stack.length % 2 !== 0;
if (hasWidthArg && !haveWidth) {
width = stack.shift() + pdct.nominalWidthX;
}
nStems += stack.length >> 1;
stack.length = 0;
haveWidth = true;
} else if (v == "o4") {
if (stack.length > 1 && !haveWidth) {
width = stack.shift() + pdct.nominalWidthX;
haveWidth = true;
}
if (open)
Typr$1.U.P.closePath(p);
y += stack.pop();
Typr$1.U.P.moveTo(p, x, y);
open = true;
} else if (v == "o5") {
while (stack.length > 0) {
x += stack.shift();
y += stack.shift();
Typr$1.U.P.lineTo(p, x, y);
}
} else if (v == "o6" || v == "o7") {
var count = stack.length;
var isX = v == "o6";
for (var j = 0; j < count; j++) {
var sval = stack.shift();
if (isX) {
x += sval;
} else {
y += sval;
}
isX = !isX;
Typr$1.U.P.lineTo(p, x, y);
}
} else if (v == "o8" || v == "o24") {
var count = stack.length;
var index = 0;
while (index + 6 <= count) {
c1x = x + stack.shift();
c1y = y + stack.shift();
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
x = c2x + stack.shift();
y = c2y + stack.shift();
Typr$1.U.P.curveTo(p, c1x, c1y, c2x, c2y, x, y);
index += 6;
}
if (v == "o24") {
x += stack.shift();
y += stack.shift();
Typr$1.U.P.lineTo(p, x, y);
}
} else if (v == "o11") {
break;
} else if (v == "o1234" || v == "o1235" || v == "o1236" || v == "o1237") {
if (v == "o1234") {
c1x = x + stack.shift();
c1y = y;
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
jpx = c2x + stack.shift();
jpy = c2y;
c3x = jpx + stack.shift();
c3y = c2y;
c4x = c3x + stack.shift();
c4y = y;
x = c4x + stack.shift();
Typr$1.U.P.curveTo(p, c1x, c1y, c2x, c2y, jpx, jpy);
Typr$1.U.P.curveTo(p, c3x, c3y, c4x, c4y, x, y);
}
if (v == "o1235") {
c1x = x + stack.shift();
c1y = y + stack.shift();
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
jpx = c2x + stack.shift();
jpy = c2y + stack.shift();
c3x = jpx + stack.shift();
c3y = jpy + stack.shift();
c4x = c3x + stack.shift();
c4y = c3y + stack.shift();
x = c4x + stack.shift();
y = c4y + stack.shift();
stack.shift();
Typr$1.U.P.curveTo(p, c1x, c1y, c2x, c2y, jpx, jpy);
Typr$1.U.P.curveTo(p, c3x, c3y, c4x, c4y, x, y);
}
if (v == "o1236") {
c1x = x + stack.shift();
c1y = y + stack.shift();
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
jpx = c2x + stack.shift();
jpy = c2y;
c3x = jpx + stack.shift();
c3y = c2y;
c4x = c3x + stack.shift();
c4y = c3y + stack.shift();
x = c4x + stack.shift();
Typr$1.U.P.curveTo(p, c1x, c1y, c2x, c2y, jpx, jpy);
Typr$1.U.P.curveTo(p, c3x, c3y, c4x, c4y, x, y);
}
if (v == "o1237") {
c1x = x + stack.shift();
c1y = y + stack.shift();
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
jpx = c2x + stack.shift();
jpy = c2y + stack.shift();
c3x = jpx + stack.shift();
c3y = jpy + stack.shift();
c4x = c3x + stack.shift();
c4y = c3y + stack.shift();
if (Math.abs(c4x - x) > Math.abs(c4y - y)) {
x = c4x + stack.shift();
} else {
y = c4y + stack.shift();
}
Typr$1.U.P.curveTo(p, c1x, c1y, c2x, c2y, jpx, jpy);
Typr$1.U.P.curveTo(p, c3x, c3y, c4x, c4y, x, y);
}
} else if (v == "o14") {
if (stack.length > 0 && !haveWidth) {
width = stack.shift() + font.nominalWidthX;
haveWidth = true;
}
if (stack.length == 4) {
var adx = stack.shift();
var ady = stack.shift();
var bchar = stack.shift();
var achar = stack.shift();
var bind = Typr$1.CFF.glyphBySE(font, bchar);
var aind = Typr$1.CFF.glyphBySE(font, achar);
Typr$1.U._drawCFF(font.CharStrings[bind], state, font, pdct, p);
state.x = adx;
state.y = ady;
Typr$1.U._drawCFF(font.CharStrings[aind], state, font, pdct, p);
}
if (open) {
Typr$1.U.P.closePath(p);
open = false;
}
} else if (v == "o19" || v == "o20") {
var hasWidthArg;
hasWidthArg = stack.length % 2 !== 0;
if (hasWidthArg && !haveWidth) {
width = stack.shift() + pdct.nominalWidthX;
}
nStems += stack.length >> 1;
stack.length = 0;
haveWidth = true;
i += nStems + 7 >> 3;
} else if (v == "o21") {
if (stack.length > 2 && !haveWidth) {
width = stack.shift() + pdct.nominalWidthX;
haveWidth = true;
}
y += stack.pop();
x += stack.pop();
if (open)
Typr$1.U.P.closePath(p);
Typr$1.U.P.moveTo(p, x, y);
open = true;
} else if (v == "o22") {
if (stack.length > 1 && !haveWidth) {
width = stack.shift() + pdct.nominalWidthX;
haveWidth = true;
}
x += stack.pop();
if (open)
Typr$1.U.P.closePath(p);
Typr$1.U.P.moveTo(p, x, y);
open = true;
} else if (v == "o25") {
while (stack.length > 6) {
x += stack.shift();
y += stack.shift();
Typr$1.U.P.lineTo(p, x, y);
}
c1x = x + stack.shift();
c1y = y + stack.shift();
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
x = c2x + stack.shift();
y = c2y + stack.shift();
Typr$1.U.P.curveTo(p, c1x, c1y, c2x, c2y, x, y);
} else if (v == "o26") {
if (stack.length % 2) {
x += stack.shift();
}
while (stack.length > 0) {
c1x = x;
c1y = y + stack.shift();
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
x = c2x;
y = c2y + stack.shift();
Typr$1.U.P.curveTo(p, c1x, c1y, c2x, c2y, x, y);
}
} else if (v == "o27") {
if (stack.length % 2) {
y += stack.shift();
}
while (stack.length > 0) {
c1x = x + stack.shift();
c1y = y;
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
x = c2x + stack.shift();
y = c2y;
Typr$1.U.P.curveTo(p, c1x, c1y, c2x, c2y, x, y);
}
} else if (v == "o10" || v == "o29") {
var obj = v == "o10" ? pdct : font;
if (stack.length == 0) {
console.warn("error: empty stack");
} else {
var ind = stack.pop();
var subr = obj.Subrs[ind + obj.Bias];
state.x = x;
state.y = y;
state.nStems = nStems;
state.haveWidth = haveWidth;
state.width = width;
state.open = open;
Typr$1.U._drawCFF(subr, state, font, pdct, p);
x = state.x;
y = state.y;
nStems = state.nStems;
haveWidth = state.haveWidth;
width = state.width;
open = state.open;
}
} else if (v == "o30" || v == "o31") {
var count, count1 = stack.length;
var index = 0;
var alternate = v == "o31";
count = count1 & -3;
index += count1 - count;
while (index < count) {
if (alternate) {
c1x = x + stack.shift();
c1y = y;
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
y = c2y + stack.shift();
if (count - index == 5) {
x = c2x + stack.shift();
index++;
} else {
x = c2x;
}
alternate = false;
} else {
c1x = x;
c1y = y + stack.shift();
c2x = c1x + stack.shift();
c2y = c1y + stack.shift();
x = c2x + stack.shift();
if (count - index == 5) {
y = c2y + stack.shift();
index++;
} else {
y = c2y;
}
alternate = true;
}
Typr$1.U.P.curveTo(p, c1x, c1y, c2x, c2y, x, y);
index += 4;
}
} else if ((v + "").charAt(0) == "o") {
console.warn("Unknown operation: " + v, cmds);
throw v;
} else
stack.push(v);
}
state.x = x;
state.y = y;
state.nStems = nStems;
state.haveWidth = haveWidth;
state.width = width;
state.open = open;
};
Typr.Typr = Typr$1;
return Typr;
}
var hasRequiredDist;
function requireDist() {
if (hasRequiredDist) return dist;
hasRequiredDist = 1;
dist.__esModule = true;
var Typr_js_1 = requireTypr();
var friendlyTags = { "aalt": "Access All Alternates", "abvf": "Above-base Forms", "abvm": "Above - base Mark Positioning", "abvs": "Above - base Substitutions", "afrc": "Alternative Fractions", "akhn": "Akhands", "blwf": "Below - base Forms", "blwm": "Below - base Mark Positioning", "blws": "Below - base Substitutions", "calt": "Contextual Alternates", "case": "Case - Sensitive Forms", "ccmp": "Glyph Composition / Decomposition", "cfar": "Conjunct Form After Ro", "cjct": "Conjunct Forms", "clig": "Contextual Ligatures", "cpct": "Centered CJK Punctuation", "cpsp": "Capital Spacing", "cswh": "Contextual Swash", "curs": "Cursive Positioning", "c2pc": "Petite Capitals From Capitals", "c2sc": "Small Capitals From Capitals", "dist": "Distances", "dlig": "Discretionary Ligatures", "dnom": "Denominators", "dtls": "Dotless Forms", "expt": "Expert Forms", "falt": "Final Glyph on Line Alternates", "fin2": "Terminal Forms #2", "fin3": "Terminal Forms #3", "fina": "Terminal Forms", "flac": "Flattened accent forms", "frac": "Fractions", "fwid": "Full Widths", "half": "Half Forms", "haln": "Halant Forms", "halt": "Alternate Half Widths", "hist": "Historical Forms", "hkna": "Horizontal Kana Alternates", "hlig": "Historical Ligatures", "hngl": "Hangul", "hojo": "Hojo Kanji Forms(JIS X 0212 - 1990 Kanji Forms)", "hwid": "Half Widths", "init": "Initial Forms", "isol": "Isolated Forms", "ital": "Italics", "jalt": "Justification Alternates", "jp78": "JIS78 Forms", "jp83": "JIS83 Forms", "jp90": "JIS90 Forms", "jp04": "JIS2004 Forms", "kern": "Kerning", "lfbd": "Left Bounds", "liga": "Standard Ligatures", "ljmo": "Leading Jamo Forms", "lnum": "Lining Figures", "locl": "Localized Forms", "ltra": "Left - to - right alternates", "ltrm": "Left - to - right mirrored forms", "mark": "Mark Positioning", "med2": "Medial Forms #2", "medi": "Medial Forms", "mgrk": "Mathematical Greek", "mkmk": "Mark to Mark Positioning", "mset": "Mark Positioning via Substitution", "nalt": "Alternate Annotation Forms", "nlck": "NLC Kanji Forms", "nukt": "Nukta Forms", "numr": "Numerators", "onum": "Oldstyle Figures", "opbd": "Optical Bounds", "ordn": "Ordinals", "ornm": "Ornaments", "palt": "Proportional Alternate Widths", "pcap": "Petite Capitals", "pkna": "Proportional Kana", "pnum": "Proportional Figures", "pref": "Pre - Base Forms", "pres": "Pre - base Substitutions", "pstf": "Post - base Forms", "psts": "Post - base Substitutions", "pwid": "Proportional Widths", "qwid": "Quarter Widths", "rand": "Randomize", "rclt": "Required Contextual Alternates", "rkrf": "Rakar Forms", "rlig": "Required Ligatures", "rphf": "Reph Forms", "rtbd": "Right Bounds", "rtla": "Right - to - left alternates", "rtlm": "Right - to - left mirrored forms", "ruby": "Ruby Notation Forms", "rvrn": "Required Variation Alternates", "salt": "Stylistic Alternates", "sinf": "Scientific Inferiors", "size": "Optical size", "smcp": "Small Capitals", "smpl": "Simplified Forms", "ssty": "Math script style alternates", "stch": "Stretching Glyph Decomposition", "subs": "Subscript", "sups": "Superscript", "swsh": "Swash", "titl": "Titling", "tjmo": "Trailing Jamo Forms", "tnam": "Traditional Name Forms", "tnum": "Tabular Figures", "trad": "Traditional Forms", "twid": "Third Widths", "unic": "Unicase", "valt": "Alternate Vertical Metrics", "vatu": "Vattu Variants", "vert": "Vertical Writing", "vhal": "Alternate Vertical Half Metrics", "vjmo": "Vowel Jamo Forms", "vkna": "Vertical Kana Alternates", "vkrn": "Vertical Kerning", "vpal": "Proportional Alternate Vertical Metrics", "vrt2": "Vertical Alternates and Rotation", "vrtr": "Vertical Alternates for Rotation", "zero": "Slashed Zero" };
var Font2 = (
/** @class */
function() {
function Font3(data) {
var obj = Typr_js_1.Typr.parse(data);
if (!obj.length || typeof obj[0] !== "object" || typeof obj[0].hasOwnProperty !== "function") {
throw "unable to parse font";
}
for (var n in obj[0]) {
this[n] = obj[0][n];
}
this.enabledGSUB = {};
}
Font3.prototype.getFamilyName = function() {
return this.name && (this.name.typoFamilyName || this.name.fontFamily) || "";
};
Font3.prototype.getSubFamilyName = function() {
return this.name && (this.name.typoSubfamilyName || this.name.fontSubfamily) || "";
};
Font3.prototype.glyphToPath = function(gid) {
return Typr_js_1.Typr.U.glyphToPath(this, gid);
};
Font3.prototype.getPairAdjustment = function(gid1, gid2) {
return Typr_js_1.Typr.U.getPairAdjustment(this, gid1, gid2);
};
Font3.prototype.stringToGlyphs = function(str) {
return Typr_js_1.Typr.U.stringToGlyphs(this, str);
};
Font3.prototype.glyphsToPath = function(gls) {
return Typr_js_1.Typr.U.glyphsToPath(this, gls);
};
Font3.prototype.pathToSVG = function(path, prec) {
return Typr_js_1.Typr.U.pathToSVG(path, prec);
};
Font3.prototype.pathToContext = function(path, ctx) {
return Typr_js_1.Typr.U.pathToContext(path, ctx);
};
Font3.prototype.lookupFriendlyName = function(table, feature) {
if (this[table] !== void 0) {
var tbl = this[table];
var feat = tbl.featureList[feature];
return this.featureFriendlyName(feat);
}
return "";
};
Font3.prototype.featureFriendlyName = function(feature) {
if (friendlyTags[feature.tag]) {
return friendlyTags[feature.tag];
}
if (feature.tag.match(/ss[0-2][0-9]/)) {
var name_1 = "Stylistic Set " + Number(feature.tag.substr(2, 2)).toString();
if (feature.featureParams) {
var version = Typr_js_1.Typr._bin.readUshort(this._data, feature.featureParams);
if (version === 0) {
var nameID = Typr_js_1.Typr._bin.readUshort(this._data, feature.featureParams + 2);
if (this.name && this.name[nameID] !== void 0) {
return name_1 + " - " + this.name[nameID];
}
}
}
return name_1;
}
if (feature.tag.match(/cv[0-9][0-9]/)) {
return "Character Variant " + Number(feature.tag.substr(2, 2)).toString();
}
return "";
};
Font3.prototype.enableGSUB = function(featureNumber) {
if (this.GSUB) {
var feature = this.GSUB.featureList[featureNumber];
if (feature) {
for (var i = 0; i < feature.tab.length; ++i) {
this.enabledGSUB[feature.tab[i]] = (this.enabledGSUB[feature.tab[i]] || 0) + 1;
}
}
}
};
Font3.prototype.disableGSUB = function(featureNumber) {
if (this.GSUB) {
var feature = this.GSUB.featureList[featureNumber];
if (feature) {
for (var i = 0; i < feature.tab.length; ++i) {
if (this.enabledGSUB[feature.tab[i]] > 1) {
--this.enabledGSUB[feature.tab[i]];
} else {
delete this.enabledGSUB[feature.tab[i]];
}
}
}
}
};
Font3.prototype.codeToGlyph = function(code) {
var g = Typr_js_1.Typr.U.codeToGlyph(this, code);
if (this.GSUB) {
var gls = [g];
for (var n in this.enabledGSUB) {
var l = this.GSUB.lookupList[n];
Typr_js_1.Typr.U._applySubs(gls, 0, l, this.GSUB.lookupList);
}
if (gls.length === 1)
return gls[0];
}
return g;
};
return Font3;
}()
);
dist.Font = Font2;
return dist;
}
var distExports = requireDist();
const typrPkg = /* @__PURE__ */ getDefaultExportFromCjs(distExports);
const { Font } = typrPkg;
function base64ToUint8Array(base64) {
const data = window.atob(base64);
const buffer = new Uint8Array(data.length);
for (let index = 0; index < data.length; index += 1) {
buffer[index] = data.charCodeAt(index);
}
return buffer;
}
function decrypt(iframeDocument) {
const styles = iframeDocument.querySelectorAll("style");
let fontStyle = null;
for (const style of styles) {
if (style.textContent?.includes("font-cxsecret")) {
fontStyle = style;
break;
}
}
if (!fontStyle?.textContent) {
return;
}
const fontDataMatch = fontStyle.textContent.match(/base64,([\w\W]+?)'/);
const fontData = fontDataMatch?.[1];
if (!fontData) {
return;
}
const font = new Font(base64ToUint8Array(fontData));
const tableText = _GM_getResourceText?.("ttf");
if (!tableText) {
return;
}
const table = JSON.parse(tableText);
const matchMap = {};
for (let codePoint = 19968; codePoint < 40870; codePoint += 1) {
const glyph = font.codeToGlyph(codePoint);
if (!glyph) {
continue;
}
const path = font.glyphToPath(glyph);
const hash = md5(JSON.stringify(path)).slice(24);
matchMap[codePoint] = table[hash];
}
const elements = iframeDocument.querySelectorAll(".font-cxsecret");
for (const element of elements) {
let html = element.innerHTML;
for (const [encoded, decoded] of Object.entries(matchMap)) {
const source = String.fromCharCode(Number(encoded));
const target = String.fromCharCode(decoded);
html = html.replace(new RegExp(source, "g"), target);
}
element.innerHTML = html;
element.classList.remove("font-cxsecret");
}
}
const fontDecrypt = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
__proto__: null,
decrypt
}, Symbol.toStringTag, { value: "Module" }));
})((typeof Vue !== "undefined" ? Vue : (typeof unsafeWindow !== "undefined" ? unsafeWindow.Vue : globalThis.Vue)), (typeof Pinia !== "undefined" ? Pinia : (typeof unsafeWindow !== "undefined" ? unsafeWindow.Pinia : globalThis.Pinia)), (typeof antd !== "undefined" ? antd : (typeof unsafeWindow !== "undefined" ? unsafeWindow.antd : globalThis.antd)), (typeof CryptoJS !== "undefined" ? CryptoJS : (typeof unsafeWindow !== "undefined" ? unsafeWindow.CryptoJS : globalThis.CryptoJS)), (typeof md5 !== "undefined" ? md5 : (typeof unsafeWindow !== "undefined" ? unsafeWindow.md5 : globalThis.md5)));