diff --git a/src/background.js b/src/background.js index 5f9aade..4d6a674 100644 --- a/src/background.js +++ b/src/background.js @@ -20,4 +20,6 @@ chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) { chrome.contextMenus.update(titleId, { "title": convertStr, }); -}); \ No newline at end of file +}); +// 此文件在 Manifest V3 中不再需要,因为功能已移至 service-worker.js +// 保留此文件以保持向后兼容性,但内容已清空 diff --git a/src/content.js b/src/content.js index 7b32555..13fad46 100644 --- a/src/content.js +++ b/src/content.js @@ -1,5 +1,5 @@ /** - * 发送消息到 background.js + * 发送消息到 service worker */ window.onmouseup = function () { let selection = window.getSelection(); @@ -8,4 +8,11 @@ window.onmouseup = function () { } else { chrome.runtime.sendMessage(""); } -} \ No newline at end of file +} + +// 监听来自service worker的消息 +chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) { + if (request.action === "showAlert") { + alert(request.message); + } +}); \ No newline at end of file diff --git a/src/manifest.json b/src/manifest.json index f28bec5..2b45fdc 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -1,10 +1,11 @@ { - "browser_action": { + "manifest_version": 3, + "name": "时间戳转化", + "version": "1.0.3", + "description": "时间戳转换小工具。右键菜单显示转化,工具页时间戳转化", + "action": { "default_popup": "popup.html" }, - "description": "时间戳转换小工具。右键菜单显示转化,工具页时间戳转化", - "manifest_version": 2, - "name": "时间戳转化", "content_scripts": [ { "matches": [ @@ -16,15 +17,12 @@ } ], "options_page": "popup.html", - "version": "1.0.3", "permissions": [ "clipboardRead", - "contextMenus" + "contextMenus", + "storage" ], "background": { - "scripts": [ - "background.js", - "utils.js" - ] + "service_worker": "service-worker.js" } -} +} \ No newline at end of file diff --git a/src/popup.html b/src/popup.html index f41a1e9..0ee2fdb 100644 --- a/src/popup.html +++ b/src/popup.html @@ -77,14 +77,14 @@

