├── test ├── helium.js ├── style │ ├── style2.css │ └── style1.css ├── test1.html └── test2.html ├── component.json ├── README.md └── helium.js /test/helium.js: -------------------------------------------------------------------------------- 1 | ../helium.js -------------------------------------------------------------------------------- /test/style/style2.css: -------------------------------------------------------------------------------- 1 | #test2 { 2 | border: 2px solid #000; 3 | } 4 | #neverused { 5 | color: red; 6 | } -------------------------------------------------------------------------------- /component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "helium", 3 | "version": "1.1", 4 | "main": "helium.js", 5 | "ignore": [ 6 | "**/.*", 7 | "node_modules", 8 | "components" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /test/style/style1.css: -------------------------------------------------------------------------------- 1 | html,body{ 2 | padding:0; 3 | margin:0; 4 | } 5 | 6 | div{ 7 | border:1px solid #000; 8 | } 9 | 10 | .test1, .test1:hover{ 11 | border:2px solid #cc0000; 12 | padding:5px; 13 | } 14 | 15 | #test2{ 16 | padding:5px; 17 | border:2px solid #cc00cc; 18 | } 19 | 20 | .nonexistent{color:#000;} 21 | .nonexistent2{} 22 | 23 | .nonexistent,body,{} 24 | 25 | :test{} 26 | 27 | !!!{} 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /test/test1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 20 | 21 |

Test Page 1

22 |
23 |
24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /test/test2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 20 | 21 | 22 |

Test Page 2

