├── .bowerrc ├── .gitignore ├── CHANGELOG.md ├── README.md ├── bin ├── app │ ├── app.html │ ├── css │ │ ├── _config.scss │ │ ├── _forms.scss │ │ ├── _globals.scss │ │ ├── _header.scss │ │ ├── components │ │ │ └── _autocomplete.scss │ │ ├── style.css │ │ ├── style.scss │ │ └── views │ │ │ ├── _About.scss │ │ │ ├── _AddOverride.scss │ │ │ ├── _AllOverrides.scss │ │ │ ├── _EditOverride.scss │ │ │ └── _ImportExport.scss │ ├── js │ │ ├── app.js │ │ ├── common │ │ │ └── mixins.js │ │ ├── config.js │ │ ├── directives.js │ │ ├── factories │ │ │ ├── chrome.factory.js │ │ │ ├── configAPI.factory.js │ │ │ └── scripts.factory.js │ │ └── views │ │ │ ├── About.js │ │ │ ├── AddOverride.js │ │ │ ├── AllOverrides.js │ │ │ ├── EditOverride.js │ │ │ └── ImportExport.js │ └── partials │ │ └── views │ │ ├── About.html │ │ ├── AddOverride.html │ │ ├── AllOverrides.html │ │ ├── EditOverride.html │ │ └── ImportExport.html ├── background │ └── background.js ├── content_script │ └── content_script.js ├── icon │ ├── 1024.png │ ├── 128.png │ ├── 16.png │ ├── 256.png │ ├── 32.png │ ├── 48.png │ ├── 512.png │ └── 64.png └── manifest.json └── bower.json /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bin/lib" 3 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | lib 3 | node_modules 4 | *.zip 5 | *.log -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | TODO: 2 | Share override 3 | Build 4 | 5 | v1.0.0 6 | - Moved to open source 7 | - Complete re-write of the application 8 | - Scripts are now stored to the chrome storage service, scripts will now sync between the users computers. 9 | - Backup and restore scripts to computer 10 | 11 | v0.6.0 12 | - Back to basics, using the chrome sync service to simplify everything 13 | - Moved the project to Github and make it open source 14 | - All icons replaced to font-awesome 15 | 16 | v0.4.1 17 | - Disable number of available scripts hint for the current website 18 | - Marked external non-editable overrides in the "All Overrides" Table 19 | - Added moment.js to the list of available libs to hack with 20 | 21 | v0.4.0 22 | - External: 23 | - All new search options to lookup scripts and overrides from the web! 24 | - now supports styles from stylebot 25 | - Notify when there are available scripts for download on the website you are visiting 26 | - UI improvements 27 | - Bug fixes and performance 28 | - async.js was added to the list of available libraries to use 29 | 30 | - Internal: 31 | - improved background & front communication 32 | - added and implemented idb and configAPI service 33 | - Added moment for clear time understanding 34 | 35 | v0.3.0 36 | - Keyboard shortcuts to move between tabs, Use Ctrl + 1-9 37 | - Implemented ACE code editor 38 | - Select code editor theme from the about screen 39 | - Multiple domain regexp for one role 40 | - Use Ctrl+S keyboard shortcut to save changes 41 | - "waitForElement", "waitForElementVisible" api 42 | - Small UI fixes 43 | 44 | v0.2.5 45 | - Fixed analytics keep alive interval bug 46 | - updated icon 47 | 48 | v0.2.4 49 | - User module. Creation date, Last interaction time; 50 | - Toggle overrides activity and privacy from the all overrides table 51 | - Add new override on the bottom of the table 52 | - Report script activated to analytics 53 | 54 | v0.2.3 55 | - Title should link to edit 56 | - Don't redirect to home after saving 57 | - keep alive event for analytics 58 | - ng-repeat issue in all overrides 59 | - Add created/updated timestamp for scripts on database 60 | - Update button caption text 61 | - Width of input fields after build 62 | - show 'last update' on all overrides table 63 | 64 | v0.2.2 65 | - Migrate users scripts to the new database 66 | 67 | v0.2.1 68 | - Store data in Remote database 69 | 70 | v0.2.0 71 | - New design -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WebOverride 2 | WebOverride let's you inject code snippets into any website allowing you to customize it to fit your needs 3 | - Automatic login 4 | - hide annoying content 5 | - create custom shortcuts and so much more... 6 | 7 | # What does it do? 8 | Using WebOverride you can inject HTML, CSS and JavaScript into any page in the web. 9 | You can also import any library you might need from cdnjs.com 10 | 11 | # Chrome Store 12 | You can download the extension from the chrome store and get updated automatically when updates come out. 13 | 14 | 15 | # Setup and run locally 16 | - Clone the project 17 | - Run `bower i` the get the components 18 | - Open Chrome in `chrome://extensions/` 19 | - Check `Developer Mode` 20 | - Click `Load unpacked extension` 21 | - Select the `bin` folder -------------------------------------------------------------------------------- /bin/app/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Web Override 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 |
37 | 38 | -------------------------------------------------------------------------------- /bin/app/css/_config.scss: -------------------------------------------------------------------------------- 1 | $dark-text: #323A45; 2 | $light-text: #ffffff; 3 | 4 | $dark-blue: #323A45; 5 | $darker-blue: #212429; 6 | $light-blue: #868f9a; 7 | $blue: #14B9D5; 8 | $orange: #F37936; 9 | $green: #1EBAA5; 10 | $grey: #EAEDF2; 11 | 12 | $header-height: 50px; -------------------------------------------------------------------------------- /bin/app/css/_forms.scss: -------------------------------------------------------------------------------- 1 | @import 'config'; 2 | 3 | form, .form { 4 | input, textarea, button, select { 5 | outline: none; 6 | } 7 | fieldset { 8 | margin-bottom: 10px; 9 | } 10 | label { 11 | display: block; 12 | height: 30px; 13 | line-height: 30px; 14 | } 15 | input, select { 16 | background: $grey; 17 | color: $darker-blue; 18 | padding: 0 5px; 19 | height: 30px; 20 | line-height: 30px; 21 | border: none; 22 | 23 | &[type="text"] { 24 | width: 100%; 25 | } 26 | &[type="checkbox"] { 27 | vertical-align: middle; 28 | } 29 | &[type="checkbox"] + label { 30 | display: inline-block; 31 | } 32 | &.ng-invalid { 33 | border: 1px solid #FF9D9D; 34 | } 35 | } 36 | 37 | button { 38 | height: 30px; 39 | min-width: 30px; 40 | background-color: $light-blue; 41 | color: $light-text; 42 | &:hover { 43 | background-color: darken($light-blue, 10); 44 | cursor: pointer; 45 | } 46 | &[disabled] { 47 | opacity: 0.3; 48 | pointer-events: none; 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /bin/app/css/_globals.scss: -------------------------------------------------------------------------------- 1 | @import 'config'; 2 | 3 | html, body { 4 | width: 100%; 5 | height: 100%; 6 | padding: 0; 7 | margin: 0; 8 | } 9 | 10 | * { 11 | box-sizing: border-box; 12 | border: none; 13 | margin: 0; 14 | padding: 0; 15 | } 16 | 17 | img { 18 | vertical-align: middle; 19 | } 20 | h1, h2, h3, h4, h5, h6 { 21 | margin: 0; 22 | padding: 0; 23 | } 24 | h1 { 25 | font-size: 1.3em; 26 | } 27 | 28 | a, a:link, a:visited { 29 | color: inherit; 30 | cursor: pointer; 31 | text-decoration: none; 32 | 33 | > .fa { 34 | margin-right: 7px; 35 | } 36 | } 37 | a:hover, a:active { 38 | color: inherit; 39 | text-decoration: none; 40 | } 41 | 42 | button { 43 | display: inline-flex; 44 | align-items: center; 45 | justify-content: center; 46 | padding: 0 10px; 47 | > .fa { 48 | margin-right: 7px; 49 | } 50 | } 51 | 52 | .fa:before { 53 | font-size: 1.5em; 54 | } 55 | 56 | table { 57 | width: 100%; 58 | tr { 59 | td { 60 | height: 40px; 61 | border-bottom: 1px $grey solid; 62 | white-space: nowrap; 63 | overflow: hidden; 64 | max-width: 250px; 65 | text-overflow: ellipsis; 66 | &:first-of-type { 67 | padding-left: 10px; 68 | } 69 | } 70 | } 71 | 72 | thead { 73 | font-weight: bold; 74 | tr { 75 | background: $green; 76 | color: $light-text; 77 | } 78 | } 79 | 80 | tbody { 81 | tr { 82 | transition: background 0.3s; 83 | &:hover { 84 | background: $grey; 85 | } 86 | td { 87 | .btn { 88 | display: block; 89 | width: 40px; 90 | height: 40px; 91 | background: no-repeat center center; 92 | background-size: 20px; 93 | border-radius: 2px; 94 | opacity: 0.3; 95 | cursor: pointer; 96 | transition: opacity 0.2s, background 0.2s 0.1s; 97 | &:hover { 98 | opacity: 1; 99 | background-color: $light-blue; 100 | } 101 | } 102 | } 103 | } 104 | } 105 | } -------------------------------------------------------------------------------- /bin/app/css/_header.scss: -------------------------------------------------------------------------------- 1 | header { 2 | display: flex; 3 | align-content: center; 4 | justify-content: space-between; 5 | height: $header-height; 6 | width: 100%; 7 | line-height: $header-height; 8 | color: $light-text; 9 | background: $dark-blue; 10 | h1 { 11 | margin: 0 10px; 12 | flex: 1; 13 | a { 14 | color: $light-text; 15 | } 16 | } 17 | button, a { 18 | display: inline-flex; 19 | justify-content: center; 20 | align-items: center; 21 | width: $header-height; 22 | height: $header-height; 23 | opacity: 0.8; 24 | transition: opacity 0.2s, background 0.2s 0.1s; 25 | cursor: pointer; 26 | border: none; 27 | text-decoration: none; 28 | color: #ffffff; 29 | background: transparent; 30 | 31 | &.highlight { 32 | opacity: 1; 33 | } 34 | &:hover { 35 | background-color: rgba(0,0,0,0.2); 36 | opacity: 1; 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /bin/app/css/components/_autocomplete.scss: -------------------------------------------------------------------------------- 1 | .mass-ac { 2 | position: relative; 3 | width: 100%; 4 | 5 | .ac-container { 6 | position: absolute !important; 7 | top: 100% !important;; 8 | left: 0 !important;; 9 | width: auto !important; 10 | .ac-menu { 11 | max-height: 144px; 12 | overflow: auto; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /bin/app/css/style.css: -------------------------------------------------------------------------------- 1 | @import url(http://fonts.googleapis.com/css?family=Open+Sans:200,400,700); 2 | html, body { 3 | width: 100%; 4 | height: 100%; 5 | padding: 0; 6 | margin: 0; } 7 | 8 | * { 9 | box-sizing: border-box; 10 | border: none; 11 | margin: 0; 12 | padding: 0; } 13 | 14 | img { 15 | vertical-align: middle; } 16 | 17 | h1, h2, h3, h4, h5, h6 { 18 | margin: 0; 19 | padding: 0; } 20 | 21 | h1 { 22 | font-size: 1.3em; } 23 | 24 | a, a:link, a:visited { 25 | color: inherit; 26 | cursor: pointer; 27 | text-decoration: none; } 28 | a > .fa, a:link > .fa, a:visited > .fa { 29 | margin-right: 7px; } 30 | 31 | a:hover, a:active { 32 | color: inherit; 33 | text-decoration: none; } 34 | 35 | button { 36 | display: inline-flex; 37 | align-items: center; 38 | justify-content: center; 39 | padding: 0 10px; } 40 | button > .fa { 41 | margin-right: 7px; } 42 | 43 | .fa:before { 44 | font-size: 1.5em; } 45 | 46 | table { 47 | width: 100%; } 48 | table tr td { 49 | height: 40px; 50 | border-bottom: 1px #eaedf2 solid; 51 | white-space: nowrap; 52 | overflow: hidden; 53 | max-width: 250px; 54 | text-overflow: ellipsis; } 55 | table tr td:first-of-type { 56 | padding-left: 10px; } 57 | table thead { 58 | font-weight: bold; } 59 | table thead tr { 60 | background: #1ebaa5; 61 | color: white; } 62 | table tbody tr { 63 | transition: background 0.3s; } 64 | table tbody tr:hover { 65 | background: #eaedf2; } 66 | table tbody tr td .btn { 67 | display: block; 68 | width: 40px; 69 | height: 40px; 70 | background: no-repeat center center; 71 | background-size: 20px; 72 | border-radius: 2px; 73 | opacity: 0.3; 74 | cursor: pointer; 75 | transition: opacity 0.2s, background 0.2s 0.1s; } 76 | table tbody tr td .btn:hover { 77 | opacity: 1; 78 | background-color: #868f9a; } 79 | 80 | form input, form textarea, form button, form select, .form input, .form textarea, .form button, .form select { 81 | outline: none; } 82 | form fieldset, .form fieldset { 83 | margin-bottom: 10px; } 84 | form label, .form label { 85 | display: block; 86 | height: 30px; 87 | line-height: 30px; } 88 | form input, form select, .form input, .form select { 89 | background: #eaedf2; 90 | color: #212429; 91 | padding: 0 5px; 92 | height: 30px; 93 | line-height: 30px; 94 | border: none; } 95 | form input[type="text"], form select[type="text"], .form input[type="text"], .form select[type="text"] { 96 | width: 100%; } 97 | form input[type="checkbox"], form select[type="checkbox"], .form input[type="checkbox"], .form select[type="checkbox"] { 98 | vertical-align: middle; } 99 | form input[type="checkbox"] + label, form select[type="checkbox"] + label, .form input[type="checkbox"] + label, .form select[type="checkbox"] + label { 100 | display: inline-block; } 101 | form input.ng-invalid, form select.ng-invalid, .form input.ng-invalid, .form select.ng-invalid { 102 | border: 1px solid #FF9D9D; } 103 | form button, .form button { 104 | height: 30px; 105 | min-width: 30px; 106 | background-color: #868f9a; 107 | color: white; } 108 | form button:hover, .form button:hover { 109 | background-color: #6c7581; 110 | cursor: pointer; } 111 | form button[disabled], .form button[disabled] { 112 | opacity: 0.3; 113 | pointer-events: none; } 114 | 115 | body { 116 | font-family: 'Open Sans', Helvetica Neue, Helvetica, sans-serif; 117 | background: #ffffff; 118 | color: #323a45; 119 | font-size: 14px; 120 | min-width: 700px; 121 | min-height: 400px; } 122 | body header { 123 | display: flex; 124 | align-content: center; 125 | justify-content: space-between; 126 | height: 50px; 127 | width: 100%; 128 | line-height: 50px; 129 | color: white; 130 | background: #323a45; } 131 | body header h1 { 132 | margin: 0 10px; 133 | flex: 1; } 134 | body header h1 a { 135 | color: white; } 136 | body header button, body header a { 137 | display: inline-flex; 138 | justify-content: center; 139 | align-items: center; 140 | width: 50px; 141 | height: 50px; 142 | opacity: 0.8; 143 | transition: opacity 0.2s, background 0.2s 0.1s; 144 | cursor: pointer; 145 | border: none; 146 | text-decoration: none; 147 | color: #ffffff; 148 | background: transparent; } 149 | body header button.highlight, body header a.highlight { 150 | opacity: 1; } 151 | body header button:hover, body header a:hover { 152 | background-color: rgba(0, 0, 0, 0.2); 153 | opacity: 1; } 154 | body .mass-ac { 155 | position: relative; 156 | width: 100%; } 157 | body .mass-ac .ac-container { 158 | position: absolute !important; 159 | top: 100% !important; 160 | left: 0 !important; 161 | width: auto !important; } 162 | body .mass-ac .ac-container .ac-menu { 163 | max-height: 144px; 164 | overflow: auto; } 165 | body .about .content { 166 | padding: 0 10px; } 167 | body .allOverrides .no-scripts { 168 | text-align: center; 169 | padding: 20px 0; } 170 | body .allOverrides .no-scripts > * { 171 | margin: 20px 0; } 172 | body .allOverrides table tbody tr.external span { 173 | opacity: 0.3; } 174 | body .allOverrides table tbody tr td.add a { 175 | display: flex; 176 | align-content: center; 177 | padding: 10px 0; } 178 | body .allOverrides table tbody tr td.add a img { 179 | height: 20px; 180 | margin-right: 7px; } 181 | body .allOverrides table tbody tr td.secondary { 182 | color: #868f9a; 183 | font-size: 12px; } 184 | body .addOverride .content { 185 | padding: 20px; } 186 | body .addOverride .content .urlQuery { 187 | display: flex; } 188 | body .addOverride .content .urlQuery > input { 189 | flex: 1; } 190 | body .addOverride .content .urlQuery .remove-input-row { 191 | background: #eaedf2; 192 | color: #323a45; } 193 | body .addOverride .content .urlQuery .remove-input-row:hover { 194 | background-color: #868f9a; } 195 | body .editOverride .menu, body .editOverride .tab { 196 | position: absolute; 197 | top: 50px; 198 | bottom: 0; 199 | left: 0; 200 | right: 0; } 201 | body .editOverride .menu { 202 | width: 80px; 203 | background: #eaedf2; 204 | color: #ffffff; } 205 | body .editOverride .menu .item { 206 | display: flex; 207 | justify-content: center; 208 | align-items: center; 209 | flex-direction: column; 210 | width: 80px; 211 | height: 80px; 212 | transition: font-size 0.3s; 213 | font-size: 0; 214 | color: inherit; } 215 | body .editOverride .menu .item i { 216 | font-size: 20px; 217 | margin-bottom: 5px; } 218 | body .editOverride .menu .item:hover, body .editOverride .menu .item.selected { 219 | font-size: 14px; } 220 | body .editOverride .menu .item.selected { 221 | cursor: default; 222 | color: rgba(255, 255, 255, 0.5); } 223 | body .editOverride .menu .item.settings { 224 | background-color: #14b9d5; } 225 | body .editOverride .menu .item.html { 226 | background-color: #f37936; } 227 | body .editOverride .menu .item.css { 228 | background-color: #1ebaa5; } 229 | body .editOverride .menu .item.js { 230 | background-color: #14b9d5; } 231 | body .editOverride .tab { 232 | left: 80px; } 233 | body .editOverride .tab.settings { 234 | padding: 20px; } 235 | body .editOverride .tab.settings .urlQuery { 236 | display: flex; } 237 | body .editOverride .tab.settings .urlQuery > input { 238 | flex: 1; } 239 | body .editOverride .tab.settings .urlQuery .remove-input-row { 240 | background: #eaedf2; 241 | color: #323a45; } 242 | body .editOverride .tab.settings .urlQuery .remove-input-row:hover { 243 | background-color: #868f9a; } 244 | body .editOverride .tab.settings .libs .head { 245 | display: flex; } 246 | body .editOverride .tab.settings .libs .head h2 { 247 | margin-right: 10px; } 248 | body .editOverride .tab.settings .libs .list { 249 | display: flex; 250 | align-items: center; } 251 | body .editOverride .tab.settings .libs .list div { 252 | flex: 1; } 253 | body .editOverride .tab.settings .libs .list:hover { 254 | background: rgba(0, 0, 0, 0.05); } 255 | body .editOverride .tab .code-input { 256 | width: 100%; 257 | height: 100%; } 258 | body .importExport .content { 259 | padding: 10px; } 260 | -------------------------------------------------------------------------------- /bin/app/css/style.scss: -------------------------------------------------------------------------------- 1 | @import url(http://fonts.googleapis.com/css?family=Open+Sans:200,400,700); 2 | 3 | @import 'config'; 4 | 5 | @import 'globals'; 6 | @import 'forms'; 7 | 8 | body { 9 | font-family: 'Open Sans', Helvetica Neue, Helvetica, sans-serif; 10 | background: #ffffff; 11 | color: $dark-text; 12 | font-size: 14px; 13 | min-width: 700px; 14 | min-height: 400px; 15 | 16 | @import 'header'; 17 | @import 'components/autocomplete'; 18 | @import 'views/_About'; 19 | @import 'views/_AllOverrides'; 20 | @import 'views/_AddOverride'; 21 | @import 'views/_EditOverride'; 22 | @import 'views/ImportExport'; 23 | } -------------------------------------------------------------------------------- /bin/app/css/views/_About.scss: -------------------------------------------------------------------------------- 1 | .about { 2 | .content { 3 | padding: 0 10px; 4 | } 5 | } -------------------------------------------------------------------------------- /bin/app/css/views/_AddOverride.scss: -------------------------------------------------------------------------------- 1 | .addOverride { 2 | .content { 3 | padding: 20px; 4 | 5 | .urlQuery { 6 | display: flex; 7 | > input { 8 | flex: 1; 9 | } 10 | .remove-input-row { 11 | background: $grey; 12 | color: $dark-text; 13 | &:hover { 14 | background-color: $light-blue; 15 | } 16 | } 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /bin/app/css/views/_AllOverrides.scss: -------------------------------------------------------------------------------- 1 | .allOverrides { 2 | .no-scripts { 3 | text-align: center; 4 | padding: 20px 0; 5 | > * { 6 | margin: 20px 0; 7 | } 8 | } 9 | 10 | table { 11 | tbody { 12 | tr { 13 | &.external { 14 | span { 15 | opacity: 0.3; 16 | } 17 | } 18 | td { 19 | &.add { 20 | a { 21 | display: flex; 22 | align-content: center; 23 | padding: 10px 0; 24 | img { 25 | height: 20px; 26 | margin-right: 7px; 27 | } 28 | } 29 | } 30 | &.secondary { 31 | color: $light-blue; 32 | font-size: 12px; 33 | } 34 | } 35 | } 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /bin/app/css/views/_EditOverride.scss: -------------------------------------------------------------------------------- 1 | .editOverride { 2 | $menu-width: 80px; 3 | 4 | .menu, .tab { 5 | position: absolute; 6 | top: $header-height; 7 | bottom: 0; 8 | left: 0; 9 | right: 0; 10 | } 11 | 12 | .menu { 13 | width: $menu-width; 14 | background: $grey; 15 | color: #ffffff; 16 | .item { 17 | display: flex; 18 | justify-content: center; 19 | align-items: center; 20 | flex-direction: column; 21 | width: $menu-width; 22 | height: $menu-width; 23 | transition: font-size 0.3s; 24 | font-size: 0; 25 | color: inherit; 26 | i { 27 | font-size: 20px; 28 | margin-bottom: 5px; 29 | } 30 | &:hover, &.selected { 31 | font-size: 14px; 32 | } 33 | &.selected { 34 | cursor: default; 35 | color: rgba(255, 255, 255, 0.5); 36 | } 37 | &.settings { 38 | background-color: $blue; 39 | } 40 | &.html { 41 | background-color: $orange; 42 | } 43 | &.css { 44 | background-color: $green; 45 | } 46 | &.js { 47 | background-color: $blue; 48 | } 49 | } 50 | } 51 | 52 | .tab { 53 | left: $menu-width; 54 | &.settings { 55 | padding: 20px; 56 | .urlQuery { 57 | display: flex; 58 | > input { 59 | flex: 1; 60 | } 61 | .remove-input-row { 62 | background: $grey; 63 | color: $dark-text; 64 | &:hover { 65 | background-color: $light-blue; 66 | } 67 | } 68 | } 69 | 70 | .libs { 71 | .head { 72 | display: flex; 73 | h2 { 74 | margin-right: 10px; 75 | } 76 | } 77 | .list { 78 | display: flex; 79 | align-items: center; 80 | div { 81 | flex: 1; 82 | } 83 | &:hover { 84 | background: rgba(0, 0, 0, 0.05); 85 | } 86 | } 87 | } 88 | } 89 | 90 | .code-input { 91 | width: 100%; 92 | height: 100%; 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /bin/app/css/views/_ImportExport.scss: -------------------------------------------------------------------------------- 1 | .importExport { 2 | .content { 3 | padding: 10px; 4 | } 5 | } -------------------------------------------------------------------------------- /bin/app/js/app.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Initialize th angular application 3 | */ 4 | var app = angular.module('app', [ 5 | 'ngSanitize', 6 | 'ui.router', 7 | 'ui.ace', 8 | 'cfp.hotkeys', 9 | 'MassAutoComplete' 10 | ]) 11 | .config(['$urlRouterProvider', '$compileProvider', 12 | function ($urlRouterProvider, $compileProvider) { 13 | // For any unmatched url, redirect to default state 14 | $urlRouterProvider.otherwise("/all-overrides"); 15 | 16 | // Allow the app to load assets from the extension 17 | var sanitizeWhitelist = /^\s*(https?|ftp|mailto|chrome-extension):/; 18 | $compileProvider.aHrefSanitizationWhitelist(sanitizeWhitelist); 19 | $compileProvider.imgSrcSanitizationWhitelist(sanitizeWhitelist); 20 | }]) 21 | .run(['$rootScope', 'configAPI', 22 | function ($rootScope, configAPI) { 23 | configAPI.init(); 24 | 25 | $rootScope.config = config; 26 | $rootScope._ = _; 27 | 28 | $rootScope.fullmode = window.location.hash.indexOf('full') !== -1; 29 | 30 | $rootScope.$on('$stateChangeSuccess', function (e, newState) { 31 | $rootScope.currentState = newState.name; 32 | }); 33 | }]); -------------------------------------------------------------------------------- /bin/app/js/common/mixins.js: -------------------------------------------------------------------------------- 1 | function s4() { 2 | return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1); 3 | } 4 | 5 | _.mixin({ 6 | guid: function () { 7 | return [s4() + s4(), s4(), s4(), s4(), s4() + s4() + s4()].join('-'); 8 | }, 9 | isUUID: function(str) { 10 | return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(str) 11 | }, 12 | downloadFileFromText: function (filename, content) { 13 | var a = document.createElement('a'); 14 | var blob = new Blob([content], {type: "text/plain;charset=UTF-8"}); 15 | a.href = window.URL.createObjectURL(blob); 16 | a.download = filename; 17 | a.style.display = 'none'; 18 | document.body.appendChild(a); 19 | a.click(); //this is probably the key - simulating a click on a download link 20 | } 21 | }); -------------------------------------------------------------------------------- /bin/app/js/config.js: -------------------------------------------------------------------------------- 1 | var config = {}; 2 | 3 | config.editorThemes = [ 4 | {name: 'Textmate', value: 'textmate'}, 5 | {name: 'Ambiance', value: 'ambiance'}, 6 | {name: 'Chaos', value: 'chaos'}, 7 | {name: 'Chrome', value: 'chrome'}, 8 | {name: 'Clouds', value: 'clouds'}, 9 | {name: 'Clouds Midnight', value: 'clouds_midnight'}, 10 | {name: 'Cobalt', value: 'cobalt'}, 11 | {name: 'Crimson Editor', value: 'crimson_editor'}, 12 | {name: 'Dawn', value: 'dawn'}, 13 | {name: 'Dreamweaver', value: 'dreamweaver'}, 14 | {name: 'Eclipse', value: 'eclipse'}, 15 | {name: 'Github', value: 'github'}, 16 | {name: 'Idle Fingers', value: 'idle_fingers'}, 17 | {name: 'Katzenmilch', value: 'katzenmilch'}, 18 | {name: 'Kr Theme', value: 'kr_theme'}, 19 | {name: 'Kuroir', value: 'kuroir'}, 20 | {name: 'Merbivore', value: 'merbivore'}, 21 | {name: 'Merbivore Soft', value: 'merbivore_soft'}, 22 | {name: 'Mono Industrial', value: 'mono_industrial'}, 23 | {name: 'Monokai', value: 'monokai'}, 24 | {name: 'Pastel On Dark', value: 'pastel_on_dark'}, 25 | {name: 'Solarized Dark', value: 'solarized_dark'}, 26 | {name: 'Solarized Light', value: 'solarized_light'}, 27 | {name: 'Terminal', value: 'terminal'}, 28 | {name: 'Tomorrow', value: 'tomorrow'}, 29 | {name: 'Tomorrow Night', value: 'tomorrow_night'}, 30 | {name: 'Tomorrow Night Blue', value: 'tomorrow_night_blue'}, 31 | {name: 'Tomorrow Night Bright', value: 'tomorrow_night_bright'}, 32 | {name: 'Tomorrow Night Eighties', value: 'tomorrow_night_eighties'}, 33 | {name: 'Twilight', value: 'twilight'}, 34 | {name: 'Vibrant Ink', value: 'vibrant_ink'} 35 | ]; 36 | config.editorTheme = config.editorThemes[0].value; -------------------------------------------------------------------------------- /bin/app/js/directives.js: -------------------------------------------------------------------------------- 1 | angular.module('app') 2 | .directive('fileReader', function () { 3 | return { 4 | scope: { 5 | onContent: '=' 6 | }, 7 | template: '
' + 8 | '' + 9 | '
', 10 | link: function (scope, element) { 11 | var fileInput = element.find('input'); 12 | fileInput.on('change', function (e) { 13 | var file = fileInput[0].files[0]; 14 | var reader = new FileReader(); 15 | 16 | reader.onload = function (e) { 17 | try { 18 | var result = JSON.parse(reader.result); 19 | } catch (e) { 20 | } 21 | scope.onContent.apply(null, [result]); 22 | }; 23 | 24 | reader.readAsText(file); 25 | }); 26 | } 27 | } 28 | }); -------------------------------------------------------------------------------- /bin/app/js/factories/chrome.factory.js: -------------------------------------------------------------------------------- 1 | angular.module('app') 2 | .factory('chrome', ['$q', 3 | function ($q) { 4 | 5 | var EXTENSION_ID = chrome.app.getDetails().id; 6 | 7 | /** 8 | * 9 | * @returns {*} 10 | */ 11 | function activeTab() { 12 | return $q(function (resolve) { 13 | chrome.tabs.getSelected(null, function (tab) { 14 | tab = !_.contains(tab.url, EXTENSION_ID) ? tab : null; 15 | resolve(tab); 16 | }); 17 | }); 18 | } 19 | 20 | /** 21 | * 22 | * @param message 23 | * @returns {*} 24 | */ 25 | function messageTabs(message) { 26 | return $q(function (resolve) { 27 | chrome.tabs.query({}, function (tabs) { 28 | tabs.forEach(function (tab) { 29 | chrome.tabs.sendMessage(tab.id, message); 30 | }); 31 | 32 | resolve(); 33 | }); 34 | }); 35 | } 36 | 37 | return { 38 | activeTab: activeTab, 39 | messageTabs: messageTabs 40 | }; 41 | }]); -------------------------------------------------------------------------------- /bin/app/js/factories/configAPI.factory.js: -------------------------------------------------------------------------------- 1 | angular.module('app') 2 | .factory('configAPI', [function () { 3 | 'use strict'; 4 | 5 | /** 6 | * 7 | */ 8 | function init() { 9 | if (!window.config) { 10 | window.config = {}; 11 | } 12 | 13 | _.each(_getStoredConfig(), function (value, key) { 14 | config[key] = value; 15 | }); 16 | } 17 | 18 | /** 19 | * 20 | * @param key 21 | * @param value 22 | */ 23 | function set(key, value) { 24 | config[key] = value; 25 | 26 | // Long term storage 27 | var storedConfig = _getStoredConfig(); 28 | storedConfig[key] = value; 29 | localStorage.config = JSON.stringify(storedConfig); 30 | } 31 | 32 | /** 33 | * 34 | * @param key 35 | */ 36 | function remove(key) { 37 | var storedConfig = _getStoredConfig(); 38 | delete storedConfig[key]; 39 | delete config[key]; 40 | localStorage.config = JSON.stringify(storedConfig); 41 | } 42 | 43 | /** 44 | * 45 | * @returns {*} 46 | */ 47 | function _getStoredConfig() { 48 | if (!localStorage.config) { 49 | return {}; 50 | } 51 | 52 | try { 53 | var result = JSON.parse(localStorage.config); 54 | return result; 55 | } catch (e) { 56 | return {}; 57 | } 58 | } 59 | 60 | init(); 61 | 62 | return { 63 | init: init, 64 | set: set, 65 | remove: remove 66 | }; 67 | }]); -------------------------------------------------------------------------------- /bin/app/js/factories/scripts.factory.js: -------------------------------------------------------------------------------- 1 | angular.module('app') 2 | .factory('scripts', ['$q', 3 | function ($q) { 4 | 5 | /** 6 | * 7 | * @returns {*} 8 | */ 9 | function getAll() { 10 | return $q(function (resolve) { 11 | chrome.storage.sync.get(function (scripts) { 12 | if (_.size(scripts) === 0) { 13 | scripts = null; 14 | } 15 | resolve(scripts); 16 | }); 17 | }); 18 | } 19 | 20 | /** 21 | * 22 | * @param id 23 | * @returns {*} 24 | */ 25 | function get(id) { 26 | return $q(function (resolve) { 27 | chrome.storage.sync.get(id, function (result) { 28 | resolve(result[id]); 29 | }); 30 | }); 31 | } 32 | 33 | /** 34 | * 35 | * @param id 36 | * @returns {*} 37 | */ 38 | function remove(id) { 39 | return $q(function (resolve) { 40 | chrome.storage.sync.remove(id, function () { 41 | resolve(); 42 | }); 43 | }); 44 | } 45 | 46 | /** 47 | * 48 | * @param id 49 | * @param script 50 | * @returns {*} 51 | */ 52 | function set(id, script) { 53 | id = id || _.guid(); 54 | 55 | script = angular.copy(script); 56 | 57 | if (!script.createdAt) { 58 | script.createdAt = Date.now(); 59 | } 60 | script.updatedAt = Date.now(); 61 | 62 | var obj = {}; 63 | obj[id] = script; 64 | 65 | return $q(function (resolve) { 66 | chrome.storage.sync.set(obj, function () { 67 | resolve(id, script); 68 | }); 69 | }); 70 | } 71 | 72 | return { 73 | getAll: getAll, 74 | get: get, 75 | remove: remove, 76 | set: set 77 | }; 78 | }]); -------------------------------------------------------------------------------- /bin/app/js/views/About.js: -------------------------------------------------------------------------------- 1 | angular.module('app') 2 | .config(['$stateProvider', function ($stateProvider) { 3 | $stateProvider.state('about', { 4 | url: "/about", 5 | controller: 'AboutCtrl', 6 | templateUrl: "/app/partials/views/About.html" 7 | }); 8 | }]) 9 | .controller('AboutCtrl', ['$scope', 'configAPI', 10 | function ($scope, configAPI) { 11 | 12 | $scope.version = chrome.app.getDetails().version; 13 | $scope.year = new Date().getFullYear(); 14 | 15 | $scope.updateConfig = function (key, val) { 16 | configAPI.set(key, val); 17 | }; 18 | } 19 | ]); -------------------------------------------------------------------------------- /bin/app/js/views/AddOverride.js: -------------------------------------------------------------------------------- 1 | angular.module('app') 2 | .config(['$stateProvider', function ($stateProvider) { 3 | $stateProvider.state('addOverride', { 4 | url: "/add-override", 5 | controller: 'AddOverrideCtrl', 6 | templateUrl: "/app/partials/views/AddOverride.html", 7 | resolve: { 8 | activeTab: function (chrome) { 9 | return chrome.activeTab(); 10 | } 11 | } 12 | }); 13 | }]) 14 | .controller('AddOverrideCtrl', ['$scope', '$state', 'scripts', 'activeTab', 15 | function ($scope, $state, scripts, activeTab) { 16 | 17 | $scope.data = { 18 | title: null, 19 | active: true, 20 | urlQueries: [activeTab && activeTab.url] 21 | }; 22 | 23 | /** 24 | * 25 | */ 26 | $scope.resetURL = function () { 27 | $scope.data.urlQueries = [activeTab && activeTab.url]; 28 | }; 29 | 30 | /** 31 | * 32 | */ 33 | $scope.submitHandler = function () { 34 | scripts.set(null, $scope.data).then(function (id) { 35 | // Redirect to the edit page if this is a newly added override 36 | $state.go('editOverride', { 37 | id: id 38 | }); 39 | }); 40 | }; 41 | 42 | /** 43 | * 44 | * @param arr 45 | * @param index 46 | */ 47 | $scope.remove = function (arr, index) { 48 | arr.splice(index, 1); 49 | }; 50 | } 51 | ]); -------------------------------------------------------------------------------- /bin/app/js/views/AllOverrides.js: -------------------------------------------------------------------------------- 1 | angular.module('app') 2 | .config(['$stateProvider', 3 | function ($stateProvider) { 4 | $stateProvider.state('allOverrides', { 5 | url: "/all-overrides", 6 | templateUrl: "/app/partials/views/AllOverrides.html", 7 | resolve: { 8 | overrides: function (scripts) { 9 | return scripts.getAll(); 10 | } 11 | }, 12 | controller: 'AllOverridesCtrl' 13 | }); 14 | }]) 15 | .controller('AllOverridesCtrl', ['$scope', '$state', '$q', 'scripts', 'overrides', 16 | function ($scope, $state, $q, scripts, overrides) { 17 | 18 | $scope.scripts = overrides; 19 | 20 | $scope.update = function (id, script) { 21 | scripts.set(id, script); 22 | }; 23 | 24 | $scope.removeOverride = function (id) { 25 | if (confirm('Are you sure you want to remove this override?')) { 26 | scripts.remove(id).then(function () { 27 | delete $scope.scripts[id]; 28 | }); 29 | } 30 | }; 31 | 32 | $scope.downloadBackup = function (script, id) { 33 | var filename = 'web_override_backup_' + script.title + '_(' + new Date().toISOString() + ').json'; 34 | if (id) { 35 | var obj = {}; 36 | obj[id] = overrides[id]; 37 | } 38 | var contents = JSON.stringify(obj, null, 2); 39 | _.downloadFileFromText(filename, contents); 40 | }; 41 | } 42 | ]); -------------------------------------------------------------------------------- /bin/app/js/views/EditOverride.js: -------------------------------------------------------------------------------- 1 | angular.module('app') 2 | .config(['$stateProvider', function ($stateProvider) { 3 | $stateProvider.state('editOverride', { 4 | url: "/edit-override/:id", 5 | controller: 'EditOverrideCtrl', 6 | templateUrl: '/app/partials/views/EditOverride.html', 7 | resolve: { 8 | activeTab: function (chrome) { 9 | return chrome.activeTab(); 10 | }, 11 | scriptID: function ($stateParams) { 12 | return $stateParams.id; 13 | }, 14 | data: function (scripts, $stateParams) { 15 | return scripts.get($stateParams.id); 16 | } 17 | } 18 | }); 19 | }]) 20 | .controller('EditOverrideCtrl', ['$scope', '$http', '$q', '$state', 'scriptID', 'scripts', 'data', 'activeTab', 'chrome', 'hotkeys', 21 | function ($scope, $http, $q, $state, scriptID, scripts, data, activeTab, chrome, hotkeys) { 22 | 23 | $scope.data = data; 24 | 25 | $scope.tabsMenu = [ 26 | { 27 | id: 'settings', 28 | icon: 'fa fa-wrench', 29 | title: 'Settings' 30 | }, 31 | { 32 | id: 'html', 33 | icon: 'fa fa-html5', 34 | title: 'HTML' 35 | }, 36 | { 37 | id: 'css', 38 | icon: 'fa fa-css3', 39 | title: 'CSS' 40 | }, 41 | { 42 | id: 'js', 43 | icon: 'fa fa-jsfiddle', 44 | title: 'Javascript' 45 | } 46 | ]; 47 | 48 | $scope.ac_options = { 49 | suggest: function (term) { 50 | return $q(function (resolve) { 51 | $http({ 52 | url: 'http://api.cdnjs.com/libraries', 53 | params: { 54 | fields: 'version', 55 | search: term 56 | } 57 | }).success(function (results) { 58 | results = results.results.map(function (result) { 59 | return { 60 | label: result.name + ' (' + result.version + ')', 61 | value: result.latest.replace('http://', 'https://') 62 | } 63 | }); 64 | resolve(results.reverse()); 65 | }); 66 | }); 67 | }, 68 | on_select: function (selected_item) { 69 | if (!$scope.data.libs) { 70 | $scope.data.libs = []; 71 | } 72 | $scope.data.libs.push(selected_item); 73 | document.getElementsByClassName('mass-ac-input')[0].value = null; 74 | $scope.form.$setDirty(); 75 | } 76 | }; 77 | 78 | function init() { 79 | hotkeys.bindTo($scope) 80 | .add({ 81 | combo: 'ctrl+s', 82 | callback: $scope.submitHandler 83 | }); 84 | } 85 | 86 | /** 87 | * 88 | */ 89 | $scope.resetURL = function () { 90 | $scope.data.urlQueries = [activeTab && activeTab.url]; 91 | }; 92 | 93 | /** 94 | * 95 | */ 96 | $scope.submitHandler = function () { 97 | $scope.saving = true; 98 | 99 | scripts.set(scriptID, $scope.data).then(function () { 100 | chrome.messageTabs({ 101 | request: "overrideUpdated", 102 | urlQueries: $scope.data.urlQueries 103 | }); 104 | 105 | // Reset the save button 106 | $scope.form.$setPristine(); 107 | $scope.saving = false; 108 | }); 109 | }; 110 | 111 | /** 112 | * 113 | */ 114 | $scope.removeOverride = function () { 115 | if (confirm('Are you sure you want to remove this override?')) { 116 | scripts.remove(scriptID).then(function () { 117 | $state.go('allOverrides'); 118 | }); 119 | } 120 | }; 121 | 122 | /** 123 | * 124 | * @param arr 125 | * @param index 126 | */ 127 | $scope.remove = function (arr, index) { 128 | arr.splice(index, 1); 129 | $scope.form.$setDirty(); 130 | }; 131 | 132 | init(); 133 | } 134 | ]); -------------------------------------------------------------------------------- /bin/app/js/views/ImportExport.js: -------------------------------------------------------------------------------- 1 | angular.module('app') 2 | .config(['$stateProvider', function ($stateProvider) { 3 | $stateProvider.state('importExport', { 4 | url: "/import-export", 5 | controller: 'ImportExportCtrl', 6 | templateUrl: "/app/partials/views/ImportExport.html" 7 | }); 8 | }]) 9 | .controller('ImportExportCtrl', ['$scope', '$state', 'scripts', 10 | function ($scope, $state, scripts) { 11 | 12 | $scope.exportScripts = function () { 13 | var filename = 'web_override_backup_(' + new Date().toISOString() + ').json'; 14 | scripts.getAll().then(function (overrides) { 15 | var contents = JSON.stringify(overrides || []); 16 | _.downloadFileFromText(filename, contents); 17 | }); 18 | }; 19 | 20 | $scope.onContent = function (content) { 21 | if (!content) { 22 | return alert('Invalid Backup file was provided.'); 23 | } 24 | 25 | var newOverrides = {}; 26 | _.map(content, function (override, id) { 27 | if (!_.isUUID(id)) return; 28 | if (!override.title) return; 29 | newOverrides[id] = { 30 | title: override.title, 31 | urlQueries: override.urlQueries || [], 32 | active: override.active || true, 33 | libs: override.libs || [], 34 | jsContent: override.jsContent || '', 35 | cssContent: override.cssContent || '', 36 | htmlContent: override.htmlContent || '' 37 | } 38 | }); 39 | 40 | if (_.size(newOverrides) === 0) return alert('Backup file has no valid overrides in it'); 41 | 42 | scripts.getAll().then(function (overrides) { 43 | // Skip user verification if there are no scripts 44 | if (_.size(overrides) > 0) { 45 | var existingOverrides = _.compact(_.map(newOverrides, function (a, id) { 46 | return _.result(overrides[id], 'title'); 47 | })); 48 | 49 | // Notify the user about existing scripts that will be replaced 50 | if (existingOverrides.length > 0) { 51 | var message = ['The following scripts will be overridden:', existingOverrides.join('\n'), 'continue?'].join('\n\n'); 52 | if (!confirm(message)) return; 53 | } 54 | } 55 | 56 | // Import the scripts 57 | _.each(newOverrides, function (override, id) { 58 | scripts.set(id, override); 59 | }); 60 | 61 | // Go back to the main view 62 | $state.go('allOverrides'); 63 | }); 64 | }; 65 | } 66 | ]); -------------------------------------------------------------------------------- /bin/app/partials/views/About.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |

