diff --git a/u2_history.user.js b/u2_history.user.js new file mode 100644 index 0000000..df0c0a0 --- /dev/null +++ b/u2_history.user.js @@ -0,0 +1,224 @@ +// ==UserScript== +// @name 保存个人说明历史 +// @namespace https://github.com/lifegpc/userscript +// @version 0.0.1 +// @description 保存个人说明历史 +// @author lifegpc +// @match https://u2.dmhy.org/usercp.php?action=personal* +// @icon https://u2.dmhy.org/favicon.ico +// ==/UserScript== +/**@type {IDBDatabase} */ +let db = undefined; +let need_reinit = false; +let storage = navigator.storage || globalThis['WorkerNavigator']['storage']; +async function make_storage_persist() { + let persisted = await storage.persisted(); + if (!persisted) { + persisted = await storage.persist(); + } + return persisted; +} +function init() { + return new Promise((resolve, reject) => { + make_storage_persist().then(() => { + if (db !== undefined && !need_reinit) { + resolve(); + return; + } + let indexedReq = indexedDB.open('u2_history', 1); + /**@param {IDBVersionChangeEvent} event*/ + indexedReq.onupgradeneeded = function (event) { + let db = this.result; + console.log(`upgrade u2_history from ${event.oldVersion} to ${event.newVersion}`); + /*No version or version < 1 -> v1 */ + if (isNaN(event.oldVersion) || event.oldVersion < 1) { + db.createObjectStore('info', { keyPath: 'time' }); + } + } + indexedReq.onsuccess = () => { + db = indexedReq.result; + resolve(); + } + indexedReq.onerror = () => { + need_reinit = true; + reject(indexedReq.error); + } + }).catch(reject); + }) +} +/** + * @template T + * @param {(tx: IDBDatabase) => IDBRequest} callback + * @returns {Promise} + */ +function db_handle(callback) { + return new Promise((resolve, reject) => { + init().then(() => { + let req = callback(db); + req.onsuccess = () => { + let re = req.result; + resolve(re); + } + req.onerror = () => { + need_reinit = true; + reject(req.error); + } + }).catch(reject); + }) +} +async function get_all_info_keys() { + return await db_handle(db => db.transaction('info').objectStore('info').getAllKeys()); +} +async function get_info(time) { + let info = await db_handle(db => db.transaction('info').objectStore('info').get(time)); + return info ? info.info : undefined; +} +async function delete_info(time) { + await db_handle(db => db.transaction('info', 'readwrite').objectStore('info').delete(time)); +} +async function save_info(time, info) { + return await db_handle(db => db.transaction('info', 'readwrite').objectStore('info').put({ time, info })); +} +async function render_page() {} +let times = await get_all_info_keys(); +let textarea = document.querySelector('textarea[name="info"]'); +let submit = document.querySelector('input[type="submit"]'); +if (!times.length) { + let info = textarea.value; + if (info) { + times.push(await save_info(new Date, info)); + } +} +console.log(times) +if (times.length) { + times.sort((a, b) => b.getTime() - a.getTime()) + let details = document.createElement('details'); + let summary = document.createElement('summary'); + summary.innerText = '历史记录'; + details.append(summary); + let body = document.createElement('div'); + details.append(body); + textarea.parentElement.append(details); + let page = 0; + const count_per_page = 10; + /** + * @param {Date} time + * @param {string} info + */ + function render_info(time, info) { + const details = document.createElement('details'); + const summary = document.createElement('summary'); + summary.innerText = time.toLocaleString(); + details.append(summary); + const form = document.createElement('form'); + form.target = '_blank'; + form.action = "/tags.php"; + form.method = "post"; + details.append(form); + const ntextarea = document.createElement('textarea'); + ntextarea.readOnly = true; + ntextarea.name = "test"; + ntextarea.value = info; + ntextarea.style.width = textarea.style.width; + ntextarea.rows = textarea.rows; + form.append(ntextarea); + const line = document.createElement('div'); + form.append(line); + const use = document.createElement('input'); + use.type = "button"; + use.value = "使用"; + use.addEventListener('click', () => { + textarea.value = info; + }) + line.append(use); + const preview = document.createElement('input'); + preview.type = "submit"; + preview.value = "预览"; + line.append(preview); + const del = document.createElement('input'); + del.type = "button"; + del.value = "删除"; + del.addEventListener('click', async () => { + await delete_info(time); + times = await get_all_info_keys(); + times.sort((a, b) => b.getTime() - a.getTime()); + await render_page(); + }) + line.append(del); + body.append(details); + } + async function render_page() { + body.innerHTML = ''; + const total_page = Math.ceil(times.length / count_per_page); + if (page < 0) page = 0; + if (page >= total_page) page = total_page - 1; + const max = Math.min((page + 1) * count_per_page, times.length); + for (let i = page * count_per_page; i < max; i++) { + const time = times[i]; + const info = await get_info(time); + render_info(time, info); + } + const line = document.createElement('div'); + body.append(line); + const pagei = document.createElement('input'); + pagei.type = 'number'; + pagei.min = '1'; + pagei.max = `${total_page}`; + pagei.value = `${page + 1}`; + pagei.addEventListener('change', () => { + page = pagei.valueAsNumber - 1; + render_page(); + }) + line.append(pagei); + line.append(`/${total_page}页`); + if (page > 0) { + const first = document.createElement('input'); + first.type = 'button'; + first.value = '首页'; + first.addEventListener('click', () => { + page = 0; + render_page(); + }) + line.append(first); + const prev = document.createElement('input'); + prev.type = 'button'; + prev.value = '上一页'; + prev.addEventListener('click', () => { + page--; + render_page(); + }) + line.append(prev); + } + if (page < total_page - 1) { + const next = document.createElement('input'); + next.type = 'button'; + next.value = '下一页'; + next.addEventListener('click', () => { + page++; + render_page(); + }) + line.append(next); + const last = document.createElement('input'); + last.type = 'button'; + last.value = '尾页'; + last.addEventListener('click', () => { + page = total_page - 1; + render_page(); + }) + line.append(last); + } + } + await render_page(); +} else { + let div = document.createElement('div'); + div.innerText = "无历史记录"; + textarea.parentElement.append(div); +} +submit.addEventListener('click', async () => { + const last_time = new Date(Math.max(...times)); + const info_db = await get_info(last_time); + const info = textarea.value; + if (info != info_db) { + await save_info(new Date, info); + } +})