- 时间戳位数判断: + 时间戳位数判断:
- 小提示:鼠标滚轮中键点击可以复制或者粘贴,年月日时分秒字符串的分隔符不限 + 小提示:鼠标滚轮中键点击可以复制或者粘贴,年月日时分秒字符串的分隔符不限
  diff --git a/src/scripts.js b/src/scripts.js index 61c25ae..f63d72c 100644 --- a/src/scripts.js +++ b/src/scripts.js @@ -27,44 +27,79 @@ let only10Radio = document.getElementById("only-10-radio"); let only13Radio = document.getElementById("only-13-radio"); let both10_13 = document.getElementById("both-10-13-radio"); - +/** + * 获取当前时间的13位时间戳 + * @returns {number} 当前时间的13位时间戳 + */ function getTimestamp13() { return now.getTime(); } +/** + * 刷新时间显示 + */ function refresh() { now = new Date(); timestampNowInput.value = getTimestamp13(); - bjTimeInput.value = getTimeString(getTimestamp13(), localStorage.timestampJudgeType); + bjTimeInput.value = getTimeString(getTimestamp13(), getTypeFromStorage()); +} + +/** + * 从存储中获取时间戳判断类型 + */ +function getTypeFromStorage() { + // 默认返回 "3" (10/13位) + return localStorage.timestampJudgeType || "3"; } +/** + * 刷新时间显示并重置定时器 + */ function refreshWithInterval() { window.clearInterval(interval); refresh(); interval = getInterval(); } +/** + * 执行转换操作 + */ function change() { let s = inputInput.value.trim().toString(); - resultInput.value = convert(s, localStorage.timestampJudgeType); + resultInput.value = convert(s, getTypeFromStorage()); } +/** + * 从剪贴板粘贴内容 + * @param item 要粘贴到的元素 + */ function paste(item) { item.select(); document.execCommand('paste'); msg("从剪切板获取!"); } +/** + * 交换输入输出框的内容 + */ function exchangeEachOther() { sendStrToInput(resultInput.value); } +/** + * 复制内容到剪贴板 + * @param item 要复制的元素 + */ function copy(item) { item.select(); document.execCommand('copy'); msg("已复制到剪切板"); } +/** + * 显示消息并在1秒后清除 + * @param m 要显示的消息 + */ function msg(m) { msgSpan.innerText = m; setTimeout(function () { @@ -72,6 +107,9 @@ function msg(m) { }, 1000); } +/** + * 更新刷新间隔 + */ function refreshGap() { let value = gapInput.value; if (!isNaN(value)) { @@ -81,27 +119,36 @@ function refreshGap() { } } +/** + * 设置输入框的值并执行转换 + * @param text 要设置的文本 + */ function sendStrToInput(text) { inputInput.value = text; change(); } +// 绑定刷新按钮事件 refreshButton.onclick = function () { refreshWithInterval(); }; +// 绑定转换按钮事件 changeButton.onclick = function () { change(); }; +// 绑定输入框输入事件 inputInput.oninput = function () { change(); }; +// 绑定刷新间隔输入框事件 gapInput.oninput = function () { refreshGap(); }; +// 绑定刷新间隔输入框按键事件 gapInput.onkeypress = function (e) { refreshGap(); @@ -110,60 +157,74 @@ gapInput.onkeypress = function (e) { } }; +// 绑定结果输入框输入事件 resultInput.oninput = function () { let value = resultInput.value; inputInput.value = formatTimeString(value); }; +// 绑定输入框鼠标按下事件 inputInput.onmousedown = function (e) { if (e.button === 1) { paste(inputInput); } }; +// 绑定结果框鼠标按下事件 resultInput.onmousedown = function (e) { if (e.button === 1) { copy(resultInput); } }; +// 绑定时间戳输入框鼠标按下事件 timestampNowInput.onmousedown = function (e) { if (e.button === 1) { copy(timestampNowInput); } }; +// 绑定北京时间输入框鼠标按下事件 bjTimeInput.onmousedown = function (e) { if (e.button === 1) { copy(bjTimeInput); } }; +// 绑定"now"按钮点击事件 nowButton.onclick = function () { sendStrToInput(new Date().getTime()); }; +// 绑定复制时间戳按钮事件 copyTimestampButton.onclick = function () { copy(timestampNowInput); }; +// 绑定复制时间按钮事件 copyTimeButton.onclick = function () { copy(bjTimeInput); }; +// 绑定粘贴按钮事件 pasteButton.onclick = function () { paste(inputInput); }; +// 绑定交换按钮事件 exchangeEachOtherButton.onclick = function () { exchangeEachOther(); }; +// 绑定清空按钮事件 clearButton.onclick = function () { resultInput.value = ""; inputInput.value = ""; }; +/** + * 更改自动刷新复选框状态 + */ function changeGoCheckBox() { goStatus = goonCheckBox.checked; if (goStatus) { @@ -172,12 +233,15 @@ function changeGoCheckBox() { localStorage.goStatus = goStatus; } +// 绑定自动刷新复选框事件 goonCheckBox.onclick = changeGoCheckBox; +// 绑定复制结果按钮事件 copyResultButton.onclick = function () { copy(resultInput); }; +// 绑定显示警告复选框事件 showAlertCheckbox.onclick = function () { let checked = showAlertCheckbox.checked; if (checked) { @@ -187,18 +251,24 @@ showAlertCheckbox.onclick = function () { } }; +// 绑定仅10位时间戳单选框事件 only10Radio.onclick = function () { localStorage.timestampJudgeType = "1"; }; +// 绑定仅13位时间戳单选框事件 only13Radio.onclick = function () { localStorage.timestampJudgeType = "2"; }; +// 绑定10/13位时间戳单选框事件 both10_13.onclick = function () { localStorage.timestampJudgeType = "3"; }; +/** + * 加载时间戳判断类型设置 + */ function loadTimestampJudgeType() { let timestampJudgeType = localStorage.timestampJudgeType; switch (timestampJudgeType) { @@ -217,16 +287,26 @@ function loadTimestampJudgeType() { } } +/** + * 加载自动刷新状态 + */ function loadGoonStatus() { goStatus = !(localStorage.goStatus === "false"); goonCheckBox.checked = goStatus; goonCheckBox.isChecked = goStatus; } +/** + * 加载菜单提醒操作设置 + */ function loadMenuRadioAction() { showAlertCheckbox.checked = !(localStorage.showAlert === "false"); } +/** + * 获取定时器 + * @returns {number} 定时器ID + */ function getInterval() { return setInterval(function () { if (goStatus) { @@ -235,6 +315,7 @@ function getInterval() { }, gap); } +// 初始化 refresh(); inputInput.focus(); @@ -242,9 +323,7 @@ inputInput.value = localStorage.selectText; change(); loadGoonStatus(); - loadMenuRadioAction(); - loadTimestampJudgeType(); interval = getInterval(); \ No newline at end of file diff --git a/src/service-worker.js b/src/service-worker.js new file mode 100644 index 0000000..d841d71 --- /dev/null +++ b/src/service-worker.js @@ -0,0 +1,121 @@ +// 导入工具函数 +importScripts('utils.js'); + +let titleId = "convert"; + +chrome.contextMenus.create({ + title: "时间戳转换", + id: titleId, + contexts: ["selection"] +}, () => { + // 处理菜单创建可能的错误 + if (chrome.runtime.lastError) { + console.error("创建上下文菜单时出错:", chrome.runtime.lastError.message); + } +}); + +// 监听菜单项点击事件 +chrome.contextMenus.onClicked.addListener((info, tab) => { + if (info.menuItemId === titleId) { + let selectionText = info.selectionText; + + // 检查selectionText是否有效 + if (!selectionText) { + console.warn("未找到选中的文本"); + return; + } + + // 获取设置 + chrome.storage.local.get(['timestampJudgeType', 'showAlert'], function(result) { + // 处理可能的存储错误 + if (chrome.runtime.lastError) { + console.error("读取存储时出错:", chrome.runtime.lastError.message); + return; + } + + let timestampJudgeType = result.timestampJudgeType || "3"; + let showAlert = result.showAlert !== "false"; + + try { + let convertStr = convert(selectionText, timestampJudgeType); + + // 保存选中文本 + chrome.storage.local.set({selectText: convertStr}, () => { + if (chrome.runtime.lastError) { + console.error("保存选中文本时出错:", chrome.runtime.lastError.message); + } + }); + + if (showAlert) { + // 通过 tabs.sendMessage 发送消息到内容脚本显示 alert + chrome.tabs.sendMessage(tab.id, {action: "showAlert", message: convertStr}, () => { + // 忽略发送消息可能的错误 + if (chrome.runtime.lastError) { + console.warn("发送消息到内容脚本时出错:", chrome.runtime.lastError.message); + } + }); + } + } catch (e) { + console.error("转换文本时出错:", e); + } + }); + } +}); + +// 监听来自内容脚本的消息 +chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) { + if (typeof message === 'string') { + // 获取设置 + chrome.storage.local.get(['timestampJudgeType'], function(result) { + // 处理可能的存储错误 + if (chrome.runtime.lastError) { + console.error("读取存储时出错:", chrome.runtime.lastError.message); + return; + } + + let timestampJudgeType = result.timestampJudgeType || "3"; + try { + let convertStr = convert(message, timestampJudgeType) + " "; + chrome.contextMenus.update(titleId, { + "title": convertStr, + }, () => { + if (chrome.runtime.lastError) { + console.error("更新上下文菜单时出错:", chrome.runtime.lastError.message); + } + }); + } catch (e) { + console.error("转换文本时出错:", e); + } + }); + return true; + } else if (message && message.action === "convert") { + // 检查消息完整性 + if (!message.text) { + sendResponse({result: ""}); + return false; + } + + // 获取设置 + chrome.storage.local.get(['timestampJudgeType'], function(result) { + // 处理可能的存储错误 + if (chrome.runtime.lastError) { + console.error("读取存储时出错:", chrome.runtime.lastError.message); + sendResponse({result: "错误: 无法读取配置"}); + return; + } + + let timestampJudgeType = result.timestampJudgeType || "3"; + try { + let convertStr = convert(message.text, timestampJudgeType); + sendResponse({result: convertStr}); + } catch (e) { + console.error("转换文本时出错:", e); + sendResponse({result: "错误: 转换失败"}); + } + }); + return true; // 保持消息通道开放以进行异步响应 + } + + // 对于未处理的消息,直接返回false + return false; +}); \ No newline at end of file diff --git a/src/utils.js b/src/utils.js index c16fe99..23335a5 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,10 +1,11 @@ /** * 时间戳转字符串 - * @param timestamp 10/13 位时间戳 - * @param type 转换类型 + * @param {number} timestamp - 10/13 位时间戳 + * @param {string} type - 转换类型 * @returns {string} 可视化时间字符串 */ function getTimeString(timestamp, type) { + // 根据类型调整时间戳 switch (type) { case "1": timestamp *= 1000; @@ -19,79 +20,92 @@ function getTimeString(timestamp, type) { break; } + const date = new Date(timestamp); + const year = date.getFullYear(); + const month = date.getMonth() + 1; + const day = date.getDate(); + const hours = date.getHours(); + const minutes = date.getMinutes(); + const seconds = date.getSeconds(); + const milliseconds = date.getMilliseconds(); - let date = new Date(timestamp); - let year = date.getFullYear(); - let month = date.getMonth() + 1; - let day = date.getDate(); - let hours = date.getHours(); - let minutes = date.getMinutes(); - let seconds = date.getSeconds(); - let milliseconds = date.getMilliseconds(); + return formatDate(year, month, day, hours, minutes, seconds, milliseconds); +} - minutes = minutes < 10 ? "0" + minutes : minutes; - seconds = seconds < 10 ? "0" + seconds : seconds; - milliseconds = milliseconds < 100 ? milliseconds < 10 ? "00" + milliseconds : "0" + milliseconds : milliseconds; +/** + * 格式化日期和时间 + * @param {number} year - 年 + * @param {number} month - 月 + * @param {number} day - 日 + * @param {number} hours - 时 + * @param {number} minutes - 分 + * @param {number} seconds - 秒 + * @param {number} milliseconds - 毫秒 + * @returns {string} 格式化后的日期时间字符串 + */ +function formatDate(year, month, day, hours, minutes, seconds, milliseconds) { + const formattedMinutes = minutes < 10 ? `0${minutes}` : minutes; + const formattedSeconds = seconds < 10 ? `0${seconds}` : seconds; + const formattedMilliseconds = milliseconds < 100 ? + (milliseconds < 10 ? `00${milliseconds}` : `0${milliseconds}`) : + milliseconds; - return year + "年" + month + "月" + day + "日 " + hours + ":" + minutes + ":" + seconds + "." + milliseconds; + return `${year}年${month}月${day}日 ${hours}:${formattedMinutes}:${formattedSeconds}.${formattedMilliseconds}`; } /** * 字符串转 13 位时间戳 - * @param s 字符串 + * @param {string} s - 字符串 * @returns {number} 13 位时间戳 */ function formatTimeString(s) { - // 替换非数字为 - let value = s.replace(/[^\d]/g, "-").replace(/-+/g, "-"); - let res = ""; - // 以 - 分隔 - let split = value.split("-"); - // 组装字符串为 xx/xx/xx xx:xx:xx.xxx - for (let i = 0; i < split.length; i++) { - let item = split[i]; + + if (value.startsWith("-")) { + value = value.substring(1); + } + if (value.endsWith("-")) { + value = value.slice(0, -1); + } + + let result = ""; + const parts = value.split("-"); + for (let i = 0; i < parts.length; i++) { + const part = parts[i]; if (i === 0) { - // 第 1 位: 年 - res += item; + result += part; // 年 } else if (i <= 2) { - // 2-3 位: 月日 - res += "/" + item; + result += `/${part}`; // 月日 } else if (i === 3) { - // 第 4 位: 时 - res += " " + item; + result += ` ${part}`; // 时 } else if (i <= 5) { - // 5-6 位: 分秒 - res += ":" + item; + result += `:${part}`; // 分秒 } else if (i === 6) { - // 第 7 位: 毫秒 - res += "." + item; + result += `.${part}`; // 毫秒 } } - // 如果最后一位为小数点,那么应该是没有输入毫秒,去掉小数点 - if (res.endsWith(".")) { - res = res.slice(0, value.length - 1); + if (result.endsWith(".")) { + result = result.slice(0, -1); } - let date = new Date(res); + + const date = new Date(result); return date.getTime(); } /** * 转换数字时间戳或者字符串 - * @param s 输入 - * @param type 转换类型 + * @param {string|number} s - 输入 + * @param {string} type - 转换类型 * @returns {string|number} 字符串或者数字时间戳 */ function convert(s, type) { - if (s == null) { - return ""; - } - if (s === "") { + if (s == null || s === "") { return ""; } if (s.indexOf(".") === -1 && !isNaN(s)) { - return getTimeString(parseInt(s), type); + return getTimeString(parseInt(s, 10), type); } else { return formatTimeString(s); }