├── HACKING
├── README
├── icons
├── readability-128.png
├── readability-16.png
├── readability-48.png
├── readability-toolbar.png
└── small-tile.png
├── manifest.json
├── readability
├── arc90-logo-large.png
├── arc90-logo-small.png
├── arc90lab-logo-small.png
├── email-head.gif
├── email-readability.gif
├── footer-arc90.png
├── footer-readability.png
├── footer-thanks.png
├── footer.png
├── kindling-logo-small.gif
├── read-email.png
├── read-kindle.png
├── read-print.png
├── read-refresh.png
├── readability-drag.png
├── readability-logo-small.png
├── readability-orig.js
├── readability-print.css
├── readability-x.js
├── readability.css
├── readability.js
├── readability.png
├── title-small.png
├── title.png
├── twitter.png
└── typekit-icon.png
└── redux
├── background.html
├── background.js
├── contentscript.js
├── example.html
├── jquery-1.4.2.js
├── options.css
├── options.html
├── options.js
└── underscore-0.6.js
/HACKING:
--------------------------------------------------------------------------------
1 | SOME TIPS ON HOW TO IMPROVE READABILITY
2 | =======================================
3 |
4 |
5 | IMPORTANT
6 | ---------
7 |
8 | Readability Redux is just a wrapper around Readability. If you want to
9 | improve css styling, add new fonts or whatnot, consider contributing
10 | to the original Readability project[1].
11 |
12 |
13 | Layout
14 | ------
15 |
16 | Okay, having that sorted out, let's look how RR is organized:
17 |
18 | / - some boilerplate files, like the one you're reading right now
19 | /icon*.png - icon files. Accepted dimensions are 16x16, 19x19, 48x48 and 128x128.
20 | /readability - "stock" Readability files
21 | /readability.js - original Readability script
22 | /readability-x.js - Readability that works with selections ("experimental")
23 | /redux - extension-specific files
24 | /background.js - background page
25 | /contentscript.js - content script (launched with every tab)
26 | /options.* - options page
27 | /example.html - example text shown in the options page
28 |
29 | Innards
30 | -------
31 |
32 | There are three extensions scripts: background.js, options.js and contentscript.js.
33 | All communication happens through message passing.
34 |
35 | Note that background.js accepts messages sent by another extensions.
36 |
37 | Here are the interactions between those 3 scripts:
38 |
39 | + background.js - main pivot of the extension
40 | Messages accepted:
41 | + {"type": "javascript"} - returns a javascript code that readabilizes a document.
42 | You can pass an additional parameter "settings" with
43 | which you can customize the script. For the accepted
44 | format, see what getSettings spews out.
45 | + {"type": "getSettings"} - gets settings object. (see source for more)
46 | + {"type": "setSettings"} - analogous
47 | + {"type": "render", "tab_id": 123} - launches Redability in the given tab.
48 | If tab_id is ommitted, sender.tab.id
49 | is assumed.
50 |
51 | Actions performed:
52 | + When browser button or context menu item is clicked, sends "render" message
53 | to the proper context script.
54 | + When settings are changed (through setSettings) sends "newSettings" message
55 | to all its content scripts.
56 |
57 | + options.js
58 | Actions performed:
59 | + Communicates with the background.js through "getSettings"/"setSettings".
60 |
61 | + contentscript.js
62 | Messages accepted:
63 | + {"type": "render"} - launches Readability in the tab.
64 | + {"type": "newSettings"} - updates internal settings storage used for
65 | key shortcuts.
66 |
67 | Actions performed:
68 | + When correct key shortcut is pressed, Readablity is launched.
69 | + When Readability is launched, uses "javascript" message to get the
70 | code from background.js
71 |
72 |
73 | [1]: http://code.google.com/p/arc90labs-readability/
74 |
75 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | =================
2 | READABILITY REDUX
3 | =================
4 |
5 | Give your browsing an edge! Readability is a tool designed by Arc90.
6 | In their words:
7 | "Readability is a simple tool that makes reading on the Web more
8 | enjoyable by removing the cluter around what you're reading."
9 |
10 | Readability Redux is an extension for Google Chrome that brings you
11 | the support for Arc90's Readability. Check it out yourself.
12 |
13 | ------------
14 | Installation
15 | ------------
16 |
17 | Visit https://chrome.google.com/extensions/detail/jggheggpdocamneaacmfoipeehedigia
18 |
19 | Sources here are for development purposes.
20 |
21 | ----------
22 | Changelog
23 | ----------
24 |
25 | 1.3.4 (2011.12.25)
26 | + Added missing icons to the repo
27 |
28 | 1.3.3 (2011.12.25)
29 | + Updated to Readability r164
30 | + Removed needless console comments
31 | + Analytics
32 |
33 | 1.3.2 (2011.01.25)
34 | + New icon set by Pete Fairhurst.
35 |
36 | 1.3.1 (2010.08.15)
37 | + As context menu functionality isn't supported in stable Google Chrome, I had to remove it.
38 | + Minor bugfix.
39 |
40 | 1.3 (2010.08.14)
41 | + Now works with local files (if it isn't working, check out chrome://extensions and set "Allow access to file URLs")
42 | + Support for context menus (sadly they don't work with local files, and the hack I've used with the browser action is moot here)
43 | + Key shortcut updates should take an effect immediately after saving.
44 | + RR can be launched from another extensions (see HACKING).
45 | + A lil' code reorganization.
46 |
47 | 1.2.1 (2010.08.09)
48 | + Support for Readability 1.7.1 (multi-page support)
49 |
50 | 1.2 (2010.06.15)
51 | + Support for Readability 1.6 r147 (links-to-footnotes conversion)
52 | + Keyboard shortcuts, finally!
53 |
54 | 1.1.2 (2010.03.15)
55 | + Support for Readability 1.5.0 r137
56 |
57 | 1.1.1 (2010.03.01)
58 | + Fixed typo in options
59 |
60 | 1.1
61 | + Support for Readability 1.5
62 | + Preview is now in an iframe
63 |
64 | 1.0.1
65 | + Code overhaul, options are now based on jQuery + Underscore
66 | + Hosted on GitHub
67 |
68 | 1.0
69 | + Initial release
70 |
71 | ------------
72 | Contributing
73 | ------------
74 |
75 | If you want improve on css styling (or anything else in readability/ folder),
76 | talk to original Readability authors instead.
77 |
78 | In any case, see HACKING for more info.
79 |
80 | ----------------
81 | Acknowledgements
82 | ----------------
83 |
84 | + Ilsi 50Mhz - for applying Readability to a selection.
85 | + Ed Marshall (logic) - for updating RR to Readability 1.7.1 (RR 1.2.1).
86 | + Pete Fairhurst - for the new icon set.
87 |
88 |
--------------------------------------------------------------------------------
/icons/readability-128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/icons/readability-128.png
--------------------------------------------------------------------------------
/icons/readability-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/icons/readability-16.png
--------------------------------------------------------------------------------
/icons/readability-48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/icons/readability-48.png
--------------------------------------------------------------------------------
/icons/readability-toolbar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/icons/readability-toolbar.png
--------------------------------------------------------------------------------
/icons/small-tile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/icons/small-tile.png
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Readability Redux",
3 | "version": "1.3.4",
4 | "description": "Readability for Chrome. Now fully customizable!",
5 | "background_page": "redux/background.html",
6 | "browser_action": { "default_icon": "icons/readability-toolbar.png" },
7 | "icons": {
8 | "16": "icons/readability-16.png",
9 | "48": "icons/readability-48.png",
10 | "128": "icons/readability-128.png"
11 | },
12 | "permissions": [ "tabs", "http://*/*", "https://*/*"],
13 | "options_page": "redux/options.html",
14 | "content_scripts": [ { "matches": ["http://*/*", "https://*/*", "ftp://*/*", "file://*/*"], "js": ["redux/contentscript.js"] } ]
15 | }
16 |
--------------------------------------------------------------------------------
/readability/arc90-logo-large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/arc90-logo-large.png
--------------------------------------------------------------------------------
/readability/arc90-logo-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/arc90-logo-small.png
--------------------------------------------------------------------------------
/readability/arc90lab-logo-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/arc90lab-logo-small.png
--------------------------------------------------------------------------------
/readability/email-head.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/email-head.gif
--------------------------------------------------------------------------------
/readability/email-readability.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/email-readability.gif
--------------------------------------------------------------------------------
/readability/footer-arc90.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/footer-arc90.png
--------------------------------------------------------------------------------
/readability/footer-readability.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/footer-readability.png
--------------------------------------------------------------------------------
/readability/footer-thanks.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/footer-thanks.png
--------------------------------------------------------------------------------
/readability/footer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/footer.png
--------------------------------------------------------------------------------
/readability/kindling-logo-small.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/kindling-logo-small.gif
--------------------------------------------------------------------------------
/readability/read-email.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/read-email.png
--------------------------------------------------------------------------------
/readability/read-kindle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/read-kindle.png
--------------------------------------------------------------------------------
/readability/read-print.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/read-print.png
--------------------------------------------------------------------------------
/readability/read-refresh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/read-refresh.png
--------------------------------------------------------------------------------
/readability/readability-drag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/readability-drag.png
--------------------------------------------------------------------------------
/readability/readability-logo-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/readability-logo-small.png
--------------------------------------------------------------------------------
/readability/readability-orig.js:
--------------------------------------------------------------------------------
1 | /*jslint undef: true, nomen: true, eqeqeq: true, plusplus: true, newcap: true, immed: true, browser: true, devel: true, passfail: false */
2 | /*global window: false, readConvertLinksToFootnotes: false, readStyle: false, readSize: false, readMargin: false, Typekit: false, ActiveXObject: false */
3 |
4 | var dbg = (typeof console !== 'undefined') ? function(s) {
5 | console.log("Readability: " + s);
6 | } : function() {};
7 |
8 | /*
9 | * Readability. An Arc90 Lab Experiment.
10 | * Website: http://lab.arc90.com/experiments/readability
11 | * Source: http://code.google.com/p/arc90labs-readability
12 | *
13 | * "Readability" is a trademark of Arc90 Inc and may not be used without explicit permission.
14 | *
15 | * Copyright (c) 2010 Arc90 Inc
16 | * Readability is licensed under the Apache License, Version 2.0.
17 | **/
18 | var readability = {
19 | version: '1.7.1',
20 | emailSrc: 'http://lab.arc90.com/experiments/readability/email.php',
21 | iframeLoads: 0,
22 | convertLinksToFootnotes: false,
23 | reversePageScroll: false, /* If they hold shift and hit space, scroll up */
24 | frameHack: false, /**
25 | * The frame hack is to workaround a firefox bug where if you
26 | * pull content out of a frame and stick it into the parent element, the scrollbar won't appear.
27 | * So we fake a scrollbar in the wrapping div.
28 | **/
29 | biggestFrame: false,
30 | bodyCache: null, /* Cache the body HTML in case we need to re-use it later */
31 | flags: 0x1 | 0x2 | 0x4, /* Start with all flags set. */
32 |
33 | /* constants */
34 | FLAG_STRIP_UNLIKELYS: 0x1,
35 | FLAG_WEIGHT_CLASSES: 0x2,
36 | FLAG_CLEAN_CONDITIONALLY: 0x4,
37 |
38 | maxPages: 30, /* The maximum number of pages to loop through before we call it quits and just show a link. */
39 | parsedPages: {}, /* The list of pages we've parsed in this call of readability, for autopaging. As a key store for easier searching. */
40 | pageETags: {}, /* A list of the ETag headers of pages we've parsed, in case they happen to match, we'll know it's a duplicate. */
41 |
42 | /**
43 | * All of the regular expressions in use within readability.
44 | * Defined up here so we don't instantiate them repeatedly in loops.
45 | **/
46 | regexps: {
47 | unlikelyCandidates: /combx|comment|community|disqus|extra|foot|header|menu|remark|rss|shoutbox|sidebar|sponsor|ad-break|agegate|pagination|pager|popup|tweet|twitter/i,
48 | okMaybeItsACandidate: /and|article|body|column|main|shadow/i,
49 | positive: /article|body|content|entry|hentry|main|page|pagination|post|text|blog|story/i,
50 | negative: /combx|comment|com-|contact|foot|footer|footnote|masthead|media|meta|outbrain|promo|related|scroll|shoutbox|sidebar|sponsor|shopping|tags|tool|widget/i,
51 | extraneous: /print|archive|comment|discuss|e[\-]?mail|share|reply|all|login|sign|single/i,
52 | divToPElements: /<(a|blockquote|dl|div|img|ol|p|pre|table|ul)/i,
53 | replaceBrs: /(
]*>[ \n\r\t]*){2,}/gi,
54 | replaceFonts: /<(\/?)font[^>]*>/gi,
55 | trim: /^\s+|\s+$/g,
56 | normalize: /\s{2,}/g,
57 | killBreaks: /(
(\s| ?)*){1,}/g,
58 | videos: /http:\/\/(www\.)?(youtube|vimeo)\.com/i,
59 | skipFootnoteLink: /^\s*(\[?[a-z0-9]{1,2}\]?|^|edit|citation needed)\s*$/i,
60 | nextLink: /(next|weiter|continue|>([^\|]|$)|»([^\|]|$))/i, // Match: next, continue, >, >>, » but not >|, »| as those usually mean last.
61 | prevLink: /(prev|earl|old|new|<|«)/i
62 | },
63 |
64 | /**
65 | * Runs readability.
66 | *
67 | * Workflow:
68 | * 1. Prep the document by removing script tags, css, etc.
69 | * 2. Build readability's DOM tree.
70 | * 3. Grab the article content from the current dom tree.
71 | * 4. Replace the current DOM tree with the new one.
72 | * 5. Read peacefully.
73 | *
74 | * @return void
75 | **/
76 | init: function() {
77 | /* Before we do anything, remove all scripts that are not readability. */
78 | window.onload = window.onunload = function() {};
79 |
80 | readability.removeScripts(document);
81 |
82 | if(document.body && !readability.bodyCache) {
83 | readability.bodyCache = document.body.innerHTML;
84 |
85 | }
86 | /* Make sure this document is added to the list of parsed pages first, so we don't double up on the first page */
87 | readability.parsedPages[window.location.href.replace(/\/$/, '')] = true;
88 |
89 | /* Pull out any possible next page link first */
90 | var nextPageLink = readability.findNextPageLink(document.body);
91 |
92 | readability.prepDocument();
93 |
94 | /* Build readability's DOM tree */
95 | var overlay = document.createElement("DIV");
96 | var innerDiv = document.createElement("DIV");
97 | var articleTools = readability.getArticleTools();
98 | var articleTitle = readability.getArticleTitle();
99 | var articleContent = readability.grabArticle();
100 | var articleFooter = readability.getArticleFooter();
101 |
102 | if(!articleContent) {
103 | articleContent = document.createElement("DIV");
104 | articleContent.id = "readability-content";
105 | articleContent.innerHTML = [
106 | "
Sorry, readability was unable to parse this page for content. If you feel like it should have been able to, please let us know by submitting an issue.
", 107 | (readability.frameHack ? "It appears this page uses frames. Unfortunately, browser security properties often cause Readability to fail on pages that include frames. You may want to try running readability itself on this source page: " + readability.biggestFrame.src + "
" : ""), 108 | "Also, please note that Readability does not play very nicely with front pages. Readability is intended to work on articles with a sizable chunk of text that you'd like to read comfortably. If you're using Readability on a landing page (like nytimes.com for example), please click into an article first before using Readability.
" 109 | ].join(''); 110 | 111 | nextPageLink = null; 112 | } 113 | 114 | overlay.id = "readOverlay"; 115 | innerDiv.id = "readInner"; 116 | 117 | /* Apply user-selected styling */ 118 | document.body.className = readStyle; 119 | document.dir = readability.getSuggestedDirection(articleTitle.innerHTML); 120 | 121 | if (readStyle === "style-athelas" || readStyle === "style-apertura"){ 122 | overlay.className = readStyle + " rdbTypekit"; 123 | } 124 | else { 125 | overlay.className = readStyle; 126 | } 127 | innerDiv.className = readMargin + " " + readSize; 128 | 129 | if(typeof(readConvertLinksToFootnotes) !== 'undefined' && readConvertLinksToFootnotes === true) { 130 | readability.convertLinksToFootnotes = true; 131 | } 132 | 133 | /* Glue the structure of our document together. */ 134 | innerDiv.appendChild( articleTitle ); 135 | innerDiv.appendChild( articleContent ); 136 | innerDiv.appendChild( articleFooter ); 137 | overlay.appendChild( articleTools ); 138 | overlay.appendChild( innerDiv ); 139 | 140 | /* Clear the old HTML, insert the new content. */ 141 | document.body.innerHTML = ""; 142 | document.body.insertBefore(overlay, document.body.firstChild); 143 | document.body.removeAttribute('style'); 144 | 145 | if(readability.frameHack) 146 | { 147 | var readOverlay = document.getElementById('readOverlay'); 148 | readOverlay.style.height = '100%'; 149 | readOverlay.style.overflow = 'auto'; 150 | } 151 | 152 | /** 153 | * If someone tries to use Readability on a site's root page, give them a warning about usage. 154 | **/ 155 | if((window.location.protocol + "//" + window.location.host + "/") === window.location.href) 156 | { 157 | articleContent.style.display = "none"; 158 | var rootWarning = document.createElement('p'); 159 | rootWarning.id = "readability-warning"; 160 | rootWarning.innerHTML = "Readability was intended for use on individual articles and not home pages. " + 161 | "If you'd like to try rendering this page anyway, click here to continue."; 162 | 163 | innerDiv.insertBefore( rootWarning, articleContent ); 164 | } 165 | 166 | readability.postProcessContent(articleContent); 167 | 168 | window.scrollTo(0, 0); 169 | 170 | /* If we're using the Typekit library, select the font */ 171 | if (readStyle === "style-athelas" || readStyle === "style-apertura") { 172 | readability.useRdbTypekit(); 173 | } 174 | 175 | if (nextPageLink) { 176 | /** 177 | * Append any additional pages after a small timeout so that people 178 | * can start reading without having to wait for this to finish processing. 179 | **/ 180 | window.setTimeout(function() { 181 | readability.appendNextPage(nextPageLink); 182 | }, 500); 183 | } 184 | 185 | /** Smooth scrolling **/ 186 | document.onkeydown = function(e) { 187 | var code = (window.event) ? event.keyCode : e.keyCode; 188 | if (code === 16) { 189 | readability.reversePageScroll = true; 190 | return; 191 | } 192 | 193 | if (code === 32) { 194 | readability.curScrollStep = 0; 195 | var windowHeight = window.innerHeight ? window.innerHeight : (document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight); 196 | 197 | if(readability.reversePageScroll) { 198 | readability.scrollTo(readability.scrollTop(), readability.scrollTop() - (windowHeight - 50), 20, 10); 199 | } 200 | else { 201 | readability.scrollTo(readability.scrollTop(), readability.scrollTop() + (windowHeight - 50), 20, 10); 202 | } 203 | 204 | return false; 205 | } 206 | }; 207 | 208 | document.onkeyup = function(e) { 209 | var code = (window.event) ? event.keyCode : e.keyCode; 210 | if (code === 16) { 211 | readability.reversePageScroll = false; 212 | return; 213 | } 214 | }; 215 | }, 216 | 217 | /** 218 | * Run any post-process modifications to article content as necessary. 219 | * 220 | * @param Element 221 | * @return void 222 | **/ 223 | postProcessContent: function(articleContent) { 224 | if(readability.convertLinksToFootnotes && !window.location.href.match(/wikipedia\.org/g)) { 225 | readability.addFootnotes(articleContent); 226 | } 227 | 228 | readability.fixImageFloats(articleContent); 229 | }, 230 | 231 | /** 232 | * Some content ends up looking ugly if the image is too large to be floated. 233 | * If the image is wider than a threshold (currently 55%), no longer float it, 234 | * center it instead. 235 | * 236 | * @param Element 237 | * @return void 238 | **/ 239 | fixImageFloats: function (articleContent) { 240 | var imageWidthThreshold = Math.min(articleContent.offsetWidth, 800) * 0.55, 241 | images = articleContent.getElementsByTagName('img'); 242 | 243 | for(var i=0, il = images.length; i < il; i+=1) { 244 | var image = images[i]; 245 | 246 | if(image.offsetWidth > imageWidthThreshold) { 247 | image.className += " blockImage"; 248 | } 249 | } 250 | }, 251 | 252 | /** 253 | * Get the article tools Element that has buttons like reload, print, email. 254 | * 255 | * @return void 256 | **/ 257 | getArticleTools: function () { 258 | var articleTools = document.createElement("DIV"); 259 | 260 | articleTools.id = "readTools"; 261 | articleTools.innerHTML = 262 | "Reload Original Page" + 263 | "Print Page" + 264 | "Email Page"; 265 | 266 | return articleTools; 267 | }, 268 | 269 | /** 270 | * retuns the suggested direction of the string 271 | * 272 | * @return "rtl" || "ltr" 273 | **/ 274 | getSuggestedDirection: function(text) { 275 | function sanitizeText() { 276 | return text.replace(/@\w+/, ""); 277 | } 278 | 279 | function countMatches(match) { 280 | var matches = text.match(new RegExp(match, "g")); 281 | return matches !== null ? matches.length : 0; 282 | } 283 | 284 | function isRTL() { 285 | var count_heb = countMatches("[\\u05B0-\\u05F4\\uFB1D-\\uFBF4]"); 286 | var count_arb = countMatches("[\\u060C-\\u06FE\\uFB50-\\uFEFC]"); 287 | 288 | // if 20% of chars are Hebrew or Arbic then direction is rtl 289 | return (count_heb + count_arb) * 100 / text.length > 20; 290 | } 291 | 292 | text = sanitizeText(text); 293 | return isRTL() ? "rtl" : "ltr"; 294 | }, 295 | 296 | 297 | /** 298 | * Get the article title as an H1. 299 | * 300 | * @return void 301 | **/ 302 | getArticleTitle: function () { 303 | var curTitle = "", 304 | origTitle = ""; 305 | 306 | try { 307 | curTitle = origTitle = document.title; 308 | 309 | if(typeof curTitle !== "string") { /* If they had an element with id "title" in their HTML */ 310 | curTitle = origTitle = readability.getInnerText(document.getElementsByTagName('title')[0]); 311 | } 312 | } 313 | catch(e) {} 314 | 315 | if(curTitle.match(/ [\|\-] /)) 316 | { 317 | curTitle = origTitle.replace(/(.*)[\|\-] .*/gi,'$1'); 318 | 319 | if(curTitle.split(' ').length < 3) { 320 | curTitle = origTitle.replace(/[^\|\-]*[\|\-](.*)/gi,'$1'); 321 | } 322 | } 323 | else if(curTitle.indexOf(': ') !== -1) 324 | { 325 | curTitle = origTitle.replace(/.*:(.*)/gi, '$1'); 326 | 327 | if(curTitle.split(' ').length < 3) { 328 | curTitle = origTitle.replace(/[^:]*[:](.*)/gi,'$1'); 329 | } 330 | } 331 | else if(curTitle.length > 150 || curTitle.length < 15) 332 | { 333 | var hOnes = document.getElementsByTagName('h1'); 334 | if(hOnes.length === 1) 335 | { 336 | curTitle = readability.getInnerText(hOnes[0]); 337 | } 338 | } 339 | 340 | curTitle = curTitle.replace( readability.regexps.trim, "" ); 341 | 342 | if(curTitle.split(' ').length <= 4) { 343 | curTitle = origTitle; 344 | } 345 | 346 | var articleTitle = document.createElement("H1"); 347 | articleTitle.innerHTML = curTitle; 348 | 349 | return articleTitle; 350 | }, 351 | 352 | /** 353 | * Get the footer with the readability mark etc. 354 | * 355 | * @return void 356 | **/ 357 | getArticleFooter: function () { 358 | var articleFooter = document.createElement("DIV"); 359 | 360 | /** 361 | * For research purposes, generate an img src that contains the chosen readstyle etc, 362 | * so we can generate aggregate stats and change styles based on them in the future 363 | **/ 364 | // var statsQueryParams = "?readStyle=" + encodeURIComponent(readStyle) + "&readMargin=" + encodeURIComponent(readMargin) + "&readSize=" + encodeURIComponent(readSize); 365 | /* TODO: attach this to an image */ 366 | 367 | articleFooter.id = "readFooter"; 368 | articleFooter.innerHTML = [ 369 | " ", 370 | " "].join(''); 381 | 382 | return articleFooter; 383 | }, 384 | 385 | /** 386 | * Prepare the HTML document for readability to scrape it. 387 | * This includes things like stripping javascript, CSS, and handling terrible markup. 388 | * 389 | * @return void 390 | **/ 391 | prepDocument: function () { 392 | /** 393 | * In some cases a body element can't be found (if the HTML is totally hosed for example) 394 | * so we create a new body node and append it to the document. 395 | */ 396 | if(document.body === null) 397 | { 398 | var body = document.createElement("body"); 399 | try { 400 | document.body = body; 401 | } 402 | catch(e) { 403 | document.documentElement.appendChild(body); 404 | dbg(e); 405 | } 406 | } 407 | 408 | document.body.id = "readabilityBody"; 409 | 410 | var frames = document.getElementsByTagName('frame'); 411 | if(frames.length > 0) 412 | { 413 | var bestFrame = null; 414 | var bestFrameSize = 0; /* The frame to try to run readability upon. Must be on same domain. */ 415 | var biggestFrameSize = 0; /* Used for the error message. Can be on any domain. */ 416 | for(var frameIndex = 0; frameIndex < frames.length; frameIndex+=1) 417 | { 418 | var frameSize = frames[frameIndex].offsetWidth + frames[frameIndex].offsetHeight; 419 | var canAccessFrame = false; 420 | try { 421 | var frameBody = frames[frameIndex].contentWindow.document.body; 422 | canAccessFrame = true; 423 | } 424 | catch(eFrames) { 425 | dbg(eFrames); 426 | } 427 | 428 | if(frameSize > biggestFrameSize) { 429 | biggestFrameSize = frameSize; 430 | readability.biggestFrame = frames[frameIndex]; 431 | } 432 | 433 | if(canAccessFrame && frameSize > bestFrameSize) 434 | { 435 | readability.frameHack = true; 436 | 437 | bestFrame = frames[frameIndex]; 438 | bestFrameSize = frameSize; 439 | } 440 | } 441 | 442 | if(bestFrame) 443 | { 444 | var newBody = document.createElement('body'); 445 | newBody.innerHTML = bestFrame.contentWindow.document.body.innerHTML; 446 | newBody.style.overflow = 'scroll'; 447 | document.body = newBody; 448 | 449 | var frameset = document.getElementsByTagName('frameset')[0]; 450 | if(frameset) { 451 | frameset.parentNode.removeChild(frameset); } 452 | } 453 | } 454 | 455 | /* Remove all stylesheets */ 456 | for (var k=0;k < document.styleSheets.length; k+=1) { 457 | if (document.styleSheets[k].href !== null && document.styleSheets[k].href.lastIndexOf("readability") === -1) { 458 | document.styleSheets[k].disabled = true; 459 | } 460 | } 461 | 462 | /* Remove all style tags in head (not doing this on IE) - TODO: Why not? */ 463 | var styleTags = document.getElementsByTagName("style"); 464 | for (var st=0;st < styleTags.length; st+=1) { 465 | styleTags[st].textContent = ""; 466 | } 467 | 468 | /* Turn all double br's into p's */ 469 | /* Note, this is pretty costly as far as processing goes. Maybe optimize later. */ 470 | document.body.innerHTML = document.body.innerHTML.replace(readability.regexps.replaceBrs, '').replace(readability.regexps.replaceFonts, '<$1span>'); 471 | }, 472 | 473 | /** 474 | * For easier reading, convert this document to have footnotes at the bottom rather than inline links. 475 | * @see http://www.roughtype.com/archives/2010/05/experiments_in.php 476 | * 477 | * @return void 478 | **/ 479 | addFootnotes: function(articleContent) { 480 | var footnotesWrapper = document.getElementById('readability-footnotes'), 481 | articleFootnotes = document.getElementById('readability-footnotes-list'); 482 | 483 | if(!footnotesWrapper) { 484 | footnotesWrapper = document.createElement("DIV"); 485 | footnotesWrapper.id = 'readability-footnotes'; 486 | footnotesWrapper.innerHTML = '
tags, etc.
609 | *
610 | * @param Element
611 | * @return void
612 | **/
613 | prepArticle: function (articleContent) {
614 | readability.cleanStyles(articleContent);
615 | readability.killBreaks(articleContent);
616 |
617 | /* Clean out junk from the article content */
618 | readability.cleanConditionally(articleContent, "form");
619 | readability.clean(articleContent, "object");
620 | readability.clean(articleContent, "h1");
621 |
622 | /**
623 | * If there is only one h2, they are probably using it
624 | * as a header and not a subheader, so remove it since we already have a header.
625 | ***/
626 | if(articleContent.getElementsByTagName('h2').length === 1) {
627 | readability.clean(articleContent, "h2");
628 | }
629 | readability.clean(articleContent, "iframe");
630 |
631 | readability.cleanHeaders(articleContent);
632 |
633 | /* Do these last as the previous stuff may have removed junk that will affect these */
634 | readability.cleanConditionally(articleContent, "table");
635 | readability.cleanConditionally(articleContent, "ul");
636 | readability.cleanConditionally(articleContent, "div");
637 |
638 | /* Remove extra paragraphs */
639 | var articleParagraphs = articleContent.getElementsByTagName('p');
640 | for(var i = articleParagraphs.length-1; i >= 0; i-=1) {
641 | var imgCount = articleParagraphs[i].getElementsByTagName('img').length;
642 | var embedCount = articleParagraphs[i].getElementsByTagName('embed').length;
643 | var objectCount = articleParagraphs[i].getElementsByTagName('object').length;
644 |
645 | if(imgCount === 0 && embedCount === 0 && objectCount === 0 && readability.getInnerText(articleParagraphs[i], false) === '') {
646 | articleParagraphs[i].parentNode.removeChild(articleParagraphs[i]);
647 | }
648 | }
649 |
650 | try {
651 | articleContent.innerHTML = articleContent.innerHTML.replace(/
]*>\s*
topCandidate.readability.contentScore) { 852 | topCandidate = candidates[c]; } 853 | } 854 | 855 | /** 856 | * If we still have no top candidate, just use the body as a last resort. 857 | * We also have to copy the body node so it is something we can modify. 858 | **/ 859 | if (topCandidate === null || topCandidate.tagName === "BODY") 860 | { 861 | topCandidate = document.createElement("DIV"); 862 | topCandidate.innerHTML = page.innerHTML; 863 | page.innerHTML = ""; 864 | page.appendChild(topCandidate); 865 | readability.initializeNode(topCandidate); 866 | } 867 | 868 | /** 869 | * Now that we have the top candidate, look through its siblings for content that might also be related. 870 | * Things like preambles, content split by ads that we removed, etc. 871 | **/ 872 | var articleContent = document.createElement("DIV"); 873 | if (isPaging) { 874 | articleContent.id = "readability-content"; 875 | } 876 | var siblingScoreThreshold = Math.max(10, topCandidate.readability.contentScore * 0.2); 877 | var siblingNodes = topCandidate.parentNode.childNodes; 878 | 879 | 880 | for(var s=0, sl=siblingNodes.length; s < sl; s+=1) { 881 | var siblingNode = siblingNodes[s]; 882 | var append = false; 883 | 884 | /** 885 | * Fix for odd IE7 Crash where siblingNode does not exist even though this should be a live nodeList. 886 | * Example of error visible here: http://www.esquire.com/features/honesty0707 887 | **/ 888 | if(!siblingNode) { 889 | continue; 890 | } 891 | 892 | dbg("Looking at sibling node: " + siblingNode + " (" + siblingNode.className + ":" + siblingNode.id + ")" + ((typeof siblingNode.readability !== 'undefined') ? (" with score " + siblingNode.readability.contentScore) : '')); 893 | dbg("Sibling has score " + (siblingNode.readability ? siblingNode.readability.contentScore : 'Unknown')); 894 | 895 | if(siblingNode === topCandidate) 896 | { 897 | append = true; 898 | } 899 | 900 | var contentBonus = 0; 901 | /* Give a bonus if sibling nodes and top candidates have the example same classname */ 902 | if(siblingNode.className === topCandidate.className && topCandidate.className !== "") { 903 | contentBonus += topCandidate.readability.contentScore * 0.2; 904 | } 905 | 906 | if(typeof siblingNode.readability !== 'undefined' && (siblingNode.readability.contentScore+contentBonus) >= siblingScoreThreshold) 907 | { 908 | append = true; 909 | } 910 | 911 | if(siblingNode.nodeName === "P") { 912 | var linkDensity = readability.getLinkDensity(siblingNode); 913 | var nodeContent = readability.getInnerText(siblingNode); 914 | var nodeLength = nodeContent.length; 915 | 916 | if(nodeLength > 80 && linkDensity < 0.25) 917 | { 918 | append = true; 919 | } 920 | else if(nodeLength < 80 && linkDensity === 0 && nodeContent.search(/\.( |$)/) !== -1) 921 | { 922 | append = true; 923 | } 924 | } 925 | 926 | if(append) { 927 | dbg("Appending node: " + siblingNode); 928 | 929 | var nodeToAppend = null; 930 | if(siblingNode.nodeName !== "DIV" && siblingNode.nodeName !== "P") { 931 | /* We have a node that isn't a common block level element, like a form or td tag. Turn it into a div so it doesn't get filtered out later by accident. */ 932 | 933 | dbg("Altering siblingNode of " + siblingNode.nodeName + ' to div.'); 934 | nodeToAppend = document.createElement("DIV"); 935 | try { 936 | nodeToAppend.id = siblingNode.id; 937 | nodeToAppend.innerHTML = siblingNode.innerHTML; 938 | } 939 | catch(er) { 940 | dbg("Could not alter siblingNode to div, probably an IE restriction, reverting back to original."); 941 | nodeToAppend = siblingNode; 942 | s-=1; 943 | sl-=1; 944 | } 945 | } else { 946 | nodeToAppend = siblingNode; 947 | s-=1; 948 | sl-=1; 949 | } 950 | 951 | /* To ensure a node does not interfere with readability styles, remove its classnames */ 952 | nodeToAppend.className = ""; 953 | 954 | /* Append sibling and subtract from our list because it removes the node when you append to another node */ 955 | articleContent.appendChild(nodeToAppend); 956 | } 957 | } 958 | 959 | /** 960 | * So we have all of the content that we need. Now we clean it up for presentation. 961 | **/ 962 | readability.prepArticle(articleContent); 963 | 964 | if (readability.curPageNum === 1) { 965 | articleContent.innerHTML = '
§
'; 1405 | 1406 | document.getElementById("readability-content").appendChild(articlePage); 1407 | 1408 | if(readability.curPageNum > readability.maxPages) { 1409 | var nextPageMarkup = ""; 1410 | 1411 | articlePage.innerHTML = articlePage.innerHTML + nextPageMarkup; 1412 | return; 1413 | } 1414 | 1415 | /** 1416 | * Now that we've built the article page DOM element, get the page content 1417 | * asynchronously and load the cleaned content into the div we created for it. 1418 | **/ 1419 | (function(pageUrl, thisPage) { 1420 | readability.ajax(pageUrl, { 1421 | success: function(r) { 1422 | 1423 | /* First, check to see if we have a matching ETag in headers - if we do, this is a duplicate page. */ 1424 | var eTag = r.getResponseHeader('ETag'); 1425 | if(eTag) { 1426 | if(eTag in readability.pageETags) { 1427 | dbg("Exact duplicate page found via ETag. Aborting."); 1428 | articlePage.style.display = 'none'; 1429 | return; 1430 | } else { 1431 | readability.pageETags[eTag] = 1; 1432 | } 1433 | } 1434 | 1435 | // TODO: this ends up doubling up page numbers on NYTimes articles. Need to generically parse those away. 1436 | var page = document.createElement("DIV"); 1437 | 1438 | /** 1439 | * Do some preprocessing to our HTML to make it ready for appending. 1440 | * • Remove any script tags. Swap and reswap newlines with a unicode character because multiline regex doesn't work in javascript. 1441 | * • Turn any noscript tags into divs so that we can parse them. This allows us to find any next page links hidden via javascript. 1442 | * • Turn all double br's into p's - was handled by prepDocument in the original view. 1443 | * Maybe in the future abstract out prepDocument to work for both the original document and AJAX-added pages. 1444 | **/ 1445 | var responseHtml = r.responseText.replace(/\n/g,'\uffff').replace(/');
1449 | responseHtml = responseHtml.replace(readability.regexps.replaceFonts, '<$1span>');
1450 |
1451 | page.innerHTML = responseHtml;
1452 |
1453 | /**
1454 | * Reset all flags for the next page, as they will search through it and disable as necessary at the end of grabArticle.
1455 | **/
1456 | readability.flags = 0x1 | 0x2 | 0x4;
1457 |
1458 | var nextPageLink = readability.findNextPageLink(page),
1459 | content = readability.grabArticle(page);
1460 |
1461 | if(!content) {
1462 | dbg("No content found in page to append. Aborting.");
1463 | return;
1464 | }
1465 |
1466 | /**
1467 | * Anti-duplicate mechanism. Essentially, get the first paragraph of our new page.
1468 | * Compare it against all of the the previous document's we've gotten. If the previous
1469 | * document contains exactly the innerHTML of this first paragraph, it's probably a duplicate.
1470 | **/
1471 | var firstP = content.getElementsByTagName("P").length ? content.getElementsByTagName("P")[0] : null;
1472 | if(firstP && firstP.innerHTML.length > 100) {
1473 | for(var i=1; i <= readability.curPageNum; i+=1) {
1474 | var rPage = document.getElementById('readability-page-' + i);
1475 | if(rPage && rPage.innerHTML.indexOf(firstP.innerHTML) !== -1) {
1476 | dbg('Duplicate of page ' + i + ' - skipping.');
1477 | articlePage.style.display = 'none';
1478 | readability.parsedPages[pageUrl] = true;
1479 | return;
1480 | }
1481 | }
1482 | }
1483 |
1484 | readability.removeScripts(content);
1485 |
1486 | thisPage.innerHTML = thisPage.innerHTML + content.innerHTML;
1487 |
1488 | /**
1489 | * After the page has rendered, post process the content. This delay is necessary because,
1490 | * in webkit at least, offsetWidth is not set in time to determine image width. We have to
1491 | * wait a little bit for reflow to finish before we can fix floating images.
1492 | **/
1493 | window.setTimeout(
1494 | function() { readability.postProcessContent(thisPage); },
1495 | 500
1496 | );
1497 |
1498 | if(nextPageLink) {
1499 | readability.appendNextPage(nextPageLink);
1500 | }
1501 | }
1502 | });
1503 | }(nextPageLink, articlePage));
1504 | },
1505 |
1506 | /**
1507 | * Get an elements class/id weight. Uses regular expressions to tell if this
1508 | * element looks good or bad.
1509 | *
1510 | * @param Element
1511 | * @return number (Integer)
1512 | **/
1513 | getClassWeight: function (e) {
1514 | if(!readability.flagIsActive(readability.FLAG_WEIGHT_CLASSES)) {
1515 | return 0;
1516 | }
1517 |
1518 | var weight = 0;
1519 |
1520 | /* Look for a special classname */
1521 | if (typeof(e.className) === 'string' && e.className !== '')
1522 | {
1523 | if(e.className.search(readability.regexps.negative) !== -1) {
1524 | weight -= 25; }
1525 |
1526 | if(e.className.search(readability.regexps.positive) !== -1) {
1527 | weight += 25; }
1528 | }
1529 |
1530 | /* Look for a special ID */
1531 | if (typeof(e.id) === 'string' && e.id !== '')
1532 | {
1533 | if(e.id.search(readability.regexps.negative) !== -1) {
1534 | weight -= 25; }
1535 |
1536 | if(e.id.search(readability.regexps.positive) !== -1) {
1537 | weight += 25; }
1538 | }
1539 |
1540 | return weight;
1541 | },
1542 |
1543 | nodeIsVisible: function (node) {
1544 | return (node.offsetWidth !== 0 || node.offsetHeight !== 0) && node.style.display.toLowerCase() !== 'none';
1545 | },
1546 |
1547 | /**
1548 | * Remove extraneous break tags from a node.
1549 | *
1550 | * @param Element
1551 | * @return void
1552 | **/
1553 | killBreaks: function (e) {
1554 | try {
1555 | e.innerHTML = e.innerHTML.replace(readability.regexps.killBreaks,'
');
1556 | }
1557 | catch (eBreaks) {
1558 | dbg("KillBreaks failed - this is an IE bug. Ignoring.: " + eBreaks);
1559 | }
1560 | },
1561 |
1562 | /**
1563 | * Clean a node of all elements of type "tag".
1564 | * (Unless it's a youtube/vimeo video. People love movies.)
1565 | *
1566 | * @param Element
1567 | * @param string tag to clean
1568 | * @return void
1569 | **/
1570 | clean: function (e, tag) {
1571 | var targetList = e.getElementsByTagName( tag );
1572 | var isEmbed = (tag === 'object' || tag === 'embed');
1573 |
1574 | for (var y=targetList.length-1; y >= 0; y-=1) {
1575 | /* Allow youtube and vimeo videos through as people usually want to see those. */
1576 | if(isEmbed) {
1577 | var attributeValues = "";
1578 | for (var i=0, il=targetList[y].attributes.length; i < il; i+=1) {
1579 | attributeValues += targetList[y].attributes[i].value + '|';
1580 | }
1581 |
1582 | /* First, check the elements attributes to see if any of them contain youtube or vimeo */
1583 | if (attributeValues.search(readability.regexps.videos) !== -1) {
1584 | continue;
1585 | }
1586 |
1587 | /* Then check the elements inside this element for the same. */
1588 | if (targetList[y].innerHTML.search(readability.regexps.videos) !== -1) {
1589 | continue;
1590 | }
1591 |
1592 | }
1593 |
1594 | targetList[y].parentNode.removeChild(targetList[y]);
1595 | }
1596 | },
1597 |
1598 | /**
1599 | * Clean an element of all tags of type "tag" if they look fishy.
1600 | * "Fishy" is an algorithm based on content length, classnames, link density, number of images & embeds, etc.
1601 | *
1602 | * @return void
1603 | **/
1604 | cleanConditionally: function (e, tag) {
1605 |
1606 | if(!readability.flagIsActive(readability.FLAG_CLEAN_CONDITIONALLY)) {
1607 | return;
1608 | }
1609 |
1610 | var tagsList = e.getElementsByTagName(tag);
1611 | var curTagsLength = tagsList.length;
1612 |
1613 | /**
1614 | * Gather counts for other typical elements embedded within.
1615 | * Traverse backwards so we can remove nodes at the same time without effecting the traversal.
1616 | *
1617 | * TODO: Consider taking into account original contentScore here.
1618 | **/
1619 | for (var i=curTagsLength-1; i >= 0; i-=1) {
1620 | var weight = readability.getClassWeight(tagsList[i]);
1621 | var contentScore = (typeof tagsList[i].readability !== 'undefined') ? tagsList[i].readability.contentScore : 0;
1622 |
1623 | dbg("Cleaning Conditionally " + tagsList[i] + " (" + tagsList[i].className + ":" + tagsList[i].id + ")" + ((typeof tagsList[i].readability !== 'undefined') ? (" with score " + tagsList[i].readability.contentScore) : ''));
1624 |
1625 | if(weight+contentScore < 0)
1626 | {
1627 | tagsList[i].parentNode.removeChild(tagsList[i]);
1628 | }
1629 | else if ( readability.getCharCount(tagsList[i],',') < 10) {
1630 | /**
1631 | * If there are not very many commas, and the number of
1632 | * non-paragraph elements is more than paragraphs or other ominous signs, remove the element.
1633 | **/
1634 | var p = tagsList[i].getElementsByTagName("p").length;
1635 | var img = tagsList[i].getElementsByTagName("img").length;
1636 | var li = tagsList[i].getElementsByTagName("li").length-100;
1637 | var input = tagsList[i].getElementsByTagName("input").length;
1638 |
1639 | var embedCount = 0;
1640 | var embeds = tagsList[i].getElementsByTagName("embed");
1641 | for(var ei=0,il=embeds.length; ei < il; ei+=1) {
1642 | if (embeds[ei].src.search(readability.regexps.videos) === -1) {
1643 | embedCount+=1;
1644 | }
1645 | }
1646 |
1647 | var linkDensity = readability.getLinkDensity(tagsList[i]);
1648 | var contentLength = readability.getInnerText(tagsList[i]).length;
1649 | var toRemove = false;
1650 |
1651 | if ( img > p ) {
1652 | toRemove = true;
1653 | } else if(li > p && tag !== "ul" && tag !== "ol") {
1654 | toRemove = true;
1655 | } else if( input > Math.floor(p/3) ) {
1656 | toRemove = true;
1657 | } else if(contentLength < 25 && (img === 0 || img > 2) ) {
1658 | toRemove = true;
1659 | } else if(weight < 25 && linkDensity > 0.2) {
1660 | toRemove = true;
1661 | } else if(weight >= 25 && linkDensity > 0.5) {
1662 | toRemove = true;
1663 | } else if((embedCount === 1 && contentLength < 75) || embedCount > 1) {
1664 | toRemove = true;
1665 | }
1666 |
1667 | if(toRemove) {
1668 | tagsList[i].parentNode.removeChild(tagsList[i]);
1669 | }
1670 | }
1671 | }
1672 | },
1673 |
1674 | /**
1675 | * Clean out spurious headers from an Element. Checks things like classnames and link density.
1676 | *
1677 | * @param Element
1678 | * @return void
1679 | **/
1680 | cleanHeaders: function (e) {
1681 | for (var headerIndex = 1; headerIndex < 3; headerIndex+=1) {
1682 | var headers = e.getElementsByTagName('h' + headerIndex);
1683 | for (var i=headers.length-1; i >=0; i-=1) {
1684 | if (readability.getClassWeight(headers[i]) < 0 || readability.getLinkDensity(headers[i]) > 0.33) {
1685 | headers[i].parentNode.removeChild(headers[i]);
1686 | }
1687 | }
1688 | }
1689 | },
1690 |
1691 | /*** Smooth scrolling logic ***/
1692 |
1693 | /**
1694 | * easeInOut animation algorithm - returns an integer that says how far to move at this point in the animation.
1695 | * Borrowed from jQuery's easing library.
1696 | * @return integer
1697 | **/
1698 | easeInOut: function(start,end,totalSteps,actualStep) {
1699 | var delta = end - start;
1700 |
1701 | if ((actualStep/=totalSteps/2) < 1) {
1702 | return delta/2*actualStep*actualStep + start;
1703 | }
1704 | actualStep -=1;
1705 | return -delta/2 * ((actualStep)*(actualStep-2) - 1) + start;
1706 | },
1707 |
1708 | /**
1709 | * Helper function to, in a cross compatible way, get or set the current scroll offset of the document.
1710 | * @return mixed integer on get, the result of window.scrollTo on set
1711 | **/
1712 | scrollTop: function(scroll){
1713 | var setScroll = typeof scroll !== 'undefined';
1714 |
1715 | if(setScroll) {
1716 | return window.scrollTo(0, scroll);
1717 | }
1718 | if(typeof window.pageYOffset !== 'undefined') {
1719 | return window.pageYOffset;
1720 | }
1721 | else if(document.documentElement.clientHeight) {
1722 | return document.documentElement.scrollTop;
1723 | }
1724 | else {
1725 | return document.body.scrollTop;
1726 | }
1727 | },
1728 |
1729 | /**
1730 | * scrollTo - Smooth scroll to the point of scrollEnd in the document.
1731 | * @return void
1732 | **/
1733 | curScrollStep: 0,
1734 | scrollTo: function (scrollStart, scrollEnd, steps, interval) {
1735 | if(
1736 | (scrollStart < scrollEnd && readability.scrollTop() < scrollEnd) ||
1737 | (scrollStart > scrollEnd && readability.scrollTop() > scrollEnd)
1738 | ) {
1739 | readability.curScrollStep+=1;
1740 | if(readability.curScrollStep > steps) {
1741 | return;
1742 | }
1743 |
1744 | var oldScrollTop = readability.scrollTop();
1745 |
1746 | readability.scrollTop(readability.easeInOut(scrollStart, scrollEnd, steps, readability.curScrollStep));
1747 |
1748 | // We're at the end of the window.
1749 | if(oldScrollTop === readability.scrollTop()) {
1750 | return;
1751 | }
1752 |
1753 | window.setTimeout(function() {
1754 | readability.scrollTo(scrollStart, scrollEnd, steps, interval);
1755 | }, interval);
1756 | }
1757 | },
1758 |
1759 |
1760 | /**
1761 | * Show the email popup.
1762 | *
1763 | * @return void
1764 | **/
1765 | emailBox: function () {
1766 | var emailContainerExists = document.getElementById('email-container');
1767 | if(null !== emailContainerExists)
1768 | {
1769 | return;
1770 | }
1771 |
1772 | var emailContainer = document.createElement("DIV");
1773 | emailContainer.setAttribute('id', 'email-container');
1774 | emailContainer.innerHTML = '';
1775 |
1776 | document.body.appendChild(emailContainer);
1777 | },
1778 |
1779 | /**
1780 | * Close the email popup. This is a hacktackular way to check if we're in a "close loop".
1781 | * Since we don't have crossdomain access to the frame, we can only know when it has
1782 | * loaded again. If it's loaded over 3 times, we know to close the frame.
1783 | *
1784 | * @return void
1785 | **/
1786 | removeFrame: function () {
1787 | readability.iframeLoads+=1;
1788 | if (readability.iframeLoads > 3)
1789 | {
1790 | var emailContainer = document.getElementById('email-container');
1791 | if (null !== emailContainer) {
1792 | emailContainer.parentNode.removeChild(emailContainer);
1793 | }
1794 |
1795 | readability.iframeLoads = 0;
1796 | }
1797 | },
1798 |
1799 | htmlspecialchars: function (s) {
1800 | if (typeof(s) === "string") {
1801 | s = s.replace(/&/g, "&");
1802 | s = s.replace(/"/g, """);
1803 | s = s.replace(/'/g, "'");
1804 | s = s.replace(//g, ">");
1806 | }
1807 |
1808 | return s;
1809 | },
1810 |
1811 | flagIsActive: function(flag) {
1812 | return (readability.flags & flag) > 0;
1813 | },
1814 |
1815 | addFlag: function(flag) {
1816 | readability.flags = readability.flags | flag;
1817 | },
1818 |
1819 | removeFlag: function(flag) {
1820 | readability.flags = readability.flags & ~flag;
1821 | }
1822 |
1823 | };
1824 |
1825 | readability.init();
1826 |
--------------------------------------------------------------------------------
/readability/readability-print.css:
--------------------------------------------------------------------------------
1 | body, #readOverlay {
2 | background-color: white !important;
3 | }
4 |
5 | embed, object {
6 | display: none !important;
7 | }
8 |
9 | /*#readInner {
10 | width: 100% !important;
11 | }
12 | */
13 | #readInner.margin-x-narrow {width:100% !important;}
14 | #readInner.margin-narrow {width:91% !important;}
15 | #readInner.margin-medium {width:84% !important;}
16 | #readInner.margin-wide {width:77% !important;}
17 | #readInner.margin-x-wide {width:70% !important;}
18 |
19 | #readTools {
20 | display: none !important;
21 | }
22 |
23 | #readFooter {
24 | font-size: .85em;
25 | text-align: left !important;
26 | }
27 |
28 | #readFooter a {
29 | border-bottom-width: 0 !important;
30 | }
31 |
32 | #readability-url {
33 | display: inline !important;
34 | }
35 |
36 | #rdb-footer-print {
37 | display: block !important;
38 | font-size: .85em;
39 | text-align: right;
40 | margin-bottom: 1.5em;
41 | }
42 |
43 | #rdb-footer-print span {
44 | white-space: ;
45 | }
46 |
47 | #rdb-footer-left {
48 | width: auto !important;
49 | display: block !important;
50 | float: none !important;
51 | font-family: "Adobe Caslon Pro", "Hoefler Text", Georgia, Garamond, serif;
52 | }
53 |
54 | #rdb-footer-right {
55 | display: none !important;
56 | }
57 |
58 | #readFooter #arc90-logo, #readFooter #readability-logo {
59 | background-image: none !important;
60 | text-indent: 0 !important;
61 | width: auto !important;
62 | height: auto !important;
63 | line-height: auto !important;
64 | margin: 0 !important;
65 | text-align: left;
66 | }
67 |
68 | #readFooter #readability-logo {
69 | color: #333 !important;
70 | font-variant: small-caps;
71 | }
72 |
73 | #footer-twitterLink {
74 | display: none;
75 | }
76 |
77 | #readFooter span.version {
78 | display: none;
79 | }
80 |
81 | a {
82 | color: #333 !important;
83 | border-bottom: 1px solid #CCC !important;
84 | }
85 |
86 | div.footer-right {
87 | display: none;
88 | }
89 |
--------------------------------------------------------------------------------
/readability/readability.css:
--------------------------------------------------------------------------------
1 | @charset "utf-8";
2 | /* Document */
3 | body{font-size:10px;line-height:1;}
4 | #readability-logo,#arc90-logo,.footer-twitterLink,#readTools a,a.rdbTK-powered span{background-color:transparent!important;background-image:url(http://lab.arc90.com/experiments/readability/images/sprite-readability.png)!important;background-repeat:no-repeat!important;}
5 | #readOverlay{text-rendering:optimizeLegibility;display:block;position:absolute;top:0;left:0;width:100%;}
6 | #readInner{max-width:800px;margin:1em auto;}
7 | #readInner a{color:#039;text-decoration:none;}
8 | #readInner a:hover,#readInner a:focus{text-decoration:underline;}
9 | #readInner img{float:left;clear:both;margin:0 12px 12px 0;}
10 | #readInner img.blockImage{clear:both;float:none;display:block;margin-left:auto;margin-right:auto;}
11 | #readInner h1{display:block;width:100%;border-bottom:1px solid #333;font-size:1.2em;padding-bottom:.5em;margin-bottom:.75em;}
12 | #readInner sup{line-height:.8em;}
13 | #readInner .page-separator{clear:both;display:block;font-size:.85em;filter:alpha(opacity=20);opacity:.20;text-align:center;}
14 | .style-apertura #readInner h1{border-bottom-color:#ededed;}
15 | .style-terminal #readInner h1{border-bottom-color:#c6ffc6;}
16 | #readInner blockquote{margin-left:3em;margin-right:3em;}
17 | #readability-inner *{margin-bottom:16px;border:none;background:none;}
18 | #readability-footnotes{clear:both;}
19 | /* Footer */
20 | #rdb-footer-wrapper{display:block;border-top:1px solid #333;clear:both;overflow:hidden;margin:2em 0;}
21 | .style-apertura #rdb-footer-wrapper{border-top-color:#ededed;}
22 | .style-terminal #rdb-footer-wrapper{border-top-color:#c6ffc6;}
23 | #rdb-footer-left{display:inline;float:left;margin-top:15px;width:285px;background-position:0 -36px;}
24 | .rdbTypekit #rdb-footer-left{width:475px;}
25 | #rdb-footer-left a,#rdb-footer-left a:link{float:left;}
26 | #readability-logo{display:inline;background-position:0 -36px;height:29px;width:189px;text-indent:-9000px;}
27 | #arc90-logo{display:inline;background-position:right -36px;height:29px;width:96px;text-indent:-9000px;}
28 | .style-apertura #readability-logo,.style-terminal #readability-logo{background-position:0 -67px;}
29 | .style-apertura #arc90-logo,.style-terminal #arc90-logo{background-position:right -67px;}
30 | #rdb-footer-right{display:inline;float:right;text-align:right;font-size:.75em;margin-top:18px;}
31 | #rdb-footer-right a{display:inline-block;float:left;overflow:visible;line-height:16px;vertical-align:baseline;}
32 | .footer-twitterLink{height:20px;margin-left:20px;background-position:0 -123px;font-size:12px;padding:4px 0 0 28px;}
33 | #rdb-footer-left .footer-twitterLink{display:none;margin-top:1px;padding-top:2px;}
34 | .rdbTypekit #rdb-footer-left .footer-twitterLink{display:inline-block!important;}
35 | a.rdbTK-powered,a.rdbTK-powered:link,a.rdbTK-powered:hover{font-size:16px;color:#858789!important;text-decoration:none!important;}
36 | a.rdbTK-powered span{display:inline-block;height:22px;margin-left:2px;background-position:0 -146px!important;padding:4px 0 0 26px;}
37 | .style-apertura #rdb-inverse,.style-athelas #rdb-athelas{display:block;}
38 | #rdb-footer-print,#readability-url,.rdbTypekit #rdb-footer-right .footer-twitterLink,span.version{display:none;}
39 | /* Tools */
40 | #readTools{width:34px;height:150px;position:fixed;z-index:100;top:10px;left:10px;}
41 | #readTools a{overflow:hidden;margin-bottom:8px;display:block;opacity:.4;text-indent:-99999px;height:34px;width:34px;text-decoration:none;filter:alpha(opacity=40);}
42 | #reload-page{background-position:0 0;}
43 | #print-page{background-position:-36px 0;}
44 | #email-page{background-position:-72px 0;}
45 | #kindle-page{background-position:-108px 0;}
46 | #readTools a:hover,#readTools a:focus{opacity:1;filter:alpha(opacity=100);}
47 | /* @group User Styles */
48 | /* Size */
49 | .size-x-small{font-size:1.1em;line-height:1.5em;}
50 | .size-small{font-size:1.4em;line-height:1.5em;}
51 | .size-medium{font-size:1.7em;line-height:1.48em;}
52 | .size-large{font-size:2em;line-height:1.47em;}
53 | .size-x-large{font-size:2.5em;line-height:1.43em;}
54 | .size-x-small h1,.size-small h1,.size-medium h1,.size-large h1{font-size:1.6em;line-height:1.5em;}
55 | .size-x-large h1{font-size:1.6em;line-height:1.3em;}
56 | /* Style */
57 | .style-newspaper {font-family:Georgia,"Times New Roman", Times, serif;background:#fbfbfb;color:#080000;}
58 | .style-newspaper h1 {text-transform:capitalize;font-family:Georgia, "Times New Roman", Times, serif;}
59 | .style-newspaper #readInner a {color:#0924e1;}
60 | .style-novel {font-family:"Palatino Linotype", "Book Antiqua", Palatino, serif;background:#f4eed9;color:#1d1916;}
61 | .style-novel #readInner a {color:#1856ba;}
62 | .style-ebook {font-family:Arial, Helvetica, sans-serif;background:#edebe8;color:#2c2d32;}
63 | .style-ebook #readInner a {color:#187dc9;}
64 | .style-ebook h1 {font-family:"Arial Black", Gadget, sans-serif;font-weight:400;}
65 | .style-terminal {font-family:"Lucida Console", Monaco, monospace;background:#1d4e2c;color:#c6ffc6;}
66 | .style-terminal #readInner a {color:#093;}
67 | /* Typekit */
68 | .style-apertura{font-family:apertura-1,apertura-2,sans-serif;background-color:#2d2828;color:#eae8e9;}
69 | .style-apertura #readInner a{color:#58b0ff;}
70 | .style-athelas{font-family:athelas-1,athelas-2,"Palatino Linotype","Book Antiqua",Palatino,serif;background-color:#f7f7f7;color:#2b373d;}
71 | .style-athelas #readInner a{color:#1e83cb;}
72 | /* Margin */
73 | .margin-x-narrow{width:95%;}
74 | .margin-narrow{width:85%;}
75 | .margin-medium{width:75%;}
76 | .margin-wide{width:55%;}
77 | .margin-x-wide{width:35%;}
78 | /* @end User Styles */
79 | /* -- DEBUG -- */
80 | .bug-green{background:#bbf9b0;border:4px solid green;}
81 | .bug-red{background:red;}
82 | .bug-yellow{background:#ffff8e;}
83 | .bug-blue{background:#bfdfff;}
84 | /* -- EMAIL / KINDLE POP UP -- */
85 | #kindle-container,#email-container{position:fixed;top:60px;left:50%;width:500px;height:490px;border:solid 3px #666;background-color:#fff;z-index:100!important;overflow:hidden;margin:0 0 0 -240px;padding:0;}
86 | /* Override html styling attributes */
87 | table,tr,td{background-color:transparent!important;}
88 |
--------------------------------------------------------------------------------
/readability/readability.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/readability.png
--------------------------------------------------------------------------------
/readability/title-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/title-small.png
--------------------------------------------------------------------------------
/readability/title.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/title.png
--------------------------------------------------------------------------------
/readability/twitter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/twitter.png
--------------------------------------------------------------------------------
/readability/typekit-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MHordecki/readability-redux/0ac367b6def41f1e841282790ceb80989ac3b404/readability/typekit-icon.png
--------------------------------------------------------------------------------
/redux/background.html:
--------------------------------------------------------------------------------
1 |
2 |
29 | | The Evil Clergyman 30 | by |
31 | 32 | |
37 | |
I was shown into the attic chamber by a grave, intelligent-looking man with quiet clothes and an iron-gray beard, who spoke to me in this fashion:
42 |"Yes, he lived here – but I don’t advise your doing anything. Your curiosity makes you irresponsible. We never come here at night, and it’s only because of his will that we keep it this way. You know what he did. That abominable society took charge at last, and we don’t know where he is buried. There was no way the law or anything else could reach the society.
43 |"I hope you won’t stay till after dark. And I beg of you to let that thing on the table – the thing that looks like a match-box – alone. We don’t know what it is, but we suspect it has something to do with what he did. We even avoid looking at it very steadily."
44 |After a time the man left me alone in the attic room. It was very dingy and dusty, and only primitively furnished, but it had a neatness which showed it was not a slum-denizen’s quarters. There were shelves full of theological and classical books, and another bookcase containing treatises on magic — Paracelsus, Albertus Magnus, Trithemius, Hermes Trismegistus, Borellus, and others in a strange alphabet whose titles I could not decipher. The furniture was very plain. There was a door, but it led only into a closet. The only egress was the aperture in the floor up to which the crude, steep staircase led. The windows were of bull’s-eye pattern, and the black oak beams bespoke unbelievable antiquity. Plainly, this house was of the Old World. I seemed to know where I was, but cannot recall what I then knew. Certainly the town was not London. My impression is of a small seaport.
45 |The small object on the table fascinated me intensely. I seemed to know what to do with it, for I drew a pocket electric light – or what looked like one – out of my pocket and nervously tested its flashes. The light was not white but violet, and seemed less like true light than like some radioactive bombardment. I recall that I did not regard it as a common flashlight – indeed, I had a common flashlight in another pocket.
46 |It was getting dark, and the ancient roofs and chimney-pots outside looked very queer through the bull's-eye window-panes. Finally I summoned up courage and propped the small object up on the table against a book – then turned the rays of the peculiar violet light upon it. The light seemed now to be more like a rain of hail or small violet particles than like a continuous beam. As the particles struck the glassy surface at the center of the strange device, they seemed to produce a crackling noise like the sputtering of a vacuum tube through which sparks are passed. The dark glassy surface displayed a pinkish glow, and a vague white shape seemed to be taking form at its center. Then I noticed that I was not alone in the room – and put the ray-projector back in my pocket.
47 |But the newcomer did not speak – nor did I hear any sound whatever during all the immediately following moments. Everything was shadowy pantomime, as if seen at a vast distance through some intervening haze – although on the other hand the newcomer and all subsequent comers loomed large and close, as if both near and distant, according to some abnormal geometry.
48 |The newcomer was a thin, dark man of medium height attired in the clerical garb of the Anglican church. He was apparently about thirty years old, with a sallow, olive complexion and fairly good features, but an abnormally high forehead. His black hair was well cut and neatly brushed, and he was clean-shaven though blue-chinned with a heavy growth of beard. He wore rimless spectacles with steel bows. His build and lower facial features were like other clergymen I had seen, but he had a vastly higher forehead, and was darker and more intelligent-looking – also more subtly and concealedly evil-looking. At the present moment – having just lighted a faint oil lamp – he looked nervous, and before I knew it he was casting all his magical books into a fireplace on the window side of the room (where the wall slanted sharply) which I had not noticed before. The flames devoured the volumes greedily – leaping up in strange colors and emitting indescribably hideous odors as the strangely hieroglyphed leaves and wormy bindings succumbed to the devastating element. All at once I saw there were others in the room – grave-looking men in clerical costume, one of whom wore the bands and knee-breeches of a bishop. Though I could hear nothing, I could see that they were bringing a decision of vast import to the first-comer. They seemed to hate and fear him at the same time, and he seemed to return these sentiments. His face set itself into a grim expression, but I could see his right hand shaking as he tried to grip the back of a chair. The bishop pointed to the empty case and to the fireplace (where the flames had died down amidst a charred, non-committal mass), and seemed filled with a peculiar loathing. The first-comer then gave a wry smile and reached out with his left hand toward the small object on the table. Everyone then seemed frightened. The procession of clerics began filing down the steep stairs through the trapdoor in the floor, turning and making menacing gestures as they left. The bishop was last to go.
49 |The first-comer now went to a cupboard on the inner side of the room and extracted a coil of rope. Mounting a chair, he attached one end of the rope to a hook in the great exposed central beam of black oak, and began making a noose with the other end. Realizing he was about to hang himself, I started forward to dissuade or save him. He saw me and ceased his preparations, looking at me with a kind of triumph which puzzled and disturbed me. He slowly stepped down from the chair and began gliding toward me with a positively wolfish grin on his dark, thin-lipped face.
50 |I felt somehow in deadly peril, and drew out the peculiar ray-projector as a weapon of defense. Why I thought it could help me, I do not know. I turned it on – full in his face, and saw the sallow features glow first with violet and then with pinkish light. His expression of wolfish exultation began to be crowded aside by a look of profound fear – which did not, however, wholly displace the exultation. He stopped in his tracks – then, flailing his arms wildly in the air, began to stagger backwards. I saw he was edging toward the open stair-well in the floor, and tried to shout a warning, but he did not hear me. In another instant he had lurched backward through the opening and was lost to view.
51 |I found difficulty in moving toward the stair-well, but when I did get there I found no crushed body on the floor below. Instead there was a clatter of people coming up with lanterns, for the spell of phantasmal silence had broken, and I once more heard sounds and saw figures as normally tri-dimensional. Something had evidently drawn a crowd to this place. Had there been a noise I had not heard?
52 |Presently the two people (simple villagers, apparently) farthest in the lead saw me – and stood paralyzed. One of them shrieked loudly and reverberantly:
53 |"Ahrrh! ... It be’ee, zur? Again?"
54 |Then they all turned and fled frantically. All, that is, but one. When the crowd was gone I saw the grave-bearded man who had brought me to this place – standing alone with a lantern. He was gazing at me gaspingly and fascinatedly, but did not seem afraid. Then he began to ascend the stairs, and joined me in the attic. He spoke:
55 |"So you didn’t let it alone! I’m sorry. I know what has happened. It happened once before, but the man got frightened and shot himself. You ought not to have made him come back. You know what he wants. But you mustn’t get frightened like the other man he got. Something very strange and terrible has happened to you, but it didn’t get far enough to hurt your mind and personality. If you’ll keep cool, and accept the need for making certain radical readjustments in your life, you can keep right on enjoying the world, and the fruits of your scholarship. But you can’t live here – and I don’t think you’ll wish to go back to London. I’d advise America.
56 |"You mustn’t try anything more with that— thing. Nothing can be put back now. It would only make matters worse to do – or summon – anything. You are not as badly off as you might be – but you must get out of here at once and stay away. You’d better thank Heaven it didn’t go further...
57 |"I’m going to prepare you as bluntly as I can. There’s been a certain change – in your personal appearance. He always causes that. But in a new country you can get used to it. There’s a mirror up at the other end of the room, and I’m going to take you to it. You’ll get a shock – though you will see nothing repulsive."
58 |I was now shaking with a deadly fear, and the bearded man almost had to hold me up as he walked me across the room to the mirror, the faint lamp (i.e., that formerly on the table, not the still fainter lantern he had brought) in his free hand. This is what I saw in the glass:
59 |A thin, dark man of medium stature attired in the clerical garb of the Anglican church, apparently about thirty, and with rimless, steel-bowed glasses glistening beneath a sallow, olive forehead of abnormal height.
60 |It was the silent first-comer who had burned his books.
61 |For all the rest of my life, in outward form, I was to be that man!
62 |=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()}, 80 | CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m, 81 | g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)}, 82 | text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}}, 83 | setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return hl[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h= 84 | h[3];l=0;for(m=h.length;l =0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m=== 86 | "="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g, 87 | h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l ";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&& 90 | q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML=""; 91 | if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}(); 92 | (function(){var g=s.createElement("div");g.innerHTML="";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}: 93 | function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q =0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f
0)for(var j=d;j 0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j= 96 | {},i;if(f&&a.length){e=0;for(var o=a.length;e -1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a=== 97 | "string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode", 98 | d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")? 99 | a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType=== 100 | 1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/"+d+">"},F={option:[1,""],legend:[1,""],thead:[1," ","
"],tr:[2,"","
"],td:[3,""],col:[2,"
"," "],area:[1,""],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div
"," ",""];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= 102 | c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, 103 | wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, 104 | prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, 105 | this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); 106 | return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja, 107 | ""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]); 111 | return this}else{e=0;for(var j=d.length;e 0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["", 112 | ""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]===" "&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e= 113 | c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]? 114 | c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja= 115 | function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter= 116 | Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a, 117 | "border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f= 118 | a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b= 119 | a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/ 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 |Readability Redux
Options15 | 16 |You can see the preview below.
17 |18 | 19 | 20 | (Inverse and Athelas use online fonts)
46 | 47 |
27 | 28 | 29 |
36 | 37 | 38 | 45 |48 | 49 | 50 |
51 | 52 |53 | 54 | 55 | 56 |
57 | 58 |59 | 60 | 61 |
62 | 63 |64 | 65 | 66 |
67 | 68 |Preview69 |70 | 71 |72 | 73 |Credits74 | 75 |76 | Readability created by
79 |
77 |78 |
80 | Readability Redux created by Mike Hordecki. 81 |
82 |Readability-experimental by IIsi 50Mhz.
83 | 84 | 85 |