diff --git a/README.md b/README.md
index 85b0e9136..aa884db33 100644
--- a/README.md
+++ b/README.md
@@ -20,9 +20,12 @@ Surfingkeys is doing its best to make full use of keyboard for web browsing, but
## Installation
+
+
* [Surfingkeys - Chrome Web Store](https://chrome.google.com/webstore/detail/surfingkeys/gfbliohnnapiefjpjlpjnehglfpaknnc)
* [Surfingkeys – Get this Extension for 🦊 Firefox](https://addons.mozilla.org/en-US/firefox/addon/surfingkeys_ff/)
* [Surfingkeys - Microsoft Edge Addons](https://microsoftedge.microsoft.com/addons/detail/kgnghhfkloifoabeaobjkgagcecbnppg)
+* [Surfingkeys on the Mac App Store](https://apps.apple.com/us/app/surfingkeys/id1599827286)
### TABLE OF CONTENTS
diff --git a/config/webpack.config.js b/config/webpack.config.js
index 850d69de1..d4b5388a9 100644
--- a/config/webpack.config.js
+++ b/config/webpack.config.js
@@ -4,6 +4,7 @@ let buildPath = path.resolve(__dirname, '../dist/');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const FileManagerPlugin = require('filemanager-webpack-plugin');
+const TerserPlugin = require('terser-webpack-plugin');
function modifyManifest(browser, mode, buffer) {
// copy-webpack-plugin passes a buffer
@@ -36,21 +37,38 @@ function modifyManifest(browser, mode, buffer) {
return manifest_JSON;
}
-function modifyOptionsHtml(browser, buffer) {
- let content = buffer.toString();
- if (browser === "firefox") {
- content = content.split("\n").filter((line) => {
- return line.indexOf('https://www.google-analytics.com/analytics.js') === -1;
- }).join("\n");
- }
- return content;
-}
-
module.exports = (env, argv) => {
const mode = argv.mode;
const browser = env.browser ? env.browser : 'chrome';
buildPath += "/" + browser;
- return [{
+ const entry = {
+ background: `./src/background/${browser}.js`,
+ content: `./src/content_scripts/${browser}.js`,
+ 'pages/frontend': `./src/content_scripts/ui/frontend.js`,
+ 'pages/options': './src/content_scripts/options.js',
+ 'pages/start': './src/content_scripts/start.js',
+ 'pages/ace': './src/content_scripts/ace.js',
+ };
+ const pagesCopyOptions = {
+ ignore: [
+ '**/neovim.*',
+ '**/pdf_viewer.html',
+ ]
+ };
+ if (browser === "chrome") {
+ pagesCopyOptions.ignore = [];
+ entry['pages/neovim'] = './src/pages/neovim.js';
+ entry['pages/pdf_viewer'] = './src/content_scripts/pdf_viewer.js';
+ }
+ if (browser !== "safari") {
+ entry['pages/markdown'] = './src/content_scripts/markdown.js';
+ } else {
+ pagesCopyOptions.ignore.push('**/markdown.html');
+ pagesCopyOptions.ignore.push('**/donation.png');
+ }
+ console.log(pagesCopyOptions);
+
+ const modules = [{
devtool: false,
output: {
path: buildPath,
@@ -88,21 +106,16 @@ module.exports = (env, argv) => {
],
},
target: 'web',
- entry: {
- 'pages/neovim': './src/pages/neovim.js',
- background: `./src/background/${browser}.js`,
- content: `./src/content_scripts/${browser}.js`,
- 'pages/frontend': `./src/content_scripts/ui/frontend.js`,
- 'pages/options': './src/content_scripts/options.js',
- 'pages/markdown': './src/content_scripts/markdown.js',
- 'pages/pdf_viewer': './src/content_scripts/pdf_viewer.js',
- 'pages/start': './src/content_scripts/start.js',
- 'pages/ace': './src/content_scripts/ace.js',
+ entry: entry,
+ optimization: {
+ minimizer: [new TerserPlugin({
+ extractComments: false,
+ })],
},
plugins: [
new CopyWebpackPlugin({
patterns: [
- { from: 'src/pages', to: 'pages' },
+ { from: 'src/pages', to: 'pages', globOptions: pagesCopyOptions },
{ from: 'src/content_scripts/ui/frontend.html', to: 'pages' },
{ from: 'src/content_scripts/ui/frontend.css', to: 'pages' },
{ from: 'node_modules/ace-builds/src-noconflict/worker-javascript.js', to: 'pages' },
@@ -114,16 +127,13 @@ module.exports = (env, argv) => {
transform (content, path) {
return modifyManifest(browser, mode, content)
}
- },
- {
- from: "src/pages/options.html",
- to: "pages",
- transform (content, path) {
- return modifyOptionsHtml(browser, content)
- }
}
]
- }),
+ })
+ ]
+ }];
+ if (browser !== "safari") {
+ modules[0].plugins.push(
new FileManagerPlugin({
events: {
onEnd: {
@@ -136,39 +146,48 @@ module.exports = (env, argv) => {
},
},
})
- ]
- }, {
- devtool: false,
- output: {
- path: buildPath,
- filename: '[name].js',
- libraryTarget: 'module',
- },
- resolve: {
- extensions: ['.ts', '.js'],
- },
- target: 'web',
- entry: {
- 'pages/neovim_lib': './src/nvim/renderer.ts',
- },
- module: {
- rules: [
- {
- test: /\.ts$/,
- exclude: /node_modules/,
- loader: 'ts-loader',
- },
- {
- test: /\.css$/,
- use: [
- { loader: "style-loader", options: { injectType: "linkTag" } },
- { loader: "file-loader" },
- ]
- },
- ],
- },
- experiments: {
- outputModule: true,
- }
- }]
+ );
+ }
+ if (browser === "chrome") {
+ modules.push({
+ devtool: false,
+ output: {
+ path: buildPath,
+ filename: '[name].js',
+ libraryTarget: 'module',
+ },
+ resolve: {
+ extensions: ['.ts', '.js'],
+ },
+ target: 'web',
+ entry: {
+ 'pages/neovim_lib': './src/nvim/renderer.ts',
+ },
+ module: {
+ rules: [
+ {
+ test: /\.ts$/,
+ exclude: /node_modules/,
+ loader: 'ts-loader',
+ },
+ {
+ test: /\.css$/,
+ use: [
+ { loader: "style-loader", options: { injectType: "linkTag" } },
+ { loader: "file-loader" },
+ ]
+ },
+ ],
+ },
+ optimization: {
+ minimizer: [new TerserPlugin({
+ extractComments: false,
+ })],
+ },
+ experiments: {
+ outputModule: true,
+ }
+ });
+ }
+ return modules;
};
diff --git a/package.json b/package.json
index d18b6b7f7..dd21d4f49 100644
--- a/package.json
+++ b/package.json
@@ -11,11 +11,13 @@
"clean": "rm -rf dist/*",
"build:doc": "documentation build src/content_scripts/common/api.js src/content_scripts/common/clipboard.js src/content_scripts/common/hints.js src/content_scripts/common/visual.js src/content_scripts/front.js -f md -o docs/api.md",
"build:dev-firefox": "webpack --env=browser=firefox --mode=development --config ./config/webpack.config.js",
+ "build:dev-safari": "webpack --env=browser=safari --mode=development --config ./config/webpack.config.js",
"build:dev": "webpack --mode=development --config ./config/webpack.config.js",
"build:prod-firefox": "webpack --env=browser=firefox --mode=production --config ./config/webpack.config.js",
+ "build:prod-safari": "webpack --env=browser=safari --mode=production --config ./config/webpack.config.js",
"build:prod": "webpack --mode=production --config ./config/webpack.config.js",
"build:testdata": "webpack --mode=production --config ./config/webpack.test.config.js",
- "build": "npm-run-all clean test build:doc build:prod build:prod-firefox",
+ "build": "npm-run-all clean test build:doc build:prod build:prod-firefox build:prod-safari",
"test": "jest"
},
"repository": {
@@ -43,6 +45,7 @@
"documentation": "^13.2.5",
"file-loader": "^6.2.0",
"filemanager-webpack-plugin": "^6.1.7",
+ "jest": "^27.3.1",
"jest-image-snapshot": "^4.5.1",
"npm-run-all": "^4.1.5",
"puppeteer": "^10.2.0",
diff --git a/sk.svg b/sk.svg
new file mode 100644
index 000000000..d369fbe0d
--- /dev/null
+++ b/sk.svg
@@ -0,0 +1,3 @@
+
diff --git a/sk.xcf b/sk.xcf
index 39ca36280..284b93a27 100644
Binary files a/sk.xcf and b/sk.xcf differ
diff --git a/src/background/safari.js b/src/background/safari.js
new file mode 100644
index 000000000..a7e6702fa
--- /dev/null
+++ b/src/background/safari.js
@@ -0,0 +1,55 @@
+import {
+ _save,
+ dictFromArray,
+ extendObject,
+ getSubSettings,
+ start
+} from './start.js';
+
+function loadRawSettings(keys, cb, defaultSet) {
+ var rawSet = defaultSet || {};
+ chrome.storage.local.get(null, function(localSet) {
+ var localSavedAt = localSet.savedAt || 0;
+ chrome.storage.sync.get(null, function(syncSet) {
+ var syncSavedAt = syncSet.savedAt || 0;
+ if (localSavedAt > syncSavedAt) {
+ extendObject(rawSet, localSet);
+ _save(chrome.storage.sync, localSet, function() {
+ var subset = getSubSettings(rawSet, keys);
+ if (chrome.runtime.lastError) {
+ subset.error = "Settings sync may not work thoroughly because of: " + chrome.runtime.lastError.message;
+ }
+ cb(subset);
+ });
+ } else if (localSavedAt < syncSavedAt) {
+ extendObject(rawSet, syncSet);
+ cb(getSubSettings(rawSet, keys));
+ _save(chrome.storage.local, syncSet);
+ } else {
+ extendObject(rawSet, localSet);
+ cb(getSubSettings(rawSet, keys));
+ }
+ });
+ });
+}
+
+function _applyProxySettings(proxyConf) {
+}
+
+function _setNewTabUrl(){
+ return "favorites://";
+}
+
+function _getContainerName(self, _response){
+}
+
+function getLatestHistoryItem(text, maxResults, cb) {
+}
+
+start({
+ getLatestHistoryItem,
+ loadRawSettings,
+ _applyProxySettings,
+ _setNewTabUrl,
+ _getContainerName
+});
diff --git a/src/background/start.js b/src/background/start.js
index 81cf1c9bf..5c83f9f73 100644
--- a/src/background/start.js
+++ b/src/background/start.js
@@ -524,7 +524,7 @@ function start(browser) {
loadSettings('blocklist', function(data) {
var origin = ".*";
var senderOrigin = sender.origin || new URL(getSenderUrl(sender)).origin;
- if (chrome.extension.getURL("").indexOf(senderOrigin) !== 0) {
+ if (chrome.extension.getURL("/").indexOf(senderOrigin) !== 0 && senderOrigin !== "null") {
origin = senderOrigin;
}
if (data.blocklist.hasOwnProperty(origin)) {
@@ -543,7 +543,7 @@ function start(browser) {
};
self.toggleMouseQuery = function(message, sender, sendResponse) {
loadSettings('mouseSelectToQuery', function(data) {
- if (sender.tab && sender.tab.url.indexOf(chrome.extension.getURL("")) !== 0) {
+ if (sender.tab && sender.tab.url.indexOf(chrome.extension.getURL("/")) !== 0) {
var mouseSelectToQuery = data.mouseSelectToQuery || [];
var idx = mouseSelectToQuery.indexOf(message.origin);
if (idx === -1) {
@@ -659,12 +659,18 @@ function start(browser) {
});
};
self.getTopSites = function(message, sender, sendResponse) {
- chrome.topSites.get(function(urls) {
- urls = _filterByTitleOrUrl(urls, message.query);
+ if (chrome.topSites) {
+ chrome.topSites.get(function(urls) {
+ urls = _filterByTitleOrUrl(urls, message.query);
+ _response(message, sendResponse, {
+ urls: urls
+ });
+ });
+ } else {
_response(message, sendResponse, {
- urls: urls
+ urls: []
});
- });
+ }
};
@@ -1607,6 +1613,9 @@ function start(browser) {
}
chrome.tabs.reload(sender.tab.id);
};
+ self.writeClipboard = function (message, sender, sendResponse) {
+ navigator.clipboard.writeText(message.text)
+ };
self.getContainerName = browser._getContainerName(self, _response);
chrome.runtime.setUninstallURL("http://brookhong.github.io/2018/01/30/why-did-you-uninstall-surfingkeys.html");
diff --git a/src/content_scripts/common/api.js b/src/content_scripts/common/api.js
index a352ee7ef..7fb7d5f18 100644
--- a/src/content_scripts/common/api.js
+++ b/src/content_scripts/common/api.js
@@ -4,6 +4,7 @@ import KeyboardUtils from './keyboardUtils';
import {
actionWithSelectionPreserved,
constructSearchURL,
+ getBrowserName,
getClickableElements,
getRealEdit,
getTextNodePos,
@@ -11,6 +12,7 @@ import {
htmlEncode,
mapInMode,
parseAnnotation,
+ setSanitizedContent,
showBanner,
showPopup,
tabOpenLink,
@@ -433,23 +435,39 @@ function createAPI(clipboard, insert, normal, hints, visual, front, browser) {
imapkey('', '#15Open vim editor for current input', function() {
openVim(false);
});
- imapkey('', '#15Open neovim for current input', function() {
- openVim(true);
- });
-
- function toggleProxySite(host) {
- RUNTIME('updateProxy', {
- host: host,
- operation: "toggle"
+ const browserName = getBrowserName();
+ if (browserName === "Chrome") {
+ imapkey('', '#15Open neovim for current input', function() {
+ openVim(true);
+ });
+ mapkey(';s', 'Toggle PDF viewer from SurfingKeys', function() {
+ var pdfUrl = window.location.href;
+ if (pdfUrl.indexOf(chrome.extension.getURL("/pages/pdf_viewer.html")) === 0) {
+ pdfUrl = window.location.search.substr(3);
+ chrome.storage.local.set({"noPdfViewer": 1}, function() {
+ window.location.replace(pdfUrl);
+ });
+ } else {
+ if (document.querySelector("EMBED") && document.querySelector("EMBED").getAttribute("type") === "application/pdf") {
+ chrome.storage.local.remove("noPdfViewer", function() {
+ window.location.replace(pdfUrl);
+ });
+ } else {
+ chrome.storage.local.get("noPdfViewer", function(resp) {
+ if(!resp.noPdfViewer) {
+ chrome.storage.local.set({"noPdfViewer": 1}, function() {
+ showBanner("PDF viewer disabled.");
+ });
+ } else {
+ chrome.storage.local.remove("noPdfViewer", function() {
+ showBanner("PDF viewer enabled.");
+ });
+ }
+ });
+ }
+ }
});
- return true;
}
- mapkey('cp', '#13Toggle proxy for current site', function() {
- var host = window.location.host.replace(/:\d+/,'');
- if (host && host.length) {
- toggleProxySite(host);
- }
- });
mapkey(";ql", '#0Show last action', function() {
showPopup(htmlEncode(runtime.conf.lastKeys.map(function(k) {
@@ -461,34 +479,6 @@ function createAPI(clipboard, insert, normal, hints, visual, front, browser) {
hints.createInputLayer();
});
- mapkey(';s', 'Toggle PDF viewer from SurfingKeys', function() {
- var pdfUrl = window.location.href;
- if (pdfUrl.indexOf(chrome.extension.getURL("/pages/pdf_viewer.html")) === 0) {
- pdfUrl = window.location.search.substr(3);
- chrome.storage.local.set({"noPdfViewer": 1}, function() {
- window.location.replace(pdfUrl);
- });
- } else {
- if (document.querySelector("EMBED") && document.querySelector("EMBED").getAttribute("type") === "application/pdf") {
- chrome.storage.local.remove("noPdfViewer", function() {
- window.location.replace(pdfUrl);
- });
- } else {
- chrome.storage.local.get("noPdfViewer", function(resp) {
- if(!resp.noPdfViewer) {
- chrome.storage.local.set({"noPdfViewer": 1}, function() {
- showBanner("PDF viewer disabled.");
- });
- } else {
- chrome.storage.local.remove("noPdfViewer", function() {
- showBanner("PDF viewer enabled.");
- });
- }
- });
- }
- }
- });
-
mapkey('zv', '#9Enter visual mode, and select whole element', function() {
visual.toggle("z");
});
@@ -690,6 +680,7 @@ function createAPI(clipboard, insert, normal, hints, visual, front, browser) {
cmap,
imap,
imapkey,
+ getBrowserName,
getClickableElements,
getFormData,
map,
diff --git a/src/content_scripts/common/clipboard.js b/src/content_scripts/common/clipboard.js
index 9799ca6af..622efecc8 100644
--- a/src/content_scripts/common/clipboard.js
+++ b/src/content_scripts/common/clipboard.js
@@ -1,6 +1,8 @@
+import { RUNTIME } from './runtime.js';
import {
actionWithSelectionPreserved,
insertJS,
+ getBrowserName,
setSanitizedContent,
showBanner,
} from './utils.js';
@@ -36,7 +38,7 @@ function createClipboard() {
* });
*/
self.read = function(onReady) {
- if (window.navigator.userAgent.indexOf("Firefox") !== -1 &&
+ if (getBrowserName() === "Firefox" &&
typeof navigator.clipboard === 'object' && typeof navigator.clipboard.readText === 'function') {
navigator.clipboard.readText().then((data) => {
// call back onReady in a different thread to avoid breaking UI operations
@@ -73,27 +75,28 @@ function createClipboard() {
const cb = () => {
showBanner("Copied: " + text);
};
- if (window.navigator.userAgent.indexOf("Firefox") !== -1 &&
- typeof navigator.clipboard === 'object' && typeof navigator.clipboard.writeText === 'function') {
- navigator.clipboard.writeText(text).then(cb);
- return;
- }
- insertJS(function() {
- window.oncopy = document.oncopy;
- document.oncopy = null;
- }, function() {
- clipboardActionWithSelectionPreserved(function() {
- holder.value = text;
- holder.select();
- document.execCommand('copy');
- holder.value = '';
- });
+ if (getBrowserName() === "Chrome") {
insertJS(function() {
- document.oncopy = window.oncopy;
- delete window.oncopy;
+ window.oncopy = document.oncopy;
+ document.oncopy = null;
+ }, function() {
+ clipboardActionWithSelectionPreserved(function() {
+ holder.value = text;
+ holder.select();
+ document.execCommand('copy');
+ holder.value = '';
+ });
+ insertJS(function() {
+ document.oncopy = window.oncopy;
+ delete window.oncopy;
+ });
+ cb();
});
+ } else {
+ // works for Firefox and Safari now.
+ RUNTIME("writeClipboard", { text });
cb();
- });
+ }
};
return self;
diff --git a/src/content_scripts/common/default.js b/src/content_scripts/common/default.js
index 4df3bec0b..5ca68f9e0 100644
--- a/src/content_scripts/common/default.js
+++ b/src/content_scripts/common/default.js
@@ -2,6 +2,7 @@ module.exports = function(api) {
const {
addSearchAlias,
cmap,
+ getBrowserName,
getFormData,
map,
mapkey,
@@ -14,38 +15,6 @@ module.exports = function(api) {
RUNTIME
} = api;
- mapkey(';cp', '#13Copy proxy info', function() {
- RUNTIME('getSettings', {
- key: ['proxyMode', 'proxy', 'autoproxy_hosts']
- }, function(response) {
- Clipboard.write(JSON.stringify(response.settings, null, 4));
- });
- });
- mapkey(';ap', '#13Apply proxy info from clipboard', function() {
- Clipboard.read(function(response) {
- var proxyConf = JSON.parse(response.data);
- RUNTIME('updateProxy', {
- operation: 'set',
- host: proxyConf.autoproxy_hosts,
- proxy: proxyConf.proxy,
- mode: proxyConf.proxyMode
- });
- });
- });
- // create shortcuts for the command with different parameters
- map(';pa', ':setProxyMode always', 0, '#13set proxy mode `always`');
- map(';pb', ':setProxyMode byhost', 0, '#13set proxy mode `byhost`');
- map(';pd', ':setProxyMode direct', 0, '#13set proxy mode `direct`');
- map(';ps', ':setProxyMode system', 0, '#13set proxy mode `system`');
- map(';pc', ':setProxyMode clear', 0, '#13set proxy mode `clear`');
- mapkey('gr', '#14Read selected text or text from clipboard', function() {
- Clipboard.read(function(response) {
- readText(window.getSelection().toString() || response.data, {verbose: true});
- });
- });
- vmapkey('gr', '#9Read selected text', function() {
- readText(window.getSelection().toString(), {verbose: true});
- });
map('g0', ':feedkeys 99E', 0, "#3Go to the first tab");
map('g$', ':feedkeys 99R', 0, "#3Go to the last tab");
mapkey('zr', '#3zoom reset', function() {
@@ -152,11 +121,6 @@ module.exports = function(api) {
Front.showEditor(element);
});
});
- mapkey('', '#1Go to edit box with neo vim editor', function() {
- Hints.create("input, textarea, *[contenteditable=true], select", function(element) {
- Front.showEditor(element, null, null, true);
- });
- });
map('', 'I');
cmap('', '');
@@ -196,36 +160,15 @@ module.exports = function(api) {
mapkey('r', '#4Reload the page', function() {
RUNTIME("reloadTab", { nocache: false });
});
- mapkey('t', '#8Open a URL', function() {
- Front.openOmnibar({type: "URLs"});
- });
- mapkey('go', '#8Open a URL in current tab', function() {
- Front.openOmnibar({type: "URLs", tabbed: false});
- });
mapkey('oi', '#8Open incognito window', function() {
RUNTIME('openIncognito', {
url: window.location.href
});
});
- mapkey('ox', '#8Open recently closed URL', function() {
- Front.openOmnibar({type: "RecentlyClosed"});
- });
+
mapkey('H', '#8Open opened URL in current tab', function() {
Front.openOmnibar({type: "TabURLs"});
});
- mapkey('b', '#8Open a bookmark', function() {
- Front.openOmnibar(({type: "Bookmarks"}));
- });
- mapkey('ab', '#8Bookmark current page to selected folder', function() {
- var page = {
- url: window.location.href,
- title: document.title
- };
- Front.openOmnibar(({type: "AddBookmark", extra: page}));
- });
- mapkey('oh', '#8Open URL from history', function() {
- Front.openOmnibar({type: "History"});
- });
mapkey('om', '#8Open URL from vim-like marks', function() {
Front.openOmnibar({type: "VIMarks"});
});
@@ -240,30 +183,6 @@ module.exports = function(api) {
mapkey('x', '#3Close current tab', function() {
RUNTIME("closeTab");
});
- mapkey('X', '#3Restore closed tab', function() {
- RUNTIME("openLast");
- });
- mapkey('W', '#3Move current tab to another window', function() {
- Front.openOmnibar(({type: "Windows"}));
- });
- mapkey(';gt', '#3Gather filtered tabs into current window', function() {
- Front.openOmnibar({type: "Tabs", extra: {
- action: "gather"
- }});
- });
- mapkey(';gw', '#3Gather all tabs into current window', function() {
- RUNTIME("gatherWindows");
- });
- mapkey('<<', '#3Move current tab to left', function() {
- RUNTIME('moveTab', {
- step: -1
- });
- });
- mapkey('>>', '#3Move current tab to right', function() {
- RUNTIME('moveTab', {
- step: 1
- });
- });
mapkey(';w', '#2Focus top window', function() {
top.focus();
});
@@ -294,16 +213,6 @@ module.exports = function(api) {
});
});
});
- mapkey('yd', "#7Copy current downloading URL", function() {
- RUNTIME('getDownloads', {
- query: {state: "in_progress"}
- }, function(response) {
- var items = response.downloads.map(function(o) {
- return o.url;
- });
- Clipboard.write(items.join(','));
- });
- });
mapkey('yt', '#3Duplicate current tab', function() {
RUNTIME("duplicateTab");
});
@@ -406,45 +315,7 @@ module.exports = function(api) {
mapkey('oy', '#8Open Search with alias y', function() {
Front.openOmnibar({type: "SearchEngine", extra: "y"});
});
- if (window.navigator.userAgent.indexOf("Firefox") > 0) {
- mapkey('on', '#3Open newtab', function() {
- tabOpenLink("about:blank");
- });
- } else {
- mapkey('on', '#3Open newtab', function() {
- tabOpenLink("chrome://newtab/");
- });
- mapkey('ga', '#12Open Chrome About', function() {
- tabOpenLink("chrome://help/");
- });
- mapkey('gb', '#12Open Chrome Bookmarks', function() {
- tabOpenLink("chrome://bookmarks/");
- });
- mapkey('gc', '#12Open Chrome Cache', function() {
- tabOpenLink("chrome://cache/");
- });
- mapkey('gd', '#12Open Chrome Downloads', function() {
- tabOpenLink("chrome://downloads/");
- });
- mapkey('gh', '#12Open Chrome History', function() {
- tabOpenLink("chrome://history/");
- });
- mapkey('gk', '#12Open Chrome Cookies', function() {
- tabOpenLink("chrome://settings/content/cookies");
- });
- mapkey('ge', '#12Open Chrome Extensions', function() {
- tabOpenLink("chrome://extensions/");
- });
- mapkey('gn', '#12Open Chrome net-internals', function() {
- tabOpenLink("chrome://net-internals/#proxy");
- });
- mapkey(';i', '#12Open Chrome Inspect', function() {
- tabOpenLink("chrome://inspect/#devices");
- });
- }
- mapkey('gs', '#12View page source', function() {
- RUNTIME("viewSource", { tab: { tabbed: true }});
- });
+
mapkey('g?', '#4Reload current page without query string(all parts after question mark)', function() {
window.location.href = window.location.href.replace(/\?[^\?]*$/, '');
});
@@ -472,12 +343,6 @@ module.exports = function(api) {
mapkey(';e', '#11Edit Settings', function() {
tabOpenLink("/pages/options.html");
});
- mapkey(';v', '#11Open neovim', function() {
- tabOpenLink("/pages/neovim.html");
- });
- mapkey(';pm', '#11Preview markdown', function() {
- tabOpenLink("/pages/markdown.html");
- });
mapkey(';u', '#4Edit current URL with vim editor, and open in new tab', function() {
Front.showEditor(window.location.href, function(data) {
tabOpenLink(data);
@@ -488,35 +353,6 @@ module.exports = function(api) {
window.location.href = data;
}, 'url');
});
- mapkey(';di', '#1Download image', function() {
- Hints.create('img', function(element) {
- RUNTIME('download', {
- url: element.src
- });
- });
- });
- mapkey(';j', '#12Close Downloads Shelf', function() {
- RUNTIME("closeDownloadsShelf", {clearHistory: true});
- });
-
- mapkey(';dh', '#14Delete history older than 30 days', function() {
- RUNTIME('deleteHistoryOlderThan', {
- days: 30
- });
- });
- mapkey(';yh', '#14Yank histories', function() {
- RUNTIME('getHistory', {}, function(response) {
- Clipboard.write(response.history.map(h => h.url).join("\n"));
- });
- });
- mapkey(';ph', '#14Put histories from clipboard', function() {
- Clipboard.read(function(response) {
- RUNTIME('addHistories', {history: response.data.split("\n")});
- });
- });
- mapkey(';db', '#14Remove bookmark for current page', function() {
- RUNTIME('removeBookmark');
- });
addSearchAlias('g', 'google', 'https://www.google.com/search?q=', 's', 'https://www.google.com/complete/search?client=chrome-omni&gs_ri=chrome-ext&oit=1&cp=1&pgcl=7&q=', function(response) {
var res = JSON.parse(response.text);
@@ -557,4 +393,184 @@ module.exports = function(api) {
});
});
+ const browser = getBrowserName();
+ if (browser === "Firefox") {
+ mapkey('on', '#3Open newtab', function() {
+ tabOpenLink("about:blank");
+ });
+ } else if (browser === "Chrome") {
+ mapkey('cp', '#13Toggle proxy for current site', function() {
+ var host = window.location.host.replace(/:\d+/,'');
+ if (host && host.length) {
+ RUNTIME('updateProxy', {
+ host: host,
+ operation: "toggle"
+ });
+ }
+ });
+ mapkey(';cp', '#13Copy proxy info', function() {
+ RUNTIME('getSettings', {
+ key: ['proxyMode', 'proxy', 'autoproxy_hosts']
+ }, function(response) {
+ Clipboard.write(JSON.stringify(response.settings, null, 4));
+ });
+ });
+ mapkey(';ap', '#13Apply proxy info from clipboard', function() {
+ Clipboard.read(function(response) {
+ var proxyConf = JSON.parse(response.data);
+ RUNTIME('updateProxy', {
+ operation: 'set',
+ host: proxyConf.autoproxy_hosts,
+ proxy: proxyConf.proxy,
+ mode: proxyConf.proxyMode
+ });
+ });
+ });
+ // create shortcuts for the command with different parameters
+ map(';pa', ':setProxyMode always', 0, '#13set proxy mode `always`');
+ map(';pb', ':setProxyMode byhost', 0, '#13set proxy mode `byhost`');
+ map(';pd', ':setProxyMode direct', 0, '#13set proxy mode `direct`');
+ map(';ps', ':setProxyMode system', 0, '#13set proxy mode `system`');
+ map(';pc', ':setProxyMode clear', 0, '#13set proxy mode `clear`');
+ mapkey('gr', '#14Read selected text or text from clipboard', function() {
+ Clipboard.read(function(response) {
+ readText(window.getSelection().toString() || response.data, {verbose: true});
+ });
+ });
+ vmapkey('gr', '#9Read selected text', function() {
+ readText(window.getSelection().toString(), {verbose: true});
+ });
+
+ mapkey('on', '#3Open newtab', function() {
+ tabOpenLink("chrome://newtab/");
+ });
+ mapkey('ga', '#12Open Chrome About', function() {
+ tabOpenLink("chrome://help/");
+ });
+ mapkey('gb', '#12Open Chrome Bookmarks', function() {
+ tabOpenLink("chrome://bookmarks/");
+ });
+ mapkey('gc', '#12Open Chrome Cache', function() {
+ tabOpenLink("chrome://cache/");
+ });
+ mapkey('gd', '#12Open Chrome Downloads', function() {
+ tabOpenLink("chrome://downloads/");
+ });
+ mapkey('gh', '#12Open Chrome History', function() {
+ tabOpenLink("chrome://history/");
+ });
+ mapkey('gk', '#12Open Chrome Cookies', function() {
+ tabOpenLink("chrome://settings/content/cookies");
+ });
+ mapkey('ge', '#12Open Chrome Extensions', function() {
+ tabOpenLink("chrome://extensions/");
+ });
+ mapkey('gn', '#12Open Chrome net-internals', function() {
+ tabOpenLink("chrome://net-internals/#proxy");
+ });
+ mapkey(';i', '#12Open Chrome Inspect', function() {
+ tabOpenLink("chrome://inspect/#devices");
+ });
+ mapkey(';v', '#11Open neovim', function() {
+ tabOpenLink("/pages/neovim.html");
+ });
+ mapkey('', '#1Go to edit box with neo vim editor', function() {
+ Hints.create("input, textarea, *[contenteditable=true], select", function(element) {
+ Front.showEditor(element, null, null, true);
+ });
+ });
+ }
+
+ if (browser !== "Safari") {
+ mapkey('t', '#8Open a URL', function() {
+ Front.openOmnibar({type: "URLs"});
+ });
+ mapkey('go', '#8Open a URL in current tab', function() {
+ Front.openOmnibar({type: "URLs", tabbed: false});
+ });
+ mapkey('ox', '#8Open recently closed URL', function() {
+ Front.openOmnibar({type: "RecentlyClosed"});
+ });
+ mapkey('X', '#3Restore closed tab', function() {
+ RUNTIME("openLast");
+ });
+ mapkey('b', '#8Open a bookmark', function() {
+ Front.openOmnibar(({type: "Bookmarks"}));
+ });
+ mapkey('ab', '#8Bookmark current page to selected folder', function() {
+ var page = {
+ url: window.location.href,
+ title: document.title
+ };
+ Front.openOmnibar(({type: "AddBookmark", extra: page}));
+ });
+ mapkey('oh', '#8Open URL from history', function() {
+ Front.openOmnibar({type: "History"});
+ });
+ mapkey('W', '#3Move current tab to another window', function() {
+ Front.openOmnibar(({type: "Windows"}));
+ });
+ mapkey(';gt', '#3Gather filtered tabs into current window', function() {
+ Front.openOmnibar({type: "Tabs", extra: {
+ action: "gather"
+ }});
+ });
+ mapkey(';gw', '#3Gather all tabs into current window', function() {
+ RUNTIME("gatherWindows");
+ });
+ mapkey('<<', '#3Move current tab to left', function() {
+ RUNTIME('moveTab', {
+ step: -1
+ });
+ });
+ mapkey('>>', '#3Move current tab to right', function() {
+ RUNTIME('moveTab', {
+ step: 1
+ });
+ });
+ mapkey('yd', "#7Copy current downloading URL", function() {
+ RUNTIME('getDownloads', {
+ query: {state: "in_progress"}
+ }, function(response) {
+ var items = response.downloads.map(function(o) {
+ return o.url;
+ });
+ Clipboard.write(items.join(','));
+ });
+ });
+ mapkey('gs', '#12View page source', function() {
+ RUNTIME("viewSource", { tab: { tabbed: true }});
+ });
+ mapkey(';pm', '#11Preview markdown', function() {
+ tabOpenLink("/pages/markdown.html");
+ });
+ mapkey(';di', '#1Download image', function() {
+ Hints.create('img', function(element) {
+ RUNTIME('download', {
+ url: element.src
+ });
+ });
+ });
+ mapkey(';j', '#12Close Downloads Shelf', function() {
+ RUNTIME("closeDownloadsShelf", {clearHistory: true});
+ });
+ mapkey(';dh', '#14Delete history older than 30 days', function() {
+ RUNTIME('deleteHistoryOlderThan', {
+ days: 30
+ });
+ });
+ mapkey(';yh', '#14Yank histories', function() {
+ RUNTIME('getHistory', {}, function(response) {
+ Clipboard.write(response.history.map(h => h.url).join("\n"));
+ });
+ });
+ mapkey(';ph', '#14Put histories from clipboard', function() {
+ Clipboard.read(function(response) {
+ RUNTIME('addHistories', {history: response.data.split("\n")});
+ });
+ });
+ mapkey(';db', '#14Remove bookmark for current page', function() {
+ RUNTIME('removeBookmark');
+ });
+ }
}
diff --git a/src/content_scripts/common/hints.js b/src/content_scripts/common/hints.js
index 6bb479750..74222e267 100644
--- a/src/content_scripts/common/hints.js
+++ b/src/content_scripts/common/hints.js
@@ -7,6 +7,7 @@ import {
flashPressedLink,
getElements,
listElements,
+ getBrowserName,
getClickableElements,
getRealRect,
getTextNodePos,
@@ -750,7 +751,7 @@ div.hint-scrollable {
if (shiftKey && runtime.conf.hintShiftNonActive) {
tabbed = true;
active = false;
- } else if (shiftKey && window.navigator.userAgent.indexOf("Firefox") !== -1) {
+ } else if (shiftKey && getBrowserName() === "Firefox") {
// mouseButton does not work for firefox in mouse event.
tabbed = true;
active = true;
diff --git a/src/content_scripts/common/normal.js b/src/content_scripts/common/normal.js
index 1a57fba1c..9fbd0d2c5 100644
--- a/src/content_scripts/common/normal.js
+++ b/src/content_scripts/common/normal.js
@@ -194,7 +194,7 @@ function createNormal(insert) {
});
self.toggleBlocklist = function() {
- if (document.location.href.indexOf(chrome.extension.getURL("")) !== 0) {
+ if (document.location.href.indexOf(chrome.extension.getURL("/")) !== 0) {
RUNTIME('toggleBlocklist', {
blocklistPattern: (runtime.conf.blocklistPattern ? runtime.conf.blocklistPattern.toJSON() : "")
}, function(resp) {
diff --git a/src/content_scripts/common/utils.js b/src/content_scripts/common/utils.js
index 688724915..e59185431 100644
--- a/src/content_scripts/common/utils.js
+++ b/src/content_scripts/common/utils.js
@@ -2,8 +2,24 @@ import * as DOMPurify from 'dompurify';
import KeyboardUtils from './keyboardUtils';
import { RUNTIME, dispatchSKEvent, runtime } from './runtime.js';
+/**
+ * Get current browser name
+ * @returns {string} "Chrome" | "Firefox" | "Safari"
+ *
+ */
+function getBrowserName() {
+ if (window.navigator.userAgent.indexOf("Chrome") !== -1) {
+ return "Chrome";
+ } else if (window.navigator.vendor.indexOf("Apple Computer, Inc.") === 0) {
+ return "Safari";
+ } else if (window.navigator.userAgent.indexOf("Firefox") !== -1) {
+ return "Firefox";
+ }
+ return "Chrome";
+}
+
function isInUIFrame() {
- return document.location.href.indexOf(chrome.extension.getURL("")) === 0;
+ return document.location.href.indexOf(chrome.extension.getURL("/")) === 0;
}
function timeStampString(t) {
@@ -720,6 +736,7 @@ export {
flashPressedLink,
generateQuickGuid,
getAnnotations,
+ getBrowserName,
getClickableElements,
getDocumentOrigin,
getElements,
diff --git a/src/content_scripts/common/visual.js b/src/content_scripts/common/visual.js
index 437deb9c3..64e291933 100644
--- a/src/content_scripts/common/visual.js
+++ b/src/content_scripts/common/visual.js
@@ -6,6 +6,7 @@ import {
actionWithSelectionPreserved,
dispatchMouseEvent,
flashPressedLink,
+ getBrowserName,
getTextNodes,
getTextRect,
getVisibleElements,
@@ -157,7 +158,7 @@ function createVisual(clipboard, hints) {
feature_group: 9,
code: function() {
document.scrollingElement.scrollTop = document.scrollingElement.scrollHeight;
- if (window.navigator.userAgent.indexOf("Firefox") === -1) {
+ if (getBrowserName() !== "Firefox") {
modifySelection();
} else {
self.hideCursor();
@@ -183,7 +184,7 @@ function createVisual(clipboard, hints) {
dispatchSKEvent('showStatus', [2, currentOccurrence + 1 + ' / ' + matches.length]);
}
- if (window.navigator.userAgent.indexOf("Firefox") === -1) {
+ if (getBrowserName() !== "Firefox") {
modifySelection();
} else {
self.hideCursor();
@@ -211,7 +212,7 @@ function createVisual(clipboard, hints) {
p: "paragraphboundary"
};
function _selectUnit(w) {
- if (window.navigator.userAgent.indexOf("Firefox") === -1 || (w !== "p" && w !== "s")) {
+ if (getBrowserName() !== "Firefox" || (w !== "p" && w !== "s")) {
var unit = _units[w];
// sentence and paragraphboundary not support in firefox
// document.getSelection().modify("move", "backward", "paragraphboundary")
diff --git a/src/content_scripts/content.js b/src/content_scripts/content.js
index efc2dca28..f65871367 100644
--- a/src/content_scripts/content.js
+++ b/src/content_scripts/content.js
@@ -250,7 +250,7 @@ function start(browser) {
} else {
// activate Modes in the frames on extension pages
runtime.getTopURL(function(u) {
- if (u.indexOf(chrome.extension.getURL("")) === 0) {
+ if (u.indexOf(chrome.extension.getURL("/")) === 0) {
_initContent(_initModules());
}
});
diff --git a/src/content_scripts/front.js b/src/content_scripts/front.js
index 89dc5d737..a712250b7 100644
--- a/src/content_scripts/front.js
+++ b/src/content_scripts/front.js
@@ -3,6 +3,7 @@ import {
flashPressedLink,
generateQuickGuid,
getAnnotations,
+ getBrowserName,
getDocumentOrigin,
httpRequest,
isEditable,
@@ -507,7 +508,7 @@ function createFront(insert, normal, hints, visual) {
if (queryResult.constructor.name !== "Array") {
queryResult = [queryResult];
}
- if (window.navigator.userAgent.indexOf("Firefox") === -1) {
+ if (getBrowserName() === "Chrome") {
var sentence = visual.findSentenceOf(response.query);
if (sentence.length > 0) {
queryResult.push(sentence);
@@ -556,7 +557,7 @@ function createFront(insert, normal, hints, visual) {
clearPendingQuery();
_pendingQuery = setTimeout(function() {
visual.visualUpdateForContentWindow(message.query);
- if (window.navigator.userAgent.indexOf("Firefox") !== -1) {
+ if (getBrowserName() === "Firefox") {
frontendCommand({
action: "visualUpdatedForFirefox"
});
diff --git a/src/content_scripts/options.js b/src/content_scripts/options.js
index 29367fc2d..bbb90be46 100644
--- a/src/content_scripts/options.js
+++ b/src/content_scripts/options.js
@@ -4,6 +4,7 @@ import Mode from './common/mode';
import {
createElementWithContent,
generateQuickGuid,
+ getBrowserName,
htmlEncode,
httpRequest,
initL10n,
@@ -12,15 +13,6 @@ import {
showBanner,
} from './common/utils.js';
-var defaultMappingsEditor = ace.edit("defaultMappings");
-defaultMappingsEditor.setTheme("ace/theme/chrome");
-defaultMappingsEditor.setKeyboardHandler('ace/keyboard/vim');
-defaultMappingsEditor.getSession().setMode("ace/mode/javascript");
-defaultMappingsEditor.container.hide();
-defaultMappingsEditor.setReadOnly(true);
-defaultMappingsEditor.container.style.background="#f1f1f1";
-defaultMappingsEditor.$blockScrolling = Infinity;
-
var mappingsEditor = null;
function createMappingEditor(elmId) {
var _ace = ace.edit(elmId);
@@ -84,8 +76,13 @@ function createMappingEditor(elmId) {
return self;
}
-if (window.navigator.userAgent.indexOf("Firefox") !== -1) {
+if (getBrowserName() === "Firefox") {
+ document.querySelector("#localPathForSettings").style.display = "none";
+ document.querySelector("#proxySettings").style.display = "none";
+} else if (getBrowserName() === "Safari") {
+ document.querySelector("#localPathForSettings").style.display = "none";
document.querySelector("#proxySettings").style.display = "none";
+ document.querySelector("#donationDiv").style.display = "none";
}
var proxyModeSelect = document.querySelector("#proxyMode>select");
var proxyGroup = document.getElementById("proxyMode").parentElement;
@@ -250,7 +247,6 @@ function renderSettings(rs) {
}
var h = window.innerHeight / 2;
mappingsEditor.container.style.height = h + "px";
- defaultMappingsEditor.container.style.height = h + "px";
if (rs.snippets && rs.snippets.length) {
mappingsEditor.setValue(rs.snippets, -1);
} else {
@@ -298,22 +294,6 @@ document.querySelector('.infoPointer').onclick = function() {
}
};
-document.getElementById('showDefaultSettings').onclick = function() {
- if (defaultMappingsEditor.container.style.display !== "none") {
- defaultMappingsEditor.container.hide();
- mappingsEditor.container.style.width = "100%";
- } else {
- httpRequest({
- url: chrome.extension.getURL('/pages/default.js'),
- }, function(res) {
- defaultMappingsEditor.container.style.display = "inline-block";
- defaultMappingsEditor.setValue(res.text, -1);
- defaultMappingsEditor.container.style.width = "50%";
- });
- mappingsEditor.container.style.width = "50%";
- }
-};
-
function getURIPath(fn) {
if (fn.length && !/^\w+:\/\/\w+/i.test(fn) && fn.indexOf('file:///') === -1) {
fn = fn.replace(/\\/g, '/');
@@ -359,11 +339,16 @@ var basicMappings = ['d', 'R', 'f', 'E', 'e', 'x', 'gg', 'j', '/', 'n', 'r', 'k'
document.addEventListener("surfingkeys:defaultSettingsLoaded", function(evt) {
const { normal } = evt.detail;
basicMappings = basicMappings.map(function(w, i) {
- return {
- origin: w,
- annotation: normal.mappings.find(KeyboardUtils.encodeKeystroke(w)).meta.annotation
- };
- });
+ const binding = normal.mappings.find(KeyboardUtils.encodeKeystroke(w));
+ if (binding) {
+ return {
+ origin: w,
+ annotation: binding.meta.annotation
+ };
+ } else {
+ return null;
+ }
+ }).filter((m) => m !== null);;
});
function renderKeyMappings(rs) {
diff --git a/src/content_scripts/safari.js b/src/content_scripts/safari.js
new file mode 100644
index 000000000..509c28049
--- /dev/null
+++ b/src/content_scripts/safari.js
@@ -0,0 +1,3 @@
+import { start } from './content.js';
+
+start();
diff --git a/src/content_scripts/ui/command.js b/src/content_scripts/ui/command.js
index c5ba2a63e..b348a9204 100644
--- a/src/content_scripts/ui/command.js
+++ b/src/content_scripts/ui/command.js
@@ -1,4 +1,5 @@
import {
+ createElementWithContent,
showBanner,
showPopup,
} from '../common/utils.js';
diff --git a/src/content_scripts/ui/frontend.js b/src/content_scripts/ui/frontend.js
index 5eaef44d1..22272b5b2 100644
--- a/src/content_scripts/ui/frontend.js
+++ b/src/content_scripts/ui/frontend.js
@@ -3,6 +3,7 @@ import {
createElementWithContent,
generateQuickGuid,
getAnnotations,
+ getBrowserName,
getWordUnderCursor,
htmlEncode,
initL10n,
@@ -180,6 +181,25 @@ const Front = (function() {
var keystroke = document.getElementById('sk_keystroke');
var _display;
+ self.startInputGuard = () => {
+ if (getBrowserName() === "Safari") {
+ var inputGuard = setInterval(() => {
+ let input = null;
+ for (const a of document.querySelectorAll("input, textarea")) {
+ if (a.getBoundingClientRect().width) {
+ input = a;
+ break;
+ }
+ }
+ if (input && document.activeElement !== input) {
+ input.focus();
+ } else {
+ clearInterval(inputGuard);
+ }
+ console.log(inputGuard);
+ }, 100);
+ }
+ };
_actions['hidePopup'] = function() {
if (_display && _display.style.display !== "none") {
_display.style.display = "none";
@@ -198,6 +218,7 @@ const Front = (function() {
_display = td;
_display.style.display = "";
_display.onShow && _display.onShow(args);
+ self.startInputGuard();
}
function showElement(td, args) {
@@ -783,6 +804,7 @@ var Find = (function() {
}
};
input.focus();
+ Front.startInputGuard();
self.enter();
};
return self;
diff --git a/src/content_scripts/ui/omnibar.js b/src/content_scripts/ui/omnibar.js
index f73beab2c..e176df593 100644
--- a/src/content_scripts/ui/omnibar.js
+++ b/src/content_scripts/ui/omnibar.js
@@ -5,6 +5,7 @@ import { debounce } from 'lodash';
import {
constructSearchURL,
createElementWithContent,
+ getBrowserName,
htmlEncode,
parseAnnotation,
scrollIntoViewIfNeeded,
@@ -498,7 +499,7 @@ function createOmnibar(front, clipboard) {
if (b.hasOwnProperty('html')) {
li = self.createItemFromRawHtml(b);
} else if (b.hasOwnProperty('url') && b.url !== undefined) {
- if (window.navigator.userAgent.indexOf("Firefox") !== -1 && /^(place|data):/i.test(b.url)) {
+ if (getBrowserName() === "Firefox" && /^(place|data):/i.test(b.url)) {
return null;
}
li = self.createURLItem(b, rxp);
diff --git a/src/content_scripts/uiframe.js b/src/content_scripts/uiframe.js
index 3f8f668c8..2a4151c93 100644
--- a/src/content_scripts/uiframe.js
+++ b/src/content_scripts/uiframe.js
@@ -1,4 +1,5 @@
import {
+ getBrowserName,
getDocumentOrigin
} from './common/utils.js';
@@ -111,6 +112,9 @@ function createUiHost(onload) {
document.body.style.overflowY = _origOverflowY;
}
} else {
+ if (getBrowserName() === "Safari") {
+ ifr.focus();
+ }
if (document.body) {
document.body.style.animationFillMode = "none";
if (_origOverflowY === undefined) {
diff --git a/src/icons/128.png b/src/icons/128.png
index ee02e80e0..b46c2e0de 100644
Binary files a/src/icons/128.png and b/src/icons/128.png differ
diff --git a/src/icons/16.png b/src/icons/16.png
index 450173226..52a43fc01 100644
Binary files a/src/icons/16.png and b/src/icons/16.png differ
diff --git a/src/icons/48-x.png b/src/icons/48-x.png
index 638e41ef7..1287befe1 100644
Binary files a/src/icons/48-x.png and b/src/icons/48-x.png differ
diff --git a/src/icons/48.png b/src/icons/48.png
index 5d111ecff..6230059d1 100644
Binary files a/src/icons/48.png and b/src/icons/48.png differ
diff --git a/src/manifest.json b/src/manifest.json
index a143dcc9e..6ef1e0029 100644
--- a/src/manifest.json
+++ b/src/manifest.json
@@ -79,5 +79,5 @@
"pages/shadow.css",
"pages/default.css"
],
- "content_security_policy": "script-src 'self' https://www.google-analytics.com chrome-extension://aajlcoiaogpknhgninhopncaldipjdnp; object-src 'self'"
+ "content_security_policy": "script-src 'self' chrome-extension://aajlcoiaogpknhgninhopncaldipjdnp; object-src 'self'"
}
diff --git a/src/pages/ga.js b/src/pages/ga.js
deleted file mode 100644
index b028cf6d5..000000000
--- a/src/pages/ga.js
+++ /dev/null
@@ -1,6 +0,0 @@
-window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments);};ga.l=+new Date;
-ga('create', 'UA-108751049-1', {'siteSpeedSampleRate': 100});
-ga('set', 'checkProtocolTask', function(){});
-ga('set', 'location', 'http://surfingkeys.com/'+document.location.pathname);
-ga('set', 'dimension1', chrome.runtime.id);
-ga('send', 'pageview');
diff --git a/src/pages/markdown.html b/src/pages/markdown.html
index 268ad2c68..064629c0f 100644
--- a/src/pages/markdown.html
+++ b/src/pages/markdown.html
@@ -17,7 +17,5 @@
-
-