├── .babelrc ├── .gitignore ├── README.md ├── critical-style-snapshot.zip ├── dist ├── images │ ├── critical.png │ ├── icon128.png │ ├── icon16.png │ ├── icon19.png │ ├── icon24.png │ ├── icon38.png │ ├── icon48.png │ ├── logo.png │ └── promotional.png ├── index.js ├── manifest.json ├── scripts │ └── execute.js └── styles │ └── style.css ├── gulpfile.js ├── package.json ├── promotional.png └── src ├── images ├── critical.png ├── icon128.png ├── icon16.png ├── icon19.png ├── icon24.png ├── icon38.png ├── icon48.png └── logo.png ├── index.js ├── manifest.json ├── scripts ├── components │ └── popup.jsx ├── execute.jsx ├── generators │ ├── CriticalCSS.jsx │ └── DocumentCSSMediaRules.jsx ├── polyfills │ └── get-matched-css-rules.jsx └── utilities │ ├── arrayContainsObject.jsx │ ├── equalObjects.jsx │ ├── explainWarning.jsx │ ├── removeDocumentStyles.jsx │ └── selectText.jsx └── styles └── components └── critical.scss /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"] 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Critical Style Snapshot 2 | 3 |

4 | 5 |

6 | 7 | Capture critical CSS above the fold with one click. Works for most websites, this extension captures 99% of the of the currently active media query CSS. Selectors like pseudo-elements don't get captured (yet), so in some cases minor tweaking is nessescary. 8 | 9 | Inspired by [CriticalCSS Bookmarklet and Devtool Snippetjs](https://gist.github.com/PaulKinlan/6284142) 10 | 11 | ## Features 12 | - Capture your webpage above the fold CSS with one click 13 | - Copy the CSS with one extra click 14 | - Preview the captured CSS 15 | 16 | ## Installation 17 | No setup required, [Install it directly from the Chrome Webstore](https://chrome.google.com/webstore/detail/critical-snapshot/gkoeffcejdhhojognlonafnijfkcepob) 18 | 19 | ## Usage 20 | Resize your browser window to the desired device width and click the capture icon ![icon](/src/images/icon19.png "icon") in your chome extensions bar. Copy the outputted style, then paste it in a style element just before the first `` element. This way your project CSS will override the "above the fold" CSS when it is loaded. 21 | 22 | Example: 23 | ``` 24 | 25 | 28 | 29 | 30 | ``` 31 | 32 | ### @media queries 33 | 34 | This plugin only outputs CSS that is **currently active**, meaning you have full control over the media specific styles you capture by resizing your browser window. So to capture for multiple screen widths, you will have to capture on multiple screen widths. 35 | 36 | Example: 37 | ``` 38 | 39 | 52 | 53 | 54 | ``` 55 | 56 | ### CSS Optimization (recommended) 57 | As you might guess, the plugin does not (yet) optimize the CSS, meaning every time you capture the CSS for a specific media query, you will (most likely) get some redundant CSS that was already captured for smaller screens. For this I recommend you run your final "above the fold" CSS through some CSS optimizers. 58 | 59 | These are some optimizers I find very useful that solve most of these issues: 60 | 61 | [PostCSS](https://github.com/postcss/postcss) 62 | >PostCSS is a tool for transforming styles with JS plugins. These plugins can lint your CSS, support variables and mixins, transpile future CSS syntax, inline images, and more. 63 | 64 | [PostCSS Merge Selectors](https://github.com/georgeadamson/postcss-merge-selectors) **Get rid of (most) duplicate selectors and rules** 65 | >PostCSS plugin to combine selectors that have identical rules. Can be configured to only merge rules who's selectors match specific filters. 66 | 67 | [Autoprefixer](https://github.com/postcss/autoprefixer) **Autoprefixing to make your above the fold CSS compatible with most browsers** 68 | >PostCSS plugin to parse CSS and add vendor prefixes to CSS rules using values from Can I Use. It is recommended by Google and used in Twitter, and Taobao. 69 | 70 | [PostCSS Clean](https://github.com/leodido/postcss-clean) **Minify the CSS** 71 | >PostCss plugin to minify your CSS 72 | 73 | Using these optimizations I was able to reduce the outputted CSS size by around 80%. Ofcourse you are free to choose any other CSS optimization tools, this is just what worked best for me.. 74 | 75 | ## TODO 76 | - Pretty output CSS option 77 | - Implement loader for the slower `getMatchedCSSRules()` polyfill 78 | - Support pseudo elements 79 | - Re-capture on window-resize for easy media-query capturing 80 | - Auto prefixing 81 | - Auto optimize 82 | 83 | ## Info 84 | More on [Critical Rendering Path](https://developers.google.com/web/fundamentals/performance/critical-rendering-path/) 85 | -------------------------------------------------------------------------------- /critical-style-snapshot.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreleon/critical-style-snapshot/a094109865e7c3706b9aaee00517e34ef159a46e/critical-style-snapshot.zip -------------------------------------------------------------------------------- /dist/images/critical.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreleon/critical-style-snapshot/a094109865e7c3706b9aaee00517e34ef159a46e/dist/images/critical.png -------------------------------------------------------------------------------- /dist/images/icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreleon/critical-style-snapshot/a094109865e7c3706b9aaee00517e34ef159a46e/dist/images/icon128.png -------------------------------------------------------------------------------- /dist/images/icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreleon/critical-style-snapshot/a094109865e7c3706b9aaee00517e34ef159a46e/dist/images/icon16.png -------------------------------------------------------------------------------- /dist/images/icon19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreleon/critical-style-snapshot/a094109865e7c3706b9aaee00517e34ef159a46e/dist/images/icon19.png -------------------------------------------------------------------------------- /dist/images/icon24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreleon/critical-style-snapshot/a094109865e7c3706b9aaee00517e34ef159a46e/dist/images/icon24.png -------------------------------------------------------------------------------- /dist/images/icon38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreleon/critical-style-snapshot/a094109865e7c3706b9aaee00517e34ef159a46e/dist/images/icon38.png -------------------------------------------------------------------------------- /dist/images/icon48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreleon/critical-style-snapshot/a094109865e7c3706b9aaee00517e34ef159a46e/dist/images/icon48.png -------------------------------------------------------------------------------- /dist/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreleon/critical-style-snapshot/a094109865e7c3706b9aaee00517e34ef159a46e/dist/images/logo.png -------------------------------------------------------------------------------- /dist/images/promotional.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreleon/critical-style-snapshot/a094109865e7c3706b9aaee00517e34ef159a46e/dist/images/promotional.png -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | var triggeredTabs = []; 2 | var window = chrome.extension.getBackgroundPage(); 3 | chrome.browserAction.onClicked.addListener(function(tab) { 4 | chrome.tabs.insertCSS(null, {file: "styles/style.css"}); 5 | chrome.tabs.executeScript(null, {file: "scripts/execute.js"}); 6 | }); 7 | -------------------------------------------------------------------------------- /dist/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Critical Style Snapshot", 3 | "description": "Capture CSS above the fold with one click.", 4 | "version": "0.0.8", 5 | "permissions": [ 6 | "activeTab" 7 | ], 8 | "background": { 9 | "scripts": ["index.js"], 10 | "persistent": false 11 | }, 12 | "icons": { 13 | "16": "images/icon16.png", 14 | "48": "images/icon48.png", 15 | "128": "images/icon128.png" 16 | }, 17 | "browser_action": { 18 | "default_title": "Capture CSS above the fold", 19 | "default_icon": { 20 | "19": "images/icon19.png", 21 | "38": "images/icon38.png" 22 | } 23 | }, 24 | "manifest_version": 2, 25 | "homepage_url": "https://github.com/andreleon/critical-style-snapshot" 26 | } 27 | -------------------------------------------------------------------------------- /dist/scripts/execute.js: -------------------------------------------------------------------------------- 1 | (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0) { 42 | throw new Error('Invalid string. Length must be a multiple of 4') 43 | } 44 | 45 | // the number of equal signs (place holders) 46 | // if there are two placeholders, than the two characters before it 47 | // represent one byte 48 | // if there is only one, then the three characters before it represent 2 bytes 49 | // this is just a cheap hack to not do indexOf twice 50 | var len = b64.length 51 | placeHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0 52 | 53 | // base64 is 4/3 + up to two characters of the original data 54 | arr = new Arr(b64.length * 3 / 4 - placeHolders) 55 | 56 | // if there are placeholders, only get up to the last complete 4 chars 57 | l = placeHolders > 0 ? b64.length - 4 : b64.length 58 | 59 | var L = 0 60 | 61 | function push (v) { 62 | arr[L++] = v 63 | } 64 | 65 | for (i = 0, j = 0; i < l; i += 4, j += 3) { 66 | tmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3)) 67 | push((tmp & 0xFF0000) >> 16) 68 | push((tmp & 0xFF00) >> 8) 69 | push(tmp & 0xFF) 70 | } 71 | 72 | if (placeHolders === 2) { 73 | tmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4) 74 | push(tmp & 0xFF) 75 | } else if (placeHolders === 1) { 76 | tmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2) 77 | push((tmp >> 8) & 0xFF) 78 | push(tmp & 0xFF) 79 | } 80 | 81 | return arr 82 | } 83 | 84 | function uint8ToBase64 (uint8) { 85 | var i, 86 | extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes 87 | output = "", 88 | temp, length 89 | 90 | function encode (num) { 91 | return lookup.charAt(num) 92 | } 93 | 94 | function tripletToBase64 (num) { 95 | return encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F) 96 | } 97 | 98 | // go through the array every three bytes, we'll deal with trailing stuff later 99 | for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) { 100 | temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]) 101 | output += tripletToBase64(temp) 102 | } 103 | 104 | // pad the end with zeros, but make sure to not forget the extra bytes 105 | switch (extraBytes) { 106 | case 1: 107 | temp = uint8[uint8.length - 1] 108 | output += encode(temp >> 2) 109 | output += encode((temp << 4) & 0x3F) 110 | output += '==' 111 | break 112 | case 2: 113 | temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1]) 114 | output += encode(temp >> 10) 115 | output += encode((temp >> 4) & 0x3F) 116 | output += encode((temp << 2) & 0x3F) 117 | output += '=' 118 | break 119 | } 120 | 121 | return output 122 | } 123 | 124 | exports.toByteArray = b64ToByteArray 125 | exports.fromByteArray = uint8ToBase64 126 | }(typeof exports === 'undefined' ? (this.base64js = {}) : exports)) 127 | 128 | }).call(this,require("rH1JPG"),typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],"/../../node_modules/base64-js/lib/b64.js","/../../node_modules/base64-js/lib") 129 | },{"buffer":2,"rH1JPG":4}],2:[function(require,module,exports){ 130 | (function (process,global,Buffer,__argument0,__argument1,__argument2,__argument3,__filename,__dirname){ 131 | /*! 132 | * The buffer module from node.js, for the browser. 133 | * 134 | * @author Feross Aboukhadijeh 135 | * @license MIT 136 | */ 137 | 138 | var base64 = require('base64-js') 139 | var ieee754 = require('ieee754') 140 | 141 | exports.Buffer = Buffer 142 | exports.SlowBuffer = Buffer 143 | exports.INSPECT_MAX_BYTES = 50 144 | Buffer.poolSize = 8192 145 | 146 | /** 147 | * If `Buffer._useTypedArrays`: 148 | * === true Use Uint8Array implementation (fastest) 149 | * === false Use Object implementation (compatible down to IE6) 150 | */ 151 | Buffer._useTypedArrays = (function () { 152 | // Detect if browser supports Typed Arrays. Supported browsers are IE 10+, Firefox 4+, 153 | // Chrome 7+, Safari 5.1+, Opera 11.6+, iOS 4.2+. If the browser does not support adding 154 | // properties to `Uint8Array` instances, then that's the same as no `Uint8Array` support 155 | // because we need to be able to add all the node Buffer API methods. This is an issue 156 | // in Firefox 4-29. Now fixed: https://bugzilla.mozilla.org/show_bug.cgi?id=695438 157 | try { 158 | var buf = new ArrayBuffer(0) 159 | var arr = new Uint8Array(buf) 160 | arr.foo = function () { return 42 } 161 | return 42 === arr.foo() && 162 | typeof arr.subarray === 'function' // Chrome 9-10 lack `subarray` 163 | } catch (e) { 164 | return false 165 | } 166 | })() 167 | 168 | /** 169 | * Class: Buffer 170 | * ============= 171 | * 172 | * The Buffer constructor returns instances of `Uint8Array` that are augmented 173 | * with function properties for all the node `Buffer` API functions. We use 174 | * `Uint8Array` so that square bracket notation works as expected -- it returns 175 | * a single octet. 176 | * 177 | * By augmenting the instances, we can avoid modifying the `Uint8Array` 178 | * prototype. 179 | */ 180 | function Buffer (subject, encoding, noZero) { 181 | if (!(this instanceof Buffer)) 182 | return new Buffer(subject, encoding, noZero) 183 | 184 | var type = typeof subject 185 | 186 | // Workaround: node's base64 implementation allows for non-padded strings 187 | // while base64-js does not. 188 | if (encoding === 'base64' && type === 'string') { 189 | subject = stringtrim(subject) 190 | while (subject.length % 4 !== 0) { 191 | subject = subject + '=' 192 | } 193 | } 194 | 195 | // Find the length 196 | var length 197 | if (type === 'number') 198 | length = coerce(subject) 199 | else if (type === 'string') 200 | length = Buffer.byteLength(subject, encoding) 201 | else if (type === 'object') 202 | length = coerce(subject.length) // assume that object is array-like 203 | else 204 | throw new Error('First argument needs to be a number, array or string.') 205 | 206 | var buf 207 | if (Buffer._useTypedArrays) { 208 | // Preferred: Return an augmented `Uint8Array` instance for best performance 209 | buf = Buffer._augment(new Uint8Array(length)) 210 | } else { 211 | // Fallback: Return THIS instance of Buffer (created by `new`) 212 | buf = this 213 | buf.length = length 214 | buf._isBuffer = true 215 | } 216 | 217 | var i 218 | if (Buffer._useTypedArrays && typeof subject.byteLength === 'number') { 219 | // Speed optimization -- use set if we're copying from a typed array 220 | buf._set(subject) 221 | } else if (isArrayish(subject)) { 222 | // Treat array-ish objects as a byte array 223 | for (i = 0; i < length; i++) { 224 | if (Buffer.isBuffer(subject)) 225 | buf[i] = subject.readUInt8(i) 226 | else 227 | buf[i] = subject[i] 228 | } 229 | } else if (type === 'string') { 230 | buf.write(subject, 0, encoding) 231 | } else if (type === 'number' && !Buffer._useTypedArrays && !noZero) { 232 | for (i = 0; i < length; i++) { 233 | buf[i] = 0 234 | } 235 | } 236 | 237 | return buf 238 | } 239 | 240 | // STATIC METHODS 241 | // ============== 242 | 243 | Buffer.isEncoding = function (encoding) { 244 | switch (String(encoding).toLowerCase()) { 245 | case 'hex': 246 | case 'utf8': 247 | case 'utf-8': 248 | case 'ascii': 249 | case 'binary': 250 | case 'base64': 251 | case 'raw': 252 | case 'ucs2': 253 | case 'ucs-2': 254 | case 'utf16le': 255 | case 'utf-16le': 256 | return true 257 | default: 258 | return false 259 | } 260 | } 261 | 262 | Buffer.isBuffer = function (b) { 263 | return !!(b !== null && b !== undefined && b._isBuffer) 264 | } 265 | 266 | Buffer.byteLength = function (str, encoding) { 267 | var ret 268 | str = str + '' 269 | switch (encoding || 'utf8') { 270 | case 'hex': 271 | ret = str.length / 2 272 | break 273 | case 'utf8': 274 | case 'utf-8': 275 | ret = utf8ToBytes(str).length 276 | break 277 | case 'ascii': 278 | case 'binary': 279 | case 'raw': 280 | ret = str.length 281 | break 282 | case 'base64': 283 | ret = base64ToBytes(str).length 284 | break 285 | case 'ucs2': 286 | case 'ucs-2': 287 | case 'utf16le': 288 | case 'utf-16le': 289 | ret = str.length * 2 290 | break 291 | default: 292 | throw new Error('Unknown encoding') 293 | } 294 | return ret 295 | } 296 | 297 | Buffer.concat = function (list, totalLength) { 298 | assert(isArray(list), 'Usage: Buffer.concat(list, [totalLength])\n' + 299 | 'list should be an Array.') 300 | 301 | if (list.length === 0) { 302 | return new Buffer(0) 303 | } else if (list.length === 1) { 304 | return list[0] 305 | } 306 | 307 | var i 308 | if (typeof totalLength !== 'number') { 309 | totalLength = 0 310 | for (i = 0; i < list.length; i++) { 311 | totalLength += list[i].length 312 | } 313 | } 314 | 315 | var buf = new Buffer(totalLength) 316 | var pos = 0 317 | for (i = 0; i < list.length; i++) { 318 | var item = list[i] 319 | item.copy(buf, pos) 320 | pos += item.length 321 | } 322 | return buf 323 | } 324 | 325 | // BUFFER INSTANCE METHODS 326 | // ======================= 327 | 328 | function _hexWrite (buf, string, offset, length) { 329 | offset = Number(offset) || 0 330 | var remaining = buf.length - offset 331 | if (!length) { 332 | length = remaining 333 | } else { 334 | length = Number(length) 335 | if (length > remaining) { 336 | length = remaining 337 | } 338 | } 339 | 340 | // must be an even number of digits 341 | var strLen = string.length 342 | assert(strLen % 2 === 0, 'Invalid hex string') 343 | 344 | if (length > strLen / 2) { 345 | length = strLen / 2 346 | } 347 | for (var i = 0; i < length; i++) { 348 | var byte = parseInt(string.substr(i * 2, 2), 16) 349 | assert(!isNaN(byte), 'Invalid hex string') 350 | buf[offset + i] = byte 351 | } 352 | Buffer._charsWritten = i * 2 353 | return i 354 | } 355 | 356 | function _utf8Write (buf, string, offset, length) { 357 | var charsWritten = Buffer._charsWritten = 358 | blitBuffer(utf8ToBytes(string), buf, offset, length) 359 | return charsWritten 360 | } 361 | 362 | function _asciiWrite (buf, string, offset, length) { 363 | var charsWritten = Buffer._charsWritten = 364 | blitBuffer(asciiToBytes(string), buf, offset, length) 365 | return charsWritten 366 | } 367 | 368 | function _binaryWrite (buf, string, offset, length) { 369 | return _asciiWrite(buf, string, offset, length) 370 | } 371 | 372 | function _base64Write (buf, string, offset, length) { 373 | var charsWritten = Buffer._charsWritten = 374 | blitBuffer(base64ToBytes(string), buf, offset, length) 375 | return charsWritten 376 | } 377 | 378 | function _utf16leWrite (buf, string, offset, length) { 379 | var charsWritten = Buffer._charsWritten = 380 | blitBuffer(utf16leToBytes(string), buf, offset, length) 381 | return charsWritten 382 | } 383 | 384 | Buffer.prototype.write = function (string, offset, length, encoding) { 385 | // Support both (string, offset, length, encoding) 386 | // and the legacy (string, encoding, offset, length) 387 | if (isFinite(offset)) { 388 | if (!isFinite(length)) { 389 | encoding = length 390 | length = undefined 391 | } 392 | } else { // legacy 393 | var swap = encoding 394 | encoding = offset 395 | offset = length 396 | length = swap 397 | } 398 | 399 | offset = Number(offset) || 0 400 | var remaining = this.length - offset 401 | if (!length) { 402 | length = remaining 403 | } else { 404 | length = Number(length) 405 | if (length > remaining) { 406 | length = remaining 407 | } 408 | } 409 | encoding = String(encoding || 'utf8').toLowerCase() 410 | 411 | var ret 412 | switch (encoding) { 413 | case 'hex': 414 | ret = _hexWrite(this, string, offset, length) 415 | break 416 | case 'utf8': 417 | case 'utf-8': 418 | ret = _utf8Write(this, string, offset, length) 419 | break 420 | case 'ascii': 421 | ret = _asciiWrite(this, string, offset, length) 422 | break 423 | case 'binary': 424 | ret = _binaryWrite(this, string, offset, length) 425 | break 426 | case 'base64': 427 | ret = _base64Write(this, string, offset, length) 428 | break 429 | case 'ucs2': 430 | case 'ucs-2': 431 | case 'utf16le': 432 | case 'utf-16le': 433 | ret = _utf16leWrite(this, string, offset, length) 434 | break 435 | default: 436 | throw new Error('Unknown encoding') 437 | } 438 | return ret 439 | } 440 | 441 | Buffer.prototype.toString = function (encoding, start, end) { 442 | var self = this 443 | 444 | encoding = String(encoding || 'utf8').toLowerCase() 445 | start = Number(start) || 0 446 | end = (end !== undefined) 447 | ? Number(end) 448 | : end = self.length 449 | 450 | // Fastpath empty strings 451 | if (end === start) 452 | return '' 453 | 454 | var ret 455 | switch (encoding) { 456 | case 'hex': 457 | ret = _hexSlice(self, start, end) 458 | break 459 | case 'utf8': 460 | case 'utf-8': 461 | ret = _utf8Slice(self, start, end) 462 | break 463 | case 'ascii': 464 | ret = _asciiSlice(self, start, end) 465 | break 466 | case 'binary': 467 | ret = _binarySlice(self, start, end) 468 | break 469 | case 'base64': 470 | ret = _base64Slice(self, start, end) 471 | break 472 | case 'ucs2': 473 | case 'ucs-2': 474 | case 'utf16le': 475 | case 'utf-16le': 476 | ret = _utf16leSlice(self, start, end) 477 | break 478 | default: 479 | throw new Error('Unknown encoding') 480 | } 481 | return ret 482 | } 483 | 484 | Buffer.prototype.toJSON = function () { 485 | return { 486 | type: 'Buffer', 487 | data: Array.prototype.slice.call(this._arr || this, 0) 488 | } 489 | } 490 | 491 | // copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) 492 | Buffer.prototype.copy = function (target, target_start, start, end) { 493 | var source = this 494 | 495 | if (!start) start = 0 496 | if (!end && end !== 0) end = this.length 497 | if (!target_start) target_start = 0 498 | 499 | // Copy 0 bytes; we're done 500 | if (end === start) return 501 | if (target.length === 0 || source.length === 0) return 502 | 503 | // Fatal error conditions 504 | assert(end >= start, 'sourceEnd < sourceStart') 505 | assert(target_start >= 0 && target_start < target.length, 506 | 'targetStart out of bounds') 507 | assert(start >= 0 && start < source.length, 'sourceStart out of bounds') 508 | assert(end >= 0 && end <= source.length, 'sourceEnd out of bounds') 509 | 510 | // Are we oob? 511 | if (end > this.length) 512 | end = this.length 513 | if (target.length - target_start < end - start) 514 | end = target.length - target_start + start 515 | 516 | var len = end - start 517 | 518 | if (len < 100 || !Buffer._useTypedArrays) { 519 | for (var i = 0; i < len; i++) 520 | target[i + target_start] = this[i + start] 521 | } else { 522 | target._set(this.subarray(start, start + len), target_start) 523 | } 524 | } 525 | 526 | function _base64Slice (buf, start, end) { 527 | if (start === 0 && end === buf.length) { 528 | return base64.fromByteArray(buf) 529 | } else { 530 | return base64.fromByteArray(buf.slice(start, end)) 531 | } 532 | } 533 | 534 | function _utf8Slice (buf, start, end) { 535 | var res = '' 536 | var tmp = '' 537 | end = Math.min(buf.length, end) 538 | 539 | for (var i = start; i < end; i++) { 540 | if (buf[i] <= 0x7F) { 541 | res += decodeUtf8Char(tmp) + String.fromCharCode(buf[i]) 542 | tmp = '' 543 | } else { 544 | tmp += '%' + buf[i].toString(16) 545 | } 546 | } 547 | 548 | return res + decodeUtf8Char(tmp) 549 | } 550 | 551 | function _asciiSlice (buf, start, end) { 552 | var ret = '' 553 | end = Math.min(buf.length, end) 554 | 555 | for (var i = start; i < end; i++) 556 | ret += String.fromCharCode(buf[i]) 557 | return ret 558 | } 559 | 560 | function _binarySlice (buf, start, end) { 561 | return _asciiSlice(buf, start, end) 562 | } 563 | 564 | function _hexSlice (buf, start, end) { 565 | var len = buf.length 566 | 567 | if (!start || start < 0) start = 0 568 | if (!end || end < 0 || end > len) end = len 569 | 570 | var out = '' 571 | for (var i = start; i < end; i++) { 572 | out += toHex(buf[i]) 573 | } 574 | return out 575 | } 576 | 577 | function _utf16leSlice (buf, start, end) { 578 | var bytes = buf.slice(start, end) 579 | var res = '' 580 | for (var i = 0; i < bytes.length; i += 2) { 581 | res += String.fromCharCode(bytes[i] + bytes[i+1] * 256) 582 | } 583 | return res 584 | } 585 | 586 | Buffer.prototype.slice = function (start, end) { 587 | var len = this.length 588 | start = clamp(start, len, 0) 589 | end = clamp(end, len, len) 590 | 591 | if (Buffer._useTypedArrays) { 592 | return Buffer._augment(this.subarray(start, end)) 593 | } else { 594 | var sliceLen = end - start 595 | var newBuf = new Buffer(sliceLen, undefined, true) 596 | for (var i = 0; i < sliceLen; i++) { 597 | newBuf[i] = this[i + start] 598 | } 599 | return newBuf 600 | } 601 | } 602 | 603 | // `get` will be removed in Node 0.13+ 604 | Buffer.prototype.get = function (offset) { 605 | console.log('.get() is deprecated. Access using array indexes instead.') 606 | return this.readUInt8(offset) 607 | } 608 | 609 | // `set` will be removed in Node 0.13+ 610 | Buffer.prototype.set = function (v, offset) { 611 | console.log('.set() is deprecated. Access using array indexes instead.') 612 | return this.writeUInt8(v, offset) 613 | } 614 | 615 | Buffer.prototype.readUInt8 = function (offset, noAssert) { 616 | if (!noAssert) { 617 | assert(offset !== undefined && offset !== null, 'missing offset') 618 | assert(offset < this.length, 'Trying to read beyond buffer length') 619 | } 620 | 621 | if (offset >= this.length) 622 | return 623 | 624 | return this[offset] 625 | } 626 | 627 | function _readUInt16 (buf, offset, littleEndian, noAssert) { 628 | if (!noAssert) { 629 | assert(typeof littleEndian === 'boolean', 'missing or invalid endian') 630 | assert(offset !== undefined && offset !== null, 'missing offset') 631 | assert(offset + 1 < buf.length, 'Trying to read beyond buffer length') 632 | } 633 | 634 | var len = buf.length 635 | if (offset >= len) 636 | return 637 | 638 | var val 639 | if (littleEndian) { 640 | val = buf[offset] 641 | if (offset + 1 < len) 642 | val |= buf[offset + 1] << 8 643 | } else { 644 | val = buf[offset] << 8 645 | if (offset + 1 < len) 646 | val |= buf[offset + 1] 647 | } 648 | return val 649 | } 650 | 651 | Buffer.prototype.readUInt16LE = function (offset, noAssert) { 652 | return _readUInt16(this, offset, true, noAssert) 653 | } 654 | 655 | Buffer.prototype.readUInt16BE = function (offset, noAssert) { 656 | return _readUInt16(this, offset, false, noAssert) 657 | } 658 | 659 | function _readUInt32 (buf, offset, littleEndian, noAssert) { 660 | if (!noAssert) { 661 | assert(typeof littleEndian === 'boolean', 'missing or invalid endian') 662 | assert(offset !== undefined && offset !== null, 'missing offset') 663 | assert(offset + 3 < buf.length, 'Trying to read beyond buffer length') 664 | } 665 | 666 | var len = buf.length 667 | if (offset >= len) 668 | return 669 | 670 | var val 671 | if (littleEndian) { 672 | if (offset + 2 < len) 673 | val = buf[offset + 2] << 16 674 | if (offset + 1 < len) 675 | val |= buf[offset + 1] << 8 676 | val |= buf[offset] 677 | if (offset + 3 < len) 678 | val = val + (buf[offset + 3] << 24 >>> 0) 679 | } else { 680 | if (offset + 1 < len) 681 | val = buf[offset + 1] << 16 682 | if (offset + 2 < len) 683 | val |= buf[offset + 2] << 8 684 | if (offset + 3 < len) 685 | val |= buf[offset + 3] 686 | val = val + (buf[offset] << 24 >>> 0) 687 | } 688 | return val 689 | } 690 | 691 | Buffer.prototype.readUInt32LE = function (offset, noAssert) { 692 | return _readUInt32(this, offset, true, noAssert) 693 | } 694 | 695 | Buffer.prototype.readUInt32BE = function (offset, noAssert) { 696 | return _readUInt32(this, offset, false, noAssert) 697 | } 698 | 699 | Buffer.prototype.readInt8 = function (offset, noAssert) { 700 | if (!noAssert) { 701 | assert(offset !== undefined && offset !== null, 702 | 'missing offset') 703 | assert(offset < this.length, 'Trying to read beyond buffer length') 704 | } 705 | 706 | if (offset >= this.length) 707 | return 708 | 709 | var neg = this[offset] & 0x80 710 | if (neg) 711 | return (0xff - this[offset] + 1) * -1 712 | else 713 | return this[offset] 714 | } 715 | 716 | function _readInt16 (buf, offset, littleEndian, noAssert) { 717 | if (!noAssert) { 718 | assert(typeof littleEndian === 'boolean', 'missing or invalid endian') 719 | assert(offset !== undefined && offset !== null, 'missing offset') 720 | assert(offset + 1 < buf.length, 'Trying to read beyond buffer length') 721 | } 722 | 723 | var len = buf.length 724 | if (offset >= len) 725 | return 726 | 727 | var val = _readUInt16(buf, offset, littleEndian, true) 728 | var neg = val & 0x8000 729 | if (neg) 730 | return (0xffff - val + 1) * -1 731 | else 732 | return val 733 | } 734 | 735 | Buffer.prototype.readInt16LE = function (offset, noAssert) { 736 | return _readInt16(this, offset, true, noAssert) 737 | } 738 | 739 | Buffer.prototype.readInt16BE = function (offset, noAssert) { 740 | return _readInt16(this, offset, false, noAssert) 741 | } 742 | 743 | function _readInt32 (buf, offset, littleEndian, noAssert) { 744 | if (!noAssert) { 745 | assert(typeof littleEndian === 'boolean', 'missing or invalid endian') 746 | assert(offset !== undefined && offset !== null, 'missing offset') 747 | assert(offset + 3 < buf.length, 'Trying to read beyond buffer length') 748 | } 749 | 750 | var len = buf.length 751 | if (offset >= len) 752 | return 753 | 754 | var val = _readUInt32(buf, offset, littleEndian, true) 755 | var neg = val & 0x80000000 756 | if (neg) 757 | return (0xffffffff - val + 1) * -1 758 | else 759 | return val 760 | } 761 | 762 | Buffer.prototype.readInt32LE = function (offset, noAssert) { 763 | return _readInt32(this, offset, true, noAssert) 764 | } 765 | 766 | Buffer.prototype.readInt32BE = function (offset, noAssert) { 767 | return _readInt32(this, offset, false, noAssert) 768 | } 769 | 770 | function _readFloat (buf, offset, littleEndian, noAssert) { 771 | if (!noAssert) { 772 | assert(typeof littleEndian === 'boolean', 'missing or invalid endian') 773 | assert(offset + 3 < buf.length, 'Trying to read beyond buffer length') 774 | } 775 | 776 | return ieee754.read(buf, offset, littleEndian, 23, 4) 777 | } 778 | 779 | Buffer.prototype.readFloatLE = function (offset, noAssert) { 780 | return _readFloat(this, offset, true, noAssert) 781 | } 782 | 783 | Buffer.prototype.readFloatBE = function (offset, noAssert) { 784 | return _readFloat(this, offset, false, noAssert) 785 | } 786 | 787 | function _readDouble (buf, offset, littleEndian, noAssert) { 788 | if (!noAssert) { 789 | assert(typeof littleEndian === 'boolean', 'missing or invalid endian') 790 | assert(offset + 7 < buf.length, 'Trying to read beyond buffer length') 791 | } 792 | 793 | return ieee754.read(buf, offset, littleEndian, 52, 8) 794 | } 795 | 796 | Buffer.prototype.readDoubleLE = function (offset, noAssert) { 797 | return _readDouble(this, offset, true, noAssert) 798 | } 799 | 800 | Buffer.prototype.readDoubleBE = function (offset, noAssert) { 801 | return _readDouble(this, offset, false, noAssert) 802 | } 803 | 804 | Buffer.prototype.writeUInt8 = function (value, offset, noAssert) { 805 | if (!noAssert) { 806 | assert(value !== undefined && value !== null, 'missing value') 807 | assert(offset !== undefined && offset !== null, 'missing offset') 808 | assert(offset < this.length, 'trying to write beyond buffer length') 809 | verifuint(value, 0xff) 810 | } 811 | 812 | if (offset >= this.length) return 813 | 814 | this[offset] = value 815 | } 816 | 817 | function _writeUInt16 (buf, value, offset, littleEndian, noAssert) { 818 | if (!noAssert) { 819 | assert(value !== undefined && value !== null, 'missing value') 820 | assert(typeof littleEndian === 'boolean', 'missing or invalid endian') 821 | assert(offset !== undefined && offset !== null, 'missing offset') 822 | assert(offset + 1 < buf.length, 'trying to write beyond buffer length') 823 | verifuint(value, 0xffff) 824 | } 825 | 826 | var len = buf.length 827 | if (offset >= len) 828 | return 829 | 830 | for (var i = 0, j = Math.min(len - offset, 2); i < j; i++) { 831 | buf[offset + i] = 832 | (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>> 833 | (littleEndian ? i : 1 - i) * 8 834 | } 835 | } 836 | 837 | Buffer.prototype.writeUInt16LE = function (value, offset, noAssert) { 838 | _writeUInt16(this, value, offset, true, noAssert) 839 | } 840 | 841 | Buffer.prototype.writeUInt16BE = function (value, offset, noAssert) { 842 | _writeUInt16(this, value, offset, false, noAssert) 843 | } 844 | 845 | function _writeUInt32 (buf, value, offset, littleEndian, noAssert) { 846 | if (!noAssert) { 847 | assert(value !== undefined && value !== null, 'missing value') 848 | assert(typeof littleEndian === 'boolean', 'missing or invalid endian') 849 | assert(offset !== undefined && offset !== null, 'missing offset') 850 | assert(offset + 3 < buf.length, 'trying to write beyond buffer length') 851 | verifuint(value, 0xffffffff) 852 | } 853 | 854 | var len = buf.length 855 | if (offset >= len) 856 | return 857 | 858 | for (var i = 0, j = Math.min(len - offset, 4); i < j; i++) { 859 | buf[offset + i] = 860 | (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff 861 | } 862 | } 863 | 864 | Buffer.prototype.writeUInt32LE = function (value, offset, noAssert) { 865 | _writeUInt32(this, value, offset, true, noAssert) 866 | } 867 | 868 | Buffer.prototype.writeUInt32BE = function (value, offset, noAssert) { 869 | _writeUInt32(this, value, offset, false, noAssert) 870 | } 871 | 872 | Buffer.prototype.writeInt8 = function (value, offset, noAssert) { 873 | if (!noAssert) { 874 | assert(value !== undefined && value !== null, 'missing value') 875 | assert(offset !== undefined && offset !== null, 'missing offset') 876 | assert(offset < this.length, 'Trying to write beyond buffer length') 877 | verifsint(value, 0x7f, -0x80) 878 | } 879 | 880 | if (offset >= this.length) 881 | return 882 | 883 | if (value >= 0) 884 | this.writeUInt8(value, offset, noAssert) 885 | else 886 | this.writeUInt8(0xff + value + 1, offset, noAssert) 887 | } 888 | 889 | function _writeInt16 (buf, value, offset, littleEndian, noAssert) { 890 | if (!noAssert) { 891 | assert(value !== undefined && value !== null, 'missing value') 892 | assert(typeof littleEndian === 'boolean', 'missing or invalid endian') 893 | assert(offset !== undefined && offset !== null, 'missing offset') 894 | assert(offset + 1 < buf.length, 'Trying to write beyond buffer length') 895 | verifsint(value, 0x7fff, -0x8000) 896 | } 897 | 898 | var len = buf.length 899 | if (offset >= len) 900 | return 901 | 902 | if (value >= 0) 903 | _writeUInt16(buf, value, offset, littleEndian, noAssert) 904 | else 905 | _writeUInt16(buf, 0xffff + value + 1, offset, littleEndian, noAssert) 906 | } 907 | 908 | Buffer.prototype.writeInt16LE = function (value, offset, noAssert) { 909 | _writeInt16(this, value, offset, true, noAssert) 910 | } 911 | 912 | Buffer.prototype.writeInt16BE = function (value, offset, noAssert) { 913 | _writeInt16(this, value, offset, false, noAssert) 914 | } 915 | 916 | function _writeInt32 (buf, value, offset, littleEndian, noAssert) { 917 | if (!noAssert) { 918 | assert(value !== undefined && value !== null, 'missing value') 919 | assert(typeof littleEndian === 'boolean', 'missing or invalid endian') 920 | assert(offset !== undefined && offset !== null, 'missing offset') 921 | assert(offset + 3 < buf.length, 'Trying to write beyond buffer length') 922 | verifsint(value, 0x7fffffff, -0x80000000) 923 | } 924 | 925 | var len = buf.length 926 | if (offset >= len) 927 | return 928 | 929 | if (value >= 0) 930 | _writeUInt32(buf, value, offset, littleEndian, noAssert) 931 | else 932 | _writeUInt32(buf, 0xffffffff + value + 1, offset, littleEndian, noAssert) 933 | } 934 | 935 | Buffer.prototype.writeInt32LE = function (value, offset, noAssert) { 936 | _writeInt32(this, value, offset, true, noAssert) 937 | } 938 | 939 | Buffer.prototype.writeInt32BE = function (value, offset, noAssert) { 940 | _writeInt32(this, value, offset, false, noAssert) 941 | } 942 | 943 | function _writeFloat (buf, value, offset, littleEndian, noAssert) { 944 | if (!noAssert) { 945 | assert(value !== undefined && value !== null, 'missing value') 946 | assert(typeof littleEndian === 'boolean', 'missing or invalid endian') 947 | assert(offset !== undefined && offset !== null, 'missing offset') 948 | assert(offset + 3 < buf.length, 'Trying to write beyond buffer length') 949 | verifIEEE754(value, 3.4028234663852886e+38, -3.4028234663852886e+38) 950 | } 951 | 952 | var len = buf.length 953 | if (offset >= len) 954 | return 955 | 956 | ieee754.write(buf, value, offset, littleEndian, 23, 4) 957 | } 958 | 959 | Buffer.prototype.writeFloatLE = function (value, offset, noAssert) { 960 | _writeFloat(this, value, offset, true, noAssert) 961 | } 962 | 963 | Buffer.prototype.writeFloatBE = function (value, offset, noAssert) { 964 | _writeFloat(this, value, offset, false, noAssert) 965 | } 966 | 967 | function _writeDouble (buf, value, offset, littleEndian, noAssert) { 968 | if (!noAssert) { 969 | assert(value !== undefined && value !== null, 'missing value') 970 | assert(typeof littleEndian === 'boolean', 'missing or invalid endian') 971 | assert(offset !== undefined && offset !== null, 'missing offset') 972 | assert(offset + 7 < buf.length, 973 | 'Trying to write beyond buffer length') 974 | verifIEEE754(value, 1.7976931348623157E+308, -1.7976931348623157E+308) 975 | } 976 | 977 | var len = buf.length 978 | if (offset >= len) 979 | return 980 | 981 | ieee754.write(buf, value, offset, littleEndian, 52, 8) 982 | } 983 | 984 | Buffer.prototype.writeDoubleLE = function (value, offset, noAssert) { 985 | _writeDouble(this, value, offset, true, noAssert) 986 | } 987 | 988 | Buffer.prototype.writeDoubleBE = function (value, offset, noAssert) { 989 | _writeDouble(this, value, offset, false, noAssert) 990 | } 991 | 992 | // fill(value, start=0, end=buffer.length) 993 | Buffer.prototype.fill = function (value, start, end) { 994 | if (!value) value = 0 995 | if (!start) start = 0 996 | if (!end) end = this.length 997 | 998 | if (typeof value === 'string') { 999 | value = value.charCodeAt(0) 1000 | } 1001 | 1002 | assert(typeof value === 'number' && !isNaN(value), 'value is not a number') 1003 | assert(end >= start, 'end < start') 1004 | 1005 | // Fill 0 bytes; we're done 1006 | if (end === start) return 1007 | if (this.length === 0) return 1008 | 1009 | assert(start >= 0 && start < this.length, 'start out of bounds') 1010 | assert(end >= 0 && end <= this.length, 'end out of bounds') 1011 | 1012 | for (var i = start; i < end; i++) { 1013 | this[i] = value 1014 | } 1015 | } 1016 | 1017 | Buffer.prototype.inspect = function () { 1018 | var out = [] 1019 | var len = this.length 1020 | for (var i = 0; i < len; i++) { 1021 | out[i] = toHex(this[i]) 1022 | if (i === exports.INSPECT_MAX_BYTES) { 1023 | out[i + 1] = '...' 1024 | break 1025 | } 1026 | } 1027 | return '' 1028 | } 1029 | 1030 | /** 1031 | * Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance. 1032 | * Added in Node 0.12. Only available in browsers that support ArrayBuffer. 1033 | */ 1034 | Buffer.prototype.toArrayBuffer = function () { 1035 | if (typeof Uint8Array !== 'undefined') { 1036 | if (Buffer._useTypedArrays) { 1037 | return (new Buffer(this)).buffer 1038 | } else { 1039 | var buf = new Uint8Array(this.length) 1040 | for (var i = 0, len = buf.length; i < len; i += 1) 1041 | buf[i] = this[i] 1042 | return buf.buffer 1043 | } 1044 | } else { 1045 | throw new Error('Buffer.toArrayBuffer not supported in this browser') 1046 | } 1047 | } 1048 | 1049 | // HELPER FUNCTIONS 1050 | // ================ 1051 | 1052 | function stringtrim (str) { 1053 | if (str.trim) return str.trim() 1054 | return str.replace(/^\s+|\s+$/g, '') 1055 | } 1056 | 1057 | var BP = Buffer.prototype 1058 | 1059 | /** 1060 | * Augment a Uint8Array *instance* (not the Uint8Array class!) with Buffer methods 1061 | */ 1062 | Buffer._augment = function (arr) { 1063 | arr._isBuffer = true 1064 | 1065 | // save reference to original Uint8Array get/set methods before overwriting 1066 | arr._get = arr.get 1067 | arr._set = arr.set 1068 | 1069 | // deprecated, will be removed in node 0.13+ 1070 | arr.get = BP.get 1071 | arr.set = BP.set 1072 | 1073 | arr.write = BP.write 1074 | arr.toString = BP.toString 1075 | arr.toLocaleString = BP.toString 1076 | arr.toJSON = BP.toJSON 1077 | arr.copy = BP.copy 1078 | arr.slice = BP.slice 1079 | arr.readUInt8 = BP.readUInt8 1080 | arr.readUInt16LE = BP.readUInt16LE 1081 | arr.readUInt16BE = BP.readUInt16BE 1082 | arr.readUInt32LE = BP.readUInt32LE 1083 | arr.readUInt32BE = BP.readUInt32BE 1084 | arr.readInt8 = BP.readInt8 1085 | arr.readInt16LE = BP.readInt16LE 1086 | arr.readInt16BE = BP.readInt16BE 1087 | arr.readInt32LE = BP.readInt32LE 1088 | arr.readInt32BE = BP.readInt32BE 1089 | arr.readFloatLE = BP.readFloatLE 1090 | arr.readFloatBE = BP.readFloatBE 1091 | arr.readDoubleLE = BP.readDoubleLE 1092 | arr.readDoubleBE = BP.readDoubleBE 1093 | arr.writeUInt8 = BP.writeUInt8 1094 | arr.writeUInt16LE = BP.writeUInt16LE 1095 | arr.writeUInt16BE = BP.writeUInt16BE 1096 | arr.writeUInt32LE = BP.writeUInt32LE 1097 | arr.writeUInt32BE = BP.writeUInt32BE 1098 | arr.writeInt8 = BP.writeInt8 1099 | arr.writeInt16LE = BP.writeInt16LE 1100 | arr.writeInt16BE = BP.writeInt16BE 1101 | arr.writeInt32LE = BP.writeInt32LE 1102 | arr.writeInt32BE = BP.writeInt32BE 1103 | arr.writeFloatLE = BP.writeFloatLE 1104 | arr.writeFloatBE = BP.writeFloatBE 1105 | arr.writeDoubleLE = BP.writeDoubleLE 1106 | arr.writeDoubleBE = BP.writeDoubleBE 1107 | arr.fill = BP.fill 1108 | arr.inspect = BP.inspect 1109 | arr.toArrayBuffer = BP.toArrayBuffer 1110 | 1111 | return arr 1112 | } 1113 | 1114 | // slice(start, end) 1115 | function clamp (index, len, defaultValue) { 1116 | if (typeof index !== 'number') return defaultValue 1117 | index = ~~index; // Coerce to integer. 1118 | if (index >= len) return len 1119 | if (index >= 0) return index 1120 | index += len 1121 | if (index >= 0) return index 1122 | return 0 1123 | } 1124 | 1125 | function coerce (length) { 1126 | // Coerce length to a number (possibly NaN), round up 1127 | // in case it's fractional (e.g. 123.456) then do a 1128 | // double negate to coerce a NaN to 0. Easy, right? 1129 | length = ~~Math.ceil(+length) 1130 | return length < 0 ? 0 : length 1131 | } 1132 | 1133 | function isArray (subject) { 1134 | return (Array.isArray || function (subject) { 1135 | return Object.prototype.toString.call(subject) === '[object Array]' 1136 | })(subject) 1137 | } 1138 | 1139 | function isArrayish (subject) { 1140 | return isArray(subject) || Buffer.isBuffer(subject) || 1141 | subject && typeof subject === 'object' && 1142 | typeof subject.length === 'number' 1143 | } 1144 | 1145 | function toHex (n) { 1146 | if (n < 16) return '0' + n.toString(16) 1147 | return n.toString(16) 1148 | } 1149 | 1150 | function utf8ToBytes (str) { 1151 | var byteArray = [] 1152 | for (var i = 0; i < str.length; i++) { 1153 | var b = str.charCodeAt(i) 1154 | if (b <= 0x7F) 1155 | byteArray.push(str.charCodeAt(i)) 1156 | else { 1157 | var start = i 1158 | if (b >= 0xD800 && b <= 0xDFFF) i++ 1159 | var h = encodeURIComponent(str.slice(start, i+1)).substr(1).split('%') 1160 | for (var j = 0; j < h.length; j++) 1161 | byteArray.push(parseInt(h[j], 16)) 1162 | } 1163 | } 1164 | return byteArray 1165 | } 1166 | 1167 | function asciiToBytes (str) { 1168 | var byteArray = [] 1169 | for (var i = 0; i < str.length; i++) { 1170 | // Node's code seems to be doing this and not & 0x7F.. 1171 | byteArray.push(str.charCodeAt(i) & 0xFF) 1172 | } 1173 | return byteArray 1174 | } 1175 | 1176 | function utf16leToBytes (str) { 1177 | var c, hi, lo 1178 | var byteArray = [] 1179 | for (var i = 0; i < str.length; i++) { 1180 | c = str.charCodeAt(i) 1181 | hi = c >> 8 1182 | lo = c % 256 1183 | byteArray.push(lo) 1184 | byteArray.push(hi) 1185 | } 1186 | 1187 | return byteArray 1188 | } 1189 | 1190 | function base64ToBytes (str) { 1191 | return base64.toByteArray(str) 1192 | } 1193 | 1194 | function blitBuffer (src, dst, offset, length) { 1195 | var pos 1196 | for (var i = 0; i < length; i++) { 1197 | if ((i + offset >= dst.length) || (i >= src.length)) 1198 | break 1199 | dst[i + offset] = src[i] 1200 | } 1201 | return i 1202 | } 1203 | 1204 | function decodeUtf8Char (str) { 1205 | try { 1206 | return decodeURIComponent(str) 1207 | } catch (err) { 1208 | return String.fromCharCode(0xFFFD) // UTF 8 invalid char 1209 | } 1210 | } 1211 | 1212 | /* 1213 | * We have to make sure that the value is a valid integer. This means that it 1214 | * is non-negative. It has no fractional component and that it does not 1215 | * exceed the maximum allowed value. 1216 | */ 1217 | function verifuint (value, max) { 1218 | assert(typeof value === 'number', 'cannot write a non-number as a number') 1219 | assert(value >= 0, 'specified a negative value for writing an unsigned value') 1220 | assert(value <= max, 'value is larger than maximum value for type') 1221 | assert(Math.floor(value) === value, 'value has a fractional component') 1222 | } 1223 | 1224 | function verifsint (value, max, min) { 1225 | assert(typeof value === 'number', 'cannot write a non-number as a number') 1226 | assert(value <= max, 'value larger than maximum allowed value') 1227 | assert(value >= min, 'value smaller than minimum allowed value') 1228 | assert(Math.floor(value) === value, 'value has a fractional component') 1229 | } 1230 | 1231 | function verifIEEE754 (value, max, min) { 1232 | assert(typeof value === 'number', 'cannot write a non-number as a number') 1233 | assert(value <= max, 'value larger than maximum allowed value') 1234 | assert(value >= min, 'value smaller than minimum allowed value') 1235 | } 1236 | 1237 | function assert (test, message) { 1238 | if (!test) throw new Error(message || 'Failed assertion') 1239 | } 1240 | 1241 | }).call(this,require("rH1JPG"),typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],"/../../node_modules/buffer/index.js","/../../node_modules/buffer") 1242 | },{"base64-js":1,"buffer":2,"ieee754":3,"rH1JPG":4}],3:[function(require,module,exports){ 1243 | (function (process,global,Buffer,__argument0,__argument1,__argument2,__argument3,__filename,__dirname){ 1244 | exports.read = function (buffer, offset, isLE, mLen, nBytes) { 1245 | var e, m 1246 | var eLen = (nBytes * 8) - mLen - 1 1247 | var eMax = (1 << eLen) - 1 1248 | var eBias = eMax >> 1 1249 | var nBits = -7 1250 | var i = isLE ? (nBytes - 1) : 0 1251 | var d = isLE ? -1 : 1 1252 | var s = buffer[offset + i] 1253 | 1254 | i += d 1255 | 1256 | e = s & ((1 << (-nBits)) - 1) 1257 | s >>= (-nBits) 1258 | nBits += eLen 1259 | for (; nBits > 0; e = (e * 256) + buffer[offset + i], i += d, nBits -= 8) {} 1260 | 1261 | m = e & ((1 << (-nBits)) - 1) 1262 | e >>= (-nBits) 1263 | nBits += mLen 1264 | for (; nBits > 0; m = (m * 256) + buffer[offset + i], i += d, nBits -= 8) {} 1265 | 1266 | if (e === 0) { 1267 | e = 1 - eBias 1268 | } else if (e === eMax) { 1269 | return m ? NaN : ((s ? -1 : 1) * Infinity) 1270 | } else { 1271 | m = m + Math.pow(2, mLen) 1272 | e = e - eBias 1273 | } 1274 | return (s ? -1 : 1) * m * Math.pow(2, e - mLen) 1275 | } 1276 | 1277 | exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { 1278 | var e, m, c 1279 | var eLen = (nBytes * 8) - mLen - 1 1280 | var eMax = (1 << eLen) - 1 1281 | var eBias = eMax >> 1 1282 | var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) 1283 | var i = isLE ? 0 : (nBytes - 1) 1284 | var d = isLE ? 1 : -1 1285 | var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 1286 | 1287 | value = Math.abs(value) 1288 | 1289 | if (isNaN(value) || value === Infinity) { 1290 | m = isNaN(value) ? 1 : 0 1291 | e = eMax 1292 | } else { 1293 | e = Math.floor(Math.log(value) / Math.LN2) 1294 | if (value * (c = Math.pow(2, -e)) < 1) { 1295 | e-- 1296 | c *= 2 1297 | } 1298 | if (e + eBias >= 1) { 1299 | value += rt / c 1300 | } else { 1301 | value += rt * Math.pow(2, 1 - eBias) 1302 | } 1303 | if (value * c >= 2) { 1304 | e++ 1305 | c /= 2 1306 | } 1307 | 1308 | if (e + eBias >= eMax) { 1309 | m = 0 1310 | e = eMax 1311 | } else if (e + eBias >= 1) { 1312 | m = ((value * c) - 1) * Math.pow(2, mLen) 1313 | e = e + eBias 1314 | } else { 1315 | m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) 1316 | e = 0 1317 | } 1318 | } 1319 | 1320 | for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} 1321 | 1322 | e = (e << mLen) | m 1323 | eLen += mLen 1324 | for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} 1325 | 1326 | buffer[offset + i - d] |= s * 128 1327 | } 1328 | 1329 | }).call(this,require("rH1JPG"),typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],"/../../node_modules/ieee754/index.js","/../../node_modules/ieee754") 1330 | },{"buffer":2,"rH1JPG":4}],4:[function(require,module,exports){ 1331 | (function (process,global,Buffer,__argument0,__argument1,__argument2,__argument3,__filename,__dirname){ 1332 | // shim for using process in browser 1333 | 1334 | var process = module.exports = {}; 1335 | 1336 | process.nextTick = (function () { 1337 | var canSetImmediate = typeof window !== 'undefined' 1338 | && window.setImmediate; 1339 | var canPost = typeof window !== 'undefined' 1340 | && window.postMessage && window.addEventListener 1341 | ; 1342 | 1343 | if (canSetImmediate) { 1344 | return function (f) { return window.setImmediate(f) }; 1345 | } 1346 | 1347 | if (canPost) { 1348 | var queue = []; 1349 | window.addEventListener('message', function (ev) { 1350 | var source = ev.source; 1351 | if ((source === window || source === null) && ev.data === 'process-tick') { 1352 | ev.stopPropagation(); 1353 | if (queue.length > 0) { 1354 | var fn = queue.shift(); 1355 | fn(); 1356 | } 1357 | } 1358 | }, true); 1359 | 1360 | return function nextTick(fn) { 1361 | queue.push(fn); 1362 | window.postMessage('process-tick', '*'); 1363 | }; 1364 | } 1365 | 1366 | return function nextTick(fn) { 1367 | setTimeout(fn, 0); 1368 | }; 1369 | })(); 1370 | 1371 | process.title = 'browser'; 1372 | process.browser = true; 1373 | process.env = {}; 1374 | process.argv = []; 1375 | 1376 | function noop() {} 1377 | 1378 | process.on = noop; 1379 | process.addListener = noop; 1380 | process.once = noop; 1381 | process.off = noop; 1382 | process.removeListener = noop; 1383 | process.removeAllListeners = noop; 1384 | process.emit = noop; 1385 | 1386 | process.binding = function (name) { 1387 | throw new Error('process.binding is not supported'); 1388 | } 1389 | 1390 | // TODO(shtylman) 1391 | process.cwd = function () { return '/' }; 1392 | process.chdir = function (dir) { 1393 | throw new Error('process.chdir is not supported'); 1394 | }; 1395 | 1396 | }).call(this,require("rH1JPG"),typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],"/../../node_modules/process/browser.js","/../../node_modules/process") 1397 | },{"buffer":2,"rH1JPG":4}],5:[function(require,module,exports){ 1398 | (function (process,global,Buffer,__argument0,__argument1,__argument2,__argument3,__filename,__dirname){ 1399 | 'use strict'; 1400 | 1401 | Object.defineProperty(exports, "__esModule", { 1402 | value: true 1403 | }); 1404 | exports.showPopup = undefined; 1405 | 1406 | var _getMatchedCssRules = require('../polyfills/get-matched-css-rules.jsx'); 1407 | 1408 | var _getMatchedCssRules2 = _interopRequireDefault(_getMatchedCssRules); 1409 | 1410 | var _CriticalCSS = require('../generators/CriticalCSS.jsx'); 1411 | 1412 | var _CriticalCSS2 = _interopRequireDefault(_CriticalCSS); 1413 | 1414 | var _selectText = require('../utilities/selectText.jsx'); 1415 | 1416 | var _selectText2 = _interopRequireDefault(_selectText); 1417 | 1418 | var _removeDocumentStyles = require('../utilities/removeDocumentStyles.jsx'); 1419 | 1420 | var _removeDocumentStyles2 = _interopRequireDefault(_removeDocumentStyles); 1421 | 1422 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 1423 | 1424 | // Generates the popup with wich the user will interact 1425 | function showPopup() { 1426 | var copyGeneratedStylesheet = function copyGeneratedStylesheet(event) { 1427 | event.preventDefault(); 1428 | event.stopPropagation(); 1429 | 1430 | (0, _selectText2.default)('CriticalSnap__output-css'); 1431 | document.execCommand('copy'); 1432 | copyButton.style.backgroundColor = "#34A853"; 1433 | copyButton.style.color = "#fff"; 1434 | copyButton.innerHTML = "Copied 👍"; 1435 | }; 1436 | 1437 | var previewGeneratedStylesheet = function previewGeneratedStylesheet(event) { 1438 | event.preventDefault(); 1439 | event.stopPropagation(); 1440 | 1441 | (0, _removeDocumentStyles2.default)(); 1442 | 1443 | var previewStyle = document.createElement('style'); 1444 | previewStyle.innerHTML = stylesheet; 1445 | document.getElementsByTagName('head')[0].appendChild(previewStyle); 1446 | 1447 | previewButton.removeEventListener('click', previewGeneratedStylesheet); 1448 | previewButton.remove(); 1449 | 1450 | minifyPopup(); 1451 | }; 1452 | 1453 | var selectGeneratedStylesheet = function selectGeneratedStylesheet(event) { 1454 | event.preventDefault(); 1455 | event.stopPropagation(); 1456 | (0, _selectText2.default)('CriticalSnap__output-css'); 1457 | }; 1458 | 1459 | var closePopup = function closePopup(event) { 1460 | if (event) event.preventDefault(); 1461 | destroyPopup(); 1462 | }; 1463 | 1464 | var createPopup = function createPopup(content) { 1465 | var popup = document.createElement('div'); 1466 | popup.id = 'CriticalSnap'; 1467 | 1468 | var divHTML = ''; 1469 | divHTML += '

Critical Snapshot

'; 1470 | divHTML += '

'; 1471 | divHTML += content; 1472 | divHTML += '

'; 1473 | divHTML += '
'; 1474 | divHTML += ''; 1475 | divHTML += ''; 1476 | divHTML += ''; 1477 | divHTML += '
'; 1478 | divHTML += '
'; 1479 | 1480 | popup.innerHTML = divHTML; 1481 | 1482 | return popup; 1483 | }; 1484 | 1485 | var minifyPopup = function minifyPopup() { 1486 | popup.className = 'CriticalSnap__minified'; 1487 | }; 1488 | 1489 | var destroyPopup = function destroyPopup() { 1490 | copyButton.removeEventListener('click', copyGeneratedStylesheet); 1491 | previewButton.removeEventListener('click', previewGeneratedStylesheet); 1492 | outputElement.removeEventListener('click', selectGeneratedStylesheet); 1493 | containerElement.removeEventListener('click', closePopup); 1494 | popup.remove(); 1495 | }; 1496 | 1497 | // scroll to top before generating CSS 1498 | document.body.scrollTop = 0; 1499 | 1500 | var snapshot = new _CriticalCSS2.default(window, document); 1501 | var stylesheet = snapshot.generate(); 1502 | 1503 | var popup = createPopup(stylesheet); 1504 | document.body.appendChild(popup); 1505 | 1506 | var copyButton = document.getElementById('CriticalSnap__copy'); 1507 | var previewButton = document.getElementById('CriticalSnap__preview'); 1508 | var outputElement = document.getElementById('CriticalSnap__output-css'); 1509 | var containerElement = document.getElementById('CriticalSnap'); 1510 | 1511 | copyButton.addEventListener('click', copyGeneratedStylesheet); 1512 | previewButton.addEventListener('click', previewGeneratedStylesheet); 1513 | outputElement.addEventListener('click', selectGeneratedStylesheet); 1514 | containerElement.addEventListener('click', closePopup); 1515 | }; 1516 | 1517 | exports.showPopup = showPopup; 1518 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInBvcHVwLmpzeCJdLCJuYW1lcyI6WyJzaG93UG9wdXAiLCJjb3B5R2VuZXJhdGVkU3R5bGVzaGVldCIsImV2ZW50IiwicHJldmVudERlZmF1bHQiLCJzdG9wUHJvcGFnYXRpb24iLCJkb2N1bWVudCIsImV4ZWNDb21tYW5kIiwiY29weUJ1dHRvbiIsInN0eWxlIiwiYmFja2dyb3VuZENvbG9yIiwiY29sb3IiLCJpbm5lckhUTUwiLCJwcmV2aWV3R2VuZXJhdGVkU3R5bGVzaGVldCIsInByZXZpZXdTdHlsZSIsImNyZWF0ZUVsZW1lbnQiLCJzdHlsZXNoZWV0IiwiZ2V0RWxlbWVudHNCeVRhZ05hbWUiLCJhcHBlbmRDaGlsZCIsInByZXZpZXdCdXR0b24iLCJyZW1vdmVFdmVudExpc3RlbmVyIiwicmVtb3ZlIiwibWluaWZ5UG9wdXAiLCJzZWxlY3RHZW5lcmF0ZWRTdHlsZXNoZWV0IiwiY2xvc2VQb3B1cCIsImRlc3Ryb3lQb3B1cCIsImNyZWF0ZVBvcHVwIiwiY29udGVudCIsInBvcHVwIiwiaWQiLCJkaXZIVE1MIiwiY2xhc3NOYW1lIiwib3V0cHV0RWxlbWVudCIsImNvbnRhaW5lckVsZW1lbnQiLCJib2R5Iiwic2Nyb2xsVG9wIiwic25hcHNob3QiLCJ3aW5kb3ciLCJnZW5lcmF0ZSIsImdldEVsZW1lbnRCeUlkIiwiYWRkRXZlbnRMaXN0ZW5lciJdLCJtYXBwaW5ncyI6Ijs7Ozs7OztBQUFBOzs7O0FBQ0E7Ozs7QUFDQTs7OztBQUNBOzs7Ozs7QUFFQTtBQUNBLFNBQVNBLFNBQVQsR0FBcUI7QUFDakIsUUFBSUMsMEJBQTBCLFNBQTFCQSx1QkFBMEIsQ0FBU0MsS0FBVCxFQUFnQjtBQUMxQ0EsY0FBTUMsY0FBTjtBQUNBRCxjQUFNRSxlQUFOOztBQUVBLGtDQUFXLDBCQUFYO0FBQ0FDLGlCQUFTQyxXQUFULENBQXFCLE1BQXJCO0FBQ0FDLG1CQUFXQyxLQUFYLENBQWlCQyxlQUFqQixHQUFtQyxTQUFuQztBQUNBRixtQkFBV0MsS0FBWCxDQUFpQkUs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QXdDM0IsMEJBQXhDO0FBQ0FtQixrQkFBY1EsZ0JBQWQsQ0FBK0IsT0FBL0IsRUFBd0NqQix5QkFBeEM7QUFDQVUscUJBQWlCTyxnQkFBakIsQ0FBa0MsT0FBbEMsRUFBMkNoQixVQUEzQztBQUNIOztRQUVRdkIsUyxHQUFBQSxTIiwiZmlsZSI6InBvcHVwLmpzeCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBnZXROb2RlQ1NTUnVsZXMgZnJvbSAnLi4vcG9seWZpbGxzL2dldC1tYXRjaGVkLWNzcy1ydWxlcy5qc3gnO1xuaW1wb3J0IENyaXRpY2FsQ1NTIGZyb20gJy4uL2dlbmVyYXRvcnMvQ3JpdGljYWxDU1MuanN4JztcbmltcG9ydCBzZWxlY3RUZXh0IGZyb20gJy4uL3V0aWxpdGllcy9zZWxlY3RUZXh0LmpzeCc7XG5pbXBvcnQgcmVtb3ZlRG9jdW1lbnRTdHlsZXMgZnJvbSAnLi4vdXRpbGl0aWVzL3JlbW92ZURvY3VtZW50U3R5bGVzLmpzeCc7XG5cbi8vIEdlbmVyYXRlcyB0aGUgcG9wdXAgd2l0aCB3aWNoIHRoZSB1c2VyIHdpbGwgaW50ZXJhY3RcbmZ1bmN0aW9uIHNob3dQb3B1cCgpIHtcbiAgICB2YXIgY29weUdlbmVyYXRlZFN0eWxlc2hlZXQgPSBmdW5jdGlvbihldmVudCkge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcblxuICAgICAgICBzZWxlY3RUZXh0KCdDcml0aWNhbFNuYXBfX291dHB1dC1jc3MnKTtcbiAgICAgICAgZG9jdW1lbnQuZXhlY0NvbW1hbmQoJ2NvcHknKTtcbiAgICAgICAgY29weUJ1dHRvbi5zdHlsZS5iYWNrZ3JvdW5kQ29sb3IgPSBcIiMzNEE4NTNcIjtcbiAgICAgICAgY29weUJ1dHRvbi5zdHlsZS5jb2xvciA9IFwiI2ZmZlwiO1xuICAgICAgICBjb3B5QnV0dG9uLmlubmVySFRNTCA9IFwiQ29waWVkIDxzcGFuPvCfkY08L3NwYW4+XCI7XG4gICAgfTtcblxuICAgIHZhciBwcmV2aWV3R2VuZXJhdGVkU3R5bGVzaGVldCA9IGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuXG4gICAgICAgIHJlbW92ZURvY3VtZW50U3R5bGVzKCk7XG5cbiAgICAgICAgdmFyIHByZXZpZXdTdHlsZSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3N0eWxlJyk7XG4gICAgICAgIHByZXZpZXdTdHlsZS5pbm5lckhUTUwgPSBzdHlsZXNoZWV0O1xuICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnaGVhZCcpWzBdLmFwcGVuZENoaWxkKHByZXZpZXdTdHlsZSk7XG5cbiAgICAgICAgcHJldmlld0J1dHRvbi5yZW1vdmVFdmVudExpc3RlbmVyKCdjbGljaycsIHByZXZpZXdHZW5lcmF0ZWRTdHlsZXNoZWV0KTtcbiAgICAgICAgcHJldmlld0J1dHRvbi5yZW1vdmUoKTtcblxuICAgICAgICBtaW5pZnlQb3B1cCgpO1xuICAgIH07XG5cbiAgICB2YXIgc2VsZWN0R2VuZXJhdGVkU3R5bGVzaGVldCA9IGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgICAgICBzZWxlY3RUZXh0KCdDcml0aWNhbFNuYXBfX291dHB1dC1jc3MnKTtcbiAgICB9O1xuXG4gICAgdmFyIGNsb3NlUG9wdXAgPSBmdW5jdGlvbihldmVudCkge1xuICAgICAgICBpZiAoZXZlbnQpIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIGRlc3Ryb3lQb3B1cCgpO1xuICAgIH07XG5cbiAgICB2YXIgY3JlYXRlUG9wdXAgPSBmdW5jdGlvbihjb250ZW50KSB7XG4gICAgICAgIHZhciBwb3B1cCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuICAgICAgICBwb3B1cC5pZCA9ICdDcml0aWNhbFNuYXAnO1xuXG4gICAgICAgIHZhciBkaXZIVE1MID0gJyc7XG4gICAgICAgIGRpdkhUTUwgKz0gICc8ZGl2PjxoMT5Dcml0aWNhbCBTbmFwc2hvdDwvaDE+JztcbiAgICAgICAgZGl2SFRNTCArPSAgICAgICc8cCBpZD1cIkNyaXRpY2FsU25hcF9fb3V0cHV0LWNzc1wiPic7XG4gICAgICAgIGRpdkhUTUwgKz0gICAgICAgICAgY29udGVudFxuICAgICAgICBkaXZIVE1MICs9ICAgICAgJzwvcD4nO1xuICAgICAgICBkaXZIVE1MICs9ICAgICAgJzxkaXYgaWQ9XCJDcml0aWNhbFNuYXBfX2J1dHRvbnNcIj4nO1xuICAgICAgICBkaXZIVE1MICs9ICAgICAgICAgICc8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cIkNyaXRpY2FsU25hcF9fYnV0dG9uXCIgaWQ9XCJDcml0aWNhbFNuYXBfX2NvcHlcIj5Db3B5PC9idXR0b24+JztcbiAgICAgICAgZGl2SFRNTCArPSAgICAgICAgICAnPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJDcml0aWNhbFNuYXBfX2J1dHRvblwiIGlkPVwiQ3JpdGljYWxTbmFwX19wcmV2aWV3XCI+UHJldmlldzwvYnV0dG9uPic7XG4gICAgICAgIGRpdkhUTUwgKz0gICAgICAgICAgJzxidXR0b24gdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwiQ3JpdGljYWxTbmFwX19idXR0b25cIiBpZD1cIkNyaXRpY2FsU25hcF9fY2xvc2VcIj5DbG9zZTwvYnV0dG9uPic7XG4gICAgICAgIGRpdkhUTUwgKz0gICAgICAnPC9kaXY+JztcbiAgICAgICAgZGl2SFRNTCArPSAgJzwvZGl2Pic7XG5cbiAgICAgICAgcG9wdXAuaW5uZXJIVE1MID0gZGl2SFRNTDtcblxuICAgICAgICByZXR1cm4gcG9wdXA7XG4gICAgfTtcblxuICAgIHZhciBtaW5pZnlQb3B1cCA9IGZ1bmN0aW9uKCkge1xuICAgICAgICBwb3B1cC5jbGFzc05hbWUgPSAnQ3JpdGljYWxTbmFwX19taW5pZmllZCc7XG4gICAgfTtcblxuICAgIHZhciBkZXN0cm95UG9wdXAgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgY29weUJ1dHRvbi5yZW1vdmVFdmVudExpc3RlbmVyKCdjbGljaycsIGNvcHlHZW5lcmF0ZWRTdHlsZXNoZWV0KTtcbiAgICAgICAgcHJldmlld0J1dHRvbi5yZW1vdmVFdmVudExpc3RlbmVyKCdjbGljaycsIHByZXZpZXdHZW5lcmF0ZWRTdHlsZXNoZWV0KTtcbiAgICAgICAgb3V0cHV0RWxlbWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCdjbGljaycsIHNlbGVjdEdlbmVyYXRlZFN0eWxlc2hlZXQpO1xuICAgICAgICBjb250YWluZXJFbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgY2xvc2VQb3B1cCk7XG4gICAgICAgIHBvcHVwLnJlbW92ZSgpO1xuICAgIH07XG5cbiAgICAvLyBzY3JvbGwgdG8gdG9wIGJlZm9yZSBnZW5lcmF0aW5nIENTU1xuICAgIGRvY3VtZW50LmJvZHkuc2Nyb2xsVG9wID0gMDtcblxuICAgIHZhciBzbmFwc2hvdCA9IG5ldyBDcml0aWNhbENTUyh3aW5kb3csIGRvY3VtZW50KTtcbiAgICB2YXIgc3R5bGVzaGVldCA9IHNuYXBzaG90LmdlbmVyYXRlKCk7XG5cbiAgICB2YXIgcG9wdXAgPSBjcmVhdGVQb3B1cChzdHlsZXNoZWV0KTtcbiAgICBkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHBvcHVwKTtcblxuICAgIHZhciBjb3B5QnV0dG9uID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ0NyaXRpY2FsU25hcF9fY29weScpO1xuICAgIHZhciBwcmV2aWV3QnV0dG9uID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ0NyaXRpY2FsU25hcF9fcHJldmlldycpO1xuICAgIHZhciBvdXRwdXRFbGVtZW50ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ0NyaXRpY2FsU25hcF9fb3V0cHV0LWNzcycpO1xuICAgIHZhciBjb250YWluZXJFbGVtZW50ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ0NyaXRpY2FsU25hcCcpO1xuXG4gICAgY29weUJ1dHRvbi5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIGNvcHlHZW5lcmF0ZWRTdHlsZXNoZWV0KTtcbiAgICBwcmV2aWV3QnV0dG9uLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgcHJldmlld0dlbmVyYXRlZFN0eWxlc2hlZXQpO1xuICAgIG91dHB1dEVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCBzZWxlY3RHZW5lcmF0ZWRTdHlsZXNoZWV0KTtcbiAgICBjb250YWluZXJFbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgY2xvc2VQb3B1cCk7XG59O1xuXG5leHBvcnQgeyBzaG93UG9wdXAgfTtcbiJdfQ== 1519 | }).call(this,require("rH1JPG"),typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],"/components/popup.jsx","/components") 1520 | },{"../generators/CriticalCSS.jsx":7,"../polyfills/get-matched-css-rules.jsx":8,"../utilities/removeDocumentStyles.jsx":10,"../utilities/selectText.jsx":11,"buffer":2,"rH1JPG":4}],6:[function(require,module,exports){ 1521 | (function (process,global,Buffer,__argument0,__argument1,__argument2,__argument3,__filename,__dirname){ 1522 | 'use strict'; 1523 | 1524 | var _popup = require('./components/popup.jsx'); 1525 | 1526 | (0, _popup.showPopup)(); 1527 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZha2VfNGM0Njg4NzUuanMiXSwibmFtZXMiOlsiX3BvcHVwIiwicmVxdWlyZSIsInNob3dQb3B1cCJdLCJtYXBwaW5ncyI6IkFBQUE7O0FBRUEsSUFBSUEsU0FBU0MsUUFBUSx3QkFBUixDQUFiOztBQUVBLENBQUMsR0FBR0QsT0FBT0UsU0FBWCIsImZpbGUiOiJmYWtlXzRjNDY4ODc1LmpzIiwic291cmNlc0NvbnRlbnQiOlsiJ3VzZSBzdHJpY3QnO1xuXG52YXIgX3BvcHVwID0gcmVxdWlyZSgnLi9jb21wb25lbnRzL3BvcHVwLmpzeCcpO1xuXG4oMCwgX3BvcHVwLnNob3dQb3B1cCkoKTsiXX0= 1528 | }).call(this,require("rH1JPG"),typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],"/fake_4c468875.js","/") 1529 | },{"./components/popup.jsx":5,"buffer":2,"rH1JPG":4}],7:[function(require,module,exports){ 1530 | (function (process,global,Buffer,__argument0,__argument1,__argument2,__argument3,__filename,__dirname){ 1531 | 'use strict'; 1532 | 1533 | Object.defineProperty(exports, "__esModule", { 1534 | value: true 1535 | }); 1536 | 1537 | var _explainWarning = require('../utilities/explainWarning.jsx'); 1538 | 1539 | var _explainWarning2 = _interopRequireDefault(_explainWarning); 1540 | 1541 | var _getMatchedCssRules = require('../polyfills/get-matched-css-rules.jsx'); 1542 | 1543 | var _getMatchedCssRules2 = _interopRequireDefault(_getMatchedCssRules); 1544 | 1545 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 1546 | 1547 | // CSS generator 1548 | var CriticalCSS = function CriticalCSS(window, document, options) { 1549 | var options = options || {}; 1550 | var parsedCSS = {}; 1551 | 1552 | var pushCSS = function pushCSS(rule) { 1553 | if (!!parsedCSS[rule.selectorText] === false) parsedCSS[rule.selectorText] = {}; 1554 | 1555 | var styles = rule.style.cssText.split(/;(?![A-Za-z0-9])/); 1556 | 1557 | styles.forEach(function (style) { 1558 | if (!!style === false) return; 1559 | 1560 | var pair = style.split(': '); 1561 | pair[0] = pair[0].trim(); 1562 | pair[1] = pair[1].trim(); 1563 | parsedCSS[rule.selectorText][pair[0]] = pair[1]; 1564 | }); 1565 | }; 1566 | 1567 | var parseTree = function parseTree() { 1568 | var height = window.innerHeight; 1569 | var walker = document.createTreeWalker(document, NodeFilter.SHOW_ELEMENT, function (node) { 1570 | return NodeFilter.FILTER_ACCEPT; 1571 | }, true); 1572 | 1573 | while (walker.nextNode()) { 1574 | var node = walker.currentNode; 1575 | var rect = node.getBoundingClientRect(); 1576 | if (rect.top < height || options.scanFullPage) { 1577 | var rules; 1578 | if (typeof window.getMatchedCSSRules !== 'function') { 1579 | rules = (0, _getMatchedCssRules2.default)(node); 1580 | } else { 1581 | rules = window.getMatchedCSSRules(node); 1582 | 1583 | (0, _explainWarning2.default)(); 1584 | } 1585 | if (!rules) rules = (0, _getMatchedCssRules2.default)(node); 1586 | 1587 | if (!!rules) { 1588 | for (var i = 0; i < rules.length; i++) { 1589 | pushCSS(rules[i]); 1590 | } 1591 | } 1592 | } 1593 | } 1594 | }; 1595 | 1596 | this.generate = function () { 1597 | var outputCSS = ''; 1598 | 1599 | for (var key in parsedCSS) { 1600 | outputCSS += key + '{'; 1601 | 1602 | for (var innerKey in parsedCSS[key]) { 1603 | outputCSS += innerKey + ':' + parsedCSS[key][innerKey] + ';'; 1604 | } 1605 | 1606 | outputCSS += '}'; 1607 | } 1608 | 1609 | return outputCSS; 1610 | }; 1611 | 1612 | parseTree(); 1613 | }; 1614 | 1615 | exports.default = CriticalCSS; 1616 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIkNyaXRpY2FsQ1NTLmpzeCJdLCJuYW1lcyI6WyJDcml0aWNhbENTUyIsIndpbmRvdyIsImRvY3VtZW50Iiwib3B0aW9ucyIsInBhcnNlZENTUyIsInB1c2hDU1MiLCJydWxlIiwic2VsZWN0b3JUZXh0Iiwic3R5bGVzIiwic3R5bGUiLCJjc3NUZXh0Iiwic3BsaXQiLCJmb3JFYWNoIiwicGFpciIsInRyaW0iLCJwYXJzZVRyZWUiLCJoZWlnaHQiLCJpbm5lckhlaWdodCIsIndhbGtlciIsImNyZWF0ZVRyZWVXYWxrZXIiLCJOb2RlRmlsdGVyIiwiU0hPV19FTEVNRU5UIiwibm9kZSIsIkZJTFRFUl9BQ0NFUFQiLCJuZXh0Tm9kZSIsImN1cnJlbnROb2RlIiwicmVjdCIsImdldEJvdW5kaW5nQ2xpZW50UmVjdCIsInRvcCIsInNjYW5GdWxsUGFnZSIsInJ1bGVzIiwiZ2V0TWF0Y2hlZENTU1J1bGVzIiwiaSIsImxlbmd0aCIsImdlbmVyYXRlIiwib3V0cHV0Q1NTIiwia2V5IiwiaW5uZXJLZXkiXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBOzs7O0FBQ0E7Ozs7OztBQUNBO0FBQ0EsSUFBSUEsY0FBYyxTQUFkQSxXQUFjLENBQVNDLE1BQVQsRUFBaUJDLFFBQWpCLEVBQTJCQyxPQUEzQixFQUFvQztBQUNsRCxRQUFJQSxVQUFVQSxXQUFXLEVBQXpCO0FBQ0EsUUFBSUMsWUFBWSxFQUFoQjs7QUFFQSxRQUFJQyxVQUFVLFNBQVZBLE9BQVUsQ0FBU0MsSUFBVCxFQUFlO0FBQ3pCLFlBQUcsQ0FBQyxDQUFDRixVQUFVRSxLQUFLQyxZQUFmLENBQUYsS0FBbUMsS0FBdEMsRUFBNkNILFVBQVVFLEtBQUtDLFlBQWYsSUFBK0IsRUFBL0I7O0FBRTdDLFlBQUlDLFNBQVNGLEtBQUtHLEtBQUwsQ0FBV0MsT0FBWCxDQUFtQkMsS0FBbkIsQ0FBeUIsa0JBQXpCLENBQWI7O0FBRUFILGVBQU9JLE9BQVAsQ0FBZSxVQUFTSCxLQUFULEVBQWdCO0FBQzNCLGdCQUFHLENBQUMsQ0FBQ0EsS0FBRixLQUFZLEtBQWYsRUFBc0I7O0FBRXRCLGdCQUFJSSxPQUFPSixNQUFNRSxLQUFOLENBQVksSUFBWixDQUFYO0FBQ0FFLGlCQUFLLENBQUwsSUFBVUEsS0FBSyxDQUFMLEVBQVFDLElBQVIsRUFBVjtBQUNBRCxpQkFBSyxDQUFMLElBQVVBLEtBQUssQ0FBTCxFQUFRQyxJQUFSLEVBQVY7QUFDQVYsc0JBQVVFLEtBQUtDLFlBQWYsRUFBNkJNLEtBQUssQ0FBTCxDQUE3QixJQUF3Q0EsS0FBSyxDQUFMLENBQXhDO0FBRUgsU0FSRDtBQVNILEtBZEQ7O0FBZ0JBLFFBQUlFLFlBQVksU0FBWkEsU0FBWSxHQUFXO0FBQ3ZCLFlBQUlDLFNBQVNmLE9BQU9nQixXQUFwQjtBQUNBLFlBQUlDLFNBQVNoQixTQUFTaUIsZ0JBQVQsQ0FBMEJqQixRQUExQixFQUFvQ2tCLFdBQVdDLFlBQS9DLEVBQTZELFVBQVNDLElBQVQsRUFBZTtBQUFFLG1CQUFPRixXQUFXRyxhQUFsQjtBQUFrQyxTQUFoSCxFQUFrSCxJQUFsSCxDQUFiOztBQUVBLGVBQU1MLE9BQU9NLFFBQVAsRUFBTixFQUF5QjtBQUNyQixnQkFBSUYsT0FBT0osT0FBT08sV0FBbEI7QUFDQSxnQkFBSUMsT0FBT0osS0FBS0sscUJBQUwsRUFBWDtBQUNBLGdCQUFHRCxLQUFLRSxHQUFMLEdBQVdaLE1BQVgsSUFBcUJiLFFBQVEwQixZQUFoQyxFQUE4QztBQUMxQyxvQkFBSUMsS0FBSjtBQUNBLG9CQUFLLE9BQU83QixPQUFPOEIsa0JBQWQsS0FBcUMsVUFBMUMsRUFBdUQ7QUFDbkRELDRCQUFRLGtDQUFnQlIsSUFBaEIsQ0FBUjtBQUNILGlCQUZELE1BRU87QUFDSFEsNEJBQVE3QixPQUFPOEIsa0JBQVAsQ0FBMEJULElBQTFCLENBQVI7O0FBRUE7QUFDSDtBQUNELG9CQUFJLENBQUNRLEtBQUwsRUFBWUEsUUFBUSxrQ0FBZ0JSLElBQWhCLENBQVI7O0FBRVosb0JBQUcsQ0FBQyxDQUFDUSxLQUFMLEVBQVk7QUFDUix5QkFBSyxJQUFJRSxJQUFJLENBQWIsRUFBZ0JBLElBQUlGLE1BQU1HLE1BQTFCLEVBQWtDRCxHQUFsQyxFQUF1QztBQUNuQzNCLGdDQUFReUIsTUFBTUUsQ0FBTixDQUFSO0FBRUg7QUFDSjtBQUVKO0FBQ0o7QUFDSixLQTNCRDs7QUE2QkEsU0FBS0UsUUFBTCxHQUFnQixZQUFXO0FBQ3ZCLFlBQUlDLFlBQVksRUFBaEI7O0FBRUEsYUFBSSxJQUFJQyxHQUFSLElBQWVoQyxTQUFmLEVBQTBCO0FBQ3RCK0IseUJBQWFDLE1BQU0sR0FBbkI7O0FBRUEsaUJBQUksSUFBSUMsUUFBUixJQUFvQmpDLFVBQVVnQyxHQUFWLENBQXBCLEVBQW9DO0FBQ2hDRCw2QkFBYUUsV0FBVyxHQUFYLEdBQWlCakMsVUFBVWdDLEdBQVYsRUFBZUMsUUFBZixDQUFqQixHQUE0QyxHQUF6RDtBQUVIOztBQUVERix5QkFBYSxHQUFiO0FBQ0g7O0FBRUQsZUFBT0EsU0FBUDtBQUNILEtBZkQ7O0FBaUJBcEI7QUFDSCxDQW5FRDs7a0JBcUVlZixXIiwiZmlsZSI6IkNyaXRpY2FsQ1NTLmpzeCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBleHBsYWluV2FybmluZyBmcm9tICcuLi91dGlsaXRpZXMvZXhwbGFpbldhcm5pbmcuanN4JztcbmltcG9ydCBnZXROb2RlQ1NTUnVsZXMgZnJvbSAnLi4vcG9seWZpbGxzL2dldC1tYXRjaGVkLWNzcy1ydWxlcy5qc3gnO1xuLy8gQ1NTIGdlbmVyYXRvclxudmFyIENyaXRpY2FsQ1NTID0gZnVuY3Rpb24od2luZG93LCBkb2N1bWVudCwgb3B0aW9ucykge1xuICAgIHZhciBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICB2YXIgcGFyc2VkQ1NTID0ge307XG5cbiAgICB2YXIgcHVzaENTUyA9IGZ1bmN0aW9uKHJ1bGUpIHtcbiAgICAgICAgaWYoISFwYXJzZWRDU1NbcnVsZS5zZWxlY3RvclRleHRdID09PSBmYWxzZSkgcGFyc2VkQ1NTW3J1bGUuc2VsZWN0b3JUZXh0XSA9IHt9O1xuXG4gICAgICAgIHZhciBzdHlsZXMgPSBydWxlLnN0eWxlLmNzc1RleHQuc3BsaXQoLzsoPyFbQS1aYS16MC05XSkvKTtcblxuICAgICAgICBzdHlsZXMuZm9yRWFjaChmdW5jdGlvbihzdHlsZSkge1xuICAgICAgICAgICAgaWYoISFzdHlsZSA9PT0gZmFsc2UpIHJldHVybjtcblxuICAgICAgICAgICAgdmFyIHBhaXIgPSBzdHlsZS5zcGxpdCgnOiAnKTtcbiAgICAgICAgICAgIHBhaXJbMF0gPSBwYWlyWzBdLnRyaW0oKTtcbiAgICAgICAgICAgIHBhaXJbMV0gPSBwYWlyWzFdLnRyaW0oKTtcbiAgICAgICAgICAgIHBhcnNlZENTU1tydWxlLnNlbGVjdG9yVGV4dF1bcGFpclswXV0gPSBwYWlyWzFdO1xuXG4gICAgICAgIH0pO1xuICAgIH07XG5cbiAgICB2YXIgcGFyc2VUcmVlID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBoZWlnaHQgPSB3aW5kb3cuaW5uZXJIZWlnaHQ7XG4gICAgICAgIHZhciB3YWxrZXIgPSBkb2N1bWVudC5jcmVhdGVUcmVlV2Fsa2VyKGRvY3VtZW50LCBOb2RlRmlsdGVyLlNIT1dfRUxFTUVOVCwgZnVuY3Rpb24obm9kZSkgeyByZXR1cm4gTm9kZUZpbHRlci5GSUxURVJfQUNDRVBUOyB9LCB0cnVlKTtcblxuICAgICAgICB3aGlsZSh3YWxrZXIubmV4dE5vZGUoKSkge1xuICAgICAgICAgICAgdmFyIG5vZGUgPSB3YWxrZXIuY3VycmVudE5vZGU7XG4gICAgICAgICAgICB2YXIgcmVjdCA9IG5vZGUuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICAgICAgICBpZihyZWN0LnRvcCA8IGhlaWdodCB8fCBvcHRpb25zLnNjYW5GdWxsUGFnZSkge1xuICAgICAgICAgICAgICAgIHZhciBydWxlcztcbiAgICAgICAgICAgICAgICBpZiAoIHR5cGVvZiB3aW5kb3cuZ2V0TWF0Y2hlZENTU1J1bGVzICE9PSAnZnVuY3Rpb24nICkge1xuICAgICAgICAgICAgICAgICAgICBydWxlcyA9IGdldE5vZGVDU1NSdWxlcyhub2RlKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBydWxlcyA9IHdpbmRvdy5nZXRNYXRjaGVkQ1NTUnVsZXMobm9kZSk7XG5cbiAgICAgICAgICAgICAgICAgICAgZXhwbGFpbldhcm5pbmcoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKCFydWxlcykgcnVsZXMgPSBnZXROb2RlQ1NTUnVsZXMobm9kZSk7XG5cbiAgICAgICAgICAgICAgICBpZighIXJ1bGVzKSB7XG4gICAgICAgICAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcnVsZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHB1c2hDU1MocnVsZXNbaV0pO1xuXG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB0aGlzLmdlbmVyYXRlID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBvdXRwdXRDU1MgPSAnJztcblxuICAgICAgICBmb3IodmFyIGtleSBpbiBwYXJzZWRDU1MpIHtcbiAgICAgICAgICAgIG91dHB1dENTUyArPSBrZXkgKyAneyc7XG5cbiAgICAgICAgICAgIGZvcih2YXIgaW5uZXJLZXkgaW4gcGFyc2VkQ1NTW2tleV0pIHtcbiAgICAgICAgICAgICAgICBvdXRwdXRDU1MgKz0gaW5uZXJLZXkgKyAnOicgKyBwYXJzZWRDU1Nba2V5XVtpbm5lcktleV0gKyAnOyc7XG5cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgb3V0cHV0Q1NTICs9ICd9JztcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBvdXRwdXRDU1M7XG4gICAgfTtcblxuICAgIHBhcnNlVHJlZSgpO1xufTtcblxuZXhwb3J0IGRlZmF1bHQgQ3JpdGljYWxDU1M7XG4iXX0= 1617 | }).call(this,require("rH1JPG"),typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],"/generators/CriticalCSS.jsx","/generators") 1618 | },{"../polyfills/get-matched-css-rules.jsx":8,"../utilities/explainWarning.jsx":9,"buffer":2,"rH1JPG":4}],8:[function(require,module,exports){ 1619 | (function (process,global,Buffer,__argument0,__argument1,__argument2,__argument3,__filename,__dirname){ 1620 | 'use strict'; 1621 | 1622 | Object.defineProperty(exports, "__esModule", { 1623 | value: true 1624 | }); 1625 | /* 1626 | * Fallback for window.getMatchedCSSRules(node); 1627 | * Forked from: (A Gecko only polyfill for Webkit's window.getMatchedCSSRules) https://gist.github.com/ydaniv/3033012 1628 | * This version is compatible with most browsers hoi 1629 | */ 1630 | var ELEMENT_RE = /[\w-]+/g; 1631 | var ID_RE = /#[\w-]+/g; 1632 | var CLASS_RE = /\.[\w-]+/g; 1633 | var ATTR_RE = /\[[^\]]+\]/g; 1634 | // :not() pseudo-class does not add to specificity, but its content does as if it was outside it 1635 | var PSEUDO_CLASSES_RE = /\:(?!not)[\w-]+(\(.*\))?/g; 1636 | var PSEUDO_ELEMENTS_RE = /\:\:?(after|before|first-letter|first-line|selection)/g; 1637 | 1638 | // convert an array-like object to array 1639 | function toArray(list) { 1640 | list = list || {}; 1641 | return [].slice.call(list); 1642 | } 1643 | 1644 | // handles extraction of `cssRules` as an `Array` from a stylesheet or something that behaves the same 1645 | function getSheetRules(stylesheet) { 1646 | var sheet_media = stylesheet.media && stylesheet.media.mediaText; 1647 | // if this sheet is disabled skip it 1648 | if (stylesheet.disabled) return []; 1649 | // if this sheet's media is specified and doesn't match the viewport then skip it 1650 | if (sheet_media && sheet_media.length && !window.matchMedia(sheet_media).matches) return []; 1651 | // get the style rules of this sheet 1652 | 1653 | try { 1654 | return toArray(stylesheet.cssRules || stylesheet.rules || []); 1655 | } catch (err) { 1656 | return []; 1657 | } 1658 | } 1659 | 1660 | function _find(string, re) { 1661 | var matches = string.match(re); 1662 | return re ? re.length : 0; 1663 | } 1664 | 1665 | // calculates the specificity of a given `selector` 1666 | function calculateScore(selector) { 1667 | var score = [0, 0, 0]; 1668 | var parts = selector.split(' '); 1669 | var part; 1670 | var match; 1671 | 1672 | //TODO: clean the ':not' part since the last ELEMENT_RE will pick it up 1673 | while (part = parts.shift(), typeof part == 'string') { 1674 | // find all pseudo-elements 1675 | match = _find(part, PSEUDO_ELEMENTS_RE); 1676 | score[2] = match; 1677 | // and remove them 1678 | match && (part = part.replace(PSEUDO_ELEMENTS_RE, '')); 1679 | // find all pseudo-classes 1680 | match = _find(part, PSEUDO_CLASSES_RE); 1681 | score[1] = match; 1682 | // and remove them 1683 | match && (part = part.replace(PSEUDO_CLASSES_RE, '')); 1684 | // find all attributes 1685 | match = _find(part, ATTR_RE); 1686 | score[1] += match; 1687 | // and remove them 1688 | match && (part = part.replace(ATTR_RE, '')); 1689 | // find all IDs 1690 | match = _find(part, ID_RE); 1691 | score[0] = match; 1692 | // and remove them 1693 | match && (part = part.replace(ID_RE, '')); 1694 | // find all classes 1695 | match = _find(part, CLASS_RE); 1696 | score[1] += match; 1697 | // and remove them 1698 | match && (part = part.replace(CLASS_RE, '')); 1699 | // find all elements 1700 | score[2] += _find(part, ELEMENT_RE); 1701 | } 1702 | return parseInt(score.join(''), 10); 1703 | } 1704 | 1705 | // returns the heights possible specificity score an element can get from a give rule's selectorText 1706 | function getSpecificityScore(element, selector_text) { 1707 | var selectors = selector_text.split(','); 1708 | var selector; 1709 | var score; 1710 | var result = 0; 1711 | 1712 | while (selector = selectors.shift()) { 1713 | element.matches = element.matches || element.webkitMatchesSelector || element.mozMatchesSelector || element.msMatchesSelector || element.oMatchesSelector; 1714 | if (element.matches(selector)) { 1715 | score = calculateScore(selector); 1716 | result = score > result ? score : result; 1717 | } 1718 | } 1719 | 1720 | return result; 1721 | } 1722 | 1723 | function sortBySpecificity(element, rules) { 1724 | // comparing function that sorts CSSStyleRules according to specificity of their `selectorText` 1725 | function compareSpecificity(a, b) { 1726 | return getSpecificityScore(element, b.selectorText) - getSpecificityScore(element, a.selectorText); 1727 | } 1728 | 1729 | return rules.sort(compareSpecificity); 1730 | } 1731 | 1732 | //TODO: not supporting 2nd argument for selecting pseudo elements 1733 | //TODO: not supporting 3rd argument for checking author style sheets only 1734 | function getNodeCSSRules(element /*, pseudo, author_only*/) { 1735 | var style_sheets; 1736 | var sheet; 1737 | var sheet_media; 1738 | var rules; 1739 | var rule; 1740 | var result = []; 1741 | 1742 | // get stylesheets and convert to a regular Array 1743 | style_sheets = toArray(window.document.styleSheets); 1744 | 1745 | // assuming the browser hands us stylesheets in order of appearance 1746 | // we iterate them from the beginning to follow proper cascade order 1747 | while (sheet = style_sheets.shift()) { 1748 | // get the style rules of this sheet 1749 | rules = getSheetRules(sheet); 1750 | // loop the rules in order of appearance 1751 | while (rule = rules.shift()) { 1752 | // if this is an @import rule 1753 | if (rule.styleSheet) { 1754 | // insert the imported stylesheet's rules at the beginning of this stylesheet's rules 1755 | rules = getSheetRules(rule.styleSheet).concat(rules); 1756 | // and skip this rule 1757 | continue; 1758 | } 1759 | // if there's no stylesheet attribute BUT there IS a media attribute it's a media rule 1760 | else if (rule.media) { 1761 | // insert the contained rules of this media rule to the beginning of this stylesheet's rules 1762 | rules = getSheetRules(rule).concat(rules); 1763 | // and skip it 1764 | continue; 1765 | } 1766 | 1767 | // TODO: deal with unusual selectors 1768 | // Some sites use selectors like '[ng:cloak]' wich is not a valid selector 1769 | // try-catching this allows the plugin to work 1770 | try { 1771 | // check if this element matches this rule's selector 1772 | if (element.matches(rule.selectorText)) { 1773 | // push the rule to the results set 1774 | result.push(rule); 1775 | } 1776 | } catch (e) { 1777 | // do nothing 1778 | } 1779 | } 1780 | } 1781 | 1782 | // sort according to specificity 1783 | return sortBySpecificity(element, result); 1784 | }; 1785 | 1786 | exports.default = getNodeCSSRules; 1787 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImdldC1tYXRjaGVkLWNzcy1ydWxlcy5qc3giXSwibmFtZXMiOlsiRUxFTUVOVF9SRSIsIklEX1JFIiwiQ0xBU1NfUkUiLCJBVFRSX1JFIiwiUFNFVURPX0NMQVNTRVNfUkUiLCJQU0VVRE9fRUxFTUVOVFNfUkUiLCJ0b0FycmF5IiwibGlzdCIsInNsaWNlIiwiY2FsbCIsImdldFNoZWV0UnVsZXMiLCJzdHlsZXNoZWV0Iiwic2hlZXRfbWVkaWEiLCJtZWRpYSIsIm1lZGlhVGV4dCIsImRpc2FibGVkIiwibGVuZ3RoIiwid2luZG93IiwibWF0Y2hNZWRpYSIsIm1hdGNoZXMiLCJjc3NSdWxlcyIsInJ1bGVzIiwiZXJyIiwiX2ZpbmQiLCJzdHJpbmciLCJyZSIsIm1hdGNoIiwiY2FsY3VsYXRlU2NvcmUiLCJzZWxlY3RvciIsInNjb3JlIiwicGFydHMiLCJzcGxpdCIsInBhcnQiLCJzaGlmdCIsInJlcGxhY2UiLCJwYXJzZUludCIsImpvaW4iLCJnZXRTcGVjaWZpY2l0eVNjb3JlIiwiZWxlbWVudCIsInNlbGVjdG9yX3RleHQiLCJzZWxlY3RvcnMiLCJyZXN1bHQiLCJ3ZWJraXRNYXRjaGVzU2VsZWN0b3IiLCJtb3pNYXRjaGVzU2VsZWN0b3IiLCJtc01hdGNoZXNTZWxlY3RvciIsIm9NYXRjaGVzU2VsZWN0b3IiLCJzb3J0QnlTcGVjaWZpY2l0eSIsImNvbXBhcmVTcGVjaWZpY2l0eSIsImEiLCJiIiwic2VsZWN0b3JUZXh0Iiwic29ydCIsImdldE5vZGVDU1NSdWxlcyIsInN0eWxlX3NoZWV0cyIsInNoZWV0IiwicnVsZSIsImRvY3VtZW50Iiwic3R5bGVTaGVldHMiLCJzdHlsZVNoZWV0IiwiY29uY2F0IiwicHVzaCIsImUiXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUE7Ozs7O0FBS0EsSUFBSUEsYUFBYSxTQUFqQjtBQUNBLElBQUlDLFFBQVEsVUFBWjtBQUNBLElBQUlDLFdBQVcsV0FBZjtBQUNBLElBQUlDLFVBQVUsYUFBZDtBQUNBO0FBQ0EsSUFBSUMs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QUFDQTtBQUNBLFdBQU9ILFFBQVFELGFBQWFwQixLQUFiLEVBQWYsRUFBcUM7QUFDakM7QUFDQVosZ0JBQVFYLGNBQWM0QyxLQUFkLENBQVI7QUFDQTtBQUNBLGVBQU9DLE9BQU9sQyxNQUFNWSxLQUFOLEVBQWQsRUFBNkI7QUFDekI7QUFDQSxnQkFBSXNCLEtBQUtHLFVBQVQsRUFBcUI7QUFDakI7QUFDQXJDLHdCQUFRWCxjQUFjNkMsS0FBS0csVUFBbkIsRUFBK0JDLE1BQS9CLENBQXNDdEMsS0FBdEMsQ0FBUjtBQUNBO0FBQ0E7QUFDSDtBQUNEO0FBTkEsaUJBT0ssSUFBSWtDLEtBQUsxQyxLQUFULEVBQWdCO0FBQ2pCO0FBQ0FRLDRCQUFRWCxjQUFjNkMsSUFBZCxFQUFvQkksTUFBcEIsQ0FBMkJ0QyxLQUEzQixDQUFSO0FBQ0E7QUFDQTtBQUNIOztBQUVEO0FBQ0E7QUFDQTtBQUNBLGdCQUFJO0FBQ0E7QUFDQSxvQkFBSWlCLFFBQVFuQixPQUFSLENBQWdCb0MsS0FBS0wsWUFBckIsQ0FBSixFQUF3QztBQUNwQztBQUNBVCwyQkFBT21CLElBQVAsQ0FBWUwsSUFBWjtBQUNIO0FBQ0osYUFORCxDQU9BLE9BQU9NLENBQVAsRUFBVTtBQUNOO0FBQ0g7QUFDSjtBQUNKOztBQUVEO0FBQ0EsV0FBT2Ysa0JBQWtCUixPQUFsQixFQUEyQkcsTUFBM0IsQ0FBUDtBQUNIOztrQkFFY1csZSIsImZpbGUiOiJnZXQtbWF0Y2hlZC1jc3MtcnVsZXMuanN4Iiwic291cmNlc0NvbnRlbnQiOlsiLypcbiAqIEZhbGxiYWNrIGZvciB3aW5kb3cuZ2V0TWF0Y2hlZENTU1J1bGVzKG5vZGUpO1xuICogRm9ya2VkIGZyb206IChBIEdlY2tvIG9ubHkgcG9seWZpbGwgZm9yIFdlYmtpdCdzIHdpbmRvdy5nZXRNYXRjaGVkQ1NTUnVsZXMpIGh0dHBzOi8vZ2lzdC5naXRodWIuY29tL3lkYW5pdi8zMDMzMDEyXG4gKiBUaGlzIHZlcnNpb24gaXMgY29tcGF0aWJsZSB3aXRoIG1vc3QgYnJvd3NlcnMgaG9pXG4gKi9cbnZhciBFTEVNRU5UX1JFID0gL1tcXHctXSsvZztcbnZhciBJRF9SRSA9IC8jW1xcdy1dKy9nO1xudmFyIENMQVNTX1JFID0gL1xcLltcXHctXSsvZztcbnZhciBBVFRSX1JFID0gL1xcW1teXFxdXStcXF0vZztcbi8vIDpub3QoKSBwc2V1ZG8tY2xhc3MgZG9lcyBub3QgYWRkIHRvIHNwZWNpZmljaXR5LCBidXQgaXRzIGNvbnRlbnQgZG9lcyBhcyBpZiBpdCB3YXMgb3V0c2lkZSBpdFxudmFyIFBTRVVET19DTEFTU0VTX1JFID0gL1xcOig/IW5vdClbXFx3LV0rKFxcKC4qXFwpKT8vZztcbnZhciBQU0VVRE9fRUxFTUVOVFNfUkUgPSAvXFw6XFw6PyhhZnRlcnxiZWZvcmV8Zmlyc3QtbGV0dGVyfGZpcnN0LWxpbmV8c2VsZWN0aW9uKS9nO1xuXG4vLyBjb252ZXJ0IGFuIGFycmF5LWxpa2Ugb2JqZWN0IHRvIGFycmF5XG5mdW5jdGlvbiB0b0FycmF5IChsaXN0KSB7XG4gICAgbGlzdCA9IGxpc3QgfHwge307XG4gICAgcmV0dXJuIFtdLnNsaWNlLmNhbGwobGlzdCk7XG59XG5cbi8vIGhhbmRsZXMgZXh0cmFjdGlvbiBvZiBgY3NzUnVsZXNgIGFzIGFuIGBBcnJheWAgZnJvbSBhIHN0eWxlc2hlZXQgb3Igc29tZXRoaW5nIHRoYXQgYmVoYXZlcyB0aGUgc2FtZVxuZnVuY3Rpb24gZ2V0U2hlZXRSdWxlcyAoc3R5bGVzaGVldCkge1xuICAgIHZhciBzaGVldF9tZWRpYSA9IHN0eWxlc2hlZXQubWVkaWEgJiYgc3R5bGVzaGVldC5tZWRpYS5tZWRpYVRleHQ7XG4gICAgLy8gaWYgdGhpcyBzaGVldCBpcyBkaXNhYmxlZCBza2lwIGl0XG4gICAgaWYgKCBzdHlsZXNoZWV0LmRpc2FibGVkICkgcmV0dXJuIFtdO1xuICAgIC8vIGlmIHRoaXMgc2hlZXQncyBtZWRpYSBpcyBzcGVjaWZpZWQgYW5kIGRvZXNuJ3QgbWF0Y2ggdGhlIHZpZXdwb3J0IHRoZW4gc2tpcCBpdFxuICAgIGlmICggc2hlZXRfbWVkaWEgJiYgc2hlZXRfbWVkaWEubGVuZ3RoICYmICEgd2luZG93Lm1hdGNoTWVkaWEoc2hlZXRfbWVkaWEpLm1hdGNoZXMgKSByZXR1cm4gW107XG4gICAgLy8gZ2V0IHRoZSBzdHlsZSBydWxlcyBvZiB0aGlzIHNoZWV0XG5cbiAgICB0cnkge1xuICAgICAgICByZXR1cm4gdG9BcnJheShzdHlsZXNoZWV0LmNzc1J1bGVzIHx8IHN0eWxlc2hlZXQucnVsZXMgfHwgW10pO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICByZXR1cm4gW107XG4gICAgfVxufVxuXG5mdW5jdGlvbiBfZmluZCAoc3RyaW5nLCByZSkge1xuICAgIHZhciBtYXRjaGVzID0gc3RyaW5nLm1hdGNoKHJlKTtcbiAgICByZXR1cm4gcmUgPyByZS5sZW5ndGggOiAwO1xufVxuXG4vLyBjYWxjdWxhdGVzIHRoZSBzcGVjaWZpY2l0eSBvZiBhIGdpdmVuIGBzZWxlY3RvcmBcbmZ1bmN0aW9uIGNhbGN1bGF0ZVNjb3JlIChzZWxlY3Rvcikge1xuICAgIHZhciBzY29yZSA9IFswLDAsMF07XG4gICAgdmFyIHBhcnRzID0gc2VsZWN0b3Iuc3BsaXQoJyAnKTtcbiAgICB2YXIgcGFydDtcbiAgICB2YXIgbWF0Y2g7XG5cbiAgICAvL1RPRE86IGNsZWFuIHRoZSAnOm5vdCcgcGFydCBzaW5jZSB0aGUgbGFzdCBFTEVNRU5UX1JFIHdpbGwgcGljayBpdCB1cFxuICAgIHdoaWxlICggcGFydCA9IHBhcnRzLnNoaWZ0KCksIHR5cGVvZiBwYXJ0ID09ICdzdHJpbmcnICkge1xuICAgICAgICAvLyBmaW5kIGFsbCBwc2V1ZG8tZWxlbWVudHNcbiAgICAgICAgbWF0Y2ggPSBfZmluZChwYXJ0LCBQU0VVRE9fRUxFTUVOVFNfUkUpO1xuICAgICAgICBzY29yZVsyXSA9IG1hdGNoO1xuICAgICAgICAvLyBhbmQgcmVtb3ZlIHRoZW1cbiAgICAgICAgbWF0Y2ggJiYgKHBhcnQgPSBwYXJ0LnJlcGxhY2UoUFNFVURPX0VMRU1FTlRTX1JFLCAnJykpO1xuICAgICAgICAvLyBmaW5kIGFsbCBwc2V1ZG8tY2xhc3Nlc1xuICAgICAgICBtYXRjaCA9IF9maW5kKHBhcnQsIFBTRVVET19DTEFTU0VTX1JFKTtcbiAgICAgICAgc2NvcmVbMV0gPSBtYXRjaDtcbiAgICAgICAgLy8gYW5kIHJlbW92ZSB0aGVtXG4gICAgICAgIG1hdGNoICYmIChwYXJ0ID0gcGFydC5yZXBsYWNlKFBTRVVET19DTEFTU0VTX1JFLCAnJykpO1xuICAgICAgICAvLyBmaW5kIGFsbCBhdHRyaWJ1dGVzXG4gICAgICAgIG1hdGNoID0gX2ZpbmQocGFydCwgQVRUUl9SRSk7XG4gICAgICAgIHNjb3JlWzFdICs9IG1hdGNoO1xuICAgICAgICAvLyBhbmQgcmVtb3ZlIHRoZW1cbiAgICAgICAgbWF0Y2ggJiYgKHBhcnQgPSBwYXJ0LnJlcGxhY2UoQVRUUl9SRSwgJycpKTtcbiAgICAgICAgLy8gZmluZCBhbGwgSURzXG4gICAgICAgIG1hdGNoID0gX2ZpbmQocGFydCwgSURfUkUpO1xuICAgICAgICBzY29yZVswXSA9IG1hdGNoO1xuICAgICAgICAvLyBhbmQgcmVtb3ZlIHRoZW1cbiAgICAgICAgbWF0Y2ggJiYgKHBhcnQgPSBwYXJ0LnJlcGxhY2UoSURfUkUsICcnKSk7XG4gICAgICAgIC8vIGZpbmQgYWxsIGNsYXNzZXNcbiAgICAgICAgbWF0Y2ggPSBfZmluZChwYXJ0LCBDTEFTU19SRSk7XG4gICAgICAgIHNjb3JlWzFdICs9IG1hdGNoO1xuICAgICAgICAvLyBhbmQgcmVtb3ZlIHRoZW1cbiAgICAgICAgbWF0Y2ggJiYgKHBhcnQgPSBwYXJ0LnJlcGxhY2UoQ0xBU1NfUkUsICcnKSk7XG4gICAgICAgIC8vIGZpbmQgYWxsIGVsZW1lbnRzXG4gICAgICAgIHNjb3JlWzJdICs9IF9maW5kKHBhcnQsIEVMRU1FTlRfUkUpO1xuICAgIH1cbiAgICByZXR1cm4gcGFyc2VJbnQoc2NvcmUuam9pbignJyksIDEwKTtcbn1cblxuLy8gcmV0dXJucyB0aGUgaGVpZ2h0cyBwb3NzaWJsZSBzcGVjaWZpY2l0eSBzY29yZSBhbiBlbGVtZW50IGNhbiBnZXQgZnJvbSBhIGdpdmUgcnVsZSdzIHNlbGVjdG9yVGV4dFxuZnVuY3Rpb24gZ2V0U3BlY2lmaWNpdHlTY29yZSAoZWxlbWVudCwgc2VsZWN0b3JfdGV4dCkge1xuICAgIHZhciBzZWxlY3RvcnMgPSBzZWxlY3Rvcl90ZXh0LnNwbGl0KCcsJyk7XG4gICAgdmFyIHNlbGVjdG9yO1xuICAgIHZhciBzY29yZTtcbiAgICB2YXIgcmVzdWx0ID0gMDtcblxuICAgIHdoaWxlIChzZWxlY3RvciA9IHNlbGVjdG9ycy5zaGlmdCgpKSB7XG4gICAgICAgIGVsZW1lbnQubWF0Y2hlcyA9IGVsZW1lbnQubWF0Y2hlcyB8fCBlbGVtZW50LndlYmtpdE1hdGNoZXNTZWxlY3RvciB8fCBlbGVtZW50Lm1vek1hdGNoZXNTZWxlY3RvciB8fCBlbGVtZW50Lm1zTWF0Y2hlc1NlbGVjdG9yIHx8IGVsZW1lbnQub01hdGNoZXNTZWxlY3RvcjtcbiAgICAgICAgaWYgKCBlbGVtZW50Lm1hdGNoZXMoc2VsZWN0b3IpICkge1xuICAgICAgICAgICAgc2NvcmUgPSBjYWxjdWxhdGVTY29yZShzZWxlY3Rvcik7XG4gICAgICAgICAgICByZXN1bHQgPSBzY29yZSA+IHJlc3VsdCA/IHNjb3JlIDogcmVzdWx0O1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdDtcbn1cblxuZnVuY3Rpb24gc29ydEJ5U3BlY2lmaWNpdHkgKGVsZW1lbnQsIHJ1bGVzKSB7XG4gICAgLy8gY29tcGFyaW5nIGZ1bmN0aW9uIHRoYXQgc29ydHMgQ1NTU3R5bGVSdWxlcyBhY2NvcmRpbmcgdG8gc3BlY2lmaWNpdHkgb2YgdGhlaXIgYHNlbGVjdG9yVGV4dGBcbiAgICBmdW5jdGlvbiBjb21wYXJlU3BlY2lmaWNpdHkgKGEsIGIpIHtcbiAgICAgICAgcmV0dXJuIGdldFNwZWNpZmljaXR5U2NvcmUoZWxlbWVudCwgYi5zZWxlY3RvclRleHQpIC0gZ2V0U3BlY2lmaWNpdHlTY29yZShlbGVtZW50LCBhLnNlbGVjdG9yVGV4dCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJ1bGVzLnNvcnQoY29tcGFyZVNwZWNpZmljaXR5KTtcbn1cblxuLy9UT0RPOiBub3Qgc3VwcG9ydGluZyAybmQgYXJndW1lbnQgZm9yIHNlbGVjdGluZyBwc2V1ZG8gZWxlbWVudHNcbi8vVE9ETzogbm90IHN1cHBvcnRpbmcgM3JkIGFyZ3VtZW50IGZvciBjaGVja2luZyBhdXRob3Igc3R5bGUgc2hlZXRzIG9ubHlcbmZ1bmN0aW9uIGdldE5vZGVDU1NSdWxlcyhlbGVtZW50IC8qLCBwc2V1ZG8sIGF1dGhvcl9vbmx5Ki8pIHtcbiAgICB2YXIgc3R5bGVfc2hlZXRzO1xuICAgIHZhciBzaGVldDtcbiAgICB2YXIgc2hlZXRfbWVkaWE7XG4gICAgdmFyIHJ1bGVzO1xuICAgIHZhciBydWxlO1xuICAgIHZhciByZXN1bHQgPSBbXTtcblxuICAgIC8vIGdldCBzdHlsZXNoZWV0cyBhbmQgY29udmVydCB0byBhIHJlZ3VsYXIgQXJyYXlcbiAgICBzdHlsZV9zaGVldHMgPSB0b0FycmF5KHdpbmRvdy5kb2N1bWVudC5zdHlsZVNoZWV0cyk7XG5cbiAgICAvLyBhc3N1bWluZyB0aGUgYnJvd3NlciBoYW5kcyB1cyBzdHlsZXNoZWV0cyBpbiBvcmRlciBvZiBhcHBlYXJhbmNlXG4gICAgLy8gd2UgaXRlcmF0ZSB0aGVtIGZyb20gdGhlIGJlZ2lubmluZyB0byBmb2xsb3cgcHJvcGVyIGNhc2NhZGUgb3JkZXJcbiAgICB3aGlsZSAoc2hlZXQgPSBzdHlsZV9zaGVldHMuc2hpZnQoKSkge1xuICAgICAgICAvLyBnZXQgdGhlIHN0eWxlIHJ1bGVzIG9mIHRoaXMgc2hlZXRcbiAgICAgICAgcnVsZXMgPSBnZXRTaGVldFJ1bGVzKHNoZWV0KTtcbiAgICAgICAgLy8gbG9vcCB0aGUgcnVsZXMgaW4gb3JkZXIgb2YgYXBwZWFyYW5jZVxuICAgICAgICB3aGlsZSAocnVsZSA9IHJ1bGVzLnNoaWZ0KCkpIHtcbiAgICAgICAgICAgIC8vIGlmIHRoaXMgaXMgYW4gQGltcG9ydCBydWxlXG4gICAgICAgICAgICBpZiAocnVsZS5zdHlsZVNoZWV0KSB7XG4gICAgICAgICAgICAgICAgLy8gaW5zZXJ0IHRoZSBpbXBvcnRlZCBzdHlsZXNoZWV0J3MgcnVsZXMgYXQgdGhlIGJlZ2lubmluZyBvZiB0aGlzIHN0eWxlc2hlZXQncyBydWxlc1xuICAgICAgICAgICAgICAgIHJ1bGVzID0gZ2V0U2hlZXRSdWxlcyhydWxlLnN0eWxlU2hlZXQpLmNvbmNhdChydWxlcyk7XG4gICAgICAgICAgICAgICAgLy8gYW5kIHNraXAgdGhpcyBydWxlXG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBpZiB0aGVyZSdzIG5vIHN0eWxlc2hlZXQgYXR0cmlidXRlIEJVVCB0aGVyZSBJUyBhIG1lZGlhIGF0dHJpYnV0ZSBpdCdzIGEgbWVkaWEgcnVsZVxuICAgICAgICAgICAgZWxzZSBpZiAocnVsZS5tZWRpYSkge1xuICAgICAgICAgICAgICAgIC8vIGluc2VydCB0aGUgY29udGFpbmVkIHJ1bGVzIG9mIHRoaXMgbWVkaWEgcnVsZSB0byB0aGUgYmVnaW5uaW5nIG9mIHRoaXMgc3R5bGVzaGVldCdzIHJ1bGVzXG4gICAgICAgICAgICAgICAgcnVsZXMgPSBnZXRTaGVldFJ1bGVzKHJ1bGUpLmNvbmNhdChydWxlcyk7XG4gICAgICAgICAgICAgICAgLy8gYW5kIHNraXAgaXRcbiAgICAgICAgICAgICAgICBjb250aW51ZVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBUT0RPOiBkZWFsIHdpdGggdW51c3VhbCBzZWxlY3RvcnNcbiAgICAgICAgICAgIC8vIFNvbWUgc2l0ZXMgdXNlIHNlbGVjdG9ycyBsaWtlICdbbmc6Y2xvYWtdJyB3aWNoIGlzIG5vdCBhIHZhbGlkIHNlbGVjdG9yXG4gICAgICAgICAgICAvLyB0cnktY2F0Y2hpbmcgdGhpcyBhbGxvd3MgdGhlIHBsdWdpbiB0byB3b3JrXG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIC8vIGNoZWNrIGlmIHRoaXMgZWxlbWVudCBtYXRjaGVzIHRoaXMgcnVsZSdzIHNlbGVjdG9yXG4gICAgICAgICAgICAgICAgaWYgKGVsZW1lbnQubWF0Y2hlcyhydWxlLnNlbGVjdG9yVGV4dCkpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gcHVzaCB0aGUgcnVsZSB0byB0aGUgcmVzdWx0cyBzZXRcbiAgICAgICAgICAgICAgICAgICAgcmVzdWx0LnB1c2gocnVsZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICAvLyBkbyBub3RoaW5nXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBzb3J0IGFjY29yZGluZyB0byBzcGVjaWZpY2l0eVxuICAgIHJldHVybiBzb3J0QnlTcGVjaWZpY2l0eShlbGVtZW50LCByZXN1bHQpO1xufTtcblxuZXhwb3J0IGRlZmF1bHQgZ2V0Tm9kZUNTU1J1bGVzO1xuIl19 1788 | }).call(this,require("rH1JPG"),typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],"/polyfills/get-matched-css-rules.jsx","/polyfills") 1789 | },{"buffer":2,"rH1JPG":4}],9:[function(require,module,exports){ 1790 | (function (process,global,Buffer,__argument0,__argument1,__argument2,__argument3,__filename,__dirname){ 1791 | 'use strict'; 1792 | 1793 | Object.defineProperty(exports, "__esModule", { 1794 | value: true 1795 | }); 1796 | function explainWarning() { 1797 | if (window.explained) return; 1798 | console.log('%cWhen \'getMatchedCSSRules()\' is removed, Critical Snapshot will fallback to a polyfill. Untill then, we will use the native version for better performance.', 'color: aqua;'); 1799 | window.explained = true; 1800 | } 1801 | 1802 | exports.default = explainWarning; 1803 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImV4cGxhaW5XYXJuaW5nLmpzeCJdLCJuYW1lcyI6WyJleHBsYWluV2FybmluZyIsIndpbmRvdyIsImV4cGxhaW5lZCIsImNvbnNvbGUiLCJsb2ciXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsU0FBU0EsY0FBVCxHQUEwQjtBQUN0QixRQUFJQyxPQUFPQyxTQUFYLEVBQXNCO0FBQ3RCQyxZQUFRQyxHQUFSLENBQVksZ0tBQVosRUFBOEssY0FBOUs7QUFDQUgsV0FBT0MsU0FBUCxHQUFtQixJQUFuQjtBQUNIOztrQkFFY0YsYyIsImZpbGUiOiJleHBsYWluV2FybmluZy5qc3giLCJzb3VyY2VzQ29udGVudCI6WyJmdW5jdGlvbiBleHBsYWluV2FybmluZygpIHtcbiAgICBpZiAod2luZG93LmV4cGxhaW5lZCkgcmV0dXJuO1xuICAgIGNvbnNvbGUubG9nKCclY1doZW4gXFwnZ2V0TWF0Y2hlZENTU1J1bGVzKClcXCcgaXMgcmVtb3ZlZCwgQ3JpdGljYWwgU25hcHNob3Qgd2lsbCBmYWxsYmFjayB0byBhIHBvbHlmaWxsLiBVbnRpbGwgdGhlbiwgd2Ugd2lsbCB1c2UgdGhlIG5hdGl2ZSB2ZXJzaW9uIGZvciBiZXR0ZXIgcGVyZm9ybWFuY2UuJywgJ2NvbG9yOiBhcXVhOycpO1xuICAgIHdpbmRvdy5leHBsYWluZWQgPSB0cnVlO1xufVxuXG5leHBvcnQgZGVmYXVsdCBleHBsYWluV2FybmluZztcbiJdfQ== 1804 | }).call(this,require("rH1JPG"),typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],"/utilities/explainWarning.jsx","/utilities") 1805 | },{"buffer":2,"rH1JPG":4}],10:[function(require,module,exports){ 1806 | (function (process,global,Buffer,__argument0,__argument1,__argument2,__argument3,__filename,__dirname){ 1807 | 'use strict'; 1808 | 1809 | Object.defineProperty(exports, "__esModule", { 1810 | value: true 1811 | }); 1812 | // removes all css styles from the webpage 1813 | function removeDocumentStyles() { 1814 | var appCssElements = [].slice.call(document.querySelectorAll('[type="text/css"]')); 1815 | appCssElements.forEach(function (elm) { 1816 | elm.remove(); 1817 | }); 1818 | 1819 | var appStylesheetElements = [].slice.call(document.querySelectorAll('[rel="stylesheet"]')); 1820 | appStylesheetElements.forEach(function (elm) { 1821 | elm.remove(); 1822 | }); 1823 | 1824 | var appStyleElements = [].slice.call(document.getElementsByTagName('style')); 1825 | appStyleElements.forEach(function (elm) { 1826 | elm.remove(); 1827 | }); 1828 | } 1829 | 1830 | exports.default = removeDocumentStyles; 1831 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInJlbW92ZURvY3VtZW50U3R5bGVzLmpzeCJdLCJuYW1lcyI6WyJyZW1vdmVEb2N1bWVudFN0eWxlcyIsImFwcENzc0VsZW1lbnRzIiwic2xpY2UiLCJjYWxsIiwiZG9jdW1lbnQiLCJxdWVyeVNlbGVjdG9yQWxsIiwiZm9yRWFjaCIsImVsbSIsInJlbW92ZSIsImFwcFN0eWxlc2hlZXRFbGVtZW50cyIsImFwcFN0eWxlRWxlbWVudHMiLCJnZXRFbGVtZW50c0J5VGFnTmFtZSJdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQTtBQUNBLFNBQVNBLG9CQUFULEdBQWdDO0FBQzVCLFFBQUlDLGlCQUFpQixHQUFHQyxLQUFILENBQVNDLElBQVQsQ0FBY0MsU0FBU0MsZ0JBQVQsQ0FBMEIsbUJBQTFCLENBQWQsQ0FBckI7QUFDQUosbUJBQWVLLE9BQWYsQ0FBdUIsVUFBU0MsR0FBVCxFQUFjO0FBQ2pDQSxZQUFJQyxNQUFKO0FBQ0gsS0FGRDs7QUFJQSxRQUFJQyx3QkFBd0IsR0FBR1AsS0FBSCxDQUFTQyxJQUFULENBQWNDLFNBQVNDLGdCQUFULENBQTBCLG9CQUExQixDQUFkLENBQTVCO0FBQ0FJLDBCQUFzQkgsT0FBdEIsQ0FBOEIsVUFBU0MsR0FBVCxFQUFjO0FBQ3hDQSxZQUFJQyxNQUFKO0FBQ0gsS0FGRDs7QUFJQSxRQUFJRSxtQkFBbUIsR0FBR1IsS0FBSCxDQUFTQyxJQUFULENBQWNDLFNBQVNPLG9CQUFULENBQThCLE9BQTlCLENBQWQsQ0FBdkI7QUFDQUQscUJBQWlCSixPQUFqQixDQUF5QixVQUFTQyxHQUFULEVBQWM7QUFDbkNBLFlBQUlDLE1BQUo7QUFDSCxLQUZEO0FBR0g7O2tCQUVjUixvQiIsImZpbGUiOiJyZW1vdmVEb2N1bWVudFN0eWxlcy5qc3giLCJzb3VyY2VzQ29udGVudCI6WyIvLyByZW1vdmVzIGFsbCBjc3Mgc3R5bGVzIGZyb20gdGhlIHdlYnBhZ2VcbmZ1bmN0aW9uIHJlbW92ZURvY3VtZW50U3R5bGVzKCkge1xuICAgIHZhciBhcHBDc3NFbGVtZW50cyA9IFtdLnNsaWNlLmNhbGwoZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnW3R5cGU9XCJ0ZXh0L2Nzc1wiXScpKTtcbiAgICBhcHBDc3NFbGVtZW50cy5mb3JFYWNoKGZ1bmN0aW9uKGVsbSkge1xuICAgICAgICBlbG0ucmVtb3ZlKCk7XG4gICAgfSk7XG5cbiAgICB2YXIgYXBwU3R5bGVzaGVldEVsZW1lbnRzID0gW10uc2xpY2UuY2FsbChkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCdbcmVsPVwic3R5bGVzaGVldFwiXScpKTtcbiAgICBhcHBTdHlsZXNoZWV0RWxlbWVudHMuZm9yRWFjaChmdW5jdGlvbihlbG0pIHtcbiAgICAgICAgZWxtLnJlbW92ZSgpO1xuICAgIH0pO1xuXG4gICAgdmFyIGFwcFN0eWxlRWxlbWVudHMgPSBbXS5zbGljZS5jYWxsKGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzdHlsZScpKTtcbiAgICBhcHBTdHlsZUVsZW1lbnRzLmZvckVhY2goZnVuY3Rpb24oZWxtKSB7XG4gICAgICAgIGVsbS5yZW1vdmUoKTtcbiAgICB9KTtcbn1cblxuZXhwb3J0IGRlZmF1bHQgcmVtb3ZlRG9jdW1lbnRTdHlsZXM7XG4iXX0= 1832 | }).call(this,require("rH1JPG"),typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],"/utilities/removeDocumentStyles.jsx","/utilities") 1833 | },{"buffer":2,"rH1JPG":4}],11:[function(require,module,exports){ 1834 | (function (process,global,Buffer,__argument0,__argument1,__argument2,__argument3,__filename,__dirname){ 1835 | "use strict"; 1836 | 1837 | Object.defineProperty(exports, "__esModule", { 1838 | value: true 1839 | }); 1840 | // Selects element text by ID 1841 | function selectText(id) { 1842 | var element = document.getElementById(id); 1843 | 1844 | var range = document.createRange(); 1845 | range.selectNodeContents(element); 1846 | 1847 | var selection = window.getSelection(); 1848 | selection.removeAllRanges(); 1849 | selection.addRange(range); 1850 | } 1851 | 1852 | exports.default = selectText; 1853 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNlbGVjdFRleHQuanN4Il0sIm5hbWVzIjpbInNlbGVjdFRleHQiLCJpZCIsImVsZW1lbnQiLCJkb2N1bWVudCIsImdldEVsZW1lbnRCeUlkIiwicmFuZ2UiLCJjcmVhdGVSYW5nZSIsInNlbGVjdE5vZGVDb250ZW50cyIsInNlbGVjdGlvbiIsIndpbmRvdyIsImdldFNlbGVjdGlvbiIsInJlbW92ZUFsbFJhbmdlcyIsImFkZFJhbmdlIl0sIm1hcHBpbmdzIjoiOzs7OztBQUFBO0FBQ0EsU0FBU0EsVUFBVCxDQUFvQkMsRUFBcEIsRUFBd0I7QUFDcEIsUUFBSUMsVUFBVUMsU0FBU0MsY0FBVCxDQUF3QkgsRUFBeEIsQ0FBZDs7QUFFQSxRQUFJSSxRQUFRRixTQUFTRyxXQUFULEVBQVo7QUFDQUQsVUFBTUUsa0JBQU4sQ0FBeUJMLE9BQXpCOztBQUVBLFFBQUlNLFlBQVlDLE9BQU9DLFlBQVAsRUFBaEI7QUFDQUYsY0FBVUcsZUFBVjtBQUNBSCxjQUFVSSxRQUFWLENBQW1CUCxLQUFuQjtBQUNIOztrQkFFY0wsVSIsImZpbGUiOiJzZWxlY3RUZXh0LmpzeCIsInNvdXJjZXNDb250ZW50IjpbIi8vIFNlbGVjdHMgZWxlbWVudCB0ZXh0IGJ5IElEXG5mdW5jdGlvbiBzZWxlY3RUZXh0KGlkKSB7XG4gICAgdmFyIGVsZW1lbnQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChpZClcblxuICAgIHZhciByYW5nZSA9IGRvY3VtZW50LmNyZWF0ZVJhbmdlKCk7XG4gICAgcmFuZ2Uuc2VsZWN0Tm9kZUNvbnRlbnRzKGVsZW1lbnQpO1xuXG4gICAgdmFyIHNlbGVjdGlvbiA9IHdpbmRvdy5nZXRTZWxlY3Rpb24oKTtcbiAgICBzZWxlY3Rpb24ucmVtb3ZlQWxsUmFuZ2VzKCk7XG4gICAgc2VsZWN0aW9uLmFkZFJhbmdlKHJhbmdlKTtcbn1cblxuZXhwb3J0IGRlZmF1bHQgc2VsZWN0VGV4dDtcbiJdfQ== 1854 | }).call(this,require("rH1JPG"),typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],"/utilities/selectText.jsx","/utilities") 1855 | },{"buffer":2,"rH1JPG":4}]},{},[6]) -------------------------------------------------------------------------------- /dist/styles/style.css: -------------------------------------------------------------------------------- 1 | body > #CriticalSnap { 2 | transition: width 200ms, height 200ms; 3 | width: 100%; 4 | height: 100%; 5 | position: fixed; 6 | top: 0; 7 | right: 0; 8 | bottom: 0; 9 | left: 0; 10 | padding: 25px; 11 | z-index: 9999999999; 12 | color: #fff; 13 | background-color: rgba(0, 0, 0, 0.5); 14 | overflow: scroll; 15 | font-family: monospace; 16 | text-align: center; } 17 | 18 | body > #CriticalSnap h1 { 19 | margin-bottom: 20px; 20 | color: #fff; 21 | font-size: 28px; 22 | line-height: 1.4em; 23 | font-family: sans-serif; 24 | text-transform: none; 25 | font-style: normal; } 26 | 27 | body > #CriticalSnap > div { 28 | width: 500px; 29 | margin: 0 auto; } 30 | 31 | body > #CriticalSnap #CriticalSnap__output-css { 32 | background-color: #fff; 33 | border-radius: 4px; 34 | padding: 10px; 35 | display: inline-block; 36 | width: 500px; 37 | height: 500px; 38 | overflow: scroll; 39 | color: #292929; 40 | text-align: left; } 41 | 42 | body > #CriticalSnap #CriticalSnap__buttons { 43 | display: inline-block; 44 | width: 500px; 45 | padding: 10px; 46 | text-align: center; } 47 | 48 | body > #CriticalSnap .CriticalSnap__button { 49 | line-height: 13px; 50 | font-family: arial, sans-serif; 51 | font-weight: normal; 52 | border-radius: 4px; 53 | border: 0; 54 | outline: 0; 55 | padding: 10px; 56 | padding-right: 20px; 57 | padding-left: 20px; 58 | color: #292929; 59 | background-color: #fff; 60 | margin: 10px; 61 | font-size: 13px; 62 | cursor: pointer; 63 | -webkit-transition: color 200ms, background-color 200ms; 64 | transition: color 200ms, background-color 200ms; } 65 | 66 | body > #CriticalSnap .CriticalSnap__button:active { 67 | -webkit-transform: translateY(2px); 68 | transform: translateY(2px); } 69 | 70 | body > #CriticalSnap .CriticalSnap__button > span { 71 | font-size: 16px; 72 | vertical-align: middle; 73 | line-height: 13px; } 74 | 75 | body > #CriticalSnap.CriticalSnap__minified { 76 | top: auto; 77 | left: auto; 78 | width: 250px; 79 | height: 165px; 80 | border-top-left-radius: 4px; } 81 | 82 | body > #CriticalSnap.CriticalSnap__minified h1 { 83 | display: none; } 84 | 85 | body > #CriticalSnap.CriticalSnap__minified > div { 86 | width: 200px; } 87 | 88 | body > #CriticalSnap.CriticalSnap__minified #CriticalSnap__output-css { 89 | width: 200px; 90 | height: 75px; } 91 | 92 | body > #CriticalSnap.CriticalSnap__minified #CriticalSnap__buttons { 93 | width: 200px; 94 | padding: 0; 95 | padding-top: 5px; 96 | text-align: right; } 97 | 98 | body > #CriticalSnap.CriticalSnap__minified .CriticalSnap__button { 99 | padding: 10px 12px; 100 | margin: 0; 101 | margin-left: 5px; } 102 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | // Include gulp 2 | var gulp = require('gulp'); 3 | 4 | // Include Our Plugins 5 | var concat = require('gulp-concat'); 6 | var sass = require('gulp-sass'); 7 | var rename = require('gulp-rename'); 8 | var uglify = require('gulp-uglify'); 9 | var browserify = require('gulp-browserify'); 10 | var babel = require("gulp-babel"); 11 | var zip = require('gulp-zip'); 12 | var sequence = require('gulp-sequence') 13 | 14 | var DEST_ROOT = 'dist'; 15 | var SRC_ROOT = 'src'; 16 | 17 | var src_styles = [ 18 | 'src/styles/globals/*.scss', 19 | 'src/styles/mixins/*.scss', 20 | 'src/styles/components/*.scss' 21 | ]; 22 | 23 | var src_scripts = [ 24 | 'src/scripts/execute.jsx' 25 | ]; 26 | 27 | gulp.task('zip', function() { 28 | return gulp.src(`${DEST_ROOT}/**/*`) 29 | .pipe(zip('critical-style-snapshot.zip')) 30 | .pipe(gulp.dest('.')); 31 | }); 32 | 33 | // CSS 34 | gulp.task('sass', function() { 35 | return gulp.src(src_styles) 36 | .pipe(concat('style.scss')) 37 | .pipe(sass()) 38 | .pipe(rename('style.css')) 39 | .pipe(gulp.dest(`${DEST_ROOT}/styles`)); 40 | }); 41 | 42 | gulp.task('images', function() { 43 | return gulp.src('src/images/**/*') 44 | .pipe(gulp.dest(`${DEST_ROOT}/images`)); 45 | }); 46 | 47 | // Concatenate 48 | gulp.task('scripts', function() { 49 | 50 | return gulp.src(src_scripts) 51 | .pipe(babel({ 52 | presets: ['es2015'] 53 | })) 54 | .pipe(browserify({ 55 | insertGlobals : true 56 | })) 57 | //.pipe(uglify()) 58 | .pipe(rename('execute.js')) 59 | .pipe(gulp.dest(`${DEST_ROOT}/scripts`)); 60 | }); 61 | 62 | gulp.task('index', function() { 63 | return gulp.src(`${SRC_ROOT}/index.js`) 64 | .pipe(gulp.dest(`${DEST_ROOT}`)); 65 | }); 66 | 67 | gulp.task('manifest', function() { 68 | return gulp.src(`${SRC_ROOT}/manifest.json`) 69 | .pipe(gulp.dest(`${DEST_ROOT}`)); 70 | }); 71 | 72 | // Watch 73 | gulp.task('watch', function() { 74 | gulp.watch('src/manifest.json', ['manifest']); 75 | gulp.watch('src/index.js', ['index']); 76 | gulp.watch('src/scripts/**/*.jsx', ['scripts']); 77 | gulp.watch('src/styles/**/*.scss', ['sass']); 78 | gulp.watch('src/images/**/*', ['images']); 79 | }); 80 | 81 | // Package 82 | gulp.task('package', sequence(['manifest', 'index', 'scripts', 'sass', 'images'], ['zip'])); 83 | 84 | // Default 85 | gulp.task('default', ['manifest', 'index', 'scripts', 'sass', 'images', 'watch']); 86 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "critical-style-snapshot", 3 | "version": "0.0.8", 4 | "description": "Capture CSS above the fold", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/andreleon/critical-snapshot.git" 9 | }, 10 | "author": "Léon Smit (https://github.com/andreleon)", 11 | "license": "ISC", 12 | "bugs": { 13 | "url": "https://github.com/andreleon/critical-snapshot/issues" 14 | }, 15 | "homepage": "https://github.com/andreleon/critical-snapshot#readme", 16 | "devDependencies": { 17 | "babel-cli": "^6.16.0", 18 | "babel-core": "^6.17.0", 19 | "babel-loader": "^6.2.5", 20 | "babel-preset-es2015": "^6.16.0", 21 | "babelify": "^7.3.0", 22 | "gulp": "^3.9.1", 23 | "gulp-babel": "^6.1.2", 24 | "gulp-browserify": "^0.5.1", 25 | "gulp-concat": "^2.6.0", 26 | "gulp-jshint": "^2.0.1", 27 | "gulp-rename": "^1.2.2", 28 | "gulp-sass": "^2.3.2", 29 | "gulp-sequence": "^0.4.6", 30 | "gulp-uglify": "^2.0.0", 31 | "gulp-zip": "^3.2.0", 32 | "jshint": "^2.9.3" 33 | }, 34 | "browserify": { 35 | "transform": [ 36 | [ 37 | "babelify", 38 | { 39 | "presets": [ 40 | "es2015" 41 | ] 42 | } 43 | ] 44 | ] 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /promotional.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreleon/critical-style-snapshot/a094109865e7c3706b9aaee00517e34ef159a46e/promotional.png -------------------------------------------------------------------------------- /src/images/critical.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreleon/critical-style-snapshot/a094109865e7c3706b9aaee00517e34ef159a46e/src/images/critical.png -------------------------------------------------------------------------------- /src/images/icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreleon/critical-style-snapshot/a094109865e7c3706b9aaee00517e34ef159a46e/src/images/icon128.png -------------------------------------------------------------------------------- /src/images/icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreleon/critical-style-snapshot/a094109865e7c3706b9aaee00517e34ef159a46e/src/images/icon16.png -------------------------------------------------------------------------------- /src/images/icon19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreleon/critical-style-snapshot/a094109865e7c3706b9aaee00517e34ef159a46e/src/images/icon19.png -------------------------------------------------------------------------------- /src/images/icon24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreleon/critical-style-snapshot/a094109865e7c3706b9aaee00517e34ef159a46e/src/images/icon24.png -------------------------------------------------------------------------------- /src/images/icon38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreleon/critical-style-snapshot/a094109865e7c3706b9aaee00517e34ef159a46e/src/images/icon38.png -------------------------------------------------------------------------------- /src/images/icon48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreleon/critical-style-snapshot/a094109865e7c3706b9aaee00517e34ef159a46e/src/images/icon48.png -------------------------------------------------------------------------------- /src/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreleon/critical-style-snapshot/a094109865e7c3706b9aaee00517e34ef159a46e/src/images/logo.png -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | var triggeredTabs = []; 2 | var window = chrome.extension.getBackgroundPage(); 3 | chrome.browserAction.onClicked.addListener(function(tab) { 4 | chrome.tabs.insertCSS(null, {file: "styles/style.css"}); 5 | chrome.tabs.executeScript(null, {file: "scripts/execute.js"}); 6 | }); 7 | -------------------------------------------------------------------------------- /src/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Critical Style Snapshot", 3 | "description": "Capture CSS above the fold with one click.", 4 | "version": "0.0.8", 5 | "permissions": [ 6 | "activeTab" 7 | ], 8 | "background": { 9 | "scripts": ["index.js"], 10 | "persistent": false 11 | }, 12 | "icons": { 13 | "16": "images/icon16.png", 14 | "48": "images/icon48.png", 15 | "128": "images/icon128.png" 16 | }, 17 | "browser_action": { 18 | "default_title": "Capture CSS above the fold", 19 | "default_icon": { 20 | "19": "images/icon19.png", 21 | "38": "images/icon38.png" 22 | } 23 | }, 24 | "manifest_version": 2, 25 | "homepage_url": "https://github.com/andreleon/critical-style-snapshot" 26 | } 27 | -------------------------------------------------------------------------------- /src/scripts/components/popup.jsx: -------------------------------------------------------------------------------- 1 | import getNodeCSSRules from '../polyfills/get-matched-css-rules.jsx'; 2 | import CriticalCSS from '../generators/CriticalCSS.jsx'; 3 | import selectText from '../utilities/selectText.jsx'; 4 | import removeDocumentStyles from '../utilities/removeDocumentStyles.jsx'; 5 | 6 | // Generates the popup with wich the user will interact 7 | function showPopup() { 8 | var copyGeneratedStylesheet = function(event) { 9 | event.preventDefault(); 10 | event.stopPropagation(); 11 | 12 | selectText('CriticalSnap__output-css'); 13 | document.execCommand('copy'); 14 | copyButton.style.backgroundColor = "#34A853"; 15 | copyButton.style.color = "#fff"; 16 | copyButton.innerHTML = "Copied 👍"; 17 | }; 18 | 19 | var previewGeneratedStylesheet = function(event) { 20 | event.preventDefault(); 21 | event.stopPropagation(); 22 | 23 | removeDocumentStyles(); 24 | 25 | var previewStyle = document.createElement('style'); 26 | previewStyle.innerHTML = stylesheet; 27 | document.getElementsByTagName('head')[0].appendChild(previewStyle); 28 | 29 | previewButton.removeEventListener('click', previewGeneratedStylesheet); 30 | previewButton.remove(); 31 | 32 | minifyPopup(); 33 | }; 34 | 35 | var selectGeneratedStylesheet = function(event) { 36 | event.preventDefault(); 37 | event.stopPropagation(); 38 | selectText('CriticalSnap__output-css'); 39 | }; 40 | 41 | var closePopup = function(event) { 42 | if (event) event.preventDefault(); 43 | destroyPopup(); 44 | }; 45 | 46 | var createPopup = function(content) { 47 | var popup = document.createElement('div'); 48 | popup.id = 'CriticalSnap'; 49 | 50 | var divHTML = ''; 51 | divHTML += '