About

5 |
6 |
7 |

Web Override v{{::version}}

8 | 9 |

10 | Visit us at WebOverride.com 11 |

12 | 13 |

14 | Created by Daniel Cohen 15 |

16 | 17 |

© {{::year}}, All rights reserved.

18 | 19 |

 

20 | 21 |

Settings

22 | 23 |
24 | 25 | 28 |
29 |
-------------------------------------------------------------------------------- /bin/app/partials/views/AddOverride.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 |

Add Override

6 |
7 | 8 |
9 |
10 | 11 | 12 |
13 | 14 |
15 | 21 | 22 |
23 | 25 | 29 |
30 | 33 |
34 | 35 | 39 |
40 |
-------------------------------------------------------------------------------- /bin/app/partials/views/AllOverrides.html: -------------------------------------------------------------------------------- 1 |
2 |

My Overrides

3 | 4 | 5 | 6 |
7 |
8 |

Seems like you still have no overrides

9 | Create your first override 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 31 | 32 | 33 | 36 | 37 | 38 |
TitleLast updateActive 
{{::script.title}}{{::script.updatedAt | date:'short'}} 27 | 28 | 29 | 30 |
34 | Add a new override 35 |
-------------------------------------------------------------------------------- /bin/app/partials/views/EditOverride.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 |

