├── .editorconfig ├── .eslintrc.js ├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── __static ├── app │ ├── cache.manifest │ ├── ddms_frame_callback.html │ ├── html │ │ ├── bookmark.html │ │ ├── components.html │ │ ├── donate.html │ │ ├── main.html │ │ ├── scripts.html │ │ ├── sourcecode.html │ │ └── styles.html │ ├── index.html │ ├── resources │ │ ├── css │ │ │ ├── bootstrap.min.css │ │ │ ├── font-awesome.min.css │ │ │ ├── prettify.css │ │ │ └── style.css │ │ ├── fonts │ │ │ ├── Dressedless_Three.svg │ │ │ ├── Dressedless_Three.ttf │ │ │ ├── FontAwesome.otf │ │ │ ├── fontawesome-webfont.eot │ │ │ ├── fontawesome-webfont.svg │ │ │ ├── fontawesome-webfont.ttf │ │ │ ├── fontawesome-webfont.woff │ │ │ └── fontawesome-webfont.woff2 │ │ └── images │ │ │ ├── codelf_logo.png │ │ │ ├── paypal.png │ │ │ ├── twohardtings.jpg │ │ │ ├── wechatpay.jpg │ │ │ └── zhifubao.png │ ├── scss │ │ ├── _animate.scss │ │ ├── _bookmark.scss │ │ ├── _components.scss │ │ ├── _donate.scss │ │ ├── _main.scss │ │ ├── _sourcecode.scss │ │ ├── _util.scss │ │ └── style.scss │ ├── src │ │ ├── App.js │ │ ├── AppBundle.js │ │ ├── Util.js │ │ ├── lib │ │ │ ├── all.js │ │ │ ├── bootstrap.min.js │ │ │ ├── clipboard.min.js │ │ │ ├── fastclick.js │ │ │ ├── jquery.highlight.js │ │ │ ├── jquery.min.js │ │ │ ├── lovefield.min.js │ │ │ ├── prettify.js │ │ │ └── tether.min.js │ │ ├── model │ │ │ ├── BookmarkModel.js │ │ │ ├── DDMSModel.js │ │ │ ├── Database.js │ │ │ ├── Model.js │ │ │ ├── SearchcodeModel.js │ │ │ └── YoudaoTranslateModel.js │ │ └── view │ │ │ ├── BookmarkView.js │ │ │ └── View.js │ └── sw.js ├── data │ └── repos.json └── images │ ├── codelf_logo.png │ ├── demo1.jpg │ ├── demo2.jpg │ ├── paypal.png │ ├── twohardtings.png │ ├── twohardtings2.png │ ├── wechatpay.jpg │ └── zhifubao.png ├── app ├── ddms_frame_callback.html ├── index.html └── opensearch.xml ├── assets ├── codelf_logo.psd ├── fonts │ ├── Dressedless_Three.svg │ ├── Dressedless_Three.ttf │ ├── FontAwesome.otf │ ├── LatoLatin-Bold.woff2 │ ├── LatoLatin-BoldItalic.woff2 │ ├── LatoLatin-Italic.woff2 │ ├── LatoLatin-Regular.woff2 │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ └── fontawesome-webfont.woff2 └── images │ ├── codelf_logo.png │ ├── paypal.png │ ├── twohardtings.jpg │ ├── wechatdonate.jpg │ ├── wechatpay.jpg │ └── zhifubao.png ├── babel.config.js ├── build-system ├── build.js ├── clean.js ├── default.js ├── dist.js ├── lint.js ├── server.js └── util.js ├── dist ├── css │ ├── app.css │ ├── app.f1364fce.css │ ├── lib.b0f67b98.css │ ├── lib.css │ └── themes │ │ └── default │ │ └── assets │ │ ├── fonts │ │ ├── brand-icons.eot │ │ ├── brand-icons.svg │ │ ├── brand-icons.ttf │ │ ├── brand-icons.woff │ │ ├── brand-icons.woff2 │ │ ├── icons.eot │ │ ├── icons.otf │ │ ├── icons.svg │ │ ├── icons.ttf │ │ ├── icons.woff │ │ ├── icons.woff2 │ │ ├── outline-icons.eot │ │ ├── outline-icons.svg │ │ ├── outline-icons.ttf │ │ ├── outline-icons.woff │ │ └── outline-icons.woff2 │ │ └── images │ │ └── flags.png ├── ddms_frame_callback.html ├── fonts │ ├── Dressedless_Three.svg │ ├── Dressedless_Three.ttf │ ├── FontAwesome.otf │ ├── LatoLatin-Bold.woff2 │ ├── LatoLatin-BoldItalic.woff2 │ ├── LatoLatin-Italic.woff2 │ ├── LatoLatin-Regular.woff2 │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ └── fontawesome-webfont.woff2 ├── images │ ├── codelf_logo.f4ae25bd.png │ ├── codelf_logo.png │ ├── paypal.69412e83.png │ ├── paypal.png │ ├── twohardtings.0db8462a.jpg │ ├── twohardtings.jpg │ ├── wechatdonate.3ba3a9d8.jpg │ ├── wechatdonate.jpg │ ├── wechatpay.5f11f80c.jpg │ ├── wechatpay.jpg │ ├── zhifubao.70c19370.png │ └── zhifubao.png ├── index.html ├── js │ ├── app.792fa086.js │ ├── app.js │ ├── app.js.map │ ├── lib.5e430a5b.js │ └── lib.js ├── opensearch.xml └── sw.js ├── gulpfile.js ├── lib.config.js ├── package.json ├── src ├── App.js ├── components │ ├── Bookmark.js │ ├── Copybook.js │ ├── Donate.js │ ├── Doodle.js │ ├── Loading.js │ ├── SearchBar.js │ ├── SearchError.js │ ├── SourceCode.js │ ├── Suggestion.js │ ├── TitleLogo.js │ ├── VariableItem.js │ ├── VariableList.js │ └── hooks │ │ └── useCodeHighlighting.js ├── constants │ └── Configs.js ├── containers │ ├── CopybookContainer.js │ ├── MainContainer.js │ ├── NavBarContainer.js │ └── NoticeContainer.js ├── models │ ├── AppModel.js │ ├── BaseModel.js │ ├── CopybookModel.js │ ├── DDMSModel.js │ ├── ErrorModel.js │ ├── SearchCodeModel.js │ ├── Store.js │ └── metadata │ │ ├── BaiduTranslateData.js │ │ ├── BingTranslateData.js │ │ ├── BookmarkData.js │ │ ├── GitHubData.js │ │ └── YoudaoTranslateData.js ├── sw.js ├── utils │ ├── FormHandler.js │ ├── HashHandler.js │ ├── JSONP.js │ ├── LocalStorage.js │ ├── Navigator.js │ ├── Param.js │ ├── Tools.js │ └── TranslateHandler.js └── vendors │ ├── prettify.css │ └── prettify.js ├── styles ├── _animation.scss ├── _common.scss ├── _components.scss ├── _constants.scss ├── _containers.scss ├── _copybook-container.scss ├── _donate.scss ├── _doodle.scss ├── _logo.scss ├── _main-container.scss ├── _nav-bar-container.scss ├── _notice-container.scss ├── _source-code.scss ├── _utils.scss └── app.scss └── webpack.config.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'extends': [ 3 | 'eslint:recommended', 4 | 'plugin:react/recommended' 5 | ], 6 | 'plugins': [ 7 | 'react-hooks' 8 | ], 9 | 'rules': { 10 | 'no-unused-vars': [2, {'vars': 'all', 'args': 'none'}], 11 | 'no-empty': [0], 12 | 'react/prop-types': [0], 13 | 'react/no-unescaped-entities': [0], 14 | 'react-hooks/rules-of-hooks': 'error', 15 | 'no-useless-escape': [0], 16 | 'no-control-regex': [0] 17 | }, 18 | 'env': { 19 | 'es6': true, 20 | 'node': true, 21 | 'browser': true 22 | }, 23 | 'globals': { 24 | 'React': true, 25 | 'ReactDOM': true, 26 | 'Promise': true, 27 | 'd3': true, 28 | 'NProgress': true, 29 | 'ClipboardJS': true, 30 | 'PR': true, 31 | 'Mark': true 32 | }, 33 | 'parser': 'babel-eslint', 34 | 'parserOptions': { 35 | 'sourceType': 'module' 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | dist -diff 2 | assets -diff 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile ~/.gitignore_global 6 | .DS_Store 7 | Thumbs.db 8 | .sass-cache 9 | .idea 10 | .vscode 11 | lib-cov 12 | *.seed 13 | *.log 14 | *.csv 15 | *.dat 16 | *.out 17 | *.pid 18 | *.gz 19 | 20 | pids 21 | logs 22 | results 23 | 24 | package-lock.json 25 | npm-debug.log 26 | node_modules 27 | docs/html 28 | app/css 29 | app/js 30 | app/images 31 | app/fonts 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | SAY NO TO SUICIDE PUBLIC LICENSE 2 | 3 | Version 1.0, September 2017 4 | 5 | https://github.com/unbug/snts 6 | 7 | Copyright (C) 2017 @unbug 8 | 9 | Everyone is permitted to copy and distribute verbatim copies 10 | of this license document. 11 | 12 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, MODIFICATION, AND DISTRIBUTION 13 | 14 | 1. You can do anything with the original copy, 15 | whenever, whatever, no limitation. 16 | 17 | 2. When you are in despair, just talk to someone you trust, 18 | someone you love. Getting help from your family, your friends, 19 | the police, the community, the public. 20 | 21 | 3. Keep yourself alive and say no to suicide. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CODELF(变量命名神器) 6 | ================= 7 | A search tool helps dev to solve the naming things problem. 8 | 9 | Search over projects from Github, Bitbucket, Google Code, Codeplex, Sourceforge, Fedora Project, GitLab to find real-world usage variable names. 10 | 11 | Also a daily Algorithm Copybook. 12 | 13 | Also a GitHub stars, repositories tagger and organizer tool. 14 | 15 | >There are only two hard things in Computer Science: cache invalidation and naming things.-- Phil Karlton 16 | > 17 | >![twohardtings](https://user-images.githubusercontent.com/799578/50462942-8075fe80-09c3-11e9-9c7f-b38d495b925d.jpg) 18 | 19 | ![image](https://user-images.githubusercontent.com/799578/51435509-a2595d00-1cb3-11e9-8f4e-85ecbc3a2325.png) 20 | 21 | WIKI 22 | ================= 23 | [简体中文](https://github.com/unbug/codelf/wiki) 24 | 25 | Plugins 26 | ================= 27 | ### Codelf for VS Code 28 | 29 | ##### Install 30 | Codelf is on VS Code Extension Marketplace. Just search "codelf" on VS Code EXTENSIONS pane and click install. 31 | 32 | ##### Usage 33 | 1. Select text, right-click and select "Codelf". 34 | 35 | select 36 | 37 | ### Codelf for Atom 38 | 39 | ##### Install 40 | Codelf is [on Atom package](https://atom.io/packages/codelf). Search "codelf" on Atom setting pane and click install.Please see [Atom Packages in the Atom Flight Manual](http://flight-manual.atom.io/using-atom/sections/atom-packages/) 41 | 42 | ##### Usage 43 | 1. Select text, right-click and click "Codelf". 44 | 2. Open Packages menu select "Codelf" 45 | 3. Press CTRL+ALT+E to open Codelf 46 | 47 | 48 | 49 | Also see [How to use Codelf on Atom](https://github.com/unbug/atom-codelf#usage) 50 | 51 | 52 | ### Codelf for Sublime Text 53 | 54 | ##### Install 55 | 1. [Download Codelf for Sublime](https://github.com/unbug/codelf/archive/st-0.0.5.zip) or [Select a "st-" version to download](https://github.com/unbug/codelf/tags) 56 | 2. Unzip and rename the folder to `Codelf` 57 | 3. Copy the folder into `Packages` directory, which you can find using the menu item `Sublime Text -> Preferences -> Browse Packages...` 58 | 4. Restart Sublime Text 59 | 60 | ##### Usage 61 | 1. Select text, right-click and click "Codelf". 62 | 63 | ![ST Right Click](https://cloud.githubusercontent.com/assets/799578/12536608/655d4f72-c2e5-11e5-8836-7ce733f47eed.png) 64 | 2. Open Command Palette using menu item Tools -> Command Palette... --> Type "E" or "Codelf" -->Select "Search Selection" or "Search From Input" 65 | 66 | ![ST Command Palette...](https://cloud.githubusercontent.com/assets/799578/12536569/10422964-c2e4-11e5-9530-6efb742dad3c.png) 67 | 68 | Apps 69 | ================= 70 | [Codelf Chrome App](https://chrome.google.com/webstore/detail/codelf-best-github-stars/jnmjaglhmmcplekpfnblniiammmdpaan) 71 | 72 | 73 | Find me 74 | ================= 75 | * Twitter [@unbug](https://twitter.com/unbug) 76 | * 微博 [@听奏](http://weibo.com/unbug) 77 | 78 | Videos 79 | =============== 80 | [![Codelf first look](https://cloud.githubusercontent.com/assets/799578/12520673/e037c0c6-c180-11e5-8342-cb291b98dcab.png)](https://youtu.be/Uqg8HWaa-2c) 81 | 82 | Screenshots 83 | ================ 84 | 85 | ### Search variable 86 | 87 | ![image](https://user-images.githubusercontent.com/799578/51435477-f748a380-1cb2-11e9-89df-3ae5d99ed7e6.png) 88 | 89 | ![image](https://user-images.githubusercontent.com/799578/51435487-1b0be980-1cb3-11e9-9379-58c2ec678a81.png) 90 | 91 | ### Daily Algorithm Copybook 92 | 93 | ![jan-20-2019 14-29-06](https://user-images.githubusercontent.com/799578/51436194-75ad4180-1cc3-11e9-9ca0-80a0a56b9d7c.gif) 94 | 95 | ![image](https://user-images.githubusercontent.com/799578/51435445-71c4f380-1cb2-11e9-87a4-edc54cbe7052.png) 96 | 97 | ### GitHub stars, repositories tagger and organizer tool 98 | 99 | ![bnk1](https://cloud.githubusercontent.com/assets/799578/12507895/9945d290-c133-11e5-8bb9-ff5d5dec0cfe.png) 100 | 101 | ![bmk2](https://cloud.githubusercontent.com/assets/799578/12507854/5d2d328a-c133-11e5-85eb-d4da1c38a747.png) 102 | -------------------------------------------------------------------------------- /__static/app/cache.manifest: -------------------------------------------------------------------------------- 1 | CACHE MANIFEST 2 | # Build: _BUILD_VERSION_ 3 | 4 | CACHE: 5 | _FILES_ 6 | 7 | NETWORK: 8 | * 9 | -------------------------------------------------------------------------------- /__static/app/ddms_frame_callback.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /__static/app/html/components.html: -------------------------------------------------------------------------------- 1 | 11 | 23 | -------------------------------------------------------------------------------- /__static/app/html/donate.html: -------------------------------------------------------------------------------- 1 | 16 | -------------------------------------------------------------------------------- /__static/app/html/main.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

CODELF

4 |
Search over projects from GitHub, Bitbucket, GitLab to find
5 |
real-world usage variable names
6 |
7 |
8 |
9 |
10 |
11 | 13 | 28 |
29 |
30 | 31 |
32 | 33 | 37 | 38 | 39 |
40 |
41 |  For 42 | VS Code, 43 | Atom, 44 | Sublime Text, 45 | Chrome 46 |
47 |
48 |
49 |
50 |
51 | 54 |
55 |
56 |
57 |
58 | 77 |
78 |
79 |
80 | 86 | 94 | -------------------------------------------------------------------------------- /__static/app/html/scripts.html: -------------------------------------------------------------------------------- 1 | 2 | 9 | 12 | 143 | -------------------------------------------------------------------------------- /__static/app/html/sourcecode.html: -------------------------------------------------------------------------------- 1 | 37 | -------------------------------------------------------------------------------- /__static/app/html/styles.html: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /__static/app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | CODELF 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | @@include("html/styles.html") 15 | 21 | 22 | 23 | @@include("html/main.html") 24 | @@include("html/sourcecode.html") 25 | @@include("html/bookmark.html") 26 | @@include("html/donate.html") 27 | @@include("html/components.html") 28 | 29 | @@include("html/scripts.html") 30 | 31 | 32 | -------------------------------------------------------------------------------- /__static/app/resources/css/prettify.css: -------------------------------------------------------------------------------- 1 | .pln { 2 | color: #000 3 | } 4 | 5 | @media screen { 6 | .str { 7 | color: #080 8 | } 9 | 10 | .kwd { 11 | color: #008 12 | } 13 | 14 | .com { 15 | color: #800 16 | } 17 | 18 | .typ { 19 | color: #606 20 | } 21 | 22 | .lit { 23 | color: #066 24 | } 25 | 26 | .pun, .opn, .clo { 27 | color: #660 28 | } 29 | 30 | .tag { 31 | color: #008 32 | } 33 | 34 | .atn { 35 | color: #606 36 | } 37 | 38 | .atv { 39 | color: #080 40 | } 41 | 42 | .dec, .var { 43 | color: #606 44 | } 45 | 46 | .fun { 47 | color: red 48 | } 49 | } 50 | 51 | @media print, projection { 52 | .str { 53 | color: #060 54 | } 55 | 56 | .kwd { 57 | color: #006; 58 | font-weight: bold 59 | } 60 | 61 | .com { 62 | color: #600; 63 | font-style: italic 64 | } 65 | 66 | .typ { 67 | color: #404; 68 | font-weight: bold 69 | } 70 | 71 | .lit { 72 | color: #044 73 | } 74 | 75 | .pun, .opn, .clo { 76 | color: #440 77 | } 78 | 79 | .tag { 80 | color: #006; 81 | font-weight: bold 82 | } 83 | 84 | .atn { 85 | color: #404 86 | } 87 | 88 | .atv { 89 | color: #060 90 | } 91 | } 92 | 93 | pre.prettyprint { 94 | padding: 2px; 95 | border: 1px solid #888 96 | } 97 | 98 | ol.linenums { 99 | margin-top: 0; 100 | margin-bottom: 0 101 | } 102 | 103 | li.L0, li.L1, li.L2, li.L3, li.L5, li.L6, li.L7, li.L8 { 104 | list-style-type: none 105 | } 106 | 107 | li.L1, li.L3, li.L5, li.L7, li.L9 { 108 | background: #eee 109 | } 110 | -------------------------------------------------------------------------------- /__static/app/resources/fonts/Dressedless_Three.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/__static/app/resources/fonts/Dressedless_Three.ttf -------------------------------------------------------------------------------- /__static/app/resources/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/__static/app/resources/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /__static/app/resources/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/__static/app/resources/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /__static/app/resources/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/__static/app/resources/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /__static/app/resources/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/__static/app/resources/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /__static/app/resources/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/__static/app/resources/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /__static/app/resources/images/codelf_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/__static/app/resources/images/codelf_logo.png -------------------------------------------------------------------------------- /__static/app/resources/images/paypal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/__static/app/resources/images/paypal.png -------------------------------------------------------------------------------- /__static/app/resources/images/twohardtings.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/__static/app/resources/images/twohardtings.jpg -------------------------------------------------------------------------------- /__static/app/resources/images/wechatpay.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/__static/app/resources/images/wechatpay.jpg -------------------------------------------------------------------------------- /__static/app/resources/images/zhifubao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/__static/app/resources/images/zhifubao.png -------------------------------------------------------------------------------- /__static/app/scss/_animate.scss: -------------------------------------------------------------------------------- 1 | .animated { 2 | animation-duration: 1s; 3 | animation-fill-mode: both; 4 | } 5 | 6 | .animated.infinite { 7 | animation-iteration-count: infinite; 8 | } 9 | 10 | .animated.hinge { 11 | animation-duration: 2s; 12 | } 13 | 14 | @keyframes fadeIn { 15 | from { 16 | opacity: 0; 17 | } 18 | 19 | to { 20 | opacity: 1; 21 | } 22 | } 23 | 24 | @keyframes fadeInDown { 25 | from { 26 | opacity: 0; 27 | transform: translate3d(0, -100%, 0); 28 | } 29 | 30 | to { 31 | opacity: 1; 32 | transform: none; 33 | } 34 | } 35 | 36 | .fadeIn { 37 | animation-name: fadeIn; 38 | } 39 | 40 | .fadeInDown { 41 | animation-name: fadeInDown; 42 | } 43 | -------------------------------------------------------------------------------- /__static/app/scss/_bookmark.scss: -------------------------------------------------------------------------------- 1 | .bookmark-logo { 2 | cursor: pointer; 3 | color: #70B7FD; 4 | } 5 | 6 | .bookmark-modal { 7 | .modal-header{ 8 | .btn, .btn-group{ 9 | margin-right: .4rem; 10 | &:last-child{ 11 | margin-right: 0; 12 | } 13 | } 14 | .btn-group{ 15 | padding: 0; 16 | margin: 0; 17 | } 18 | } 19 | .modal-body { 20 | padding: 0; 21 | > .hd { 22 | display: none; 23 | padding: 1rem; 24 | > div { 25 | display: none; 26 | } 27 | &.loading, &.empty, &.loading > .loading, &.empty > .empty { 28 | display: block; 29 | margin: 0 auto; 30 | } 31 | > .empty { 32 | text-align: center; 33 | .top { 34 | margin: 2rem; 35 | } 36 | .tip { 37 | text-align: left; 38 | } 39 | } 40 | } 41 | } 42 | .card-block, .card-header { 43 | padding: .5rem; 44 | color: #373a3c; 45 | } 46 | .card-footer { 47 | padding: 0 0 .2rem .2rem; 48 | } 49 | .repo-list { 50 | padding-right: 0; 51 | padding-left: 0; 52 | padding-bottom: 0; 53 | } 54 | .repo-group-item { 55 | border: 0; 56 | margin-bottom: 0; 57 | > .hd { 58 | .dropdown-menu { 59 | min-width: initial; 60 | } 61 | .search { 62 | display: none; 63 | cursor: pointer; 64 | max-width: 70%; 65 | margin-top: -0.25rem; 66 | } 67 | } 68 | &[data-id="0"] > .hd .search { 69 | display: block; 70 | } 71 | .hd .ctrl > div { 72 | display: inline-block; 73 | padding: 0 .4rem; 74 | cursor: pointer; 75 | } 76 | &[data-id="0"] > .hd .ctrl { 77 | display: none; 78 | } 79 | .repo-item { 80 | border-top: 0; 81 | border-bottom: 0; 82 | border-left: 0; 83 | border-right: 0; 84 | border-radius: 0; 85 | &:last-child { 86 | margin-bottom: 0; 87 | } 88 | .card-footer { 89 | border-top: 0; 90 | } 91 | a { 92 | word-break: break-all; 93 | } 94 | } 95 | } 96 | .dropdown-menu .dropdown-item.add-repo { 97 | .label { 98 | width: 1.15rem; 99 | height: 1.15rem; 100 | margin-bottom: -0.2rem; 101 | i { 102 | display: none; 103 | color: #fff; 104 | } 105 | } 106 | &[data-selected] .label { 107 | padding-left: 0; 108 | padding-right: 0; 109 | i { 110 | display: inline-block; 111 | } 112 | } 113 | } 114 | .tag-dots span { 115 | margin-left: .25rem; 116 | } 117 | } 118 | 119 | .bookmark-user-modal { 120 | .user-item:first-child { 121 | margin-top: 1rem; 122 | } 123 | .user-list .ctrl { 124 | margin-top: -0.25rem; 125 | } 126 | } 127 | 128 | @media (max-width: 34em) { 129 | .bookmark-modal { 130 | .tag-dots span { 131 | margin-left: -.25rem; 132 | } 133 | .modal-header { 134 | .btn{ 135 | padding: .25rem; 136 | margin-right: .25rem; 137 | } 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /__static/app/scss/_components.scss: -------------------------------------------------------------------------------- 1 | /* 2 | http://www.fontspace.com/538fonts/dressedless 3 | https://everythingfonts.com/ttf-to-svg 4 | */ 5 | @font-face { 6 | font-family: 'Dressedless Three'; 7 | src: url('resources/fonts/Dressedless_Three.ttf') format("truetype"), url('resources/fonts/Dressedless_Three.svg') format("svg"); 8 | /* Legacy iOS */ 9 | } 10 | /*https://github.com/tobiasahlin/SpinKit*/ 11 | /* spinner */ 12 | .spinner { 13 | -webkit-animation: sk-rotateplane 1.2s infinite cubic-bezier(0.4, 0, 0.2, 1); 14 | animation: sk-rotateplane 1.2s infinite cubic-bezier(0.4, 0, 0.2, 1); 15 | } 16 | 17 | @-webkit-keyframes sk-rotateplane { 18 | 0% { 19 | -webkit-transform: perspective(120px); 20 | } 21 | 22 | 50% { 23 | -webkit-transform: perspective(120px) rotateY(180deg); 24 | } 25 | 26 | 100% { 27 | -webkit-transform: perspective(120px) rotateY(180deg) rotateX(180deg); 28 | } 29 | } 30 | 31 | 32 | @keyframes sk-rotateplane { 33 | 0% { 34 | transform: perspective(120px) rotateX(0deg) rotateY(0deg); 35 | -webkit-transform: perspective(120px) rotateX(0deg) rotateY(0deg); 36 | } 37 | 38 | 50% { 39 | transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg); 40 | -webkit-transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg); 41 | } 42 | 43 | 100% { 44 | transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg); 45 | -webkit-transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg); 46 | } 47 | } 48 | /*end spinner*/ 49 | .logo { 50 | margin: 0 auto; 51 | width: 3rem; 52 | height: 3rem; 53 | img { 54 | display: inherit; 55 | width: 100%; 56 | height: 100%; 57 | border-radius: 20%; 58 | } 59 | } 60 | .nav-bar{ 61 | position: absolute; 62 | top: 0.15rem;; 63 | right: 5%; 64 | z-index: 10; 65 | display: inline-block; 66 | transition: all 1s; 67 | >*{ 68 | float: left; 69 | display: inline-block; 70 | margin-right: .45rem; 71 | } 72 | &:last-child{ 73 | margin-right: 0; 74 | } 75 | i{ 76 | color: #70B7FD; 77 | &:hover,&:active{ 78 | color: #59AAF9; 79 | } 80 | } 81 | $anim-delay: 150ms; 82 | $anim-duration: 500ms; 83 | @for $i from 1 through 5 { 84 | >*:nth-child(#{$i}) { 85 | animation-duration: $anim-duration; 86 | animation-delay: 500 + $anim-delay*($i - 1); 87 | } 88 | } 89 | } 90 | @media (max-width: 34em) { 91 | .nav-bar{ 92 | right: 1%; 93 | } 94 | } 95 | @media (min-width: 100em) { 96 | .nav-bar{ 97 | right: 15%; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /__static/app/scss/_donate.scss: -------------------------------------------------------------------------------- 1 | .donate { 2 | display: block; 3 | padding-bottom: 5rem; 4 | margin-top: 1rem; 5 | text-align: center; 6 | form { 7 | display: inline-block; 8 | } 9 | .title { 10 | padding-bottom: .8rem; 11 | text-align: center; 12 | .lang { 13 | display: none; 14 | } 15 | &.cn .cn, &.en .en { 16 | display: block; 17 | } 18 | } 19 | .bd { 20 | display: block; 21 | width: 100%; 22 | margin: 0 auto; 23 | text-align: center; 24 | } 25 | } 26 | 27 | .zhifubao, .wechatpay { 28 | margin-right: 1rem; 29 | margin-top: -3rem; 30 | width: 5rem; 31 | } 32 | 33 | .paypal { 34 | width: 5rem; 35 | } 36 | 37 | body.dark { 38 | .zhifubao, .wechatpay, .paypal { 39 | background-color: #fff; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /__static/app/scss/_main.scss: -------------------------------------------------------------------------------- 1 | .main { 2 | padding-top: 2.5rem; 3 | } 4 | 5 | .main-title { 6 | text-align: center; 7 | padding: 0 1.2rem; 8 | > header a { 9 | color: inherit; 10 | text-decoration: none; 11 | &:visited, &:link, &:active, &:hover { 12 | color: inherit; 13 | text-decoration: none; 14 | } 15 | } 16 | h1 { 17 | font-family: "Dressedless Three",Roboto,"Helvetica Neue",Helvetica,Arial,sans-serif; 18 | text-transform: uppercase; 19 | font-size: 3.5rem; 20 | &.animated span { 21 | transition: color 250ms linear; 22 | /*C*/ 23 | &:nth-child(1) { 24 | color: #3369e8; 25 | transition-delay: 200ms; 26 | } 27 | /*O*/ 28 | &:nth-child(2) { 29 | color: #d50f25; 30 | transition-delay: 350ms; 31 | } 32 | /*D*/ 33 | &:nth-child(3) { 34 | color: #eeb211; 35 | transition-delay: 500ms; 36 | } 37 | /*E*/ 38 | &:nth-child(4) { 39 | color: #3369e8; 40 | transition-delay: 650ms; 41 | } 42 | /*L*/ 43 | &:nth-child(5) { 44 | color: #009925; 45 | transition-delay: 800ms; 46 | } 47 | /*F*/ 48 | &:nth-child(6) { 49 | color: #d50f25; 50 | transition-delay: 950ms; 51 | } 52 | } 53 | } 54 | h5 { 55 | max-height: 300px; 56 | transition: all 250ms cubic-bezier(0.4, 0, 0.2, 1); 57 | overflow: hidden; 58 | 59 | .label { 60 | background-color: #71b7fd; 61 | } 62 | } 63 | } 64 | 65 | .search-form { 66 | padding: 1rem 0; 67 | .input-group{ 68 | height: 44px; 69 | border-radius: 2px; 70 | box-shadow: 0 2px 2px 0 rgba(0,0,0,0.16), 0 0 0 1px rgba(0,0,0,0.08); 71 | transition: box-shadow 200ms cubic-bezier(0.4, 0.0, 0.2, 1); 72 | &:focus, &:active, &:hover { 73 | box-shadow: 0 3px 8px 0 rgba(0,0,0,0.2), 0 0 0 1px rgba(0,0,0,0.08); 74 | } 75 | } 76 | input, button, a { 77 | height: 44px; 78 | line-height: 44px; 79 | padding-top: 0; 80 | padding-bottom: 0; 81 | border: 0 !important; 82 | } 83 | .dropdown-menu { 84 | max-height: 320px; 85 | overflow-y: scroll; 86 | -webkit-overflow-scrolling: touch; 87 | transform: translate3d(0, 0, 0); 88 | } 89 | button.search{ 90 | .more{ 91 | display: none; 92 | } 93 | &.more{ 94 | .normal{ 95 | display: none; 96 | } 97 | .more{ 98 | display: inline-block; 99 | } 100 | } 101 | } 102 | } 103 | .search-relate a:hover { 104 | text-decoration: underline; 105 | } 106 | 107 | .search-result { 108 | padding-top: .8rem; 109 | .ct { 110 | border-left: .15rem solid #eceeef; 111 | background: none; 112 | &.ct--white { 113 | border-left: 0; 114 | } 115 | } 116 | .variable-wrap { 117 | display: inline-block; 118 | cursor: pointer; 119 | .btn-sm { 120 | margin-right: .4rem; 121 | padding: 0 .4em; 122 | font-weight: bold; 123 | } 124 | } 125 | a:hover { 126 | text-decoration: underline; 127 | } 128 | .hd { 129 | text-align: center; 130 | > div { 131 | text-align: center; 132 | display: none; 133 | } 134 | &.loading .loading, &.error .error { 135 | display: block; 136 | margin: 0 auto; 137 | } 138 | .logo { 139 | margin: 0 auto 1rem; 140 | } 141 | } 142 | } 143 | .notice-link{ 144 | position: fixed; 145 | bottom: 0; 146 | left: 0; 147 | width: 100%; 148 | height: 3rem; 149 | padding: 1rem; 150 | text-align: center; 151 | background: #fff; 152 | } 153 | .notice-link a { 154 | display: none; 155 | } 156 | .popover--variable { 157 | background-color: transparent; 158 | border-left: 0; 159 | border-right: 0; 160 | border-top: 0; 161 | border-color: #ccc; 162 | .popover-content { 163 | padding: 0; 164 | } 165 | .btn { 166 | border-bottom: 0; 167 | } 168 | } 169 | .variable-btns > .variable-btns__copy { 170 | display: none; 171 | } 172 | body.mobile .variable-btns__copy { 173 | display: none !important; 174 | } 175 | body.dark { 176 | .search-form .input-group { 177 | box-shadow: 0 2px 2px 0 rgba(255,255,255,0.16), 0 0 0 1px rgba(255,255,255,0.08); 178 | &:focus, &:active, &:hover { 179 | box-shadow: 0 3px 12px 0 rgba(255,255,255,0.2), 0 0 0 1px rgba(255,255,255,0.08); 180 | } 181 | } 182 | .search-result { 183 | .ct, hr { 184 | border-color: rgba(0,0,0,.16); 185 | } 186 | } 187 | .notice-link { 188 | background: #272b38; 189 | } 190 | .popover--variable { 191 | border-bottom: 0; 192 | } 193 | } 194 | @media (max-width: 767px){ 195 | .search-form { 196 | button.search{ 197 | border-top-right-radius: .25rem !important; 198 | border-bottom-right-radius: .25rem !important;; 199 | } 200 | } 201 | } 202 | @media (max-width: 34em) { 203 | .search-result { 204 | .ct { 205 | overflow-x: scroll; 206 | -webkit-overflow-scrolling: touch; 207 | } 208 | } 209 | } 210 | @media (min-width: 62em) { 211 | .main-title h1 { 212 | font-size: 4.5rem; 213 | } 214 | .search-relate { 215 | padding-bottom: 1.8rem; 216 | } 217 | .search-result .ct { 218 | overflow-x: auto; 219 | } 220 | .variable-btns > .variable-btns__copy { 221 | display: block; 222 | } 223 | } 224 | @media (min-width: 100em) { 225 | .main { 226 | padding-top: 5rem; 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /__static/app/scss/_sourcecode.scss: -------------------------------------------------------------------------------- 1 | .sourcecode-modal { 2 | .dropdown-menu { 3 | max-height: 320px; 4 | overflow-y: scroll; 5 | -webkit-overflow-scrolling: touch; 6 | transform: translate3d(0, 0, 0); 7 | } 8 | .cur-repo { 9 | margin-left: .4rem; 10 | } 11 | code { 12 | display: inline-block; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /__static/app/scss/_util.scss: -------------------------------------------------------------------------------- 1 | .fix-break-word, p { 2 | word-break: break-all; 3 | word-break: break-word; 4 | -webkit-hyphens: auto; 5 | hyphens: auto; 6 | } 7 | .label { 8 | margin-right: .4rem; 9 | } 10 | .blockquote { 11 | border: none; 12 | text-align: center; 13 | img { 14 | max-width: 100%; 15 | height: auto; 16 | } 17 | } 18 | .jumbotron{ 19 | margin-bottom: 0; 20 | } 21 | .highlight { 22 | background-color: #FFFF88; 23 | } 24 | .modal-header .close { 25 | padding-left: .65rem; 26 | } 27 | 28 | .modal--fix { 29 | max-height: 98%; 30 | .modal-dialog { 31 | height: 100%; 32 | max-width: 100%; 33 | overflow: hidden; 34 | } 35 | .modal-content { 36 | height: 100%; 37 | max-width: 100%; 38 | overflow: hidden; 39 | padding-bottom: 8%; 40 | } 41 | .modal-body { 42 | max-height: 98%; 43 | overflow: scroll; 44 | -webkit-overflow-scrolling: touch; 45 | } 46 | } 47 | @media (min-width: 62em) { 48 | .modal--fix { 49 | max-height: none; 50 | .modal-dialog, .modal-content, .modal-body { 51 | height: auto; 52 | overflow: auto; 53 | } 54 | .modal-content { 55 | padding-bottom: 0; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /__static/app/scss/style.scss: -------------------------------------------------------------------------------- 1 | html, body { 2 | width: 100%; 3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; 4 | -webkit-font-smoothing: antialiased; 5 | transition: all 350ms cubic-bezier(0.4, 0, 0.2, 1); 6 | } 7 | @import "util.scss"; 8 | @import "animate.scss"; 9 | @import "components.scss"; 10 | @import "main.scss"; 11 | @import "donate.scss"; 12 | @import "sourcecode.scss"; 13 | @import "bookmark.scss"; 14 | 15 | body.dark { 16 | background: #272b38; 17 | color: #fff; 18 | } 19 | -------------------------------------------------------------------------------- /__static/app/src/App.js: -------------------------------------------------------------------------------- 1 | $(function () { 2 | require('./view/View.js'); 3 | require('./view/BookmarkView.js'); 4 | }); 5 | -------------------------------------------------------------------------------- /__static/app/src/lib/all.js: -------------------------------------------------------------------------------- 1 | @@include("jquery.min.js") 2 | @@include("jquery.highlight.js") 3 | @@include("tether.min.js") 4 | @@include("bootstrap.min.js") 5 | @@include("prettify.js") 6 | @@include("clipboard.min.js") 7 | @@include("lovefield.min.js") 8 | @@include("fastclick.js") 9 | -------------------------------------------------------------------------------- /__static/app/src/lib/jquery.highlight.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery Highlight plugin 3 | * 4 | * Based on highlight v3 by Johann Burkard 5 | * http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html 6 | * 7 | * Code a little bit refactored and cleaned (in my humble opinion). 8 | * Most important changes: 9 | * - has an option to highlight only entire words (wordsOnly - false by default), 10 | * - has an option to be case sensitive (caseSensitive - false by default) 11 | * - highlight element tag and class names can be specified in options 12 | * 13 | * Usage: 14 | * // wrap every occurrance of text 'lorem' in content 15 | * // with (default options) 16 | * $('#content').highlight('lorem'); 17 | * 18 | * // search for and highlight more terms at once 19 | * // so you can save some time on traversing DOM 20 | * $('#content').highlight(['lorem', 'ipsum']); 21 | * $('#content').highlight('lorem ipsum'); 22 | * 23 | * // search only for entire word 'lorem' 24 | * $('#content').highlight('lorem', { wordsOnly: true }); 25 | * 26 | * // don't ignore case during search of term 'lorem' 27 | * $('#content').highlight('lorem', { caseSensitive: true }); 28 | * 29 | * // wrap every occurrance of term 'ipsum' in content 30 | * // with 31 | * $('#content').highlight('ipsum', { element: 'em', className: 'important' }); 32 | * 33 | * // remove default highlight 34 | * $('#content').unhighlight(); 35 | * 36 | * // remove custom highlight 37 | * $('#content').unhighlight({ element: 'em', className: 'important' }); 38 | * 39 | * 40 | * Copyright (c) 2009 Bartek Szopka 41 | * 42 | * Licensed under MIT license. 43 | * 44 | */ 45 | 46 | jQuery.extend({ 47 | highlight: function (node, re, nodeName, className) { 48 | if (node.nodeType === 3) { 49 | var match = node.data.match(re); 50 | if (match) { 51 | var highlight = document.createElement(nodeName || 'span'); 52 | highlight.className = className || 'highlight'; 53 | var wordNode = node.splitText(match.index); 54 | wordNode.splitText(match[0].length); 55 | var wordClone = wordNode.cloneNode(true); 56 | highlight.appendChild(wordClone); 57 | wordNode.parentNode.replaceChild(highlight, wordNode); 58 | return 1; //skip added node in parent 59 | } 60 | } else if ((node.nodeType === 1 && node.childNodes) && // only element nodes that have children 61 | !/(script|style)/i.test(node.tagName) && // ignore script and style nodes 62 | !(node.tagName === nodeName.toUpperCase() && node.className === className)) { // skip if already highlighted 63 | for (var i = 0; i < node.childNodes.length; i++) { 64 | i += jQuery.highlight(node.childNodes[i], re, nodeName, className); 65 | } 66 | } 67 | return 0; 68 | } 69 | }); 70 | 71 | jQuery.fn.unhighlight = function (options) { 72 | var settings = { className: 'highlight', element: 'span' }; 73 | jQuery.extend(settings, options); 74 | 75 | return this.find(settings.element + "." + settings.className).each(function () { 76 | var parent = this.parentNode; 77 | parent.replaceChild(this.firstChild, this); 78 | parent.normalize(); 79 | }).end(); 80 | }; 81 | 82 | jQuery.fn.highlight = function (words, options) { 83 | var settings = { className: 'highlight', element: 'span', caseSensitive: false, wordsOnly: false }; 84 | jQuery.extend(settings, options); 85 | 86 | if (words.constructor === String) { 87 | words = [words]; 88 | } 89 | words = jQuery.grep(words, function(word, i){ 90 | return word != ''; 91 | }); 92 | words = jQuery.map(words, function(word, i) { 93 | return word.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); 94 | }); 95 | if (words.length == 0) { return this; }; 96 | 97 | var flag = settings.caseSensitive ? "" : "i"; 98 | var pattern = "(" + words.join("|") + ")"; 99 | if (settings.wordsOnly) { 100 | pattern = "\\b" + pattern + "\\b"; 101 | } 102 | var re = new RegExp(pattern, flag); 103 | 104 | return this.each(function () { 105 | jQuery.highlight(this, re, settings.element, settings.className); 106 | }); 107 | }; 108 | 109 | -------------------------------------------------------------------------------- /__static/app/src/model/DDMSModel.js: -------------------------------------------------------------------------------- 1 | var Util = require('Util.js'); 2 | 3 | module.exports = new function () { 4 | var formAction = '//ddms.mihtool.com/apis/v1/formdata/'; 5 | var formDataAction = '//ddms.mihtool.com/apis/v1/formdata_detail/'; 6 | var persistKeyWordsName = 'codelf_ddms_keywords'; 7 | var persistOrganizerName = 'codelf_ddms_group_sync_id'; 8 | var persistKeyWordsTimerName = persistKeyWordsName + '_timer'; 9 | var cacheKeyWords = (Util.localStorage.get(persistKeyWordsName) || '').split(','); 10 | var ot = new Date(Util.localStorage.get(persistKeyWordsTimerName) || 0); 11 | var nt = new Date().getTime(); 12 | var OrganizerSyncId; 13 | 14 | if ((nt - ot) > 1000 * 60 * 60 * 24) { 15 | cacheKeyWords = []; 16 | Util.localStorage.set(persistKeyWordsTimerName, nt); 17 | } 18 | function saveKeyWords(val) { 19 | if (!Util.isInArray(cacheKeyWords, val)) { 20 | cacheKeyWords.push(val); 21 | Util.localStorage.set(persistKeyWordsName, cacheKeyWords.join(',').replace(/^,*/g, '').replace(/,*&/g, '')); 22 | } 23 | } 24 | 25 | this.setOrganizerSyncId = function (val) { 26 | OrganizerSyncId = val; 27 | Util.localStorage.set(persistOrganizerName, val); 28 | } 29 | 30 | this.getOrganizerSyncId = function () { 31 | return OrganizerSyncId || Util.localStorage.get(persistOrganizerName); 32 | } 33 | 34 | this.postKeyWords = function (val) { 35 | if (val && !Util.isInArray(cacheKeyWords, val)) { 36 | Util.FormHandler.asyncSubmit(formAction, { 37 | formid: '56e58775ade3a8e84dbacadf', 38 | keyword: val 39 | }); 40 | saveKeyWords(val); 41 | } 42 | } 43 | this.postBookmarkUser = function (val) { 44 | if (val) { 45 | Util.FormHandler.asyncSubmit(formAction, { 46 | formid: '56e587a9ade3a8e84dbacae1', 47 | account: val 48 | }); 49 | } 50 | } 51 | this.postBookmarkGroup = function (repoid,repourl,groupname,lang,stars) { 52 | if (repoid) { 53 | Util.FormHandler.asyncSubmit(formAction, { 54 | formid: '56e587ecade3a8e84dbacae3', 55 | repoid: repoid, 56 | repourl: repourl, 57 | groupname: groupname, 58 | lang: lang, 59 | stars: stars 60 | }); 61 | } 62 | } 63 | this.postBookmarkOrganizer = function (data, callback) { 64 | if (data) { 65 | window.afterPostBookmarkOrganizer = callback; 66 | Util.FormHandler.asyncSubmit(formAction, { 67 | formid: '56fb7d9dade3a8e84dbacaf0', 68 | success_url: Util.thisPath+'ddms_frame_callback.html?frame_callback=afterPostBookmarkOrganizer', 69 | data: data 70 | }); 71 | } 72 | } 73 | this.postUpdateBookmarkOrganizer = function (id, data, callback) { 74 | if (id && data) { 75 | window.afterPostUpdateBookmarkOrganizer = callback; 76 | Util.FormHandler.asyncSubmit(formDataAction, { 77 | id: id, 78 | success_url: Util.thisPath+'ddms_frame_callback.html?frame_callback=afterPostUpdateBookmarkOrganizer', 79 | data: data 80 | }); 81 | } 82 | } 83 | this.getBookmarkOrganizer = function (id, callback) { 84 | $.getJSON(formDataAction+'?callback=?', 85 | { 86 | id: id 87 | }, 88 | function (data) { 89 | if (data) { 90 | callback && callback(data); 91 | } 92 | }); 93 | } 94 | }; 95 | -------------------------------------------------------------------------------- /__static/app/src/model/Database.js: -------------------------------------------------------------------------------- 1 | var Util = require('Util.js'); 2 | 3 | exports.schemaBuilder = lf.schema.create('Codelf', 6); 4 | exports.eventType = { 5 | C: 'CREATE', 6 | U: 'UPDATED', 7 | D: 'DELETE' 8 | }; 9 | 10 | -------------------------------------------------------------------------------- /__static/app/src/model/Model.js: -------------------------------------------------------------------------------- 1 | var Util = require('Util.js'); 2 | var Database = require('model/Database.js'); 3 | 4 | //model 5 | //http://githut.info/ 6 | exports.TopProgramLan = [{"id": "22,106", "language": "JavaScript, CoffeeScript"}, { 7 | "id": "133,135", 8 | "language": "CSS" 9 | }, {"id": "3,39", "language": "HTML"}, {"id": 137, "language": "Swift"}, { 10 | "id": 35, 11 | "language": "Objective-C" 12 | }, {"id": 23, "language": "Java"}, {"id": 19, "language": "Python"}, {"id": 24, "language": "PHP"}, { 13 | "id": 32, 14 | "language": "Ruby" 15 | }, {"id": 28, "language": "C"}, {"id": 16, "language": "C++"}, {"id": 6, "language": "C#"}, { 16 | "id": 55, 17 | "language": "Go" 18 | }, {"id": 51, "language": "Perl"}, {"id": "104,109", "language": "Clojure, ClojureScript"}, { 19 | "id": 40, 20 | "language": "Haskell" 21 | }, {"id": 54, "language": "Lua"}, {"id": 20, "language": "Matlab"}, {"id": 144, "language": "R"}, { 22 | "id": 47, 23 | "language": "Scala" 24 | }, {"id": "69,78,146", "language": "Shell"}, {"id": 29, "language": "Lisp"}, {"id": 42, "language": "ActionScript"}]; 25 | 26 | exports.BeanHelpers = new function () { 27 | this.getRandomLabelType = function () { 28 | var types = ['primary', 'secondary', 'success', 'info', 'warning', 'danger']; 29 | return Util.randomList(types, 1)[0]; 30 | }; 31 | 32 | this.getKeyWordReg = function (key) { 33 | return new RegExp('([\\-_\\w\\d\\/\\$]{0,}){0,1}' + key + '([\\-_\\w\\d\\$]{0,}){0,1}', 'gi'); 34 | } 35 | }; 36 | exports.Searchcode = require('./SearchcodeModel'); 37 | exports.YoudaoTranslate = require('./YoudaoTranslateModel'); 38 | exports.Bookmark = require('./BookmarkModel'); 39 | exports.DDMS = require('./DDMSModel'); 40 | 41 | //init DB 42 | Database.schemaBuilder.connect({ 43 | storeType: Util.os.ios?lf.schema.DataStoreType.WEB_SQL: null 44 | }).then(function (db) { 45 | $(window).trigger('DB:ready',db); 46 | }); 47 | -------------------------------------------------------------------------------- /__static/app/src/model/SearchcodeModel.js: -------------------------------------------------------------------------------- 1 | var Util = require('Util.js'); 2 | var Database = require('model/Database.js'); 3 | 4 | 5 | module.exports = new function () { 6 | var _this = this; 7 | var DB; 8 | var schemaBuilder = Database.schemaBuilder; 9 | var Tables; 10 | var DBEventType = Database.eventType; 11 | var win = $(window); 12 | 13 | schemaBuilder 14 | .createTable('SourceCode') 15 | .addColumn('id', lf.Type.INTEGER) 16 | .addColumn('sid', lf.Type.OBJECT) 17 | .addColumn('htm', lf.Type.OBJECT) 18 | .addColumn('create', lf.Type.DATE_TIME) 19 | .addPrimaryKey(['id'], true); 20 | 21 | var persistLangsName = 'codelf_langs_selected'; 22 | var langs = Util.localStorage.get(persistLangsName), langQuery; 23 | var page = 0; 24 | var lastVal; 25 | var cacheSourceCodes = {}; 26 | var cacheSourceCodeHtmls = {}; 27 | var afterRequestSearchcode; 28 | 29 | genLangQuery(langs); 30 | 31 | this.resetPage = function () { 32 | page = 0; 33 | } 34 | 35 | this.setLang = function (val) { 36 | langs = val || null; 37 | genLangQuery(val); 38 | this.resetPage(); 39 | Util.localStorage[langs ? 'set' : 'del'](persistLangsName, langs); 40 | } 41 | 42 | this.getLang = function () { 43 | return langs; 44 | } 45 | 46 | function genLangQuery(val) { 47 | if (!!val) { 48 | var arr1 = val.replace(/\s+/g, ',').split(','), 49 | arr2 = []; 50 | arr1.forEach(function (key) { 51 | arr2.push('lan=' + key); 52 | }); 53 | langQuery = arr2.join('&'); 54 | } else { 55 | langQuery = null; 56 | } 57 | } 58 | 59 | win.on('DB:ready', function (ev,db) { 60 | DB = db; 61 | Tables = { 62 | SourceCode: DB.getSchema().table('SourceCode') 63 | }; 64 | _this.SourceCodeTable.getAll(function(rows){ 65 | rows.forEach(function (key) { 66 | cacheSourceCodeHtmls[key.sid] = key.htm; 67 | }); 68 | }); 69 | }); 70 | 71 | this.SourceCodeTable = new function () { 72 | this.add = function (sid, htm, callback) { 73 | if (!sid) { 74 | return; 75 | } 76 | var row = Tables.SourceCode.createRow({ 77 | 'sid': sid, 78 | 'htm': htm, 79 | 'create': new Date() 80 | }); 81 | DB.insertOrReplace().into(Tables.SourceCode).values([row]) 82 | .exec().then(function () { 83 | callback && callback(); 84 | win.trigger('DB:Table.SourceCode.onchange', {type: DBEventType.C}); 85 | }); 86 | } 87 | 88 | this.getAll = function (callback) { 89 | DB.select() 90 | .from(Tables.SourceCode) 91 | .orderBy(Tables.SourceCode.id, lf.Order.DESC) 92 | .exec().then(function (rows) { 93 | callback && callback(rows); 94 | }); 95 | } 96 | }; 97 | 98 | this.setCacheSourceCodeHtmlById = function(id,htm){ 99 | cacheSourceCodeHtmls[id] = htm; 100 | _this.SourceCodeTable.add(id,htm); 101 | } 102 | this.getCacheSourceCodeHtmlById = function(id){ 103 | return cacheSourceCodeHtmls[id]; 104 | } 105 | 106 | //search code by query 107 | this.request = function (val, callback) { 108 | afterRequestSearchcode = callback; 109 | if (val != lastVal) { 110 | this.resetPage(); 111 | } 112 | lastVal = val; 113 | lastVal && $.ajax({ 114 | type: 'GET', 115 | dataType: 'jsonp', 116 | //dataType: 'json', 117 | //url: 'https://searchcode.com/api/codesearch_I/' + (langQuery ? ('?' + langQuery) : ''), 118 | url: 'https://searchcode.com/api/jsonp_codesearch_I/' + (langQuery ? ('?' + langQuery) : ''), 119 | data: { 120 | q: lastVal, 121 | p: page, 122 | per_page: 42, 123 | callback: 'afterRequestSearchcode' 124 | }, 125 | jsonp: false, 126 | jsonpCallback: false, 127 | success: function (data) { 128 | callback && callback(data, page); 129 | page++; 130 | } 131 | }) 132 | }; 133 | 134 | window.afterRequestSearchcode = function(data){ 135 | afterRequestSearchcode && afterRequestSearchcode(data, page); 136 | page++; 137 | } 138 | 139 | //get source code by id 140 | this.requestSourceCode = function (id, callback) { 141 | if (cacheSourceCodes[id]) { 142 | callback && callback(cacheSourceCodes[id]); 143 | return; 144 | } 145 | id && $.ajax({ 146 | type: 'GET', 147 | dataType: 'json', 148 | url: 'https://searchcode.com/api/result/' + id + '/', 149 | success: function (data) { 150 | cacheSourceCodes[id] = data; 151 | callback && callback(data); 152 | } 153 | }); 154 | } 155 | }; 156 | -------------------------------------------------------------------------------- /__static/app/src/model/YoudaoTranslateModel.js: -------------------------------------------------------------------------------- 1 | var Util = require('Util.js'); 2 | 3 | module.exports = new function () { 4 | var lastVal; 5 | var translateRequestCallback; 6 | this.request = function (val, callback) { 7 | lastVal = val; 8 | translateRequestCallback = callback; 9 | lastVal && $.getJSON('//fanyi.youdao.com/openapi.do?callback=?&keyfrom=Codelf&key=2023743559&type=data&doctype=jsonp&version=1.1', 10 | { 11 | q: lastVal 12 | }, 13 | function (data) { 14 | if (data) { 15 | translateRequestCallback && translateRequestCallback(data); 16 | } 17 | }); 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /__static/app/sw.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Google Inc. All Rights Reserved. 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software 8 | distributed under the License is distributed on an "AS IS" BASIS, 9 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | See the License for the specific language governing permissions and 11 | limitations under the License. 12 | */ 13 | 14 | // While overkill for this specific sample in which there is only one cache, 15 | // this is one best practice that can be followed in general to keep track of 16 | // multiple caches used by a given service worker, and keep them all versioned. 17 | // It maps a shorthand identifier for a cache to a specific, versioned cache name. 18 | 19 | // Note that since global state is discarded in between service worker restarts, these 20 | // variables will be reinitialized each time the service worker handles an event, and you 21 | // should not attempt to change their values inside an event handler. (Treat them as constants.) 22 | 23 | // If at any point you want to force pages that use this service worker to start using a fresh 24 | // cache, then increment the CACHE_VERSION value. It will kick off the service worker update 25 | // flow and the old cache(s) will be purged as part of the activate event handler when the 26 | // updated service worker is activated. 27 | var CACHE_VERSION = _BUILD_VERSION_; 28 | var CURRENT_CACHES = { 29 | prefetch: 'prefetch-cache-v' + CACHE_VERSION 30 | }; 31 | 32 | self.addEventListener('install', function(event) { 33 | var now = Date.now(); 34 | 35 | var urlsToPrefetch = [_FILES_]; 36 | 37 | // All of these logging statements should be visible via the "Inspect" interface 38 | // for the relevant SW accessed via chrome://serviceworker-internals 39 | console.log('Handling install event. Resources to prefetch:', urlsToPrefetch); 40 | 41 | event.waitUntil( 42 | caches.open(CURRENT_CACHES.prefetch).then(function(cache) { 43 | var cachePromises = urlsToPrefetch.map(function(urlToPrefetch) { 44 | // This constructs a new URL object using the service worker's script location as the base 45 | // for relative URLs. 46 | var url = new URL(urlToPrefetch, location.href); 47 | // Append a cache-bust=TIMESTAMP URL parameter to each URL's query string. 48 | // This is particularly important when precaching resources that are later used in the 49 | // fetch handler as responses directly, without consulting the network (i.e. cache-first). 50 | // If we were to get back a response from the HTTP browser cache for this precaching request 51 | // then that stale response would be used indefinitely, or at least until the next time 52 | // the service worker script changes triggering the install flow. 53 | url.search += (url.search ? '&' : '?') + 'cache-bust=' + now; 54 | 55 | // It's very important to use {mode: 'no-cors'} if there is any chance that 56 | // the resources being fetched are served off of a server that doesn't support 57 | // CORS (http://en.wikipedia.org/wiki/Cross-origin_resource_sharing). 58 | // In this example, www.chromium.org doesn't support CORS, and the fetch() 59 | // would fail if the default mode of 'cors' was used for the fetch() request. 60 | // The drawback of hardcoding {mode: 'no-cors'} is that the response from all 61 | // cross-origin hosts will always be opaque 62 | // (https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#cross-origin-resources) 63 | // and it is not possible to determine whether an opaque response represents a success or failure 64 | // (https://github.com/whatwg/fetch/issues/14). 65 | var request = new Request(url, {mode: 'no-cors'}); 66 | return fetch(request).then(function(response) { 67 | if (response.status >= 400) { 68 | throw new Error('request for ' + urlToPrefetch + 69 | ' failed with status ' + response.statusText); 70 | } 71 | 72 | // Use the original URL without the cache-busting parameter as the key for cache.put(). 73 | return cache.put(urlToPrefetch, response); 74 | }).catch(function(error) { 75 | console.error('Not caching ' + urlToPrefetch + ' due to ' + error); 76 | }); 77 | }); 78 | 79 | return Promise.all(cachePromises).then(function() { 80 | console.log('Pre-fetching complete.'); 81 | }); 82 | }).catch(function(error) { 83 | console.error('Pre-fetching failed:', error); 84 | }) 85 | ); 86 | }); 87 | 88 | self.addEventListener('activate', function(event) { 89 | // Delete all caches that aren't named in CURRENT_CACHES. 90 | // While there is only one cache in this example, the same logic will handle the case where 91 | // there are multiple versioned caches. 92 | var expectedCacheNames = Object.keys(CURRENT_CACHES).map(function(key) { 93 | return CURRENT_CACHES[key]; 94 | }); 95 | 96 | event.waitUntil( 97 | caches.keys().then(function(cacheNames) { 98 | return Promise.all( 99 | cacheNames.map(function(cacheName) { 100 | if (expectedCacheNames.indexOf(cacheName) === -1) { 101 | // If this cache name isn't present in the array of "expected" cache names, then delete it. 102 | console.log('Deleting out of date cache:', cacheName); 103 | return caches.delete(cacheName); 104 | } 105 | }) 106 | ); 107 | }) 108 | ); 109 | }); 110 | 111 | self.addEventListener('fetch', function(event) { 112 | console.log('Handling fetch event for', event.request.url); 113 | var requestURL = new URL(event.request.url); 114 | requestURL.origin == location.origin && event.respondWith( 115 | // caches.match() will look for a cache entry in all of the caches available to the service worker. 116 | // It's an alternative to first opening a specific named cache and then matching on that. 117 | caches.match(event.request).then(function(response) { 118 | if (response) { 119 | console.log('Found response in cache:', response); 120 | 121 | return response; 122 | } 123 | 124 | console.log('No response found in cache. About to fetch from network...'); 125 | 126 | // event.request will always have the proper mode set ('cors, 'no-cors', etc.) so we don't 127 | // have to hardcode 'no-cors' like we do when fetch()ing in the install handler. 128 | return fetch(event.request).then(function(response) { 129 | console.log('Response from network is:', response); 130 | 131 | return response; 132 | }).catch(function(error) { 133 | // This catch() will handle exceptions thrown from the fetch() operation. 134 | // Note that a HTTP error response (e.g. 404) will NOT trigger an exception. 135 | // It will return a normal response object that has the appropriate error code set. 136 | console.error('Fetching failed:', error); 137 | 138 | throw error; 139 | }); 140 | }) 141 | ); 142 | }); 143 | -------------------------------------------------------------------------------- /__static/images/codelf_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/__static/images/codelf_logo.png -------------------------------------------------------------------------------- /__static/images/demo1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/__static/images/demo1.jpg -------------------------------------------------------------------------------- /__static/images/demo2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/__static/images/demo2.jpg -------------------------------------------------------------------------------- /__static/images/paypal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/__static/images/paypal.png -------------------------------------------------------------------------------- /__static/images/twohardtings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/__static/images/twohardtings.png -------------------------------------------------------------------------------- /__static/images/twohardtings2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/__static/images/twohardtings2.png -------------------------------------------------------------------------------- /__static/images/wechatpay.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/__static/images/wechatpay.jpg -------------------------------------------------------------------------------- /__static/images/zhifubao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/__static/images/zhifubao.png -------------------------------------------------------------------------------- /app/ddms_frame_callback.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | CODELF 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /app/opensearch.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | CODELF 4 | Search CODELF 5 | UTF-8 6 | CODELF Search 7 | logo 8 | 9 | 10 | -------------------------------------------------------------------------------- /assets/codelf_logo.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/assets/codelf_logo.psd -------------------------------------------------------------------------------- /assets/fonts/Dressedless_Three.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/assets/fonts/Dressedless_Three.ttf -------------------------------------------------------------------------------- /assets/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/assets/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /assets/fonts/LatoLatin-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/assets/fonts/LatoLatin-Bold.woff2 -------------------------------------------------------------------------------- /assets/fonts/LatoLatin-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/assets/fonts/LatoLatin-BoldItalic.woff2 -------------------------------------------------------------------------------- /assets/fonts/LatoLatin-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/assets/fonts/LatoLatin-Italic.woff2 -------------------------------------------------------------------------------- /assets/fonts/LatoLatin-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/assets/fonts/LatoLatin-Regular.woff2 -------------------------------------------------------------------------------- /assets/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/assets/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /assets/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/assets/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /assets/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/assets/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /assets/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/assets/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /assets/images/codelf_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/assets/images/codelf_logo.png -------------------------------------------------------------------------------- /assets/images/paypal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/assets/images/paypal.png -------------------------------------------------------------------------------- /assets/images/twohardtings.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/assets/images/twohardtings.jpg -------------------------------------------------------------------------------- /assets/images/wechatdonate.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/assets/images/wechatdonate.jpg -------------------------------------------------------------------------------- /assets/images/wechatpay.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/assets/images/wechatpay.jpg -------------------------------------------------------------------------------- /assets/images/zhifubao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/assets/images/zhifubao.png -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "presets": [ 3 | "@babel/preset-env", 4 | "@babel/preset-react" 5 | ], 6 | "plugins": [ 7 | "@babel/plugin-proposal-class-properties", 8 | "@babel/plugin-proposal-optional-chaining" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /build-system/build.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const gulp = require('gulp'); 4 | const $ = require('./util'); 5 | const webpack = require('webpack'); 6 | const webpackConfig = require('../webpack.config.js'); 7 | const env = process.env.NODE_ENV; 8 | 9 | // Builds the app scripts. 10 | gulp.task('build:app-js', () => { 11 | return new Promise(resolve => webpack(webpackConfig[env === 'production' ? 'prod' : 'dev'], (err, stats) => { 12 | if (err) throw new $.util.PluginError('webpack', err); 13 | let errorStats = stats.toString('errors-only'); 14 | if (errorStats != '') $.util.log('[webpack]', errorStats); 15 | resolve(); 16 | })); 17 | }); 18 | 19 | // Builds the app style. 20 | gulp.task('build:app-css', cb => { 21 | gulp.src(['./styles/**/*.scss'], { buffer: true }) 22 | .pipe($.sass({ 23 | outputStyle: 'expanded', 24 | sourceMap: 'app.css.map', 25 | sourceMapContents: true, 26 | sourceMapEmbed: false, 27 | includePaths: ['./node_modules/'] 28 | }).on('error', $.sass.logError)) 29 | .pipe($.cached('sass-cache', { 30 | optimizeMemory: true 31 | })) 32 | .pipe($.autoprefixer()) 33 | .pipe(gulp.dest('./app/css/')) 34 | .on('end', function () { 35 | cb(); 36 | }); 37 | }); 38 | 39 | // Builds the lib scripts. 40 | gulp.task('build:lib-js', () => { 41 | return gulp.src(require('../lib.config').js) 42 | .pipe($.concat('lib.js')) 43 | .pipe(gulp.dest('./app/js/')); 44 | }); 45 | 46 | // Builds the lib style. 47 | gulp.task('build:lib-css', () => { 48 | return gulp.src(require('../lib.config').css) 49 | .pipe($.concat('lib.css')) 50 | .pipe($.replace('@import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic&subset=latin);', '')) 51 | .pipe(gulp.dest('./app/css/')); 52 | }); 53 | 54 | // Builds the images. 55 | gulp.task('build:images', () => { 56 | return gulp.src('./assets/images/**/*.*') 57 | .pipe(gulp.dest('./app/images/')); 58 | }); 59 | 60 | // Builds the fonts. 61 | gulp.task('build:fonts', () => { 62 | return gulp.src('./assets/fonts/**/*.*') 63 | .pipe(gulp.dest('./app/fonts/')); 64 | }); 65 | 66 | // Builds extra files. 67 | gulp.task('build:extra', () => { 68 | return Promise.all(require('../lib.config').extra.map(key => { 69 | const dest = Object.keys(key); 70 | const path = key[dest]; 71 | return gulp.src(path) 72 | .pipe(gulp.dest(`./app/${dest}`)); 73 | })); 74 | }); 75 | 76 | // Builds the app. 77 | gulp.task('build', gulp.parallel('build:extra', 'build:fonts', 'build:images', 'build:app-js', 'build:lib-css', 'build:app-css', 'build:lib-js')); 78 | -------------------------------------------------------------------------------- /build-system/clean.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const gulp = require('gulp'); 4 | const del = require('del'); 5 | 6 | // Cleans dist files. 7 | gulp.task('clean:dist', () => { 8 | return del(['./dist/**'], { force: true }); 9 | }); 10 | 11 | // Cleans files. 12 | gulp.task('clean', gulp.series('clean:dist')); 13 | -------------------------------------------------------------------------------- /build-system/default.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const gulp = require('gulp'); 4 | const $ = require('./util'); 5 | 6 | function watch(files, task) { 7 | const watcher = gulp.watch(files, task); 8 | ['add', 'addDir', 'change', 'unlink', 'unlinkDir'].forEach(type => { 9 | watcher.on(type, (path, stats) => { 10 | $.util.log($.util.colors.bold('File ' + path + ' was ' + type + ', running tasks...')); 11 | }); 12 | }); 13 | } 14 | 15 | // Watches for changes in files. 16 | gulp.task('watch', cb => { 17 | watch(['lib.config.js'], gulp.series('lint', 'build:extra', 'build:lib-js', 'build:lib-css')); 18 | watch(['styles/**/*.*'], gulp.series('lint', 'build:app-css')); 19 | cb(); 20 | }); 21 | -------------------------------------------------------------------------------- /build-system/dist.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const gulp = require('gulp'); 4 | const $ = require('./util'); 5 | const pngquant = require('imagemin-pngquant'); 6 | const cachebust = $.cachebust(); 7 | const through2 = require('through2'); 8 | 9 | const distPath = './dist'; 10 | const buildVersion = (new Date()).toISOString(); 11 | 12 | // Copy all to dist. 13 | gulp.task('dist:all', () => { 14 | return gulp.src(['./app/**/**']) 15 | .pipe(gulp.dest(distPath)) 16 | .pipe($.size({ title: 'dist:all' })); 17 | }); 18 | 19 | // Compress images to dist. 20 | gulp.task('dist:images', () => { 21 | return gulp.src(['./app/images/**/*']) 22 | .pipe($.imagemin({ 23 | use: [pngquant()] 24 | })) 25 | .pipe(cachebust.resources()) 26 | .pipe(gulp.dest(distPath + '/images/')) 27 | .pipe($.size({ title: 'dist:images' })); 28 | }); 29 | 30 | // Compress css to dist. 31 | gulp.task('dist:css', () => { 32 | return gulp.src('./app/css/**/*.css') 33 | .pipe(cachebust.references()) 34 | .pipe($.csso({ comments: false })) 35 | .pipe(cachebust.resources()) 36 | .pipe(gulp.dest(distPath + '/css')) 37 | .pipe($.size({ title: 'dist:css' })); 38 | }); 39 | 40 | // Compress js to dist. 41 | gulp.task('dist:js', () => { 42 | return gulp.src(['./app/js/*.js']) 43 | .pipe(cachebust.references()) 44 | .pipe($.minify()) 45 | .pipe(cachebust.resources()) 46 | .pipe(gulp.dest(distPath + '/js/')) 47 | .pipe($.size({ title: 'dist:js' })); 48 | }); 49 | 50 | // Compress html to dist. 51 | gulp.task('dist:html', () => { 52 | return gulp.src(['./app/*.html']) 53 | .pipe(cachebust.references()) 54 | .pipe($.htmlmin({ collapseWhitespace: true, minifyCSS: true, minifyJS: true })) 55 | .pipe(gulp.dest(distPath)) 56 | .pipe($.size({ title: 'dist:html' })); 57 | }); 58 | 59 | //generate service workers 60 | gulp.task('dist:serviceworkers', cb => { 61 | const swConfig = require('../lib.config').serviceWorker; 62 | const rootPath = __dirname.replace('build-system', '') + 'dist/'; 63 | let resources = ['"./"']; 64 | gulp.src([distPath + '/**/*.*']) 65 | .pipe(through2.obj(function (file, enc, next) { 66 | !/sw\.js|\.html|\.map/.test(file.path) && this.push('"' + file.path.replace(rootPath, '') + '"'); 67 | next(); 68 | })) 69 | .on('data', data => { 70 | resources.push(data) 71 | }) 72 | .on('end', function () { 73 | gulp.src(['./src/sw.js']) 74 | .pipe($.replace(/_BUILD_VERSION_/g, buildVersion)) 75 | .pipe($.replace(/_FILES_/g, resources.join(',\n'))) 76 | .pipe($.replace(/_INCLUDED_/g, swConfig.included.join(',\n'))) 77 | .pipe($.replace(/_NETWORK_ONLY_/g, swConfig.networkOnly.join(',\n'))) 78 | .pipe($.replace(/_CACHE_ONLY_/g, swConfig.cacheOnly.join(',\n'))) 79 | .pipe($.replace(/_EXCLUDED_/g, swConfig.excluded.join(',\n'))) 80 | .pipe($.minify()) 81 | .pipe(gulp.dest(distPath)) 82 | .on('end', cb); 83 | }); 84 | }); 85 | 86 | // Dist the app. 87 | gulp.task('dist', gulp.series('clean:dist', 'dist:all', 'dist:images', 'dist:css', 'dist:js', 'dist:html', 'dist:serviceworkers')); 88 | -------------------------------------------------------------------------------- /build-system/lint.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const gulp = require('gulp'); 4 | const $ = require('./util'); 5 | 6 | // Lint JS files. 7 | gulp.task('lint', () => { 8 | return gulp.src(['gulpfile.js', 'build-system/**/*.js', 'src/**/*.js*', '!src/vendors/**/**.*', '!src/sw.js']) 9 | .pipe($.eslint()) 10 | .pipe($.eslint.format()); 11 | }); 12 | -------------------------------------------------------------------------------- /build-system/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const gulp = require('gulp'); 4 | const browserSync = require('browser-sync').create(); 5 | const $ = require('./util'); 6 | const serveIndex = require('serve-index'); 7 | const webpackDevMiddleware = require('webpack-dev-middleware'); 8 | const webpackHotMiddleware = require('webpack-hot-middleware'); 9 | const webpack = require('webpack'); 10 | const webpackConfig = require('../webpack.config.js'); 11 | 12 | // Starts a HTTP(s) server for debug. 13 | gulp.task('server', () => { 14 | return new Promise(resolve => { 15 | const compiler = webpack(webpackConfig.dev, () => { 16 | const config = { 17 | open: false, 18 | cors: true, 19 | reloadDelay: 1000, 20 | reloadDebounce: 3000, 21 | ghostMode: false, 22 | logPrefix: 'Debug Server', 23 | codeSync: $.util.argv['bs_code_sync'] != 'false', 24 | notify: false, 25 | server: { 26 | baseDir: ['./'], 27 | }, 28 | https: $.util.argv['bs_https'] != 'false', 29 | serveStatic: ['./'], 30 | middleware: [ 31 | serveIndex('.'), 32 | webpackDevMiddleware(compiler, { 33 | publicPath: webpackConfig.dev.output.publicPath, 34 | stats: { colors: true }, 35 | writeToDisk: true, 36 | logTime: true, 37 | logLevel: 'error' 38 | }), 39 | webpackHotMiddleware(compiler) 40 | ] 41 | }; 42 | if ($.util.argv['bs_proxy']) { 43 | config.server = false; 44 | config.proxy = $.util.argv['bs_proxy']; 45 | } 46 | // disable Browsersync scripts in browser 47 | if (!$.util.argv['bs_code_sync']) { 48 | config.scriptPath = () => ''; 49 | } else { 50 | gulp.watch(['./app/**/*.*'], browserSync.reload); 51 | } 52 | browserSync.init(config, resolve); 53 | }); 54 | }); 55 | }); 56 | -------------------------------------------------------------------------------- /build-system/util.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let util = require('gulp-load-plugins')(); 4 | const argv = require('minimist')(process.argv.slice(2)); 5 | const log = require('fancy-log'); 6 | const colors = require('ansi-colors'); 7 | const PluginError = require('plugin-error'); 8 | const replace = require('gulp-replace'); 9 | 10 | util.util = { 11 | argv: argv, 12 | log: log, 13 | colors: colors, 14 | PluginError: PluginError, 15 | replace: replace 16 | }; 17 | 18 | util.minify = function (options) { 19 | return util.babelMinify( 20 | Object.assign({ 21 | evaluate: false, 22 | builtIns: false, 23 | simplifyComparisons: false 24 | }, options), 25 | { 26 | comments: false 27 | } 28 | ); 29 | }; 30 | 31 | module.exports = util; 32 | -------------------------------------------------------------------------------- /dist/css/themes/default/assets/fonts/brand-icons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/css/themes/default/assets/fonts/brand-icons.eot -------------------------------------------------------------------------------- /dist/css/themes/default/assets/fonts/brand-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/css/themes/default/assets/fonts/brand-icons.ttf -------------------------------------------------------------------------------- /dist/css/themes/default/assets/fonts/brand-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/css/themes/default/assets/fonts/brand-icons.woff -------------------------------------------------------------------------------- /dist/css/themes/default/assets/fonts/brand-icons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/css/themes/default/assets/fonts/brand-icons.woff2 -------------------------------------------------------------------------------- /dist/css/themes/default/assets/fonts/icons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/css/themes/default/assets/fonts/icons.eot -------------------------------------------------------------------------------- /dist/css/themes/default/assets/fonts/icons.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/css/themes/default/assets/fonts/icons.otf -------------------------------------------------------------------------------- /dist/css/themes/default/assets/fonts/icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/css/themes/default/assets/fonts/icons.ttf -------------------------------------------------------------------------------- /dist/css/themes/default/assets/fonts/icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/css/themes/default/assets/fonts/icons.woff -------------------------------------------------------------------------------- /dist/css/themes/default/assets/fonts/icons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/css/themes/default/assets/fonts/icons.woff2 -------------------------------------------------------------------------------- /dist/css/themes/default/assets/fonts/outline-icons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/css/themes/default/assets/fonts/outline-icons.eot -------------------------------------------------------------------------------- /dist/css/themes/default/assets/fonts/outline-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/css/themes/default/assets/fonts/outline-icons.ttf -------------------------------------------------------------------------------- /dist/css/themes/default/assets/fonts/outline-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/css/themes/default/assets/fonts/outline-icons.woff -------------------------------------------------------------------------------- /dist/css/themes/default/assets/fonts/outline-icons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/css/themes/default/assets/fonts/outline-icons.woff2 -------------------------------------------------------------------------------- /dist/css/themes/default/assets/images/flags.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/css/themes/default/assets/images/flags.png -------------------------------------------------------------------------------- /dist/ddms_frame_callback.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dist/fonts/Dressedless_Three.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/fonts/Dressedless_Three.ttf -------------------------------------------------------------------------------- /dist/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /dist/fonts/LatoLatin-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/fonts/LatoLatin-Bold.woff2 -------------------------------------------------------------------------------- /dist/fonts/LatoLatin-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/fonts/LatoLatin-BoldItalic.woff2 -------------------------------------------------------------------------------- /dist/fonts/LatoLatin-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/fonts/LatoLatin-Italic.woff2 -------------------------------------------------------------------------------- /dist/fonts/LatoLatin-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/fonts/LatoLatin-Regular.woff2 -------------------------------------------------------------------------------- /dist/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /dist/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /dist/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /dist/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /dist/images/codelf_logo.f4ae25bd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/images/codelf_logo.f4ae25bd.png -------------------------------------------------------------------------------- /dist/images/codelf_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/images/codelf_logo.png -------------------------------------------------------------------------------- /dist/images/paypal.69412e83.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/images/paypal.69412e83.png -------------------------------------------------------------------------------- /dist/images/paypal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/images/paypal.png -------------------------------------------------------------------------------- /dist/images/twohardtings.0db8462a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/images/twohardtings.0db8462a.jpg -------------------------------------------------------------------------------- /dist/images/twohardtings.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/images/twohardtings.jpg -------------------------------------------------------------------------------- /dist/images/wechatdonate.3ba3a9d8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/images/wechatdonate.3ba3a9d8.jpg -------------------------------------------------------------------------------- /dist/images/wechatdonate.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/images/wechatdonate.jpg -------------------------------------------------------------------------------- /dist/images/wechatpay.5f11f80c.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/images/wechatpay.5f11f80c.jpg -------------------------------------------------------------------------------- /dist/images/wechatpay.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/images/wechatpay.jpg -------------------------------------------------------------------------------- /dist/images/zhifubao.70c19370.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/images/zhifubao.70c19370.png -------------------------------------------------------------------------------- /dist/images/zhifubao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/dist/images/zhifubao.png -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | CODELF
-------------------------------------------------------------------------------- /dist/opensearch.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | CODELF 4 | Search CODELF 5 | UTF-8 6 | CODELF Search 7 | logo 8 | 9 | 10 | -------------------------------------------------------------------------------- /dist/sw.js: -------------------------------------------------------------------------------- 1 | function asyncGeneratorStep(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){return void c(a)}h.done?b(i):Promise.resolve(i).then(d,e)}function _asyncToGenerator(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){function f(a){asyncGeneratorStep(h,d,e,f,g,"next",a)}function g(a){asyncGeneratorStep(h,d,e,f,g,"throw",a)}var h=a.apply(b,c);f(void 0)})}}var CACHE_VERSION="2023-02-10T14:15:46.873Z",CURRENT_CACHES={prefetch:"prefetch-cache-v"+CACHE_VERSION},INCLUDED=["searchcode.com","fanyi.youdao.com","api.cognitive.microsofttranslator.com","api.github.com"],CACHE_ONLY=["fanyi.youdao.com","api.cognitive.microsofttranslator.com","api.github.com"],NETWORK_ONLY=[],EXCLUDED=[];function matchLocation(a,b){return b.find(function(b){return-1!==a.indexOf(b)})}self.addEventListener("install",function(a){self.skipWaiting();var b=Date.now(),c=["./","opensearch.xml","css/app.css","css/app.f1364fce.css","css/lib.b0f67b98.css","css/lib.css","fonts/Dressedless_Three.svg","fonts/Dressedless_Three.ttf","fonts/FontAwesome.otf","fonts/LatoLatin-Bold.woff2","fonts/LatoLatin-BoldItalic.woff2","fonts/LatoLatin-Italic.woff2","fonts/LatoLatin-Regular.woff2","fonts/fontawesome-webfont.eot","fonts/fontawesome-webfont.svg","fonts/fontawesome-webfont.ttf","fonts/fontawesome-webfont.woff","fonts/fontawesome-webfont.woff2","images/codelf_logo.f4ae25bd.png","images/codelf_logo.png","images/paypal.69412e83.png","images/paypal.png","images/twohardtings.0db8462a.jpg","images/twohardtings.jpg","images/wechatdonate.3ba3a9d8.jpg","images/wechatdonate.jpg","images/wechatpay.5f11f80c.jpg","images/wechatpay.jpg","images/zhifubao.70c19370.png","images/zhifubao.png","js/app.792fa086.js","js/app.js","js/lib.5e430a5b.js","js/lib.js","css/themes/default/assets/fonts/brand-icons.eot","css/themes/default/assets/fonts/brand-icons.svg","css/themes/default/assets/fonts/brand-icons.ttf","css/themes/default/assets/fonts/brand-icons.woff","css/themes/default/assets/fonts/brand-icons.woff2","css/themes/default/assets/fonts/icons.eot","css/themes/default/assets/fonts/icons.otf","css/themes/default/assets/fonts/icons.svg","css/themes/default/assets/fonts/icons.ttf","css/themes/default/assets/fonts/icons.woff","css/themes/default/assets/fonts/icons.woff2","css/themes/default/assets/fonts/outline-icons.eot","css/themes/default/assets/fonts/outline-icons.svg","css/themes/default/assets/fonts/outline-icons.ttf","css/themes/default/assets/fonts/outline-icons.woff","css/themes/default/assets/fonts/outline-icons.woff2","css/themes/default/assets/images/flags.png"];console.log("Handling install event. Resources to prefetch:",c),a.waitUntil(caches.open(CURRENT_CACHES.prefetch).then(function(a){var d=c.map(function(c){var d=new URL(c,location.href);d.search+=(d.search?"&":"?")+"cache-bust="+b;var e=new Request(d,{mode:"no-cors"});return fetch(e).then(function(b){if(400<=b.status)throw new Error("request for "+c+" failed with status "+b.statusText);return a.put(c,b)})["catch"](function(a){console.error("Not caching "+c+" due to "+a)})});return Promise.all(d).then(function(){console.log("Pre-fetching complete.")})})["catch"](function(a){console.error("Pre-fetching failed:",a)}))}),self.addEventListener("activate",function(a){var b=Object.keys(CURRENT_CACHES).map(function(a){return CURRENT_CACHES[a]});a.waitUntil(caches.keys().then(function(a){return Promise.all(a.map(function(a){if(-1===b.indexOf(a))return console.log("Deleting out of date cache:",a),caches["delete"](a)}))}))}),self.addEventListener("fetch",function(a){console.log("Handling fetch event for",a.request.url);var b=new URL(a.request.url);"navigate"===a.request.mode?(console.log("request mode:",a.request.mode),a.respondWith(_asyncToGenerator(regeneratorRuntime.mark(function c(){var d,e,f;return regeneratorRuntime.wrap(function(c){for(;;)switch(c.prev=c.next){case 0:return d=b,d.search="",e=fetch(d),f=e.then(function(a){return a.clone()}),a.waitUntil(_asyncToGenerator(regeneratorRuntime.mark(function a(){var b;return regeneratorRuntime.wrap(function(a){for(;;)switch(a.prev=a.next){case 0:return a.next=2,caches.open(CURRENT_CACHES.prefetch);case 2:return b=a.sent,a.t0=b,a.t1=d,a.next=7,f;case 7:return a.t2=a.sent,a.next=10,a.t0.put.call(a.t0,a.t1,a.t2);case 10:case"end":return a.stop();}},a)}))()),c.next=7,caches.match(d);case 7:if(c.t0=c.sent,c.t0){c.next=10;break}c.t0=e;case 10:return c.abrupt("return",c.t0);case 11:case"end":return c.stop();}},c)}))())):matchLocation(b.href,INCLUDED)&&!matchLocation(b.href,EXCLUDED)&&/get/i.test(a.request.method)?matchLocation(b.href,NETWORK_ONLY)?(console.log("network-falling-back-to-caches:",a.request.url),a.respondWith(caches.open(CURRENT_CACHES.prefetch).then(function(b){return fetch(a.request).then(function(c){return b.put(a.request,c.clone()),c})["catch"](function(){return b.match(a.request).then(function(a){return a})})}))):matchLocation(b.href,CACHE_ONLY)?(console.log("cache-falling-back-to-network:",a.request.url),a.respondWith(caches.open(CURRENT_CACHES.prefetch).then(function(b){return b.match(a.request).then(function(c){return c||fetch(a.request).then(function(c){return b.put(a.request,c.clone()),c})})}))):(console.log("cache-then-network:",a.request.url),a.respondWith(caches.open(CURRENT_CACHES.prefetch).then(function(b){return b.match(a.request).then(function(c){var d=fetch(a.request).then(function(c){return b.put(a.request,c.clone()),c});return c||d})}))):b.origin==location.origin&&(console.log("request origin:",b.origin),a.respondWith(caches.match(a.request).then(function(b){return b?(console.log("Found response in cache:",b),b):(console.log("No response found in cache. About to fetch from network..."),fetch(a.request).then(function(a){return console.log("Response from network is:",a),a})["catch"](function(a){throw console.error("Fetching failed:",a),a}))})))}),"storage"in navigator&&"estimate"in navigator.storage&&navigator.storage.estimate().then(function(a){console.log("Using ".concat(a.usage," out of ").concat(a.quota," bytes."))}); -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const gulp = require('gulp'); 4 | const $ = require('./build-system/util'); 5 | const requireDir = require('require-dir'); 6 | requireDir('./build-system'); 7 | 8 | gulp.task('help', cb => { 9 | $.util.log( 10 | ` 11 | Usage 12 | gulp [TASK] [OPTIONS...] 13 | 14 | Available tasks 15 | build Builds the app. 16 | build:app-css Builds the app style. 17 | build:app-js Builds the app scripts. 18 | build:extra Builds extra files. 19 | build:images Builds the app style. 20 | build:lib-css Builds the lib style. 21 | build:lib-js Builds the lib scripts. 22 | clean Cleans files. 23 | clean:dist Cleans dist files. 24 | default 25 | dist Dist the app. 26 | dist:all Copy all to dist. 27 | dist:css Compress css to dist. 28 | dist:html Compress html to dist. 29 | dist:images Compress images to dist. 30 | dist:js Compress js to dist. 31 | help Display this help text. 32 | lint Lint JS files. 33 | server Starts a HTTP(s) server for debug. 34 | watch Watches for changes in files. 35 | ` 36 | ); 37 | cb(); 38 | }); 39 | 40 | // Run tasks: lint, build, docs, watch, server 41 | gulp.task('default', cb => { 42 | $.util.log( 43 | $.util.colors.green('Building and watching for changes ...') 44 | ); 45 | gulp.series( 46 | 'lint', 47 | 'build:extra', 'build:images', 'build:app-css', 'build:lib-js', 'build:lib-css', 'watch', 'server', () => { 48 | $.util.log( 49 | $.util.colors.green('Ready! Run "gulp help" for more build command usages.'), '\n' 50 | ); 51 | })(cb); 52 | }); 53 | -------------------------------------------------------------------------------- /lib.config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.js = [ 4 | './node_modules/react/umd/react.production.min.js', 5 | './node_modules/react-dom/umd/react-dom.production.min.js', 6 | './node_modules/clipboard/dist/clipboard.min.js', 7 | './src/vendors/prettify.js', 8 | './node_modules/mark.js/dist/mark.min.js' 9 | ]; 10 | 11 | exports.css = [ 12 | './node_modules/semantic-ui-css/semantic.min.css', 13 | './node_modules/animate.css/animate.min.css', 14 | './src/vendors/prettify.css' 15 | ]; 16 | 17 | exports.extra = [{ 18 | 'css/themes': './node_modules/semantic-ui-css/themes/**' 19 | }]; 20 | 21 | // configs for service worker, get request only, not in "included" url won't be cached 22 | exports.serviceWorker = { 23 | included: [ // cache then network, url must start with it's host 24 | '"searchcode.com"', 25 | '"fanyi.youdao.com"', 26 | '"api.cognitive.microsofttranslator.com"', 27 | '"api.github.com"' 28 | ], 29 | networkOnly: [ // network falling back to cache, url|path|etc must included in "included" 30 | ], 31 | cacheOnly: [ // cache fallback to network, url|path|etc must included in "included" 32 | '"fanyi.youdao.com"', 33 | '"api.cognitive.microsofttranslator.com"', 34 | '"api.github.com"' 35 | ], 36 | excluded: [ // won't be cache, url|path|etc must included in "included" 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Codelf", 3 | "version": "8.1.0", 4 | "description": "A search tool helps dev to solve the naming things problem.", 5 | "keywords": [ 6 | "Codelf", 7 | "real-world usage variable names", 8 | "searchcode" 9 | ], 10 | "author": "unbug", 11 | "license": "snts", 12 | "scripts": { 13 | "test": "echo \"Error: no test specified\" && exit 1", 14 | "start": "gulp", 15 | "build": "NODE_ENV=production gulp build", 16 | "dist": "NODE_ENV=production gulp build && gulp dist", 17 | "gh-pages": "npm run dist && sleep 3 && git add dist/ && git commit -m \"build dist\" && git push origin `git subtree split --prefix dist HEAD`:gh-pages --force" 18 | }, 19 | "devDependencies": { 20 | "@babel/core": "^7.7.4", 21 | "@babel/plugin-proposal-class-properties": "^7.7.4", 22 | "@babel/plugin-proposal-optional-chaining": "^7.7.4", 23 | "@babel/preset-env": "^7.7.4", 24 | "@babel/preset-react": "^7.7.4", 25 | "ansi-colors": "^4.1.1", 26 | "babel-eslint": "^10.0.3", 27 | "babel-loader": "^8.0.6", 28 | "browser-sync": "^2.26.7", 29 | "css-loader": "^3.2.1", 30 | "cssnano": "^4.1.10", 31 | "del": "^5.1.0", 32 | "eslint": "^6.7.2", 33 | "eslint-plugin-react": "^7.17.0", 34 | "eslint-plugin-react-hooks": "^2.3.0", 35 | "fancy-log": "^1.3.3", 36 | "gulp": "^4.0.2", 37 | "gulp-autoprefixer": "^7.0.1", 38 | "gulp-babel-minify": "^0.5.1", 39 | "gulp-cachebust": "0.0.10", 40 | "gulp-cached": "^1.1.1", 41 | "gulp-concat": "^2.6.1", 42 | "gulp-csso": "^3.0.1", 43 | "gulp-eslint": "^6.0.0", 44 | "gulp-htmlmin": "^5.0.1", 45 | "gulp-if": "^3.0.0", 46 | "gulp-imagemin": "^6.2.0", 47 | "gulp-load-plugins": "^2.0.1", 48 | "gulp-replace": "^1.0.0", 49 | "gulp-sass": "^4.0.2", 50 | "gulp-sass-lint": "^1.4.0", 51 | "gulp-size": "^3.0.0", 52 | "gulp-watch": "^5.0.1", 53 | "imagemin-pngquant": "^8.0.0", 54 | "minimist": "^1.2.0", 55 | "node-sass": "^4.13.0", 56 | "plugin-error": "^1.0.1", 57 | "require-dir": "^1.2.0", 58 | "sass-loader": "^8.0.0", 59 | "serve-index": "^1.9.1", 60 | "through2": "^3.0.0", 61 | "webpack": "^4.41.2", 62 | "webpack-cli": "^3.3.10", 63 | "webpack-dev-server": "^3.9.0", 64 | "webpack-hot-middleware": "^2.25.0", 65 | "webpack-merge": "^4.2.2" 66 | }, 67 | "dependencies": { 68 | "@babel/polyfill": "^7.7.0", 69 | "animate.css": "^3.7.2", 70 | "clipboard": "^2.0.4", 71 | "code-prettify": "^0.1.0", 72 | "css-doodle": "^0.7.6", 73 | "events": "^3.0.0", 74 | "file-saver": "^2.0.2", 75 | "lodash": "^4.17.15", 76 | "mark.js": "^8.11.1", 77 | "nprogress": "^0.2.0", 78 | "react": "^16.12.0", 79 | "react-dom": "^16.12.0", 80 | "react-router-dom": "^5.1.2", 81 | "semantic-ui-css": "^2.4.1", 82 | "semantic-ui-react": "^0.88.1", 83 | "spark-md5": "^3.0.0", 84 | "whatwg-fetch": "^3.0.0" 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import 'whatwg-fetch'; 2 | import ReactDOM from 'react-dom'; 3 | import MainContainer from './containers/MainContainer'; 4 | // import CopybookContainer from './containers/CopybookContainer'; 5 | import NoticeContainer from './containers/NoticeContainer'; 6 | import NavBarContainer from './containers/NavBarContainer'; 7 | 8 | function App() { 9 | return ( 10 | <> 11 | 12 | 13 | {/* */} 14 | 15 | 16 | ); 17 | } 18 | 19 | ReactDOM.render(, document.querySelector('.app')); 20 | -------------------------------------------------------------------------------- /src/components/Bookmark.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unbug/codelf/0bfb88a8d297ca0f65abbf8f83f7826311df42a3/src/components/Bookmark.js -------------------------------------------------------------------------------- /src/components/Copybook.js: -------------------------------------------------------------------------------- 1 | import React, { useRef } from 'react'; 2 | import { Button, Dropdown, Modal } from 'semantic-ui-react'; 3 | import Loading from "./Loading"; 4 | import useCodeHighlighting from './hooks/useCodeHighlighting'; 5 | 6 | export default function Copybook(props) { 7 | const codeEl = useCodeHighlighting([props.copybookFileContent, props.copybookVisible]); 8 | const editorEl = useRef(null); 9 | 10 | function handleClose() { 11 | props.onCloseCopybook(); 12 | } 13 | 14 | function handleDropdownChange(e, { searchQuery, value }) { 15 | if (value != props.copybookSelectedFile.path) { 16 | props.onRequestCopybookFile( 17 | props.copybookFileList.find(f => f.path === value) 18 | ); 19 | } 20 | } 21 | 22 | function renderDropdownItem() { 23 | if (!props.copybookFileList) { 24 | return null; 25 | } 26 | return props.copybookFileList.map((file, idx) => { 27 | return { 28 | key: file.path, 29 | value: file.path, 30 | text: (idx + 1) + '. ' + file.path 31 | } 32 | }); 33 | } 34 | 35 | if (!props.copybookVisible || !props.copybookFileList || !props.copybookFileContent) { 36 | return ( 37 | 39 | 40 |
Daily Algorithm Copybook
41 |
42 | 43 | 44 |
45 |
46 |
47 | ); 48 | } 49 | 50 | return ( 51 | 53 | 54 |
Daily Algorithm Copybook
55 | 58 | 64 |
65 | 66 | {props.copybookRequesting ? : ''} 67 |
68 |           {props.copybookFileContent.content}
69 |           
70 |
71 |
72 |
73 | ) 74 | } 75 | -------------------------------------------------------------------------------- /src/components/Donate.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import * as Tools from '../utils/Tools'; 3 | 4 | const cnText = Tools.randomList([ 5 | '颈椎病晚期', 6 | '买不起奶粉', 7 | '快交不起房租', 8 | '全年996', 9 | '有可能会猝死', 10 | '快要失业', 11 | '头发越来越少', 12 | '还没从 ICU 出来', 13 | '天天写需求', 14 | '又被降薪', 15 | '昨晚熬夜修 BUG ' 16 | ], 1)[0]; 17 | export default function Donate(props) { 18 | let text =

Buy @unbug a drink

; 19 | if (props.isZH) { 20 | text =

{cnText}的作者打赏个红包吧

; 21 | } 22 | return ( 23 |
24 |
{text}
25 |
26 | 27 | 28 |
29 | 30 | 31 | 33 |
34 |
35 |
36 | ) 37 | } 38 | -------------------------------------------------------------------------------- /src/components/Doodle.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import 'css-doodle'; 3 | 4 | export default function Doodle(props) { 5 | const { text } = props; 6 | let doodle = null; 7 | if (/鱼|fish/i.test(text)) { 8 | doodle = 'fish'; 9 | } else if (/糖|甜|candy|圣诞|Christmas|xmas|春节/i.test(text)) { 10 | doodle = 'candy' 11 | } 12 | 13 | if (!doodle) { return null; } 14 | 15 | return ( 16 | 17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /src/components/Loading.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default function Loading() { 4 | return ( 5 |
6 |
7 |
8 | ) 9 | } 10 | -------------------------------------------------------------------------------- /src/components/SearchBar.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useRef, useState } from 'react'; 2 | import { Dropdown, Icon, Input } from 'semantic-ui-react'; 3 | 4 | // http://githut.info/ 5 | const topProgramLan = [ 6 | { id: '22,106', language: 'JavaScript, CoffeeScript' }, 7 | { id: '133,135', language: 'CSS' }, 8 | { id: '3,39', language: 'HTML' }, 9 | { id: 137, language: 'Swift' }, 10 | { id: 35, language: 'Objective-C' }, 11 | { id: 23, language: 'Java' }, 12 | { id: 19, language: 'Python' }, 13 | { id: 24, language: 'PHP' }, 14 | { id: 32, language: 'Ruby' }, 15 | { id: 28, language: 'C' }, 16 | { id: 16, language: 'C++' }, 17 | { id: 6, language: 'C#' }, 18 | { id: 55, language: 'Go' }, 19 | { id: 51, language: 'Perl' }, 20 | { id: '104,109', language: 'Clojure, ClojureScript' }, 21 | { id: 40, language: 'Haskell' }, 22 | { id: 54, language: 'Lua' }, 23 | { id: 20, language: 'Matlab' }, 24 | { id: 144, language: 'R' }, 25 | { id: 47, language: 'Scala' }, 26 | { id: '69,78,146', language: 'Shell' }, 27 | { id: 29, language: 'Lisp' }, 28 | { id: 42, language: 'ActionScript' } 29 | ]; 30 | 31 | export default function SearchBar(props) { 32 | const inputEl = useRef(null); 33 | const inputSize = useInputSize('huge'); 34 | const [state, setState] = useState({ 35 | lang: props.searchLang || [], 36 | valChanged: false 37 | }); 38 | 39 | function updateState(vals) { 40 | setState(prevState => { 41 | return { ...prevState, ...vals }; 42 | }); 43 | } 44 | 45 | function handleSearch() { 46 | props.onSearch(inputEl.current.inputRef.current.value, state.lang); 47 | inputEl.current.inputRef.current.blur(); 48 | updateState({ valChanged: false }); 49 | } 50 | 51 | function handleRestLang() { 52 | updateState({ lang: [], valChanged: true }); 53 | } 54 | 55 | function handleSelectLang(id) { 56 | updateState({ lang: state.lang.concat(id).sort(), valChanged: true }); 57 | } 58 | 59 | function handleDeselectLang(id) { 60 | let lang = state.lang; 61 | lang.splice(state.lang.indexOf(id), 1); 62 | updateState({ lang: lang.sort(), valChanged: true }); 63 | } 64 | 65 | function handleToggleSelectLang(id) { 66 | state.lang.indexOf(id) === -1 ? handleSelectLang(id) : handleDeselectLang(id); 67 | } 68 | 69 | const langItems = topProgramLan.map(key => { 70 | const active = state.lang.indexOf(key.id) !== -1; 71 | return handleToggleSelectLang(key.id)}> 74 | {key.language} 75 | ; 76 | }); 77 | 78 | return ( 79 |
80 |
81 | Search over GitHub, Bitbucket, GitLab to find real-world usage variable names 82 |
83 |
84 | updateState({ valChanged: true })} 86 | className='search-bar__input' 87 | icon fluid placeholder={props.placeholder} size={inputSize}> 88 | 89 | 90 | 91 | 92 | {langItems} 93 | 94 | 95 | 96 | 97 | { 99 | e.key === 'Enter' && handleSearch() 100 | }} /> 101 | 103 | 104 | {props.luckyKeyWords.map((item, i) => 106 | 107 | 108 |
109 | Extensions:  110 | VS Code,  112 | Atom,  114 | Sublime,  116 | WebStorm,  118 | Alfred 120 |
121 |
122 | ) 123 | } 124 | 125 | function useInputSize(val) { 126 | const [size, setSize] = useState(val); 127 | 128 | useEffect(() => { 129 | resizeInput(); 130 | window.addEventListener('resize', resizeInput, false); 131 | return () => window.removeEventListener('resize', resizeInput, false); 132 | }, []);// run an effect and clean it up only once (on mount and unmount), you can pass an empty array ([]) 133 | 134 | function resizeInput() { 135 | setSize(document.body.offsetWidth < 800 ? '' : val); 136 | } 137 | 138 | return size; 139 | } 140 | -------------------------------------------------------------------------------- /src/components/SearchError.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Label } from 'semantic-ui-react'; 3 | 4 | export default function SearchError() { 5 | return ( 6 |
7 |
Nothing found, please try or come back later :)
8 |
You can also get help from https://github.com/unbug/codelf/issues. 11 |
12 |
13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /src/components/SourceCode.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Modal, Button, Dropdown, Label } from 'semantic-ui-react'; 3 | import * as Tools from '../utils/Tools'; 4 | import Loading from "./Loading"; 5 | import useCodeHighlighting from './hooks/useCodeHighlighting'; 6 | 7 | export default function SourceCode(props) { 8 | const codeEl = useCodeHighlighting([props.sourceCode, props.sourceCodeVisible], props.sourceCodeVariable ?.keyword); 9 | 10 | function handleClose() { 11 | props.onCloseSourceCode(); 12 | } 13 | 14 | if (!props.sourceCodeVariable || !props.sourceCodeRepo) { return null; } 15 | const sourceCodeVariable = props.sourceCodeVariable; 16 | const dropText = ( 17 |
All Codes
20 | ); 21 | const dropdownItems = props.sourceCodeVariable && props.sourceCodeVariable.repoList.map(repo => { 22 | return ( 23 | 24 | 25 | 26 | 27 | 28 | ) 29 | }); 30 | return ( 31 | 33 | 34 | 36 | 37 | 38 | {dropdownItems} 39 | 40 | 41 | 42 | 43 | 44 | 45 | {props.sourceCodeRequesting ? : ''} 46 |
{props.sourceCode}
47 |
48 |
49 | ) 50 | } 51 | -------------------------------------------------------------------------------- /src/components/Suggestion.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Label } from 'semantic-ui-react'; 3 | 4 | export default function Suggestion(props) { 5 | if (!props.suggestion || !props.suggestion.length) { return null; } 6 | const list = props.suggestion.map((item, i) => { 7 | return 8 | }); 9 | return ( 10 |
11 | {list} 12 |
13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /src/components/TitleLogo.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default function TitleLogo() { 4 | return ( 5 |
6 |

CODELF

7 |
8 | ) 9 | } 10 | -------------------------------------------------------------------------------- /src/components/VariableItem.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Button, Label, Popup } from 'semantic-ui-react'; 3 | import * as Tools from '../utils/Tools'; 4 | 5 | export default function VariableItem(props) { 6 | const clipboardId = `clipboardId-${Tools.uuid()}`; 7 | const variable = props.variable; 8 | let clipboard = null; 9 | 10 | function handlePopOnMount() { 11 | clipboard = new ClipboardJS(`#${clipboardId}`); 12 | } 13 | 14 | function handlePopUnmount() { 15 | clipboard && clipboard.destroy(); 16 | } 17 | 18 | return ( 19 | 23 | {variable.keyword} 24 | } 25 | onMount={handlePopOnMount} 26 | onUnmount={handlePopUnmount} 27 | hoverable={true}> 28 | 29 | 30 | 31 | 32 | 35 | 36 | 37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /src/components/VariableList.js: -------------------------------------------------------------------------------- 1 | import React, { useMemo, useRef } from 'react'; 2 | import * as Tools from '../utils/Tools'; 3 | import VariableItem from './VariableItem'; 4 | 5 | const notFound = val => val && /59ce9297fba93aeb9d693a2f61922fb6|bfd876277827a33f49d363e8857977a0/g.test(Tools.MD5(val)); 6 | const notFoundImg = '//user-images.githubusercontent.com/799578/50722775-1a9a1d00-110f-11e9-9bcc-efe5465a4ad5.jpg'; 7 | const animationName = Math.random() > 0.5 ? 'zoomInDown' : 'zoomInUp'; 8 | 9 | export default function VariableList(props) { 10 | const lastPageLen = useRef(); 11 | const list = useMemo(() => { // same as "shouldComponentUpdate", only compute when "variableList" has changed 12 | const variableList = props.variableList; 13 | const pageLen = variableList.length; 14 | let pages = []; 15 | if (notFound(props.searchValue)) { 16 | pages.push(); 17 | } 18 | variableList.forEach((list, i) => { 19 | const isLast = i === pageLen - 1 && lastPageLen.current != pageLen; 20 | const variables = list.map((variable, j) => { 21 | let style = {}, className = '', duration = (list.length - j) / list.length; 22 | if (isLast) { 23 | className = 'animated'; 24 | style = { 25 | animationName: animationName, 26 | animationDelay: duration + 's', 27 | animationDuration: Math.min(duration, 0.8) + Math.random() + 's' 28 | }; 29 | } 30 | return 32 | }); 33 | if (variables && variables.length) { 34 | if (pages.length) { 35 | pages.unshift(
); 36 | } 37 | Array.prototype.unshift.apply(pages, variables) 38 | } 39 | }); 40 | lastPageLen.current = pageLen; 41 | return pages; 42 | }, [props.variableList]); 43 | 44 | return
{list}
; 45 | } 46 | -------------------------------------------------------------------------------- /src/components/hooks/useCodeHighlighting.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef } from 'react'; 2 | 3 | export default function useCodeHighlighting(watchedProps, keyword) { 4 | const container = useRef(null); 5 | const mark = useRef(null); 6 | useEffect(() => { 7 | renderPrettyPrint(); 8 | }, [...watchedProps]); 9 | 10 | function renderPrettyPrint() { 11 | setTimeout(() => { 12 | if (container.current) { 13 | container.current.classList.remove('prettyprinted'); 14 | setTimeout(() => PR.prettyPrint( 15 | () => setTimeout(() => renderHighLight(), 1000) 16 | ), 100); 17 | } 18 | }, container.current ? 0 : 1000); 19 | } 20 | 21 | function renderHighLight() { 22 | if (!keyword) { 23 | return; 24 | } 25 | if (mark.current) { 26 | mark.current.unmark() 27 | } 28 | mark.current = new Mark(container.current); 29 | let idx = 0; 30 | mark.current.mark(keyword, { 31 | each: el => { 32 | el.setAttribute('tabindex', idx++); 33 | } 34 | }); 35 | } 36 | 37 | return container; 38 | } 39 | -------------------------------------------------------------------------------- /src/constants/Configs.js: -------------------------------------------------------------------------------- 1 | import * as Tools from '../utils/Tools'; 2 | 3 | const APP_NANE = 'codelf'; 4 | const PAGE_URL = Tools.thisPage; 5 | const PAGE_PATH = Tools.thisPath; 6 | 7 | export { APP_NANE, PAGE_PATH, PAGE_URL } 8 | -------------------------------------------------------------------------------- /src/containers/CopybookContainer.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useReducer } from 'react'; 2 | import AppModel from '../models/AppModel'; 3 | import CopybookModel from '../models/CopybookModel'; 4 | import Copybook from '../components/Copybook'; 5 | 6 | const actionTypes = { 7 | UPDATE: 'update', 8 | }; 9 | 10 | const initState = { 11 | copybookRequesting: false, 12 | copybookVisible: CopybookModel.visible, 13 | copybookFileList: CopybookModel.fileList, 14 | copybookSelectedFile: CopybookModel.selectedFile, 15 | copybookFileContent: CopybookModel.fileContent, 16 | }; 17 | 18 | function reducer(state, action) { 19 | switch (action.type) { 20 | case actionTypes.UPDATE: 21 | return { 22 | ...state, 23 | ...action.payload 24 | }; 25 | default: 26 | return state; 27 | } 28 | } 29 | 30 | export default function CopybookContainer(props) { 31 | const [state, dispatch] = useReducer(reducer, initState); 32 | 33 | useEffect(() => { 34 | CopybookModel.onUpdated(handleCopybookModelUpdate); 35 | return () => CopybookModel.offUpdated(handleCopybookModelUpdate); 36 | }); 37 | 38 | function setState(payload) { 39 | dispatch({ type: actionTypes.UPDATE, payload: payload }); 40 | } 41 | 42 | function handleCopybookModelUpdate(curr, prev, mutation) { 43 | if (mutation.fileList) { 44 | setState({ 45 | copybookFileList: CopybookModel.fileList 46 | }); 47 | } 48 | if (mutation.fileContent) { 49 | setState({ 50 | copybookRequesting: false, 51 | copybookSelectedFile: CopybookModel.selectedFile, 52 | copybookFileContent: CopybookModel.fileContent, 53 | }); 54 | } 55 | if (mutation.visible) { 56 | setState({ 57 | copybookVisible: CopybookModel.visible, 58 | }); 59 | if (CopybookModel.visible) { 60 | AppModel.analytics('copybook&q=read'); 61 | } 62 | } 63 | } 64 | 65 | function handleCloseCopybook() { 66 | CopybookModel.update({ visible: false }); 67 | } 68 | 69 | function handleRequestCopybookFile(file) { 70 | setState({ copybookRequesting: true }); 71 | CopybookModel.requestRepoFile(file); 72 | AppModel.analytics('copybook&q=read'); 73 | } 74 | 75 | return ; 79 | } 80 | -------------------------------------------------------------------------------- /src/containers/MainContainer.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useReducer, useCallback } from 'react'; 2 | import { Container } from 'semantic-ui-react'; 3 | import SearchBar from '../components/SearchBar'; 4 | import TitleLogo from '../components/TitleLogo'; 5 | import SearchCodeModel from '../models/SearchCodeModel'; 6 | import HashHandler from '../utils/HashHandler'; 7 | import VariableList from '../components/VariableList'; 8 | import SearchError from '../components/SearchError'; 9 | import Loading from '../components/Loading'; 10 | import Donate from '../components/Donate'; 11 | import Suggestion from '../components/Suggestion'; 12 | import SourceCode from '../components/SourceCode'; 13 | import AppModel from '../models/AppModel'; 14 | import DDMSModel from '../models/DDMSModel'; 15 | import Doodle from '../components/Doodle'; 16 | 17 | const actionTypes = { 18 | UPDATE: 'update', 19 | }; 20 | 21 | const initState = { 22 | isZH: false, 23 | isError: false, 24 | variableRequesting: false, 25 | searchValue: SearchCodeModel.searchValue, 26 | searchLang: SearchCodeModel.searchLang, 27 | page: SearchCodeModel.page, 28 | variableList: SearchCodeModel.variableList, 29 | suggestion: SearchCodeModel.suggestion, 30 | luckyKeyWords: DDMSModel.luckyKeyWords, 31 | sourceCodeRequesting: false, 32 | sourceCodeVisible: false, 33 | sourceCodeVariable: null, 34 | sourceCodeRepo: null, 35 | }; 36 | 37 | function reducer(state, action) { 38 | switch (action.type) { 39 | case actionTypes.UPDATE: 40 | return { 41 | ...state, 42 | ...action.payload 43 | }; 44 | default: 45 | return state; 46 | } 47 | } 48 | 49 | 50 | export default function MainContainer(props) { 51 | const [state, dispatch] = useReducer(reducer, initState); 52 | 53 | useEffect(() => { 54 | AppModel.analytics(); 55 | setTimeout(handleLocationHashChanged, 100); 56 | window.addEventListener('hashchange', handleLocationHashChanged, false); 57 | return () => window.removeEventListener('hashchange', handleLocationHashChanged); 58 | }, []); 59 | 60 | useEffect(() => { 61 | state.variableList.length && document.body.classList.add('dark'); 62 | }, [state.variableList]); 63 | 64 | useEffect(() => { 65 | SearchCodeModel.onUpdated(handleSearchCodeModelUpdate); 66 | return () => SearchCodeModel.offUpdated(handleSearchCodeModelUpdate); 67 | }); 68 | 69 | useEffect(() => { 70 | function handleDDMSModelUpdate(curr, prev, mutation) { 71 | if (mutation.luckyKeyWords) { 72 | setState({ luckyKeyWords: curr.luckyKeyWords }); 73 | } 74 | } 75 | DDMSModel.onUpdated(handleDDMSModelUpdate); 76 | return () => DDMSModel.offUpdated(handleDDMSModelUpdate); 77 | }, []); 78 | 79 | const handleSearch = useCallback((val, lang) => { 80 | if (val === null || val === undefined || state.variableRequesting) { 81 | return; 82 | } 83 | val = val.trim().replace(/\s+/ig, ' '); // filter spaces 84 | if (val.length < 1) { 85 | return; 86 | } 87 | if (val == state.searchValue) { 88 | requestVariable(val, lang); 89 | } else { 90 | setState({ searchLang: lang }); 91 | setTimeout(() => HashHandler.set(val)); // update window.location.hash 92 | } 93 | }, [state.searchValue, state.variableRequesting]); 94 | 95 | const handleOpenSourceCode = useCallback((variable) => { 96 | setState({ sourceCodeVariable: variable }); 97 | setTimeout(() => requestSourceCode(variable.repoList[0]), 0); 98 | }, []); 99 | 100 | function handleCloseSourceCode() { 101 | setState({ sourceCodeVisible: false }); 102 | } 103 | 104 | function handleRequestSourceCode(repo) { 105 | requestSourceCode(repo); 106 | } 107 | 108 | function renderSloganImage() { 109 | if (state.page > 0 || state.variableList.length) { 110 | return ''; 111 | } 112 | return
; 113 | } 114 | 115 | function renderDoodle() { 116 | if (state.variableList.length == 0) { return null; } 117 | return 118 | } 119 | 120 | function setState(payload) { 121 | dispatch({ type: actionTypes.UPDATE, payload: payload }); 122 | } 123 | 124 | function checkError(data) { 125 | if (state.variableRequesting) { 126 | // no search result 127 | if (data.variableList.length < 1 || data.variableList[data.variableList.length - 1].length < 1) { 128 | return true; 129 | } 130 | } 131 | return false; 132 | } 133 | 134 | function requestVariable(val, lang) { 135 | const langChanged = lang ? (lang.join(',') != state.searchLang.join(',')) : !!state.searchLang; 136 | val = decodeURIComponent(val); 137 | let page = state.page; 138 | if (val == state.searchValue && !langChanged) { 139 | page += 1; 140 | } else { 141 | page = 0; 142 | } 143 | setState({ searchValue: val, variableRequesting: true }); 144 | SearchCodeModel.requestVariable(val, page, lang || state.searchLang); 145 | AppModel.analytics('q=' + val); 146 | DDMSModel.postKeyWords(val); 147 | updateDocTitle(val); 148 | } 149 | 150 | function requestSourceCode(repo) { 151 | setState({ 152 | sourceCodeVisible: true, 153 | sourceCodeRequesting: true, 154 | sourceCodeRepo: repo 155 | }); 156 | SearchCodeModel.requestSourceCode(repo.id); 157 | AppModel.analytics('sourcecode&q=' + state.sourceCodeVariable.keyword); 158 | } 159 | 160 | function updateDocTitle(title) { 161 | document.title = `${title ? (title + ' - ') : ''}CODELF`; 162 | } 163 | 164 | function handleLocationHashChanged(e) { 165 | e && e.preventDefault(); 166 | const hash = HashHandler.get(); 167 | hash && requestVariable(hash.replace(/(\?.*)/, '')); 168 | } 169 | 170 | function handleSearchCodeModelUpdate(curr, prev, mutation) { 171 | if (mutation.variableList) { 172 | setState({ 173 | isZH: SearchCodeModel.isZH || state.isZH, 174 | isError: checkError(curr), 175 | variableRequesting: !mutation.variableList, 176 | searchValue: SearchCodeModel.searchValue, 177 | searchLang: SearchCodeModel.searchLang, 178 | page: SearchCodeModel.page, 179 | variableList: SearchCodeModel.variableList, 180 | suggestion: SearchCodeModel.suggestion 181 | }); 182 | } 183 | if (mutation.sourceCode) { 184 | setState({ 185 | sourceCodeRequesting: false, 186 | sourceCode: SearchCodeModel.sourceCode 187 | }); 188 | } 189 | } 190 | 191 | return ( 192 | 193 | 194 | 195 | 196 | {state.variableRequesting ? : (state.isError ? : '')} 197 | {renderSloganImage()} 198 | 199 | {state.variableList.length ? : ''} 200 | 203 | {renderDoodle()} 204 | 205 | ) 206 | } 207 | -------------------------------------------------------------------------------- /src/containers/NavBarContainer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Container, Icon, Popup } from 'semantic-ui-react'; 3 | // import CopybookModel from '../models/CopybookModel'; 4 | 5 | export default function NavBarContainer() { 6 | function handleOpenCopybook() { 7 | // CopybookModel.update({ visible: true }); 8 | } 9 | 10 | return ( 11 | 12 |
13 | {/* 17 | 18 |
19 | }> 20 | Daily algorithm copybook, learn algorithm easily! 21 | 22 | 26 | 27 | 28 | }> 29 | Sorry, GitHub stars organize tool currently is not available, new version is coming soon :) 30 | 31 | */} 32 | 35 | 36 | 37 | 40 | 41 | 42 | 43 |
44 | ) 45 | } 46 | -------------------------------------------------------------------------------- /src/containers/NoticeContainer.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect, useRef } from 'react'; 2 | import { Icon, Popup } from 'semantic-ui-react'; 3 | 4 | export default function NoticeContainer() { 5 | const listEl = useRef(null); 6 | const [activeIndex, setDisable] = useSliderEffect(listEl); 7 | 8 | return ( 9 |
setDisable(true)} onMouseLeave={() => setDisable(false)}> 10 | 12 | [Micropaper]一分钟读懂一篇论文 13 | 14 | 16 | SAY NO TO SUICIDE PUBLIC LICENSE 17 | 18 | 19 | [MIHTool] iOS 上调试和优化页面的工具 20 | 21 | 22 | WebAssembly Rocks 23 | 24 | 26 | [开源] React Native 开发培训资料和视频 27 | 28 | 30 | 33 | 字节跳动内推, 请扫二维码或点链接 34 |
35 | 41 |
42 | 43 |
44 | 2020校招内推 45 |
46 |
47 |
48 | 49 |
50 | 技术实习内推 51 |
52 |
53 |
54 | 前端,后端,产品,运营,设计,交互,策划,算法,数据,DevOps,QA,IT,实习生 55 |
56 | } 57 | trigger={ 58 | [内推]字节跳动中国/美国/新加坡社招/校招/实习 59 | } /> 60 | 61 | 62 | ) 63 | } 64 | 65 | function useSliderEffect(el) { 66 | const [disable, setDisable] = useState(false); 67 | const [active, setActive] = useState(1); 68 | useEffect(() => { 69 | let interval = 0; 70 | const delay = setTimeout(() => { 71 | interval = setInterval(() => { 72 | !disable && renderItem(el.current.children); 73 | }, 5000); 74 | }, 15000); 75 | 76 | return () => { 77 | clearTimeout(delay); 78 | clearInterval(interval); 79 | }; 80 | }, [disable]); 81 | 82 | function renderItem(list) { 83 | Array.prototype.forEach.call(list, (item, i) => { 84 | if (i === active) { 85 | item.classList.add('show'); 86 | } else { 87 | item.classList.remove('show'); 88 | } 89 | }); 90 | const index = (active + 1) % list.length; 91 | setActive(index); 92 | } 93 | return [active, setDisable]; 94 | } 95 | -------------------------------------------------------------------------------- /src/models/AppModel.js: -------------------------------------------------------------------------------- 1 | import BaseModel from './BaseModel'; 2 | import LocalStorage from '../utils/LocalStorage'; 3 | import * as Tools from '../utils/Tools'; 4 | import * as Configs from '../constants/Configs'; 5 | import { searchParams } from '../utils/Param'; 6 | import Navigator from '../utils/Navigator'; 7 | 8 | const DEVICE_ID_KEY = `${Configs.APP_NANE}_device_id`; 9 | 10 | class AppModel extends BaseModel { 11 | constructor() { 12 | super(); 13 | this._data = { 14 | debug: searchParams()['debug'], 15 | appName: Configs.APP_NANE, 16 | deviceId: LocalStorage.getItem(DEVICE_ID_KEY), 17 | isGithub: /github\.io/g.test(window.location.href) 18 | }; 19 | if (!this._data.deviceId) { 20 | this._data.deviceId = Tools.uuid(); 21 | LocalStorage.setItem(DEVICE_ID_KEY, this._data.deviceId) 22 | } 23 | } 24 | 25 | analytics(param) { 26 | (this.isGithub || this.debug) && setTimeout(function () { 27 | Navigator.getFrame(null).setAttribute('src', '//www.mihtool.com/analytics.html?codelf' + (param ? ('&' + param) : '')); 28 | }, param ? 500 : 1000); 29 | } 30 | 31 | genPersistenceKey(key) { 32 | if (key !== undefined && key !== null) { 33 | return `${this._data.appName}_${key}`; 34 | } 35 | return null; 36 | } 37 | 38 | get debug() { 39 | return this._data.debug; 40 | } 41 | 42 | get isGithub() { 43 | return this._data.isGithub; 44 | } 45 | 46 | get appName() { 47 | return this._data.appName; 48 | } 49 | 50 | get deviceId() { 51 | return this._data.deviceId; 52 | } 53 | } 54 | 55 | export default new AppModel(); 56 | -------------------------------------------------------------------------------- /src/models/BaseModel.js: -------------------------------------------------------------------------------- 1 | import EventEmitter from 'events'; 2 | 3 | class Mutation { 4 | constructor(data) { 5 | this._data = data; 6 | this._serialize(); 7 | this.has = this.has.bind(this); 8 | } 9 | 10 | _serialize() { 11 | Object.keys(this._data).forEach(key => { 12 | this[key] = true; 13 | }); 14 | } 15 | 16 | get() { 17 | return this._data; 18 | } 19 | 20 | has(fields) { 21 | if (/string/i.test(typeof fields)) { 22 | fields = fields.split(','); 23 | } 24 | if (Array.isArray(fields)) { 25 | return fields.every((key) => { 26 | key = key.trim(); 27 | return this[key]; 28 | }); 29 | } 30 | return false; 31 | } 32 | } 33 | 34 | class BaseModel extends EventEmitter { 35 | constructor() { 36 | super(); 37 | this.on('error', () => { }); 38 | this.setMaxListeners(99); 39 | this._updateEventName = 'update'; 40 | this._data = {}; 41 | } 42 | 43 | set(data) { 44 | let prevData = Object.assign({}, this._data); 45 | this._data = data || {}; 46 | this.notify(prevData, Object.assign({}, prevData, data, { isReset: true })); 47 | } 48 | 49 | get() { 50 | return this._data; 51 | } 52 | 53 | create(data) { 54 | let instance = Object.create(Object.getPrototypeOf(this)); 55 | instance._data = data; 56 | return instance; 57 | } 58 | 59 | notify(prevData, mutationData) { 60 | let data = Object.assign({}, this._data); 61 | this.emit(this._updateEventName, data, prevData || data, new Mutation(mutationData)); 62 | } 63 | 64 | update(data) { 65 | let prevData = Object.assign({}, this._data); 66 | Object.assign(this._data, data); 67 | this.notify(prevData, data); 68 | } 69 | 70 | onUpdated(listener) { 71 | this.on(this._updateEventName, listener); 72 | } 73 | 74 | offUpdated(listener) { 75 | this.removeListener(this._updateEventName, listener); 76 | } 77 | } 78 | 79 | export default BaseModel; 80 | -------------------------------------------------------------------------------- /src/models/CopybookModel.js: -------------------------------------------------------------------------------- 1 | import BaseModel from './BaseModel'; 2 | import * as Tools from '../utils/Tools'; 3 | import GitHubData from './metadata/GitHubData'; 4 | import LocalStorage from '../utils/LocalStorage'; 5 | import AppModel from './AppModel'; 6 | 7 | const REPO_FILE_URL_KEY = AppModel.genPersistenceKey('agor_repo_file_url_key'); 8 | 9 | class CopybookModel extends BaseModel { 10 | constructor() { 11 | super(); 12 | this._data = { 13 | visible: false, 14 | fileList: [], 15 | selectedFile: null, 16 | fileContent: null, 17 | cachedFileUrl: LocalStorage.getItem(REPO_FILE_URL_KEY), 18 | }; 19 | // only cache 24 hours 20 | if (this._data.cachedFileUrl && (new Date() - new Date(this._data.cachedFileUrl.timer)) >= 86400000) { 21 | this._data.cachedFileUrl = null; 22 | } 23 | setTimeout(() => this.requestRepoTrees(), 100); 24 | } 25 | 26 | async requestRepoTrees() { 27 | const clData = await GitHubData.requestCLangAlgorithmsRepoTree(); 28 | if (!this._data.cachedFileUrl && clData) { 29 | this._updateFileList(clData); 30 | this.requestRepoFile(this._genCachedFile(this.fileList)); 31 | } 32 | const jsData = await GitHubData.requestJavascriptAlgorithmsRepoTree(); 33 | this._updateFileList(jsData); 34 | const pyData = await GitHubData.requestPythonAlgorithmsRepoTree(); 35 | this._updateFileList(pyData); 36 | const jvData = await GitHubData.requestJavaAlgorithmsRepoTree(); 37 | this._updateFileList(jvData); 38 | const swData = await GitHubData.requestSwiftAlgorithmsRepoTree(); 39 | this._updateFileList(swData); 40 | if (this.fileList.length) { 41 | this.requestRepoFile(this._genCachedFile(this.fileList)); 42 | } 43 | } 44 | 45 | async requestRepoFile(file) { 46 | if (!file) { return; } 47 | const data = await GitHubData.requestRepoFile(file.url); 48 | if (data) { 49 | const cachedFileUrl = { 50 | timer: (new Date()).toISOString().substr(0, 10), 51 | url: file.url 52 | }; 53 | this.update({ 54 | selectedFile: file, 55 | fileContent: data, 56 | cachedFileUrl: cachedFileUrl 57 | }); 58 | LocalStorage.setItem(REPO_FILE_URL_KEY, cachedFileUrl); 59 | } 60 | } 61 | 62 | _updateFileList(data) { 63 | data && this.update({ 64 | fileList: [...this.fileList, ...data] 65 | }); 66 | } 67 | 68 | _genCachedFile(data) { 69 | let file; 70 | if (this._data.cachedFileUrl) { 71 | file = data.find(f => f.url === this._data.cachedFileUrl.url); 72 | } 73 | return file || Tools.randomList(data, 1)[0]; 74 | } 75 | 76 | get fileList() { 77 | return this._data.fileList; 78 | } 79 | 80 | get selectedFile() { 81 | return this._data.selectedFile; 82 | } 83 | 84 | get fileContent() { 85 | return this._data.fileContent; 86 | } 87 | 88 | get visible() { 89 | return this._data.visible; 90 | } 91 | } 92 | 93 | export default new CopybookModel(); 94 | -------------------------------------------------------------------------------- /src/models/DDMSModel.js: -------------------------------------------------------------------------------- 1 | import BaseModel from './BaseModel'; 2 | import FormHandler from '../utils/FormHandler'; 3 | import LocalStorage from '../utils/LocalStorage'; 4 | import AppModel from './AppModel'; 5 | import * as Tools from '../utils/Tools'; 6 | import JSONP from '../utils/JSONP'; 7 | 8 | const formAction = '//ddms.mihtool.com/apis/v1/formdata/'; 9 | const formDataAction = '//ddms.mihtool.com/apis/v1/formdata_detail/'; 10 | const persistKeyWordsName = AppModel.genPersistenceKey('ddms_keywords'); 11 | const persistOrganizerName = AppModel.genPersistenceKey('ddms_group_sync_id'); 12 | const persistKeyWordsTimerName = persistKeyWordsName + '_timer'; 13 | let cacheKeyWords = (LocalStorage.getItem(persistKeyWordsName) || '').split(','); 14 | const ot = new Date(LocalStorage.getItem(persistKeyWordsTimerName) || 0); 15 | const nt = Date.now(); 16 | 17 | if ((nt - ot) > 1000 * 60 * 60 * 24) { 18 | cacheKeyWords = []; 19 | LocalStorage.setItem(persistKeyWordsTimerName, nt); 20 | } 21 | 22 | class DDMSModel extends BaseModel { 23 | constructor() { 24 | super(); 25 | this._data = { 26 | organizerSyncId: LocalStorage.getItem(persistOrganizerName), 27 | luckyKeyWords: [] 28 | }; 29 | this.getLuckyKeyWords(); 30 | } 31 | 32 | getLuckyKeyWords() { 33 | JSONP(`${formAction}?callback=?&formid=56e58775ade3a8e84dbacadf`).then(res => { 34 | if (res && res.code == 1) { 35 | this.update({ 36 | luckyKeyWords: Tools.randomList([...new Set(res.data.reduce((cal, cur) => { 37 | if (cur.data.keyword.length > 1) { 38 | cal.push(cur.data.keyword); 39 | } 40 | return cal; 41 | }, []))], 6) 42 | }); 43 | } 44 | }); 45 | } 46 | 47 | postKeyWords(val) { 48 | if (!(AppModel.isGithub || AppModel.debug)) { return; } 49 | if (val && cacheKeyWords.indexOf(val) == -1) { 50 | FormHandler.asyncSubmit(formAction, { 51 | formid: '56e58775ade3a8e84dbacadf', 52 | keyword: val 53 | }); 54 | this._saveKeyWords(val); 55 | } 56 | } 57 | 58 | postBookmarkUser(val) { 59 | if (val) { 60 | FormHandler.asyncSubmit(formAction, { 61 | formid: '56e587a9ade3a8e84dbacae1', 62 | account: val 63 | }); 64 | } 65 | } 66 | 67 | postBookmarkGroup(repoid, repourl, groupname, lang, stars) { 68 | if (repoid) { 69 | FormHandler.asyncSubmit(formAction, { 70 | formid: '56e587ecade3a8e84dbacae3', 71 | repoid: repoid, 72 | repourl: repourl, 73 | groupname: groupname, 74 | lang: lang, 75 | stars: stars 76 | }); 77 | } 78 | } 79 | 80 | postBookmarkOrganizer(data, callback) { 81 | if (data) { 82 | window.afterPostBookmarkOrganizer = callback; 83 | FormHandler.asyncSubmit(formAction, { 84 | formid: '56fb7d9dade3a8e84dbacaf0', 85 | success_url: Tools.thisPath + 'ddms_frame_callback.html?frame_callback=afterPostBookmarkOrganizer', 86 | data: data 87 | }); 88 | } 89 | } 90 | 91 | postUpdateBookmarkOrganizer(id, data, callback) { 92 | if (id && data) { 93 | window.afterPostUpdateBookmarkOrganizer = callback; 94 | FormHandler.asyncSubmit(formDataAction, { 95 | id: id, 96 | success_url: Tools.thisPath + 'ddms_frame_callback.html?frame_callback=afterPostUpdateBookmarkOrganizer', 97 | data: data 98 | }); 99 | } 100 | } 101 | 102 | getBookmarkOrganizer(id, callback) { 103 | JSONP(`${formDataAction}?callback=?&id=${id}`).then(data => { 104 | if (data) { 105 | callback && callback(data); 106 | } 107 | }); 108 | } 109 | 110 | _saveKeyWords(val) { 111 | if (cacheKeyWords.indexOf(val) == -1) { 112 | cacheKeyWords.push(val); 113 | LocalStorage.setItem(persistKeyWordsName, cacheKeyWords.join(',').replace(/^,*/g, '').replace(/,*&/g, '')); 114 | } 115 | } 116 | 117 | set organizerSyncId(val) { 118 | this._data.organizerSyncId = val; 119 | LocalStorage.setItem(persistOrganizerName, val); 120 | } 121 | 122 | get organizerSyncId() { 123 | return this._data.organizerSyncId || LocalStorage.getItem(persistOrganizerName); 124 | } 125 | 126 | get luckyKeyWords() { 127 | return this._data.luckyKeyWords; 128 | } 129 | } 130 | 131 | export default new DDMSModel(); 132 | -------------------------------------------------------------------------------- /src/models/ErrorModel.js: -------------------------------------------------------------------------------- 1 | import BaseModel from './BaseModel'; 2 | 3 | class ErrorModel extends BaseModel { 4 | constructor() { 5 | super(); 6 | this._data = { 7 | visible: false, 8 | message: '', 9 | error: null 10 | }; 11 | } 12 | 13 | get message() { 14 | return this._data.message; 15 | } 16 | 17 | get error() { 18 | return this._data.error; 19 | } 20 | 21 | set error(error) { 22 | this.update({ 23 | visible: true, 24 | message: error.message, 25 | error: error 26 | }); 27 | } 28 | } 29 | 30 | export default new ErrorModel(); 31 | -------------------------------------------------------------------------------- /src/models/Store.js: -------------------------------------------------------------------------------- 1 | import LocalStorage, { SessionStorage } from '../utils/LocalStorage'; 2 | import * as Tools from '../utils/Tools'; 3 | /** 4 | * Store data in memory cache. 5 | */ 6 | export default class Store { 7 | /** 8 | * Create a memory cache. 9 | * 10 | * @param expire expire time in seconds for each record, Infinity value will never expire. default (60 * 60 * 1000)s. 11 | */ 12 | constructor(expire, options) { 13 | this._expire = expire || (60 * 60 * 1000); 14 | this._cache = {}; 15 | this._options = options || {}; 16 | if (this._options.persistence === 'local') { 17 | this._local = LocalStorage; 18 | } 19 | if (this._options.persistence === 'session') { 20 | this._local = SessionStorage; 21 | } 22 | if (this._local && this._options.persistenceKey) { 23 | this._cache = this._local.getItem(this._options.persistenceKey) || {}; 24 | } 25 | } 26 | 27 | /** 28 | * Returns cached record data with id. 29 | * Returns null if the record is expired. 30 | * 31 | * @param id unique id. 32 | * @return {*} cache data. 33 | */ 34 | get(id) { 35 | if (id !== undefined || id != null) { 36 | id = Tools.MD5(id.toString()); 37 | let record = this._cache[id]; 38 | if (record) { 39 | // delete record when it is expired 40 | if (Date.now() - record.created > this._expire) { 41 | delete this._cache[id]; 42 | return null; 43 | } 44 | return record.data; 45 | } 46 | return null; 47 | } 48 | return null; 49 | } 50 | 51 | /** 52 | * Save a record data to memory. 53 | * Saving different record with same id will always overwrite the old record. 54 | * 55 | * @param id unique id. 56 | * @param data cache record data. 57 | */ 58 | save(id, data) { 59 | if (id !== undefined || id != null) { 60 | id = Tools.MD5(id.toString()); 61 | this._cache[id] = { 62 | id: id, 63 | data: data, 64 | created: Date.now() 65 | }; 66 | this._persist(); 67 | } 68 | } 69 | 70 | /** 71 | * Clear all cached records. 72 | */ 73 | clear() { 74 | this._cache = {}; 75 | this._persist(); 76 | } 77 | 78 | _persist() { 79 | if (this._local && this._options.persistenceKey) { 80 | this._local.setItem(this._options.persistenceKey, this._cache) 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/models/metadata/BaiduTranslateData.js: -------------------------------------------------------------------------------- 1 | import Store from '../Store'; 2 | import * as Tools from '../../utils/Tools'; 3 | import JSONP from '../../utils/JSONP'; 4 | import { formatSuggestionStr, formatTranslationArr } from '../../utils/TranslateHandler'; 5 | import AppModel from '../AppModel'; 6 | 7 | /** 8 | * 特别重要,必读! 9 | * CODELF 用的是 Baidu 翻译 API 的免费套餐,一个月仅有200万字符请求限制! 10 | * 所以,如果你想二次开发,请单独申请自己的 Baidu 翻译 API 的 KEY,否则会直接影响 CODELF 的用户。 11 | * Baidu 翻译 API 申请参看: https://api.fanyi.baidu.com/api/trans/product/apidoc 12 | */ 13 | const translateAppId = '20191206000363640'; 14 | const translateKey = '4hJrdEmxB3M42OYwhAPA'; 15 | const translateSalt = Date.now(); 16 | const translateEndpoint = `//fanyi-api.baidu.com/api/trans/vip/translate?callback=?&from=auto&to=en&appid=${translateAppId}&salt=${translateSalt}`; 17 | 18 | // https://fanyi-api.baidu.com/api/trans/vip/translate?callback=baiduFanyiRequestCallback&from=auto&to=en&appid=20191206000363640&salt=1575646376369&q=%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD&sign=4e7d639cd17477acf5b13bd5ba6bab76 19 | function genUrl(val) { 20 | const sign = Tools.MD5(`${translateAppId}${val}${translateSalt}${translateKey}`); // appid+q+salt+密钥 的MD5值 21 | return `${translateEndpoint}&q=${encodeURIComponent(val)}&sign=${sign}`; 22 | } 23 | 24 | class BaiduTranslateData { 25 | constructor() { 26 | this._store = new Store(Infinity, { 27 | persistence: 'session', 28 | persistenceKey: AppModel.genPersistenceKey('baidu_translate_key') 29 | }); 30 | } 31 | 32 | async request(val) { 33 | const cache = this._store.get(val); 34 | if (cache) { 35 | return cache; 36 | } 37 | 38 | try { 39 | const url = genUrl(val); 40 | let res = await JSONP(url, { callbackName: 'baiduFanyiRequestCallback' }); 41 | if (res && res.trans_result) { 42 | let translation = res.trans_result.map(key => key.dst); 43 | let suggestion = formatSuggestionStr(translation.join(' ')); 44 | translation = formatTranslationArr(translation); 45 | let response = { suggestion, translation }; 46 | this._store.save(val, response); 47 | return response; 48 | } else { 49 | throw new Error(`Request Baidu translate failed`); 50 | } 51 | } catch (err) { 52 | return null; 53 | } 54 | } 55 | } 56 | 57 | export default new BaiduTranslateData(); 58 | -------------------------------------------------------------------------------- /src/models/metadata/BingTranslateData.js: -------------------------------------------------------------------------------- 1 | import Store from '../Store'; 2 | import { formatSuggestionStr, formatTranslationArr } from '../../utils/TranslateHandler'; 3 | import AppModel from '../AppModel'; 4 | 5 | /** 6 | * 特别重要,必读! 7 | * CODELF 用的是 Bing 翻译 API 的免费套餐,一个月仅有200万字符请求限制! 8 | * 所以,如果你想二次开发,请单独申请自己的 Bing 翻译 API 的 KEY,否则会直接影响 CODELF 的用户。 9 | * Bing 翻译 API 申请参看: https://docs.microsoft.com/en-us/azure/cognitive-services/translator/ 10 | * https://docs.microsoft.com/en-us/azure/cognitive-services/translator/reference/v3-0-translate 11 | */ 12 | // curl -X POST "https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to=en" -H "Ocp-Apim-Subscription-Key: 445fd33be8764339add46f0770ac617d" -H "Content-Type: application/json; charset=UTF-8" -d "[{'Text':'咸鱼'}]" 13 | const translateEndpoint = 'https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to=en'; 14 | const translateKey = '445fd33be8764339add46f0770ac617d'; 15 | 16 | class BingTranslateData { 17 | constructor() { 18 | this._store = new Store(Infinity, { 19 | persistence: 'session', 20 | persistenceKey: AppModel.genPersistenceKey('bing_translate_key') 21 | }); 22 | } 23 | 24 | async request(val) { 25 | const cache = this._store.get(val); 26 | if (cache) { 27 | return cache; 28 | } 29 | 30 | try { 31 | let res = await fetch(translateEndpoint, { 32 | method: 'POST', 33 | headers: { 34 | 'Ocp-Apim-Subscription-Key': translateKey, 35 | 'Content-Type': 'application/json; charset=UTF-8' 36 | }, 37 | body: JSON.stringify(val.split(' ').map(text => { return { Text: text } })) 38 | }); 39 | res = await res.json(); 40 | if (res) { 41 | let suggestionStr = ''; 42 | let suggestion = null; 43 | let translation = []; 44 | 45 | res.forEach(key => { 46 | const trans = key.translations.map(t => t.text); 47 | suggestionStr += ' ' + trans.join(' '); 48 | Array.prototype.push.apply(translation, trans); 49 | }); 50 | 51 | suggestion = formatSuggestionStr(suggestionStr); 52 | if (translation) { 53 | translation = formatTranslationArr(translation); 54 | } 55 | let response = { suggestion, translation }; 56 | this._store.save(val, response); 57 | return response; 58 | } else { 59 | throw new Error(`Request Bing translate failed`); 60 | } 61 | } catch (err) { 62 | return null; 63 | } 64 | } 65 | } 66 | 67 | export default new BingTranslateData(); 68 | -------------------------------------------------------------------------------- /src/models/metadata/GitHubData.js: -------------------------------------------------------------------------------- 1 | import Store from '../Store'; 2 | import ErrorModel from '../ErrorModel'; 3 | 4 | const CLANG = { 5 | name: 'TheAlgorithms/C', 6 | gitHub: 'https://github.com/TheAlgorithms/C/tree/master', 7 | postfix: '.c', 8 | included: [ 9 | 'conversions', 10 | 'data_structures', 11 | 'hash', 12 | 'misc', 13 | 'searching', 14 | 'sorting' 15 | ], 16 | excluded: [ 17 | ] 18 | }; 19 | 20 | const JS = { 21 | name: 'trekhleb/javascript-algorithms', 22 | gitHub: 'https://github.com/trekhleb/javascript-algorithms/tree/master', 23 | postfix: '.js', 24 | included: [ 25 | 'src/algorithms/', 26 | 'src/data-structures/' 27 | ], 28 | excluded: [ 29 | '__test__' 30 | ] 31 | }; 32 | 33 | const PY = { 34 | name: 'TheAlgorithms/Python', 35 | gitHub: 'https://github.com/TheAlgorithms/Python/tree/master', 36 | postfix: '.py', 37 | included: [ 38 | 'Maths', 39 | 'binary_tree', 40 | 'data_structures', 41 | 'dynamic_programming', 42 | 'graphs', 43 | 'hashes', 44 | 'maths', 45 | 'other', 46 | 'searches', 47 | 'strings', 48 | 'sorts' 49 | ], 50 | excluded: [ 51 | '__init__.py' 52 | ] 53 | }; 54 | 55 | const JAVA = { 56 | name: 'TheAlgorithms/Java', 57 | gitHub: 'https://github.com/TheAlgorithms/Java/tree/master', 58 | postfix: '.java', 59 | included: [ 60 | 'Conversions', 61 | 'DataStructures', 62 | 'Misc', 63 | 'Others', 64 | 'Searches', 65 | 'Sorts' 66 | ], 67 | excluded: [ 68 | ] 69 | }; 70 | 71 | const SWIFT = { 72 | name: 'raywenderlich/swift-algorithm-club', 73 | gitHub: 'https://github.com/raywenderlich/swift-algorithm-club/tree/master', 74 | postfix: '.swift', 75 | included: [ 76 | ], 77 | excluded: [ 78 | '/Tests/', 79 | '.playground' 80 | ] 81 | } 82 | 83 | class GitHubData { 84 | constructor() { 85 | this._repoStore = new Store(Infinity); 86 | } 87 | 88 | async requestRepoLatestCommit(repo) { 89 | const cacheId = 'requestRepoLatestCommit' + repo; 90 | const cache = this._repoStore.get(cacheId); 91 | if (cache) { 92 | return cache; 93 | } 94 | try { 95 | const url = `https://api.github.com/repos/${repo}/commits?`; 96 | let res = await fetch(url + (new Date()).toISOString().substr(0, 7)); 97 | res = await res.json(); 98 | if (res) { 99 | const data = res[0]; 100 | this._repoStore.save(cacheId, data); 101 | return data; 102 | } else { 103 | throw new Error(`Request Repo latest Commit failed`); 104 | } 105 | } catch (err) { 106 | ErrorModel.error = err; 107 | } 108 | } 109 | 110 | async requestRepoTree(repo) { 111 | const cacheId = 'requestRepoTree' + repo.name; 112 | const cache = this._repoStore.get(cacheId); 113 | if (cache) { 114 | return cache; 115 | } 116 | try { 117 | const latestCommit = await this.requestRepoLatestCommit(repo.name); 118 | const url = `${latestCommit.commit.tree.url}?recursive=1`; 119 | let res = await fetch(url); 120 | res = await res.json(); 121 | if (res) { 122 | const data = Array.prototype.filter.call(res.tree, n => { 123 | const path = n.path; 124 | n.link = `${repo.gitHub}/${path}`; 125 | return (this._isIncludedFile(path, repo.included) || !repo.included.length) 126 | && path.endsWith(repo.postfix) 127 | && !this._isIncludedFile(path, repo.excluded); 128 | }); 129 | this._repoStore.save(cacheId, data); 130 | return data; 131 | } else { 132 | throw new Error(`Request Repo Tree failed`); 133 | } 134 | } catch (err) { 135 | ErrorModel.error = err; 136 | } 137 | } 138 | 139 | async requestJavascriptAlgorithmsRepoTree() { 140 | return this.requestRepoTree(JS); 141 | } 142 | 143 | async requestPythonAlgorithmsRepoTree() { 144 | return this.requestRepoTree(PY); 145 | } 146 | 147 | async requestJavaAlgorithmsRepoTree() { 148 | return this.requestRepoTree(JAVA); 149 | } 150 | 151 | async requestCLangAlgorithmsRepoTree() { 152 | return this.requestRepoTree(CLANG); 153 | } 154 | 155 | async requestSwiftAlgorithmsRepoTree() { 156 | return this.requestRepoTree(SWIFT); 157 | } 158 | 159 | async requestRepoFile(url) { 160 | const cache = this._repoStore.get(url); 161 | if (cache) { 162 | return cache; 163 | } 164 | try { 165 | let res = await fetch(url); 166 | res = await res.json(); 167 | if (res) { 168 | res.content = window.atob(res.content); 169 | this._repoStore.save(url, res); 170 | return res; 171 | } else { 172 | throw new Error(`Request Repo File failed`); 173 | } 174 | } catch (err) { 175 | ErrorModel.error = err; 176 | } 177 | } 178 | 179 | _isIncludedFile(path, list) { 180 | return list.find(p => { 181 | return path.includes(p); 182 | }); 183 | } 184 | } 185 | 186 | export default new GitHubData(); 187 | -------------------------------------------------------------------------------- /src/models/metadata/YoudaoTranslateData.js: -------------------------------------------------------------------------------- 1 | import Store from '../Store'; 2 | import JSONP from '../../utils/JSONP'; 3 | import { formatSuggestionStr, formatTranslationArr } from '../../utils/TranslateHandler'; 4 | import AppModel from '../AppModel'; 5 | 6 | /** 7 | * 特别重要,必读! 8 | * CODELF 用的是有道翻译 API 的免费套餐,1小时仅有1K的请求次数限制! 9 | * 所以,如果你想二次开发,请单独申请自己的有道翻译 API 的 KEY,否则会直接影响 CODELF 的用户。 10 | * 有道翻译 API 申请参看: http://fanyi.youdao.com/openapi?path=data-mode 11 | */ 12 | const translateEndpoint = '//fanyi.youdao.com/openapi.do?callback=?&keyfrom=Codelf&key=2023743559&type=data&doctype=jsonp&version=1.1'; 13 | 14 | class YoudaoTranslateData { 15 | constructor() { 16 | this._store = new Store(Infinity, { 17 | persistence: 'session', 18 | persistenceKey: AppModel.genPersistenceKey('youdao_translate_key') 19 | }); 20 | } 21 | 22 | async request(val) { 23 | const cache = this._store.get(val); 24 | if (cache) { 25 | return cache; 26 | } 27 | const url = `${translateEndpoint}&q=${val}`; 28 | const data = await JSONP(url, { callbackName: 'youdaoFanyiRequestCallback' }); 29 | try { 30 | let suggestionStr = ''; 31 | let suggestion; 32 | let translation; 33 | //basic translate 34 | if (data.basic && data.basic.explains) { 35 | suggestionStr += data.basic.explains.join(' '); 36 | translation = suggestionStr; 37 | } 38 | //web translate 39 | if (data.web && data.web) { 40 | data.web.forEach(function (key) { 41 | suggestionStr += ' ' + key.value.join(' '); 42 | }); 43 | } 44 | suggestion = formatSuggestionStr(suggestionStr); 45 | if (data && data.translation) { 46 | translation = formatTranslationArr(data.translation); 47 | } 48 | let response = { suggestion, translation }; 49 | this._store.save(val, response); 50 | return response; 51 | } catch (e) { 52 | return null; 53 | } 54 | } 55 | } 56 | 57 | export default new YoudaoTranslateData(); 58 | -------------------------------------------------------------------------------- /src/utils/FormHandler.js: -------------------------------------------------------------------------------- 1 | import Navigator from './Navigator'; 2 | 3 | const FormHandler = new function () { 4 | function getForm(method) { 5 | let _form = document.createElement('form'); 6 | _form.setAttribute("style", "display:none;width:0;height:0;position: absolute;top:0;left:0;border:0;"); 7 | _form.setAttribute("method", method || 'POST'); 8 | document.body.appendChild(_form); 9 | return _form; 10 | } 11 | 12 | this.asyncSubmit = function (action, data) { 13 | this.submit(action, data, true); 14 | } 15 | 16 | this.submit = function (action, data, async) { 17 | let target, 18 | frame, 19 | form = getForm(), 20 | inputs = [], 21 | itpl = ''; 22 | 23 | if (async) { 24 | target = '__formhandler_' + new Date().getTime(); 25 | frame = Navigator.getFrame(null, target); 26 | form.setAttribute('target', target); 27 | setTimeout(function () { 28 | Navigator.removeFrame(frame); 29 | }, 120000); 30 | } 31 | 32 | form.setAttribute('action', action); 33 | data = data || {}; 34 | for (let key in data) { 35 | inputs.push(itpl.replace('{N}', key).replace('{V}', data[key])); 36 | } 37 | form.innerHTML = inputs.join(''); 38 | action && setTimeout(function () { 39 | form.submit(); 40 | }, 100); 41 | } 42 | }; 43 | export default FormHandler; 44 | -------------------------------------------------------------------------------- /src/utils/HashHandler.js: -------------------------------------------------------------------------------- 1 | const HashHandler = (function () { 2 | let lc = window.location; 3 | function getByURL(url) { 4 | let hash; 5 | url && decodeURIComponent(url).replace(new RegExp('#(.*)', 'g'), function ($1, $2) { 6 | hash = $2; 7 | }); 8 | return hash && decodeURIComponent(hash); 9 | } 10 | 11 | function get() { 12 | return getByURL(lc.hash); 13 | } 14 | 15 | function set(hash) { 16 | if (hash) { 17 | lc.hash = encodeURIComponent(hash); 18 | } 19 | } 20 | 21 | return { 22 | get: get, 23 | set: set, 24 | getByURL: getByURL 25 | } 26 | })(); 27 | 28 | export default HashHandler; 29 | -------------------------------------------------------------------------------- /src/utils/JSONP.js: -------------------------------------------------------------------------------- 1 | const JSONP = (url, options) => { 2 | options = options || {}; 3 | url = options.url || url; 4 | return new Promise((resolve, reject) => { 5 | let timer = 0; 6 | let script = document.createElement('script'); 7 | const callbackName = options.callbackName || `__jsonp_${Date.now()}_callback`; 8 | url = url.replace('=?', `=${callbackName}${options.nocache ? ('&_=' + Date.now()) : ''}`); 9 | const done = () => { 10 | window.clearTimeout(timer); 11 | try { document.head.removeChild(script); } catch (e) { } 12 | window[callbackName] = null; 13 | }; 14 | const onerror = () => { 15 | window.removeEventListener('error', onerror); 16 | done(); 17 | reject(); 18 | }; 19 | window[callbackName] = (...args) => { 20 | done(); 21 | resolve(...args); 22 | }; 23 | timer = setTimeout(onerror, 5 * 60 * 1000); // timeout in 5 min 24 | window.addEventListener('error', onerror); 25 | script.onerror = onerror; 26 | script.src = url; 27 | document.head.appendChild(script); 28 | }); 29 | } 30 | export default JSONP; 31 | -------------------------------------------------------------------------------- /src/utils/LocalStorage.js: -------------------------------------------------------------------------------- 1 | class BasicStorage { 2 | constructor() { 3 | this._store = {}; 4 | } 5 | 6 | getItem(key) { 7 | return this._store[key]; 8 | } 9 | 10 | setItem(key, value) { 11 | return this._store[key] = value; 12 | } 13 | } 14 | 15 | class Storage { 16 | constructor(store) { 17 | this._store = store; 18 | if (!store) { 19 | return new BasicStorage(); 20 | } 21 | } 22 | 23 | getItem(key, defaultValue) { 24 | let rawValue = this._store.getItem(key); 25 | if (rawValue == null) { 26 | return defaultValue; 27 | } 28 | try { 29 | return JSON.parse(rawValue); 30 | } catch (e) { 31 | return null; 32 | } 33 | } 34 | 35 | setItem(key, value) { 36 | try { 37 | this._store.setItem(key, JSON.stringify(value)); 38 | } catch (e) { 39 | // todo 40 | } 41 | } 42 | } 43 | 44 | const LocalStorage = new Storage(window.localStorage); 45 | const SessionStorage = new Storage(window.sessionStorage); 46 | 47 | export { SessionStorage }; 48 | export default LocalStorage; 49 | -------------------------------------------------------------------------------- /src/utils/Navigator.js: -------------------------------------------------------------------------------- 1 | const Navigator = (function () { 2 | let frame, 3 | androidReg = /Android/gi, 4 | isAndroid = androidReg.test(navigator.platform) || androidReg.test(navigator.userAgent); 5 | frame = null; 6 | 7 | function appendFrame(frame) { 8 | frame && document.body.appendChild(frame); 9 | } 10 | 11 | function removeFrame(frame) { 12 | frame && frame.parentNode.removeChild(frame); 13 | } 14 | 15 | function getFrame(src, name) { 16 | let _frame = document.createElement('iframe'); 17 | _frame.setAttribute('style', 'display:none;width:0;height:0;position: absolute;top:0;left:0;border:0;'); 18 | _frame.setAttribute('height', '0px'); 19 | _frame.setAttribute('width', '0px'); 20 | _frame.setAttribute('frameborder', '0'); 21 | name && _frame.setAttribute('name', name); 22 | if (src) { 23 | _frame.setAttribute('src', src); 24 | } else { 25 | appendFrame(_frame); 26 | } 27 | return _frame; 28 | } 29 | 30 | function protocol(command, single, noframe) { 31 | let _frame, timer; 32 | if (noframe) { 33 | window.location.href = command; 34 | return; 35 | } 36 | if (single) { 37 | if (isAndroid) { 38 | _frame = getFrame(); 39 | _frame.setAttribute('src', command); 40 | } else { 41 | _frame = getFrame(command); 42 | appendFrame(_frame); 43 | } 44 | timer = setTimeout(function () { 45 | _frame && removeFrame(_frame); 46 | }, 30000); 47 | _frame.onload = _frame.onreadystatechange = function () { 48 | timer && clearTimeout(timer); 49 | _frame && removeFrame(_frame); 50 | } 51 | } else { 52 | frame = frame || getFrame(); 53 | frame.setAttribute('src', command); 54 | } 55 | } 56 | 57 | return { 58 | protocol: protocol, 59 | getFrame: getFrame, 60 | appendFrame: appendFrame, 61 | removeFrame: removeFrame 62 | } 63 | })(); 64 | 65 | export default Navigator; 66 | -------------------------------------------------------------------------------- /src/utils/Param.js: -------------------------------------------------------------------------------- 1 | 2 | function fn(str, reg) { 3 | if (str) { 4 | let data = {}; 5 | str.replace(reg, function ($0, $1, $2, $3) { 6 | data[$1] = $3; 7 | }); 8 | return data; 9 | } 10 | } 11 | 12 | export function searchParams(search) { 13 | search = search || window.location.search; 14 | return fn(search, new RegExp("([^?=&]+)(=([^&]*))?", "g")) || {}; 15 | } 16 | 17 | export function hashParams(hash) { 18 | hash = hash || window.location.hash; 19 | return fn(hash, new RegExp("([^#=&]+)(=([^&]*))?", "g")) || {}; 20 | } 21 | 22 | export function params(search, hash) { 23 | return { 24 | search: searchParams(search), 25 | hash: hashParams(hash) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/utils/Tools.js: -------------------------------------------------------------------------------- 1 | const ua = navigator.userAgent; 2 | const android = ua.match(/(Android);?[\s/]+([\d.]+)?/); 3 | const ipad = ua.match(/(iPad).*OS\s([\d_]+)/); 4 | const ipod = ua.match(/(iPod)(.*OS\s([\d_]+))?/); 5 | const iphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/); 6 | let os = {}; 7 | 8 | if (android) os.android = true, os.version = android[2]; 9 | if (iphone && !ipod) os.ios = os.iphone = true, os.version = iphone[2].replace(/_/g, '.'); 10 | if (ipad) os.ios = os.ipad = true, os.version = ipad[2].replace(/_/g, '.'); 11 | if (ipod) os.ios = os.ipod = true, os.version = ipod[3] ? ipod[3].replace(/_/g, '.') : null; 12 | 13 | const thisPage = window.location.href.replace(window.location.hash, ''); 14 | const thisPath = thisPage.substring(0, thisPage.lastIndexOf('/') + 1); 15 | 16 | const randomColor = () => { 17 | const letters = '0123456789ABCDEF'.split(''); 18 | let color = '#'; 19 | for (let i = 0; i < 6; i++) { 20 | color += letters[Math.floor(Math.random() * 16)]; 21 | } 22 | return color; 23 | } 24 | 25 | const randomList = (list, len, verify, ratio) => { 26 | let rs = [], _list = list.slice(0); 27 | len = len || _list.length; 28 | ratio = ratio ? ratio : 0; 29 | 30 | function rd(_array) { 31 | _array.sort(function () { 32 | return (0.5 - Math.random()); 33 | }); 34 | } 35 | 36 | while (ratio) { 37 | rd(_list); 38 | ratio--; 39 | } 40 | if (_list.length <= len) { 41 | rs = _list; 42 | } else { 43 | while (rs.length < len) { 44 | let index = Math.floor(Math.random() * _list.length), 45 | item = _list[index]; 46 | if ((verify && verify.call(this, item, _list)) || !verify) { 47 | rs.push(item); 48 | _list.splice(index, 1); 49 | } 50 | } 51 | } 52 | return rs; 53 | } 54 | 55 | const InlineWebWorker = { 56 | ready: window.Blob && window.Worker && window.URL, 57 | create: function create(selector) { 58 | return new Worker(window.URL.createObjectURL(new Blob([document.querySelector(selector).textContent]))); 59 | } 60 | } 61 | 62 | const uuid = len => { 63 | let res = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'.replace(/[x]/g, function (c) { 64 | let num = Math.random() * 16 | 0, v = c === 'x' ? num : (num & 0x3 | 0x8); 65 | return v.toString(16); 66 | }); 67 | return len ? res.substr(0, len) : res; 68 | } 69 | 70 | const randomLabelColor = () => { 71 | const colors = [ 72 | 'red', 73 | 'orange', 74 | 'yellow', 75 | 'olive', 76 | 'green', 77 | 'teal', 78 | 'blue', 79 | 'violet', 80 | 'purple', 81 | 'pink', 82 | 'brown', 83 | ]; 84 | return randomList(colors, 1)[0]; 85 | }; 86 | 87 | import SparkMD5 from 'spark-md5'; 88 | const MD5 = SparkMD5.hash; 89 | 90 | export { os, thisPage, thisPath, randomList, randomColor, InlineWebWorker, uuid, randomLabelColor, MD5 } 91 | -------------------------------------------------------------------------------- /src/utils/TranslateHandler.js: -------------------------------------------------------------------------------- 1 | 2 | export function formatSuggestionStr(str) { 3 | if (!str) { return []; } 4 | let tmp = []; 5 | return str.replace(/[`~!@#$^&*()=|{}':;',\[\].<>\/?~!@#¥……&*()——|\\{\\}【】‘;:”“’。,、?]/g, ' ') 6 | .replace(/\s+/ig, '+').split('+') 7 | .filter((key, idx, inputArray) => { 8 | const checked = key.length > 1 9 | && inputArray.indexOf(key) == idx 10 | && !/[^\x00-\xff]/gi.test(key) 11 | && !tmp.find(ikey => { 12 | return new RegExp('^' + key + '$', 'ig').test(ikey); 13 | }); 14 | if (checked) { 15 | tmp.push(key); 16 | } 17 | return checked; 18 | }); 19 | } 20 | 21 | export function formatTranslationArr(arr) { 22 | if (!arr) { return null; } 23 | return arr.join(' ') 24 | .replace(/[!$%^&*()_+|~=`{}\[\]:";'<>?,.\/]/g, '') 25 | .split(' ').filter(function (key, idx, inputArray) { 26 | return inputArray.indexOf(key) == idx && !/^(a|an|the)$/ig.test(key); 27 | }).join(' '); 28 | } 29 | -------------------------------------------------------------------------------- /src/vendors/prettify.css: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright (C) 2015 Google Inc. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /* Pretty printing styles. Used with prettify.js. */ 19 | 20 | 21 | /* SPAN elements with the classes below are added by prettyprint. */ 22 | .pln { color: #000 } /* plain text */ 23 | 24 | @media screen { 25 | .str { color: #080 } /* string content */ 26 | .kwd { color: #008 } /* a keyword */ 27 | .com { color: #800 } /* a comment */ 28 | .typ { color: #606 } /* a type name */ 29 | .lit { color: #066 } /* a literal value */ 30 | /* punctuation, lisp open bracket, lisp close bracket */ 31 | .pun, .opn, .clo { color: #660 } 32 | .tag { color: #008 } /* a markup tag name */ 33 | .atn { color: #606 } /* a markup attribute name */ 34 | .atv { color: #080 } /* a markup attribute value */ 35 | .dec, .var { color: #606 } /* a declaration; a variable name */ 36 | .fun { color: red } /* a function name */ 37 | } 38 | 39 | /* Use higher contrast and text-weight for printable form. */ 40 | @media print, projection { 41 | .str { color: #060 } 42 | .kwd { color: #006; font-weight: bold } 43 | .com { color: #600; font-style: italic } 44 | .typ { color: #404; font-weight: bold } 45 | .lit { color: #044 } 46 | .pun, .opn, .clo { color: #440 } 47 | .tag { color: #006; font-weight: bold } 48 | .atn { color: #404 } 49 | .atv { color: #060 } 50 | } 51 | 52 | /* Put a border around prettyprinted code snippets. */ 53 | pre.prettyprint { padding: 2px; border: 1px solid #888 } 54 | 55 | /* Specify class=linenums on a pre to get line numbering */ 56 | ol.linenums { margin-top: 0; margin-bottom: 0 } /* IE indents via margin-left */ 57 | li.L0, 58 | li.L1, 59 | li.L2, 60 | li.L3, 61 | li.L5, 62 | li.L6, 63 | li.L7, 64 | li.L8 { list-style-type: none } 65 | /* Alternate shading for lines */ 66 | li.L1, 67 | li.L3, 68 | li.L5, 69 | li.L7, 70 | li.L9 { background: #eee } 71 | -------------------------------------------------------------------------------- /styles/_animation.scss: -------------------------------------------------------------------------------- 1 | %animate { 2 | animation-duration: $anim-default-time; 3 | animation-iteration-count: 1; 4 | animation-fill-mode: both; 5 | animation-timing-function: $anim-cubic-bezier; 6 | } 7 | /*https://github.com/tobiasahlin/SpinKit*/ 8 | .spinner { 9 | animation: sk-rotateplane 1.2s infinite $anim-cubic-bezier; 10 | } 11 | 12 | @-webkit-keyframes sk-rotateplane { 13 | 0% { 14 | -webkit-transform: perspective(120px); 15 | } 16 | 17 | 50% { 18 | -webkit-transform: perspective(120px) rotateY(180deg); 19 | } 20 | 21 | 100% { 22 | -webkit-transform: perspective(120px) rotateY(180deg) rotateX(180deg); 23 | } 24 | } 25 | 26 | 27 | @keyframes sk-rotateplane { 28 | 0% { 29 | transform: perspective(120px) rotateX(0deg) rotateY(0deg); 30 | -webkit-transform: perspective(120px) rotateX(0deg) rotateY(0deg); 31 | } 32 | 33 | 50% { 34 | transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg); 35 | -webkit-transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg); 36 | } 37 | 38 | 100% { 39 | transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg); 40 | -webkit-transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /styles/_common.scss: -------------------------------------------------------------------------------- 1 | *, 2 | :after, 3 | :before { 4 | -webkit-box-sizing: border-box; /*size not include padding and margin*/ 5 | } 6 | 7 | html, body { 8 | width: 100%; 9 | font-size: 1rem; 10 | line-height: 1.5; 11 | -webkit-font-smoothing: antialiased; 12 | -moz-osx-font-smoothing: grayscale; 13 | } 14 | 15 | body { 16 | background: #fff; 17 | color: #373a3c; 18 | transition: all 350ms $anim-cubic-bezier; 19 | &.dark { 20 | background: $dark; 21 | color: #fff; 22 | } 23 | } 24 | 25 | /* 26 | http://www.fontspace.com/538fonts/dressedless 27 | https://everythingfonts.com/ttf-to-svg 28 | */ 29 | @font-face { 30 | font-family: 'Dressedless Three'; 31 | src: url('../fonts/Dressedless_Three.ttf') format("truetype"), url('../fonts/Dressedless_Three.svg') format("svg"); 32 | /* Legacy iOS */ 33 | } 34 | 35 | /* latin-ext */ 36 | @font-face { 37 | font-family: 'Lato'; 38 | font-style: italic; 39 | font-weight: 400; 40 | src: local('Lato Italic'), local('Lato-Italic'), url('../fonts/LatoLatin-Italic.woff2') format('woff2'); 41 | unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; 42 | } 43 | 44 | /* latin */ 45 | @font-face { 46 | font-family: 'Lato'; 47 | font-style: italic; 48 | font-weight: 400; 49 | src: local('Lato Italic'), local('Lato-Italic'), url('../fonts/LatoLatin-Italic.woff2') format('woff2'); 50 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; 51 | } 52 | 53 | /* latin-ext */ 54 | @font-face { 55 | font-family: 'Lato'; 56 | font-style: italic; 57 | font-weight: 700; 58 | src: local('Lato Bold Italic'), local('Lato-BoldItalic'), url('../fonts/LatoLatin-BoldItalic.woff2') format('woff2'); 59 | unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; 60 | } 61 | 62 | /* latin */ 63 | @font-face { 64 | font-family: 'Lato'; 65 | font-style: italic; 66 | font-weight: 700; 67 | src: local('Lato Bold Italic'), local('Lato-BoldItalic'), url('../fonts/LatoLatin-BoldItalic.woff2') format('woff2'); 68 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; 69 | } 70 | 71 | /* latin-ext */ 72 | @font-face { 73 | font-family: 'Lato'; 74 | font-style: normal; 75 | font-weight: 400; 76 | src: local('Lato Regular'), local('Lato-Regular'), url('../fonts/LatoLatin-Regular.woff2') format('woff2'); 77 | unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; 78 | } 79 | 80 | /* latin */ 81 | @font-face { 82 | font-family: 'Lato'; 83 | font-style: normal; 84 | font-weight: 400; 85 | src: local('Lato Regular'), local('Lato-Regular'), url('../fonts/LatoLatin-Regular.woff2') format('woff2'); 86 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; 87 | } 88 | 89 | /* latin-ext */ 90 | @font-face { 91 | font-family: 'Lato'; 92 | font-style: normal; 93 | font-weight: 700; 94 | src: local('Lato Bold'), local('Lato-Bold'), url('../fonts/LatoLatin-Bold.woff2') format('woff2'); 95 | unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; 96 | } 97 | 98 | /* latin */ 99 | @font-face { 100 | font-family: 'Lato'; 101 | font-style: normal; 102 | font-weight: 700; 103 | src: local('Lato Bold'), local('Lato-Bold'), url('../fonts/LatoLatin-Bold.woff2') format('woff2'); 104 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; 105 | } 106 | -------------------------------------------------------------------------------- /styles/_components.scss: -------------------------------------------------------------------------------- 1 | @import "logo"; 2 | @import "donate"; 3 | @import "nav-bar-container"; 4 | @import "source-code"; 5 | @import "doodle"; 6 | -------------------------------------------------------------------------------- /styles/_constants.scss: -------------------------------------------------------------------------------- 1 | /* animation */ 2 | $anim-cubic-bezier: cubic-bezier(0.4, 0, 0.2, 1); 3 | $anim-default-time: 0.6s; 4 | 5 | /* color */ 6 | $box-shadow: rgb(187,187,187) 0px 2px 8px !important; 7 | $dark: #272b38; 8 | 9 | /* dimensions */ 10 | -------------------------------------------------------------------------------- /styles/_containers.scss: -------------------------------------------------------------------------------- 1 | @import "main-container"; 2 | @import "copybook-container"; 3 | @import "notice-container"; 4 | -------------------------------------------------------------------------------- /styles/_copybook-container.scss: -------------------------------------------------------------------------------- 1 | @at-root { 2 | .copybook-container { 3 | &#{&}> .header { 4 | padding: 0.8rem 1rem; 5 | } 6 | > .content { 7 | position: relative; 8 | &:after { 9 | content: ""; 10 | position: absolute; 11 | top: 0; 12 | left: 0; 13 | right: 0; 14 | bottom: 0; 15 | z-index: 1; 16 | transition: background $anim-default-time $anim-cubic-bezier; 17 | } 18 | &:hover, &:focus { 19 | &:after { 20 | background: rgba(255, 255, 255, 0.76); 21 | } 22 | } 23 | pre { 24 | position: relative; 25 | display: inline-block; 26 | margin: 0; 27 | padding: 0; 28 | min-width: 98%; 29 | } 30 | code { 31 | display: inline-block; 32 | color: #000; 33 | } 34 | } 35 | .ui.search.selection.dropdown { 36 | font-size: .8rem; 37 | min-width: 30rem; 38 | .menu>.item { 39 | font-size: .8rem; 40 | } 41 | } 42 | .title { 43 | text-align: center; 44 | font-size: 1rem; 45 | margin-bottom: -0.2rem; 46 | margin-top: -1rem; 47 | } 48 | .editor { 49 | position: absolute; 50 | top: 0; 51 | left: 0; 52 | right: 0; 53 | bottom: 0; 54 | z-index: 4; 55 | color: #000; 56 | -webkit-tap-highlight-color: rgba(255,255,255,0); 57 | outline: none; 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /styles/_donate.scss: -------------------------------------------------------------------------------- 1 | .donate { 2 | padding: 2rem 0; 3 | text-align: center; 4 | 5 | form { 6 | display: inline-block; 7 | } 8 | 9 | .hd { 10 | padding-bottom: .8rem; 11 | text-align: center; 12 | } 13 | 14 | .bd { 15 | display: flex; 16 | flex-direction: row; 17 | align-items: center; 18 | } 19 | 20 | .zhifubao, 21 | .wechatpay, 22 | .paypal { 23 | margin: 0 0.5rem; 24 | width: 5rem; 25 | background: #fff; 26 | border-radius: 0.1rem; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /styles/_doodle.scss: -------------------------------------------------------------------------------- 1 | @at-root { 2 | css-doodle { 3 | position: fixed; 4 | z-index: -1; 5 | // fish 6 | &.fish { 7 | --color: @p(#FDFFFC, #2EC4B6, #E71D36, #FF9F1C); 8 | --color-fade: var(--color)@repeat2(@p([0-9a-b])); 9 | --noise: @svg-filter( 10 | 11 | 12 | 13 | 14 | 15 | 16 | ); 17 | 18 | --rule: ( 19 | :doodle { 20 | @grid: 12x1 / 100vw 100vh; 21 | background-position: 50%; 22 | filter: var(--noise); 23 | } 24 | 25 | @size: 100% 50%; 26 | position: absolute; top: 25%; 27 | transform: rotate(calc((@i() - 1) * 360deg / @size())); 28 | 29 | :after { 30 | --c: var(--color); 31 | --s: @r(5); 32 | content: ''; 33 | position: absolute; 34 | @size: @r(40vmin, 61vmin) @r(12vmin, 17vmin); 35 | border-left: @r(3px) solid @var(--c); 36 | border-radius: 50vmin; 37 | background: 38 | radial-gradient(@var(--c) 50%, transparent 0%) 1vmin 42% / 3px 6px no-repeat, 39 | radial-gradient(@var(--c) 50%, transparent 0%) 1vmin 58% / 3px 6px no-repeat, 40 | @m20(linear-gradient(to right, @var(--c), transparent @r(50%, 80%)) 0 @r(100%) / @r(20%) 1px no-repeat), 41 | linear-gradient(to right, @var(--c), transparent @r(50%, 80%)) 0 50% / @r(40%, 60%) 1px no-repeat, 42 | linear-gradient(to right, rgba(255, 255, 255, .015), transparent); 43 | transform: rotateY(0) scaleX(@var(--s)) translateZ(50vmin); 44 | transform-origin: 0 50%; 45 | will-change: transform; 46 | animation: r @r(10s, 20s) linear infinite; 47 | animation-delay: -@r(50s); 48 | } 49 | 50 | @keyframes r { 51 | to { transform: rotateY(-1turn) scaleX(@var(--s)) translateZ(50vmin) } 52 | } 53 | ); 54 | } 55 | 56 | // candy 57 | &.candy { 58 | --rule: ( :doodle { 59 | position: absolute; 60 | width: 100%; 61 | @grid: 10 / 101% 100vh; 62 | overflow: hidden; 63 | } 64 | animation: bounce linear @r(7s, 15s) @r(-1s, -5s) infinite; 65 | opacity: @r(0.3, 1); 66 | @place-cell: @r(100%) @r(100%); 67 | @random(.3) { 68 | :after { 69 | content: '🍭'; 70 | position: absolute; 71 | font-size: @r(25px, 35px); 72 | transform: rotate(@r(360deg)); 73 | } 74 | } 75 | @random(.2) { 76 | :after { 77 | content: '🍫'; 78 | position: absolute; 79 | @place-cell: @r(100%) @r(100%); 80 | font-size: @r(15px, 25px); 81 | z-index: @p(1, 2); 82 | transform: rotate(@r(360deg)); 83 | } 84 | } 85 | @random(.2) { 86 | :before { 87 | content: '🧁'; 88 | position: absolute; 89 | @place-cell: @r(100%) @r(100%); 90 | font-size: @r(15px, 25px); 91 | z-index: @p(1, 2); 92 | transform: rotate(@r(360deg)); 93 | } 94 | } 95 | @random(.2) { 96 | :before { 97 | content: '🍪'; 98 | position: absolute; 99 | @place-cell: @r(100%) @r(100%); 100 | font-size: @r(15px, 25px); 101 | z-index: @p(1, 2); 102 | transform: rotate(@r(360deg)); 103 | } 104 | } 105 | 106 | @keyframes bounce { 107 | 0% { 108 | transform: translateY(@r(-101vh, -110vh)); 109 | } 110 | 100% { 111 | transform: translateY(@r(101vh, 110vh)); 112 | } 113 | } 114 | ); 115 | } 116 | 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /styles/_logo.scss: -------------------------------------------------------------------------------- 1 | @at-root { 2 | .logo { 3 | margin: 1rem auto; 4 | width: 3rem; 5 | height: 3rem; 6 | 7 | img { 8 | display: inherit; 9 | width: 100%; 10 | height: 100%; 11 | border-radius: 20%; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /styles/_main-container.scss: -------------------------------------------------------------------------------- 1 | .main-container { 2 | $dark-theme: 'body.dark &'; 3 | position: relative; 4 | display: flex; 5 | align-items: center; 6 | flex-direction: column; 7 | padding-bottom: 3rem; 8 | .title { 9 | text-align: center; 10 | margin-top: 5rem; 11 | margin-bottom: 2rem; 12 | transition: margin 0.35s $anim-cubic-bezier; 13 | @media screen and (min-width: 50rem) { 14 | margin-top: 8rem; 15 | } 16 | 17 | a { 18 | color: inherit; 19 | text-decoration: none; 20 | 21 | &:visited, &:link, &:active, &:hover { 22 | color: inherit; 23 | text-decoration: none; 24 | } 25 | } 26 | 27 | span { 28 | font-family: "Dressedless Three", Lato, Roboto, 'Helvetica Neue', Arial, Helvetica, sans-serif; 29 | text-transform: uppercase; 30 | font-size: 3.5rem; 31 | font-weight: 100; 32 | @media screen and (min-width: 50rem) { 33 | font-size: 5rem; 34 | } 35 | } 36 | 37 | &.animated span { 38 | @extend %animate; 39 | animation-name: fadeIn; 40 | animation-duration: 250ms; 41 | animation-delay: 100ms; 42 | /*C*/ 43 | &:nth-child(1) { 44 | color: #4285F4; 45 | } 46 | 47 | /*O*/ 48 | &:nth-child(2) { 49 | color: #DB4437; 50 | } 51 | 52 | /*D*/ 53 | &:nth-child(3) { 54 | color: #F4B400; 55 | } 56 | 57 | /*E*/ 58 | &:nth-child(4) { 59 | color: #4285F4; 60 | } 61 | 62 | /*L*/ 63 | &:nth-child(5) { 64 | color: #0F9D58; 65 | } 66 | 67 | /*F*/ 68 | &:nth-child(6) { 69 | color: #DB4437; 70 | } 71 | } 72 | } 73 | 74 | #{$dark-theme} { 75 | .title { 76 | margin-top: 3rem; 77 | margin-bottom: 0; 78 | @media screen and (min-width: 50rem) { 79 | margin-top: 5rem; 80 | margin-bottom: 1rem; 81 | } 82 | } 83 | } 84 | 85 | .search-bar { 86 | padding: 1rem 0; 87 | width: 100%; 88 | @media screen and (min-width: 50rem) { 89 | width: 45rem; 90 | } 91 | 92 | form { 93 | padding: 0; 94 | margin: 0; 95 | border: 0; 96 | } 97 | 98 | &__desc { 99 | opacity: 0.5; 100 | padding-left: 0.8rem; 101 | font-size: 0.8rem; 102 | line-height: 1; 103 | margin-bottom: 0.2rem; 104 | @media screen and (min-width: 50rem) { 105 | padding-left: 1.4rem; 106 | font-size: 1rem; 107 | line-height: 1.5; 108 | margin-bottom: 0; 109 | } 110 | } 111 | 112 | &__input { 113 | background: #F1F3F4; 114 | border-radius: 5rem; 115 | transition: box-shadow 350ms $anim-cubic-bezier; 116 | 117 | &:focus, &:active, &:hover { 118 | box-shadow: 0 3px 8px 0 rgba(0, 0, 0, 0.2), 0 0 0 1px rgba(0, 0, 0, 0.08); 119 | } 120 | 121 | input { 122 | background: #F1F3F4; 123 | border-radius: 5rem; 124 | border: 0 !important; 125 | } 126 | } 127 | 128 | &__dropdown { 129 | display: flex; 130 | justify-content: center; 131 | align-items: center; 132 | margin-top: -0.4rem; 133 | margin-left: 1rem; 134 | 135 | i { 136 | opacity: 0.5; 137 | font-size: 1rem; 138 | &:hover { 139 | opacity: 1; 140 | } 141 | @media screen and (min-width: 50rem) { 142 | font-size: 1.2rem; 143 | } 144 | } 145 | } 146 | 147 | &__plugins { 148 | padding-left: 0.8rem; 149 | color: inherit; 150 | opacity: 0.5; 151 | font-size: 0.8rem; 152 | a, a:hover, a:link, a:active, a:focus, a:visited { 153 | color: inherit; 154 | } 155 | a:hover { 156 | text-decoration: underline; 157 | } 158 | @media screen and (min-width: 50rem) { 159 | padding-left: 1.4rem; 160 | font-size: 1rem; 161 | } 162 | } 163 | } 164 | 165 | #{$dark-theme} { 166 | .search-bar { 167 | &__input { 168 | &:focus, &:active, &:hover { 169 | box-shadow: $box-shadow; 170 | } 171 | } 172 | } 173 | } 174 | 175 | .suggestion { 176 | padding-bottom: 2rem; 177 | max-width: 100%; 178 | @media screen and (min-width: 50rem) { 179 | min-width: 43rem; 180 | } 181 | a { 182 | &:hover { 183 | text-decoration: underline; 184 | } 185 | } 186 | } 187 | 188 | .variable-list { 189 | width: 100%; 190 | text-align: center; 191 | 192 | .label { 193 | @extend .pointer-link; 194 | margin: 0.4rem 0.4rem 0 0; 195 | &:hover { 196 | box-shadow: $box-shadow; 197 | } 198 | &.animated { 199 | transform: translateZ(0); 200 | will-change: transform; 201 | } 202 | } 203 | 204 | hr { 205 | width: 70%; 206 | border-color: rgba(0, 0, 0, .16); 207 | margin-top: 1rem; 208 | } 209 | } 210 | 211 | .search-error { 212 | margin: 1rem 0; 213 | } 214 | 215 | .slogan-image { 216 | padding: 2rem 1rem; 217 | @media screen and (min-width: 50rem) { 218 | padding: 4rem 1rem; 219 | } 220 | 221 | img { 222 | max-width: 100%; 223 | height: auto; 224 | } 225 | } 226 | } 227 | 228 | -------------------------------------------------------------------------------- /styles/_nav-bar-container.scss: -------------------------------------------------------------------------------- 1 | .nav-bar-container { 2 | position: relative; 3 | top: 0; 4 | z-index: 10; 5 | .bd { 6 | top: -0.25rem; 7 | right: 0; 8 | position: absolute; 9 | display: inline-block; 10 | transition: all 1s; 11 | >*{ 12 | float: left; 13 | display: inline-block; 14 | cursor: pointer; 15 | margin-right: 0.4rem; 16 | } 17 | &:last-child{ 18 | margin-right: 0; 19 | } 20 | i{ 21 | width: auto; 22 | height: auto; 23 | margin: 0 !important; 24 | font-size: 2rem; 25 | color: #70B7FD; 26 | &:hover,&:active{ 27 | color: #59AAF9; 28 | } 29 | } 30 | .github-corner { 31 | margin-top: -0.2rem; 32 | i { 33 | font-size: 2.3rem; 34 | } 35 | } 36 | .copybook-btn { 37 | display: none; 38 | } 39 | $anim-delay: 150ms; 40 | $anim-duration: 500ms; 41 | @for $i from 1 through 5 { 42 | >*:nth-child(#{$i}) { 43 | animation-duration: $anim-duration; 44 | animation-delay: 500 + $anim-delay*($i - 1); 45 | } 46 | } 47 | } 48 | @media screen and (min-width: 50rem) { 49 | top: -0.25rem; 50 | .bd { 51 | i{ 52 | width: auto; 53 | height: 3.4rem; 54 | font-size: 3rem; 55 | } 56 | .copybook-btn.copybook-btn.copybook-btn { 57 | display: inline-block; 58 | } 59 | .github-corner { 60 | margin-top: -0.2rem; 61 | i { 62 | font-size: 3.3rem; 63 | } 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /styles/_notice-container.scss: -------------------------------------------------------------------------------- 1 | .notice-container { 2 | $dark-theme: 'body.dark &'; 3 | position: fixed; 4 | bottom: 0; 5 | left: 0; 6 | width: 100%; 7 | padding-bottom: 1rem; 8 | padding-top: 0.5rem; 9 | text-align: center; 10 | background-color: #fff; 11 | transition: background-color 150ms ease-in-out; 12 | @at-root { 13 | #{$dark-theme} { 14 | background-color: $dark; 15 | } 16 | } 17 | a { 18 | display: none; 19 | color: #70B7FD; 20 | &.show { 21 | display: block; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /styles/_source-code.scss: -------------------------------------------------------------------------------- 1 | @at-root { 2 | .source-code { 3 | &#{&}> .header { 4 | padding: 0.8rem 1rem; 5 | } 6 | > .content { 7 | pre { 8 | display: inline-block; 9 | margin: 0; 10 | padding: 0; 11 | } 12 | code { 13 | display: inline-block; 14 | color: #000; 15 | } 16 | } 17 | &#{&} .ui.dropdown .menu>.item { 18 | padding: 0.4rem 0 0 0.4rem !important; 19 | &:last-child { 20 | padding-bottom: 0.4rem !important; 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /styles/_utils.scss: -------------------------------------------------------------------------------- 1 | @mixin clearfix() { 2 | & { 3 | &::before, 4 | &::after { 5 | content: ""; 6 | display: table; 7 | } 8 | &::after { 9 | clear: both; 10 | } 11 | } 12 | } 13 | 14 | %ellipsis { 15 | white-space: nowrap; 16 | overflow: hidden; 17 | text-overflow: ellipsis; 18 | } 19 | 20 | .up-first { 21 | &::first-letter { 22 | text-transform: uppercase 23 | } 24 | } 25 | 26 | .pointer-link { 27 | cursor: pointer; 28 | } 29 | 30 | .hidden-link { 31 | &#{&} { 32 | color: #000; 33 | } 34 | &#{&}:hover { 35 | color: #1e70bf; 36 | } 37 | } 38 | 39 | .fix-break-word, p { 40 | word-break: break-all; 41 | word-break: break-word; 42 | -webkit-hyphens: auto; 43 | hyphens: auto; 44 | } 45 | 46 | .fix-modal.fix-modal.fix-modal.fix-modal { 47 | height: 97%; 48 | margin: 0 auto; 49 | overflow: hidden; 50 | transform: translate3d(0, 0, 0); 51 | &#{&} > .content { 52 | padding: 0.4rem 1rem; 53 | margin: 0; 54 | height: 91%; 55 | overflow: scroll; 56 | -webkit-overflow-scrolling: touch; 57 | } 58 | } 59 | @media (min-width: 50rem) { 60 | .fix-modal.fix-modal.fix-modal.fix-modal { 61 | height: auto; 62 | overflow: visible; 63 | .close.icon { 64 | top: 0.5rem; 65 | right: 0.5rem; 66 | color: rgba(0,0,0,.87); 67 | } 68 | &#{&} > .content { 69 | height: auto; 70 | overflow-y: visible; 71 | } 72 | } 73 | } 74 | 75 | .fix-dropdown-menu { 76 | -webkit-overflow-scrolling: touch; 77 | } 78 | -------------------------------------------------------------------------------- /styles/app.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | @import 'constants'; 3 | @import 'common'; 4 | @import 'utils'; 5 | @import "animation"; 6 | .app { 7 | position: relative; 8 | @import 'components'; 9 | @import 'containers'; 10 | } 11 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const path = require('path'); 4 | const merge = require('webpack-merge'); 5 | 6 | const common = { 7 | entry: ['@babel/polyfill', './src/App.js'], 8 | output: { 9 | filename: 'app.js', 10 | path: path.resolve(__dirname, 'app/js'), 11 | publicPath: '/app/js' 12 | }, 13 | externals: { 14 | 'react': 'React', 15 | 'react-dom': 'ReactDOM' 16 | }, 17 | module: { 18 | rules: [ 19 | { 20 | test: /\.jsx?$/, 21 | include: [ 22 | path.resolve(__dirname, 'src'), 23 | path.resolve(__dirname, 'node_modules') 24 | ], 25 | loader: 'babel-loader' 26 | } 27 | ] 28 | } 29 | }; 30 | 31 | exports.dev = merge(common, { 32 | mode: 'development', 33 | devtool: 'source-map' 34 | }); 35 | 36 | exports.prod = merge(common, { 37 | mode: 'production' 38 | }); 39 | --------------------------------------------------------------------------------