From 982942c780d46908484c9906e6d74ca3628ceb8d Mon Sep 17 00:00:00 2001 From: brook hong Date: Sun, 3 Nov 2019 00:06:27 +0800 Subject: [PATCH] 0.9.53 Performance improvement: create components for frames only when it is necessary. --- background.js | 2 +- content_scripts/clipboard.js | 4 +- content_scripts/content_scripts.css | 5 +- content_scripts/content_scripts.js | 157 +++++++++++++++++++- content_scripts/front.js | 82 +---------- content_scripts/hints.js | 4 +- content_scripts/insert.js | 4 +- content_scripts/keyboardUtils.js | 4 +- content_scripts/normal.js | 39 +++-- content_scripts/runtime.js | 2 +- content_scripts/{top.js => uiframe.js} | 70 +-------- content_scripts/utils.js | 6 +- content_scripts/visual.js | 4 +- gulpfile.js | 22 +-- libs/trie.js | 193 ++++++++++++------------- manifest.json | 9 +- pages/default.js | 4 +- pages/error.html | 5 +- pages/front.js | 20 +-- pages/frontend.html | 2 +- pages/markdown.html | 5 +- pages/mermaid.html | 5 +- pages/options.html | 5 +- pages/pdf_viewer.html | 8 +- pages/popup.html | 2 +- pages/start.html | 5 +- pages/start.js | 2 +- 27 files changed, 336 insertions(+), 334 deletions(-) rename content_scripts/{top.js => uiframe.js} (64%) diff --git a/background.js b/background.js index 8fa6d98ef..6f422547d 100644 --- a/background.js +++ b/background.js @@ -1112,7 +1112,7 @@ var ChromeService = (function() { var tid = sender.tab.id; chrome.tabs.executeScript(tid, { allFrames: true, - code: "Front && Front.getFrameId && Front.getFrameId()" + code: "typeof(getFrameId) === 'function' && getFrameId()" }, function(framesInTab) { framesInTab = framesInTab.filter(function(frameId) { return frameId; diff --git a/content_scripts/clipboard.js b/content_scripts/clipboard.js index 33944715e..3b0516d08 100644 --- a/content_scripts/clipboard.js +++ b/content_scripts/clipboard.js @@ -1,4 +1,4 @@ -var Clipboard = (function(mode) { +function createClipboard() { var self = {}; var holder = document.createElement('textarea'); @@ -43,4 +43,4 @@ var Clipboard = (function(mode) { return self; -})(); +} diff --git a/content_scripts/content_scripts.css b/content_scripts/content_scripts.css index 22c34ba8d..a9de6514b 100644 --- a/content_scripts/content_scripts.css +++ b/content_scripts/content_scripts.css @@ -72,9 +72,8 @@ div.surfingkeys_cursor:empty { } #sk_frame { position: fixed; - border: 4px solid #3CF30F; + border: 4px solid #434343; box-sizing: border-box; z-index: 2147483000; - background: rgba(129, 120, 222, 0.62); - box-shadow: 0px 0px 10px rgba(218, 60, 13, 0.8); + background: rgba(202, 202, 202, 0.62); } diff --git a/content_scripts/content_scripts.js b/content_scripts/content_scripts.js index 9f6dd90bd..752f3558c 100644 --- a/content_scripts/content_scripts.js +++ b/content_scripts/content_scripts.js @@ -323,7 +323,7 @@ function applySettings(rs) { if ('findHistory' in rs) { runtime.conf.lastQuery = rs.findHistory.length ? rs.findHistory[0] : ""; } - if ('snippets' in rs && rs.snippets && !Front.isProvider()) { + if ('snippets' in rs && rs.snippets && !isInUIFrame()) { var delta = runScript(rs.snippets); if (delta.error !== "") { if (window === top) { @@ -360,7 +360,65 @@ function applySettings(rs) { } } -runtime.on('settingsUpdated', function(response) { +function _initModules() { + window.KeyboardUtils = createKeyboardUtils(); + window.Mode = createMode(); + window.Normal = createNormal(); + Normal.enter(); + window.Disabled = createDisabled(); + window.PassThrough = createPassThrough(); + window.Insert = createInsert(); + window.Visual = createVisual(); + window.Hints = createHints(); + window.Clipboard = createClipboard(); + window.Front = createFront(); + createDefaultMappings(); +} + +function _initObserver() { + var pendingUpdater = undefined; + new MutationObserver(function (mutations) { + var addedNodes = []; + for (var m of mutations) { + for (var n of m.addedNodes) { + if (n.nodeType === Node.ELEMENT_NODE && !n.fromSurfingKeys) { + n.newlyCreated = true; + addedNodes.push(n); + } + } + } + + if (addedNodes.length) { + if (pendingUpdater) { + clearTimeout(pendingUpdater); + pendingUpdater = undefined; + } + pendingUpdater = setTimeout(function() { + var possibleModalElements = getVisibleElements(function(e, v) { + var br = e.getBoundingClientRect(); + if (br.width > 300 && br.height > 300 + && br.width <= window.innerWidth && br.height <= window.innerHeight + && br.top >= 0 && br.left >= 0 + ) { + var originalTop = document.scrollingElement.scrollTop; + document.scrollingElement.scrollTop += 1; + var br1 = e.getBoundingClientRect(); + if (br.top === br1.top && hasScroll(e, 'y', 16)) { + v.push(e); + } + document.scrollingElement.scrollTop = originalTop; + } + }); + + if (possibleModalElements.length) { + Normal.addScrollableElement(possibleModalElements[0]); + } + }, 200); + } + }).observe(document.body, { childList: true, subtree:true });; +} + +function _onSettingsUpdated(response) { var rs = response.settings; applySettings(rs); if (rs.hasOwnProperty('blacklist') || runtime.conf.blacklistPattern) { @@ -384,9 +442,12 @@ runtime.on('settingsUpdated', function(response) { } }); } -}); +} -function _init() { +function _initContent() { + _initObserver(); + window.frameId = generateQuickGuid(); + runtime.on('settingsUpdated', _onSettingsUpdated); runtime.command({ action: 'getSettings' }, function(response) { @@ -394,7 +455,10 @@ function _init() { applySettings(rs); - Normal.enter(); + if (runtime.conf.stealFocusOnLoad && !isInUIFrame()) { + var elm = getRealEdit(); + elm && elm.blur(); + } runtime.command({ action: 'getDisabled', @@ -427,6 +491,83 @@ function _init() { }); } -document.addEventListener("surfingkeys:defaultSettingsLoaded", function (evt) { - _init(); -}); +function getFrameId() { + if (!window.frameId && window.innerWidth > 16 && window.innerHeight > 16 + && runtime.conf.ignoredFrameHosts.indexOf(window.origin) === -1 + && (!window.frameElement || parseInt("0" + getComputedStyle(window.frameElement).zIndex) >= 0) + ) { + _initModules(); + _initContent(); + } + return window.frameId; +} + +if (window === top) { + _initModules(); + + document.addEventListener('DOMContentLoaded', function (e) { + _initContent(); + if (document.contentType === "application/pdf") { + // Appending child to document will break default pdf viewer from rendering. + // So we append child after default pdf viewer rendered. + document.body.querySelector("EMBED").addEventListener("load", function(evt) { + setTimeout(function() { + document.documentElement.appendChild(createUiHost()); + }, 10); + }); + } else { + document.documentElement.appendChild(createUiHost()); + } + window._setScrollPos = function (x, y) { + document.scrollingElement.scrollLeft = x; + document.scrollingElement.scrollTop = y; + }; + + runtime.command({ + action: 'tabURLAccessed', + title: document.title, + url: window.location.href + }, function (resp) { + if (resp.index > 0) { + var showTabIndexInTitle = function () { + skipObserver = true; + document.title = myTabIndex + " " + originalTitle; + }; + + var myTabIndex = resp.index, + skipObserver = false, + originalTitle = document.title; + + new MutationObserver(function (mutationsList) { + if (skipObserver) { + skipObserver = false; + } else { + originalTitle = document.title; + showTabIndexInTitle(); + } + }).observe(document.querySelector("title"), { childList: true });; + + showTabIndexInTitle(); + + runtime.runtime_handlers['tabIndexChange'] = function(msg, sender, response) { + if (msg.index !== myTabIndex) { + myTabIndex = msg.index; + showTabIndexInTitle(); + } + }; + } + }); + + setTimeout(function () { + // to avoid conflict with pdf extension: chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/ + for (var p in AutoCommands) { + var c = AutoCommands[p]; + if (c.regex.test(window.location.href)) { + c.code(); + } + } + }, 0); + + // There is some site firing DOMContentLoaded twice, such as http://www.423down.com/ + }, {once: true}); +} diff --git a/content_scripts/front.js b/content_scripts/front.js index bb4385cf4..4f6cdbbcf 100644 --- a/content_scripts/front.js +++ b/content_scripts/front.js @@ -1,14 +1,9 @@ -var Front = (function() { +function createFront() { var self = {}; // The agent is a front stub to talk with pages/frontend.html // that will live in all content window except the frontend.html // as there is no need to make this object live in frontend.html. - // this object is stub of UI, it's UI consumer - self.isProvider = function() { - return document.location.href.indexOf(chrome.extension.getURL("")) === 0; - }; - var frontendPromise = new Promise(function (resolve, reject) { if (window === top) { self.resolve = resolve; @@ -252,7 +247,7 @@ var Front = (function() { }, function(res) { showQueryResult(_inlineQuery.parseResult(res)); }); - } else if (Front.isProvider()) { + } else if (isInUIFrame()) { _showQueryResult = showQueryResult; document.getElementById("proxyFrame").contentWindow.postMessage({ action: "performInlineQuery", @@ -361,16 +356,6 @@ var Front = (function() { }); }; - self.getFrameId = function () { - if (document.body.offsetWidth > 16 && document.body.offsetHeight > 16 && document.body.innerText - && (!window.frameElement || getComputedStyle(window.frameElement).zIndex >= 0) - && runtime.conf.ignoredFrameHosts.indexOf(window.origin) === -1 - && !window.frameId) { - window.frameId = generateQuickGuid(); - } - return window.frameId; - }; - _actions["ace_editor_saved"] = function(response) { if (response.data !== undefined) { onEditorSaved(response.data); @@ -429,7 +414,7 @@ var Front = (function() { _actions["getBackFocus"] = function(response) { window.focus(); - if (window === top && document.activeElement === ifr[0]) { + if (window === top && document.activeElement === window.uiFrame) { // fix for Firefox, blur from iframe for frontend after Omnibar closed. document.activeElement.blur(); } @@ -490,69 +475,18 @@ var Front = (function() { block: 'center', inline: 'center' }); - var rc = document.body.getBoundingClientRect(); self.highlightElement({ duration: 500, rect: { - top: rc.top, - left: rc.left, - width: rc.width, - height: rc.height + top: 0, + left: 0, + width: window.innerWidth, + height: window.innerHeight } }); - - Normal.exit(); - Normal.enter(); } }; - document.addEventListener('DOMContentLoaded', function (e) { - if (window.location.href.indexOf(chrome.extension.getURL("/pages/pdf_viewer.html")) === 0) { - document.getElementById("proxyFrame").src = window.location.search.substr(3); - } - - var pendingUpdater = undefined; - new MutationObserver(function (mutations) { - var addedNodes = []; - for (var m of mutations) { - for (var n of m.addedNodes) { - if (n.nodeType === Node.ELEMENT_NODE && !n.fromSurfingKeys) { - n.newlyCreated = true; - addedNodes.push(n); - } - } - } - - if (addedNodes.length) { - if (pendingUpdater) { - clearTimeout(pendingUpdater); - pendingUpdater = undefined; - } - pendingUpdater = setTimeout(function() { - var possibleModalElements = getVisibleElements(function(e, v) { - var br = e.getBoundingClientRect(); - if (br.width > 300 && br.height > 300 - && br.width <= window.innerWidth && br.height <= window.innerHeight - && br.top >= 0 && br.left >= 0 - ) { - var originalTop = document.scrollingElement.scrollTop; - document.scrollingElement.scrollTop += 1; - var br1 = e.getBoundingClientRect(); - if (br.top === br1.top && hasScroll(e, 'y', 16)) { - v.push(e); - } - document.scrollingElement.scrollTop = originalTop; - } - }); - - if (possibleModalElements.length) { - Normal.addScrollableElement(possibleModalElements[0]); - } - }, 200); - } - }).observe(document.body, { childList: true, subtree:true });; - }); - window.addEventListener('message', function (event) { var _message = event.data; if (_message.action === "performInlineQuery") { @@ -588,4 +522,4 @@ var Front = (function() { }, true); return self; -})(); +} diff --git a/content_scripts/hints.js b/content_scripts/hints.js index abbd1ad8a..c04d5ada0 100644 --- a/content_scripts/hints.js +++ b/content_scripts/hints.js @@ -1,4 +1,4 @@ -var Hints = (function() { +function createHints() { var self = new Mode("Hints"); self.addEventListener('keydown', function(event) { @@ -630,4 +630,4 @@ var Hints = (function() { }; return self; -})(); +} diff --git a/content_scripts/insert.js b/content_scripts/insert.js index 02570c74d..362e5dbd4 100644 --- a/content_scripts/insert.js +++ b/content_scripts/insert.js @@ -1,4 +1,4 @@ -var Insert = (function() { +function createInsert() { var self = new Mode("Insert"); function moveCusorEOL() { @@ -420,4 +420,4 @@ var Insert = (function() { }; return self; -})(); +} diff --git a/content_scripts/keyboardUtils.js b/content_scripts/keyboardUtils.js index 198ebc54e..27de976da 100644 --- a/content_scripts/keyboardUtils.js +++ b/content_scripts/keyboardUtils.js @@ -1,4 +1,4 @@ -var KeyboardUtils = (function() { +function createKeyboardUtils() { var self = { keyCodesMac: { Minus: ["-", "_"], @@ -226,7 +226,7 @@ var KeyboardUtils = (function() { }; return self; -})(); +} /* diff --git a/content_scripts/normal.js b/content_scripts/normal.js index 57e0ff91b..458e1ac26 100644 --- a/content_scripts/normal.js +++ b/content_scripts/normal.js @@ -1,4 +1,4 @@ -var Mode = (function() { +function createMode() { var self = function(name, statusLine) { this.name = name; this.statusLine = statusLine; @@ -191,7 +191,7 @@ var Mode = (function() { } } } - Front.showStatus(0, sl); + typeof(Front) === "object" && Front.showStatus(0, sl); } }; @@ -284,9 +284,9 @@ var Mode = (function() { }; return self; -})(); +} -var Disabled = (function() { +function createDisabled() { var self = new Mode("Disabled"); // Disabled has higher priority than others. @@ -303,9 +303,9 @@ var Disabled = (function() { }); return self; -})(); +} -var PassThrough = (function() { +function createPassThrough() { var self = new Mode("PassThrough"); var _autoExit, _timeout; @@ -344,9 +344,9 @@ var PassThrough = (function() { }; return self; -})(); +} -var Normal = (function() { +function createNormal() { var self = new Mode("Normal"); // let next focus event pass @@ -355,13 +355,6 @@ var Normal = (function() { _passFocus = pf; }; - self.onEnter = function() { - if (runtime.conf.stealFocusOnLoad && !Front.isProvider()) { - var elm = getRealEdit(); - elm && elm.blur(); - } - }; - self.addEventListener('keydown', function(event) { var realTarget = getRealEdit(event); if (isEditable(realTarget) && event.isTrusted) { @@ -416,7 +409,7 @@ var Normal = (function() { }); self.addEventListener('focus', function(event) { Mode.showStatus(); - if (runtime.conf.stealFocusOnLoad && !Front.isProvider()) { + if (runtime.conf.stealFocusOnLoad && !isInUIFrame()) { var elm = getRealEdit(event); if (isEditable(elm)) { if (_passFocus || elm.enableAutoFocus) { @@ -437,6 +430,10 @@ var Normal = (function() { }, 0); }); self.addEventListener('mousedown', function(event) { + // Insert mode will never be created in frontend frame. + if (typeof(Insert) === "undefined") { + return; + } // The isTrusted read-only property of the Event interface is a boolean // that is true when the event was generated by a user action, and false // when the event was created or modified by a script or dispatched via dispatchEvent. @@ -663,7 +660,8 @@ var Normal = (function() { scrollNode = scrollNodes[scrollIndex]; if (scrollNode !== document.scrollingElement) { var br = scrollNode.getBoundingClientRect(); - if (br.width === 0 || br.height === 0) { + if (br.width === 0 || br.height === 0 || !isElementPartiallyInViewport(scrollNode) + || !hasScroll(scrollNode, 'y', 16)) { scrollNodes.splice(scrollIndex, 1); scrollIndex = 0; scrollNode = scrollNodes[scrollIndex]; @@ -733,9 +731,8 @@ var Normal = (function() { }; self.addScrollableElement = function(elm) { - initScrollIndex(); - scrollIndex = scrollNodes.indexOf(elm); - if (scrollIndex === -1) { + if (!scrollNodes || !elm.contains(scrollNodes[scrollIndex]) && scrollNodes.indexOf(elm) === -1) { + initScrollIndex(); scrollNodes.push(elm); scrollIndex = scrollNodes.length - 1; } @@ -1140,4 +1137,4 @@ var Normal = (function() { }); return self; -})(); +} diff --git a/content_scripts/runtime.js b/content_scripts/runtime.js index 458104d26..917f6a432 100644 --- a/content_scripts/runtime.js +++ b/content_scripts/runtime.js @@ -1,4 +1,4 @@ -var runtime = window.runtime || (function() { +var runtime = (function() { var self = { conf: { lastKeys: "", diff --git a/content_scripts/top.js b/content_scripts/uiframe.js similarity index 64% rename from content_scripts/top.js rename to content_scripts/uiframe.js index 397fb339a..c9a354f47 100644 --- a/content_scripts/top.js +++ b/content_scripts/uiframe.js @@ -1,4 +1,4 @@ -if (window === top) { +function createUiHost() { var uiHost = document.createElement("div"); uiHost.style.display = "block"; uiHost.style.opacity = 1; @@ -81,7 +81,7 @@ if (window === top) { uiHost.blur(); ifr.blur(); // test with https://docs.google.com/ and https://web.whatsapp.com/ - if (lastStateOfPointerEvents !== response.pointerEvents) { + if (lastStateOfPointerEvents !== response.pointerEvents && activeContent) { activeContent.window.postMessage({ action: 'getBackFocus', commandToContent: true @@ -103,68 +103,6 @@ if (window === top) { lastStateOfPointerEvents = response.pointerEvents; }; - document.addEventListener('DOMContentLoaded', function (e) { - if (document.contentType === "application/pdf") { - // Appending child to document will break default pdf viewer from rendering. - // So we append child after default pdf viewer rendered. - document.body.querySelector("EMBED").addEventListener("load", function(evt) { - setTimeout(function() { - document.documentElement.appendChild(uiHost); - }, 10); - }); - } else { - document.documentElement.appendChild(uiHost); - } - - runtime.command({ - action: 'tabURLAccessed', - title: document.title, - url: window.location.href - }, function (resp) { - if (resp.index > 0) { - var showTabIndexInTitle = function () { - skipObserver = true; - document.title = myTabIndex + " " + originalTitle; - }; - - var myTabIndex = resp.index, - skipObserver = false, - originalTitle = document.title; - - new MutationObserver(function (mutationsList) { - if (skipObserver) { - skipObserver = false; - } else { - originalTitle = document.title; - showTabIndexInTitle(); - } - }).observe(document.querySelector("title"), { childList: true });; - - showTabIndexInTitle(); - - runtime.runtime_handlers['tabIndexChange'] = function(msg, sender, response) { - if (msg.index !== myTabIndex) { - myTabIndex = msg.index; - showTabIndexInTitle(); - } - }; - } - }); - - setTimeout(function () { - // to avoid conflict with pdf extension: chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/ - for (var p in AutoCommands) { - var c = AutoCommands[p]; - if (c.regex.test(window.location.href)) { - c.code(); - } - } - }, 0); - // There is some site firing DOMContentLoaded twice, such as http://www.423down.com/ - }, {once: true}); - - function _setScrollPos(x, y) { - document.scrollingElement.scrollLeft = x; - document.scrollingElement.scrollTop = y; - } + window.uiFrame = ifr; + return uiHost; } diff --git a/content_scripts/utils.js b/content_scripts/utils.js index ce898b0ea..412c4f943 100644 --- a/content_scripts/utils.js +++ b/content_scripts/utils.js @@ -1,3 +1,7 @@ +function isInUIFrame() { + return document.location.href.indexOf(chrome.extension.getURL("")) === 0; +} + function timeStampString(t) { var dt = new Date(); dt.setTime(t); @@ -351,7 +355,7 @@ function _map(mode, nks, oks) { // meta.word need to be new var meta = Object.assign({}, old_map.meta); mode.mappings.add(nks, meta); - if (!Front.isProvider()) { + if (!isInUIFrame()) { Front.addMapkey(mode.name, nks, oks); } } diff --git a/content_scripts/visual.js b/content_scripts/visual.js index e463365b1..1128108db 100644 --- a/content_scripts/visual.js +++ b/content_scripts/visual.js @@ -1,4 +1,4 @@ -var Visual = (function() { +function createVisual() { var self = new Mode("Visual"); self.addEventListener('keydown', function(event) { @@ -826,4 +826,4 @@ var Visual = (function() { mark_template.setAttribute('style', _style.marks || ''); }; return self; -})(); +} diff --git a/gulpfile.js b/gulpfile.js index e347d1e4c..6b20efc5a 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -68,7 +68,6 @@ gulp.task('copy-es-files', function() { return gulp.src([ 'content_scripts/front.js', 'content_scripts/content_scripts.js', - 'content_scripts/top.js', 'pages/*.js' ], {base: "."}) .pipe(gulpif(options.env === 'development', sourcemaps.init())) @@ -117,8 +116,8 @@ gulp.task('build_background', function() { .pipe(gulp.dest(`dist/${buildTarget}-extension`)); }); -gulp.task('build_common_content_min_without_lib', function() { - var common_content = [ +gulp.task('build_modules', function() { + var modules = [ "libs/trie.js", "content_scripts/keyboardUtils.js", "content_scripts/utils.js", @@ -128,28 +127,29 @@ gulp.task('build_common_content_min_without_lib', function() { "content_scripts/visual.js", "content_scripts/hints.js", "content_scripts/clipboard.js", + "content_scripts/uiframe.js" ]; if (buildTarget === "Firefox") { - common_content.push("content_scripts/firefox_fg.js"); + modules.push("content_scripts/firefox_fg.js"); } else { - common_content.push("content_scripts/chrome_fg.js"); + modules.push("content_scripts/chrome_fg.js"); } - return gulp.src(common_content) + return gulp.src(modules) .pipe(gulpif(options.env === 'development', sourcemaps.init())) - .pipe(gp_concat('common_content.min.js')) + .pipe(gp_concat('modules.min.js')) .pipe(babel({presets: ['es2015']})) .pipe(gulpif(!options.nominify, gp_uglify().on('error', gulpUtil.log))) .pipe(gulpif(options.env === 'development', sourcemaps.write('.'))) .pipe(gulp.dest(`dist/${buildTarget}-extension/content_scripts`)); }); -gulp.task('build_common_content_min', gulp.series('build_common_content_min_without_lib', function(cb) { +gulp.task('build_common_content_min', gulp.series('build_modules', function(cb) { if (buildTarget === "Firefox") { - return gulp.src([`dist/${buildTarget}-extension/content_scripts/common_content.min.js`,"libs/shadydom.min.js"]) - .pipe(gp_concat('common_content.min.js')) + return gulp.src([`dist/${buildTarget}-extension/content_scripts/modules.min.js`,"libs/shadydom.min.js"]) + .pipe(gp_concat('modules.min.js')) .pipe(gulp.dest(`dist/${buildTarget}-extension/content_scripts`)); } else { - return gulp.src([`dist/${buildTarget}-extension/content_scripts/common_content.min.js`]) + return gulp.src([`dist/${buildTarget}-extension/content_scripts/modules.min.js`]) .pipe(gulp.dest(`dist/${buildTarget}-extension/content_scripts`)); } })); diff --git a/libs/trie.js b/libs/trie.js index 981133f16..2f8003d30 100644 --- a/libs/trie.js +++ b/libs/trie.js @@ -1,117 +1,112 @@ /* -* A simple implementation of Trie by brook hong, for less memory usage and better performance. -* -* Each node has at most two properties, stem or meta. All other properties are expected to be -* one character, taken to be child of the node. -* -*/ -var Trie = (function() { - - function Trie() { - if (arguments.length > 0) { - this.stem = arguments[0]; - } - if (arguments.length > 1) { - this.meta = arguments[1]; - } + * A simple implementation of Trie by brook hong, for less memory usage and better performance. + * + * Each node has at most two properties, stem or meta. All other properties are expected to be + * one character, taken to be child of the node. + * + */ +function Trie() { + if (arguments.length > 0) { + this.stem = arguments[0]; } + if (arguments.length > 1) { + this.meta = arguments[1]; + } +} - Trie.prototype = { - find: function(word) { - var found = this, len = word.length; - for (var i = 0; i < len && found; i++) { - found = found[word[i]]; - } - return found; - }, +Trie.prototype = { + find: function(word) { + var found = this, len = word.length; + for (var i = 0; i < len && found; i++) { + found = found[word[i]]; + } + return found; + }, - add: function(word, meta) { - var node = this, len = word.length; - for (var i = 0; i < len; i++) { - var c = word[i]; - if (!node.hasOwnProperty(c)) { - var t = new Trie(c); - node[c] = t; - node = t; - } else { - node = node[c]; - } + add: function(word, meta) { + var node = this, len = word.length; + for (var i = 0; i < len; i++) { + var c = word[i]; + if (!node.hasOwnProperty(c)) { + var t = new Trie(c); + node[c] = t; + node = t; + } else { + node = node[c]; } + } - meta.word = word; - node.meta = meta; - }, + meta.word = word; + node.meta = meta; + }, - remove: function(word) { - var found = this, len = word.length, ancestor = []; - for (var i = 0; i < len && found; i++) { - // keep node in path for later to remove empty nodes - ancestor.push(found); - found = found[word[i]]; - } - if (found) { - var i = ancestor.length - 1, - node = ancestor[i]; + remove: function(word) { + var found = this, len = word.length, ancestor = []; + for (var i = 0; i < len && found; i++) { + // keep node in path for later to remove empty nodes + ancestor.push(found); + found = found[word[i]]; + } + if (found) { + var i = ancestor.length - 1, + node = ancestor[i]; + delete node[found.stem]; + found = node; + while (found !== this && Object.keys(found).length === 1) { + // remove the node if it has only one property -- which should be stem + node = ancestor[--i]; delete node[found.stem]; found = node; - while (found !== this && Object.keys(found).length === 1) { - // remove the node if it has only one property -- which should be stem - node = ancestor[--i]; - delete node[found.stem]; - found = node; - } } - return found; - }, + } + return found; + }, - getWords: function(prefix, withoutStem) { - var ret = [], prefix = (prefix || "") + (withoutStem ? "" : (this.stem || "")); - if (this.hasOwnProperty('meta')) { - ret.push(prefix); - } - for (var k in this) { - if (k.length === 1) { - ret = ret.concat(this[k].getWords(prefix)); - } + getWords: function(prefix, withoutStem) { + var ret = [], prefix = (prefix || "") + (withoutStem ? "" : (this.stem || "")); + if (this.hasOwnProperty('meta')) { + ret.push(prefix); + } + for (var k in this) { + if (k.length === 1) { + ret = ret.concat(this[k].getWords(prefix)); } - return ret; - }, + } + return ret; + }, - getMetas: function(criterion) { - var ret = []; - if (this.hasOwnProperty('meta') && criterion(this.meta)) { - ret.push(this.meta); - } - for (var k in this) { - if (k.length === 1) { - ret = ret.concat(this[k].getMetas(criterion)); - } + getMetas: function(criterion) { + var ret = []; + if (this.hasOwnProperty('meta') && criterion(this.meta)) { + ret.push(this.meta); + } + for (var k in this) { + if (k.length === 1) { + ret = ret.concat(this[k].getMetas(criterion)); } - return ret; - }, + } + return ret; + }, - getPrefixWord: function() { - // unmapAllExcept could make this Trie object empty. - if (Object.keys(this).length === 0) { - return ""; - } - var fullWord = "", futureWord = this.stem, node = this; - while (fullWord === "") { - var keys = Object.keys(node); - for (var i = 0; i < keys.length; i++) { - if (keys[i] === 'meta') { - fullWord = node.meta.word; - break; - } else if (keys[i] !== 'stem') { - futureWord = futureWord + keys[i]; - node = node[keys[i]]; - break; - } + getPrefixWord: function() { + // unmapAllExcept could make this Trie object empty. + if (Object.keys(this).length === 0) { + return ""; + } + var fullWord = "", futureWord = this.stem, node = this; + while (fullWord === "") { + var keys = Object.keys(node); + for (var i = 0; i < keys.length; i++) { + if (keys[i] === 'meta') { + fullWord = node.meta.word; + break; + } else if (keys[i] !== 'stem') { + futureWord = futureWord + keys[i]; + node = node[keys[i]]; + break; } } - return fullWord.substr(0, fullWord.length - futureWord.length + 1); } - }; - - return Trie; -})(); + return fullWord.substr(0, fullWord.length - futureWord.length + 1); + } +}; diff --git a/manifest.json b/manifest.json index 91e200911..203b8ded1 100644 --- a/manifest.json +++ b/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "Surfingkeys", "short_name": "Rich shortcuts in vim spirit for productivity with keyboard.", - "version": "0.9.52", + "version": "0.9.53", "description": "Rich shortcuts to click links/switch tabs/scroll pages or capture full page, use Chrome like vim for productivity.", "icons": { "16": "icons/16.png", @@ -62,11 +62,10 @@ ], "match_about_blank": true, "js": [ - "content_scripts/common_content.min.js", + "content_scripts/modules.min.js", "content_scripts/front.js", - "content_scripts/content_scripts.js", - "content_scripts/top.js", - "pages/default.js" + "pages/default.js", + "content_scripts/content_scripts.js" ], "css": [ "content_scripts/content_scripts.css" diff --git a/pages/default.js b/pages/default.js index 0258b891a..b1b0c2250 100644 --- a/pages/default.js +++ b/pages/default.js @@ -20,6 +20,8 @@ // // ************************* WARNING ************************* +function createDefaultMappings() { + imapkey("", '#15Toggle quotes in an input element', toggleQuote); imapkey('', '#15Open vim editor for current input', function() { var element = getRealEdit(); @@ -691,4 +693,4 @@ addSearchAliasX('y', 'youtube', 'https://www.youtube.com/results?search_query=', }); }); -document.dispatchEvent(new CustomEvent('surfingkeys:defaultSettingsLoaded')); +} diff --git a/pages/error.html b/pages/error.html index f82c50884..b282dfa06 100644 --- a/pages/error.html +++ b/pages/error.html @@ -68,11 +68,10 @@

This webpage is not available

- + - - + diff --git a/pages/front.js b/pages/front.js index 4c4eafc1e..7efc1bd83 100644 --- a/pages/front.js +++ b/pages/front.js @@ -1,11 +1,12 @@ var Front = (function() { + window.KeyboardUtils = createKeyboardUtils(); + window.Mode = createMode(); + window.Normal = createNormal(); + window.Visual = createVisual(); + window.Hints = createHints(); + window.Clipboard = createClipboard(); var self = new Mode("Front"); - // this object is implementation of UI, it's UI provider - self.isProvider = function() { - return true; - }; - var topOrigin, _actions = {}, _callbacks = {}; @@ -83,13 +84,8 @@ var Front = (function() { }, topOrigin); }; self.visualCommand = function(args) { - if (_usage.style.display !== "none") { - // visual mode in frontend.html - Visual[args.action](args.query); - } else { - // visual mode for all content windows - self.contentCommand(args); - } + // visual mode for all content windows + self.contentCommand(args); }; self.omnibar = document.getElementById('sk_omnibar'); diff --git a/pages/frontend.html b/pages/frontend.html index d15c450f7..b64c47df0 100644 --- a/pages/frontend.html +++ b/pages/frontend.html @@ -42,7 +42,7 @@ - + diff --git a/pages/markdown.html b/pages/markdown.html index d1de09994..c45195c2b 100644 --- a/pages/markdown.html +++ b/pages/markdown.html @@ -8,11 +8,10 @@ - + - - +
diff --git a/pages/mermaid.html b/pages/mermaid.html index 7686b36cf..ab8083c85 100644 --- a/pages/mermaid.html +++ b/pages/mermaid.html @@ -7,11 +7,10 @@ - + - - +
diff --git a/pages/options.html b/pages/options.html index a144066aa..ed97e4c3f 100644 --- a/pages/options.html +++ b/pages/options.html @@ -134,11 +134,10 @@

Proxy Settings

Reset

- + - - + diff --git a/pages/pdf_viewer.html b/pages/pdf_viewer.html index 75a571b99..dd1e2ccb8 100644 --- a/pages/pdf_viewer.html +++ b/pages/pdf_viewer.html @@ -317,13 +317,15 @@
- + - - + + diff --git a/pages/popup.html b/pages/popup.html index 3966f082d..5dead9548 100644 --- a/pages/popup.html +++ b/pages/popup.html @@ -35,7 +35,7 @@ PDF Viewer Markdown preview Mermaid diagram generator - + diff --git a/pages/start.html b/pages/start.html index 5bd226d23..aa38494c9 100644 --- a/pages/start.html +++ b/pages/start.html @@ -8,11 +8,10 @@ - + - - +