Critical Snapshot

'; 52 | divHTML += '

'; 53 | divHTML += content 54 | divHTML += '

'; 55 | divHTML += '
'; 56 | divHTML += ''; 57 | divHTML += ''; 58 | divHTML += ''; 59 | divHTML += '
'; 60 | divHTML += '
'; 61 | 62 | popup.innerHTML = divHTML; 63 | 64 | return popup; 65 | }; 66 | 67 | var minifyPopup = function() { 68 | popup.className = 'CriticalSnap__minified'; 69 | }; 70 | 71 | var destroyPopup = function() { 72 | copyButton.removeEventListener('click', copyGeneratedStylesheet); 73 | previewButton.removeEventListener('click', previewGeneratedStylesheet); 74 | outputElement.removeEventListener('click', selectGeneratedStylesheet); 75 | containerElement.removeEventListener('click', closePopup); 76 | popup.remove(); 77 | }; 78 | 79 | // scroll to top before generating CSS 80 | document.body.scrollTop = 0; 81 | 82 | var snapshot = new CriticalCSS(window, document); 83 | var stylesheet = snapshot.generate(); 84 | 85 | var popup = createPopup(stylesheet); 86 | document.body.appendChild(popup); 87 | 88 | var copyButton = document.getElementById('CriticalSnap__copy'); 89 | var previewButton = document.getElementById('CriticalSnap__preview'); 90 | var outputElement = document.getElementById('CriticalSnap__output-css'); 91 | var containerElement = document.getElementById('CriticalSnap'); 92 | 93 | copyButton.addEventListener('click', copyGeneratedStylesheet); 94 | previewButton.addEventListener('click', previewGeneratedStylesheet); 95 | outputElement.addEventListener('click', selectGeneratedStylesheet); 96 | containerElement.addEventListener('click', closePopup); 97 | }; 98 | 99 | export { showPopup }; 100 | -------------------------------------------------------------------------------- /src/scripts/execute.jsx: -------------------------------------------------------------------------------- 1 | import { showPopup } from './components/popup.jsx'; 2 | 3 | showPopup(); 4 | -------------------------------------------------------------------------------- /src/scripts/generators/CriticalCSS.jsx: -------------------------------------------------------------------------------- 1 | import explainWarning from '../utilities/explainWarning.jsx'; 2 | import getNodeCSSRules from '../polyfills/get-matched-css-rules.jsx'; 3 | // CSS generator 4 | var CriticalCSS = function(window, document, options) { 5 | var options = options || {}; 6 | var parsedCSS = {}; 7 | 8 | var pushCSS = function(rule) { 9 | if(!!parsedCSS[rule.selectorText] === false) parsedCSS[rule.selectorText] = {}; 10 | 11 | var styles = rule.style.cssText.split(/;(?![A-Za-z0-9])/); 12 | 13 | styles.forEach(function(style) { 14 | if(!!style === false) return; 15 | 16 | var pair = style.split(': '); 17 | pair[0] = pair[0].trim(); 18 | pair[1] = pair[1].trim(); 19 | parsedCSS[rule.selectorText][pair[0]] = pair[1]; 20 | 21 | }); 22 | }; 23 | 24 | var parseTree = function() { 25 | var height = window.innerHeight; 26 | var walker = document.createTreeWalker(document, NodeFilter.SHOW_ELEMENT, function(node) { return NodeFilter.FILTER_ACCEPT; }, true); 27 | 28 | while(walker.nextNode()) { 29 | var node = walker.currentNode; 30 | var rect = node.getBoundingClientRect(); 31 | if(rect.top < height || options.scanFullPage) { 32 | var rules; 33 | if ( typeof window.getMatchedCSSRules !== 'function' ) { 34 | rules = getNodeCSSRules(node); 35 | } else { 36 | rules = window.getMatchedCSSRules(node); 37 | 38 | explainWarning(); 39 | } 40 | if (!rules) rules = getNodeCSSRules(node); 41 | 42 | if(!!rules) { 43 | for (var i = 0; i < rules.length; i++) { 44 | pushCSS(rules[i]); 45 | 46 | } 47 | } 48 | 49 | } 50 | } 51 | }; 52 | 53 | this.generate = function() { 54 | var outputCSS = ''; 55 | 56 | for(var key in parsedCSS) { 57 | outputCSS += key + '{'; 58 | 59 | for(var innerKey in parsedCSS[key]) { 60 | outputCSS += innerKey + ':' + parsedCSS[key][innerKey] + ';'; 61 | 62 | } 63 | 64 | outputCSS += '}'; 65 | } 66 | 67 | return outputCSS; 68 | }; 69 | 70 | parseTree(); 71 | }; 72 | 73 | export default CriticalCSS; 74 | -------------------------------------------------------------------------------- /src/scripts/generators/DocumentCSSMediaRules.jsx: -------------------------------------------------------------------------------- 1 | // regex: [\(](min-width|max-width):\s([0-9]{1,})(rem|em|px|%|vw|vh|cm|ex|in|mm|pc|pt|vmin)[\)] 2 | import arrayContainsObject from '../utilities/arrayContainsObject.jsx'; 3 | 4 | var DocumentCSSMediaRules = function() { 5 | var documentMediaRules = []; 6 | var toArray = function(list) { 7 | list = list || {}; 8 | return [].slice.call(list); 9 | }; 10 | 11 | var stylesheets = toArray(document.styleSheets); 12 | stylesheets.forEach(function(stylesheet) { 13 | var rules = toArray(stylesheet.cssRules || stylesheet.rules || []); 14 | rules.forEach(function(rule) { 15 | // console.log(rule.type) 16 | if (rule.type === CSSRule.MEDIA_RULE) documentMediaRules.push(rule); 17 | }); 18 | }); 19 | 20 | var hasNumber = function(text) { 21 | var number = parseFloat(text.replace(/[^\d.]/g, '')); 22 | return !isNaN(number); 23 | }; 24 | 25 | this.generate = function() { 26 | var unique = []; 27 | documentMediaRules.forEach(function(item) { 28 | var mediaRegEx = /[\(](min-width|max-width):\s([0-9]{1,})(rem|em|px|%|vw|vh|cm|ex|in|mm|pc|pt|vmin)[\)]/gi; 29 | var queries = item.media.mediaText.match(mediaRegEx); 30 | if (!queries) return; 31 | var mediaObject = queries.reduce(function(outputObject, query) { 32 | var regex = /[\(](min-width|max-width):\s([0-9]{1,})(rem|em|px|%|vw|vh|cm|ex|in|mm|pc|pt|vmin)[\)]/gi; 33 | var match = regex.exec(query); 34 | if (match) { 35 | outputObject[match[1]] = { 36 | value: parseInt(match[2]), 37 | unit: match[3] 38 | }; 39 | } 40 | return outputObject; 41 | }, {}); 42 | 43 | if (!arrayContainsObject(unique, mediaObject)) unique.push(mediaObject); 44 | }); 45 | return unique.sort(function(a, b) { 46 | if (a['min-width'] && b['min-width']) { 47 | if (a['min-width'].value < b['min-width'].value) return -1; 48 | if (a['min-width'].value > b['min-width'].value) return 1; 49 | } 50 | if (!a['min-width'] && b['min-width']) { 51 | if (a['max-width'].value < b['min-width'].value) return -1; 52 | if (a['max-width'].value > b['min-width'].value) return 1; 53 | } 54 | if (a['min-width'] && !b['min-width']) { 55 | if (a['min-width'].value < b['max-width'].value) return -1; 56 | if (a['min-width'].value > b['max-width'].value) return 1; 57 | } 58 | return 0; 59 | }); 60 | }; 61 | }; 62 | 63 | export default DocumentCSSMediaRules; 64 | -------------------------------------------------------------------------------- /src/scripts/polyfills/get-matched-css-rules.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Fallback for window.getMatchedCSSRules(node); 3 | * Forked from: (A Gecko only polyfill for Webkit's window.getMatchedCSSRules) https://gist.github.com/ydaniv/3033012 4 | * This version is compatible with most browsers hoi 5 | */ 6 | var ELEMENT_RE = /[\w-]+/g; 7 | var ID_RE = /#[\w-]+/g; 8 | var CLASS_RE = /\.[\w-]+/g; 9 | var ATTR_RE = /\[[^\]]+\]/g; 10 | // :not() pseudo-class does not add to specificity, but its content does as if it was outside it 11 | var PSEUDO_CLASSES_RE = /\:(?!not)[\w-]+(\(.*\))?/g; 12 | var PSEUDO_ELEMENTS_RE = /\:\:?(after|before|first-letter|first-line|selection)/g; 13 | 14 | // convert an array-like object to array 15 | function toArray (list) { 16 | list = list || {}; 17 | return [].slice.call(list); 18 | } 19 | 20 | // handles extraction of `cssRules` as an `Array` from a stylesheet or something that behaves the same 21 | function getSheetRules (stylesheet) { 22 | var sheet_media = stylesheet.media && stylesheet.media.mediaText; 23 | // if this sheet is disabled skip it 24 | if ( stylesheet.disabled ) return []; 25 | // if this sheet's media is specified and doesn't match the viewport then skip it 26 | if ( sheet_media && sheet_media.length && ! window.matchMedia(sheet_media).matches ) return []; 27 | // get the style rules of this sheet 28 | 29 | try { 30 | return toArray(stylesheet.cssRules || stylesheet.rules || []); 31 | } catch (err) { 32 | return []; 33 | } 34 | } 35 | 36 | function _find (string, re) { 37 | var matches = string.match(re); 38 | return re ? re.length : 0; 39 | } 40 | 41 | // calculates the specificity of a given `selector` 42 | function calculateScore (selector) { 43 | var score = [0,0,0]; 44 | var parts = selector.split(' '); 45 | var part; 46 | var match; 47 | 48 | //TODO: clean the ':not' part since the last ELEMENT_RE will pick it up 49 | while ( part = parts.shift(), typeof part == 'string' ) { 50 | // find all pseudo-elements 51 | match = _find(part, PSEUDO_ELEMENTS_RE); 52 | score[2] = match; 53 | // and remove them 54 | match && (part = part.replace(PSEUDO_ELEMENTS_RE, '')); 55 | // find all pseudo-classes 56 | match = _find(part, PSEUDO_CLASSES_RE); 57 | score[1] = match; 58 | // and remove them 59 | match && (part = part.replace(PSEUDO_CLASSES_RE, '')); 60 | // find all attributes 61 | match = _find(part, ATTR_RE); 62 | score[1] += match; 63 | // and remove them 64 | match && (part = part.replace(ATTR_RE, '')); 65 | // find all IDs 66 | match = _find(part, ID_RE); 67 | score[0] = match; 68 | // and remove them 69 | match && (part = part.replace(ID_RE, '')); 70 | // find all classes 71 | match = _find(part, CLASS_RE); 72 | score[1] += match; 73 | // and remove them 74 | match && (part = part.replace(CLASS_RE, '')); 75 | // find all elements 76 | score[2] += _find(part, ELEMENT_RE); 77 | } 78 | return parseInt(score.join(''), 10); 79 | } 80 | 81 | // returns the heights possible specificity score an element can get from a give rule's selectorText 82 | function getSpecificityScore (element, selector_text) { 83 | var selectors = selector_text.split(','); 84 | var selector; 85 | var score; 86 | var result = 0; 87 | 88 | while (selector = selectors.shift()) { 89 | element.matches = element.matches || element.webkitMatchesSelector || element.mozMatchesSelector || element.msMatchesSelector || element.oMatchesSelector; 90 | if ( element.matches(selector) ) { 91 | score = calculateScore(selector); 92 | result = score > result ? score : result; 93 | } 94 | } 95 | 96 | return result; 97 | } 98 | 99 | function sortBySpecificity (element, rules) { 100 | // comparing function that sorts CSSStyleRules according to specificity of their `selectorText` 101 | function compareSpecificity (a, b) { 102 | return getSpecificityScore(element, b.selectorText) - getSpecificityScore(element, a.selectorText); 103 | } 104 | 105 | return rules.sort(compareSpecificity); 106 | } 107 | 108 | //TODO: not supporting 2nd argument for selecting pseudo elements 109 | //TODO: not supporting 3rd argument for checking author style sheets only 110 | function getNodeCSSRules(element /*, pseudo, author_only*/) { 111 | var style_sheets; 112 | var sheet; 113 | var sheet_media; 114 | var rules; 115 | var rule; 116 | var result = []; 117 | 118 | // get stylesheets and convert to a regular Array 119 | style_sheets = toArray(window.document.styleSheets); 120 | 121 | // assuming the browser hands us stylesheets in order of appearance 122 | // we iterate them from the beginning to follow proper cascade order 123 | while (sheet = style_sheets.shift()) { 124 | // get the style rules of this sheet 125 | rules = getSheetRules(sheet); 126 | // loop the rules in order of appearance 127 | while (rule = rules.shift()) { 128 | // if this is an @import rule 129 | if (rule.styleSheet) { 130 | // insert the imported stylesheet's rules at the beginning of this stylesheet's rules 131 | rules = getSheetRules(rule.styleSheet).concat(rules); 132 | // and skip this rule 133 | continue; 134 | } 135 | // if there's no stylesheet attribute BUT there IS a media attribute it's a media rule 136 | else if (rule.media) { 137 | // insert the contained rules of this media rule to the beginning of this stylesheet's rules 138 | rules = getSheetRules(rule).concat(rules); 139 | // and skip it 140 | continue 141 | } 142 | 143 | // TODO: deal with unusual selectors 144 | // Some sites use selectors like '[ng:cloak]' wich is not a valid selector 145 | // try-catching this allows the plugin to work 146 | try { 147 | // check if this element matches this rule's selector 148 | if (element.matches(rule.selectorText)) { 149 | // push the rule to the results set 150 | result.push(rule); 151 | } 152 | } 153 | catch (e) { 154 | // do nothing 155 | } 156 | } 157 | } 158 | 159 | // sort according to specificity 160 | return sortBySpecificity(element, result); 161 | }; 162 | 163 | export default getNodeCSSRules; 164 | -------------------------------------------------------------------------------- /src/scripts/utilities/arrayContainsObject.jsx: -------------------------------------------------------------------------------- 1 | import equalObjects from '../utilities/equalObjects.jsx'; 2 | 3 | function arrayContainsObject(array, object) { 4 | return array.reduce(function(arrayContainsBool, currentObject) { 5 | if (equalObjects(currentObject, object)) arrayContainsBool = true; 6 | return arrayContainsBool; 7 | }, false); 8 | }; 9 | 10 | export default arrayContainsObject; 11 | -------------------------------------------------------------------------------- /src/scripts/utilities/equalObjects.jsx: -------------------------------------------------------------------------------- 1 | function equalObjects(object1, object2) { 2 | return JSON.stringify(object1) === JSON.stringify(object2); 3 | } 4 | 5 | export default equalObjects; 6 | -------------------------------------------------------------------------------- /src/scripts/utilities/explainWarning.jsx: -------------------------------------------------------------------------------- 1 | function explainWarning() { 2 | if (window.explained) return; 3 | console.log('%cWhen \'getMatchedCSSRules()\' is removed, Critical Snapshot will fallback to a polyfill. Untill then, we will use the native version for better performance.', 'color: aqua;'); 4 | window.explained = true; 5 | } 6 | 7 | export default explainWarning; 8 | -------------------------------------------------------------------------------- /src/scripts/utilities/removeDocumentStyles.jsx: -------------------------------------------------------------------------------- 1 | // removes all css styles from the webpage 2 | function removeDocumentStyles() { 3 | var appCssElements = [].slice.call(document.querySelectorAll('[type="text/css"]')); 4 | appCssElements.forEach(function(elm) { 5 | elm.remove(); 6 | }); 7 | 8 | var appStylesheetElements = [].slice.call(document.querySelectorAll('[rel="stylesheet"]')); 9 | appStylesheetElements.forEach(function(elm) { 10 | elm.remove(); 11 | }); 12 | 13 | var appStyleElements = [].slice.call(document.getElementsByTagName('style')); 14 | appStyleElements.forEach(function(elm) { 15 | elm.remove(); 16 | }); 17 | } 18 | 19 | export default removeDocumentStyles; 20 | -------------------------------------------------------------------------------- /src/scripts/utilities/selectText.jsx: -------------------------------------------------------------------------------- 1 | // Selects element text by ID 2 | function selectText(id) { 3 | var element = document.getElementById(id) 4 | 5 | var range = document.createRange(); 6 | range.selectNodeContents(element); 7 | 8 | var selection = window.getSelection(); 9 | selection.removeAllRanges(); 10 | selection.addRange(range); 11 | } 12 | 13 | export default selectText; 14 | -------------------------------------------------------------------------------- /src/styles/components/critical.scss: -------------------------------------------------------------------------------- 1 | body > #CriticalSnap { 2 | transition: width 200ms, height 200ms; 3 | width: 100%; 4 | height: 100%; 5 | position: fixed; 6 | top: 0; 7 | right: 0; 8 | bottom: 0; 9 | left: 0; 10 | padding: 25px; 11 | z-index: 9999999999; 12 | color: #fff; 13 | background-color: rgba(0,0,0,0.5); 14 | overflow: scroll; 15 | font-family: monospace; 16 | text-align: center; 17 | } 18 | body > #CriticalSnap h1 { 19 | margin-bottom: 20px; 20 | color: #fff; 21 | font-size: 28px; 22 | line-height: 1.4em; 23 | font-family: sans-serif; 24 | text-transform: none; 25 | font-style: normal; 26 | } 27 | body > #CriticalSnap > div { 28 | width: 500px; 29 | margin: 0 auto; 30 | } 31 | body > #CriticalSnap #CriticalSnap__output-css { 32 | background-color: #fff; 33 | border-radius: 4px; 34 | padding: 10px; 35 | display: inline-block; 36 | width: 500px; 37 | height: 500px; 38 | overflow: scroll; 39 | color: #292929; 40 | text-align: left; 41 | } 42 | body > #CriticalSnap #CriticalSnap__buttons { 43 | display: inline-block; 44 | width: 500px; 45 | padding: 10px; 46 | text-align: center; 47 | } 48 | body > #CriticalSnap .CriticalSnap__button { 49 | line-height: 13px; 50 | font-family: arial, sans-serif; 51 | font-weight: normal; 52 | border-radius: 4px; 53 | border: 0; 54 | outline: 0; 55 | padding: 10px; 56 | padding-right: 20px; 57 | padding-left: 20px; 58 | color: #292929; 59 | background-color: #fff; 60 | margin: 10px; 61 | font-size: 13px; 62 | cursor: pointer; 63 | -webkit-transition: color 200ms, background-color 200ms; 64 | transition: color 200ms, background-color 200ms; 65 | } 66 | body > #CriticalSnap .CriticalSnap__button:active { 67 | -webkit-transform: translateY(2px); 68 | transform: translateY(2px); 69 | } 70 | body > #CriticalSnap .CriticalSnap__button > span { 71 | font-size: 16px; 72 | vertical-align: middle; 73 | line-height: 13px; 74 | } 75 | body > #CriticalSnap.CriticalSnap__minified { 76 | top: auto; 77 | left: auto; 78 | width: 250px; 79 | height: 165px; 80 | border-top-left-radius: 4px; 81 | } 82 | body > #CriticalSnap.CriticalSnap__minified h1 { 83 | display: none; 84 | } 85 | body > #CriticalSnap.CriticalSnap__minified > div { 86 | width: 200px; 87 | } 88 | body > #CriticalSnap.CriticalSnap__minified #CriticalSnap__output-css { 89 | width: 200px; 90 | height: 75px; 91 | } 92 | body > #CriticalSnap.CriticalSnap__minified #CriticalSnap__buttons { 93 | width: 200px; 94 | padding: 0; 95 | padding-top: 5px; 96 | text-align: right; 97 | } 98 | body > #CriticalSnap.CriticalSnap__minified .CriticalSnap__button { 99 | padding: 10px 12px; 100 | margin: 0; 101 | margin-left: 5px; 102 | } 103 | --------------------------------------------------------------------------------