23 |
24 |
25 |
26 | 27 | 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Helium is a tool for discovering unused CSS across many pages on a web site. 2 | 3 | The tool is javascript-based and runs from the browser. 4 | 5 | Helium accepts a list of URLs for different sections of a site then loads and parses each page to build up a list of all stylesheets. It then visits each page in the URL list and checks if the selectors found in the stylesheets are used on the pages. Finally, it generates a report that details each stylesheet and the selectors that were not found to be used on any of the given pages. 6 | 7 | 8 | 9 | 10 | ##### Note: You really should only run Helium on a local, development, or otherwise privately accessible version of your site. If you run this on your public site, every visitor will see the Helium test environment. 11 | 12 | ##### PLEASE READ THE "IMPORTANT STUFF" SECTION BELOW!! 13 | 14 | ### Installation 15 | 16 | 1. Add a script element somewhere on your site that is loaded into every page that will be tested. This is typically a header or footer section. The element looks like: 17 | 18 | ```html 19 | 20 | ``` 21 | ##### Note: path/to/helium.js needs to reflect the path of where you place the javascript file. 22 | 23 | If you would like to use a CDN hosted version of Helium, checkout https://cdnjs.com/libraries/helium-css. 24 | 25 | 2. Helium is initiated by calling the method "helium.init()". This has to be placed somewhere on the page where it gets called after page load. An example of this is: 26 | 27 | ```html 28 | 35 | ``` 36 | ##### Note: Depending on the javascript loading strategy your site employs, you may wish to place "helium.init()" within a location that executes javascript after page load. 37 | 38 | 39 | ### Usage 40 | 41 | 1. Once Helium is setup, when you load your site you will see a box with a textarea where you input your URL list. 42 | 43 | 2. After you paste your list of links, click Start (lower left) to begin the process. Clicking "Reset to Beginning" clears the textarea and stored data. 44 | 45 | 3. The test will proceed to load and process each url you gave. When it is finished, you are presented with a report window that lists each stylesheet URL that was detected. Under each stylesheet, it will list the CSS selectors that were not detected to be in use on any page. 46 | 47 | 4. The selectors are color-coded. 48 | 49 | * ##### Green: Unmatched selectors. 50 | These are the primary ones that were not detected as in-use. 51 | 52 | * ##### Black: Matched selectors that are grouped with non-matched selectors. 53 | Basically this means that multiple selectors were defined together like "h1,h2,h3{}". All selectors are tested individually so these are displayed to make them easier to find in the stylesheets later. 54 | 55 | * ##### Red: Malformed selectors. 56 | These are likely to be rare. This means that when the browser tried testing for a selector, it can't parse the syntax of how it was written. This could be like ".classname# idname{}" or a "CSS hack" often used for Internet Explorer. 57 | 58 | * ##### Blue: Pseudo-class selector. 59 | These are selectors like ".div:hover" or "input:focus". These are selectors that require user interaction to activate. Currently, Helium can't simulate the interactions required to see if these are found or not. It is the developer's responsibility to test for these manually. 60 | 61 | ### Browser Support: 62 | 63 | Any modern browser that supports LocalStorage and document.querySelector. 64 | 65 | I have decided I will never adapt Helium to support IE6 or 7. 66 | 67 | ### IMPORTANT STUFF: 68 | 1. No cross-domain stylesheets: Helium has to load the stylesheets on your site via XHR in order to parse out the selectors to test. This means that all stylesheets URLs have to be on the same domain as the pages being tested. There's currently no back-end server to proxy requests, but this might be an option in the future. 69 | 70 | 2. No javascript errors on your pages: If Helium is run on a page that has one or more javascript errors, it can easily prevent Helium and other scripts from running on the page. This will stop your tests dead in their tracks. Verify ahead of time that all of the URLs you are testing do not generate any javascript errors. If you aren't sure, try running some Helium tests and see what page it stops at. Check out your error consoles on such pages. 71 | 72 | 3. No sitemap XML support: Right now, the URL list has to be line separated. No CSV or sitemap XML format is currently supported, though it will be in a future release. 73 | 74 | ### Running the tests: 75 | Helium doesn't have actual unit tests yet. I've been meaning to add them for a while (years) and will soon. 76 | 77 | To run the test pages, run a local server from the project root directory and hit http://localhost/test/test1.html. 78 | 79 | For a very simple server example using Ruby (because its on most systems): 80 | 81 | ruby -run -e httpd . -p 5000 82 | -------------------------------------------------------------------------------- /helium.js: -------------------------------------------------------------------------------- 1 | /* global alert, ActiveXObject */ 2 | // Helium-css v1.1 3 | // License: MIT License(http://opensource.org/licenses/mit-license.php) 4 | // Copyright 2010 - 2014, Charles Lawrence http://twitter.com/geuis 5 | // Release: 1/13/10 6 | // Last update: 8/29/2014 7 | 8 | var helium = { 9 | 10 | callback: undefined, 11 | 12 | data: { 13 | //timeout 14 | //status, 15 | //findinglist, 16 | //pagelist, 17 | //currenturl, 18 | //pages, 19 | //stylesheets 20 | }, 21 | 22 | init: function () { 23 | 24 | // Callback on init or default to running the report. 25 | helium.callback = (arguments.length > 0) ? arguments[0] : helium.report; 26 | 27 | //silently fail if localStorage is not available 28 | if (window.localStorage) { 29 | 30 | //load page data 31 | helium.load(); 32 | 33 | helium.data.timeout = 3000; 34 | helium.save(); 35 | 36 | helium.checkstatus(); 37 | 38 | } else { 39 | throw new Error('localStorage API not found'); 40 | } 41 | 42 | }, 43 | 44 | checkstatus: function () { 45 | //determine state 46 | //0: not started 47 | //1: finding stylesheets on all pages 48 | //2: loading/parsing stylesheets 49 | //3: check if selectors found on pages 50 | //4: finished, show report 51 | 52 | if (typeof helium.data.status === 'undefined') { 53 | helium.data.status = 0; 54 | } 55 | 56 | if (helium.data.status === 0) { 57 | //not started 58 | 59 | //prompt for list of pages. Build and display html overlay 60 | var html = [ 61 | '

Paste a list of pages on your site you want to test

