├── .github └── FUNDING.yml ├── .idea ├── HTTP-Header-Spy.iml ├── misc.xml ├── modules.xml └── vcs.xml ├── LICENSE ├── Readme.md ├── Resources ├── CSS │ ├── common.css │ ├── content.css │ ├── contentDark.css │ ├── contentLight.css │ ├── extensions.css │ ├── options.css │ └── popup.css ├── HTML │ ├── about.html │ ├── options.html │ ├── plans.html │ ├── popup.html │ └── thanks.html ├── Icons │ ├── cog.svg │ ├── eye.png │ ├── eye.svg │ ├── icon128.png │ ├── icon16.png │ ├── icon48.png │ ├── toolbarIcon19.png │ └── toolbarIcon38.png ├── Images │ ├── Options.png │ ├── Prevew.jpg │ ├── btn_donate_SM.gif │ └── michiel.png ├── JavaScript │ ├── Google │ │ └── buy.js │ ├── Mark │ │ └── mark.es6.min.js │ ├── background.js │ ├── content.js │ ├── i18n.js │ ├── library.js │ ├── options.js │ ├── optionsContextProvider.js │ ├── popup.js │ └── store.js └── Templates │ ├── messages.json │ └── strings.txt ├── _locales ├── en │ └── messages.json ├── es │ └── messages.json ├── hi │ └── messages.json ├── nl │ └── messages.json ├── ru │ └── messages.json └── zh_CN │ └── messages.json └── manifest.json /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | patreon: michielroos 2 | -------------------------------------------------------------------------------- /.idea/HTTP-Header-Spy.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # HTTP Header Spy Webextension 2 | HTTP Header Spy enables you to inspect request- response headers and cookies right after page load with no extra clicks. 3 | 4 | Inspect HTTP headers and response times without opening the page inspector tool. View headers right in the page you are looking at. 5 | 6 | - Auto-hide information panels after specified time 7 | - Response times 8 | - Server IP 9 | - XHR and sub-frame requests 10 | - Headers also available in the browser action popup 11 | - Follow the full redirect path 12 | - Show HSTS requests 13 | - Colorful status indication icons 14 | - Inspect Form Data, Get parameters and Cookies 15 | - Micro mode shows just the chosen response headers 16 | - Position in one of the four corners of the window 17 | - Easy single-click highlighting of the headers 18 | - Choose between a light and a dark color-scheme 19 | - Filter headers to be shown 20 | - Highlight any string pattern in the header views 21 | 22 | ## Installation 23 | * Go to [the Google Chrome Web Store](https://chrome.google.com/webstore/detail/http-header-spy/agnoocojkneiphkobpcfoaenhpjnmifb) and click "Add to Chrome". 24 | 25 | ## Screenshots 26 | ![In page header information](Resources/Images/Prevew.jpg) 27 | ![Options page](Resources/Images/Options.png) 28 | 29 | ## How do I contribute? 30 | A: [Submit issues and ideas](https://github.com/Tuurlijk/HTTP-Header-Spy/issues) 31 | 32 | B: [Submit a pull request](https://help.github.com/articles/using-pull-requests) 33 | 34 | 1. Fork this repo and create a branch 35 | 2. Commit and push your changes to your branch 36 | 3. When you're happy send us a pull request! 37 | 38 | _**Pro-tip:** Make sure to build upon the latest version of the code and keep pull request as small as possible. This makes your pull request easy to merge._ 39 | 40 | ## Nice to have 41 | - Show total request counter on request type buttons 42 | - domain information 43 | - Popout detailed view from a microMode panel 44 | - Pause event stream on hover 45 | - It would be great if the popup would flash red or really obviously if it detects multiple redirects 46 | - Autofocus on filter input 47 | - font size adjustment 48 | -------------------------------------------------------------------------------- /Resources/CSS/contentDark.css: -------------------------------------------------------------------------------- 1 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ, 2 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ div, 3 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ label, 4 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ span, 5 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ p, 6 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .normalMode, 7 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .microMode, 8 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .value, 9 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .location, 10 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .sectionTitle, 11 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .button:hover, 12 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .closeButton:hover, 13 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .toolBar .requestTypes .type:hover, 14 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .toolBar .requestTypes .type.active, 15 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ tr:hover .key { 16 | transition: color 75ms; 17 | color: #ddd; 18 | border-color: #ddd; 19 | } 20 | 21 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .button, 22 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .closeButton, 23 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .key, 24 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .location:hover, 25 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .sectionTitle:hover, 26 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .downPointingTriangle:before, 27 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .rightPointingTriangle:before, 28 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .toolBar .requestTypes .type, 29 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .toolBar .requestTypes .type.active:hover, 30 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ tr:hover .value { 31 | transition: color 75ms; 32 | color: #bbb; 33 | border-color: #bbb; 34 | cursor: pointer; 35 | } 36 | 37 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .cookieTable:not(:first-child) { 38 | border-top: 1px dotted #777; 39 | } 40 | 41 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .separator { 42 | border-top: 1px solid #777; 43 | } 44 | 45 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .normalMode { 46 | background: rgba(20, 20, 20, 0.85); 47 | border: 1px solid #777; 48 | box-shadow: 0 1px 2px 1px rgba(0, 0, 0, 0.26); 49 | } 50 | 51 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .microMode { 52 | background: rgba(20, 20, 20, 0.85); 53 | border: 1px solid #777; 54 | } 55 | 56 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .toolBar .requestTypes .type, 57 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ #inlineFilterInput { 58 | border-color: #777; 59 | } 60 | 61 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ #toolBar { 62 | background: rgba(20, 20, 20, 0.85); 63 | } 64 | 65 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .toolBar .requestTypes .type.active { 66 | background: rgba(20, 20, 20, 0.85); 67 | } 68 | -------------------------------------------------------------------------------- /Resources/CSS/contentLight.css: -------------------------------------------------------------------------------- 1 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ, 2 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ div, 3 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ label, 4 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ span, 5 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ p, 6 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .normalMode, 7 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .microMode, 8 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .value, 9 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .location, 10 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .sectionTitle, 11 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .button:hover, 12 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .closeButton:hover, 13 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .toolBar .requestTypes .type:hover, 14 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .toolBar .requestTypes .type.active, 15 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ tr:hover .key { 16 | transition: color 75ms; 17 | color: rgb(50, 50, 50); 18 | border-color: rgb(50, 50, 50); 19 | } 20 | 21 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .button, 22 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .closeButton, 23 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .key, 24 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .location:hover, 25 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .sectionTitle:hover, 26 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .downPointingTriangle:before, 27 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .rightPointingTriangle:before, 28 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .toolBar .requestTypes .type, 29 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .toolBar .requestTypes .type.active:hover, 30 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ tr:hover .value { 31 | transition: color 75ms; 32 | color: rgb(130, 130, 130); 33 | border-color: rgb(130, 130, 130); 34 | cursor: pointer; 35 | } 36 | 37 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .cookieTable:not(:first-child) { 38 | border-top: 1px dotted #b3b3b3; 39 | } 40 | 41 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .separator { 42 | border-top: 1px solid #b3b3b3; 43 | } 44 | 45 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .normalMode { 46 | background: rgba(221, 221, 221, 0.95); 47 | border: 1px solid #b3b3b3; 48 | box-shadow: 0 1px 2px 1px rgba(0, 0, 0, 0.26); 49 | } 50 | 51 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .microMode { 52 | background: rgba(221, 221, 221, 0.95); 53 | border: 1px solid #b3b3b3; 54 | } 55 | 56 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .toolBar .requestTypes .type, 57 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ #inlineFilterInput { 58 | border-color: #b3b3b3; 59 | } 60 | 61 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ #toolBar { 62 | background: rgba(221, 221, 221, 0.95); 63 | } 64 | 65 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .toolBar .requestTypes .type.active { 66 | background: rgba(130, 130, 130, 0.3); 67 | } 68 | -------------------------------------------------------------------------------- /Resources/CSS/options.css: -------------------------------------------------------------------------------- 1 | html body.chromeOptionBody { 2 | min-width: 700px; 3 | padding: 1em; 4 | } 5 | 6 | html body.chromeOptionBody label.radio span { 7 | margin-left: 0.5em; 8 | } 9 | 10 | html.changing-content body { 11 | -webkit-transition: -webkit-transform 100ms; 12 | } 13 | 14 | ul { 15 | list-style-type: none; 16 | padding: 0; 17 | } 18 | 19 | li:hover { 20 | color: #777; 21 | } 22 | 23 | p .inlineicon { 24 | vertical-align: middle; 25 | } 26 | 27 | #navigation a.active { 28 | -webkit-border-start-color: rgb(78, 87, 100); 29 | cursor: default; 30 | } 31 | 32 | #helpNavItem { 33 | margin-top: 27px; 34 | } 35 | 36 | #navigation li { 37 | line-height: 17px; 38 | margin: 6px 0; 39 | padding-right: 1.5em; 40 | display: inline-block; 41 | } 42 | 43 | #navigation a { 44 | display: block; 45 | background-color: white; 46 | color: #999; 47 | cursor: pointer; 48 | font: inherit; 49 | line-height: 17px; 50 | padding: 6px 0; 51 | -webkit-border-start: 6px solid transparent; 52 | -webkit-padding-start: 18px; 53 | -webkit-user-select: none; 54 | cursor: pointer; 55 | } 56 | 57 | #navigation a { 58 | color: #999; 59 | text-decoration: none; 60 | } 61 | 62 | #navigation a.active, 63 | .active > button { 64 | color: rgb(70, 78, 90); 65 | } 66 | 67 | .aboutImage { 68 | background-color: rgba(221, 221, 221, 0.95); 69 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#888), to(#aaa)); 70 | background-image: -webkit-linear-gradient(#888, #aaa); 71 | background-image: linear-gradient(#888, #aaa), linear-gradient(#888, #aaa); 72 | background-size: 2px 100%; 73 | background-position: 0 0, 100% 0; 74 | background-repeat: no-repeat; 75 | border-top: 1px solid #888; 76 | box-shadow: 1px 4px 13px rgb(100, 100, 100); 77 | border-radius: 2px; 78 | } 79 | 80 | .aboutImage img { 81 | margin: 0 1px; 82 | } 83 | 84 | .aboutImage.right { 85 | float: right; 86 | clear: right; 87 | margin: 0 0 15px 15px; 88 | } 89 | 90 | .aboutImage.left { 91 | float: left; 92 | clear: left; 93 | margin: 15px 15px 0 0; 94 | } 95 | 96 | ul.features li:before { 97 | color: #00aa00; 98 | content: '\2714'; /* ✔ */ 99 | display: inline-block; 100 | font-size: 13px; 101 | width: 20px; 102 | } 103 | 104 | ul.features li { 105 | margin: 6px 0; 106 | } 107 | 108 | #elementBox { 109 | width: 95%; 110 | } 111 | 112 | label { 113 | cursor: default; 114 | margin-top: 1px; 115 | margin-bottom: 2px; 116 | margin-inline-start: 6px; 117 | margin-inline-end: 5px; 118 | } 119 | 120 | input[type="checkbox"] + label.radio { 121 | line-height: 1.5em; 122 | } 123 | 124 | label[disabled="true"] { 125 | color: GrayText; 126 | } 127 | 128 | select { 129 | min-width: 120px; 130 | -webkit-appearance: none; 131 | -webkit-padding-end: 24px; 132 | -webkit-padding-start: 10px; 133 | /* OVERRIDE */ 134 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAAICAQAAACxSAwfAAAAUklEQVQY02P4z0AMRGZGMaShwCisyhITmb8huMzfEhOxKvuvsGAh208Ik+3ngoX/FbBbClcIUcSAw21QhXxfIIrwKAMpfNsEUYRXGVCEFc6CQwBqq4CCCtU4VgAAAABJRU5ErkJggg==); 135 | background-image: -webkit-image-set(url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAAICAQAAACxSAwfAAAAUklEQVQY02P4z0AMRGZGMaShwCisyhITmb8huMzfEhOxKvuvsGAh208Ik+3ngoX/FbBbClcIUcSAw21QhXxfIIrwKAMpfNsEUYRXGVCEFc6CQwBqq4CCCtU4VgAAAABJRU5ErkJggg==) 1x, url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACcAAAAQCAQAAAA/1a6rAAAAQUlEQVR4Xu3MsQnAMBAEMI1+myf9gw0+3ASCenmu+mQn2yGn3S4Mp906DEW3CEPfzTD03QxD380w3OmIUHe9v+u9QwAt93yns5cAAAAASUVORK5CYII=) 2x), 136 | -webkit-linear-gradient(#ededed, #ededed 38%, #dedede); 137 | background-position: right center; 138 | background-repeat: no-repeat; 139 | border-radius: 2px; 140 | font-family: inherit; 141 | font-size: inherit; 142 | padding: 2px 20px 2px 5px; 143 | } 144 | 145 | :-webkit-any(button, input[type='button'], input[type='submit']):not(.custom-appearance), select { 146 | min-height: 29px; 147 | min-width: 4em; 148 | padding-bottom: 1px; 149 | } 150 | 151 | .inline-options select { 152 | min-height: 1em; 153 | } 154 | 155 | :-webkit-any(button, input[type='button'], input[type='submit']):not(.custom-appearance), select, input[type='checkbox'], input[type='radio'] { 156 | -webkit-appearance: none; 157 | -webkit-user-select: none; 158 | border: 1px solid rgba(0, 0, 0, 0.25); 159 | border-radius: 2px; 160 | box-shadow: 0 1px 0 rgba(0, 0, 0, 0.08), inset 0 1px 2px rgba(255, 255, 255, 0.75); 161 | color: #444; 162 | font: inherit; 163 | margin: 0 1px 0 0; 164 | outline: none; 165 | text-shadow: 0 1px 0 rgb(240, 240, 240); 166 | } 167 | 168 | .detail-row { 169 | padding: 10px 0; 170 | display: flex; 171 | } 172 | 173 | .option-description { 174 | float: left; 175 | width: 35%; 176 | display: inline-block; 177 | padding-right: 0.5em; 178 | } 179 | 180 | .option-value { 181 | flex: 1; 182 | } 183 | 184 | .manageSubscriptions { 185 | font-size: smaller; 186 | } 187 | 188 | .label-container { 189 | padding: 8px 0; 190 | } 191 | 192 | /*! AUI Label -> https://docs.atlassian.com/aui/latest/docs/labels.html */ 193 | .aui-label { 194 | background: #edf0ff; 195 | border: 1px solid #ccc; 196 | border-radius: 8px; 197 | display: inline-block; 198 | font-size: 14px; 199 | font-weight: 400; 200 | line-height: 1; 201 | padding: 1px 7px; 202 | margin: 0 8px 0 0; 203 | text-align: left; 204 | text-decoration: none; 205 | } 206 | 207 | .aui-label, a.aui-label { 208 | color: #3572b0; 209 | } 210 | 211 | span.aui-label { 212 | color: #484848; 213 | } 214 | 215 | .aui-label.aui-label-closeable.aui-label-split:hover, a.aui-label:active, a.aui-label:focus, a.aui-label:hover { 216 | border-color: #707070; 217 | text-decoration: none; 218 | } 219 | 220 | .aui-label-split .aui-label-split-main:active, .aui-label-split .aui-label-split-main:focus, .aui-label-split .aui-label-split-main:hover { 221 | text-decoration: none; 222 | } 223 | 224 | .aui-label.aui-label-closeable { 225 | padding-right: 18px; 226 | position: relative; 227 | margin-bottom: 0.5em; 228 | } 229 | 230 | .aui-label-closeable .aui-icon-close { 231 | cursor: pointer; 232 | display: block; 233 | float: right; 234 | height: 16px; 235 | position: absolute; 236 | right: 0px; 237 | top: 0px; 238 | width: 20px; 239 | background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAQAAABuBnYAAAAAKUlEQVQI12NgYFj0nwEKwKxF/9P+Q4TgLAgDIQEVQuJiCKBpwWoosrUAzbg31XT4p6QAAAAASUVORK5CYII=') no-repeat 6px 4px; 240 | } 241 | 242 | .aui-icon { 243 | background-repeat: no-repeat; 244 | background-position: 0 0; 245 | border: none; 246 | display: inline-block; 247 | height: 16px; 248 | margin: 0; 249 | padding: 0; 250 | text-align: left; 251 | text-indent: -999em; 252 | vertical-align: text-bottom; 253 | width: 16px; 254 | } 255 | 256 | mark, 257 | mark:hover { 258 | background-color: rgba(255, 238, 34, 0.9); 259 | padding: 0 2px; 260 | } 261 | 262 | .pro { 263 | display: inline; 264 | } 265 | 266 | .hidden { 267 | display: none; 268 | } 269 | 270 | .status { 271 | padding: 1em; 272 | border-radius: 0.5em; 273 | border: 1px solid; 274 | } 275 | 276 | .status.notice { 277 | color: #777; 278 | background-color: #f6f7fa; 279 | border-color: #c2cbcf; 280 | } 281 | 282 | .status.notice a { 283 | color: #777; 284 | } 285 | 286 | .status.information { 287 | color: #4c73a1; 288 | background-color: #eaf7ff; 289 | border-color: #c5dbe6; 290 | } 291 | 292 | .status.information a { 293 | color: #4c73a1; 294 | } 295 | 296 | .status.ok { 297 | color: #3b7826; 298 | background-color: #cdeaca; 299 | border-color: #58b548; 300 | } 301 | 302 | .status.ok a { 303 | color: #3b7826; 304 | } 305 | 306 | .status.warning { 307 | color: #9e7d4a; 308 | background-color: #fbf6de; 309 | border-color: #b1905c; 310 | } 311 | 312 | .status.warning a { 313 | color: #9e7d4a; 314 | } 315 | 316 | .status.error { 317 | color: #aa0225; 318 | background-color: #f6d3cf; 319 | border-color: #d66c68; 320 | } 321 | 322 | .status.error a { 323 | color: #aa0225; 324 | } 325 | 326 | .price { 327 | color: #777; 328 | font-size: smaller; 329 | } 330 | 331 | .button { 332 | background: #34d94d; 333 | background-image: -webkit-linear-gradient(top, #34d94d, #2bb834); 334 | background-image: -moz-linear-gradient(top, #34d94d, #2bb834); 335 | background-image: -ms-linear-gradient(top, #34d94d, #2bb834); 336 | background-image: -o-linear-gradient(top, #34d94d, #2bb834); 337 | background-image: linear-gradient(to bottom, #34d94d, #2bb834); 338 | border-radius: 4px; 339 | text-shadow: 1px 1px 5px #8f8f8f; 340 | color: #ffffff; 341 | padding: 4px 12px; 342 | text-decoration: none; 343 | display: inline-block; 344 | margin: 2px; 345 | cursor: pointer; 346 | } 347 | 348 | .button:hover { 349 | background: #82e885; 350 | background-image: -webkit-linear-gradient(top, #82e885, #4fd934); 351 | background-image: -moz-linear-gradient(top, #82e885, #4fd934); 352 | background-image: -ms-linear-gradient(top, #82e885, #4fd934); 353 | background-image: -o-linear-gradient(top, #82e885, #4fd934); 354 | background-image: linear-gradient(to bottom, #82e885, #4fd934); 355 | color: #ffffff; 356 | text-decoration: none; 357 | } 358 | 359 | .currentPlan { 360 | background: #3498db; 361 | background-image: -webkit-linear-gradient(top, #3498db, #2980b9); 362 | background-image: -moz-linear-gradient(top, #3498db, #2980b9); 363 | background-image: -ms-linear-gradient(top, #3498db, #2980b9); 364 | background-image: -o-linear-gradient(top, #3498db, #2980b9); 365 | background-image: linear-gradient(to bottom, #3498db, #2980b9); 366 | border-radius: 4px; 367 | color: #ffffff; 368 | padding: 4px 12px; 369 | text-decoration: none; 370 | display: inline-block; 371 | margin: 2px; 372 | pointer-events: none; 373 | } 374 | 375 | .currentPlan:hover { 376 | background: #3cb0fd; 377 | background-image: -webkit-linear-gradient(top, #3cb0fd, #3498db); 378 | background-image: -moz-linear-gradient(top, #3cb0fd, #3498db); 379 | background-image: -ms-linear-gradient(top, #3cb0fd, #3498db); 380 | background-image: -o-linear-gradient(top, #3cb0fd, #3498db); 381 | background-image: linear-gradient(to bottom, #3cb0fd, #3498db); 382 | color: #ffffff; 383 | text-decoration: none; 384 | } 385 | 386 | ul.checkmark { 387 | list-style-type: none; 388 | } 389 | 390 | ul.checkmark li:before { 391 | content: "\2713\0020"; 392 | color: #008700; 393 | font-weight: bold; 394 | font-family: 'Lucida Sans Unicode', 'Arial Unicode MS', Arial, sans-serif; 395 | } -------------------------------------------------------------------------------- /Resources/CSS/popup.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: rgb(100, 100, 100); 3 | font-family: 'Lucida Grande', 'Helvetica Neue', Helvetica, Arial, sans-serif; 4 | font-size: 11px; 5 | line-height: 13px; 6 | min-width: 200px; 7 | margin: 0; 8 | } 9 | 10 | /* 11 | * Remove blue outline that Chrome makes when autoselecting the first link 12 | */ 13 | *:focus { 14 | outline: none; 15 | } 16 | 17 | /* 18 | * Shadows are visible under slightly transparent text color 19 | */ 20 | h1 { 21 | font-size: 12px; 22 | font-weight: bold; 23 | margin: 4px 8px; 24 | text-shadow: 1px 1px 1px white, 0 0 0 black, 1px 1px 1px white; 25 | white-space: nowrap; 26 | line-height: 23px; 27 | } 28 | 29 | nav { 30 | display: flex; 31 | } 32 | 33 | .separator { 34 | border-top: 1px solid #b3b3b3; 35 | margin: 4px 0; 36 | } 37 | 38 | .menu { 39 | flex: 1; 40 | vertical-align: middle; 41 | text-align: right; 42 | padding: 8px 8px 0 0; 43 | } 44 | 45 | .title { 46 | width: auto; 47 | } 48 | 49 | .donateButton { 50 | position: absolute; 51 | top: 4px; 52 | left: 4px; 53 | } 54 | 55 | #settings { 56 | text-align: left; 57 | box-sizing: border-box; 58 | position: absolute; 59 | top: 0; 60 | left: 0; 61 | width: 100%; 62 | border: 1px solid #b3b3b3; 63 | border-top: 0; 64 | background-color: white; 65 | margin: 0; 66 | padding: 0.5em; 67 | z-index: 1; 68 | border-radius: 0 0 4px 4px; 69 | box-shadow: 0 1px 2px 1px rgba(0, 0, 0, 0.26); 70 | } 71 | 72 | #settings h2 { 73 | font-size: 12px; 74 | font-weight: bold; 75 | margin: 0 0 4px 0; 76 | text-shadow: 1px 1px 1px white, 0 0 0 black, 1px 1px 1px white; 77 | white-space: nowrap; 78 | line-height: 23px; 79 | } 80 | 81 | #settings .closeButton { 82 | cursor: pointer; 83 | position: absolute; 84 | top: 4px; 85 | right: 8px; 86 | font-size: 13px !important; 87 | text-align: right; 88 | width: 25px; 89 | height: 25px; 90 | } 91 | 92 | .hidden { 93 | display: none; 94 | } 95 | 96 | .visible { 97 | transition: opacity 0.4s cubic-bezier(0.22, 0.61, 0.36, 1); 98 | height: auto; 99 | opacity: 1; 100 | position: relative; 101 | z-index: 1; 102 | visibility: visible; 103 | overflow: inherit; 104 | } 105 | 106 | #result { 107 | min-width: 550px; 108 | } 109 | 110 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .defaultMessage:hover, 111 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .defaultMessage { 112 | text-align: center; 113 | padding: 1em; 114 | } 115 | 116 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .optionsButtonInDefaultMessage { 117 | text-align: center; 118 | } 119 | 120 | #settingsIcon { 121 | z-index: 2; 122 | width: 16px; 123 | height: 16px; 124 | cursor: pointer; 125 | } 126 | 127 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .normalMode.visible { 128 | background: transparent; 129 | animation: none; 130 | } 131 | 132 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ #toolBar { 133 | border-left: 0; 134 | border-bottom: 0; 135 | border-right: 0; 136 | box-shadow: none; 137 | background-color: white; 138 | position: fixed; 139 | bottom: 0; 140 | z-index: 1; 141 | width: 100%; 142 | padding: 4px; 143 | } 144 | 145 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .toolBar { 146 | } 147 | 148 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .thankYou { 149 | color: #cc0000; 150 | padding-right: 0.5rem; 151 | padding-top: 2px; 152 | cursor: pointer; 153 | text-decoration: none; 154 | } 155 | 156 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ { 157 | position: relative; 158 | z-index: 0; 159 | padding-bottom: 30px; 160 | } 161 | 162 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .normalMode { 163 | background: transparent; 164 | border: none; 165 | box-shadow: none; 166 | margin-top: 0; 167 | } 168 | 169 | #httpSpyContainer_sq27T8VFex4CtQ623afyMoiYA89kG6UZ .normalMode:not(:first-child) { 170 | border-top: 1px solid #b3b3b3; 171 | } 172 | -------------------------------------------------------------------------------- /Resources/HTML/about.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 22 |
23 |
24 |
25 | Michiel 26 |
27 |

My name is Michiel Roos. I had a lot of fun developing this add-on. I also learnt a lot. I hope you find it usefull and enjoy using it. If you have any suggetstions or constructive criticism, please contact me.

28 |

Do you enjoy this extension? Please consider a donation:

29 |

Say Thanks ;-)

30 |
31 |
32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Resources/HTML/options.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 20 |
21 |
22 |
23 |
24 | Display Options 25 |

Press the ESC key to hide panels.

26 |

When auto-hide is enabled, the filter bar will not be shown.

