// ==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)));