From 153acf5a9df5ab037cca05bae2e552fbf4e5482a Mon Sep 17 00:00:00 2001 From: LEO D PEN Date: Wed, 2 Jun 2021 18:14:50 +0800 Subject: [PATCH] Feature/move complete (#5) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat:move(a lot works to do) * feat: 默认禁用new tab. * feat: move forward. * feat: delete search-in-new-tab * fix * todo:still need fix(especially close current tab) * fix:still alot to do. * fix * docs: update README; --- README.md | 31 ++-- background.js | 349 ++++++++++++++++++++++++++++++++++++---------- background_old.js | 110 +++++++++++++++ manifest.json | 23 ++- 4 files changed, 415 insertions(+), 98 deletions(-) create mode 100644 background_old.js diff --git a/README.md b/README.md index 75c0e1a..00ebf88 100644 --- a/README.md +++ b/README.md @@ -11,18 +11,17 @@ Search for tabs in the opened window, can also increase your speed of switching tabs. - + ## About -学习及工作中常常遇到浏览器里面打开的tab页过多,窗口也多,总感觉或确定之前打开过某个tab页,但是不知道它在哪里了,于是有时不得不重新开一个tab页,“雪球越滚越大”。 +1. 学习及工作中常常遇到浏览器里面打开的tab页过多,窗口也多,总感觉或确定之前打开过某个tab页,但是不知道它在哪里了,于是有时不得不重新开一个tab页,“雪球越滚越大”。本插件提供关键词查找功能,点击结果即可跳转到相应tab页; +2. 你还记得窗口中上一个聚焦的tab页是什么吗?本插件提供tab回退与前进功能,帮助大家在浏览器中来回穿梭,速度起飞; -本插件提供关键词查找功能,点击结果即可跳转到相应tab页;此外,还提供tab回退,助力大家使用浏览器的速度起飞;(当前已开业完全脱离鼠标使用本插件!) - -目标是解放鼠标! +3. 解放鼠标!(够熟练就行了!) ## Getting Plug-in @@ -30,7 +29,7 @@ Search for tabs in the opened window, can also increase your speed of switching g2mGP1.jpg -2. [Release](https://github.com/LEODPEN/Where-is-my-tab/releases/tag/1.2)中最新包下载并解压后,添加到本地Chrome,其他操作相同; +2. [Release](https://github.com/LEODPEN/Where-is-my-tab/releases/tag/V1.5)中最新包下载并解压后,添加到本地Chrome,其他操作相同; g2mY26.jpg @@ -42,30 +41,38 @@ Search for tabs in the opened window, can also increase your speed of switching + 根据搜索结果跳转对应tab页; -+ 分窗口tab页回退(一个窗口最多支持10次回退); ++ 分窗口tab页回退(20次左右); + ++ 分窗口tab页前进(20次左右); ## Usage + 搜索与跳转 + 搜索 1. 可选择点击浏览器右上角插件图标,按照关键词搜索tab页; - 2. 可选择键盘操作(`Command+Shift+9`),打开扩展工具(tab键可键入,回车可直接搜索,上下键可选中); - 3. 可选择键盘操作(`Command+Shift+0`),新开tab页操作; + 2. 可选择键盘操作(`Command+Shift+7`),打开扩展工具(tab键可键入,回车可直接搜索,上下键可选中); + 3. ~~可选择键盘操作(`Command+Shift+0`),新开tab页操作【在1.6版本不再自动启用,请于快捷键自己设置】;~~ + 跳转 - 点击对应标题文字,即可跳转到已打开、需去往的tab页(如果采取3方式搜索,你可以选择`Command+9`来到新建搜索页,然后`Command+W`来关闭,毕竟目的是搜索不是开更多tab页,**强烈建议使用2操作**) + 1. 点击对应搜索结果,即可跳转到已打开、需去往的tab页; + 2. 默认选中第一个搜索结果,直接回车可去往; + 3. 上下方向键选择要去往项,回车可去往; > 注意:不同窗口下搜索与跳转只会在当前窗口进行; + 回退 - 每一个窗口都会维护固定大小的回退栈,使用`Command+Shift+7`以回退tab页。再配合上Chrome的`Command+数字`以及`Command+Option+左右方向键`,相信每个人都能在tab页中**穿梭自如**,基本摆脱鼠标的桎梏! + + 使用`Command+Shift+9`以回退tab页; + + 使用`Command+Shift+0`以前进tab页; + + 再配合上Chrome的`Command+数字`以及`Command+Option+左右方向键`,相信每个人都能在tab页中**穿梭自如**,基本摆脱鼠标的桎梏! -> 注意:一个窗口只支持10个回退,多于10次则会丢弃更早的记录; +> 注意:一个窗口只支持20次左右的当前记录,更多时会丢弃更早时候的记录;此外,为了不增加tab页,回退或前进时遇到已关闭tab页将会跳过。 ## Others + Windows下将(Command键替换为Ctrl即可); ++ 可以在"管理扩展程序 -> 键盘快捷键中"自定义你的快捷键; + + **不涉及任何隐私收集**,无外部依赖,离线可用; + 前端菜鸟,代码垃圾请轻喷,此处强烈感谢[@TimGin117](https://github.com/TimGin117)对代码中各种前端问题的解答与帮助! diff --git a/background.js b/background.js index a994549..141edf6 100644 --- a/background.js +++ b/background.js @@ -1,109 +1,316 @@ /** * @author https://github.com/LEODPEN - * date: 2021/05 + * date: 2021/05/26 + * @description new version using linked list. */ - class fixedSizeStack { - - constructor(sz) { - this.len = sz; - this.data = []; - this.curSize = 0; + class PNode { + windowId;tabId;next;pre; + constructor(windowId, tabId) { + this.windowId = windowId; + this.tabId = tabId; + this.next = null; + this.pre = null; } + } - empty() { - return this.curSize <= 0; + class LinkedList { + head;tail;windowId;cur; + constructor(windowId) { + this.windowId = windowId; + this.head = new PNode(-1, -1); + this.tail = new PNode(-1, -1); + this.head.next = this.tail; + this.tail.pre = this.head; + this.cur = this.head; } - full() { - return this.curSize >= this.len; + empty() { + return this.head.next == this.tail; } clear() { - delete this.data; - this.data = []; - this.curSize = 0; + this.head.next = this.tail; + this.tail.pre = this.head; + this.cur = this.head; } - push(e) { - if (this.full()) { - this.data.shift(); - this.curSize--; + deleteOne(node) { + if (!node || node == this.head || node == this.tail) { + return; } - var newCurLen = this.data.push(e); - this.curSize = newCurLen >= this.len ? this.len : newCurLen; + var p = node.pre; + var n = node.next; + p.next = n; + n.pre = p; + node.pre = null; + node.next = null; + node = null; } - - pop() { - if (this.empty()) { + + /** + * @param threshold > 10 + */ + deleteSomeWhenSizeLargerThan(threshold) { + var sz = 0, randomNum = Math.round(Math.random()*(threshold/2)); + randomNum = randomNum >= 2 ? randomNum : 2; + var node = this.head; + var randomNode = null; + while (node.next != this.tail) { + node = node.next; + sz++; + if (sz == randomNum) { + randomNode = node; + } + } + if (sz > threshold) { + var nodeAfterHead = this.head.next; + nodeAfterHead.pre = null; + + this.head.next = randomNode; + randomNode.pre = this.head; + } + } + + /** + * @param e 待插入element(new) + */ + add(e) { + if (!e) { return; } - var res = this.data.pop(); // 最后一个 - this.curSize = this.curSize <= 0 ? 0 : --this.curSize; - return res; + + if (!this.empty()) { + var nodeBeforeTail = this.tail.pre; + var nodeAfterCur = this.cur.next; + + nodeBeforeTail.next = null; + nodeAfterCur.pre = null; + } + + this.cur.next = e; + e.pre = this.cur; + e.next = this.tail; + this.tail.pre = e; + + this.cur = this.cur.next; // 即为e + + // 保证检测概率更大 + if (Math.random() <= 0.5) { + this.deleteSomeWhenSizeLargerThan(20); + } + } + + /** + * 如果返回为null,则说明cur未变,不跳转 + * @returns + */ + loadBackard(ifDelete) { + if (this.empty()) return null; + var r = this.cur; + var l = this.cur.pre; + // while (l != this.head && + // (! (judgeExistence(l.windowId, l.tabId)) + // || (l.windowId == l.pre.windowId + // && l.tabId == l.pre.tabId))) { + // l = l.pre; + // } + while (l != this.head && l.tabId == l.pre.tabId) { + l.pre = l.pre.pre; + l.pre.next = l; + l = l.pre; + } + if (l != r.pre) { + l.next = r; + r.pre = l; + } + if (ifDelete == true) { + this.deleteOne(r); + } + if (l == this.head) { + if (r.next == null || r.pre == null) { + this.cur = l; + } + return null; + } else { + this.cur = l; + return this.cur; + } + } + + /** + * 如果返回为null,则说明cur未变,不跳转 + * @returns + */ + loadForward(ifDelete) { + if (this.empty()) return null; + var l = this.cur; + var r = this.cur.next; + // while(r != this.tail && + // (! (judgeExistence(r.windowId, r.tabId)) + // || (r.windowId == r.next.windowId + // && r.tabId == r.next.tabId))) { + // r = r.next; + // } + while (r != this.tail && r.tabId == r.next.tabId) { + r.next = r.next.next; + r.next.pre = r; + l = l.pre; + } + if (r != l.next) { + l.next = r; + r.pre = l; + } + if(ifDelete == true) { + this.deleteOne(l); + } + if (r == this.tail) { + if (l.next == null || l.pre == null) { + this.cur = r.pre; + } + return null; + } else { + this.cur = r; + return this.cur; + } } } -function doBackWard(stack, curWin) { - if (stack.empty()) return; - chrome.tabs.getCurrent(function(curTab) { - // check again - var back; - while((back = stack.pop()).tabId == curTab - && back.windowId == curWIn); - if (back.windowId != curWin) return; - chrome.tabs.update(back.tabId, {active: true}); + + +async function judgeExistence(windowId, tabId) { + var res = false; + await chrome.tabs.get(tabId) + .then((result) => { + if (chrome.runtime.lastError) { + console.log(chrome.runtime.lastError.message); + res = false; + } else { + // console.log("all things ok"); + res = true; + }}) + .catch((error) => { + console.log(error); + res = false; + }); + return res; +} + +function doBackward(lk, ifDelete) { + var back; + if (!lk || !(back = lk.loadBackard(ifDelete)) || back.windowId != lk.windowId) { + return; + } + chrome.tabs.update(back.tabId, {active: true}, function(res) { + if (chrome.runtime.lastError) { + console.log(chrome.runtime.lastError.message); + doBackward(lk, true); + } + }); +} + +function doForward(lk, ifDelete) { + var forw; + if (!lk || !(forw = lk.loadForward(ifDelete)) || forw.windowId != lk.windowId) { + return; + } + chrome.tabs.update(forw.tabId, {active: true}, function(res) { + if (chrome.runtime.lastError) { + console.log(chrome.runtime.lastError.message); + doForward(lk, true); + } }); } try{ - var latestTabMap = new Map(); - let url = chrome.runtime.getURL("srch-res.html"); - var stackMap = new Map(); + var map = new Map(); + chrome.storage.local.get("MAP", function(data) { + if (chrome.runtime.lastError || !data) { + map = new Map(); + } else { + map = new Map(); + var ols = new Map(Object.entries(data.MAP)); + for (var [key, value] of ols) { + var h = value.head, t = value.tail, c = value.cur; + var lk = new LinkedList(parseInt(key)); + var cur; + var pnode; + while(h.next != null) { + h = h.next; + if (h.windowId != -1 && h.tabId != -1) { + pnode = new PNode(h.windowId, h.tabId); + if (h == c || (h.windowId == c.windowId && h.tabId == c.tabId)) { + console.log(pnode); + cur = pnode; + } + lk.add(pnode); + } + } + if (cur) { + lk.cur = cur; + } + map.set(parseInt(key), lk); + } + } + }); chrome.commands.onCommand.addListener(function (command) { - if (command === 'do-search-in-new-tab') { - chrome.tabs.create({ url }); - } - if (command === 'backward') { + if (command === 'backward') { chrome.windows.getCurrent(function(cw) { - var stack; var curWin = cw.id; - if (stackMap.has(curWin)) { - stack = stackMap.get(curWin); + var lk; + if (!map.has(curWin)) { + // 初始时刻 + return; } else { - stack = new fixedSizeStack(10); - stackMap.set(curWin, stack); + lk = map.get(curWin); } - if (!stack.empty() && latestTabMap.get(curWin)) { - latestTabMap.set(curWin, null); + doBackward(lk, false); + chrome.storage.local.set({"MAP": Object.fromEntries(map)}); + }); + } + if (command === 'forward') { + chrome.windows.getCurrent(function(cw) { + var curWin = cw.id; + var lk; + if (!map.has(curWin)) { + // 初始时刻 + return; + } else { + lk = map.get(curWin); } - doBackWard(stack, curWin); + doForward(lk, false); + chrome.storage.local.set({"MAP": Object.fromEntries(map)}); }); - if (command === 'forward') { - } } - }); + }); chrome.tabs.onActivated.addListener(function(activeInfo) { - chrome.windows.getCurrent(function(cw){ - - var curWin = cw.id; - var stack; - var latestTab; - if (stackMap.has(curWin)) { - stack = stackMap.get(curWin); - } else { - stack = new fixedSizeStack(10); - stackMap.set(curWin, stack); + var windowId = activeInfo.windowId; + var tabId = activeInfo.tabId; + var lk; + + if (map.has(windowId)) { + lk = map.get(windowId); + if (!lk || lk.windowId != windowId) { + lk.clear(); + lk = new LinkedList(windowId); + map.set(windowId, lk); } - if ((latestTab = latestTabMap.get(curWin))) { - stack.push(latestTab); - } - latestTabMap.set(curWin, activeInfo); - }); + } else { + lk = new LinkedList(windowId); + map.set(windowId, lk); + } + if (lk.cur.windowId == windowId && lk.cur.tabId == tabId) { + return; + } else { + var curNode = new PNode(windowId, tabId); + lk.add(curNode); + chrome.storage.local.set({"MAP": Object.fromEntries(map)}); + } }); + } catch(e) { - // If tab was closed then just jump it. + map.clear(); + chrome.storage.local.set({"MAP": null}); console.error(e); -} - +} \ No newline at end of file diff --git a/background_old.js b/background_old.js new file mode 100644 index 0000000..9eaab6f --- /dev/null +++ b/background_old.js @@ -0,0 +1,110 @@ +/** + * @author https://github.com/LEODPEN + * date: 2021/05/ + * @description This is the old version which only provided "backward" feature. + */ + + class fixedSizeStack { + + constructor(sz) { + this.len = sz; + this.data = []; + this.curSize = 0; + } + + empty() { + return this.curSize <= 0; + } + + full() { + return this.curSize >= this.len; + } + + clear() { + delete this.data; + this.data = []; + this.curSize = 0; + } + + push(e) { + if (this.full()) { + this.data.shift(); + this.curSize--; + } + var newCurLen = this.data.push(e); + this.curSize = newCurLen >= this.len ? this.len : newCurLen; + } + + pop() { + if (this.empty()) { + return; + } + var res = this.data.pop(); // 最后一个 + this.curSize = this.curSize <= 0 ? 0 : --this.curSize; + return res; + } +} + +function doBackWard(stack, curWin) { + if (stack.empty()) return; + chrome.tabs.getCurrent(function(curTab) { + // check again + var back; + while((back = stack.pop()).tabId == curTab + && back.windowId == curWIn); + if (back.windowId != curWin) return; + chrome.tabs.update(back.tabId, {active: true}); + }); +} + +try{ + var latestTabMap = new Map(); + let url = chrome.runtime.getURL("srch-res.html"); + var stackMap = new Map(); + chrome.commands.onCommand.addListener(function (command) { + if (command === 'do-search-in-new-tab') { + chrome.tabs.create({ url }); + } + if (command === 'backward') { + chrome.windows.getCurrent(function(cw) { + var stack; + var curWin = cw.id; + if (stackMap.has(curWin)) { + stack = stackMap.get(curWin); + } else { + stack = new fixedSizeStack(10); + stackMap.set(curWin, stack); + } + if (!stack.empty() && latestTabMap.get(curWin)) { + latestTabMap.set(curWin, null); + } + doBackWard(stack, curWin); + }); + if (command === 'forward') { + } + } + }); + chrome.tabs.onActivated.addListener(function(activeInfo) { + + chrome.windows.getCurrent(function(cw){ + + var curWin = cw.id; + var stack; + var latestTab; + if (stackMap.has(curWin)) { + stack = stackMap.get(curWin); + } else { + stack = new fixedSizeStack(10); + stackMap.set(curWin, stack); + } + if ((latestTab = latestTabMap.get(curWin))) { + stack.push(latestTab); + } + latestTabMap.set(curWin, activeInfo); + }); + }); +} catch(e) { + // If tab was closed then just jump it. + console.error(e); +} + diff --git a/manifest.json b/manifest.json index 3d80846..9595573 100644 --- a/manifest.json +++ b/manifest.json @@ -1,11 +1,11 @@ { "name": "Where is my tab ?", "description": "Search for tabs in the opened window, can also increase your speed of switching tabs.", - "version": "1.5", + "version": "1.6", "manifest_version": 3, "update_url": "http://clients2.google.com/service/update2/crx", "permissions": [ - "tabs","commands","windows" + "tabs","commands","windows","storage" ], "background": { "service_worker": "background.js" @@ -17,31 +17,24 @@ "commands": { "_execute_action": { "suggested_key": { - "default": "Ctrl+Shift+9", - "windows": "Ctrl+Shift+9", - "mac": "Command+Shift+9" + "default": "Ctrl+Shift+7", + "windows": "Ctrl+Shift+7", + "mac": "Command+Shift+7" } }, "backward": { "suggested_key": { - "default": "Ctrl+Shift+7", - "mac": "Command+Shift+7" + "default": "Ctrl+Shift+9", + "mac": "Command+Shift+9" }, "description": "backward" }, "forward": { - "suggested_key": { - "default": "Ctrl+Shift+8", - "mac": "Command+Shift+8" - }, - "description": "forward" - }, - "do-search-in-new-tab": { "suggested_key": { "default": "Ctrl+Shift+0", "mac": "Command+Shift+0" }, - "description": "doSearchInNewTab" + "description": "forward" } } } \ No newline at end of file