27 |
28 |
29 | 30 | 35 | 36 | 42 | 43 | 47 | 71 |
72 | 76 | 77 | 88 | seconds 89 |
90 |
91 |
92 |
93 |
94 | 95 |

Request headers (or patterns thereof) that will not be displayed.

96 |
97 |
98 | 99 | 100 |
101 |
102 |
103 |
104 |
105 | 106 |

Response headers (or patterns thereof) that will not be displayed.

107 |
108 |
109 | 110 | 111 |
112 |
113 |
114 |
115 |
116 | 117 |

Response headers (or patterns thereof) that will be shown in micro mode.

118 |
119 |
120 | 121 | 122 |
123 |
124 |
125 |
126 |
127 | 128 |

Headers (or patterns thereof) that will be highlighted.

129 |
130 |
131 | 132 | 133 |
134 |
135 |
136 |
137 |
138 | 139 | 140 | 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /Resources/HTML/plans.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 22 |
23 |
24 |

Get the pro version

25 |
26 |

You can test all these great features every first 15 minutes of every hour:

27 | 34 |

If you want to enable these features permanently, please support further development by donating me some beer/pizza:

35 |

One-time beer support

36 | 37 |
38 |

One-time pizza support

39 | 40 |
41 |

Subscriptions

42 | 43 |
44 |

Manage subscription

45 |
46 |
47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /Resources/HTML/popup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 88 |
89 |
90 |
91 |
92 |
93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /Resources/HTML/thanks.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 22 |
23 |
24 |

Say Thanks ;-)

25 |

Do you enjoy this extension? Please consider a donation:

26 | 30 |

Thank you!

31 |

Manage subscription