', 62 | '', 63 | '' 64 | ]; 65 | 66 | helium.generateCSS(); 67 | 68 | var div = document.createElement('div'); 69 | div.id = 'cssdetectID'; 70 | div.innerHTML = html.join(''); 71 | 72 | helium.$('body')[0].appendChild(div); 73 | 74 | //add listener to save list and start processing 75 | helium.on(helium.$('#cssdetectStart'), 'click', function () { 76 | 77 | //currently based on new-line separated values. Eventually supports sitemap XML format and comma-delineated. 78 | var list = document.getElementById('cssdetectTextarea').value.split('\n'); 79 | 80 | helium.setPageList(list); 81 | 82 | //set status to 'finding' 83 | helium.data.status = 1; 84 | 85 | //copy pagelist 86 | helium.data.findinglist = helium.data.pagelist.slice(0); //copy not reference 87 | helium.save(); 88 | 89 | //navigate to first page 90 | helium.nav(helium.data.findinglist); 91 | 92 | }, false); 93 | 94 | //add listener to reset all data 95 | helium.on(helium.$('#cssdetectRestart'), 'click', function () { 96 | 97 | //clear stored pages 98 | document.getElementById('cssdetectTextarea').value = ''; 99 | 100 | helium.reset(); 101 | 102 | }, false); 103 | 104 | return false; 105 | } 106 | 107 | if (helium.data.status === 1) { 108 | 109 | //finding stylesheets 110 | helium.findstylesheets(); 111 | 112 | return false; 113 | } 114 | 115 | if (helium.data.status === 2) { 116 | //loading & parsing stylesheets 117 | helium.getcss(); 118 | 119 | return false; 120 | } 121 | 122 | if (helium.data.status === 3) { 123 | 124 | //check if selectors found on pages 125 | helium.checkcss(); 126 | 127 | return false; 128 | } 129 | 130 | if (helium.data.status === 4) { 131 | 132 | //Finished, issue report 133 | helium.callback(); 134 | } 135 | 136 | }, 137 | 138 | //display final report for unused selectors 139 | report: function () { 140 | 141 | var flip = false; 142 | var html = [ 143 | '

CSS Detection Report

', 144 | '', 145 | '

Download Report

', 146 | '
', 147 | '
Green: unmatched selectors
', 148 | '
Black: matched selectors that are defined with non-matched selectors
', 149 | '
Red: a malformed selector. ** Note: not all malformed selectors are bad. Chrome won\'t parse -moz extensions for example.
', 150 | '
Blue: a selector with a pseudo-class. You must test these manually.
', 151 | '
' 152 | ]; 153 | var download_report = [ 154 | '{G} Green: unmatched selectors', 155 | '{B} Black: matched selectors that are defined with non-matched selectors', 156 | '{R} Red: a malformed selector. ** Note: not all malformed selectors are bad. Chrome won\'t parse -moz extensions for example.', 157 | '{BL} Blue: a selector with a pseudo-class. You must test these manually.' 158 | ]; 159 | 160 | //loop through stylesheets 161 | for (var i = 0; i < helium.data.stylesheets.length; i++) { 162 | 163 | //add stylesheet link 164 | html.push('

' + helium.data.stylesheets[i].url + '

