diff --git a/.vscode/settings.json b/.vscode/settings.json index 5d63618..8e7e795 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,6 @@ { "[typescript]": { - "editor.defaultFormatter": "vscode.typescript-language-features", + "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnType": true }, } \ No newline at end of file diff --git a/src/app.ts b/src/app.ts index 693a608..10520bc 100644 --- a/src/app.ts +++ b/src/app.ts @@ -7,38 +7,38 @@ import ModuleQOJ from './modules/qoj/main'; import ModuleVjudge from './modules/vjudge/main'; export default class App { - modules: Dict; - _queuedPlugins: Dict void }>>; + modules: Dict; + _queuedPlugins: Dict void }>>; - log(...args: any[]) { - return console.log('[CPAssistant.js]', ...args); - } + log(...args: any[]) { + return console.log('[CPAssistant.js]', ...args); + } - apply() { - for (const name in this.modules) { - const module = this.modules[name]; - if (module.match.includes(location.host)) { - module.apply(); - break; - } - } - } + apply() { + for (const name in this.modules) { + const module = this.modules[name]; + if (module.match.includes(location.host)) { + module.apply(); + break; + } + } + } - register(module: Module) { - this.modules[module.name] = module; - if (module.name in this._queuedPlugins) { - for (const queuedPlugin of this._queuedPlugins[module.name]) { - const { feature, func } = queuedPlugin; - feature.plugin(module.name, func); - } - } - } + register(module: Module) { + this.modules[module.name] = module; + if (module.name in this._queuedPlugins) { + for (const queuedPlugin of this._queuedPlugins[module.name]) { + const { feature, func } = queuedPlugin; + feature.plugin(module.name, func); + } + } + } - constructor() { - this._queuedPlugins = {}; + constructor() { + this._queuedPlugins = {}; - this.modules = {}; - } + this.modules = {}; + } } export const app = new App(); diff --git a/src/config.ts b/src/config.ts index e1de278..a3b4235 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,35 +1,35 @@ -import { Dict } from './utils/type' +import { Dict } from './utils/type'; const config: Dict = { - match: { - codeforces: [ - 'codeforces.com', - 'codeforc.es', - ], - hdu: [ - 'acm.hdu.edu.cn', - ], - qoj: [ - 'qoj.ac', - 'pjudge.ac', - ], - vjudge: [ - 'vjudge.net', - 'vjudge.net.cn', - 'cn.vjudge.net', - 'vjudge.z180.cn', - ], - }, -} + match: { + codeforces: [ + 'codeforces.com', // + 'codeforc.es', + ], + hdu: [ + 'acm.hdu.edu.cn', // + ], + qoj: [ + 'qoj.ac', // + 'pjudge.ac', + ], + vjudge: [ + 'vjudge.net', // + 'vjudge.net.cn', + 'cn.vjudge.net', + 'vjudge.z180.cn', + ], + }, +}; -config.matches = [] +config.matches = []; for (const module in config.match) { - for (const domain of config.match[module]) { - config.matches.push(`http://${domain}`) - config.matches.push(`https://${domain}`) - config.matches.push(`http://${domain}/*`) - config.matches.push(`https://${domain}/*`) - } + for (const domain of config.match[module]) { + config.matches.push(`http://${domain}`); + config.matches.push(`https://${domain}`); + config.matches.push(`http://${domain}/*`); + config.matches.push(`https://${domain}/*`); + } } -export default config \ No newline at end of file +export default config; diff --git a/src/main.ts b/src/main.ts index 969e3d4..cb01e30 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,3 +1,3 @@ import { app } from './app'; -app.apply(); \ No newline at end of file +app.apply(); diff --git a/src/modules/codeforces/main.ts b/src/modules/codeforces/main.ts index ad26cb2..8b5b722 100644 --- a/src/modules/codeforces/main.ts +++ b/src/modules/codeforces/main.ts @@ -1,12 +1,11 @@ -import config from '../../config' -import App from '../../app' -import Module from "../../types/module" +import config from '../../config'; +import App from '../../app'; +import Module from '../../types/module'; export default class ModuleCodeforces extends Module { - run() { - } + run() {} - constructor(app: App) { - super(app, 'codeforces', config.match.codeforces) - } -} \ No newline at end of file + constructor(app: App) { + super(app, 'codeforces', config.match.codeforces); + } +} diff --git a/src/modules/hdu/main.ts b/src/modules/hdu/main.ts index 04a4bff..90867ff 100644 --- a/src/modules/hdu/main.ts +++ b/src/modules/hdu/main.ts @@ -1,12 +1,11 @@ -import config from '../../config' -import App from '../../app' -import Module from "../../types/module" +import config from '../../config'; +import App from '../../app'; +import Module from '../../types/module'; export default class ModuleHDU extends Module { - run() { - } + run() {} - constructor(app: App) { - super(app, 'hdu', config.match.hdu) - } -} \ No newline at end of file + constructor(app: App) { + super(app, 'hdu', config.match.hdu); + } +} diff --git a/src/modules/qoj/main.ts b/src/modules/qoj/main.ts index caf4c57..c3a2338 100644 --- a/src/modules/qoj/main.ts +++ b/src/modules/qoj/main.ts @@ -1,12 +1,11 @@ -import config from '../../config' -import App from '../../app' -import Module from "../../types/module" +import config from '../../config'; +import App from '../../app'; +import Module from '../../types/module'; export default class ModuleQOJ extends Module { - run() { - } + run() {} - constructor(app: App) { - super(app, 'qoj', config.match.qoj) - } -} \ No newline at end of file + constructor(app: App) { + super(app, 'qoj', config.match.qoj); + } +} diff --git a/src/modules/vjudge/features/AcceptedCounter.ts b/src/modules/vjudge/features/AcceptedCounter.ts index 42f5713..1684bf1 100644 --- a/src/modules/vjudge/features/AcceptedCounter.ts +++ b/src/modules/vjudge/features/AcceptedCounter.ts @@ -1,23 +1,23 @@ -import Feature from "../../../types/feature"; +import Feature from '../../../types/feature'; export default class AcceptedCounter extends Feature { - run() { - this.on('/user/*', () => { - (document.getElementsByClassName('toggle-detail')[0] as HTMLElement).onclick = () => { - for (const $tr of document.querySelectorAll('#probRecords tbody tr:not(#templ)')) { - let ojName = ($tr.children[0] as HTMLElement).innerText.trim(); - let acceptedNum = $tr.children[1].children.length || 0; - let attemptedNum = $tr.children[2].children.length || 0; - $tr.children[0].innerHTML = ` + run() { + this.on('/user/*', () => { + (document.getElementsByClassName('toggle-detail')[0] as HTMLElement).onclick = () => { + for (const $tr of document.querySelectorAll('#probRecords tbody tr:not(#templ)')) { + let ojName = ($tr.children[0] as HTMLElement).innerText.trim(); + let acceptedNum = $tr.children[1].children.length || 0; + let attemptedNum = $tr.children[2].children.length || 0; + $tr.children[0].innerHTML = ` ${ojName}
${acceptedNum} / ${acceptedNum + attemptedNum} `; - console.log(ojName, acceptedNum, attemptedNum); - } - } - }); - } + console.log(ojName, acceptedNum, attemptedNum); + } + }; + }); + } } diff --git a/src/modules/vjudge/features/ForkContest.ts b/src/modules/vjudge/features/ForkContest.ts index 80c47ca..fb17446 100644 --- a/src/modules/vjudge/features/ForkContest.ts +++ b/src/modules/vjudge/features/ForkContest.ts @@ -1,126 +1,139 @@ // import * as h from 'h'; import wait from 'wait'; import Module from '../../../types/module'; -import Feature from "../../../types/feature"; +import Feature from '../../../types/feature'; import { htmlToElement } from '../../../utils/element'; import { parseCPAData, generateCPAData } from '../../../utils/query-string'; import { writeClipboard, openInNewTab } from '../../../utils/browser'; export interface VjudgeProblem { - oj: string; - id: string; -}; + oj: string; + id: string; +} export default class ForkContest extends Feature { - async createContest(title: string, problemList: Array) { - let content = ''; - for (const problem of problemList) { - content += `${problem.oj}\t|\t${problem.id}\t|\t1\t|\t\n`; - } - - (document.getElementById('btn-create') as HTMLElement).click(); - await wait(500); - (document.getElementById('edit-plain') as HTMLElement).click(); - await wait(100); - (document.getElementById('contest-title') as HTMLInputElement).value = title; - (document.getElementById('problems-plain') as HTMLTextAreaElement).value = content; - await wait(100); - (document.getElementById('problems-plain-btn-confirm') as HTMLElement).click(); - } - - run() { - this.on('/contest', async () => { - const data = parseCPAData(location.search); - if (data.type == 'create-contest' && data.title && data.problems) { - return this.createContest(data.title, data.problems); - } - }) - } - - registerPlugins() { - async function copyPid(problems: Array): Promise { - let result = ''; - for (const problem of problems) { - result += `[problem:${problem.oj}-${problem.id}]\n`; - } - if (result) { result.slice(0, result.length - 1); } - return writeClipboard(result); - } - - async function forkContest(problems: Array, contestTitle: string): Promise { - openInNewTab('https://vjudge.net/contest' + generateCPAData({ - type: 'create-contest', - title: contestTitle, - problems: problems, - })); - } - - this.plugin('codeforces', function (this: Feature) { - this.log('setup'); - - function setup(situation: string, roundId: string) { - const $menu = document.getElementsByClassName('second-level-menu')[0]; - const $menuList = $menu.children[0]; - $menuList.appendChild(htmlToElement(` + async createContest(title: string, problemList: Array) { + let content = ''; + for (const problem of problemList) { + content += `${problem.oj}\t|\t${problem.id}\t|\t1\t|\t\n`; + } + + (document.getElementById('btn-create') as HTMLElement).click(); + await wait(500); + (document.getElementById('edit-plain') as HTMLElement).click(); + await wait(100); + (document.getElementById('contest-title') as HTMLInputElement).value = title; + (document.getElementById('problems-plain') as HTMLTextAreaElement).value = content; + await wait(100); + (document.getElementById('problems-plain-btn-confirm') as HTMLElement).click(); + } + + run() { + this.on('/contest', async () => { + const data = parseCPAData(location.search); + if (data.type == 'create-contest' && data.title && data.problems) { + return this.createContest(data.title, data.problems); + } + }); + } + + registerPlugins() { + async function copyPid(problems: Array): Promise { + let result = ''; + for (const problem of problems) { + result += `[problem:${problem.oj}-${problem.id}]\n`; + } + if (result) { + result.slice(0, result.length - 1); + } + return writeClipboard(result); + } + + async function forkContest(problems: Array, contestTitle: string): Promise { + openInNewTab( + 'https://vjudge.net/contest' + + generateCPAData({ + type: 'create-contest', + title: contestTitle, + problems: problems, + }) + ); + } + + this.plugin('codeforces', function (this: Feature) { + this.log('setup'); + + function setup(situation: string, roundId: string) { + const $menu = document.getElementsByClassName('second-level-menu')[0]; + const $menuList = $menu.children[0]; + $menuList.appendChild( + htmlToElement(`
  • copy problem ids (VJ)
  • - `)); - $menuList.appendChild(htmlToElement(` + `) + ); + $menuList.appendChild( + htmlToElement(`
  • fork contest (VJ)
  • - `)); - - const $buttonCopyPid: HTMLElement = document.getElementById('cpa-copy-pid')!; - const $buttonForkContest: HTMLElement = document.getElementById('cpa-fork-contest')!; - - function getProblems(): Array { - const $problemTableLines = Array.from(document.getElementsByClassName('problems')[0].children[0].children).slice(1); - const problems: Array = []; - const onlineJudge = situation == 'gym' ? 'Gym' : 'CodeForces'; - for (const $problemTableLine of $problemTableLines) { - problems.push(($problemTableLine.children[0] as HTMLElement).innerText.trim()); - } - return problems.map((problemId) => ({ oj: onlineJudge, id: `${roundId}${problemId}` })); - } - - function getContestTitle(): string { - return ((document.getElementById('sidebar') as HTMLElement).children[0].children[0].children[0].children[0].children[0] as HTMLElement).innerText.trim(); - } - - $buttonCopyPid.onclick = async () => copyPid(getProblems()); - $buttonForkContest.onclick = async () => forkContest(getProblems(), getContestTitle()); - } - - this.on('/gym/', (args) => { setup('gym', args.id); }) - this.on('/contest/', (args) => { setup('contest', args.id); }) - }); - - this.plugin('qoj', function (this: Feature) { - this.on('/contest/', () => { - const $nav = document.getElementsByClassName('nav-tabs')[0]; - $nav.appendChild(htmlToElement(``)); - $nav.appendChild(htmlToElement(``)); - - function getProblems(): Array { - const problems: Array = []; - for (const $problemLink of document.querySelectorAll('.table-responsive')[0].querySelectorAll('table>tbody a')) { - const href = $problemLink.attributes.getNamedItem('href')!.value; - const id = href.split('/').at(-1)!; - problems.push({ oj: 'QOJ', id }); - } - return problems; - } - function getContestTitle(): string { - return document.querySelector('.uoj-content .text-center h1')!.innerHTML.trim(); - } - - document.getElementById('cpa-copy-pid')!.onclick = async () => copyPid(getProblems()); - document.getElementById('cpa-fork-contest')!.onclick = async () => forkContest(getProblems(), getContestTitle()); - }); - }); - } - - constructor(module: Module, name: string) { - super(module, name); - - this.registerPlugins(); - } + `) + ); + + const $buttonCopyPid: HTMLElement = document.getElementById('cpa-copy-pid')!; + const $buttonForkContest: HTMLElement = document.getElementById('cpa-fork-contest')!; + + function getProblems(): Array { + const $problemTableLines = Array.from(document.getElementsByClassName('problems')[0].children[0].children).slice(1); + const problems: Array = []; + const onlineJudge = situation == 'gym' ? 'Gym' : 'CodeForces'; + for (const $problemTableLine of $problemTableLines) { + problems.push(($problemTableLine.children[0] as HTMLElement).innerText.trim()); + } + return problems.map((problemId) => ({ oj: onlineJudge, id: `${roundId}${problemId}` })); + } + + function getContestTitle(): string { + return ((document.getElementById('sidebar') as HTMLElement).children[0].children[0].children[0].children[0].children[0] as HTMLElement).innerText.trim(); + } + + $buttonCopyPid.onclick = async () => copyPid(getProblems()); + $buttonForkContest.onclick = async () => forkContest(getProblems(), getContestTitle()); + } + + this.on('/gym/', (args) => { + setup('gym', args.id); + }); + this.on('/contest/', (args) => { + setup('contest', args.id); + }); + }); + + this.plugin('qoj', function (this: Feature) { + this.on('/contest/', () => { + const $nav = document.getElementsByClassName('nav-tabs')[0]; + $nav.appendChild(htmlToElement(``)); + $nav.appendChild(htmlToElement(``)); + + function getProblems(): Array { + const problems: Array = []; + for (const $problemLink of document.querySelectorAll('.table-responsive')[0].querySelectorAll('table>tbody a')) { + const href = $problemLink.attributes.getNamedItem('href')!.value; + const id = href.split('/').at(-1)!; + problems.push({ oj: 'QOJ', id }); + } + return problems; + } + function getContestTitle(): string { + return document.querySelector('.uoj-content .text-center h1')!.innerHTML.trim(); + } + + document.getElementById('cpa-copy-pid')!.onclick = async () => copyPid(getProblems()); + document.getElementById('cpa-fork-contest')!.onclick = async () => forkContest(getProblems(), getContestTitle()); + }); + }); + } + + constructor(module: Module, name: string) { + super(module, name); + + this.registerPlugins(); + } } diff --git a/src/modules/vjudge/main.ts b/src/modules/vjudge/main.ts index b30abcb..8da0956 100644 --- a/src/modules/vjudge/main.ts +++ b/src/modules/vjudge/main.ts @@ -1,17 +1,16 @@ -import config from '../../config' -import App from '../../app' -import Module from "../../types/module" -import AcceptedCounter from "./features/AcceptedCounter" -import ForkContest from './features/ForkContest' +import config from '../../config'; +import App from '../../app'; +import Module from '../../types/module'; +import AcceptedCounter from './features/AcceptedCounter'; +import ForkContest from './features/ForkContest'; export default class ModuleVjudge extends Module { - run() { - } + run() {} - constructor(app: App) { - super(app, 'vjudge', config.match.vjudge) + constructor(app: App) { + super(app, 'vjudge', config.match.vjudge); - this.register(new AcceptedCounter(this, 'accepted-counter')) - this.register(new ForkContest(this, 'fork-contest')) - } -} \ No newline at end of file + this.register(new AcceptedCounter(this, 'accepted-counter')); + this.register(new ForkContest(this, 'fork-contest')); + } +} diff --git a/src/types/feature.ts b/src/types/feature.ts index 62f0423..3a548f6 100644 --- a/src/types/feature.ts +++ b/src/types/feature.ts @@ -3,83 +3,85 @@ import Module from './module'; import { Dict } from '../utils/type'; export default class Feature { - app: App - module: Module - name: string + app: App; + module: Module; + name: string; - log(...args: any[]) { - return this.module.log(`[${this.name}]`, ...args); - } + log(...args: any[]) { + return this.module.log(`[${this.name}]`, ...args); + } - run() { } + run() {} - apply() { - this.run(); - } + apply() { + this.run(); + } - plugin(moduleName: string, func: () => void) { - if (moduleName in this.app.modules) { - const module = this.app.modules[moduleName]; - const virtualFeature = new Feature(module, `${this.module.name}::${this.name}`); - virtualFeature.run = () => { func.call(virtualFeature); }; - module.register(virtualFeature); - } else { - if (!(moduleName in this.app._queuedPlugins)) { - this.app._queuedPlugins[moduleName] = []; - } - this.app._queuedPlugins[moduleName].push({ feature: this, func }); - } - } + plugin(moduleName: string, func: () => void) { + if (moduleName in this.app.modules) { + const module = this.app.modules[moduleName]; + const virtualFeature = new Feature(module, `${this.module.name}::${this.name}`); + virtualFeature.run = () => { + func.call(virtualFeature); + }; + module.register(virtualFeature); + } else { + if (!(moduleName in this.app._queuedPlugins)) { + this.app._queuedPlugins[moduleName] = []; + } + this.app._queuedPlugins[moduleName].push({ feature: this, func }); + } + } - on(match: string | Array, func: (args: Dict) => void): boolean { - if (match instanceof Array) { - let ok = false - for (const singleMatch of match) { - ok = this.on(singleMatch, func) - if (ok) { - return ok - } - } - return false - } + on(match: string | Array, func: (args: Dict) => void): boolean { + if (match instanceof Array) { + let ok = false; + for (const singleMatch of match) { + ok = this.on(singleMatch, func); + if (ok) { + return ok; + } + } + return false; + } - const args: Dict = {} - const matchParts = match.slice(1).split('/') - const pathParts = location.pathname.slice(1).split('/') - if (matchParts[matchParts.length - 1] == '') { - --matchParts.length; - } - if (pathParts[pathParts.length - 1] == '') { - --pathParts.length; - } + const args: Dict = {}; + const matchParts = match.slice(1).split('/'); + const pathParts = location.pathname.slice(1).split('/'); + if (matchParts[matchParts.length - 1] == '') { + --matchParts.length; + } + if (pathParts[pathParts.length - 1] == '') { + --pathParts.length; + } - if (pathParts.length < matchParts.length) { - return false - } - if (pathParts.length > matchParts.length && matchParts[matchParts.length - 1] !== '*') { - return false - } + if (pathParts.length < matchParts.length) { + return false; + } + if (pathParts.length > matchParts.length && matchParts[matchParts.length - 1] !== '*') { + return false; + } - for (let i = 0; i < matchParts.length; i++) { - if (matchParts[i] === '*') { - break - } else if (matchParts[i].startsWith('<') && matchParts[i].endsWith('>')) { - const key = matchParts[i].slice(1, matchParts[i].length - 1) - args[key] = pathParts[i] - } else { - if (matchParts[i] != pathParts[i]) { - return false - } - } - } + for (let i = 0; i < matchParts.length; i++) { + if (matchParts[i] === '*') { + break; + } else if (matchParts[i].startsWith('<') && matchParts[i].endsWith('>')) { + const key = matchParts[i].slice(1, matchParts[i].length - 1); + args[key] = pathParts[i]; + } else { + if (matchParts[i] != pathParts[i]) { + return false; + } + } + } - func(args) - return true - } + func(args); + return true; + } - constructor(module: Module, name: string) { - this.app = module.app; - this.module = module; - this.name = name; - } -} \ No newline at end of file + constructor(module: Module, name: string) { + this.app = module.app; + this.module = module; + this.name = name; + } +} diff --git a/src/types/module.ts b/src/types/module.ts index fa6885e..9701d91 100644 --- a/src/types/module.ts +++ b/src/types/module.ts @@ -3,37 +3,37 @@ import Feature from './feature'; import { PlainFunction } from '../utils/type'; export default class Module { - app: App - name: string - match: Array - features: Array - plugins: Array + app: App; + name: string; + match: Array; + features: Array; + plugins: Array; - log(...args: any[]) { - return this.app.log(`[${this.name}]`, ...args); - } + log(...args: any[]) { + return this.app.log(`[${this.name}]`, ...args); + } - run() { } + run() {} - apply() { - this.run() - for (const feature of this.features) { - feature.apply() - } - for (const pluginFunction of this.plugins) { - pluginFunction() - } - } + apply() { + this.run(); + for (const feature of this.features) { + feature.apply(); + } + for (const pluginFunction of this.plugins) { + pluginFunction(); + } + } - register(feature: Feature) { - this.features.push(feature) - } + register(feature: Feature) { + this.features.push(feature); + } - constructor(app: App, name: string, match: Array) { - this.app = app - this.name = name - this.match = match - this.features = [] - this.plugins = [] - } -} \ No newline at end of file + constructor(app: App, name: string, match: Array) { + this.app = app; + this.name = name; + this.match = match; + this.features = []; + this.plugins = []; + } +} diff --git a/src/utils/browser.ts b/src/utils/browser.ts index 610b2c4..fb8bf29 100644 --- a/src/utils/browser.ts +++ b/src/utils/browser.ts @@ -1,14 +1,14 @@ export function openInNewTab(url: string): void { - const element = document.createElement('a'); - element.setAttribute('href', encodeURI(url)); - element.setAttribute('target', '_blank'); - element.click(); + const element = document.createElement('a'); + element.setAttribute('href', encodeURI(url)); + element.setAttribute('target', '_blank'); + element.click(); } export async function readClipboard(): Promise { - return navigator.clipboard.readText(); + return navigator.clipboard.readText(); } export async function writeClipboard(text: string): Promise { - return navigator.clipboard.writeText(text); -} \ No newline at end of file + return navigator.clipboard.writeText(text); +} diff --git a/src/utils/element.ts b/src/utils/element.ts index afe8f7d..6bf9b93 100644 --- a/src/utils/element.ts +++ b/src/utils/element.ts @@ -1,6 +1,6 @@ export function htmlToElement(html: string): Element { - const template = document.createElement('template'); - html = html.trim(); // Never return a text node of whitespace as the result - template.innerHTML = html; - return (template.content.firstChild as Element); -} \ No newline at end of file + const template = document.createElement('template'); + html = html.trim(); // Never return a text node of whitespace as the result + template.innerHTML = html; + return template.content.firstChild as Element; +} diff --git a/src/utils/query-string.ts b/src/utils/query-string.ts index 52633ce..9844179 100644 --- a/src/utils/query-string.ts +++ b/src/utils/query-string.ts @@ -1,48 +1,52 @@ import { Dict } from './type'; export function parseQueryString(query: string): Dict { - if (query.startsWith('?')) { query = query.slice(1); } - const records: Dict = {}; - for (const kvString of query.split('&')) { - const idx = kvString.indexOf('='); - if (idx === -1) { - continue; - } - const key = kvString.slice(0, idx); - const value = kvString.slice(idx + 1, kvString.length); - records[key] = decodeURI(value); - } - return records; + if (query.startsWith('?')) { + query = query.slice(1); + } + const records: Dict = {}; + for (const kvString of query.split('&')) { + const idx = kvString.indexOf('='); + if (idx === -1) { + continue; + } + const key = kvString.slice(0, idx); + const value = kvString.slice(idx + 1, kvString.length); + records[key] = decodeURI(value); + } + return records; } export function generateQueryString(records: Dict): string { - let query = '?'; - for (let i = 0; i < Object.keys(records).length; i++) { - const key = Object.keys(records)[i]; - const value = Object.values(records)[i]; - if (i) { - query += '&'; - } - query += `${key}=${encodeURI(value)}`; - } - return query; + let query = '?'; + for (let i = 0; i < Object.keys(records).length; i++) { + const key = Object.keys(records)[i]; + const value = Object.values(records)[i]; + if (i) { + query += '&'; + } + query += `${key}=${encodeURI(value)}`; + } + return query; } export function parseCPAData(query: string): any { - const records = parseQueryString(query); - if (!records.cpa) { return null; } - const json = decodeURI(atob(records.cpa)); - let data: any = null; - try { - data = JSON.parse(json); - } catch (err) { - console.error('JSON parse error!'); - return null; - } - return data; + const records = parseQueryString(query); + if (!records.cpa) { + return null; + } + const json = decodeURI(atob(records.cpa)); + let data: any = null; + try { + data = JSON.parse(json); + } catch (err) { + console.error('JSON parse error!'); + return null; + } + return data; } export function generateCPAData(data: any): string { - const json = JSON.stringify(data); - return generateQueryString({ cpa: btoa(encodeURI(json)) }); -} \ No newline at end of file + const json = JSON.stringify(data); + return generateQueryString({ cpa: btoa(encodeURI(json)) }); +} diff --git a/src/utils/type.ts b/src/utils/type.ts index ed0e2a5..e8705a0 100644 --- a/src/utils/type.ts +++ b/src/utils/type.ts @@ -1,3 +1,3 @@ export type Dict = { [key: string]: V }; -export type PlainFunction = () => void; \ No newline at end of file +export type PlainFunction = () => void;