32 |
33 |
34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Resources/Icons/cog.svg: -------------------------------------------------------------------------------- 1 | 2 | 15 | 17 | 18 | 20 | image/svg+xml 21 | 23 | 24 | 25 | 26 | 28 | 48 | 52 | 53 | -------------------------------------------------------------------------------- /Resources/Icons/eye.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tuurlijk/HTTP-Header-Spy/8b2cd9fb05965ae01bdcad12c09c7464d9989d58/Resources/Icons/eye.png -------------------------------------------------------------------------------- /Resources/Icons/eye.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Resources/Icons/icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tuurlijk/HTTP-Header-Spy/8b2cd9fb05965ae01bdcad12c09c7464d9989d58/Resources/Icons/icon128.png -------------------------------------------------------------------------------- /Resources/Icons/icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tuurlijk/HTTP-Header-Spy/8b2cd9fb05965ae01bdcad12c09c7464d9989d58/Resources/Icons/icon16.png -------------------------------------------------------------------------------- /Resources/Icons/icon48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tuurlijk/HTTP-Header-Spy/8b2cd9fb05965ae01bdcad12c09c7464d9989d58/Resources/Icons/icon48.png -------------------------------------------------------------------------------- /Resources/Icons/toolbarIcon19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tuurlijk/HTTP-Header-Spy/8b2cd9fb05965ae01bdcad12c09c7464d9989d58/Resources/Icons/toolbarIcon19.png -------------------------------------------------------------------------------- /Resources/Icons/toolbarIcon38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tuurlijk/HTTP-Header-Spy/8b2cd9fb05965ae01bdcad12c09c7464d9989d58/Resources/Icons/toolbarIcon38.png -------------------------------------------------------------------------------- /Resources/Images/Options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tuurlijk/HTTP-Header-Spy/8b2cd9fb05965ae01bdcad12c09c7464d9989d58/Resources/Images/Options.png -------------------------------------------------------------------------------- /Resources/Images/Prevew.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tuurlijk/HTTP-Header-Spy/8b2cd9fb05965ae01bdcad12c09c7464d9989d58/Resources/Images/Prevew.jpg -------------------------------------------------------------------------------- /Resources/Images/btn_donate_SM.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tuurlijk/HTTP-Header-Spy/8b2cd9fb05965ae01bdcad12c09c7464d9989d58/Resources/Images/btn_donate_SM.gif -------------------------------------------------------------------------------- /Resources/Images/michiel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tuurlijk/HTTP-Header-Spy/8b2cd9fb05965ae01bdcad12c09c7464d9989d58/Resources/Images/michiel.png -------------------------------------------------------------------------------- /Resources/JavaScript/Google/buy.js: -------------------------------------------------------------------------------- 1 | (function() { var f=this,g=function(a,d){var c=a.split("."),b=window||f;c[0]in b||!b.execScript||b.execScript("var "+c[0]);for(var e;c.length&&(e=c.shift());)c.length||void 0===d?b=b[e]?b[e]:b[e]={}:b[e]=d};var h=function(a){var d=chrome.runtime.connect("nmmhkkegccagdldgiimedpiccmgmieda",{}),c=!1;d.onMessage.addListener(function(b){c=!0;"response"in b&&!("errorType"in b.response)?a.success&&a.success(b):a.failure&&a.failure(b)});d.onDisconnect.addListener(function(){!c&&a.failure&&a.failure({request:{},response:{errorType:"INTERNAL_SERVER_ERROR"}})});d.postMessage(a)};g("google.payments.inapp.buy",function(a){a.method="buy";h(a)}); 2 | g("google.payments.inapp.consumePurchase",function(a){a.method="consumePurchase";h(a)});g("google.payments.inapp.getPurchases",function(a){a.method="getPurchases";h(a)});g("google.payments.inapp.getSkuDetails",function(a){a.method="getSkuDetails";h(a)}); })(); -------------------------------------------------------------------------------- /Resources/JavaScript/Mark/mark.es6.min.js: -------------------------------------------------------------------------------- 1 | /*!*************************************************** 2 | * mark.js v8.6.0 3 | * https://github.com/julmot/mark.js 4 | * Copyright (c) 2014–2017, Julian Motz 5 | * Released under the MIT license https://git.io/vwTVl 6 | *****************************************************/ 7 | "use strict";((factory,window,document)=>{if(typeof define==="function"&&define.amd){define([],()=>{return factory(window,document);});}else if(typeof module==="object"&&module.exports){module.exports=factory(window,document);}else{factory(window,document);}})((window,document)=>{class Mark{constructor(ctx){this.ctx=ctx;this.ie=false;const ua=window.navigator.userAgent;if(ua.indexOf("MSIE")>-1||ua.indexOf("Trident")>-1){this.ie=true;}}set opt(val){this._opt=Object.assign({},{"element":"","className":"","exclude":[],"iframes":false,"separateWordSearch":true,"diacritics":true,"synonyms":{},"accuracy":"partially","acrossElements":false,"caseSensitive":false,"ignoreJoiners":false,"ignoreGroups":0,"each":()=>{},"noMatch":()=>{},"filter":()=>true,"done":()=>{},"debug":false,"log":window.console},val);}get opt(){return this._opt;}get iterator(){if(!this._iterator){this._iterator=new DOMIterator(this.ctx,this.opt.iframes,this.opt.exclude);}return this._iterator;}log(msg,level="debug"){const log=this.opt.log;if(!this.opt.debug){return;}if(typeof log==="object"&&typeof log[level]==="function"){log[level](`mark.js: ${msg}`);}}escapeStr(str){return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&");}createRegExp(str){str=this.escapeStr(str);if(Object.keys(this.opt.synonyms).length){str=this.createSynonymsRegExp(str);}if(this.opt.ignoreJoiners){str=this.setupIgnoreJoinersRegExp(str);}if(this.opt.diacritics){str=this.createDiacriticsRegExp(str);}str=this.createMergedBlanksRegExp(str);if(this.opt.ignoreJoiners){str=this.createIgnoreJoinersRegExp(str);}str=this.createAccuracyRegExp(str);return str;}createSynonymsRegExp(str){const syn=this.opt.synonyms,sens=this.opt.caseSensitive?"":"i";for(let index in syn){if(syn.hasOwnProperty(index)){const value=syn[index],k1=this.escapeStr(index),k2=this.escapeStr(value);str=str.replace(new RegExp(`(${k1}|${k2})`,`gm${sens}`),`(${k1}|${k2})`);}}return str;}setupIgnoreJoinersRegExp(str){return str.replace(/[^(|)\\]/g,(val,indx,original)=>{let nextChar=original.charAt(indx+1);if(/[(|)\\]/.test(nextChar)||nextChar===""){return val;}else{return val+"\u0000";}});}createIgnoreJoinersRegExp(str){return str.split("\u0000").join("[\\u00ad|\\u200b|\\u200c|\\u200d]?");}createDiacriticsRegExp(str){const sens=this.opt.caseSensitive?"":"i",dct=this.opt.caseSensitive?["aàáâãäåāąă","AÀÁÂÃÄÅĀĄĂ","cçćč","CÇĆČ","dđď","DĐĎ","eèéêëěēę","EÈÉÊËĚĒĘ","iìíîïī","IÌÍÎÏĪ","lł","LŁ","nñňń","NÑŇŃ","oòóôõöøō","OÒÓÔÕÖØŌ","rř","RŘ","sšśș","SŠŚȘ","tťț","TŤȚ","uùúûüůū","UÙÚÛÜŮŪ","yÿý","YŸÝ","zžżź","ZŽŻŹ"]:["aÀÁÂÃÄÅàáâãäåĀāąĄăĂ","cÇçćĆčČ","dđĐďĎ","eÈÉÊËèéêëěĚĒēęĘ","iÌÍÎÏìíîïĪī","lłŁ","nÑñňŇńŃ","oÒÓÔÕÖØòóôõöøŌō","rřŘ","sŠšśŚșȘ","tťŤțȚ","uÙÚÛÜùúûüůŮŪū","yŸÿýÝ","zŽžżŻźŹ"];let handled=[];str.split("").forEach(ch=>{dct.every(dct=>{if(dct.indexOf(ch)!==-1){if(handled.indexOf(dct)>-1){return false;}str=str.replace(new RegExp(`[${dct}]`,`gm${sens}`),`[${dct}]`);handled.push(dct);}return true;});});return str;}createMergedBlanksRegExp(str){return str.replace(/[\s]+/gmi,"[\\s]+");}createAccuracyRegExp(str){let acc=this.opt.accuracy,val=typeof acc==="string"?acc:acc.value,ls=typeof acc==="string"?[]:acc.limiters,lsJoin="";ls.forEach(limiter=>{lsJoin+=`|${this.escapeStr(limiter)}`;});switch(val){case"partially":default:return`()(${str})`;case"complementary":return`()([^\\s${lsJoin}]*${str}[^\\s${lsJoin}]*)`;case"exactly":return`(^|\\s${lsJoin})(${str})(?=$|\\s${lsJoin})`;}}getSeparatedKeywords(sv){let stack=[];sv.forEach(kw=>{if(!this.opt.separateWordSearch){if(kw.trim()&&stack.indexOf(kw)===-1){stack.push(kw);}}else{kw.split(" ").forEach(kwSplitted=>{if(kwSplitted.trim()&&stack.indexOf(kwSplitted)===-1){stack.push(kwSplitted);}});}});return{"keywords":stack.sort((a,b)=>{return b.length-a.length;}),"length":stack.length};}getTextNodes(cb){let val="",nodes=[];this.iterator.forEachNode(NodeFilter.SHOW_TEXT,node=>{nodes.push({start:val.length,end:(val+=node.textContent).length,node});},node=>{if(this.matchesExclude(node.parentNode,true)){return NodeFilter.FILTER_REJECT;}else{return NodeFilter.FILTER_ACCEPT;}},()=>{cb({value:val,nodes:nodes});});}matchesExclude(el,exclM){let excl=this.opt.exclude.concat(["script","style","title","head","html"]);if(exclM){excl=excl.concat(["*[data-markjs='true']"]);}return DOMIterator.matches(el,excl);}wrapRangeInTextNode(node,start,end){const hEl=!this.opt.element?"mark":this.opt.element,startNode=node.splitText(start),ret=startNode.splitText(end-start);let repl=document.createElement(hEl);repl.setAttribute("data-markjs","true");if(this.opt.className){repl.setAttribute("class",this.opt.className);}repl.textContent=startNode.textContent;startNode.parentNode.replaceChild(repl,startNode);return ret;}wrapRangeInMappedTextNode(dict,start,end,filterCb,eachCb){dict.nodes.every((n,i)=>{const sibl=dict.nodes[i+1];if(typeof sibl==="undefined"||sibl.start>start){const s=start-n.start,e=(end>n.end?n.end:end)-n.start;if(filterCb(n.node)){n.node=this.wrapRangeInTextNode(n.node,s,e);const startStr=dict.value.substr(0,n.start),endStr=dict.value.substr(e+n.start);dict.value=startStr+endStr;dict.nodes.forEach((k,j)=>{if(j>=i){if(dict.nodes[j].start>0&&j!==i){dict.nodes[j].start-=e;}dict.nodes[j].end-=e;}});end-=e;eachCb(n.node.previousSibling,n.start);if(end>n.end){start=n.end;}else{return false;}}}return true;});}wrapMatches(regex,ignoreGroups,filterCb,eachCb,endCb){const matchIdx=ignoreGroups===0?0:ignoreGroups+1;this.getTextNodes(dict=>{dict.nodes.forEach(node=>{node=node.node;let match;while((match=regex.exec(node.textContent))!==null&&match[matchIdx]!==""){if(!filterCb(match[matchIdx],node)){continue;}let pos=match.index;if(matchIdx!==0){for(let i=1;i{let match;while((match=regex.exec(dict.value))!==null&&match[matchIdx]!==""){let start=match.index;if(matchIdx!==0){for(let i=1;i{return filterCb(match[matchIdx],node);},(node,lastIndex)=>{regex.lastIndex=lastIndex;eachCb(node);});}endCb();});}unwrapMatches(node){const parent=node.parentNode;let docFrag=document.createDocumentFragment();while(node.firstChild){docFrag.appendChild(node.removeChild(node.firstChild));}parent.replaceChild(docFrag,node);if(!this.ie){parent.normalize();}else{this.normalizeTextNode(parent);}}normalizeTextNode(node){if(!node){return;}if(node.nodeType===3){while(node.nextSibling&&node.nextSibling.nodeType===3){node.nodeValue+=node.nextSibling.nodeValue;node.parentNode.removeChild(node.nextSibling);}}else{this.normalizeTextNode(node.firstChild);}this.normalizeTextNode(node.nextSibling);}markRegExp(regexp,opt){this.opt=opt;this.log(`Searching with expression "${regexp}"`);let totalMatches=0,fn="wrapMatches";const eachCb=element=>{totalMatches++;this.opt.each(element);};if(this.opt.acrossElements){fn="wrapMatchesAcrossElements";}this[fn](regexp,this.opt.ignoreGroups,(match,node)=>{return this.opt.filter(node,match,totalMatches);},eachCb,()=>{if(totalMatches===0){this.opt.noMatch(regexp);}this.opt.done(totalMatches);});}mark(sv,opt){this.opt=opt;let totalMatches=0,fn="wrapMatches";const{keywords:kwArr,length:kwArrLen}=this.getSeparatedKeywords(typeof sv==="string"?[sv]:sv),sens=this.opt.caseSensitive?"":"i",handler=kw=>{let regex=new RegExp(this.createRegExp(kw),`gm${sens}`),matches=0;this.log(`Searching with expression "${regex}"`);this[fn](regex,1,(term,node)=>{return this.opt.filter(node,kw,totalMatches,matches);},element=>{matches++;totalMatches++;this.opt.each(element);},()=>{if(matches===0){this.opt.noMatch(kw);}if(kwArr[kwArrLen-1]===kw){this.opt.done(totalMatches);}else{handler(kwArr[kwArr.indexOf(kw)+1]);}});};if(this.opt.acrossElements){fn="wrapMatchesAcrossElements";}if(kwArrLen===0){this.opt.done(totalMatches);}else{handler(kwArr[0]);}}unmark(opt){this.opt=opt;let sel=this.opt.element?this.opt.element:"*";sel+="[data-markjs]";if(this.opt.className){sel+=`.${this.opt.className}`;}this.log(`Removal selector "${sel}"`);this.iterator.forEachNode(NodeFilter.SHOW_ELEMENT,node=>{this.unwrapMatches(node);},node=>{const matchesSel=DOMIterator.matches(node,sel),matchesExclude=this.matchesExclude(node,false);if(!matchesSel||matchesExclude){return NodeFilter.FILTER_REJECT;}else{return NodeFilter.FILTER_ACCEPT;}},this.opt.done);}}class DOMIterator{constructor(ctx,iframes=true,exclude=[]){this.ctx=ctx;this.iframes=iframes;this.exclude=exclude;}static matches(element,selector){const selectors=typeof selector==="string"?[selector]:selector,fn=element.matches||element.matchesSelector||element.msMatchesSelector||element.mozMatchesSelector||element.oMatchesSelector||element.webkitMatchesSelector;if(fn){let match=false;selectors.every(sel=>{if(fn.call(element,sel)){match=true;return false;}return true;});return match;}else{return false;}}getContexts(){let ctx,filteredCtx=[];if(typeof this.ctx==="undefined"||!this.ctx){ctx=[];}else if(NodeList.prototype.isPrototypeOf(this.ctx)){ctx=Array.prototype.slice.call(this.ctx);}else if(Array.isArray(this.ctx)){ctx=this.ctx;}else if(typeof this.ctx==="string"){ctx=Array.prototype.slice.call(document.querySelectorAll(this.ctx));}else{ctx=[this.ctx];}ctx.forEach(ctx=>{const isDescendant=filteredCtx.filter(contexts=>{return contexts.contains(ctx);}).length>0;if(filteredCtx.indexOf(ctx)===-1&&!isDescendant){filteredCtx.push(ctx);}});return filteredCtx;}getIframeContents(ifr,successFn,errorFn=()=>{}){let doc;try{const ifrWin=ifr.contentWindow;doc=ifrWin.document;if(!ifrWin||!doc){throw new Error("iframe inaccessible");}}catch(e){errorFn();}if(doc){successFn(doc);}}onIframeReady(ifr,successFn,errorFn){try{const ifrWin=ifr.contentWindow,bl="about:blank",compl="complete",isBlank=()=>{const src=ifr.getAttribute("src").trim(),href=ifrWin.location.href;return href===bl&&src!==bl&&src;},observeOnload=()=>{const listener=()=>{try{if(!isBlank()){ifr.removeEventListener("load",listener);this.getIframeContents(ifr,successFn,errorFn);}}catch(e){errorFn();}};ifr.addEventListener("load",listener);};if(ifrWin.document.readyState===compl){if(isBlank()){observeOnload();}else{this.getIframeContents(ifr,successFn,errorFn);}}else{observeOnload();}}catch(e){errorFn();}}waitForIframes(ctx,done){let eachCalled=0;this.forEachIframe(ctx,()=>true,ifr=>{eachCalled++;this.waitForIframes(ifr.querySelector("html"),()=>{if(! --eachCalled){done();}});},handled=>{if(!handled){done();}});}forEachIframe(ctx,filter,each,end=()=>{}){let ifr=ctx.querySelectorAll("iframe"),open=ifr.length,handled=0;ifr=Array.prototype.slice.call(ifr);const checkEnd=()=>{if(--open<=0){end(handled);}};if(!open){checkEnd();}ifr.forEach(ifr=>{if(DOMIterator.matches(ifr,this.exclude)){checkEnd();}else{this.onIframeReady(ifr,con=>{if(filter(ifr)){handled++;each(con);}checkEnd();},checkEnd);}});}createIterator(ctx,whatToShow,filter){return document.createNodeIterator(ctx,whatToShow,filter,false);}createInstanceOnIframe(contents){return new DOMIterator(contents.querySelector("html"),this.iframes);}compareNodeIframe(node,prevNode,ifr){const compCurr=node.compareDocumentPosition(ifr),prev=Node.DOCUMENT_POSITION_PRECEDING;if(compCurr&prev){if(prevNode!==null){const compPrev=prevNode.compareDocumentPosition(ifr),after=Node.DOCUMENT_POSITION_FOLLOWING;if(compPrev&after){return true;}}else{return true;}}return false;}getIteratorNode(itr){const prevNode=itr.previousNode();let node;if(prevNode===null){node=itr.nextNode();}else{node=itr.nextNode()&&itr.nextNode();}return{prevNode,node};}checkIframeFilter(node,prevNode,currIfr,ifr){let key=false,handled=false;ifr.forEach((ifrDict,i)=>{if(ifrDict.val===currIfr){key=i;handled=ifrDict.handled;}});if(this.compareNodeIframe(node,prevNode,currIfr)){if(key===false&&!handled){ifr.push({val:currIfr,handled:true});}else if(key!==false&&!handled){ifr[key].handled=true;}return true;}if(key===false){ifr.push({val:currIfr,handled:false});}return false;}handleOpenIframes(ifr,whatToShow,eCb,fCb){ifr.forEach(ifrDict=>{if(!ifrDict.handled){this.getIframeContents(ifrDict.val,con=>{this.createInstanceOnIframe(con).forEachNode(whatToShow,eCb,fCb);});}});}iterateThroughNodes(whatToShow,ctx,eachCb,filterCb,doneCb){const itr=this.createIterator(ctx,whatToShow,filterCb);let ifr=[],elements=[],node,prevNode,retrieveNodes=()=>{({prevNode,node}=this.getIteratorNode(itr));return node;};while(retrieveNodes()){if(this.iframes){this.forEachIframe(ctx,currIfr=>{return this.checkIframeFilter(node,prevNode,currIfr,ifr);},con=>{this.createInstanceOnIframe(con).forEachNode(whatToShow,eachCb,filterCb);});}elements.push(node);}elements.forEach(node=>{eachCb(node);});if(this.iframes){this.handleOpenIframes(ifr,whatToShow,eachCb,filterCb);}doneCb();}forEachNode(whatToShow,each,filter,done=()=>{}){const contexts=this.getContexts();let open=contexts.length;if(!open){done();}contexts.forEach(ctx=>{const ready=()=>{this.iterateThroughNodes(whatToShow,ctx,each,filter,()=>{if(--open<=0){done();}});};if(this.iframes){this.waitForIframes(ctx,ready);}else{ready();}});}}window.Mark=function(ctx){const instance=new Mark(ctx);this.mark=(sv,opt)=>{instance.mark(sv,opt);return this;};this.markRegExp=(sv,opt)=>{instance.markRegExp(sv,opt);return this;};this.unmark=opt=>{instance.unmark(opt);return this;};return this;};return window.Mark;},window,document); 8 | -------------------------------------------------------------------------------- /Resources/JavaScript/background.js: -------------------------------------------------------------------------------- 1 | /*jshint bitwise:true, curly:true, eqeqeq:true, forin:true, globalstrict: true, 2 | latedef:true, noarg:true, noempty:true, nonew:true, undef:true, maxlen:256, 3 | strict:true, trailing:true, boss:true, browser:true, devel:true, jquery:true */ 4 | /*global chrome, google, hasLicense, validProducts, options, isChrome, document, getSettings, isValidUrl, localStorage, tabId, changeInfo, tab, openTab, localize */ 5 | 6 | 'use strict'; 7 | 8 | var activeLicense, 9 | headerStore = {}; 10 | 11 | /** 12 | * When we get licenses, set the active license if it's valid 13 | */ 14 | function onLicenseUpdate(response) { 15 | // console.log('onLicenseUpdate', response); 16 | var licenses = response.response.details, 17 | count = licenses.length; 18 | for (var i = 0; i < count; i++) { 19 | var license = licenses[i]; 20 | if (validProducts.includes(license.sku)) { 21 | activeLicense = license; 22 | hasLicense = true; 23 | } 24 | } 25 | } 26 | 27 | /** 28 | * Log failed license update 29 | */ 30 | function onLicenseUpdateFailed(response) { 31 | console.log('onLicenseUpdateFailed', response); 32 | } 33 | 34 | /** 35 | * Get the list of purchased products from the Chrome Web Store 36 | */ 37 | function getLicenses() { 38 | google.payments.inapp.getPurchases({ 39 | 'parameters': {env: 'prod'}, 40 | 'success': onLicenseUpdate, 41 | 'failure': onLicenseUpdateFailed 42 | }); 43 | } 44 | 45 | /** 46 | * Enable HTTP Header Spy on tabs with valid urls 47 | * 48 | * @param {object} tab A tab object. 49 | * @return {*} Not defined. 50 | */ 51 | function enablePopup(tab) { 52 | if (isValidUrl(tab.url)) { 53 | chrome.browserAction.enable(tab.id); 54 | } else { 55 | chrome.browserAction.disable(tab.id); 56 | } 57 | } 58 | 59 | /** 60 | * Inject styles into content 61 | * 62 | * @param {object} tab A tab object. 63 | * @return {*} Not defined. 64 | */ 65 | function injectStyleSheetsIntoContent(tab) { 66 | if (!isValidUrl(tab.url)) { 67 | return; 68 | } 69 | chrome.tabs.sendMessage( 70 | tab.id, 71 | {msg: 'isStyleSheetInjected'}, 72 | function(response) { 73 | if (isDefined(response) && !response.isStyleSheetInjected) { 74 | chrome.tabs.insertCSS(tab.id, { 75 | file: '/Resources/CSS/content.css' 76 | }); 77 | if (options.theme === 'light') { 78 | chrome.tabs.insertCSS(tab.id, { 79 | file: '/Resources/CSS/contentLight.css' 80 | }); 81 | } else { 82 | chrome.tabs.insertCSS(tab.id, { 83 | file: '/Resources/CSS/contentDark.css' 84 | }); 85 | } 86 | chrome.tabs.sendMessage( 87 | tab.id, 88 | {msg: 'styleSheetIsInjected'} 89 | ); 90 | } 91 | } 92 | ); 93 | } 94 | 95 | /** 96 | * Initialize header storage 97 | * 98 | * @param {Number} tabId 99 | * @param {Number} requestId 100 | */ 101 | function initializeHeaderStore(tabId, requestId) { 102 | tabId = String(tabId); 103 | if (!isDefined(headerStore[tabId])) { 104 | headerStore[tabId] = {isContentReady: false}; 105 | } 106 | if (!isDefined(headerStore[tabId][requestId])) { 107 | headerStore[tabId][requestId] = {}; 108 | headerStore[tabId][requestId].request = {}; 109 | headerStore[tabId][requestId].response = {}; 110 | headerStore[tabId][requestId].timeToFirstByte = {}; 111 | headerStore[tabId][requestId].timeToHeadersReceived = {}; 112 | headerStore[tabId][requestId].timeToComplete = {}; 113 | } 114 | } 115 | 116 | /** 117 | * Is the tab content ready 118 | * 119 | * @param {Number} tabId 120 | * @return {boolean} 121 | */ 122 | function isTabContentReady(tabId) { 123 | return !isDefined(headerStore[tabId]) || !isDefined(headerStore[tabId].isContentReady); 124 | } 125 | 126 | /** 127 | * Is the request loggable 128 | * 129 | * @param {object} info 130 | * @return {boolean} 131 | */ 132 | function isRequestLoggable(info) { 133 | return parseInt(info.tabId, 10) > 0 && isValidUrl(info.url) && 134 | (info.type === 'main_frame' || isProVersion()); 135 | } 136 | 137 | /** 138 | * Prune store 139 | */ 140 | function pruneHeaderStore(tabId) { 141 | let tabRequestLimit = localStorage.tabRequestLimit ? localStorage.tabRequestLimit : 25, 142 | requestIds = Object.keys(headerStore[tabId]); 143 | if (requestIds.length > tabRequestLimit) { 144 | delete headerStore[tabId][requestIds.splice(1, 1)]; 145 | } 146 | } 147 | 148 | /** 149 | * Reset store for each main_frame (frameId 0) request. 150 | */ 151 | function resetHeaderStore(tabId, frameId, type, requestId) { 152 | tabId = String(tabId); 153 | if (type === 'main_frame' && 154 | parseInt(frameId, 10) === 0 && 155 | isDefined(headerStore[tabId]) && 156 | Object.keys(headerStore[tabId]).shift() !== requestId 157 | ) { 158 | // console.log('-----------------------------------'); 159 | // console.log('RESETTING HEADER STORE FOR TAB ' + tabId); 160 | // console.log('-----------------------------------'); 161 | delete headerStore[tabId]; 162 | } 163 | initializeHeaderStore(tabId, requestId); 164 | } 165 | 166 | /** 167 | * Store the formData before a main_frame (Document) request will be sent. 168 | * This is the first trigger, so we initialize the object here. 169 | * https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/webRequest 170 | * 171 | * Seems to only work on Chrome at the moment: https://bugzilla.mozilla.org/show_bug.cgi?id=1305162 172 | */ 173 | chrome.webRequest.onBeforeRequest.addListener( 174 | function(info) { 175 | if (!isRequestLoggable(info)) { 176 | return; 177 | } 178 | // Firefox sets originUrl when 'cmd + click'-ing links. 179 | // It also sets the frameId to the frame of the click. Here we reset it to 0. 180 | if (!isChrome && info.type === 'main_frame' && isDefined(info.originUrl)) { 181 | info.frameId = 0; 182 | } 183 | resetHeaderStore(info.tabId, info.frameId, info.type, info.requestId); 184 | pruneHeaderStore(info.tabId); 185 | let requestId = String(info.requestId), 186 | tabId = String(info.tabId), 187 | requestIndex = headerStore[tabId][requestId].request.requestIndex; 188 | if (!isDefined(requestIndex)) { 189 | requestIndex = 0; 190 | } else { 191 | requestIndex++; 192 | } 193 | headerStore[tabId][requestId].request.requestIndex = requestIndex; 194 | 195 | // Prevent error when HSTS occurs 196 | if (!isDefined(info.requestHeaders)) { 197 | info.requestHeaders = []; 198 | } 199 | headerStore[tabId][requestId].request[requestIndex] = info; 200 | }, 201 | { 202 | urls: ['http://*/*', 'https://*/*'], 203 | types: ['main_frame', 'sub_frame', 'xmlhttprequest'] 204 | }, 205 | isChrome ? ['requestBody'] : [] 206 | ); 207 | 208 | /** 209 | * store response headers before redirecting 210 | */ 211 | chrome.webRequest.onBeforeRedirect.addListener( 212 | function(info) { 213 | if (!isRequestLoggable(info)) { 214 | return; 215 | } 216 | let requestId = String(info.requestId), 217 | tabId = String(info.tabId), 218 | requestIndex; 219 | // Maybe the request was already removed from the queue 220 | if (!isDefined(headerStore[tabId]) || !isDefined(headerStore[tabId][requestId])) { 221 | return; 222 | } 223 | requestIndex = headerStore[tabId][requestId].request.requestIndex; 224 | 225 | // In case of redirects, there may already be data for this request, extend it. 226 | if (typeof headerStore[tabId][requestId].response[requestIndex] === 'object') { 227 | headerStore[tabId][requestId].response[requestIndex] = Object.assign(headerStore[tabId][requestId].response[requestIndex], info); 228 | } else { 229 | headerStore[tabId][requestId].response[requestIndex] = info; 230 | } 231 | }, 232 | { 233 | urls: ['http://*/*', 'https://*/*'], 234 | types: ['main_frame', 'sub_frame', 'xmlhttprequest'] 235 | }, 236 | ['responseHeaders'] 237 | ); 238 | 239 | /** 240 | * Store the timestamp when the request completes 241 | */ 242 | chrome.webRequest.onCompleted.addListener( 243 | function(info) { 244 | if (!isRequestLoggable(info)) { 245 | return; 246 | } 247 | let requestId = String(info.requestId), 248 | tabId = String(info.tabId), 249 | requestIndex; 250 | // Maybe the request was already removed from the queue 251 | if (!isDefined(headerStore[tabId]) || !isDefined(headerStore[tabId][requestId])) { 252 | return; 253 | } 254 | requestIndex = headerStore[tabId][requestId].request.requestIndex; 255 | 256 | // Log time to complete the request 257 | headerStore[tabId][requestId].timeToComplete[requestIndex] = {timeStamp: info.timeStamp}; 258 | 259 | // Extend the existing object with any new fields. 260 | if (typeof headerStore[tabId][requestId].response[requestIndex] === 'object') { 261 | headerStore[tabId][requestId].response[requestIndex] = Object.assign(headerStore[tabId][requestId].response[requestIndex], info); 262 | } else { 263 | headerStore[tabId][requestId].response[requestIndex] = info; 264 | } 265 | 266 | // Results from cache don't have responseHeaders 267 | if (!isDefined(headerStore[tabId][requestId].response[requestIndex].responseHeaders)) { 268 | headerStore[tabId][requestId].response[requestIndex].responseHeaders = []; 269 | } 270 | 271 | // Clean the requestIndex, so any Object.keys().length calls will return a valid count 272 | delete headerStore[tabId][requestId].request.requestIndex; 273 | 274 | if (isProVersion()) { 275 | let headers = {}; 276 | headers[requestId] = headerStore[tabId][requestId]; 277 | sendHeadersToContent(info.tabId, info.url, headers, 'responseCompleted'); 278 | } 279 | }, 280 | { 281 | urls: ['http://*/*', 'https://*/*'], 282 | types: ['main_frame', 'sub_frame', 'xmlhttprequest'] 283 | } 284 | ); 285 | 286 | /** 287 | * Store the response headers when a main_frame (Document) response comes in. 288 | */ 289 | chrome.webRequest.onHeadersReceived.addListener( 290 | function(info) { 291 | if (!isRequestLoggable(info)) { 292 | return; 293 | } 294 | let requestId = String(info.requestId), 295 | tabId = String(info.tabId), 296 | requestIndex; 297 | // Maybe the request was already removed from the queue 298 | if (!isDefined(headerStore[tabId]) || !isDefined(headerStore[tabId][requestId])) { 299 | return; 300 | } 301 | requestIndex = headerStore[tabId][requestId].request.requestIndex; 302 | 303 | // Log timeToHeadersReceived 304 | headerStore[tabId][requestId].timeToHeadersReceived[requestIndex] = {timeStamp: info.timeStamp}; 305 | 306 | headerStore[tabId][requestId].response[requestIndex] = info; 307 | }, 308 | { 309 | urls: ['http://*/*', 'https://*/*'], 310 | types: ['main_frame', 'sub_frame', 'xmlhttprequest'] 311 | }, 312 | ['responseHeaders'] 313 | ); 314 | 315 | /** 316 | * Store the timestamp when the first byte comes in. 317 | */ 318 | chrome.webRequest.onResponseStarted.addListener( 319 | function(info) { 320 | if (!isRequestLoggable(info)) { 321 | return; 322 | } 323 | let requestId = String(info.requestId), 324 | tabId = String(info.tabId), 325 | requestIndex; 326 | // Maybe the request was already removed from the queue 327 | if (!isDefined(headerStore[tabId]) || !isDefined(headerStore[tabId][requestId])) { 328 | return; 329 | } 330 | requestIndex = headerStore[tabId][requestId].request.requestIndex; 331 | 332 | // Log timeToFirstByte 333 | headerStore[tabId][requestId].timeToFirstByte[requestIndex] = {timeStamp: info.timeStamp}; 334 | }, 335 | { 336 | urls: ['http://*/*', 'https://*/*'], 337 | types: ['main_frame', 'sub_frame', 'xmlhttprequest'] 338 | } 339 | ); 340 | 341 | /** 342 | * Store the request headers when a main_frame (Document) request will be sent. 343 | */ 344 | chrome.webRequest.onSendHeaders.addListener( 345 | function(info) { 346 | if (!isRequestLoggable(info)) { 347 | return; 348 | } 349 | // Firefox sets originUrl when 'cmd + click'-ing links. 350 | // It also sets the frameId to the frame of the click. Here we reset it to 0. 351 | if (!isChrome && info.type === 'main_frame' && isDefined(info.originUrl)) { 352 | info.frameId = 0; 353 | } 354 | let requestId = String(info.requestId), 355 | tabId = String(info.tabId), 356 | urlParser = document.createElement('a'), 357 | requestIndex; 358 | // Maybe the request was already removed from the queue 359 | if (!isDefined(headerStore[tabId]) || !isDefined(headerStore[tabId][requestId])) { 360 | return; 361 | } 362 | requestIndex = headerStore[tabId][requestId].request.requestIndex; 363 | 364 | // Get parameters 365 | urlParser.href = info.url; 366 | if (urlParser.search.length) { 367 | let get = new URLSearchParams(urlParser.search), 368 | parameters = []; 369 | for (let [key, value] of get.entries()) { 370 | parameters.push({'key': key, 'value': value}); 371 | } 372 | info.getData = parameters; 373 | } 374 | // In case of post data, there may already be data for this request, extend it. 375 | if (typeof headerStore[tabId][requestId].request[requestIndex] === 'object') { 376 | headerStore[tabId][requestId].request[requestIndex] = Object.assign(headerStore[tabId][requestId].request[requestIndex], info); 377 | } else { 378 | headerStore[tabId][requestId].request[requestIndex] = info; 379 | } 380 | }, 381 | { 382 | urls: ['http://*/*', 'https://*/*'], 383 | types: ['main_frame', 'sub_frame', 'xmlhttprequest'] 384 | }, 385 | ['requestHeaders'] 386 | ); 387 | 388 | /** 389 | * Send headers to content script 390 | * 391 | * @param {Number} tabId 392 | * @param {string} url 393 | * @param {object} headers 394 | * @param {string} message 395 | */ 396 | function sendHeadersToContent(tabId, url, headers, message) { 397 | if (!isValidUrl(url) || !isTabContentReady(tabId)) { 398 | return; 399 | } 400 | if (parseInt(tabId, 10) <= 0 || options.renderMode === 'none') { 401 | return; 402 | } 403 | chrome.tabs.sendMessage(tabId, { 404 | msg: message, 405 | hasLicense: hasLicense, 406 | headers: headers, 407 | options: options 408 | }); 409 | } 410 | 411 | /** 412 | * detect when a tab is activated (tab switch) or load a fresh tab from a 'new tab page' 413 | */ 414 | chrome.tabs.onActivated.addListener(function() { 415 | chrome.tabs.query({active: true, currentWindow: true}, function(tabs) { 416 | let tab = tabs.shift(); 417 | injectStyleSheetsIntoContent(tab); 418 | sendHeadersToContent(tab.id, tab.url, headerStore[String(tab.id)], 'tabActivated'); 419 | enablePopup(tab); 420 | }); 421 | }); 422 | 423 | /** 424 | * detect when a tab is created 425 | */ 426 | chrome.tabs.onCreated.addListener(function(tab) { 427 | sendHeadersToContent(tab.id, tab.url, headerStore[String(tab.id)], 'tabCreated'); 428 | enablePopup(tab); 429 | }); 430 | 431 | /** 432 | * Detect when the content of a tab is ready, inject the CSS and 433 | * pass the headers and the options to the content. 434 | */ 435 | chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) { 436 | // We only react on a complete load of a http(s) page, 437 | // only then we're sure the content.js is loaded. 438 | if (changeInfo.status !== 'complete' || !isValidUrl(tab.url)) { 439 | return; 440 | } 441 | // Remove the isContentReady: false property so the isTabContentReady() method will return true 442 | if (isDefined(headerStore[tabId]) && isDefined(headerStore[tabId].isContentReady)) { 443 | delete headerStore[tabId].isContentReady; 444 | } 445 | 446 | if (!isChrome) { 447 | restoreOptions(); 448 | } 449 | 450 | if (parseInt(tabId, 10) <= 0 || options.renderMode === 'none') { 451 | return; 452 | } 453 | injectStyleSheetsIntoContent(tab); 454 | sendHeadersToContent(tab.id, tab.url, headerStore[String(tab.id)], 'tabUpdated'); 455 | enablePopup(tab); 456 | }); 457 | 458 | /** 459 | * Cleanup headerStore when tab closes 460 | */ 461 | chrome.tabs.onRemoved.addListener(function(tabId) { 462 | delete headerStore[String(tabId)]; 463 | }); 464 | 465 | chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) { 466 | switch (message.msg) { 467 | case 'storeRequestTypeSelection': 468 | storeActiveRequestTypes(message.activeRequestTypes); 469 | break; 470 | } 471 | // Maybe check sender? 472 | }); 473 | 474 | function sendCurrentRequestTypesToTabs(activeRequestTypes) { 475 | chrome.tabs.query({}, function(tabs) { 476 | tabs.forEach(function(tab) { 477 | if (isValidUrl(tab.url)) { 478 | chrome.tabs.sendMessage(tab.id, { 479 | msg: 'requestTypeSelectionDidChange', 480 | activeRequestTypes: activeRequestTypes 481 | }); 482 | } 483 | }); 484 | }); 485 | } 486 | 487 | chrome.storage.onChanged.addListener(function(changes, namespace) { 488 | let activeRequestTypes = [], 489 | activeRequestTypesDidChange = false; 490 | for (let key in changes) { 491 | if (changes.hasOwnProperty(key)) { 492 | options[key] = changes[key].newValue; 493 | if (key === 'activeRequestTypes') { 494 | activeRequestTypesDidChange = true; 495 | activeRequestTypes = options[key]; 496 | } 497 | } 498 | } 499 | 500 | if (activeRequestTypesDidChange) { 501 | sendCurrentRequestTypesToTabs(activeRequestTypes); 502 | } 503 | }); 504 | 505 | // getLicenses(); 506 | restoreOptions(); 507 | -------------------------------------------------------------------------------- /Resources/JavaScript/i18n.js: -------------------------------------------------------------------------------- 1 | /*jshint bitwise:true, curly:true, eqeqeq:true, forin:true, globalstrict: true, 2 | latedef:true, noarg:true, noempty:true, nonew:true, undef:true, maxlen:256, 3 | strict:true, trailing:true, boss:true, browser:true, devel:true, jquery:true */ 4 | /*global google, chrome, isChrome, containerId, isValidUrl, sanitizeString, getPanel, getSettings, htmlEntities, Mark, googleAnalyticsId */ 5 | 'use strict'; 6 | 7 | document.addEventListener('DOMContentLoaded', function() { 8 | /** 9 | * Translate the labels 10 | */ 11 | var translateLabels = function() { 12 | document.querySelectorAll('[i18n-content]').forEach(function(element) { 13 | if (chrome.i18n.getMessage(element.getAttribute('i18n-content'))) { 14 | // element.textContent = '[Ok] ' + chrome.i18n.getMessage(element.getAttribute('i18n-content')); 15 | element.textContent = chrome.i18n.getMessage(element.getAttribute('i18n-content')); 16 | } else { 17 | element.textContent = '[' + element.getAttribute('i18n-content') + ']'; 18 | } 19 | }); 20 | }; 21 | 22 | translateLabels(); 23 | }); 24 | -------------------------------------------------------------------------------- /Resources/JavaScript/options.js: -------------------------------------------------------------------------------- 1 | /*jshint bitwise:true, curly:true, eqeqeq:true, forin:true, globalstrict: true, 2 | latedef:true, noarg:true, noempty:true, nonew:true, undef:true, maxlen:256, 3 | strict:true, trailing:true, boss:true, browser:true, devel:true, jquery:true */ 4 | /*global google, chrome, isChrome, containerId, isValidUrl, sanitizeString, getPanel, getSettings, htmlEntities, Mark, googleAnalyticsId */ 5 | 'use strict'; 6 | 7 | document.addEventListener('DOMContentLoaded', function() { 8 | function saveOptions() { 9 | let multiSelectFields = ['hiddenRequestHeaders', 'hiddenResponseHeaders', 'shownResponseHeaders', 'markers'], 10 | updatedValues = { 11 | location: document.getElementById('location').value, 12 | tabRequestLimit: document.getElementById('tabRequestLimit').value, 13 | timeout: document.getElementById('timeout').value, 14 | hidePanelAfterTimeout: parseInt(document.getElementById('hidePanelAfterTimeout').value, 10) === 1, 15 | renderMode: document.getElementById('renderMode').value, 16 | theme: document.getElementById('theme').value 17 | }; 18 | 19 | multiSelectFields.forEach(function(fieldId) { 20 | let element = document.getElementById(fieldId); 21 | if (element) { 22 | updatedValues[fieldId] = []; 23 | element.childNodes.forEach(function(node) { 24 | updatedValues[fieldId].push(node.textContent); 25 | }); 26 | } 27 | }); 28 | 29 | try { 30 | // Firefox developer edition supports storage, but a config option needs to be enabled 31 | if (isChrome && isDefined(chrome.storage.sync)) { 32 | chrome.storage.sync.set(updatedValues); 33 | } else { 34 | localStorage.location = document.getElementById('location').value; 35 | localStorage.tabRequestLimit = document.getElementById('tabRequestLimit').value; 36 | localStorage.timeout = document.getElementById('timeout').value; 37 | localStorage.hidePanelAfterTimeout = parseInt(document.getElementById('hidePanelAfterTimeout').value, 10) === 1; 38 | localStorage.renderMode = document.getElementById('renderMode').value; 39 | localStorage.theme = document.getElementById('theme').value; 40 | 41 | multiSelectFields.forEach(function(fieldId) { 42 | localStorage[fieldId] = JSON.stringify(updatedValues[fieldId]); 43 | }); 44 | } 45 | } catch (e) { 46 | // No-op 47 | } 48 | } 49 | 50 | function removeElement(element) { 51 | element.remove(); 52 | saveOptions(); 53 | } 54 | 55 | function addElement(element, newElementId, containerID) { 56 | if (element === '') { 57 | return; 58 | } 59 | 60 | let container = document.getElementById(containerID), 61 | closeButton = document.createElement('span'), 62 | label = document.createElement('span'), 63 | elementText; 64 | 65 | if (!container) { 66 | return; 67 | } 68 | 69 | elementText = document.createTextNode(element); 70 | closeButton.classList.add('aui-icon', 'aui-icon-close'); 71 | label.classList.add('aui-label', 'aui-label-closeable'); 72 | label.appendChild(elementText); 73 | label.appendChild(closeButton); 74 | 75 | container.appendChild(label); 76 | closeButton.addEventListener('click', function(event) { 77 | removeElement(event.target.parentNode); 78 | }); 79 | 80 | document.getElementById(newElementId).value = ''; 81 | saveOptions(); 82 | } 83 | 84 | function getSettingsAndRestoreOptions() { 85 | let settings; 86 | // Firefox developer edition supports storage, but a config option needs to be enabled 87 | if (isChrome && isDefined(chrome.storage.sync)) { 88 | chrome.storage.sync.get(null, function(result) { 89 | settings = { 90 | location: result.location ? result.location : 'bottomRight', 91 | theme: result.theme ? result.theme : 'light', 92 | tabRequestLimit: result.tabRequestLimit ? result.tabRequestLimit : 25, 93 | timeout: result.timeout ? result.timeout : 3, 94 | hidePanelAfterTimeout: isDefined(result.hidePanelAfterTimeout) ? result.hidePanelAfterTimeout : true, 95 | renderMode: result.renderMode ? result.renderMode : 'microMode', 96 | hiddenRequestHeaders: result.hiddenRequestHeaders ? result.hiddenRequestHeaders : [], 97 | hiddenResponseHeaders: result.hiddenResponseHeaders ? result.hiddenResponseHeaders : [], 98 | shownResponseHeaders: result.shownResponseHeaders ? result.shownResponseHeaders : ['^Server$'], 99 | markers: result.markers ? result.markers : [] 100 | }; 101 | restoreOptions(settings); 102 | }); 103 | } else { 104 | settings = { 105 | location: localStorage.location ? localStorage.location : 'bottomRight', 106 | theme: localStorage.theme ? localStorage.theme : 'light', 107 | tabRequestLimit: localStorage.tabRequestLimit ? localStorage.tabRequestLimit : 25, 108 | timeout: localStorage.timeout ? localStorage.timeout : 3, 109 | hidePanelAfterTimeout: isDefined(localStorage.hidePanelAfterTimeout) ? localStorage.hidePanelAfterTimeout : true, 110 | renderMode: localStorage.renderMode ? localStorage.renderMode : 'microMode', 111 | hiddenRequestHeaders: isDefined(localStorage.hiddenRequestHeaders) ? JSON.parse(localStorage.hiddenRequestHeaders) : [], 112 | hiddenResponseHeaders: isDefined(localStorage.hiddenResponseHeaders) ? JSON.parse(localStorage.hiddenResponseHeaders) : [], 113 | shownResponseHeaders: isDefined(localStorage.shownResponseHeaders) ? JSON.parse(localStorage.shownResponseHeaders) : ['^Server$'], 114 | markers: isDefined(localStorage.markers) ? JSON.parse(localStorage.markers) : [] 115 | }; 116 | restoreOptions(settings); 117 | } 118 | } 119 | 120 | function restoreOptions(options) { 121 | document.getElementById('location').value = options.location; 122 | document.getElementById('tabRequestLimit').value = options.tabRequestLimit; 123 | document.getElementById('timeout').value = options.timeout; 124 | document.getElementById('hidePanelAfterTimeout').value = options.hidePanelAfterTimeout ? 1 : 0; 125 | document.getElementById('renderMode').value = options.renderMode; 126 | document.getElementById('theme').value = options.theme; 127 | 128 | options.hiddenRequestHeaders.forEach(function(element) { 129 | addElement(element, 'newHiddenRequestHeader', 'hiddenRequestHeaders'); 130 | }); 131 | options.hiddenResponseHeaders.forEach(function(element) { 132 | addElement(element, 'newHiddenResponseHeader', 'hiddenResponseHeaders'); 133 | }); 134 | options.shownResponseHeaders.forEach(function(element) { 135 | addElement(element, 'newShownResponseHeader', 'shownResponseHeaders'); 136 | }); 137 | options.markers.forEach(function(element) { 138 | addElement(element, 'newMarker', 'markers'); 139 | }); 140 | } 141 | 142 | document.getElementById('renderMode').addEventListener('change', function() { 143 | saveOptions(); 144 | }); 145 | document.getElementById('location').addEventListener('change', function() { 146 | saveOptions(); 147 | }); 148 | document.getElementById('tabRequestLimit').addEventListener('change', function() { 149 | saveOptions(); 150 | }); 151 | document.getElementById('timeout').addEventListener('change', function() { 152 | saveOptions(); 153 | }); 154 | document.getElementById('hidePanelAfterTimeout').addEventListener('change', function() { 155 | saveOptions(); 156 | }); 157 | document.getElementById('theme').addEventListener('change', function() { 158 | saveOptions(); 159 | }); 160 | 161 | let multiSelectFields = { 162 | 'hiddenRequestHeaders': {addId: 'addHiddenRequestHeader', newId: 'newHiddenRequestHeader'}, 163 | 'hiddenResponseHeaders': {addId: 'addHiddenResponseHeader', newId: 'newHiddenResponseHeader'}, 164 | 'shownResponseHeaders': {addId: 'addShownResponseHeader', newId: 'newShownResponseHeader'}, 165 | 'markers': {addId: 'addMarker', newId: 'newMarker'} 166 | }; 167 | 168 | Object.keys(multiSelectFields).forEach(function(field) { 169 | let element = document.getElementById(multiSelectFields[field].addId); 170 | if (element) { 171 | document.getElementById(multiSelectFields[field].addId).addEventListener('click', function() { 172 | addElement(document.getElementById(multiSelectFields[field].newId).value, multiSelectFields[field].newId, field); 173 | }); 174 | document.getElementById(multiSelectFields[field].newId).addEventListener('keyup', function(event) { 175 | if (event.keyCode === 13) { 176 | addElement(event.target.value, multiSelectFields[field].newId, field); 177 | } 178 | }); 179 | } 180 | }); 181 | 182 | if (isProVersion()) { 183 | document.querySelectorAll('.pro').forEach(function(element) { 184 | if (element.classList.contains('hidden')) { 185 | element.classList.remove('hidden'); 186 | } 187 | }); 188 | } 189 | getSettingsAndRestoreOptions(); 190 | }); 191 | -------------------------------------------------------------------------------- /Resources/JavaScript/optionsContextProvider.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function() { 2 | 'use strict'; 3 | if (typeof chrome === 'object') { 4 | document.querySelector('body').className = 'chromeOptionBody'; 5 | } 6 | if (typeof InstallTrigger !== 'undefined') { 7 | document.querySelector('body').className = 'firefoxOptionBody'; 8 | } 9 | }); 10 | -------------------------------------------------------------------------------- /Resources/JavaScript/popup.js: -------------------------------------------------------------------------------- 1 | /*jshint bitwise:true, curly:true, eqeqeq:true, forin:true, globalstrict: true, 2 | latedef:true, noarg:true, noempty:true, nonew:true, undef:true, maxlen:256, 3 | strict:true, trailing:true, boss:true, browser:true, devel:true, jquery:true */ 4 | /*global chrome, containerId, hasLicense, options, isValidUrl, sanitizeString, getPanel, getSettings, htmlEntities, Mark, googleAnalyticsId */ 5 | 'use strict'; 6 | 7 | /** 8 | * Google Analytics 9 | */ 10 | try { 11 | let request = new XMLHttpRequest(); 12 | let message = 'v=1&tid=' + googleAnalyticsId + '&cid=23456780-ABAB-98FE-E2AF-9876AFBCC212&aip=1&ds=add-on&t=event&ec=AAA&ea=libraryLoad'; 13 | request.open('POST', 'https://www.google-analytics.com/collect', true); 14 | request.send(message); 15 | } catch (e) { 16 | console.warn('Error sending report to Google Analytics.\n' + e); 17 | } 18 | 19 | /** 20 | * Update the current tab and refresh popup after 1s 21 | * 22 | * @param {object} e The click event. 23 | * @return {*} Not defined. 24 | */ 25 | var updateTab = function(e) { 26 | chrome.tabs.update( 27 | {url: e.target.href} 28 | ); 29 | window.setTimeout(function() { 30 | window.location.href = '/Resources/HTML/popup.html'; 31 | }, 1000); 32 | }; 33 | 34 | document.addEventListener('DOMContentLoaded', function() { 35 | restoreOptions(); 36 | 37 | document.getElementById('extensionName').textContent = chrome.i18n.getMessage('extensionName'); 38 | let defaultMessageParagraph = document.createElement('p'), 39 | defaultMessageParagraphText = document.createTextNode(chrome.i18n.getMessage('popupDefaultMessage')), 40 | optionsButtonDiv = document.createElement('div'), 41 | optionsButton = document.createElement('button'), 42 | optionsButtonText = document.createTextNode(chrome.i18n.getMessage('buttonOptions')); 43 | 44 | defaultMessageParagraph.className = 'defaultMessage'; 45 | defaultMessageParagraph.appendChild(defaultMessageParagraphText); 46 | optionsButton.id = 'goToOptions'; 47 | optionsButton.appendChild(optionsButtonText); 48 | optionsButtonDiv.appendChild(optionsButton); 49 | optionsButtonDiv.className = 'optionsButtonInDefaultMessage'; 50 | document.getElementById('result').appendChild(defaultMessageParagraph); 51 | document.getElementById('result').appendChild(optionsButtonDiv); 52 | 53 | // Display settings panel 54 | document.getElementById('settingsIcon').addEventListener('click', function() { 55 | toggleElementVisibility(document.getElementById('settings')); 56 | if (isProVersion()) { 57 | document.querySelectorAll('.pro').forEach(function(element) { 58 | if (element.classList.contains('hidden')) { 59 | element.classList.remove('hidden'); 60 | } 61 | }); 62 | } 63 | }); 64 | document.getElementById('settings').querySelectorAll('.closeButton').forEach(function(element) { 65 | element.addEventListener('click', function(event) { 66 | toggleElementVisibility(event.target.parentNode); 67 | }); 68 | }); 69 | 70 | // Button to go to options page 71 | document.querySelectorAll('#goToOptions').forEach(function(element) { 72 | element.addEventListener('click', function() { 73 | if (chrome.runtime.openOptionsPage) { 74 | // New way to open options pages, if supported (Chrome 42+). 75 | chrome.runtime.openOptionsPage(); 76 | } else { 77 | // Reasonable fallback. 78 | window.open(chrome.runtime.getURL('/Resources/HTML/options.html')); 79 | } 80 | }); 81 | }); 82 | 83 | chrome.tabs.query({active: true, currentWindow: true}, function(tabs) { 84 | // For example: only the background devtools or a popup are opened 85 | if (tabs.length === 0) { 86 | return; 87 | } 88 | let tab = tabs.shift(); 89 | if (!isValidUrl(tab.url)) { 90 | return; 91 | } 92 | document.getElementById('extensionName').setAttribute('title', tab.id); 93 | chrome.runtime.getBackgroundPage(function(backgroundPage) { 94 | let headerStore = backgroundPage.headerStore; 95 | hasLicense = backgroundPage.hasLicense; 96 | 97 | if (typeof headerStore === 'undefined') { 98 | return; 99 | } 100 | let requestIds = Object.keys(headerStore[String(tab.id)]), 101 | store = headerStore[String(tab.id)], 102 | containerElement = document.getElementById('result'); 103 | 104 | while (containerElement.firstChild) { 105 | containerElement.removeChild(containerElement.firstChild); 106 | } 107 | 108 | // Add the toolbar 109 | if (!containerElement.querySelector('#toolBar')) { 110 | containerElement.appendChild(getToolbar(options)); 111 | if (isProVersion()) { 112 | // Request type selector 113 | containerElement.querySelectorAll('.requestTypes .type').forEach(function(element) { 114 | element.addEventListener('click', function(event) { 115 | toggleRequestType(event.target); 116 | storeRequestTypeSelection(containerElement); 117 | }); 118 | }); 119 | 120 | // Header filter 121 | containerElement.querySelector('#inlineFilterInput').addEventListener('keyup', function() { 122 | filterHeaders(); 123 | }); 124 | containerElement.querySelector('#inlineFilterAllowRegex').addEventListener('click', function() { 125 | filterHeaders(); 126 | }); 127 | } 128 | } 129 | 130 | requestIds.forEach(function(requestId) { 131 | let panel = getPanel(store[requestId], requestId, options); 132 | if (panel.children.length) { 133 | containerElement.insertBefore(panel, containerElement.querySelector('#toolBar')); 134 | containerElement.scrollTop = 0; 135 | } 136 | }); 137 | 138 | if (options.markers.length > 0) { 139 | let magicMarker = new Mark(containerElement); 140 | options.markers.forEach(function(marker) { 141 | let regexp = new RegExp(marker, 'gmi'); 142 | magicMarker.markRegExp(regexp); 143 | }); 144 | } 145 | }); 146 | 147 | // Select cell text on click 148 | [].slice.call(document.getElementsByTagName('td')).forEach(function(element) { 149 | element.addEventListener('click', selectElementText); 150 | }); 151 | 152 | // Header filter 153 | if (isProVersion()) { 154 | let filterInput = document.getElementById('inlineFilterInput'); 155 | if (filterInput) { 156 | filterInput.focus(); 157 | filterInput.addEventListener('keyup', function() { 158 | filterHeaders(); 159 | }); 160 | } 161 | let inlineFilterAllowRegex = document.getElementById('inlineFilterAllowRegex'); 162 | if (inlineFilterAllowRegex) { 163 | inlineFilterAllowRegex.addEventListener('click', function() { 164 | filterHeaders(); 165 | }); 166 | } 167 | } 168 | }); 169 | 170 | // Make links clickable 171 | [].slice.call(document.getElementsByTagName('a')).forEach(function(link) { 172 | link.addEventListener('click', updateTab); 173 | }); 174 | }); 175 | -------------------------------------------------------------------------------- /Resources/JavaScript/store.js: -------------------------------------------------------------------------------- 1 | /*jshint bitwise:true, curly:true, eqeqeq:true, forin:true, globalstrict: true, 2 | latedef:true, noarg:true, noempty:true, nonew:true, undef:true, maxlen:256, 3 | strict:true, trailing:true, boss:true, browser:true, devel:true, jquery:true */ 4 | /*global google, chrome, isChrome, containerId, validProducts, isValidUrl, sanitizeString, getPanel, getSettings, htmlEntities, Mark, googleAnalyticsId */ 5 | 'use strict'; 6 | 7 | var subscriptionPlans = [ 8 | 'lifetime_subscription', 9 | 'yearly_subscription', 10 | 'monthly_subscription' 11 | ]; 12 | 13 | var beerPlans = [ 14 | 'one_beer', 15 | 'three_beers', 16 | 'six_pack', 17 | 'ten_beers' 18 | ]; 19 | 20 | var pizzaPlans = [ 21 | 'one_pizza', 22 | 'two_pizzas', 23 | 'three_pizzas', 24 | 'four_pizzas', 25 | 'five_pizzas' 26 | ]; 27 | 28 | var countMap = { 29 | one: 1, 30 | two: 2, 31 | three: 3, 32 | four: 4, 33 | five: 5, 34 | six: 6, 35 | ten: 10, 36 | twenty: 20, 37 | lifetime: 20, 38 | monthly: 1, 39 | yearly: 4 40 | }; 41 | 42 | /** 43 | * Get the beer icons 44 | * 45 | * @param {string} sku 46 | * @return {Node} 47 | */ 48 | function getBeerIcons(sku) { 49 | try { 50 | let number = sku.split('_').shift(), 51 | element = document.createElement('div'); 52 | for (let index = 1; index <= countMap[number]; index++) { 53 | // Between the ticks is a beer emoji, which may not show in every console font 54 | element.appendChild(document.createTextNode('🍺')); 55 | if (index !== countMap[number] && index % 10 === 0) { 56 | element.appendChild(document.createElement('br')); 57 | } 58 | } 59 | return element; 60 | } catch (e) { 61 | console.log(e); 62 | return document.createElement('div'); 63 | } 64 | } 65 | 66 | /** 67 | * Get the pizza icons 68 | * 69 | * @param {string} sku 70 | * @return {Node} 71 | */ 72 | function getPizzaIcons(sku) { 73 | try { 74 | let number = sku.split('_').shift(), 75 | element = document.createElement('div'); 76 | for (let index = 1; index <= countMap[number]; index++) { 77 | // Between the ticks is a pizza emoji, which may not show in every console font 78 | element.appendChild(document.createTextNode('🍕')); 79 | if (index !== countMap[number] && index % 10 === 0) { 80 | element.appendChild(document.createElement('br')); 81 | } 82 | } 83 | return element; 84 | } catch (e) { 85 | console.log(e); 86 | return document.createElement('div'); 87 | } 88 | } 89 | 90 | /** 91 | * Get the value in beers 92 | * 93 | * @param {string} sku 94 | * @return {string} 95 | */ 96 | function getBeerValue(sku) { 97 | let number = sku.split('_').shift(); 98 | return countMap[number] + ' ' + chrome.i18n.getMessage('plansPageBeers'); 99 | } 100 | 101 | /** 102 | * Get the value in pizza 103 | * 104 | * @param {string} sku 105 | * @return {string} 106 | */ 107 | function getPizzaValue(sku) { 108 | let number = sku.split('_').shift(); 109 | return countMap[number] + ' ' + chrome.i18n.getMessage('plansPagePizzas'); 110 | } 111 | 112 | /** 113 | * Get a product table row 114 | * 115 | * @param {object} product 116 | * @return {Node} 117 | */ 118 | function getSubscriptionTableRow(product) { 119 | let row = document.createElement('tr'), 120 | titleCell = document.createElement('td'), 121 | titleText = document.createTextNode(product.localeData['0'].title), 122 | priceCell = document.createElement('td'), 123 | // beerCell = document.createElement('td'), 124 | priceText = document.createTextNode(product.prices['0'].currencyCode + ' ' + Number(product.prices['0'].valueMicros / 1000 / 1000).toFixed(2)), 125 | buttonCell = document.createElement('td'), 126 | button = document.createElement('a'), 127 | buttonText = document.createTextNode(chrome.i18n.getMessage('plansPageIWillSupportYouWith') + ' ' + getBeerValue(product.sku)); 128 | titleCell.className = 'title'; 129 | titleCell.appendChild(titleText); 130 | row.appendChild(titleCell); 131 | // beerCell.appendChild(getBeerIcons(Number(product.prices['0'].valueMicros))); 132 | // row.appendChild(beerCell); 133 | buttonCell.className = 'buyNow'; 134 | button.classList.add('button'); 135 | button.dataset.sku = product.sku; 136 | button.appendChild(buttonText); 137 | buttonCell.appendChild(button); 138 | row.appendChild(buttonCell); 139 | priceCell.className = 'price'; 140 | priceCell.appendChild(priceText); 141 | row.appendChild(priceCell); 142 | return row; 143 | } 144 | 145 | /** 146 | * Get a product table row 147 | * 148 | * @param {object} product 149 | * @return {Node} 150 | */ 151 | function getBeerTableRow(product) { 152 | let row = document.createElement('tr'), 153 | // titleCell = document.createElement('td'), 154 | // titleText = document.createTextNode(product.localeData['0'].title), 155 | priceCell = document.createElement('td'), 156 | beerCell = document.createElement('td'), 157 | priceText = document.createTextNode(product.prices['0'].currencyCode + ' ' + Number(product.prices['0'].valueMicros / 1000 / 1000).toFixed(2)), 158 | buttonCell = document.createElement('td'), 159 | button = document.createElement('a'), 160 | buttonText = document.createTextNode(chrome.i18n.getMessage('plansPageIWillSupportYouWith') + ' ' + getBeerValue(product.sku)); 161 | // titleCell.className = 'title'; 162 | // titleCell.appendChild(titleText); 163 | // row.appendChild(titleCell); 164 | buttonCell.className = 'buyNow'; 165 | button.classList.add('button'); 166 | button.dataset.sku = product.sku; 167 | button.appendChild(buttonText); 168 | buttonCell.appendChild(button); 169 | row.appendChild(buttonCell); 170 | beerCell.appendChild(getBeerIcons(product.sku)); 171 | row.appendChild(beerCell); 172 | priceCell.className = 'price'; 173 | priceCell.appendChild(priceText); 174 | row.appendChild(priceCell); 175 | return row; 176 | } 177 | 178 | /** 179 | * Get a product table row 180 | * 181 | * @param {object} product 182 | * @return {Node} 183 | */ 184 | function getPizzaTableRow(product) { 185 | let row = document.createElement('tr'), 186 | // titleCell = document.createElement('td'), 187 | // titleText = document.createTextNode(product.localeData['0'].title), 188 | priceCell = document.createElement('td'), 189 | beerCell = document.createElement('td'), 190 | priceText = document.createTextNode(product.prices['0'].currencyCode + ' ' + Number(product.prices['0'].valueMicros / 1000 / 1000).toFixed(2)), 191 | buttonCell = document.createElement('td'), 192 | button = document.createElement('a'), 193 | buttonText = document.createTextNode(chrome.i18n.getMessage('plansPageIWillSupportYouWith') + ' ' + getPizzaValue(product.sku)); 194 | // titleCell.className = 'title'; 195 | // titleCell.appendChild(titleText); 196 | // row.appendChild(titleCell); 197 | buttonCell.className = 'buyNow'; 198 | button.classList.add('button'); 199 | button.dataset.sku = product.sku; 200 | button.appendChild(buttonText); 201 | buttonCell.appendChild(button); 202 | row.appendChild(buttonCell); 203 | beerCell.appendChild(getPizzaIcons(product.sku)); 204 | row.appendChild(beerCell); 205 | priceCell.className = 'price'; 206 | priceCell.appendChild(priceText); 207 | row.appendChild(priceCell); 208 | return row; 209 | } 210 | 211 | /** 212 | * Show status message 213 | * 214 | * @param {string} status 215 | * @param {string} statusCode 216 | */ 217 | function setStatus(status = '', statusCode = 'information') { 218 | let statusElement = document.getElementById('status'); 219 | if (status === '') { 220 | statusElement.className = 'hidden'; 221 | } else { 222 | while (statusElement.firstChild) { 223 | statusElement.removeChild(statusElement.firstChild); 224 | } 225 | statusElement.className = ''; 226 | statusElement.classList.add('status', statusCode); 227 | statusElement.appendChild(document.createTextNode(status)); 228 | } 229 | } 230 | 231 | function addLicenseDataToProduct(license) { 232 | document.querySelectorAll('.buyNow .button').forEach(function(element) { 233 | if (element.dataset.sku === license.sku) { 234 | while (element.firstChild) { 235 | element.removeChild(element.firstChild); 236 | } 237 | element.appendChild(document.createTextNode(chrome.i18n.getMessage('plansPageThankYou'))); 238 | element.className = 'currentPlan'; 239 | } 240 | }); 241 | } 242 | 243 | function onLicenseUpdate(response) { 244 | // console.log('onLicenseUpdate', response); 245 | var activeLicense, 246 | licenses = response.response.details; 247 | var count = licenses.length; 248 | for (var i = 0; i < count; i++) { 249 | var license = licenses[i]; 250 | if (validProducts.includes(license.sku)) { 251 | activeLicense = license; 252 | addLicenseDataToProduct(license); 253 | } 254 | } 255 | chrome.runtime.getBackgroundPage(function(backgroundPage) { 256 | // console.log(activeLicense); 257 | backgroundPage.activeLicense = activeLicense; 258 | }); 259 | setStatus(); 260 | } 261 | 262 | function onLicenseUpdateFailed(response) { 263 | // console.log('onLicenseUpdateFailed', response); 264 | setStatus(chrome.i18n.getMessage('buyErrorRetrievingPurchasedProducts'), 'error'); 265 | } 266 | 267 | /***************************************************************************** 268 | * Get the list of purchased products from the Chrome Web Store 269 | *****************************************************************************/ 270 | function getLicenses() { 271 | // console.log('google.payments.inapp.getPurchases'); 272 | setStatus(chrome.i18n.getMessage('buyStatusRetrievingPurchasedProducts') + '...'); 273 | google.payments.inapp.getPurchases({ 274 | 'parameters': {'env': 'prod'}, 275 | 'success': onLicenseUpdate, 276 | 'failure': onLicenseUpdateFailed 277 | }); 278 | } 279 | 280 | function onPurchase(purchase) { 281 | // console.log('onPurchase', purchase); 282 | var orderId = purchase.response.orderId; 283 | setStatus(chrome.i18n.getMessage('buyStatusPurchaseComplete') + ': ' + orderId, 'ok'); 284 | getLicenses(); 285 | } 286 | 287 | function onPurchaseFailed(purchase) { 288 | // console.log('onPurchaseFailed', purchase); 289 | var reason = purchase.response.errorType; 290 | setStatus(chrome.i18n.getMessage('buyErrorPurchaseFailed') + '. ' + reason, 'error'); 291 | } 292 | 293 | /** 294 | * Buy subscription 295 | * 296 | * @param {string} sku 297 | */ 298 | function buyProduct(sku) { 299 | // setStatus('Kicking off purchase flow for ' + sku); 300 | google.payments.inapp.buy({ 301 | parameters: {'env': 'prod'}, 302 | 'sku': sku, 303 | 'success': onPurchase, 304 | 'failure': onPurchaseFailed 305 | }); 306 | } 307 | 308 | function getProductBySku(products, sku) { 309 | let result = false; 310 | products.forEach(function(product) { 311 | if (product.sku === sku) { 312 | result = product; 313 | } 314 | }); 315 | return result; 316 | } 317 | 318 | function onSkuDetails(response) { 319 | if (response.response.details.inAppProducts.length) { 320 | let products = response.response.details.inAppProducts, 321 | subscriptionList = document.getElementById('subscriptionList'); 322 | products.forEach(function(product) { 323 | if (subscriptionPlans.includes(product.sku)) { 324 | subscriptionList.appendChild(getSubscriptionTableRow(product)); 325 | } 326 | }); 327 | document.getElementById('subscriptionList').querySelectorAll('.buyNow .button').forEach(function(element) { 328 | element.addEventListener('click', function(event) { 329 | buyProduct(event.target.dataset.sku); 330 | }); 331 | }); 332 | 333 | // Beer plans 334 | let beerList = document.getElementById('beerList'); 335 | beerPlans.forEach(function(sku) { 336 | let product = getProductBySku(products, sku); 337 | if (product) { 338 | beerList.appendChild(getBeerTableRow(product)); 339 | } 340 | }); 341 | document.getElementById('beerList').querySelectorAll('.buyNow .button').forEach(function(element) { 342 | element.addEventListener('click', function(event) { 343 | buyProduct(event.target.dataset.sku); 344 | }); 345 | }); 346 | 347 | // Pizza plans 348 | let pizzaList = document.getElementById('pizzaList'); 349 | pizzaPlans.forEach(function(sku) { 350 | let product = getProductBySku(products, sku); 351 | if (product) { 352 | pizzaList.appendChild(getPizzaTableRow(product)); 353 | } 354 | }); 355 | document.getElementById('pizzaList').querySelectorAll('.buyNow .button').forEach(function(element) { 356 | element.addEventListener('click', function(event) { 357 | buyProduct(event.target.dataset.sku); 358 | }); 359 | }); 360 | } 361 | setStatus(); 362 | getLicenses(); 363 | } 364 | 365 | function onSkuDetailsFailed(response) { 366 | console.log('onSkuDetailsFailed', response); 367 | setStatus(chrome.i18n.getMessage('buyErrorRetrievingProducts') + '. (' + response.response.errorType + ')', 'error'); 368 | } 369 | 370 | function getProductList() { 371 | setStatus(chrome.i18n.getMessage('buyStatusRetrievingProducts') + '...'); 372 | google.payments.inapp.getSkuDetails({ 373 | 'parameters': {env: "prod"}, 374 | 'success': onSkuDetails, 375 | 'failure': onSkuDetailsFailed 376 | }); 377 | } 378 | 379 | getProductList(); 380 | -------------------------------------------------------------------------------- /Resources/Templates/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "description": "The description of the extension", 4 | "message": "" 5 | }, 6 | "extensionName": { 7 | "description": "The name of the extension", 8 | "message": "" 9 | }, 10 | "extensionNameShort": { 11 | "description": "The short name of the extension", 12 | "message": "" 13 | }, 14 | // Option menu names 15 | "optionsDisplayName": { 16 | "description": "Menu title for options page", 17 | "message": "" 18 | }, 19 | "aboutDisplayName": { 20 | "description": "Menu title for about page", 21 | "message": "" 22 | }, 23 | "plansDisplayName": { 24 | "description": "Menu title for 'Enable extra options' page", 25 | "message": "" 26 | }, 27 | // Options page 28 | "buttonAdd": { 29 | "description": "Add button text", 30 | "message": "" 31 | }, 32 | "buttonOptions": { 33 | "description": "Options page button text", 34 | "message": "" 35 | }, 36 | // Options page : Display options 37 | "optionsPageDisplayOptions": { 38 | "description": "Display options", 39 | "message": "" 40 | }, 41 | "optionsPageDisplayOptionsPressEscapeToHidePanels": { 42 | "description": "Press the ESC key to hide panels.", 43 | "message": "" 44 | }, 45 | "optionsPageDisplayOptionsAutoHide": { 46 | "description": "Press the ESC key to hide panels.", 47 | "message": "" 48 | }, 49 | "optionsPageDisplayOptionsShowIn": { 50 | "description": "___Show in___ [mode]", 51 | "message": "" 52 | }, 53 | "renderModeNormal": { 54 | "description": "Show in [___normal___]", 55 | "message": "" 56 | }, 57 | "renderModeMicro": { 58 | "description": "Show in [___micro___]", 59 | "message": "" 60 | }, 61 | "renderModeDisabled": { 62 | "description": "Show in [___disabled___]", 63 | "message": "" 64 | }, 65 | "optionsPageDisplayOptionsModeInThe": { 66 | "description": "Show in [mode] ___mode, in the___", 67 | "message": "" 68 | }, 69 | "locationTopLeftCorner": { 70 | "description": "mode, in the [___top left corner___]", 71 | "message": "" 72 | }, 73 | "locationTopRightCorner": { 74 | "description": "mode, in the [___top right corner___]", 75 | "message": "" 76 | }, 77 | "locationBottomLeftCorner": { 78 | "description": "mode, in the [___bottom left corner___]", 79 | "message": "" 80 | }, 81 | "locationBottomRightCorner": { 82 | "description": "mode, in the [___bottom right corner___]", 83 | "message": "" 84 | }, 85 | "optionsPageDisplayOptionsModeUsingA": { 86 | "description": "mode, in the [bottom right corner] ___using a___", 87 | "message": "" 88 | }, 89 | "themeDark": { 90 | "description": "using a [___dark theme___]", 91 | "message": "" 92 | }, 93 | "themeLight": { 94 | "description": "using a [___light theme___]", 95 | "message": "" 96 | }, 97 | "optionsPageDisplayOptionsAndShowThe": { 98 | "description": "using a [light theme] ___and show the___ [x] most recent requests", 99 | "message": "" 100 | }, 101 | "optionsPageDisplayOptionsMostRecentRequests": { 102 | "description": "using a [light theme] and show the [x] ___most recent requests___", 103 | "message": "" 104 | }, 105 | "doAutoHidePanels": { 106 | "description": "[___Do auto-hide panels___] after [x] seconds", 107 | "message": "" 108 | }, 109 | "doNotAutoHidePanels": { 110 | "description": "[___Do not auto-hide panels___] after [x] seconds", 111 | "message": "" 112 | }, 113 | "optionsPageDisplayOptionsAutoHideAfter": { 114 | "description": "[Do auto-hide panels] ___ after___ [x] seconds", 115 | "message": "" 116 | }, 117 | "optionsPageDisplayOptionsAutoHideSeconds": { 118 | "description": "[Do auto-hide panels] after [x] ___seconds___", 119 | "message": "" 120 | }, 121 | // Options page : Hide request headers 122 | "optionsPageHideRequestHeaders": { 123 | "description": "Hide request headers", 124 | "message": "" 125 | }, 126 | "optionsPageHideRequestHeadersDescription": { 127 | "description": "Request headers (or patterns thereof) that will not be displayed.", 128 | "message": "" 129 | }, 130 | // Options page : Hide response headers 131 | "optionsPageHideResponseHeaders": { 132 | "description": "Hide response headers", 133 | "message": "" 134 | }, 135 | "optionsPageHideResponseHeadersDescription": { 136 | "description": "Response headers (or patterns thereof) that will not be displayed.", 137 | "message": "" 138 | }, 139 | // Options page : Headers to show in Micro mode 140 | "optionsPageMicroModeHeaders": { 141 | "description": "Headers to show in Micro mode", 142 | "message": "" 143 | }, 144 | "optionsPageMicroModeHeadersDescription": { 145 | "description": "Response headers (or patterns thereof) that will be shown in micro mode.", 146 | "message": "" 147 | }, 148 | // Options page : Strings to highlight 149 | "optionsPageStringsToHightlight": { 150 | "description": "Strings to highlight", 151 | "message": "" 152 | }, 153 | "optionsPageStringsToHightlightDescription": { 154 | "description": "Headers (or patterns thereof) that will be", 155 | "message": "" 156 | }, 157 | "optionsPageStringsToHightlightDescriptionHighlighted": { 158 | "description": "Headers (or patterns thereof) that will be ___highlighted___", 159 | "message": "" 160 | }, 161 | // Plans page 162 | "plansPageTitle": { 163 | "description": "Enable extra options", 164 | "message": "" 165 | }, 166 | "plansPageYouCan": { 167 | "description": "___You can___ test all these great features every first 15 minutes of every hour:", 168 | "message": "" 169 | }, 170 | "plansPageTest": { 171 | "description": "You can ___test___ all these great features every first 15 minutes of every hour:", 172 | "message": "" 173 | }, 174 | "plansPageTheseFeatures": { 175 | "description": "You can test ___all these great features___ every first 15 minutes of every hour:", 176 | "message": "" 177 | }, 178 | "plansPageEveryFirst": { 179 | "description": "You can test all these great features ___every first 15 minutes___ of every hour:", 180 | "message": "" 181 | }, 182 | "plansPageOfEveryHour": { 183 | "description": "You can test all these great features every first 15 minutes ___of every hour___:", 184 | "message": "" 185 | }, 186 | "plansPageOptionServerIp": { 187 | "description": "Server IP address", 188 | "message": "" 189 | }, 190 | "plansPageOptionSubFrameRequests": { 191 | "description": "Sub-frame requests", 192 | "message": "" 193 | }, 194 | "plansPageOptionXhrRequests": { 195 | "description": "XML HTTP Requests (XHR / AJAX)", 196 | "message": "" 197 | }, 198 | "plansPageOptionRequestTimes": { 199 | "description": "Request times: time to headers received, time to first byte and time to complete", 200 | "message": "" 201 | }, 202 | "plansPageOptionFilterBar": { 203 | "description": "Use the filter bar to filter the headers", 204 | "message": "" 205 | }, 206 | "plansPageOneTimeBeerSupport": { 207 | "description": "One-time beer support", 208 | "message": "" 209 | }, 210 | "plansPageOneTimePizzaSupport": { 211 | "description": "One-time pizza support", 212 | "message": "" 213 | }, 214 | "plansPageSubscriptions": { 215 | "description": "Subscriptions", 216 | "message": "" 217 | }, 218 | "plansPageMangeSubscriptions": { 219 | "description": "Manage subscriptions", 220 | "message": "" 221 | }, 222 | "plansPageEnableFeatures": { 223 | "description": "___If you want to enable these features___ permanently, please support further development by donating me some beer/pizza:", 224 | "message": "" 225 | }, 226 | "plansPageEnableFeaturesPermanently": { 227 | "description": "If you want to enable these features ___permanently___, please support further development by donating me some beer/pizza:", 228 | "message": "" 229 | }, 230 | "plansPageEnableFeaturesPleaseSupport": { 231 | "description": "If you want to enable these features permanently___, please support further development by donating me some beer/pizza___:", 232 | "message": "" 233 | }, 234 | "plansPageIWillSupportYouWith": { 235 | "description": "___I'll support you with___ [x] pizzas", 236 | "message": "" 237 | }, 238 | "plansPageBeers": { 239 | "description": "I'll support you with [x] ___beers___", 240 | "message": "" 241 | }, 242 | "plansPagePizzas": { 243 | "description": "I'll support you with [x] ___pizzas___", 244 | "message": "" 245 | }, 246 | "plansPageThankYou": { 247 | "description": "Thank you for your support ;-)", 248 | "message": "" 249 | }, 250 | // Buy flow 251 | "buyStatusRetrievingProducts": { 252 | "description": "Retreiving available products", 253 | "message": "" 254 | }, 255 | "buyErrorRetrievingProducts": { 256 | "description": "Error retrieving product list", 257 | "message": "" 258 | }, 259 | "buyStatusRetrievingPurchasedProducts": { 260 | "description": "Retreiving list of purchased products", 261 | "message": "" 262 | }, 263 | "buyErrorRetrievingPurchasedProducts": { 264 | "description": "Error retreiving list of purchased products", 265 | "message": "" 266 | }, 267 | "buyStatusPurchaseComplete": { 268 | "description": "Purchase completed. Order ID", 269 | "message": "" 270 | }, 271 | "buyErrorPurchaseFailed": { 272 | "description": "Purchase failed", 273 | "message": "" 274 | }, 275 | // About page 276 | "aboutPageContent": { 277 | "description": "Section of text describing Me", 278 | "message": "" 279 | }, 280 | "popupDefaultMessage": { 281 | "description": "The default message shown in the browserAction popup", 282 | "message": "" 283 | }, 284 | // Popup and content messages 285 | "contentMessagesEnableExtraOptions": { 286 | "description": "enable XHR and sub-frame requests", 287 | "message": "" 288 | }, 289 | "contentMessagesPressEscToClosePanels": { 290 | "description": "[esc] closes these panels. Click to toggle panels.", 291 | "message": "" 292 | }, 293 | "contentMessagesCache": { 294 | "description": "cache", 295 | "message": "" 296 | }, 297 | "contentMessagesCached": { 298 | "description": "cached", 299 | "message": "" 300 | }, 301 | "contentMessagesFromDiskCache": { 302 | "description": "from disk cache", 303 | "message": "" 304 | }, 305 | "contentMessagesHeadersReceived": { 306 | "description": "shorthand for headers received: ___headers recv___", 307 | "message": "" 308 | }, 309 | "contentMessagesTimeToFirstByte": { 310 | "description": "shorthand for time to first byte: ___first byte___", 311 | "message": "" 312 | }, 313 | "contentMessagesRequestComplete": { 314 | "description": "shorthand for request completed: ___complete___", 315 | "message": "" 316 | }, 317 | "contentMessagesPanelTitleRequest": { 318 | "description": "Request", 319 | "message": "" 320 | }, 321 | "contentMessagesPanelTitleResponse": { 322 | "description": "Response", 323 | "message": "" 324 | }, 325 | "contentMessagesPanelTitleCookies": { 326 | "description": "Cookies", 327 | "message": "" 328 | }, 329 | "contentMessagesPanelTitleFormData": { 330 | "description": "Form Data", 331 | "message": "" 332 | }, 333 | "contentMessagesPanelTitleQuery": { 334 | "description": "Query", 335 | "message": "" 336 | }, 337 | "contentMessagesFilterBarFilter": { 338 | "description": "Filter", 339 | "message": "" 340 | }, 341 | "contentMessagesFilterBarRegex": { 342 | "description": "Regex", 343 | "message": "" 344 | }, 345 | "contentMessagesRequestTypeDoc": { 346 | "description": "Doc", 347 | "message": "" 348 | }, 349 | "contentMessagesRequestTypeFrame": { 350 | "description": "Frame", 351 | "message": "" 352 | }, 353 | "contentMessagesRequestTypeXhr": { 354 | "description": "XHR", 355 | "message": "" 356 | }, 357 | "contentMessagesProEnableServerIp": { 358 | "description": "enable server IP", 359 | "message": "" 360 | }, 361 | "contentMessagesProEnableResponseTimes": { 362 | "description": "enable response times", 363 | "message": "" 364 | } 365 | } 366 | -------------------------------------------------------------------------------- /Resources/Templates/strings.txt: -------------------------------------------------------------------------------- 1 | HTTP Header Spy enables you to inspect request- response headers and cookies right after page load with no extra clicks. 2 | HTTP Header Spy 3 | HTTP Headers 4 | Options 5 | About 6 | Enable extra options 7 | Add 8 | Options page 9 | Display options 10 | Press the ESC key to hide panels. 11 | When auto-hide is enabled, the filter bar will not be shown. 12 | Show in 13 | normal 14 | micro 15 | disabled 16 | mode, in the 17 | top left corner 18 | top right corner 19 | bottom left corner 20 | bottom right corner 21 | using a 22 | dark theme 23 | light theme 24 | and show the 25 | most recent requests 26 | Do auto-hide panels 27 | Do not auto-hide panels 28 | after 29 | seconds 30 | Hide request headers 31 | Request headers (or patterns thereof) that will not be displayed. 32 | Hide response headers 33 | Response headers (or patterns thereof) that will not be displayed. 34 | Headers to show in Micro mode 35 | Response headers (or patterns thereof) that will be shown in micro mode. 36 | Strings to highlight 37 | Headers (or patterns thereof) that will be 38 | highlighted 39 | Enable extra options 40 | You can 41 | test 42 | all these extra features 43 | every first 15 minutes 44 | of every hour 45 | Server IP address 46 | Sub-frame requests 47 | XML HTTP Requests (XHR / AJAX) 48 | Request times: time to headers received, time to first byte and time to complete 49 | Use the filter bar to filter the headers 50 | One-time beer support 51 | One-time pizza support 52 | Subscriptions 53 | Manage subscriptions 54 | If you want to enable these features 55 | permanently 56 | , please support further development by donating me some beer/pizza 57 | I'll support you with 58 | beers 59 | pizzas 60 | Thank you for your support ;-) 61 | Retrieving available products 62 | Error retrieving product list 63 | Retrieving list of purchased products 64 | Error retrieving list of purchased products 65 | Purchase completed. Order ID 66 | Purchase failed 67 | My name is Michiel Roos. I had a lot of fun developing this add-on. I also learnt a lot. I hope you find it usefull and enjoy using it. If you have any suggetstions or constructive criticism, please contact me. 68 | No headers were captured yet. Please reload this tab to see the headers. 69 | enable XHR and sub-frame requests 70 | [esc] closes these panels. Click to toggle panels. 71 | cache 72 | cached 73 | from disk cache 74 | headers recv 75 | first byte 76 | complete 77 | Request 78 | Response 79 | Cookies 80 | Form Data 81 | Query 82 | Filter 83 | Regex 84 | Doc 85 | Frame 86 | XHR 87 | enable server IP 88 | enable response times 89 | -------------------------------------------------------------------------------- /_locales/en/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "description": "The description of the extension", 4 | "message": "HTTP Header Spy enables you to inspect request- response headers and cookies right after page load with no extra clicks." 5 | }, 6 | "extensionName": { 7 | "description": "The name of the extension", 8 | "message": "HTTP Header Spy" 9 | }, 10 | "extensionNameShort": { 11 | "description": "The short name of the extension", 12 | "message": "HTTP Headers" 13 | }, 14 | // Option menu names 15 | "optionsDisplayName": { 16 | "description": "Menu title for options page", 17 | "message": "Options" 18 | }, 19 | "aboutDisplayName": { 20 | "description": "Menu title for about page", 21 | "message": "About" 22 | }, 23 | "plansDisplayName": { 24 | "description": "Menu title for 'Enable extra options' page", 25 | "message": "Enable extra options" 26 | }, 27 | // Options page 28 | "buttonAdd": { 29 | "description": "Add button text", 30 | "message": "Add" 31 | }, 32 | "buttonOptions": { 33 | "description": "Options page button text", 34 | "message": "Options page" 35 | }, 36 | // Options page : Display options 37 | "optionsPageDisplayOptions": { 38 | "description": "Display options", 39 | "message": "Display options" 40 | }, 41 | "optionsPageDisplayOptionsPressEscapeToHidePanels": { 42 | "description": "Press the ESC key to hide panels.", 43 | "message": "Press the ESC key to hide panels." 44 | }, 45 | "optionsPageDisplayOptionsAutoHide": { 46 | "description": "Press the ESC key to hide panels.", 47 | "message": "When auto-hide is enabled, the filter bar will not be shown." 48 | }, 49 | "optionsPageDisplayOptionsShowIn": { 50 | "description": "___Show in___ [mode]", 51 | "message": "Show in" 52 | }, 53 | "renderModeNormal": { 54 | "description": "Show in [___normal___]", 55 | "message": "normal" 56 | }, 57 | "renderModeMicro": { 58 | "description": "Show in [___micro___]", 59 | "message": "micro" 60 | }, 61 | "renderModeDisabled": { 62 | "description": "Show in [___disabled___]", 63 | "message": "disabled" 64 | }, 65 | "optionsPageDisplayOptionsModeInThe": { 66 | "description": "Show in [mode] ___mode, in the___", 67 | "message": "mode, in the" 68 | }, 69 | "locationTopLeftCorner": { 70 | "description": "mode, in the [___top left corner___]", 71 | "message": "top left corner" 72 | }, 73 | "locationTopRightCorner": { 74 | "description": "mode, in the [___top right corner___]", 75 | "message": "top right corner" 76 | }, 77 | "locationBottomLeftCorner": { 78 | "description": "mode, in the [___bottom left corner___]", 79 | "message": "bottom left corner" 80 | }, 81 | "locationBottomRightCorner": { 82 | "description": "mode, in the [___bottom right corner___]", 83 | "message": "bottom right corner" 84 | }, 85 | "optionsPageDisplayOptionsModeUsingA": { 86 | "description": "mode, in the [bottom right corner] ___using a___", 87 | "message": "using a" 88 | }, 89 | "themeDark": { 90 | "description": "using a [___dark theme___]", 91 | "message": "dark theme" 92 | }, 93 | "themeLight": { 94 | "description": "using a [___light theme___]", 95 | "message": "light theme" 96 | }, 97 | "optionsPageDisplayOptionsAndShowThe": { 98 | "description": "using a [light theme] ___and show the___ [x] most recent requests", 99 | "message": "and show the" 100 | }, 101 | "optionsPageDisplayOptionsMostRecentRequests": { 102 | "description": "using a [light theme] and show the [x] ___most recent requests___", 103 | "message": "most recent requests" 104 | }, 105 | "doAutoHidePanels": { 106 | "description": "[___Do auto-hide panels___] after [x] seconds", 107 | "message": "Do auto-hide panels" 108 | }, 109 | "doNotAutoHidePanels": { 110 | "description": "[___Do not auto-hide panels___] after [x] seconds", 111 | "message": "Do not auto-hide panels" 112 | }, 113 | "optionsPageDisplayOptionsAutoHideAfter": { 114 | "description": "[Do auto-hide panels] ___ after___ [x] seconds", 115 | "message": "after" 116 | }, 117 | "optionsPageDisplayOptionsAutoHideSeconds": { 118 | "description": "[Do auto-hide panels] after [x] ___seconds___", 119 | "message": "seconds" 120 | }, 121 | // Options page : Hide request headers 122 | "optionsPageHideRequestHeaders": { 123 | "description": "Hide request headers", 124 | "message": "Hide request headers" 125 | }, 126 | "optionsPageHideRequestHeadersDescription": { 127 | "description": "Request headers (or patterns thereof) that will not be displayed.", 128 | "message": "Request headers (or patterns thereof) that will not be displayed." 129 | }, 130 | // Options page : Hide response headers 131 | "optionsPageHideResponseHeaders": { 132 | "description": "Hide response headers", 133 | "message": "Hide response headers" 134 | }, 135 | "optionsPageHideResponseHeadersDescription": { 136 | "description": "Response headers (or patterns thereof) that will not be displayed.", 137 | "message": "Response headers (or patterns thereof) that will not be displayed." 138 | }, 139 | // Options page : Headers to show in Micro mode 140 | "optionsPageMicroModeHeaders": { 141 | "description": "Headers to show in Micro mode", 142 | "message": "Headers to show in Micro mode" 143 | }, 144 | "optionsPageMicroModeHeadersDescription": { 145 | "description": "Response headers (or patterns thereof) that will be shown in micro mode.", 146 | "message": "Response headers (or patterns thereof) that will be shown in micro mode." 147 | }, 148 | // Options page : Strings to highlight 149 | "optionsPageStringsToHightlight": { 150 | "description": "Strings to highlight", 151 | "message": "Strings to highlight" 152 | }, 153 | "optionsPageStringsToHightlightDescription": { 154 | "description": "Headers (or patterns thereof) that will be", 155 | "message": "Headers (or patterns thereof) that will be" 156 | }, 157 | "optionsPageStringsToHightlightDescriptionHighlighted": { 158 | "description": "Headers (or patterns thereof) that will be ___highlighted___", 159 | "message": "highlighted" 160 | }, 161 | // Plans page 162 | "plansPageTitle": { 163 | "description": "Enable extra options", 164 | "message": "Enable extra options" 165 | }, 166 | "plansPageYouCan": { 167 | "description": "___You can___ test all these great features every first 15 minutes of every hour:", 168 | "message": "You can" 169 | }, 170 | "plansPageTest": { 171 | "description": "You can ___test___ all these great features every first 15 minutes of every hour:", 172 | "message": "test" 173 | }, 174 | "plansPageTheseFeatures": { 175 | "description": "You can test ___all these great features___ every first 15 minutes of every hour:", 176 | "message": "all these extra features" 177 | }, 178 | "plansPageEveryFirst": { 179 | "description": "You can test all these great features ___every first 15 minutes___ of every hour:", 180 | "message": "every first 15 minutes" 181 | }, 182 | "plansPageOfEveryHour": { 183 | "description": "You can test all these great features every first 15 minutes ___of every hour___:", 184 | "message": "of every hour" 185 | }, 186 | "plansPageOptionServerIp": { 187 | "description": "Server IP address", 188 | "message": "Server IP address" 189 | }, 190 | "plansPageOptionSubFrameRequests": { 191 | "description": "Sub-frame requests", 192 | "message": "Sub-frame requests" 193 | }, 194 | "plansPageOptionXhrRequests": { 195 | "description": "XML HTTP Requests (XHR / AJAX)", 196 | "message": "XML HTTP Requests (XHR / AJAX)" 197 | }, 198 | "plansPageOptionRequestTimes": { 199 | "description": "Request times: time to headers received, time to first byte and time to complete", 200 | "message": "Request times: time to headers received, time to first byte and time to complete" 201 | }, 202 | "plansPageOptionFilterBar": { 203 | "description": "Use the filter bar to filter the headers", 204 | "message": "Use the filter bar to filter the headers" 205 | }, 206 | "plansPageOneTimeBeerSupport": { 207 | "description": "One-time beer support", 208 | "message": "One-time beer support" 209 | }, 210 | "plansPageOneTimePizzaSupport": { 211 | "description": "One-time pizza support", 212 | "message": "One-time pizza support" 213 | }, 214 | "plansPageSubscriptions": { 215 | "description": "Subscriptions", 216 | "message": "Subscriptions" 217 | }, 218 | "plansPageMangeSubscriptions": { 219 | "description": "Manage subscriptions", 220 | "message": "Manage subscriptions" 221 | }, 222 | "plansPageEnableFeatures": { 223 | "description": "___If you want to enable these features___ permanently, please support further development by donating me some beer/pizza:", 224 | "message": "If you want to enable these features" 225 | }, 226 | "plansPageEnableFeaturesPermanently": { 227 | "description": "If you want to enable these features ___permanently___, please support further development by donating me some beer/pizza:", 228 | "message": "permanently" 229 | }, 230 | "plansPageEnableFeaturesPleaseSupport": { 231 | "description": "If you want to enable these features permanently___, please support further development by donating me some beer/pizza___:", 232 | "message": ", please support further development by donating me some beer/pizza" 233 | }, 234 | "plansPageIWillSupportYouWith": { 235 | "description": "___I'll support you with___ [x] pizzas", 236 | "message": "I'll support you with" 237 | }, 238 | "plansPageBeers": { 239 | "description": "I'll support you with [x] ___beers___", 240 | "message": "beers" 241 | }, 242 | "plansPagePizzas": { 243 | "description": "I'll support you with [x] ___pizzas___", 244 | "message": "pizzas" 245 | }, 246 | "plansPageThankYou": { 247 | "description": "Thank you for your support ;-)", 248 | "message": "Thank you for your support ;-)" 249 | }, 250 | // Buy flow 251 | "buyStatusRetrievingProducts": { 252 | "description": "Retreiving available products", 253 | "message": "Retrieving available products" 254 | }, 255 | "buyErrorRetrievingProducts": { 256 | "description": "Error retrieving product list", 257 | "message": "Error retrieving product list" 258 | }, 259 | "buyStatusRetrievingPurchasedProducts": { 260 | "description": "Retreiving list of purchased products", 261 | "message": "Retrieving list of purchased products" 262 | }, 263 | "buyErrorRetrievingPurchasedProducts": { 264 | "description": "Error retreiving list of purchased products", 265 | "message": "Error retrieving list of purchased products" 266 | }, 267 | "buyStatusPurchaseComplete": { 268 | "description": "Purchase completed. Order ID", 269 | "message": "Purchase completed. Order ID" 270 | }, 271 | "buyErrorPurchaseFailed": { 272 | "description": "Purchase failed", 273 | "message": "Purchase failed" 274 | }, 275 | // About page 276 | "aboutPageContent": { 277 | "description": "Section of text describing Me", 278 | "message": "My name is Michiel Roos. I had a lot of fun developing this add-on. I also learnt a lot. I hope you find it usefull and enjoy using it. If you have any suggetstions or constructive criticism, please contact me." 279 | }, 280 | "aboutPageContentConsiderDonation": { 281 | "description": "Do you enjoy this extension? Please consider a donation:", 282 | "message": "Do you enjoy this extension? Please consider a donation:" 283 | }, 284 | "aboutPageContentSayThanks": { 285 | "description": "Section of text: say thanks", 286 | "message": "Say Thanks ;-)" 287 | }, 288 | // Thanks page 289 | "thanksDisplayName": { 290 | "description": "Thank you!", 291 | "message": "Thank you!" 292 | }, 293 | "thanksPageThankYou": { 294 | "description": "Thank you message", 295 | "message": "Thank you!" 296 | }, 297 | "thanksPagePatreon": { 298 | "description": "Become a patreon on", 299 | "message": "Become a patreon on" 300 | }, 301 | "thanksPagePaypal": { 302 | "description": "Make a donation via", 303 | "message": "Make a donation via" 304 | }, 305 | "popupDefaultMessage": { 306 | "description": "The default message shown in the browserAction popup", 307 | "message": "No headers were captured yet. Please reload this tab to see the headers." 308 | }, 309 | // Popup and content messages 310 | "contentMessagesEnableExtraOptions": { 311 | "description": "enable XHR and sub-frame requests", 312 | "message": "enable XHR and sub-frame requests" 313 | }, 314 | "contentMessagesPressEscToClosePanels": { 315 | "description": "[esc] closes these panels. Click to toggle panels.", 316 | "message": "[esc] closes these panels. Click to toggle panels." 317 | }, 318 | "contentMessagesCache": { 319 | "description": "cache", 320 | "message": "cache" 321 | }, 322 | "contentMessagesCached": { 323 | "description": "cached", 324 | "message": "cached" 325 | }, 326 | "contentMessagesFromDiskCache": { 327 | "description": "from disk cache", 328 | "message": "from disk cache" 329 | }, 330 | "contentMessagesHeadersReceived": { 331 | "description": "shorthand for headers received: ___headers recv___", 332 | "message": "headers recv" 333 | }, 334 | "contentMessagesTimeToFirstByte": { 335 | "description": "shorthand for time to first byte: ___first byte___", 336 | "message": "first byte" 337 | }, 338 | "contentMessagesRequestComplete": { 339 | "description": "shorthand for request completed: ___complete___", 340 | "message": "complete" 341 | }, 342 | "contentMessagesPanelTitleRequest": { 343 | "description": "Request", 344 | "message": "Request" 345 | }, 346 | "contentMessagesPanelTitleResponse": { 347 | "description": "Response", 348 | "message": "Response" 349 | }, 350 | "contentMessagesPanelTitleCookies": { 351 | "description": "Cookies", 352 | "message": "Cookies" 353 | }, 354 | "contentMessagesPanelTitleFormData": { 355 | "description": "Form Data", 356 | "message": "Form Data" 357 | }, 358 | "contentMessagesPanelTitleQuery": { 359 | "description": "Query", 360 | "message": "Query" 361 | }, 362 | "contentMessagesFilterBarFilter": { 363 | "description": "Filter", 364 | "message": "Filter" 365 | }, 366 | "contentMessagesFilterBarRegex": { 367 | "description": "Regex", 368 | "message": "Regex" 369 | }, 370 | "contentMessagesRequestTypeDoc": { 371 | "description": "Doc", 372 | "message": "Doc" 373 | }, 374 | "contentMessagesRequestTypeFrame": { 375 | "description": "Frame", 376 | "message": "Frame" 377 | }, 378 | "contentMessagesRequestTypeXhr": { 379 | "description": "XHR", 380 | "message": "XHR" 381 | }, 382 | "contentMessagesProEnableServerIp": { 383 | "description": "enable server IP", 384 | "message": "enable server IP" 385 | }, 386 | "contentMessagesProEnableResponseTimes": { 387 | "description": "enable response times", 388 | "message": "enable response times" 389 | } 390 | } 391 | -------------------------------------------------------------------------------- /_locales/es/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "description": "The description of the extension", 4 | "message": "HTTP Header Spy le permite inspeccionar los encabezados y las cookies de respuesta de solicitud después de la carga de la página sin clics adicionales." 5 | }, 6 | "extensionName": { 7 | "description": "The name of the extension", 8 | "message": "Espía HTTP" 9 | }, 10 | "extensionNameShort": { 11 | "description": "The short name of the extension", 12 | "message": "Encabezados HTTP" 13 | }, 14 | // Option menu names 15 | "optionsDisplayName": { 16 | "description": "Menu title for options page", 17 | "message": "Opciones" 18 | }, 19 | "aboutDisplayName": { 20 | "description": "Menu title for about page", 21 | "message": "Acerca de" 22 | }, 23 | "plansDisplayName": { 24 | "description": "Menu title for 'Enable extra options' page", 25 | "message": "Habilitar opciones adicionales" 26 | }, 27 | // Options page 28 | "buttonAdd": { 29 | "description": "Add button text", 30 | "message": "Añadir" 31 | }, 32 | "buttonOptions": { 33 | "description": "Options page button text", 34 | "message": "Página Opciones" 35 | }, 36 | // Options page : Display options 37 | "optionsPageDisplayOptions": { 38 | "description": "Display options", 39 | "message": "opciones de pantalla" 40 | }, 41 | "optionsPageDisplayOptionsPressEscapeToHidePanels": { 42 | "description": "Press the ESC key to hide panels.", 43 | "message": "Presione la tecla ESC para ocultar los paneles." 44 | }, 45 | "optionsPageDisplayOptionsAutoHide": { 46 | "description": "Press the ESC key to hide panels.", 47 | "message": "Cuando se activa la función de ocultar automáticamente, no se mostrará la barra de filtro." 48 | }, 49 | "optionsPageDisplayOptionsShowIn": { 50 | "description": "___Show in___ [mode]", 51 | "message": "Mostrar en" 52 | }, 53 | "renderModeNormal": { 54 | "description": "Show in [___normal___]", 55 | "message": "normal" 56 | }, 57 | "renderModeMicro": { 58 | "description": "Show in [___micro___]", 59 | "message": "micro" 60 | }, 61 | "renderModeDisabled": { 62 | "description": "Show in [___disabled___]", 63 | "message": "discapacitado" 64 | }, 65 | "optionsPageDisplayOptionsModeInThe": { 66 | "description": "Show in [mode] ___mode, in the___", 67 | "message": "Modo, en el" 68 | }, 69 | "locationTopLeftCorner": { 70 | "description": "mode, in the [___top left corner___]", 71 | "message": "esquina superior izquierda" 72 | }, 73 | "locationTopRightCorner": { 74 | "description": "mode, in the [___top right corner___]", 75 | "message": "esquina superior derecha" 76 | }, 77 | "locationBottomLeftCorner": { 78 | "description": "mode, in the [___bottom left corner___]", 79 | "message": "esquina izquierda inferior" 80 | }, 81 | "locationBottomRightCorner": { 82 | "description": "mode, in the [___bottom right corner___]", 83 | "message": "esquina inferior derecha" 84 | }, 85 | "optionsPageDisplayOptionsModeUsingA": { 86 | "description": "mode, in the [bottom right corner] ___using a___", 87 | "message": "usando un" 88 | }, 89 | "themeDark": { 90 | "description": "using a [___dark theme___]", 91 | "message": "Tema oscuro" 92 | }, 93 | "themeLight": { 94 | "description": "using a [___light theme___]", 95 | "message": "Tema ligero" 96 | }, 97 | "optionsPageDisplayOptionsAndShowThe": { 98 | "description": "using a [light theme] ___and show the___ [x] most recent requests", 99 | "message": "Y muestre el" 100 | }, 101 | "optionsPageDisplayOptionsMostRecentRequests": { 102 | "description": "using a [light theme] and show the [x] ___most recent requests___", 103 | "message": "Solicitudes más recientes" 104 | }, 105 | "doAutoHidePanels": { 106 | "description": "[___Do auto-hide panels___] after [x] seconds", 107 | "message": "Hacer paneles de auto-ocultar" 108 | }, 109 | "doNotAutoHidePanels": { 110 | "description": "[___Do not auto-hide panels___] after [x] seconds", 111 | "message": "No ocultar automáticamente los paneles" 112 | }, 113 | "optionsPageDisplayOptionsAutoHideAfter": { 114 | "description": "[Do auto-hide panels] ___ after___ [x] seconds", 115 | "message": "después" 116 | }, 117 | "optionsPageDisplayOptionsAutoHideSeconds": { 118 | "description": "[Do auto-hide panels] after [x] ___seconds___", 119 | "message": "segundos" 120 | }, 121 | // Options page : Hide request headers 122 | "optionsPageHideRequestHeaders": { 123 | "description": "Hide request headers", 124 | "message": "Ocultar encabezados de solicitud" 125 | }, 126 | "optionsPageHideRequestHeadersDescription": { 127 | "description": "Request headers (or patterns thereof) that will not be displayed.", 128 | "message": "Solicite encabezados (o modelos de los mismos) que no se mostrarán." 129 | }, 130 | // Options page : Hide response headers 131 | "optionsPageHideResponseHeaders": { 132 | "description": "Hide response headers", 133 | "message": "Ocultar encabezados de respuesta" 134 | }, 135 | "optionsPageHideResponseHeadersDescription": { 136 | "description": "Response headers (or patterns thereof) that will not be displayed.", 137 | "message": "Cabeceras de respuesta (o patrones del mismo) que no se mostrarán." 138 | }, 139 | // Options page : Headers to show in Micro mode 140 | "optionsPageMicroModeHeaders": { 141 | "description": "Headers to show in Micro mode", 142 | "message": "Encabezados para mostrar en modo Micro" 143 | }, 144 | "optionsPageMicroModeHeadersDescription": { 145 | "description": "Response headers (or patterns thereof) that will be shown in micro mode.", 146 | "message": "Cabeceras de respuesta (o patrones del mismo) que se mostrarán en modo micro." 147 | }, 148 | // Options page : Strings to highlight 149 | "optionsPageStringsToHightlight": { 150 | "description": "Strings to highlight", 151 | "message": "Cuerdas para resaltar" 152 | }, 153 | "optionsPageStringsToHightlightDescription": { 154 | "description": "Headers (or patterns thereof) that will be", 155 | "message": "Los encabezados (o patrones del mismo) que" 156 | }, 157 | "optionsPageStringsToHightlightDescriptionHighlighted": { 158 | "description": "Headers (or patterns thereof) that will be ___highlighted___", 159 | "message": "destacado" 160 | }, 161 | // Plans page 162 | "plansPageTitle": { 163 | "description": "Enable extra options", 164 | "message": "Habilitar opciones adicionales" 165 | }, 166 | "plansPageYouCan": { 167 | "description": "___You can___ test all these great features every first 15 minutes of every hour:", 168 | "message": "Usted puede" 169 | }, 170 | "plansPageTest": { 171 | "description": "You can ___test___ all these great features every first 15 minutes of every hour:", 172 | "message": "prueba" 173 | }, 174 | "plansPageTheseFeatures": { 175 | "description": "You can test ___all these great features___ every first 15 minutes of every hour:", 176 | "message": "todas estas características adicionales" 177 | }, 178 | "plansPageEveryFirst": { 179 | "description": "You can test all these great features ___every first 15 minutes___ of every hour:", 180 | "message": "cada 15 minutos" 181 | }, 182 | "plansPageOfEveryHour": { 183 | "description": "You can test all these great features every first 15 minutes ___of every hour___:", 184 | "message": "cada hora" 185 | }, 186 | "plansPageOptionServerIp": { 187 | "description": "Server IP address", 188 | "message": "Dirección IP del servidor" 189 | }, 190 | "plansPageOptionSubFrameRequests": { 191 | "description": "Sub-frame requests", 192 | "message": "Solicitudes secundarias" 193 | }, 194 | "plansPageOptionXhrRequests": { 195 | "description": "XML HTTP Requests (XHR / AJAX)", 196 | "message": "Solicitud HTTP XML (XHR / AJAX)" 197 | }, 198 | "plansPageOptionRequestTimes": { 199 | "description": "Request times: time to headers received, time to first byte and time to complete", 200 | "message": "Tiempo de solicitud: tiempo para los encabezados recibidos, tiempo hasta el primer byte y tiempo para completar" 201 | }, 202 | "plansPageOptionFilterBar": { 203 | "description": "Use the filter bar to filter the headers", 204 | "message": "Utilice la barra de filtros para filtrar los encabezados" 205 | }, 206 | "plansPageOneTimeBeerSupport": { 207 | "description": "One-time beer support", 208 | "message": "Soporte de cerveza de una sola vez" 209 | }, 210 | "plansPageOneTimePizzaSupport": { 211 | "description": "One-time pizza support", 212 | "message": "Soporte de una sola vez para pizza" 213 | }, 214 | "plansPageSubscriptions": { 215 | "description": "Subscriptions", 216 | "message": "Suscripciones" 217 | }, 218 | "plansPageMangeSubscriptions": { 219 | "description": "Manage subscriptions", 220 | "message": "Administrar Suscripciones" 221 | }, 222 | "plansPageEnableFeatures": { 223 | "description": "___If you want to enable these features___ permanently, please support further development by donating me some beer/pizza:", 224 | "message": "Si desea habilitar estas funciones" 225 | }, 226 | "plansPageEnableFeaturesPermanently": { 227 | "description": "If you want to enable these features ___permanently___, please support further development by donating me some beer/pizza:", 228 | "message": "permanentemente" 229 | }, 230 | "plansPageEnableFeaturesPleaseSupport": { 231 | "description": "If you want to enable these features permanently___, please support further development by donating me some beer/pizza___:", 232 | "message": ", Por favor apoye el desarrollo adicional donándome un poco de cerveza / pizza" 233 | }, 234 | "plansPageIWillSupportYouWith": { 235 | "description": "___I'll support you with___ [x] pizzas", 236 | "message": "Te apoyaré con" 237 | }, 238 | "plansPageBeers": { 239 | "description": "I'll support you with [x] ___beers___", 240 | "message": "Cervezas" 241 | }, 242 | "plansPagePizzas": { 243 | "description": "I'll support you with [x] ___pizzas___", 244 | "message": "Pizzas" 245 | }, 246 | "plansPageThankYou": { 247 | "description": "Thank you for your support ;-)", 248 | "message": "Gracias por tu apoyo ;-)" 249 | }, 250 | // Buy flow 251 | "buyStatusRetrievingProducts": { 252 | "description": "Retreiving available products", 253 | "message": "Recuperación de productos disponibles" 254 | }, 255 | "buyErrorRetrievingProducts": { 256 | "description": "Error retrieving product list", 257 | "message": "Error al recuperar la lista de productos" 258 | }, 259 | "buyStatusRetrievingPurchasedProducts": { 260 | "description": "Retreiving list of purchased products", 261 | "message": "Recuperación de la lista de productos comprados" 262 | }, 263 | "buyErrorRetrievingPurchasedProducts": { 264 | "description": "Error retreiving list of purchased products", 265 | "message": "Error al recuperar la lista de productos comprados" 266 | }, 267 | "buyStatusPurchaseComplete": { 268 | "description": "Purchase completed. Order ID", 269 | "message": "Compra terminada. Solicitar ID" 270 | }, 271 | "buyErrorPurchaseFailed": { 272 | "description": "Purchase failed", 273 | "message": "La compra falló" 274 | }, 275 | // About page 276 | "aboutPageContent": { 277 | "description": "Section of text describing Me", 278 | "message": "Mi nombre es Michiel Roos. Me divertí mucho desarrollando este complemento. También aprendí mucho. Espero que lo encuentre útil y disfrutar de su uso. Si tiene sugerencias o críticas constructivas, póngase en contacto conmigo." 279 | }, 280 | "popupDefaultMessage": { 281 | "description": "The default message shown in the browserAction popup", 282 | "message": "Todavía no se capturaron cabeceras. Vuelva a cargar esta pestaña para ver los encabezados." 283 | }, 284 | // Popup and content messages 285 | "contentMessagesEnableExtraOptions": { 286 | "description": "enable XHR and sub-frame requests", 287 | "message": "Habilitar las solicitudes de XHR y subtrama" 288 | }, 289 | "contentMessagesPressEscToClosePanels": { 290 | "description": "[esc] closes these panels. Click to toggle panels.", 291 | "message": "[Esc] cierra estos paneles. Haga clic para alternar entre paneles." 292 | }, 293 | "contentMessagesCache": { 294 | "description": "cache", 295 | "message": "cache" 296 | }, 297 | "contentMessagesCached": { 298 | "description": "cached", 299 | "message": "en caché" 300 | }, 301 | "contentMessagesFromDiskCache": { 302 | "description": "from disk cache", 303 | "message": "desde caché de disco" 304 | }, 305 | "contentMessagesHeadersReceived": { 306 | "description": "shorthand for headers received: ___headers recv___", 307 | "message": "encabezados recv" 308 | }, 309 | "contentMessagesTimeToFirstByte": { 310 | "description": "shorthand for time to first byte: ___first byte___", 311 | "message": "primer octeto" 312 | }, 313 | "contentMessagesRequestComplete": { 314 | "description": "shorthand for request completed: ___complete___", 315 | "message": "completar" 316 | }, 317 | "contentMessagesPanelTitleRequest": { 318 | "description": "Request", 319 | "message": "Solicitud" 320 | }, 321 | "contentMessagesPanelTitleResponse": { 322 | "description": "Response", 323 | "message": "Respuesta" 324 | }, 325 | "contentMessagesPanelTitleCookies": { 326 | "description": "Cookies", 327 | "message": "Galletas" 328 | }, 329 | "contentMessagesPanelTitleFormData": { 330 | "description": "Form Data", 331 | "message": "Datos del formulario" 332 | }, 333 | "contentMessagesPanelTitleQuery": { 334 | "description": "Query", 335 | "message": "Consulta" 336 | }, 337 | "contentMessagesFilterBarFilter": { 338 | "description": "Filter", 339 | "message": "Filtrar" 340 | }, 341 | "contentMessagesFilterBarRegex": { 342 | "description": "Regex", 343 | "message": "Regex" 344 | }, 345 | "contentMessagesRequestTypeDoc": { 346 | "description": "Doc", 347 | "message": "Doc" 348 | }, 349 | "contentMessagesRequestTypeFrame": { 350 | "description": "Frame", 351 | "message": "Marco" 352 | }, 353 | "contentMessagesRequestTypeXhr": { 354 | "description": "XHR", 355 | "message": "XHR" 356 | }, 357 | "contentMessagesProEnableServerIp": { 358 | "description": "enable server IP", 359 | "message": "habilitar IP del servidor" 360 | }, 361 | "contentMessagesProEnableResponseTimes": { 362 | "description": "enable response times", 363 | "message": "habilitar tiempos de respuesta" 364 | } 365 | } 366 | -------------------------------------------------------------------------------- /_locales/hi/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "description": "The description of the extension", 4 | "message": "HTTP जासूस आप सही कोई अतिरिक्त क्लिक के साथ पेज लोड करने के बाद अनुरोध प्रतिक्रिया हेडर और कुकीज़ का निरीक्षण करने के लिए सक्षम बनाता है।" 5 | }, 6 | "extensionName": { 7 | "description": "The name of the extension", 8 | "message": "HTTP स्पाई" 9 | }, 10 | "extensionNameShort": { 11 | "description": "The short name of the extension", 12 | "message": "HTTP शीर्ष" 13 | }, 14 | // Option menu names 15 | "optionsDisplayName": { 16 | "description": "Menu title for options page", 17 | "message": "विकल्प" 18 | }, 19 | "aboutDisplayName": { 20 | "description": "Menu title for about page", 21 | "message": "के बारे में" 22 | }, 23 | "plansDisplayName": { 24 | "description": "Menu title for 'Enable extra options' page", 25 | "message": "अतिरिक्त विकल्प सक्षम करें" 26 | }, 27 | // Options page 28 | "buttonAdd": { 29 | "description": "Add button text", 30 | "message": "जोड़ना" 31 | }, 32 | "buttonOptions": { 33 | "description": "Options page button text", 34 | "message": "विकल्प पृष्ठ" 35 | }, 36 | // Options page : Display options 37 | "optionsPageDisplayOptions": { 38 | "description": "Display options", 39 | "message": "प्रदर्शित विकल्प" 40 | }, 41 | "optionsPageDisplayOptionsPressEscapeToHidePanels": { 42 | "description": "Press the ESC key to hide panels.", 43 | "message": "पैनलों को छिपाने के लिए ईएससी कुंजी दबाएँ।" 44 | }, 45 | "optionsPageDisplayOptionsAutoHide": { 46 | "description": "Press the ESC key to hide panels.", 47 | "message": "जब ऑटो छिपाने सक्षम है, फिल्टर बार नहीं दिखाया जाएगा।" 48 | }, 49 | "optionsPageDisplayOptionsShowIn": { 50 | "description": "___Show in___ [mode]", 51 | "message": "में दिखाएं" 52 | }, 53 | "renderModeNormal": { 54 | "description": "Show in [___normal___]", 55 | "message": "साधारण" 56 | }, 57 | "renderModeMicro": { 58 | "description": "Show in [___micro___]", 59 | "message": "सूक्ष्म" 60 | }, 61 | "renderModeDisabled": { 62 | "description": "Show in [___disabled___]", 63 | "message": "विकलांग" 64 | }, 65 | "optionsPageDisplayOptionsModeInThe": { 66 | "description": "Show in [mode] ___mode, in the___", 67 | "message": "मोड, में" 68 | }, 69 | "locationTopLeftCorner": { 70 | "description": "mode, in the [___top left corner___]", 71 | "message": "ऊपरी बायां कोना" 72 | }, 73 | "locationTopRightCorner": { 74 | "description": "mode, in the [___top right corner___]", 75 | "message": "ऊपरी दायां किनारा" 76 | }, 77 | "locationBottomLeftCorner": { 78 | "description": "mode, in the [___bottom left corner___]", 79 | "message": "निचला बायां किनारा" 80 | }, 81 | "locationBottomRightCorner": { 82 | "description": "mode, in the [___bottom right corner___]", 83 | "message": "नीचे का दांया कोना" 84 | }, 85 | "optionsPageDisplayOptionsModeUsingA": { 86 | "description": "mode, in the [bottom right corner] ___using a___", 87 | "message": "इसका उपयोग करना" 88 | }, 89 | "themeDark": { 90 | "description": "using a [___dark theme___]", 91 | "message": "अंधेरे विषय" 92 | }, 93 | "themeLight": { 94 | "description": "using a [___light theme___]", 95 | "message": "प्रकाश विषय" 96 | }, 97 | "optionsPageDisplayOptionsAndShowThe": { 98 | "description": "using a [light theme] ___and show the___ [x] most recent requests", 99 | "message": "और दिखाने के लिए" 100 | }, 101 | "optionsPageDisplayOptionsMostRecentRequests": { 102 | "description": "using a [light theme] and show the [x] ___most recent requests___", 103 | "message": "सबसे हाल ही में अनुरोधों" 104 | }, 105 | "doAutoHidePanels": { 106 | "description": "[___Do auto-hide panels___] after [x] seconds", 107 | "message": "ऑटो छिपाने के पैनल" 108 | }, 109 | "doNotAutoHidePanels": { 110 | "description": "[___Do not auto-hide panels___] after [x] seconds", 111 | "message": "पैनलों ऑटो छिपा नहीं है" 112 | }, 113 | "optionsPageDisplayOptionsAutoHideAfter": { 114 | "description": "[Do auto-hide panels] ___ after___ [x] seconds", 115 | "message": "बाद" 116 | }, 117 | "optionsPageDisplayOptionsAutoHideSeconds": { 118 | "description": "[Do auto-hide panels] after [x] ___seconds___", 119 | "message": "सेकंड" 120 | }, 121 | // Options page : Hide request headers 122 | "optionsPageHideRequestHeaders": { 123 | "description": "Hide request headers", 124 | "message": "मिटायें अनुरोध हेडर" 125 | }, 126 | "optionsPageHideRequestHeadersDescription": { 127 | "description": "Request headers (or patterns thereof) that will not be displayed.", 128 | "message": "अनुरोध हेडर (या पैटर्न क्या है) कि प्रदर्शित नहीं किया जाएगा।" 129 | }, 130 | // Options page : Hide response headers 131 | "optionsPageHideResponseHeaders": { 132 | "description": "Hide response headers", 133 | "message": "प्रतिक्रिया हेडर छुपाएं" 134 | }, 135 | "optionsPageHideResponseHeadersDescription": { 136 | "description": "Response headers (or patterns thereof) that will not be displayed.", 137 | "message": "प्रतिक्रिया हेडर (या पैटर्न क्या है) कि प्रदर्शित नहीं किया जाएगा।" 138 | }, 139 | // Options page : Headers to show in Micro mode 140 | "optionsPageMicroModeHeaders": { 141 | "description": "Headers to show in Micro mode", 142 | "message": "हेडर माइक्रो मोड में दिखाने के लिए" 143 | }, 144 | "optionsPageMicroModeHeadersDescription": { 145 | "description": "Response headers (or patterns thereof) that will be shown in micro mode.", 146 | "message": "प्रतिक्रिया हेडर (या पैटर्न क्या है) कि माइक्रो मोड में दिखाया जाएगा।" 147 | }, 148 | // Options page : Strings to highlight 149 | "optionsPageStringsToHightlight": { 150 | "description": "Strings to highlight", 151 | "message": "स्ट्रिंग्स को उजागर करने के लिए" 152 | }, 153 | "optionsPageStringsToHightlightDescription": { 154 | "description": "Headers (or patterns thereof) that will be", 155 | "message": "हेडर (या उसके पैटर्न) कि हो जाएगा" 156 | }, 157 | "optionsPageStringsToHightlightDescriptionHighlighted": { 158 | "description": "Headers (or patterns thereof) that will be ___highlighted___", 159 | "message": "प्रकाश डाला" 160 | }, 161 | // Plans page 162 | "plansPageTitle": { 163 | "description": "Enable extra options", 164 | "message": "अतिरिक्त विकल्प सक्षम करें" 165 | }, 166 | "plansPageYouCan": { 167 | "description": "___You can___ test all these great features every first 15 minutes of every hour:", 168 | "message": "आप ऐसा कर सकते हैं" 169 | }, 170 | "plansPageTest": { 171 | "description": "You can ___test___ all these great features every first 15 minutes of every hour:", 172 | "message": "परीक्षण" 173 | }, 174 | "plansPageTheseFeatures": { 175 | "description": "You can test ___all these great features___ every first 15 minutes of every hour:", 176 | "message": "इन सभी अतिरिक्त सुविधाओं" 177 | }, 178 | "plansPageEveryFirst": { 179 | "description": "You can test all these great features ___every first 15 minutes___ of every hour:", 180 | "message": "हर 15 मिनट पहले" 181 | }, 182 | "plansPageOfEveryHour": { 183 | "description": "You can test all these great features every first 15 minutes ___of every hour___:", 184 | "message": "हर घंटे के" 185 | }, 186 | "plansPageOptionServerIp": { 187 | "description": "Server IP address", 188 | "message": "सर्वर आईपी पता" 189 | }, 190 | "plansPageOptionSubFrameRequests": { 191 | "description": "Sub-frame requests", 192 | "message": "उप फ्रेम अनुरोधों" 193 | }, 194 | "plansPageOptionXhrRequests": { 195 | "description": "XML HTTP Requests (XHR / AJAX)", 196 | "message": "एक्सएमएल HTTP अनुरोध (एक्सएचआर / AJAX)" 197 | }, 198 | "plansPageOptionRequestTimes": { 199 | "description": "Request times: time to headers received, time to first byte and time to complete", 200 | "message": "अनुरोध बार में: हेडर के लिए समय पहली बाइट और पूरा करने के लिए समय के लिए प्राप्त किया, समय" 201 | }, 202 | "plansPageOptionFilterBar": { 203 | "description": "Use the filter bar to filter the headers", 204 | "message": "हेडर फिल्टर करने के लिए फिल्टर पट्टी का उपयोग करें" 205 | }, 206 | "plansPageOneTimeBeerSupport": { 207 | "description": "One-time beer support", 208 | "message": "एक बार बीयर समर्थन" 209 | }, 210 | "plansPageOneTimePizzaSupport": { 211 | "description": "One-time pizza support", 212 | "message": "एक बार पिज्जा समर्थन" 213 | }, 214 | "plansPageSubscriptions": { 215 | "description": "Subscriptions", 216 | "message": "सदस्यताएँ" 217 | }, 218 | "plansPageMangeSubscriptions": { 219 | "description": "Manage subscriptions", 220 | "message": "सदस्यता प्रबंधित करें" 221 | }, 222 | "plansPageEnableFeatures": { 223 | "description": "___If you want to enable these features___ permanently, please support further development by donating me some beer/pizza:", 224 | "message": "यदि आप इन सुविधाओं सक्षम करना चाहते हैं" 225 | }, 226 | "plansPageEnableFeaturesPermanently": { 227 | "description": "If you want to enable these features ___permanently___, please support further development by donating me some beer/pizza:", 228 | "message": "स्थायी रूप से" 229 | }, 230 | "plansPageEnableFeaturesPleaseSupport": { 231 | "description": "If you want to enable these features permanently___, please support further development by donating me some beer/pizza___:", 232 | "message": ", मुझे कुछ बियर / पिज्जा दान करके आगे विकास का समर्थन करें" 233 | }, 234 | "plansPageIWillSupportYouWith": { 235 | "description": "___I'll support you with___ [x] pizzas", 236 | "message": "मैं के साथ आप का समर्थन करेंगे" 237 | }, 238 | "plansPageBeers": { 239 | "description": "I'll support you with [x] ___beers___", 240 | "message": "बियर" 241 | }, 242 | "plansPagePizzas": { 243 | "description": "I'll support you with [x] ___pizzas___", 244 | "message": "पिज्जा" 245 | }, 246 | "plansPageThankYou": { 247 | "description": "Thank you for your support ;-)", 248 | "message": "आपके सहयोग के लिए धन्यवाद ;-)" 249 | }, 250 | // Buy flow 251 | "buyStatusRetrievingProducts": { 252 | "description": "Retreiving available products", 253 | "message": "उपलब्ध उत्पादों को पुन: प्राप्त" 254 | }, 255 | "buyErrorRetrievingProducts": { 256 | "description": "Error retrieving product list", 257 | "message": "उत्पाद की सूची को पुन: प्राप्त त्रुटि" 258 | }, 259 | "buyStatusRetrievingPurchasedProducts": { 260 | "description": "Retreiving list of purchased products", 261 | "message": "खरीदे गए उत्पादों का पुन: प्राप्त सूची" 262 | }, 263 | "buyErrorRetrievingPurchasedProducts": { 264 | "description": "Error retreiving list of purchased products", 265 | "message": "खरीदे गए उत्पादों की सूची को पुन: प्राप्त त्रुटि" 266 | }, 267 | "buyStatusPurchaseComplete": { 268 | "description": "Purchase completed. Order ID", 269 | "message": "क्रय पूरा किया। आदेश आईडी" 270 | }, 271 | "buyErrorPurchaseFailed": { 272 | "description": "Purchase failed", 273 | "message": "खरीद विफल रही" 274 | }, 275 | // About page 276 | "aboutPageContent": { 277 | "description": "Section of text describing Me", 278 | "message": "ेरा नाम Michiel Roos है। मैं इस ऐड-ऑन के विकास का एक बहुत मज़ा किया था। मैं भी बहुत कुछ सीखा। मैं आपको यह उपयोगी है और इसे उपयोग का आनंद मिल उम्मीद है। आप किसी भी suggetstions या रचनात्मक आलोचना है, तो कृपया मुझसे संपर्क करें।" 279 | }, 280 | "popupDefaultMessage": { 281 | "description": "The default message shown in the browserAction popup", 282 | "message": "कोई हेडर अभी तक कब्जा कर लिया गया। हेडर को देखने के लिए इस टैब को फिर से लोड करें।" 283 | }, 284 | // Popup and content messages 285 | "contentMessagesEnableExtraOptions": { 286 | "description": "enable XHR and sub-frame requests", 287 | "message": "एक्सएचआर और उप फ्रेम अनुरोधों सक्षम" 288 | }, 289 | "contentMessagesPressEscToClosePanels": { 290 | "description": "[esc] closes these panels. Click to toggle panels.", 291 | "message": "[ईएससी] इन पैनलों बंद कर देता है। पैनलों को चालू करने के लिए क्लिक करें।" 292 | }, 293 | "contentMessagesCache": { 294 | "description": "cache", 295 | "message": "कैश" 296 | }, 297 | "contentMessagesCached": { 298 | "description": "cached", 299 | "message": "कैश्ड" 300 | }, 301 | "contentMessagesFromDiskCache": { 302 | "description": "from disk cache", 303 | "message": "डिस्क कैश से" 304 | }, 305 | "contentMessagesHeadersReceived": { 306 | "description": "shorthand for headers received: ___headers recv___", 307 | "message": "हेडर recv" 308 | }, 309 | "contentMessagesTimeToFirstByte": { 310 | "description": "shorthand for time to first byte: ___first byte___", 311 | "message": "पहली बाइट" 312 | }, 313 | "contentMessagesRequestComplete": { 314 | "description": "shorthand for request completed: ___complete___", 315 | "message": "पूर्ण" 316 | }, 317 | "contentMessagesPanelTitleRequest": { 318 | "description": "Request", 319 | "message": "निवेदन" 320 | }, 321 | "contentMessagesPanelTitleResponse": { 322 | "description": "Response", 323 | "message": "प्रतिक्रिया" 324 | }, 325 | "contentMessagesPanelTitleCookies": { 326 | "description": "Cookies", 327 | "message": "कुकीज़" 328 | }, 329 | "contentMessagesPanelTitleFormData": { 330 | "description": "Form Data", 331 | "message": "प्रपत्र डेटा" 332 | }, 333 | "contentMessagesPanelTitleQuery": { 334 | "description": "Query", 335 | "message": "सवाल" 336 | }, 337 | "contentMessagesFilterBarFilter": { 338 | "description": "Filter", 339 | "message": "फ़िल्टर" 340 | }, 341 | "contentMessagesFilterBarRegex": { 342 | "description": "Regex", 343 | "message": "regex" 344 | }, 345 | "contentMessagesRequestTypeDoc": { 346 | "description": "Doc", 347 | "message": "डॉक्टर" 348 | }, 349 | "contentMessagesRequestTypeFrame": { 350 | "description": "Frame", 351 | "message": "ढांचा" 352 | }, 353 | "contentMessagesRequestTypeXhr": { 354 | "description": "XHR", 355 | "message": "एक्सएचआर" 356 | }, 357 | "contentMessagesProEnableServerIp": { 358 | "description": "enable server IP", 359 | "message": "सर्वर आईपी सक्षम" 360 | }, 361 | "contentMessagesProEnableResponseTimes": { 362 | "description": "enable response times", 363 | "message": "प्रतिक्रिया समय के लिए सक्षम" 364 | } 365 | } 366 | -------------------------------------------------------------------------------- /_locales/nl/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "description": "The description of the extension", 4 | "message": "HTTP Header Spy toont de request-, response headers en cookies direct nadat een pagina geladen is, zonder extra klikken." 5 | }, 6 | "extensionName": { 7 | "description": "The name of the extension", 8 | "message": "HTTP Header Spy" 9 | }, 10 | "extensionNameShort": { 11 | "description": "The short name of the extension", 12 | "message": "HTTP Headers" 13 | }, 14 | // Option menu names 15 | "optionsDisplayName": { 16 | "description": "Menu title for options page", 17 | "message": "Opties" 18 | }, 19 | "aboutDisplayName": { 20 | "description": "Menu title for about page", 21 | "message": "Over" 22 | }, 23 | "plansDisplayName": { 24 | "description": "Menu title for 'Enable extra options' page", 25 | "message": "Schakel extra opties in" 26 | }, 27 | // Options page 28 | "buttonAdd": { 29 | "description": "Add button text", 30 | "message": "Toevoegen" 31 | }, 32 | "buttonOptions": { 33 | "description": "Options page button text", 34 | "message": "Opties pagina" 35 | }, 36 | // Options page : Display options 37 | "optionsPageDisplayOptions": { 38 | "description": "Display options", 39 | "message": "Weergave opties" 40 | }, 41 | "optionsPageDisplayOptionsPressEscapeToHidePanels": { 42 | "description": "Press the ESC key to hide panels.", 43 | "message": "Gebruik de ESC toets om panelen te verbergen." 44 | }, 45 | "optionsPageDisplayOptionsAutoHide": { 46 | "description": "Press the ESC key to hide panels.", 47 | "message": "Als automatisch verbergen is ingeschakeld, wordt de filter balk niet getoond." 48 | }, 49 | "optionsPageDisplayOptionsShowIn": { 50 | "description": "___Show in___ [mode]", 51 | "message": "Toon in" 52 | }, 53 | "renderModeNormal": { 54 | "description": "Show in [___normal___]", 55 | "message": "normale" 56 | }, 57 | "renderModeMicro": { 58 | "description": "Show in [___micro___]", 59 | "message": "micro" 60 | }, 61 | "renderModeDisabled": { 62 | "description": "Show in [___disabled___]", 63 | "message": "uitgeschakelde" 64 | }, 65 | "optionsPageDisplayOptionsModeInThe": { 66 | "description": "Show in [mode] ___mode, in the___", 67 | "message": "modus, in de" 68 | }, 69 | "locationTopLeftCorner": { 70 | "description": "mode, in the [___top left corner___]", 71 | "message": "linkerbovenhoek" 72 | }, 73 | "locationTopRightCorner": { 74 | "description": "mode, in the [___top right corner___]", 75 | "message": "rechterbovenhoek" 76 | }, 77 | "locationBottomLeftCorner": { 78 | "description": "mode, in the [___bottom left corner___]", 79 | "message": "linkeronderhoek" 80 | }, 81 | "locationBottomRightCorner": { 82 | "description": "mode, in the [___bottom right corner___]", 83 | "message": "rechteronderhoek" 84 | }, 85 | "optionsPageDisplayOptionsModeUsingA": { 86 | "description": "mode, in the [bottom right corner] ___using a___", 87 | "message": "gebruik een" 88 | }, 89 | "themeDark": { 90 | "description": "using a [___dark theme___]", 91 | "message": "donker thema" 92 | }, 93 | "themeLight": { 94 | "description": "using a [___light theme___]", 95 | "message": "licht thema" 96 | }, 97 | "optionsPageDisplayOptionsAndShowThe": { 98 | "description": "using a [light theme] ___and show the___ [x] most recent requests", 99 | "message": "en toon de" 100 | }, 101 | "optionsPageDisplayOptionsMostRecentRequests": { 102 | "description": "using a [light theme] and show the [x] ___most recent requests___", 103 | "message": "meest recente requests" 104 | }, 105 | "doAutoHidePanels": { 106 | "description": "[___Do auto-hide panels___] after [x] seconds", 107 | "message": "Verberg panelen" 108 | }, 109 | "doNotAutoHidePanels": { 110 | "description": "[___Do not auto-hide panels___] after [x] seconds", 111 | "message": "Verberg panelen niet" 112 | }, 113 | "optionsPageDisplayOptionsAutoHideAfter": { 114 | "description": "[Do auto-hide panels] ___ after___ [x] seconds", 115 | "message": "na" 116 | }, 117 | "optionsPageDisplayOptionsAutoHideSeconds": { 118 | "description": "[Do auto-hide panels] after [x] ___seconds___", 119 | "message": "seconden" 120 | }, 121 | // Options page : Hide request headers 122 | "optionsPageHideRequestHeaders": { 123 | "description": "Hide request headers", 124 | "message": "Verberg request headers" 125 | }, 126 | "optionsPageHideRequestHeadersDescription": { 127 | "description": "Request headers (or patterns thereof) that will not be displayed.", 128 | "message": "Request headers (of delen daarvan) die niet zullen worden getoond." 129 | }, 130 | // Options page : Hide response headers 131 | "optionsPageHideResponseHeaders": { 132 | "description": "Hide response headers", 133 | "message": "Verberg response headers" 134 | }, 135 | "optionsPageHideResponseHeadersDescription": { 136 | "description": "Response headers (or patterns thereof) that will not be displayed.", 137 | "message": "Response headers (of delen daarvan) die niet zullen worden getoond." 138 | }, 139 | // Options page : Headers to show in Micro mode 140 | "optionsPageMicroModeHeaders": { 141 | "description": "Headers to show in Micro mode", 142 | "message": "Headers die in Micro modus getoond worden" 143 | }, 144 | "optionsPageMicroModeHeadersDescription": { 145 | "description": "Response headers (or patterns thereof) that will be shown in micro mode.", 146 | "message": "Response headers (of delen daarvan) die zullen worden getoond in micro modus." 147 | }, 148 | // Options page : Strings to highlight 149 | "optionsPageStringsToHightlight": { 150 | "description": "Strings to highlight", 151 | "message": "Te markeren strings" 152 | }, 153 | "optionsPageStringsToHightlightDescription": { 154 | "description": "Headers (or patterns thereof) that will be", 155 | "message": "Headers (of delen daarvan) die zullen worden" 156 | }, 157 | "optionsPageStringsToHightlightDescriptionHighlighted": { 158 | "description": "Headers (or patterns thereof) that will be ___highlighted___", 159 | "message": "gemarkeerd" 160 | }, 161 | // Plans page 162 | "plansPageTitle": { 163 | "description": "Enable extra options", 164 | "message": "Schakel extra opties in" 165 | }, 166 | "plansPageYouCan": { 167 | "description": "___You can___ test all these great features every first 15 minutes of every hour:", 168 | "message": "Je kunt deze extra opties" 169 | }, 170 | "plansPageTest": { 171 | "description": "You can ___test___ all these great features every first 15 minutes of every hour:", 172 | "message": "testen" 173 | }, 174 | "plansPageTheseFeatures": { 175 | "description": "You can test ___all these great features___ every first 15 minutes of every hour:", 176 | "message": "tijdens" 177 | }, 178 | "plansPageEveryFirst": { 179 | "description": "You can test all these great features ___every first 15 minutes___ of every hour:", 180 | "message": "iedere eerste 15 minuten" 181 | }, 182 | "plansPageOfEveryHour": { 183 | "description": "You can test all these great features every first 15 minutes ___of every hour___:", 184 | "message": "van ieder uur" 185 | }, 186 | "plansPageOptionServerIp": { 187 | "description": "Server IP address", 188 | "message": "Server IP adres" 189 | }, 190 | "plansPageOptionSubFrameRequests": { 191 | "description": "Sub-frame requests", 192 | "message": "Sub-frame requests" 193 | }, 194 | "plansPageOptionXhrRequests": { 195 | "description": "XML HTTP Requests (XHR / AJAX)", 196 | "message": "XML HTTP Requests (XHR / AJAX)" 197 | }, 198 | "plansPageOptionRequestTimes": { 199 | "description": "Request times: time to headers received, time to first byte and time to complete", 200 | "message": "Request tijden: tijd tot ontvangen response headers, tijd tot eerste byte en tijd tot voltooiing" 201 | }, 202 | "plansPageOptionFilterBar": { 203 | "description": "Use the filter bar to filter the headers", 204 | "message": "Gebruik de filter-balk om headers te filteren" 205 | }, 206 | "plansPageOneTimeBeerSupport": { 207 | "description": "One-time beer support", 208 | "message": "Eenmalige bier donatie" 209 | }, 210 | "plansPageOneTimePizzaSupport": { 211 | "description": "One-time pizza support", 212 | "message": "Eenmalige pizza donatie" 213 | }, 214 | "plansPageSubscriptions": { 215 | "description": "Subscriptions", 216 | "message": "Abonnementen" 217 | }, 218 | "plansPageMangeSubscriptions": { 219 | "description": "Manage subscriptions", 220 | "message": "Betalingen beheer" 221 | }, 222 | "plansPageEnableFeatures": { 223 | "description": "___If you want to enable these features___ permanently, please support further development by donating me some beer/pizza:", 224 | "message": "Als je deze opties" 225 | }, 226 | "plansPageEnableFeaturesPermanently": { 227 | "description": "If you want to enable these features ___permanently___, please support further development by donating me some beer/pizza:", 228 | "message": "permanent" 229 | }, 230 | "plansPageEnableFeaturesPleaseSupport": { 231 | "description": "If you want to enable these features permanently___, please support further development by donating me some beer/pizza___:", 232 | "message": " wilt inschakelen, kun je verdere ontwikkeling ondersteunen door wat bier/pizza te doneren" 233 | }, 234 | "plansPageIWillSupportYouWith": { 235 | "description": "___I'll support you with___ [x] pizzas", 236 | "message": "Ik ondersteun je met" 237 | }, 238 | "plansPageBeers": { 239 | "description": "I'll support you with [x] ___beers___", 240 | "message": "biertjes" 241 | }, 242 | "plansPagePizzas": { 243 | "description": "I'll support you with [x] ___pizzas___", 244 | "message": "pizzas" 245 | }, 246 | "plansPageThankYou": { 247 | "description": "Thank you for your support ;-)", 248 | "message": "Bedankt voor je ondersteuning ;-)" 249 | }, 250 | // Buy flow 251 | "buyStatusRetrievingProducts": { 252 | "description": "Retreiving available products", 253 | "message": "Produkten ophalen" 254 | }, 255 | "buyErrorRetrievingProducts": { 256 | "description": "Error retrieving product list", 257 | "message": "Er is een fout opgetreden bij het ophalen van de produkten" 258 | }, 259 | "buyStatusRetrievingPurchasedProducts": { 260 | "description": "Retreiving list of purchased products", 261 | "message": "Produkten ophalen" 262 | }, 263 | "buyErrorRetrievingPurchasedProducts": { 264 | "description": "Error retreiving list of purchased products", 265 | "message": "Er is een fout opgetreden bij het ophalen van de produkten" 266 | }, 267 | "buyStatusPurchaseComplete": { 268 | "description": "Purchase completed. Order ID", 269 | "message": "Aankoop voltooid. Order id" 270 | }, 271 | "buyErrorPurchaseFailed": { 272 | "description": "Purchase failed", 273 | "message": "Aankoop mislukt" 274 | }, 275 | // About page 276 | "aboutPageContent": { 277 | "description": "Section of text describing Me", 278 | "message": "Mijn naam is Michiel Roos. Ik vond het leuk om deze add-on te ontwikkelen. Ik heb er veel van geleerd. Ik hoop dat je hem nuttig vindt en hem gebruikt met plezier. Als je suggesties of opbouwende kritiek hebt, neem dan contact met me op." 279 | }, 280 | "aboutPageContentConsiderDonation": { 281 | "description": "Do you enjoy this extension? Please consider a donation:", 282 | "message": "Heb je plezier van deze extensie, overweeg een donatie." 283 | }, 284 | "aboutPageContentSayThanks": { 285 | "description": "Section of text: say thanks", 286 | "message": "Zeg dankjewel ;-)" 287 | }, 288 | // Thanks page 289 | "thanksDisplayName": { 290 | "description": "Thank you!", 291 | "message": "Dank!" 292 | }, 293 | "thanksPageThankYou": { 294 | "description": "Thank you message", 295 | "message": "Dank!" 296 | }, 297 | "thanksPagePatreon": { 298 | "description": "Become a patreon on", 299 | "message": "Word patreon op" 300 | }, 301 | "thanksPagePaypal": { 302 | "description": "Make a donation via", 303 | "message": "Doneer via" 304 | }, 305 | "popupDefaultMessage": { 306 | "description": "The default message shown in the browserAction popup", 307 | "message": "Er zijn nog geen headers ontvangen. Ververs deze tab om de headers te zien." 308 | }, 309 | // Popup and content messages 310 | "contentMessagesEnableExtraOptions": { 311 | "description": "enable XHR and sub-frame requests", 312 | "message": "toon XHR en sub-frame requests" 313 | }, 314 | "contentMessagesPressEscToClosePanels": { 315 | "description": "[esc] closes these panels. Click to toggle panels.", 316 | "message": "[esc] sluit deze panelen. Klik om panelen te tonen / verbergen." 317 | }, 318 | "contentMessagesCache": { 319 | "description": "cache", 320 | "message": "cache" 321 | }, 322 | "contentMessagesCached": { 323 | "description": "cached", 324 | "message": "gecached" 325 | }, 326 | "contentMessagesFromDiskCache": { 327 | "description": "from disk cache", 328 | "message": "van schijf cache" 329 | }, 330 | "contentMessagesHeadersReceived": { 331 | "description": "shorthand for headers received: ___headers recv___", 332 | "message": "headers recv" 333 | }, 334 | "contentMessagesTimeToFirstByte": { 335 | "description": "shorthand for time to first byte: ___first byte___", 336 | "message": "first byte" 337 | }, 338 | "contentMessagesRequestComplete": { 339 | "description": "shorthand for request completed: ___complete___", 340 | "message": "complete" 341 | }, 342 | "contentMessagesPanelTitleRequest": { 343 | "description": "Request", 344 | "message": "Request" 345 | }, 346 | "contentMessagesPanelTitleResponse": { 347 | "description": "Response", 348 | "message": "Response" 349 | }, 350 | "contentMessagesPanelTitleCookies": { 351 | "description": "Cookies", 352 | "message": "Cookies" 353 | }, 354 | "contentMessagesPanelTitleFormData": { 355 | "description": "Form Data", 356 | "message": "Form Data" 357 | }, 358 | "contentMessagesPanelTitleQuery": { 359 | "description": "Query", 360 | "message": "Query" 361 | }, 362 | "contentMessagesFilterBarFilter": { 363 | "description": "Filter", 364 | "message": "Filter" 365 | }, 366 | "contentMessagesFilterBarRegex": { 367 | "description": "Regex", 368 | "message": "Regex" 369 | }, 370 | "contentMessagesRequestTypeDoc": { 371 | "description": "Doc", 372 | "message": "Doc" 373 | }, 374 | "contentMessagesRequestTypeFrame": { 375 | "description": "Frame", 376 | "message": "Frame" 377 | }, 378 | "contentMessagesRequestTypeXhr": { 379 | "description": "XHR", 380 | "message": "XHR" 381 | }, 382 | "contentMessagesProEnableServerIp": { 383 | "description": "enable server IP", 384 | "message": "toon server IP" 385 | }, 386 | "contentMessagesProEnableResponseTimes": { 387 | "description": "enable response times", 388 | "message": "toon response tijden" 389 | } 390 | } 391 | -------------------------------------------------------------------------------- /_locales/ru/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "description": "The description of the extension", 4 | "message": "HTTP Header Spy позволяет проверять request- заголовки ответа и печенье сразу после загрузки страницы без дополнительных кликов." 5 | }, 6 | "extensionName": { 7 | "description": "The name of the extension", 8 | "message": "HTTP Header Spy" 9 | }, 10 | "extensionNameShort": { 11 | "description": "The short name of the extension", 12 | "message": "Заголовки HTTP" 13 | }, 14 | // Option menu names 15 | "optionsDisplayName": { 16 | "description": "Menu title for options page", 17 | "message": "Опции" 18 | }, 19 | "aboutDisplayName": { 20 | "description": "Menu title for about page", 21 | "message": "О" 22 | }, 23 | "plansDisplayName": { 24 | "description": "Menu title for 'Enable extra options' page", 25 | "message": "Включить дополнительные опции" 26 | }, 27 | // Options page 28 | "buttonAdd": { 29 | "description": "Add button text", 30 | "message": "Добавить" 31 | }, 32 | "buttonOptions": { 33 | "description": "Options page button text", 34 | "message": "Параметры сканирования" 35 | }, 36 | // Options page : Display options 37 | "optionsPageDisplayOptions": { 38 | "description": "Display options", 39 | "message": "Параметры отображения" 40 | }, 41 | "optionsPageDisplayOptionsPressEscapeToHidePanels": { 42 | "description": "Press the ESC key to hide panels.", 43 | "message": "Нажмите клавишу ESC, чтобы скрыть панели." 44 | }, 45 | "optionsPageDisplayOptionsAutoHide": { 46 | "description": "Press the ESC key to hide panels.", 47 | "message": "Если включена функция автоматического скрытия включена, строка фильтра не будет отображаться." 48 | }, 49 | "optionsPageDisplayOptionsShowIn": { 50 | "description": "___Show in___ [mode]", 51 | "message": "Показывать в" 52 | }, 53 | "renderModeNormal": { 54 | "description": "Show in [___normal___]", 55 | "message": "нормальный" 56 | }, 57 | "renderModeMicro": { 58 | "description": "Show in [___micro___]", 59 | "message": "микро" 60 | }, 61 | "renderModeDisabled": { 62 | "description": "Show in [___disabled___]", 63 | "message": "отключено" 64 | }, 65 | "optionsPageDisplayOptionsModeInThe": { 66 | "description": "Show in [mode] ___mode, in the___", 67 | "message": "Режим, в" 68 | }, 69 | "locationTopLeftCorner": { 70 | "description": "mode, in the [___top left corner___]", 71 | "message": "верхний левый угол" 72 | }, 73 | "locationTopRightCorner": { 74 | "description": "mode, in the [___top right corner___]", 75 | "message": "в правом верхнем углу" 76 | }, 77 | "locationBottomLeftCorner": { 78 | "description": "mode, in the [___bottom left corner___]", 79 | "message": "левый нижний угол" 80 | }, 81 | "locationBottomRightCorner": { 82 | "description": "mode, in the [___bottom right corner___]", 83 | "message": "нижний правый угол" 84 | }, 85 | "optionsPageDisplayOptionsModeUsingA": { 86 | "description": "mode, in the [bottom right corner] ___using a___", 87 | "message": "с помощью" 88 | }, 89 | "themeDark": { 90 | "description": "using a [___dark theme___]", 91 | "message": "темная тема" 92 | }, 93 | "themeLight": { 94 | "description": "using a [___light theme___]", 95 | "message": "свет тема" 96 | }, 97 | "optionsPageDisplayOptionsAndShowThe": { 98 | "description": "using a [light theme] ___and show the___ [x] most recent requests", 99 | "message": "и показать" 100 | }, 101 | "optionsPageDisplayOptionsMostRecentRequests": { 102 | "description": "using a [light theme] and show the [x] ___most recent requests___", 103 | "message": "большинство недавних запросов" 104 | }, 105 | "doAutoHidePanels": { 106 | "description": "[___Do auto-hide panels___] after [x] seconds", 107 | "message": "Do автоматического скрытия панели" 108 | }, 109 | "doNotAutoHidePanels": { 110 | "description": "[___Do not auto-hide panels___] after [x] seconds", 111 | "message": "Не автоматическое скрытие панели" 112 | }, 113 | "optionsPageDisplayOptionsAutoHideAfter": { 114 | "description": "[Do auto-hide panels] ___ after___ [x] seconds", 115 | "message": "после того, как" 116 | }, 117 | "optionsPageDisplayOptionsAutoHideSeconds": { 118 | "description": "[Do auto-hide panels] after [x] ___seconds___", 119 | "message": "секунды" 120 | }, 121 | // Options page : Hide request headers 122 | "optionsPageHideRequestHeaders": { 123 | "description": "Hide request headers", 124 | "message": "Скрыть заголовки запроса" 125 | }, 126 | "optionsPageHideRequestHeadersDescription": { 127 | "description": "Request headers (or patterns thereof) that will not be displayed.", 128 | "message": "В заголовках запросов (или их образцы), которые не будут отображаться." 129 | }, 130 | // Options page : Hide response headers 131 | "optionsPageHideResponseHeaders": { 132 | "description": "Hide response headers", 133 | "message": "Скрыть заголовки ответа" 134 | }, 135 | "optionsPageHideResponseHeadersDescription": { 136 | "description": "Response headers (or patterns thereof) that will not be displayed.", 137 | "message": "заголовки ответа (или их структуры), которые не будут отображаться." 138 | }, 139 | // Options page : Headers to show in Micro mode 140 | "optionsPageMicroModeHeaders": { 141 | "description": "Headers to show in Micro mode", 142 | "message": "Заголовки, чтобы показать в режиме Micro" 143 | }, 144 | "optionsPageMicroModeHeadersDescription": { 145 | "description": "Response headers (or patterns thereof) that will be shown in micro mode.", 146 | "message": "заголовки ответа (или их структуры), которые будут показаны в микро режиме." 147 | }, 148 | // Options page : Strings to highlight 149 | "optionsPageStringsToHightlight": { 150 | "description": "Strings to highlight", 151 | "message": "Строки, чтобы выделить" 152 | }, 153 | "optionsPageStringsToHightlightDescription": { 154 | "description": "Headers (or patterns thereof) that will be", 155 | "message": "Заголовки (или шаблоны их), которые будут" 156 | }, 157 | "optionsPageStringsToHightlightDescriptionHighlighted": { 158 | "description": "Headers (or patterns thereof) that will be ___highlighted___", 159 | "message": "выделенный" 160 | }, 161 | // Plans page 162 | "plansPageTitle": { 163 | "description": "Enable extra options", 164 | "message": "Включить дополнительные опции" 165 | }, 166 | "plansPageYouCan": { 167 | "description": "___You can___ test all these great features every first 15 minutes of every hour:", 168 | "message": "Вы можете" 169 | }, 170 | "plansPageTest": { 171 | "description": "You can ___test___ all these great features every first 15 minutes of every hour:", 172 | "message": "тест" 173 | }, 174 | "plansPageTheseFeatures": { 175 | "description": "You can test ___all these great features___ every first 15 minutes of every hour:", 176 | "message": "все эти дополнительные функции" 177 | }, 178 | "plansPageEveryFirst": { 179 | "description": "You can test all these great features ___every first 15 minutes___ of every hour:", 180 | "message": "каждые первые 15 минут" 181 | }, 182 | "plansPageOfEveryHour": { 183 | "description": "You can test all these great features every first 15 minutes ___of every hour___:", 184 | "message": "каждого часа" 185 | }, 186 | "plansPageOptionServerIp": { 187 | "description": "Server IP address", 188 | "message": "IP-адрес сервера" 189 | }, 190 | "plansPageOptionSubFrameRequests": { 191 | "description": "Sub-frame requests", 192 | "message": "запросы подрамник" 193 | }, 194 | "plansPageOptionXhrRequests": { 195 | "description": "XML HTTP Requests (XHR / AJAX)", 196 | "message": "XML HTTP-запросов (XHR / AJAX)" 197 | }, 198 | "plansPageOptionRequestTimes": { 199 | "description": "Request times: time to headers received, time to first byte and time to complete", 200 | "message": "Запрос раз: время заголовки получены, время до первого байта и времени для завершения" 201 | }, 202 | "plansPageOptionFilterBar": { 203 | "description": "Use the filter bar to filter the headers", 204 | "message": "С помощью панели фильтра для фильтрации заголовков" 205 | }, 206 | "plansPageOneTimeBeerSupport": { 207 | "description": "One-time beer support", 208 | "message": "поддержка пиво Одноразовый" 209 | }, 210 | "plansPageOneTimePizzaSupport": { 211 | "description": "One-time pizza support", 212 | "message": "поддержка пиццы Одноразовый" 213 | }, 214 | "plansPageSubscriptions": { 215 | "description": "Subscriptions", 216 | "message": "Подписки" 217 | }, 218 | "plansPageMangeSubscriptions": { 219 | "description": "Manage subscriptions", 220 | "message": "Управление подписками" 221 | }, 222 | "plansPageEnableFeatures": { 223 | "description": "___If you want to enable these features___ permanently, please support further development by donating me some beer/pizza:", 224 | "message": "Если вы хотите, чтобы включить эти функции" 225 | }, 226 | "plansPageEnableFeaturesPermanently": { 227 | "description": "If you want to enable these features ___permanently___, please support further development by donating me some beer/pizza:", 228 | "message": "постоянно" 229 | }, 230 | "plansPageEnableFeaturesPleaseSupport": { 231 | "description": "If you want to enable these features permanently___, please support further development by donating me some beer/pizza___:", 232 | "message": ", пожалуйста, поддерживать дальнейшее развитие, пожертвовав мне пиво / пицца" 233 | }, 234 | "plansPageIWillSupportYouWith": { 235 | "description": "___I'll support you with___ [x] pizzas", 236 | "message": "Я буду поддерживать вас" 237 | }, 238 | "plansPageBeers": { 239 | "description": "I'll support you with [x] ___beers___", 240 | "message": "пиво" 241 | }, 242 | "plansPagePizzas": { 243 | "description": "I'll support you with [x] ___pizzas___", 244 | "message": "пицц" 245 | }, 246 | "plansPageThankYou": { 247 | "description": "Thank you for your support ;-)", 248 | "message": "Спасибо за Вашу поддержку ;-)" 249 | }, 250 | // Buy flow 251 | "buyStatusRetrievingProducts": { 252 | "description": "Retreiving available products", 253 | "message": "Получение доступных продуктов" 254 | }, 255 | "buyErrorRetrievingProducts": { 256 | "description": "Error retrieving product list", 257 | "message": "Ошибка получения списка продукции" 258 | }, 259 | "buyStatusRetrievingPurchasedProducts": { 260 | "description": "Retreiving list of purchased products", 261 | "message": "Получение списка купленных продуктов" 262 | }, 263 | "buyErrorRetrievingPurchasedProducts": { 264 | "description": "Error retreiving list of purchased products", 265 | "message": "Ошибка при получении списка купленных продуктов" 266 | }, 267 | "buyStatusPurchaseComplete": { 268 | "description": "Purchase completed. Order ID", 269 | "message": "Покупка завершена. номер заказа" 270 | }, 271 | "buyErrorPurchaseFailed": { 272 | "description": "Purchase failed", 273 | "message": "Не удалось совершить покупку" 274 | }, 275 | // About page 276 | "aboutPageContent": { 277 | "description": "Section of text describing Me", 278 | "message": "Меня зовут Михель Роос. У меня было много веселья разработке этого дополнения. Я также узнал много нового. Я надеюсь, что вы найдете это и полезно пользоваться ею. Если у вас есть какие-либо suggetstions или конструктивную критику, пожалуйста, свяжитесь со мной." 279 | }, 280 | "popupDefaultMessage": { 281 | "description": "The default message shown in the browserAction popup", 282 | "message": "Нет заголовки еще не были захвачены в плен. Пожалуйста, перезагрузите эту вкладку, чтобы увидеть заголовки." 283 | }, 284 | // Popup and content messages 285 | "contentMessagesEnableExtraOptions": { 286 | "description": "enable XHR and sub-frame requests", 287 | "message": "включить XHR и подрамника запросы" 288 | }, 289 | "contentMessagesPressEscToClosePanels": { 290 | "description": "[esc] closes these panels. Click to toggle panels.", 291 | "message": "[ESC] закрывает эти панели. Нажмите для переключения панелей." 292 | }, 293 | "contentMessagesCache": { 294 | "description": "cache", 295 | "message": "кэш" 296 | }, 297 | "contentMessagesCached": { 298 | "description": "cached", 299 | "message": "кэшируются" 300 | }, 301 | "contentMessagesFromDiskCache": { 302 | "description": "from disk cache", 303 | "message": "из дискового кэша" 304 | }, 305 | "contentMessagesHeadersReceived": { 306 | "description": "shorthand for headers received: ___headers recv___", 307 | "message": "заголовки recv" 308 | }, 309 | "contentMessagesTimeToFirstByte": { 310 | "description": "shorthand for time to first byte: ___first byte___", 311 | "message": "первый байт" 312 | }, 313 | "contentMessagesRequestComplete": { 314 | "description": "shorthand for request completed: ___complete___", 315 | "message": "полный" 316 | }, 317 | "contentMessagesPanelTitleRequest": { 318 | "description": "Request", 319 | "message": "Запрос" 320 | }, 321 | "contentMessagesPanelTitleResponse": { 322 | "description": "Response", 323 | "message": "отклик" 324 | }, 325 | "contentMessagesPanelTitleCookies": { 326 | "description": "Cookies", 327 | "message": "Печенье" 328 | }, 329 | "contentMessagesPanelTitleFormData": { 330 | "description": "Form Data", 331 | "message": "Форма данных" 332 | }, 333 | "contentMessagesPanelTitleQuery": { 334 | "description": "Query", 335 | "message": "запрос" 336 | }, 337 | "contentMessagesFilterBarFilter": { 338 | "description": "Filter", 339 | "message": "Фильтр" 340 | }, 341 | "contentMessagesFilterBarRegex": { 342 | "description": "Regex", 343 | "message": "Regex" 344 | }, 345 | "contentMessagesRequestTypeDoc": { 346 | "description": "Doc", 347 | "message": "Doc" 348 | }, 349 | "contentMessagesRequestTypeFrame": { 350 | "description": "Frame", 351 | "message": "Рамка" 352 | }, 353 | "contentMessagesRequestTypeXhr": { 354 | "description": "XHR", 355 | "message": "XHR" 356 | }, 357 | "contentMessagesProEnableServerIp": { 358 | "description": "enable server IP", 359 | "message": "включить IP-адрес сервера" 360 | }, 361 | "contentMessagesProEnableResponseTimes": { 362 | "description": "enable response times", 363 | "message": "включить время отклика" 364 | } 365 | } 366 | -------------------------------------------------------------------------------- /_locales/zh_CN/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "description": "The description of the extension", 4 | "message": "HTTP Header Spy使您可以在页面加载后立即检查请求 - 响应头和Cookie,无需额外的点击。" 5 | }, 6 | "extensionName": { 7 | "description": "The name of the extension", 8 | "message": "HTTP间谍" 9 | }, 10 | "extensionNameShort": { 11 | "description": "The short name of the extension", 12 | "message": "HTTP头" 13 | }, 14 | // Option menu names 15 | "optionsDisplayName": { 16 | "description": "Menu title for options page", 17 | "message": "选项" 18 | }, 19 | "aboutDisplayName": { 20 | "description": "Menu title for about page", 21 | "message": "关于" 22 | }, 23 | "plansDisplayName": { 24 | "description": "Menu title for 'Enable extra options' page", 25 | "message": "启用额外选项" 26 | }, 27 | // Options page 28 | "buttonAdd": { 29 | "description": "Add button text", 30 | "message": "加" 31 | }, 32 | "buttonOptions": { 33 | "description": "Options page button text", 34 | "message": "选项页面" 35 | }, 36 | // Options page : Display options 37 | "optionsPageDisplayOptions": { 38 | "description": "Display options", 39 | "message": "显示选项" 40 | }, 41 | "optionsPageDisplayOptionsPressEscapeToHidePanels": { 42 | "description": "Press the ESC key to hide panels.", 43 | "message": "按ESC键隐藏面板。" 44 | }, 45 | "optionsPageDisplayOptionsAutoHide": { 46 | "description": "Press the ESC key to hide panels.", 47 | "message": "启用自动隐藏时,不会显示过滤器栏。" 48 | }, 49 | "optionsPageDisplayOptionsShowIn": { 50 | "description": "___Show in___ [mode]", 51 | "message": "显示" 52 | }, 53 | "renderModeNormal": { 54 | "description": "Show in [___normal___]", 55 | "message": "正常" 56 | }, 57 | "renderModeMicro": { 58 | "description": "Show in [___micro___]", 59 | "message": "微" 60 | }, 61 | "renderModeDisabled": { 62 | "description": "Show in [___disabled___]", 63 | "message": "禁用" 64 | }, 65 | "optionsPageDisplayOptionsModeInThe": { 66 | "description": "Show in [mode] ___mode, in the___", 67 | "message": "模式,在" 68 | }, 69 | "locationTopLeftCorner": { 70 | "description": "mode, in the [___top left corner___]", 71 | "message": "左上角" 72 | }, 73 | "locationTopRightCorner": { 74 | "description": "mode, in the [___top right corner___]", 75 | "message": "右上角" 76 | }, 77 | "locationBottomLeftCorner": { 78 | "description": "mode, in the [___bottom left corner___]", 79 | "message": "左下角" 80 | }, 81 | "locationBottomRightCorner": { 82 | "description": "mode, in the [___bottom right corner___]", 83 | "message": "右下角" 84 | }, 85 | "optionsPageDisplayOptionsModeUsingA": { 86 | "description": "mode, in the [bottom right corner] ___using a___", 87 | "message": "使用a" 88 | }, 89 | "themeDark": { 90 | "description": "using a [___dark theme___]", 91 | "message": "黑暗的主题" 92 | }, 93 | "themeLight": { 94 | "description": "using a [___light theme___]", 95 | "message": "光主题" 96 | }, 97 | "optionsPageDisplayOptionsAndShowThe": { 98 | "description": "using a [light theme] ___and show the___ [x] most recent requests", 99 | "message": "并显示" 100 | }, 101 | "optionsPageDisplayOptionsMostRecentRequests": { 102 | "description": "using a [light theme] and show the [x] ___most recent requests___", 103 | "message": "最近的请求" 104 | }, 105 | "doAutoHidePanels": { 106 | "description": "[___Do auto-hide panels___] after [x] seconds", 107 | "message": "自动隐藏面板" 108 | }, 109 | "doNotAutoHidePanels": { 110 | "description": "[___Do not auto-hide panels___] after [x] seconds", 111 | "message": "不要自动隐藏面板" 112 | }, 113 | "optionsPageDisplayOptionsAutoHideAfter": { 114 | "description": "[Do auto-hide panels] ___ after___ [x] seconds", 115 | "message": "后" 116 | }, 117 | "optionsPageDisplayOptionsAutoHideSeconds": { 118 | "description": "[Do auto-hide panels] after [x] ___seconds___", 119 | "message": "秒" 120 | }, 121 | // Options page : Hide request headers 122 | "optionsPageHideRequestHeaders": { 123 | "description": "Hide request headers", 124 | "message": "隐藏请求标头" 125 | }, 126 | "optionsPageHideRequestHeadersDescription": { 127 | "description": "Request headers (or patterns thereof) that will not be displayed.", 128 | "message": "将不显示的请求标头(或其模式)。" 129 | }, 130 | // Options page : Hide response headers 131 | "optionsPageHideResponseHeaders": { 132 | "description": "Hide response headers", 133 | "message": "隐藏响应标头" 134 | }, 135 | "optionsPageHideResponseHeadersDescription": { 136 | "description": "Response headers (or patterns thereof) that will not be displayed.", 137 | "message": "将不显示的响应标头(或其模式)。" 138 | }, 139 | // Options page : Headers to show in Micro mode 140 | "optionsPageMicroModeHeaders": { 141 | "description": "Headers to show in Micro mode", 142 | "message": "标题在微模式下显示" 143 | }, 144 | "optionsPageMicroModeHeadersDescription": { 145 | "description": "Response headers (or patterns thereof) that will be shown in micro mode.", 146 | "message": "将在微模式中显示的响应头(或其模式)。" 147 | }, 148 | // Options page : Strings to highlight 149 | "optionsPageStringsToHightlight": { 150 | "description": "Strings to highlight", 151 | "message": "字符串高亮" 152 | }, 153 | "optionsPageStringsToHightlightDescription": { 154 | "description": "Headers (or patterns thereof) that will be", 155 | "message": "将是的标题(或其模式)" 156 | }, 157 | "optionsPageStringsToHightlightDescriptionHighlighted": { 158 | "description": "Headers (or patterns thereof) that will be ___highlighted___", 159 | "message": "突出显示" 160 | }, 161 | // Plans page 162 | "plansPageTitle": { 163 | "description": "Enable extra options", 164 | "message": "启用额外选项" 165 | }, 166 | "plansPageYouCan": { 167 | "description": "___You can___ test all these great features every first 15 minutes of every hour:", 168 | "message": "您可以" 169 | }, 170 | "plansPageTest": { 171 | "description": "You can ___test___ all these great features every first 15 minutes of every hour:", 172 | "message": "测试" 173 | }, 174 | "plansPageTheseFeatures": { 175 | "description": "You can test ___all these great features___ every first 15 minutes of every hour:", 176 | "message": "所有这些额外的功能" 177 | }, 178 | "plansPageEveryFirst": { 179 | "description": "You can test all these great features ___every first 15 minutes___ of every hour:", 180 | "message": "每隔15分钟" 181 | }, 182 | "plansPageOfEveryHour": { 183 | "description": "You can test all these great features every first 15 minutes ___of every hour___:", 184 | "message": "的每小时" 185 | }, 186 | "plansPageOptionServerIp": { 187 | "description": "Server IP address", 188 | "message": "服务器IP地址" 189 | }, 190 | "plansPageOptionSubFrameRequests": { 191 | "description": "Sub-frame requests", 192 | "message": "子帧请求" 193 | }, 194 | "plansPageOptionXhrRequests": { 195 | "description": "XML HTTP Requests (XHR / AJAX)", 196 | "message": "XML HTTP请求(XHR / AJAX)" 197 | }, 198 | "plansPageOptionRequestTimes": { 199 | "description": "Request times: time to headers received, time to first byte and time to complete", 200 | "message": "请求时间:接收到标头的时间,到第一个字节的时间和完成时间" 201 | }, 202 | "plansPageOptionFilterBar": { 203 | "description": "Use the filter bar to filter the headers", 204 | "message": "使用过滤器栏过滤标题" 205 | }, 206 | "plansPageOneTimeBeerSupport": { 207 | "description": "One-time beer support", 208 | "message": "一次性啤酒支持" 209 | }, 210 | "plansPageOneTimePizzaSupport": { 211 | "description": "One-time pizza support", 212 | "message": "一次性比萨饼支持" 213 | }, 214 | "plansPageSubscriptions": { 215 | "description": "Subscriptions", 216 | "message": "订阅" 217 | }, 218 | "plansPageMangeSubscriptions": { 219 | "description": "Manage subscriptions", 220 | "message": "管理订阅" 221 | }, 222 | "plansPageEnableFeatures": { 223 | "description": "___If you want to enable these features___ permanently, please support further development by donating me some beer/pizza:", 224 | "message": "如果要启用这些功能" 225 | }, 226 | "plansPageEnableFeaturesPermanently": { 227 | "description": "If you want to enable these features ___permanently___, please support further development by donating me some beer/pizza:", 228 | "message": "永久" 229 | }, 230 | "plansPageEnableFeaturesPleaseSupport": { 231 | "description": "If you want to enable these features permanently___, please support further development by donating me some beer/pizza___:", 232 | "message": ",请支持进一步发展捐赠我一些啤酒/比萨饼" 233 | }, 234 | "plansPageIWillSupportYouWith": { 235 | "description": "___I'll support you with___ [x] pizzas", 236 | "message": "我会支持你的" 237 | }, 238 | "plansPageBeers": { 239 | "description": "I'll support you with [x] ___beers___", 240 | "message": "啤酒" 241 | }, 242 | "plansPagePizzas": { 243 | "description": "I'll support you with [x] ___pizzas___", 244 | "message": "比萨饼" 245 | }, 246 | "plansPageThankYou": { 247 | "description": "Thank you for your support ;-)", 248 | "message": "感谢您的支持 ;-)" 249 | }, 250 | // Buy flow 251 | "buyStatusRetrievingProducts": { 252 | "description": "Retreiving available products", 253 | "message": "检索可用产品" 254 | }, 255 | "buyErrorRetrievingProducts": { 256 | "description": "Error retrieving product list", 257 | "message": "检索产品列表时出错" 258 | }, 259 | "buyStatusRetrievingPurchasedProducts": { 260 | "description": "Retreiving list of purchased products", 261 | "message": "检索已购买产品的列表" 262 | }, 263 | "buyErrorRetrievingPurchasedProducts": { 264 | "description": "Error retreiving list of purchased products", 265 | "message": "检索已购买产品的列表时出错" 266 | }, 267 | "buyStatusPurchaseComplete": { 268 | "description": "Purchase completed. Order ID", 269 | "message": "购买完成。订单ID" 270 | }, 271 | "buyErrorPurchaseFailed": { 272 | "description": "Purchase failed", 273 | "message": "购买失败" 274 | }, 275 | // About page 276 | "aboutPageContent": { 277 | "description": "Section of text describing Me", 278 | "message": "我的名字是Michiel Roos。我有很多乐趣开发这个插件。我也学到了很多。我希望你发现它有用,喜欢使用它。如果你有任何建议或建设性的批评,请与我联系。" 279 | }, 280 | "popupDefaultMessage": { 281 | "description": "The default message shown in the browserAction popup", 282 | "message": "尚未捕获任何标头。请重新载入此标签以查看标题。" 283 | }, 284 | // Popup and content messages 285 | "contentMessagesEnableExtraOptions": { 286 | "description": "enable XHR and sub-frame requests", 287 | "message": "启用XHR和子帧请求" 288 | }, 289 | "contentMessagesPressEscToClosePanels": { 290 | "description": "[esc] closes these panels. Click to toggle panels.", 291 | "message": "[esc]关闭这些面板。单击可切换面板。" 292 | }, 293 | "contentMessagesCache": { 294 | "description": "cache", 295 | "message": "缓存" 296 | }, 297 | "contentMessagesCached": { 298 | "description": "cached", 299 | "message": "缓存" 300 | }, 301 | "contentMessagesFromDiskCache": { 302 | "description": "from disk cache", 303 | "message": "从磁盘缓存" 304 | }, 305 | "contentMessagesHeadersReceived": { 306 | "description": "shorthand for headers received: ___headers recv___", 307 | "message": "标题recv" 308 | }, 309 | "contentMessagesTimeToFirstByte": { 310 | "description": "shorthand for time to first byte: ___first byte___", 311 | "message": "第一字节" 312 | }, 313 | "contentMessagesRequestComplete": { 314 | "description": "shorthand for request completed: ___complete___", 315 | "message": "完成" 316 | }, 317 | "contentMessagesPanelTitleRequest": { 318 | "description": "Request", 319 | "message": "请求" 320 | }, 321 | "contentMessagesPanelTitleResponse": { 322 | "description": "Response", 323 | "message": "响应" 324 | }, 325 | "contentMessagesPanelTitleCookies": { 326 | "description": "Cookies", 327 | "message": "饼干" 328 | }, 329 | "contentMessagesPanelTitleFormData": { 330 | "description": "Form Data", 331 | "message": "表单数据" 332 | }, 333 | "contentMessagesPanelTitleQuery": { 334 | "description": "Query", 335 | "message": "查询" 336 | }, 337 | "contentMessagesFilterBarFilter": { 338 | "description": "Filter", 339 | "message": "过滤" 340 | }, 341 | "contentMessagesFilterBarRegex": { 342 | "description": "Regex", 343 | "message": "正则表达式" 344 | }, 345 | "contentMessagesRequestTypeDoc": { 346 | "description": "Doc", 347 | "message": "Doc" 348 | }, 349 | "contentMessagesRequestTypeFrame": { 350 | "description": "Frame", 351 | "message": "帧" 352 | }, 353 | "contentMessagesRequestTypeXhr": { 354 | "description": "XHR", 355 | "message": "XHR" 356 | }, 357 | "contentMessagesProEnableServerIp": { 358 | "description": "enable server IP", 359 | "message": "启用服务器IP" 360 | }, 361 | "contentMessagesProEnableResponseTimes": { 362 | "description": "enable response times", 363 | "message": "启用响应时间" 364 | } 365 | } 366 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "__MSG_extensionName__", 3 | "short_name": "__MSG_extensionNameShort__", 4 | "version": "2.0.49", 5 | "manifest_version": 2, 6 | "minimum_chrome_version": "18", 7 | "description": "__MSG_extensionDescription__", 8 | "author": "Michiel Roos", 9 | "homepage_url": "http://www.michielroos.com/", 10 | "default_locale": "en", 11 | "permissions": [ 12 | "http://*/*", 13 | "https://*/*", 14 | "tabs", 15 | "activeTab", 16 | "storage", 17 | "webRequest" 18 | ], 19 | "background": { 20 | "scripts": [ 21 | "Resources/JavaScript/Google/buy.js", 22 | "Resources/JavaScript/library.js", 23 | "Resources/JavaScript/background.js" 24 | ], 25 | "persistent": true 26 | }, 27 | "browser_action": { 28 | "default_icon": { 29 | "19": "Resources/Icons/toolbarIcon19.png", 30 | "38": "Resources/Icons/toolbarIcon38.png" 31 | }, 32 | "default_title": "__MSG_extensionName__", 33 | "default_popup": "Resources/HTML/popup.html" 34 | }, 35 | "icons": { 36 | "16": "Resources/Icons/icon16.png", 37 | "48": "Resources/Icons/icon48.png", 38 | "128": "Resources/Icons/icon128.png" 39 | }, 40 | "oauth2": { 41 | "client_id": "344825410658-1hrj72o88dvpau57j8sdvhi6l01a8prg.apps.googleusercontent.com", 42 | "scopes": [ 43 | "https://www.googleapis.com/auth/chromewebstore.readonly" 44 | ] 45 | }, 46 | "options_ui": { 47 | "page": "Resources/HTML/options.html", 48 | "open_in_tab": false 49 | }, 50 | "options_page": "Resources/HTML/options.html", 51 | "content_scripts": [ 52 | { 53 | "js": [ 54 | "Resources/JavaScript/Mark/mark.es6.min.js", 55 | "Resources/JavaScript/library.js", 56 | "Resources/JavaScript/content.js" 57 | ], 58 | "matches": [ 59 | "http://*/*", 60 | "https://*/*" 61 | ], 62 | "run_at": "document_idle" 63 | } 64 | ], 65 | "web_accessible_resources": [ 66 | "Resources/HTML/plans.html", 67 | "Resources/HTML/thanks.html" 68 | ] 69 | } 70 | --------------------------------------------------------------------------------