Edit Override

6 | 7 | 11 |
12 |
13 | 14 | 24 | 25 |
26 |
27 | 28 | 29 |
30 | 31 |
32 | 38 | 39 |
40 | 43 | 46 |
47 | 50 |
51 | 52 |
53 | 54 | 55 |
56 | 57 |
58 |
59 |

Libraries

60 | 61 |
62 | 66 |
67 |
68 | 69 |
70 |
{{lib.label}}
71 | 72 |
73 |
74 |
75 | 76 |
77 |
81 |
82 |
83 | 84 |
85 |
89 |
90 |
91 | 92 |
93 |
97 |
98 |
99 |
-------------------------------------------------------------------------------- /bin/app/partials/views/ImportExport.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |

Import / Export

5 |
6 |
7 |

Export Scripts

8 | 9 | Export 10 | 11 | 12 |

Import Scripts

13 | 14 |
15 | 16 |
17 |
-------------------------------------------------------------------------------- /bin/background/background.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Daniel Cohen 3 | * @date 6/1/2015 4 | */ 5 | var win; 6 | 7 | // Listen for clicks on the extension button 8 | chrome.browserAction.onClicked.addListener(function () { 9 | 10 | // Focus the window if there is one already open in the background 11 | if (win) { 12 | // Window still exists, just focus. 13 | chrome.windows.update(win.id, { 14 | focused: true 15 | }, function (_win) { 16 | 17 | }); 18 | return; 19 | } 20 | 21 | // Create a popup window of the app 22 | chrome.windows.create({ 23 | url: 'app/app.html', 24 | left: 10, 25 | top: 10, 26 | width: 800, 27 | height: 600, 28 | focused: true, 29 | type: 'popup' 30 | }, function (_win) { 31 | win = _win; 32 | }); 33 | }); 34 | 35 | // Listen for closing windows and reset the win object when the app is closed 36 | chrome.windows.onRemoved.addListener(function (windowId) { 37 | if (win && win.id === windowId) { 38 | win = null; 39 | } 40 | }); -------------------------------------------------------------------------------- /bin/content_script/content_script.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Get all the scripts and activate the relevant ones 3 | */ 4 | chrome.storage.sync.get(function (overrides) { 5 | // Filter out inactive and irrelevant overrides 6 | var relevantOverrides = []; 7 | for (var id in overrides) { 8 | if (overrides.hasOwnProperty(id) && overrides[id].active) { 9 | var query = overrides[id].urlQueries.filter(function (urlQuery) { 10 | return new RegExp(urlQuery).test(window.location.href); 11 | }); 12 | if (query.length > 0) { 13 | relevantOverrides.push(overrides[id]); 14 | } 15 | } 16 | } 17 | 18 | // Activate all relevant overrides 19 | relevantOverrides.forEach(function (override) { 20 | if (override.htmlContent) { 21 | document.body.innerHTML += override.htmlContent; 22 | } 23 | if (override.cssContent) { 24 | document.head.innerHTML += ''; 25 | } 26 | if (override.libs) { 27 | override.libs.forEach(function (lib) { 28 | var s = document.createElement("script"); 29 | s.type = "text/javascript"; 30 | s.src = lib.value; 31 | document.head.appendChild(s); 32 | }); 33 | } 34 | if (override.jsContent) { 35 | var s = document.createElement("script"); 36 | s.type = "text/javascript"; 37 | s.text = override.jsContent; 38 | document.head.appendChild(s); 39 | } 40 | }); 41 | }); 42 | 43 | /** 44 | * Listen for updates in overrides and reload the page if the updated override is relevant 45 | */ 46 | chrome.runtime.onMessage.addListener(function (message) { 47 | if (message.request == 'overrideUpdated' && message.urlQueries) { 48 | // Check if any of the overrides urls pass the regexp test 49 | var overrideRelevant = message.urlQueries.filter(function (urlQuery) { 50 | return new RegExp(urlQuery).test(window.location.href); 51 | }); 52 | 53 | if (overrideRelevant.length > 0) { 54 | window.location.reload(); 55 | } 56 | } 57 | }); -------------------------------------------------------------------------------- /bin/icon/1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcohenb/WebOverride/feb6ec796fc2a45e59481f6efc0750cb0d4e2833/bin/icon/1024.png -------------------------------------------------------------------------------- /bin/icon/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcohenb/WebOverride/feb6ec796fc2a45e59481f6efc0750cb0d4e2833/bin/icon/128.png -------------------------------------------------------------------------------- /bin/icon/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcohenb/WebOverride/feb6ec796fc2a45e59481f6efc0750cb0d4e2833/bin/icon/16.png -------------------------------------------------------------------------------- /bin/icon/256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcohenb/WebOverride/feb6ec796fc2a45e59481f6efc0750cb0d4e2833/bin/icon/256.png -------------------------------------------------------------------------------- /bin/icon/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcohenb/WebOverride/feb6ec796fc2a45e59481f6efc0750cb0d4e2833/bin/icon/32.png -------------------------------------------------------------------------------- /bin/icon/48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcohenb/WebOverride/feb6ec796fc2a45e59481f6efc0750cb0d4e2833/bin/icon/48.png -------------------------------------------------------------------------------- /bin/icon/512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcohenb/WebOverride/feb6ec796fc2a45e59481f6efc0750cb0d4e2833/bin/icon/512.png -------------------------------------------------------------------------------- /bin/icon/64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcohenb/WebOverride/feb6ec796fc2a45e59481f6efc0750cb0d4e2833/bin/icon/64.png -------------------------------------------------------------------------------- /bin/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Web Override", 3 | "short_name": "webo", 4 | "description": "Override websites with your own code snippets", 5 | "version": "1.0.1", 6 | "homepage_url": "http://weboverride.com", 7 | "permissions": [ 8 | "storage", 9 | "tabs", 10 | "http://*/*", 11 | "https://*/*" 12 | ], 13 | "optional_permissions": [ 14 | "notifications" 15 | ], 16 | "icons": { 17 | "16": "icon/16.png", 18 | "48": "icon/48.png", 19 | "128": "icon/128.png" 20 | }, 21 | "browser_action": { 22 | "default_title": "See my overrides", 23 | "default_icon": "icon/64.png" 24 | }, 25 | "background": { 26 | "scripts": [ 27 | "background/background.js" 28 | ] 29 | }, 30 | "content_scripts": [ 31 | { 32 | "run_at": "document_end", 33 | "matches": [ 34 | "http://*/*", 35 | "https://*/*" 36 | ], 37 | "js": [ 38 | "content_script/content_script.js" 39 | ] 40 | } 41 | ], 42 | "manifest_version": 2, 43 | "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'" 44 | } -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web-override", 3 | "version": "1.0.1", 4 | "authors": [ 5 | "Daniel Cohen " 6 | ], 7 | "license": "MIT", 8 | "ignore": [ 9 | "**/.*", 10 | "node_modules", 11 | "bower_components", 12 | "test", 13 | "tests" 14 | ], 15 | "dependencies": { 16 | "lodash": "~3.6.0", 17 | "font-awesome": "~4.3.0", 18 | "angular-ui-router": "~0.2.14", 19 | "angular-ui-ace": "~0.2.3", 20 | "angular-hotkeys": "chieffancypants/angular-hotkeys#~1.4.5", 21 | "angular-mass-autocomplete": "~0.2.3", 22 | "angular-sanitize": "~1.3.15" 23 | } 24 | } 25 | --------------------------------------------------------------------------------