'); 165 | 166 | download_report.push('\r\nStylesheet: ' + helium.data.stylesheets[i].url + '\r\n'); 167 | 168 | var sels = helium.data.stylesheets[i].selectors; 169 | 170 | if (sels.length > 0) { 171 | 172 | html.push(''); 242 | 243 | } else { 244 | html.push('
No unmatched selectors found.
'); 245 | download_report.push('No unmatched selectors found.'); 246 | } 247 | 248 | } 249 | 250 | var div = document.createElement('div'); 251 | div.id = 'cssdetectID'; 252 | div.innerHTML = html.join(''); 253 | 254 | helium.generateCSS(); 255 | 256 | helium.$('body')[0].appendChild(div); 257 | 258 | //toggle selector visibility 259 | var toggles = helium.$('#cssdetectID ul li'); 260 | 261 | for (var s = 0; s < toggles.length; s++) { 262 | 263 | (function () { 264 | var i = s; 265 | helium.on(toggles[i], 'click', function () { 266 | 267 | if (this.style.opacity === '0.5') { 268 | this.style.opacity = '1'; 269 | } else { 270 | this.style.opacity = '0.5'; 271 | } 272 | 273 | }, false); 274 | })(); 275 | 276 | } 277 | 278 | //setup New Test button 279 | helium.on(helium.$('#cssreportResetID'), 'click', function () { 280 | helium.reset(); 281 | }, false); 282 | 283 | if (window.URL.createObjectURL && window.Blob) { 284 | 285 | //setup Download Report button 286 | var blob = new Blob([download_report.join('\r\n')], {type : 'text/rtf'}); 287 | var btn = helium.$('#cssreportDownloadReport'); 288 | btn[0].href = window.URL.createObjectURL(blob); 289 | btn[0].download = 'helium-report.txt'; 290 | 291 | } else { 292 | 293 | helium.on(helium.$('#cssreportDownloadReport'), 'click', function () { 294 | alert('Report downloads aren\'t supported in this browser. The necessary file api\'s aren\'t available. Use Chrome or Firefox.'); 295 | }); 296 | 297 | } 298 | 299 | }, 300 | 301 | generateCSS: function () { 302 | /* jshint ignore:start */ 303 | var css = [ 304 | '#cssdetectID{', 305 | 'font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;', 306 | 'font-size: 16px;', 307 | 'font-weight: bold;', 308 | 'color: #fff;', 309 | 'position: absolute;', 310 | 'z-index: 999999999;', 311 | 'top: 10%;', 312 | 'width: 80%;', 313 | 'left: 10%;', 314 | 'background-color: #3498db;', //blue 315 | //'background-color: #B9090B;', //red 316 | 'padding: 10px 20px 20px 20px;', 317 | 'border: none', 318 | '}', 319 | '#cssdetectID .cell{', 320 | 'background: #fff;', 321 | 'padding: 10px;', 322 | 'color: #000;', 323 | '}', 324 | '#cssdetectID div{', 325 | 'border:none;', 326 | '}', 327 | '#cssdetectID .alternate{', 328 | 'border: 1px solid #eee;', 329 | 'border-width: 1px 0 1px 0;', 330 | '}', 331 | '#cssdetectID ul{', 332 | 'list-style: none;', 333 | 'padding: 0;', 334 | 'margin: 0;', 335 | '}', 336 | '#cssdetectID li:hover{', 337 | 'background: #eee', 338 | '}', 339 | '#cssdetectID h1{', 340 | 'margin: 0 0 10px 0;', 341 | 'padding: 0;', 342 | 'font-size: 20px;', 343 | '}', 344 | '#cssdetectID h2{', 345 | 'margin: 0 0 0 0;', 346 | 'padding: 0;', 347 | 'font-size: 16px;', 348 | '}', 349 | '#cssdetectDesc{', 350 | 'background: #8ac6ed;', 351 | '}', 352 | '#cssdetectID textarea{', 353 | 'width: 100%;', 354 | 'height:300px;', 355 | 'border: none;', 356 | 'margin: 0 0 10px 0;', 357 | 'padding: 10px;', 358 | 'resize: none;', 359 | 'outline: 1px none transparent;', 360 | 'border-radius: 0;', 361 | '}', 362 | '#cssdetectID input{', 363 | 'background: #fff !important;', 364 | 'color: #000 !important;', 365 | 'border: none;', 366 | 'padding: 10px 20px 10px 20px;', 367 | 'margin: 0 10px 0 0;', 368 | 'font-size: 18px;', 369 | 'cursor: pointer;', 370 | '-webkit-appearance: button;', 371 | '}', 372 | '#cssdetectID input:hover{', 373 | 'background: #ecf0f1;', 374 | 'pointer: cursor;', 375 | '}', 376 | '#cssdetectID a{', 377 | 'color: #fff', 378 | '}', 379 | '#cssreportResetID{', 380 | 'position:absolute;', 381 | 'top: 10px;', 382 | 'right: 10px;', 383 | '}', 384 | '#cssdetectID .green, #cssdetectID .selector{', 385 | 'color: #009000;', 386 | '}', 387 | 388 | '#cssdetectID .black, #cssdetectID .matched_selector{', 389 | 'color: #000000;', 390 | '}', 391 | 392 | '#cssdetectID .red, #cssdetectID .invalid_selector{', 393 | 'color: #cc0000;', 394 | '}', 395 | 396 | '#cssdetectID .blue, #cssdetectID .pseudo_class{', 397 | 'color: #0000cc', 398 | '}' 399 | ]; 400 | 401 | 402 | var style = document.createElement('style'); 403 | style.innerHTML = css.join(''); 404 | 405 | helium.$('body')[0].appendChild(style); 406 | /* jshint ignore:end */ 407 | }, 408 | 409 | reset: function () { 410 | //resets to beginning 411 | localStorage.removeItem('cssdetect'); 412 | 413 | var nodes = helium.$('#cssdetectID'); 414 | for (var i = 0; i < nodes.length; i++) { 415 | nodes[i].parentNode.removeChild(nodes[i]); 416 | } 417 | 418 | helium.init(); 419 | }, 420 | 421 | //check if selectors found on pages 422 | checkcss: function () { 423 | 424 | //delay time period set with helium.data.timeout. For purposes of waiting for content to render after load event(XHR) 425 | setTimeout(function () { 426 | 427 | //find the current page in the list of pages 428 | for (var i = 0; i < helium.data.pages.length; i++) { 429 | 430 | if (helium.data.pages[i].url === helium.data.currenturl) { 431 | 432 | //loop through stylesheet links on page 433 | for (var b = 0; b < helium.data.pages[i].links.length; b++) { 434 | 435 | //find the stylesheet array element that matches the stylesheet link currently being worked on 436 | var thislink = helium.data.pages[i].links[b]; 437 | 438 | for (var c = 0; c < helium.data.stylesheets.length; c++) { 439 | 440 | if (helium.data.stylesheets[c].url === thislink) { 441 | 442 | var stylesheet = helium.data.stylesheets[c]; 443 | 444 | //loop through selectors and test if active on this page. 445 | //If it is a single selector( length===1 ), remove them from the array 446 | //If length > 1, the "sub selector" gets an attribute of 'true' to indicate it was found 447 | for (var d = 0; d < stylesheet.selectors.length; d++) { 448 | 449 | for (var e = 0; e < stylesheet.selectors[d].length; e++) { 450 | 451 | var response = helium.find(stylesheet.selectors[d][e].s); 452 | 453 | if (response === true) { 454 | stylesheet.selectors[d][e].v = true; 455 | } 456 | if (response === 'invalid_selector') { 457 | stylesheet.selectors[d][e].v = 'invalid_selector'; 458 | } 459 | if (response === 'pseudo_class') { 460 | stylesheet.selectors[d][e].v = 'pseudo_class'; 461 | } 462 | 463 | } 464 | 465 | } 466 | 467 | //end the current loop 468 | c = helium.data.stylesheets.length; 469 | } 470 | } 471 | 472 | } 473 | 474 | //end the current loop 475 | i = helium.data.pages.length; 476 | } 477 | 478 | } 479 | 480 | helium.save(); 481 | 482 | if (helium.data.pagelist.length > 0) { 483 | 484 | //navigate to next page 485 | helium.nav(); 486 | 487 | } else { 488 | 489 | helium.data.status = 4; 490 | helium.save(); 491 | 492 | //run callback 493 | helium.callback(); 494 | 495 | } 496 | 497 | }, helium.data.timeout); 498 | 499 | 500 | }, 501 | 502 | //search current page for selectors 503 | find: function (selector) { 504 | 505 | //try/catch is used because querySelectorAll throws errors when syntactically invalid selectors are passed through. Useful for detection purposes. 506 | try { 507 | 508 | //returns true if selector found on page, false if not 509 | if (helium.$(selector).length > 0) { 510 | return true; 511 | } 512 | 513 | } catch (err) { 514 | return 'invalid_selector'; 515 | } 516 | 517 | //detect if the selector includes a pseudo-class, i.e. :active, :focus 518 | var parse = selector.match(/\:+[\w-]+/gi); 519 | if (parse !== null && parse.hasOwnProperty('length') && parse.length > 0) { 520 | return 'pseudo_class'; 521 | } else { 522 | return false; 523 | } 524 | 525 | }, 526 | 527 | findstylesheets: function () { 528 | 529 | var page = { 530 | url: helium.data.currenturl, 531 | links: [] 532 | }; 533 | 534 | //find link elements on the page 535 | var links = helium.$('link[rel="stylesheet"]'); 536 | 537 | for (var i = 0; i < links.length; i++) { 538 | 539 | //get href 540 | var tmplink = links[i].getAttribute('href'); 541 | 542 | //append full URI if absent 543 | if (tmplink.indexOf('http') !== 0 && tmplink.substr(0, 2) !== '//') { 544 | 545 | // make sure that relative URLs work too 546 | if (tmplink.indexOf('/') !== 0) { 547 | var lastDir = window.location.pathname.lastIndexOf('/'); 548 | var directory; 549 | 550 | if (lastDir > 0) { 551 | directory = window.location.pathname.substring(0, lastDir + 1); 552 | } else { 553 | directory = '/'; 554 | } 555 | tmplink = directory + tmplink; 556 | } 557 | tmplink = window.location.protocol + '//' + window.location.hostname + ':' + window.location.port + tmplink; 558 | 559 | } 560 | 561 | //filter out urls not on this domain 562 | if (tmplink.indexOf(window.location.hostname) !== -1) { 563 | page.links.push(tmplink); 564 | 565 | if (typeof helium.data.stylesheets === 'undefined') { 566 | helium.data.stylesheets = []; 567 | } 568 | 569 | helium.data.stylesheets.push(tmplink); 570 | } 571 | 572 | } 573 | 574 | //check if data field exists 575 | if (typeof helium.data.pages === 'undefined') { 576 | helium.data.pages = []; 577 | } 578 | 579 | //save pages 580 | helium.data.pages.push(page); 581 | helium.save(); 582 | 583 | //go to next page 584 | if (helium.data.findinglist.length > 0) { 585 | 586 | helium.nav(helium.data.findinglist); 587 | 588 | } else { 589 | 590 | //remove duplicates from stylesheets list 591 | helium.data.stylesheets.sort(); 592 | 593 | for (var i = 0; i < helium.data.stylesheets.length - 1; i++) { 594 | if (helium.data.stylesheets[i] === helium.data.stylesheets[i + 1]) { 595 | helium.data.stylesheets.splice(i--, 1); 596 | } 597 | } 598 | 599 | for (var i = 0; i < helium.data.stylesheets.length; i++) { 600 | var tmp = helium.data.stylesheets[i]; 601 | helium.data.stylesheets[i] = { 602 | url: tmp, 603 | selectors: [] 604 | }; 605 | } 606 | 607 | //update status 608 | helium.data.status = 2; 609 | helium.save(); 610 | 611 | helium.checkstatus(); 612 | 613 | } 614 | 615 | }, 616 | 617 | //list of stylesheet links on page 618 | getcss: function () { 619 | 620 | for (var i = 0; i < helium.data.stylesheets.length; i++) { 621 | 622 | //get content of stylesheets via XHR 623 | helium.get(helium.data.stylesheets[i].url, i, function (index, data) { 624 | 625 | //remove css comments 626 | data = data.replace(/\/\*[\s\S]*?\*\//gim, ''); 627 | 628 | //parse selectors. ##NEWLINE REMOVAL IS HACKISH, CAN BE DONE BETTER WITH A BETTER REGEX 629 | var selectors = data.replace(/\n/g, '').match(/[^\}]+[\.\#\-\w]?(?=\{)/gim) || []; 630 | 631 | //results of selector tests 632 | var results = []; 633 | 634 | for (var e = 0; e < selectors.length; e++) { 635 | 636 | var sel = selectors[e].split(','); 637 | 638 | //check for multiple selectors defined together. eg body,h1,h2,h3{} 639 | if (sel.length > 1) { 640 | 641 | var arr = []; 642 | for (var t = 0; t < sel.length; t++) { 643 | 644 | if (sel[t] !== '') { //don't add empty selectors 645 | arr.push({s: sel[t], v: false}); 646 | } 647 | 648 | } 649 | 650 | results.push(arr); 651 | 652 | } else { 653 | 654 | results.push([{s: selectors[e], v: false}]); 655 | 656 | } 657 | 658 | } 659 | 660 | //store stylesheet results 661 | helium.data.stylesheets[index].selectors = results; 662 | helium.save(); 663 | 664 | //set status if the last request is done 665 | if (index === helium.data.stylesheets.length - 1) { 666 | helium.data.status = 3; 667 | 668 | //navigate to first page in helium.pagelist 669 | helium.nav(); 670 | } 671 | 672 | }); 673 | 674 | } 675 | 676 | }, 677 | 678 | //navigate to next page in list 679 | nav: function (list) { 680 | 681 | //if no list is provided, default to pagelist 682 | if (!list) { 683 | list = helium.data.pagelist; 684 | } 685 | 686 | //remove first url in list 687 | var next = list.shift(); 688 | 689 | //stores the url that is being redirected to 690 | if (next !== undefined) { 691 | helium.data.currenturl = next; 692 | } 693 | 694 | helium.save(); 695 | 696 | //redirect 697 | if (next !== undefined) { 698 | window.location = next; 699 | } 700 | 701 | }, 702 | 703 | //store list of pages to be checked 704 | setPageList: function (pagelist) { 705 | 706 | helium.data.pagelist = pagelist; 707 | helium.save(); 708 | 709 | }, 710 | 711 | trim: function (str) { 712 | 713 | if (typeof String.prototype.trim === 'function') { 714 | return str.trim(); 715 | } else { 716 | return str.replace(/^\s+/, '').replace(/\s+$/, ''); 717 | } 718 | 719 | }, 720 | 721 | on: function (target, ev, fn) { 722 | //only add events to the first element in the target/querySelectorAll nodeList. 723 | //don't need to add in support for multiple targets 724 | target = target[0] || target; 725 | target.addEventListener(ev, fn, false); 726 | }, 727 | 728 | //return info from localStorage 729 | load: function () { 730 | 731 | if (!localStorage.cssdetect) { 732 | localStorage.cssdetect = JSON.stringify({}); 733 | } 734 | 735 | helium.data = JSON.parse(localStorage.cssdetect); 736 | 737 | }, 738 | 739 | save: function () { 740 | 741 | //store page data into localStorage 742 | localStorage.cssdetect = JSON.stringify(helium.data); 743 | 744 | }, 745 | 746 | // when something goes wrong, nice to helium.clear() to nuke the local storage 747 | clear: function () { 748 | delete localStorage['cssdetect']; 749 | }, 750 | 751 | get: function (url, index, callback) { 752 | var http; 753 | if (window.attachEvent) { 754 | http = new ActiveXObject('Microsoft.XMLHTTP'); 755 | } else { 756 | http = new XMLHttpRequest(); 757 | } 758 | http.open('GET', url); 759 | http.onreadystatechange = function () { 760 | if (http.readyState === 4) { 761 | callback(index, http.responseText); 762 | } 763 | }; 764 | http.send(null); 765 | }, 766 | 767 | $: function (selector) { 768 | return document.querySelectorAll(selector); 769 | } 770 | 771 | }; 772 | --------------------------------------------------------------------------------