├── github1s ├── src │ ├── icons │ │ ├── icon128.png │ │ ├── icon16.png │ │ ├── icon160.png │ │ ├── icon38.png │ │ └── icon48.png │ ├── options │ │ ├── options.js │ │ ├── options.html │ │ ├── options.css │ │ └── pages.js │ ├── manifest.json │ ├── background │ │ └── background.js │ ├── js │ │ ├── common.js │ │ └── utils.js │ └── content │ │ └── content.js ├── extension.202105090813.zip ├── extension.202105261113.zip ├── extension.202108241012.zip ├── webpack.dev.js ├── .babelrc ├── webpack.options.js ├── webpack.prod.js ├── package.json ├── webpack.common.js ├── webpack.config.js └── webpack.config.bak.js ├── LICENSE ├── .gitignore ├── README.md └── images └── buymeacoffee.svg /github1s/src/icons/icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fhefh2015/GitHub1s_chrome_extension/HEAD/github1s/src/icons/icon128.png -------------------------------------------------------------------------------- /github1s/src/icons/icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fhefh2015/GitHub1s_chrome_extension/HEAD/github1s/src/icons/icon16.png -------------------------------------------------------------------------------- /github1s/src/icons/icon160.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fhefh2015/GitHub1s_chrome_extension/HEAD/github1s/src/icons/icon160.png -------------------------------------------------------------------------------- /github1s/src/icons/icon38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fhefh2015/GitHub1s_chrome_extension/HEAD/github1s/src/icons/icon38.png -------------------------------------------------------------------------------- /github1s/src/icons/icon48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fhefh2015/GitHub1s_chrome_extension/HEAD/github1s/src/icons/icon48.png -------------------------------------------------------------------------------- /github1s/extension.202105090813.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fhefh2015/GitHub1s_chrome_extension/HEAD/github1s/extension.202105090813.zip -------------------------------------------------------------------------------- /github1s/extension.202105261113.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fhefh2015/GitHub1s_chrome_extension/HEAD/github1s/extension.202105261113.zip -------------------------------------------------------------------------------- /github1s/extension.202108241012.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fhefh2015/GitHub1s_chrome_extension/HEAD/github1s/extension.202108241012.zip -------------------------------------------------------------------------------- /github1s/src/options/options.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import Pages from './pages'; 4 | 5 | 6 | ReactDOM.render( 7 | , 8 | document.getElementById('options') 9 | ); -------------------------------------------------------------------------------- /github1s/webpack.dev.js: -------------------------------------------------------------------------------- 1 | const { merge } = require('webpack-merge'); 2 | const config = require('./webpack.config.js'); 3 | const ExtensionReloader = require("webpack-extension-reloader"); 4 | 5 | module.exports = merge(config, { 6 | plugins: [ 7 | new ExtensionReloader() 8 | ], 9 | devtool: "source-map", 10 | }); -------------------------------------------------------------------------------- /github1s/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env", 4 | "@babel/preset-react" 5 | ], 6 | "plugins": [ 7 | [ 8 | "import",{ 9 | "libraryName":"antd", 10 | "libraryDirectory":"es", 11 | "style":"css" 12 | }], 13 | "@babel/plugin-transform-runtime", 14 | "@babel/plugin-proposal-class-properties" 15 | ] 16 | } -------------------------------------------------------------------------------- /github1s/src/options/options.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | GitHub1s Config 8 | 9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /github1s/src/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "update_url": "https://clients2.google.com/service/update2/crx", 3 | "manifest_version": 2, 4 | "homepage_url": "https://github.com/conwnet/github1s", 5 | "name": "GitHub1s", 6 | "description": "One second to read GitHub code with VS Code", 7 | "version": "0.3.8", 8 | "icons": { 9 | "16": "icons/icon16.png", 10 | "48": "icons/icon48.png", 11 | "128": "icons/icon128.png" 12 | }, 13 | "browser_action": {}, 14 | "options_ui": { 15 | "page": "options.html", 16 | "open_in_tab": true 17 | }, 18 | "background": { 19 | "scripts": [ 20 | "js/background.js" 21 | ], 22 | "persistent": true 23 | }, 24 | "content_scripts": [ 25 | { 26 | "matches": [ 27 | "*://github.com/*" 28 | ], 29 | "js": [ 30 | "js/content.js" 31 | ], 32 | "run_at": "document_end" 33 | } 34 | ], 35 | "permissions": [ 36 | "storage", 37 | "contextMenus", 38 | "activeTab" 39 | ] 40 | } -------------------------------------------------------------------------------- /github1s/src/options/options.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #f0f2f5 !important; 3 | } 4 | 5 | .container { 6 | padding-bottom: 60px; 7 | } 8 | 9 | .logo { 10 | width: 72px; 11 | height: 72px; 12 | background: url(../icons/icon160.png) no-repeat center center; 13 | background-size: 100% 100%; 14 | margin: 0 auto; 15 | margin-top: 40px; 16 | } 17 | 18 | .text { 19 | padding: 10px 0; 20 | font-size: 32px; 21 | color: #000; 22 | text-align: center; 23 | } 24 | 25 | .mt20 { 26 | margin-top: 20px; 27 | } 28 | 29 | .mb10 { 30 | margin-bottom: 10px; 31 | } 32 | 33 | .prview_btn { 34 | position: relative; 35 | display: inline-block; 36 | padding: 5px 16px; 37 | font-size: 14px; 38 | font-weight: 500; 39 | line-height: 20px; 40 | white-space: nowrap; 41 | vertical-align: middle; 42 | cursor: pointer; 43 | -webkit-user-select: none; 44 | -moz-user-select: none; 45 | -ms-user-select: none; 46 | user-select: none; 47 | border: 1px solid transparent; 48 | border-radius: 6px; 49 | -webkit-appearance: none; 50 | -moz-appearance: none; 51 | appearance: none; 52 | } 53 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 fhefh2015 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /github1s/webpack.options.js: -------------------------------------------------------------------------------- 1 | const { merge } = require('webpack-merge'); 2 | const common = require('./webpack.common.js'); 3 | const { resolve } = require('path'); 4 | 5 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 6 | const { CleanWebpackPlugin } = require('clean-webpack-plugin'); 7 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 8 | const TerserPlugin = require('terser-webpack-plugin'); 9 | const CopyWebpackPlugin = require("copy-webpack-plugin"); 10 | const isDev = "development" == process.env.NODE_ENV ? true : false; 11 | 12 | module.exports = merge(common, { 13 | plugins: [ 14 | new MiniCssExtractPlugin({ 15 | filename: 'css/[name].[contenthash:7].css', 16 | }), 17 | new HtmlWebpackPlugin({ 18 | template: './src/options/options.html', 19 | filename: 'options.html', 20 | favicon: './src/icons/icon160.png', 21 | inject: 'body', 22 | chunks: ['options'], 23 | minify: { 24 | collapseWhitespace: true, 25 | removeComments: true, 26 | } 27 | }), 28 | new CopyWebpackPlugin({ 29 | patterns: [ 30 | { from: resolve(__dirname, 'src/icons'), to: resolve(__dirname, 'build/icons') }, 31 | { from: resolve(__dirname, 'src/manifest.json'), to: resolve(__dirname, 'build') }, 32 | ], 33 | }), 34 | new CleanWebpackPlugin(), 35 | ], 36 | mode: isDev ? 'development' : 'production', 37 | target: 'web', 38 | devtool: isDev ? "eval-source-map" : "source-map", 39 | devServer: { 40 | contentBase: resolve(__dirname, 'dist'), 41 | compress: true, 42 | open: false, 43 | hot: true, 44 | port: 9999, 45 | } 46 | }); -------------------------------------------------------------------------------- /github1s/webpack.prod.js: -------------------------------------------------------------------------------- 1 | const { merge } = require('webpack-merge'); 2 | const common = require('./webpack.common.js'); 3 | const { resolve } = require('path'); 4 | 5 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 6 | const { CleanWebpackPlugin } = require('clean-webpack-plugin'); 7 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 8 | const TerserPlugin = require('terser-webpack-plugin'); 9 | const CopyWebpackPlugin = require("copy-webpack-plugin"); 10 | 11 | module.exports = merge(common, { 12 | plugins: [ 13 | new MiniCssExtractPlugin({ 14 | filename: 'css/[name].[contenthash:7].css', 15 | }), 16 | new TerserPlugin({ 17 | exclude: /node_modules/, 18 | terserOptions: { 19 | warnings: false, 20 | compress: { 21 | drop_console: true, 22 | drop_debugger: true, 23 | pure_funcs: ['console.log'] // 移除console 24 | } 25 | } 26 | }), 27 | new HtmlWebpackPlugin({ 28 | template: './src/options/options.html', 29 | filename: 'options.html', 30 | favicon: './src/icons/icon160.png', 31 | inject: 'body', 32 | chunks: ['options'], 33 | minify: { 34 | collapseWhitespace: true, 35 | removeComments: true, 36 | } 37 | }), 38 | new CopyWebpackPlugin({ 39 | patterns: [ 40 | { from: resolve(__dirname, 'src/icons'), to: resolve(__dirname, 'build/icons') }, 41 | { from: resolve(__dirname, 'src/manifest.json'), to: resolve(__dirname, 'build') }, 42 | ], 43 | }), 44 | new CleanWebpackPlugin(), 45 | ], 46 | mode: 'production', 47 | // devtool: "source-map", 48 | }); -------------------------------------------------------------------------------- /github1s/src/background/background.js: -------------------------------------------------------------------------------- 1 | import { getQueryTab, getItem, getHref, setItemByKey } from '../js/utils'; 2 | 3 | // chrome.browserAction.onClicked.addListener(async () => { 4 | 5 | // const tabs = await getQueryTab(); 6 | // const form = await getItem("form"); 7 | // const url = tabs[0]["url"]; 8 | 9 | // const href = await getHref(form, url); 10 | // createTab(href); 11 | // }); 12 | 13 | chrome.extension.onRequest.addListener((request) => { 14 | 15 | const { href, action } = request; 16 | 17 | console.log("chrome runtime: ", request); 18 | 19 | if (action == 'createContextMenuItem') { 20 | 21 | const { button_title, href } = request; 22 | 23 | setItemByKey("right_menu_create", 1); 24 | 25 | chrome.contextMenus.create({ 26 | title: `Open with ${button_title}`, 27 | type: 'normal', 28 | contexts: ['page'], 29 | onclick: function (data) { 30 | 31 | const pageUrl = data['pageUrl']; 32 | createTab(href); 33 | 34 | }, 35 | documentUrlPatterns: ['https://*.github.com/*/*'] 36 | }); 37 | } 38 | 39 | if (action == 'keyboard') { 40 | createTab(href); 41 | } 42 | }); 43 | 44 | // chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) { 45 | // const { status } = changeInfo; 46 | 47 | // if (status == "complete") { 48 | // chrome.tabs.sendMessage(tabId, "url-update"); 49 | // } 50 | 51 | // }); 52 | 53 | 54 | async function createTab(href) { 55 | 56 | const tabs = await getQueryTab(); 57 | 58 | if (tabs) { 59 | const index = tabs[0]['index']; 60 | chrome.tabs.create({ 61 | index: index + 1, 62 | url: href 63 | }); 64 | } else { 65 | chrome.tabs.create({ 66 | url: href 67 | }); 68 | } 69 | } -------------------------------------------------------------------------------- /github1s/src/js/common.js: -------------------------------------------------------------------------------- 1 | export const validateMessages = { 2 | required: "${name} is a required field", 3 | }; 4 | 5 | export const checkBoxItems = [ 6 | { 7 | name: "new_tab", 8 | desc: "Open with new tab", 9 | note: "", 10 | }, 11 | { 12 | name: "right_menu", 13 | desc: "Open with Right-click menu", 14 | note: "This feature requires a browser restart", 15 | }, 16 | { 17 | name: "is_private", 18 | desc: "Allow use it in private repositories", 19 | note: "Please make sure your project is a private repository, otherwise the settings will not take effect" 20 | }, 21 | { 22 | name: "use_keyboard", 23 | desc: "Allow use it with keyboard_shortcuts", 24 | note: "Keyboard shortcuts disabled by default" 25 | }, 26 | ]; 27 | 28 | export const selectBoxItems = [ 29 | { 30 | name: "CodeSandbox", 31 | url: "https://codesandbox.io/s/github/", 32 | index: 0, 33 | }, 34 | { 35 | name: "Github1s", 36 | url: "https://github1s.com/", 37 | index: 1, 38 | }, 39 | { 40 | name: "Gitpod", 41 | url: "https://gitpod.io/#https://github.com/", 42 | index: 2, 43 | }, 44 | { 45 | name: "Repl.it", 46 | url: "https://repl.it/github/", 47 | index: 3, 48 | }, 49 | { 50 | name: "Vscode", 51 | url: "vscode://vscode.git/clone?url=https://github.com/", 52 | index: 4, 53 | }, 54 | { 55 | name: "Stackblitz", 56 | // url: "https://githubblitz.com/", 57 | url: "https://stackblitz.com/github/", 58 | index: 5, 59 | }, 60 | { 61 | name: "GitHub.Dev", 62 | url: "https://github.dev/", 63 | index: 6, 64 | } 65 | ]; 66 | 67 | export const defaultSetting = { 68 | "input_url": "https://github1s.com", 69 | "button_title": "Github1s", 70 | "button_title_color": "#ffffff", 71 | "button_background_color": "#2ea44f", 72 | "check_box": { 73 | "new_tab": 1, 74 | "right_menu": 0, 75 | "is_private": 0, 76 | "use_keyboard": 0, 77 | }, 78 | "web_service": 1, 79 | "keyboard_shortcuts": "alt+shift+g", 80 | }; -------------------------------------------------------------------------------- /github1s/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "github1s", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "webpack --config webpack.dev.js --mode=development --watch", 8 | "dev:options": "cross-env NODE_ENV=production webpack-dev-server --config webpack.options.js", 9 | "build": "webpack --config webpack.config.js --mode=production", 10 | "zip": "zip -r extension.$(date +%Y%m%d%H%M).zip dist/" 11 | }, 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": { 15 | "antd": "^3.26.20", 16 | "hotkeys-js": "^3.8.2", 17 | "react": "^16.14.0", 18 | "react-dom": "^16.14.0" 19 | }, 20 | "devDependencies": { 21 | "@babel/core": "^7.12.16", 22 | "@babel/plugin-proposal-class-properties": "^7.12.13", 23 | "@babel/plugin-syntax-jsx": "^7.12.13", 24 | "@babel/plugin-transform-runtime": "^7.12.15", 25 | "@babel/preset-env": "^7.12.16", 26 | "@babel/preset-react": "^7.12.13", 27 | "@webpack-cli/serve": "^1.3.0", 28 | "babel-core": "^6.26.3", 29 | "babel-loader": "^8.2.2", 30 | "babel-plugin-import": "^1.13.3", 31 | "clean-webpack-plugin": "^3.0.0", 32 | "copy-webpack-plugin": "^6.0.3", 33 | "core-js": "^2.6.12", 34 | "cross-env": "^7.0.3", 35 | "css-loader": "^5.0.2", 36 | "cssnano": "^4.1.10", 37 | "eslint": "^7.20.0", 38 | "eslint-config-airbnb-base": "^14.2.1", 39 | "eslint-loader": "^4.0.2", 40 | "eslint-plugin-import": "^2.22.1", 41 | "file-loader": "^6.2.0", 42 | "html-loader": "^1.3.2", 43 | "html-webpack-plugin": "4.5.2", 44 | "less-loader": "^8.0.0", 45 | "mini-css-extract-plugin": "^0.9.0", 46 | "postcss": "^8.2.6", 47 | "postcss-loader": "^4.2.0", 48 | "postcss-preset-env": "^6.7.0", 49 | "style-loader": "^2.0.0", 50 | "terser-webpack-plugin": "^5.1.1", 51 | "url-loader": "^4.1.1", 52 | "webpack": "^4.43.0", 53 | "webpack-cli": "^3.3.12", 54 | "webpack-dev-server": "3.11.2", 55 | "webpack-extension-reloader": "^1.1.4", 56 | "webpack-merge": "^5.7.3" 57 | } 58 | } -------------------------------------------------------------------------------- /github1s/src/js/utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * r:react state data 3 | * c:chrome store data 4 | */ 5 | import { checkBoxItems, defaultSetting, selectBoxItems } from './common'; 6 | 7 | export function r2c(r) { 8 | let items = r["check_box"]; 9 | 10 | if (typeof items === "undefined") { 11 | throw Error("check_box undefined"); 12 | } 13 | 14 | let temp = {}; 15 | 16 | if (typeof items !== 'undefined') { 17 | 18 | for (let m = 0; m < checkBoxItems.length; m++) { 19 | temp[checkBoxItems[m]["name"]] = 0; 20 | } 21 | 22 | for (let n = 0; n < items.length; n++) { 23 | temp[items[n]] = 1; 24 | } 25 | } 26 | 27 | return Object.assign({}, r, { 28 | "check_box": temp 29 | }); 30 | } 31 | 32 | export function c2r(c) { 33 | let items = c["check_box"]; 34 | if (typeof items === "undefined") { 35 | throw Error("check_box undefined"); 36 | } 37 | 38 | let temp = []; 39 | 40 | if (typeof items !== 'undefined') { 41 | for (let i in items) { 42 | if (items[i] == 1) { 43 | temp.push(i); 44 | } 45 | } 46 | } 47 | 48 | return Object.assign({}, c, { 49 | "check_box": temp 50 | }); 51 | } 52 | 53 | export function setItemByKey(key, value) { 54 | let obj = {}; 55 | obj[key] = value; 56 | chrome.storage.sync.set(obj); 57 | chrome.storage.local.set(obj); 58 | } 59 | 60 | export function getItem(obj) { 61 | return new Promise(function (resolve, reject) { 62 | chrome.storage.sync.get(obj, function (result) { 63 | if (result) { 64 | resolve(result[obj]); 65 | } 66 | reject(false); 67 | }); 68 | }); 69 | } 70 | 71 | export async function fixOldVersion() { 72 | let form = await getItem('form'); 73 | 74 | if (form == undefined) { 75 | formReset(); 76 | return defaultSetting; 77 | } 78 | 79 | return Object.assign({}, defaultSetting, form); 80 | } 81 | 82 | export function formReset() { 83 | setItemByKey("form", defaultSetting); 84 | setItemByKey("right_menu_create", 0); 85 | } 86 | 87 | export function getQueryTab() { 88 | return new Promise(function (resolve, reject) { 89 | chrome.tabs.query({ 90 | active: true, 91 | currentWindow: true 92 | }, (tabs) => { 93 | if (tabs) { 94 | resolve(tabs); 95 | } else { 96 | reject(false); 97 | } 98 | }); 99 | }); 100 | } 101 | 102 | export function getHref(data, siteURL, inputURL) { 103 | 104 | const url = new URL(siteURL); 105 | const path = url.pathname.split('/').slice(1).join('/'); 106 | // const [userName, repository] = url.pathname.split('/').slice(1, 3); 107 | 108 | let href; 109 | const { 110 | web_service 111 | } = data; 112 | 113 | switch (web_service) { 114 | case 1: 115 | href = `${inputURL}/${path}`; 116 | break; 117 | case 0: 118 | case 2: 119 | case 3: 120 | case 4: 121 | case 5: 122 | case 6: 123 | href = `${selectBoxItems[web_service]["url"]}${path}`; 124 | break; 125 | } 126 | 127 | return href; 128 | } 129 | 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /github1s/src/content/content.js: -------------------------------------------------------------------------------- 1 | import hotkeys from 'hotkeys-js'; 2 | import { fixOldVersion, getHref, getItem } from '../js/utils'; 3 | 4 | 5 | init(); 6 | 7 | function insertGitHub1sButton(setting) { 8 | const { 9 | input_url, 10 | button_title, 11 | button_title_color, 12 | button_background_color, 13 | check_box, 14 | } = setting; 15 | 16 | const localURL = window.location.href; 17 | const href = getHref(setting, localURL, input_url); 18 | 19 | const target = (check_box["new_tab"] == 1) ? "_blank" : "_self"; 20 | 21 | // const insertNode = document.querySelector('.details-overlay.d-block'); 22 | const insertNode = document.querySelector(".btn.d-none.d-md-block"); 23 | 24 | if (insertNode) { 25 | const layoutClass = insertNode.classList.contains('ml-2') ? 'ml-2' : 'mr-2'; 26 | const btn = ` 27 | ${button_title} 28 | `; 29 | 30 | // insertNode.insertAdjacentHTML('afterend', btn); 31 | insertNode.insertAdjacentHTML('beforebegin', btn); 32 | } 33 | } 34 | 35 | function ensureGitHub1sButtonExists(setting) { 36 | if (!document.getElementById('github1s_kkk')) { 37 | insertGitHub1sButton(setting); 38 | } 39 | } 40 | 41 | async function init() { 42 | let setting = await fixOldVersion(); 43 | const localURL = window.location.href; 44 | 45 | const { 46 | input_url, 47 | button_title, 48 | check_box, 49 | keyboard_shortcuts 50 | } = setting; 51 | 52 | const href = getHref(setting, localURL, input_url); 53 | 54 | const privateElems = document.querySelectorAll('#js-repo-pjax-container .Label'); 55 | let judge_is_private = false; 56 | 57 | judge_is_private = Array.from(privateElems).some(item => { 58 | return (item.textContent.trim().toLowerCase() == "private"); 59 | }); 60 | 61 | if (judge_is_private) { 62 | if (check_box["is_private"] == 0) { 63 | return; 64 | } 65 | } 66 | 67 | const mutationObserver = new MutationObserver(() => ensureGitHub1sButtonExists(setting)); 68 | mutationObserver.observe(document.body, { childList: true, subtree: true }); 69 | 70 | if (check_box["use_keyboard"]) { 71 | const key = keyboard_shortcuts.replace(/\s/ig, "").toLowerCase(); 72 | hotkeys(key, function (event, handler) { 73 | // Prevent the default refresh event under WINDOWS system 74 | event.preventDefault(); 75 | chrome.extension.sendRequest({ 76 | "action": "keyboard", 77 | "href": href, 78 | "key": key, 79 | }); 80 | }); 81 | } 82 | 83 | if (check_box["right_menu"]) { 84 | const right_menu_create = await getItem("right_menu_create"); 85 | 86 | if (right_menu_create == 1) { 87 | return; 88 | } else { 89 | chrome.extension.sendRequest({ 90 | "action": "createContextMenuItem", 91 | "href": href, 92 | "button_title": button_title 93 | }); 94 | } 95 | } 96 | } 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.toptal.com/developers/gitignore/api/node,vscode,macos 3 | # Edit at https://www.toptal.com/developers/gitignore?templates=node,vscode,macos 4 | 5 | ### macOS ### 6 | # General 7 | .DS_Store 8 | .AppleDouble 9 | .LSOverride 10 | 11 | # Icon must end with two \r 12 | Icon 13 | 14 | 15 | # Thumbnails 16 | ._* 17 | 18 | # Files that might appear in the root of a volume 19 | .DocumentRevisions-V100 20 | .fseventsd 21 | .Spotlight-V100 22 | .TemporaryItems 23 | .Trashes 24 | .VolumeIcon.icns 25 | .com.apple.timemachine.donotpresent 26 | 27 | # Directories potentially created on remote AFP share 28 | .AppleDB 29 | .AppleDesktop 30 | Network Trash Folder 31 | Temporary Items 32 | .apdisk 33 | 34 | ### Node ### 35 | # Logs 36 | logs 37 | *.log 38 | npm-debug.log* 39 | yarn-debug.log* 40 | yarn-error.log* 41 | lerna-debug.log* 42 | 43 | # Diagnostic reports (https://nodejs.org/api/report.html) 44 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 45 | 46 | # Runtime data 47 | pids 48 | *.pid 49 | *.seed 50 | *.pid.lock 51 | 52 | # Directory for instrumented libs generated by jscoverage/JSCover 53 | lib-cov 54 | 55 | # Coverage directory used by tools like istanbul 56 | coverage 57 | *.lcov 58 | 59 | # nyc test coverage 60 | .nyc_output 61 | 62 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 63 | .grunt 64 | 65 | # Bower dependency directory (https://bower.io/) 66 | bower_components 67 | 68 | # node-waf configuration 69 | .lock-wscript 70 | 71 | # Compiled binary addons (https://nodejs.org/api/addons.html) 72 | build/Release 73 | 74 | # Dependency directories 75 | node_modules/ 76 | jspm_packages/ 77 | 78 | # TypeScript v1 declaration files 79 | typings/ 80 | 81 | # TypeScript cache 82 | *.tsbuildinfo 83 | 84 | # Optional npm cache directory 85 | .npm 86 | 87 | # Optional eslint cache 88 | .eslintcache 89 | 90 | # Optional stylelint cache 91 | .stylelintcache 92 | 93 | # Microbundle cache 94 | .rpt2_cache/ 95 | .rts2_cache_cjs/ 96 | .rts2_cache_es/ 97 | .rts2_cache_umd/ 98 | 99 | # Optional REPL history 100 | .node_repl_history 101 | 102 | # Output of 'npm pack' 103 | *.tgz 104 | 105 | # Yarn Integrity file 106 | .yarn-integrity 107 | 108 | # dotenv environment variables file 109 | .env 110 | .env.test 111 | .env*.local 112 | 113 | # parcel-bundler cache (https://parceljs.org/) 114 | .cache 115 | .parcel-cache 116 | 117 | # Next.js build output 118 | .next 119 | 120 | # Nuxt.js build / generate output 121 | .nuxt 122 | dist 123 | 124 | # Gatsby files 125 | .cache/ 126 | # Comment in the public line in if your project uses Gatsby and not Next.js 127 | # https://nextjs.org/blog/next-9-1#public-directory-support 128 | # public 129 | 130 | # vuepress build output 131 | .vuepress/dist 132 | 133 | # Serverless directories 134 | .serverless/ 135 | 136 | # FuseBox cache 137 | .fusebox/ 138 | 139 | # DynamoDB Local files 140 | .dynamodb/ 141 | 142 | # TernJS port file 143 | .tern-port 144 | 145 | # Stores VSCode versions used for testing VSCode extensions 146 | .vscode-test 147 | 148 | ### vscode ### 149 | .vscode/* 150 | !.vscode/settings.json 151 | !.vscode/tasks.json 152 | !.vscode/launch.json 153 | !.vscode/extensions.json 154 | *.code-workspace 155 | 156 | # End of https://www.toptal.com/developers/gitignore/api/node,vscode,macos -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GitHub1s_chrome_extension 2 | 3 | # Introduction 4 | 5 | [![Page Views Count](https://badges.toozhao.com/badges/01EYB0JV8TJM3A7E0TK240SB29/green.svg)](https://badges.toozhao.com/stats/01EYB0JV8TJM3A7E0TK240SB29 "Get your own page views count badge on badges.toozhao.com") 6 | 7 | Easier and faster to use Github1s 8 | 9 | Based on conwnet/github1s, Thanks! 10 | 11 | One second to read GitHub code with VS Code. 12 | 13 | https://github.com/conwnet/github1s 14 | 15 | --- 16 | 17 | # chrome extension 18 | 19 | https://chrome.google.com/webstore/detail/github1s/lodjfmkfbfkpdhnhkcdcoonghhghbkhe 20 | 21 | # safari extension 22 | 23 | https://github.com/code4you2021/GitHub1s-For-Safari-Extension 24 | 25 | # Buy Me A Coffee 26 | 27 | Love the project? Wanna buy me a coffee? (or a beer :D) 28 | 29 | [![alt text](./images/buymeacoffee.svg)](https://www.buymeacoffee.com/fhefh2015) 30 | 31 | --- 32 | 33 | # Noted 34 | 35 | ``` 36 | Why does my chrome extension ask for history permissions? 37 | 38 | This is the standard warning for the "tabs" permission. 39 | It allows you to query, and be notified of changes, to URLs of all tabs. This allows you to spy on the user's history in real time - even if you don't have access to the browser's own history log. 40 | 41 | Note that "tabs" permission is not required in most cases. Providing access to URLs is basically the only reason to include it. You can use most of the tabs API without it, and can get access to current tab without warning using the "activeTab" permission. 42 | ``` 43 | 44 | manifest - Why does my chrome extension ask for history permissions? - Stack Overflow 45 | 46 | https://stackoverflow.com/questions/40660407/why-does-my-chrome-extension-ask-for-history-permissions 47 | 48 | I'm so sorry for that, i have changed the permission to activeTab. 49 | 50 | --- 51 | 52 | # Tampermonkey 53 | 54 | https://greasyfork.org/zh-CN/scripts/421412-%E4%B8%80%E9%94%AE%E5%BC%80%E5%90%AFgithub1s%E9%A1%B5%E9%9D%A2 55 | 56 | # Bookmarklet 57 | 58 | ```javascript 59 | javascript: window.location.href = window.location.href.replace( 60 | "github.com", 61 | "github1s.com" 62 | ); 63 | ``` 64 | 65 | # Preview 66 | 67 | ![nLqP6Fx](https://user-images.githubusercontent.com/14891797/108682902-de62ea00-752b-11eb-8572-4b66268f422d.png) 68 | ![NXNTz7P](https://i.imgur.com/NXNTz7P.png) 69 | ![iNomSiR](https://i.imgur.com/iNomSiR.png) 70 | ![BU6atl0](https://i.imgur.com/BU6atl0.png) 71 | 72 | # History 73 | 74 | v0.2.1 75 | 76 | add customization options 77 | 78 | v0.2.2 79 | 80 | add 'Open with new tab' option 81 | 82 | v0.2.3 83 | 84 | add 'Open with Right-click menu' option 85 | 86 | v0.2.4 87 | 88 | add 'Allow use of GitHub1s in private repositories' option 89 | 90 | v0.2.5 91 | 92 | add 'Switching to use Gitpod' option 93 | 94 | v0.3.0 95 | 96 | Configuration page UI modification 97 | 98 | Add the option to use keyboard shortcut keys 99 | 100 | v0.3.1 101 | 102 | Fix the problem of not being able to customize URLs 103 | 104 | v0.3.2 105 | 106 | Fix the problem that GitHub Pjax loading makes it impossible to use GitHub1s 107 | 108 | v0.3.3 109 | 110 | v0.3.4 111 | 112 | fix bugs 113 | 114 | v0.3.5 115 | 116 | Fix the button not appearing problem 117 | 118 | v0.3.6 119 | 120 | Add stackblitz.com support 121 | 122 | Use GitHub1s without logging into Github 123 | -------------------------------------------------------------------------------- /github1s/webpack.common.js: -------------------------------------------------------------------------------- 1 | const { resolve } = require('path'); 2 | 3 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 4 | const webpack = require('webpack'); 5 | 6 | const isDev = "development" == process.env.NODE_ENV ? true : false; 7 | 8 | /** 9 | * loader: 10 | * 1.下载 11 | * 2.使用配置loader 12 | * 13 | * plugin: 14 | * 1.下载 15 | * 2.引入 16 | * 3.配置使用 17 | */ 18 | 19 | module.exports = { 20 | // 入口 21 | entry: { 22 | options: './src/options/options.js', 23 | background: './src/background/background.js', 24 | content: './src/content/content.js', 25 | }, 26 | // 输出路径配置 27 | output: { 28 | // 输出文件名 29 | filename: 'js/[name].js', 30 | // 输出文件路径 31 | path: resolve(__dirname, 'dist') 32 | }, 33 | // loader配置,将非js文件翻译成js文件 34 | module: { 35 | rules: [ 36 | //需要匹配的文件 37 | // js语法检查 38 | { 39 | test: /\.(js|jsx)$/, 40 | // 只检查自己写的源代码,第三方的库是不用检查的 41 | exclude: /node_modules/, 42 | use: [ 43 | { 44 | /** 45 | * 解决js代码对浏览器兼容问题 46 | * @babel/preset-env 基本js兼容性处理,只能转换基本语法,不能转换Promise 47 | * @babel/polyfill 将兼容性代码完全引入,体积大 48 | * core-js 按需引用 49 | */ 50 | loader: 'babel-loader', 51 | 52 | }, 53 | // { 54 | // loader: 'eslint-loader', 55 | // options: { 56 | // // 自动修复eslint的错误 57 | // fix: true, 58 | // } 59 | // } 60 | ], 61 | }, 62 | { 63 | //匹配css文件类型 64 | test: /\.css$/, 65 | // 使用哪个loader进行转换 66 | //调用loader顺序,从右至左,从下到上 依次执行 67 | use: [ 68 | //创建 15 | 16 | 17 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 59 | 89 | 119 | 131 | 141 | 151 | 161 | 171 | 172 | 173 | 174 | --------------------------------------------------------------------------------