WikiIndent

Four visual improvements for Wikipedia (and other wikis): Indents sub-sections to make the layout clearer. Hides the sidebar (toggle by clicking the header). Floats the Table of Contents for access when scrolled. Converts heading underlines to overlines.

  1. // ==UserScript==
  2. // @name WikiIndent
  3. // @namespace joeytwiddle
  4. // @description Four visual improvements for Wikipedia (and other wikis): Indents sub-sections to make the layout clearer. Hides the sidebar (toggle by clicking the header). Floats the Table of Contents for access when scrolled. Converts heading underlines to overlines.
  5. // @downstreamURL http://userscripts.org/scripts/source/60832.user.js
  6. // @version 1.3.5
  7. // @include *wiki*
  8. // @include http://www.buzztard.com/*
  9. // @include http://encyclopediadramatica.com/*
  10. // @include http://www.wormus.com/leakytap/*
  11. // @include http://theinfosphere.org/*
  12. // @include http://rosettacode.org/mw/*
  13. // @grant GM_setValue
  14. // @grant GM_addStyle
  15. // @grant GM_getValue
  16. // @grant GM_log
  17. // ==/UserScript==
  18.  
  19. // Without this function wrapper, Mozilla Firefox rejects the whole script, because it sees the top-level 'return;' as invalid syntax!
  20.  
  21. (function(){
  22.  
  23. // Feature #1 : Make the sidebar collapsible so the page content can fill the whole width.
  24.  
  25. var toggleSidebar = true;
  26.  
  27. // Feature #2 : Float the TOC on the top-right of the screen, so it can still be used after scrolling down the page.
  28.  
  29. var makeTableOfContentsFloat = true;
  30.  
  31. // Feature #3 : Indent the blocks so their tree-like structure is visible.
  32.  
  33. var indentSubBlocks = true;
  34.  
  35. // Feature #4 : Change underlined headings to overlined headings. (So the lines separate the heading from the previous section, rather than separating the heading from its content.)
  36.  
  37. var fixUnderlinesToOverlines = true;
  38.  
  39.  
  40.  
  41. // var minimisedSidebarSize = 6; // Small
  42. var minimisedSidebarSize = 16;
  43.  
  44. // When opening the sidebar again, the transition displays the sidebar contents
  45. // before there is space for it, causing brief ugly overlap! So we delay
  46. // unhiding to look prettier.
  47. // CONSIDER: Perhaps this could look even smoother if the text appeared/disappeared using opacity.
  48. var delayHide = 0;
  49. var delayUnhide = ( document.getElementById("mw-panel") ? 250 : 0 );
  50.  
  51. var debug = false;
  52.  
  53.  
  54.  
  55. /* CONSIDER: As we scroll the page, light up the "current" section in the TOC.
  56. *
  57. * FIXED: One occasional problem with the TOC is when it is taller than the
  58. * window! (I usually work around this by zooming out (reducing font
  59. * size), but perhaps we can use CSS overflow to solve it properly.)
  60. *
  61. * TODO: Indentation was not working well in edit preview on Hwiki(MW).
  62. */
  63.  
  64. /* Changelog
  65. * 5/ 2/2012 - Better (though more fragile) click-to-toggle areas.
  66. * 3/ 1/2012 - Fixed Chrome compatibility so it works! Doh.
  67. * 23/ 3/2011 - Added Chrome compatibility.
  68. */
  69.  
  70. // Recent versions do not play nice together, so just in case we run WI twice:
  71. if (unsafeWindow.WikiIndent_loaded) {
  72. return;
  73. } else {
  74. unsafeWindow.WikiIndent_loaded = true;
  75. }
  76.  
  77. function log(x) {
  78. x = "[WI] "+x;
  79. if (this.GM_log) {
  80. this.GM_log(x);
  81. } else if (this.console && console.log) {
  82. console.log(x);
  83. } else {
  84. window.status = ""+x;
  85. // alert(x);
  86. }
  87. }
  88.  
  89. // For bookmarklets:
  90. if (typeof GM_addStyle == "undefined") {
  91. GM_addStyle = function(css) {
  92. var head, style;
  93. head = document.getElementsByTagName("head")[0];
  94. if (!head) { return; }
  95. style = document.createElement("style");
  96. style.type = "text/css";
  97. style.innerHTML = css;
  98. head.appendChild(style);
  99. };
  100. }
  101.  
  102. if (typeof GM_setValue == 'undefined' || window.navigator.vendor.match(/Google/)) {
  103. GM_log("WikiIndent: Adding fallback implementation of GM_set/getValue");
  104.  
  105. if (typeof localStorage == 'undefined') {
  106.  
  107. GM_getValue = function(name, defaultValue) {
  108. return defaultValue;
  109. };
  110.  
  111. } else {
  112.  
  113. GM_setValue = function(name, value) {
  114. value = (typeof value)[0] + value;
  115. localStorage.setItem(name, value);
  116. };
  117.  
  118. GM_getValue = function(name, defaultValue) {
  119. var value = localStorage.getItem(name);
  120. if (!value)
  121. return defaultValue;
  122. var type = value[0];
  123. value = value.substring(1);
  124. switch (type) {
  125. case 'b':
  126. return value == 'true';
  127. case 'n':
  128. return Number(value);
  129. default:
  130. return value;
  131. }
  132. };
  133.  
  134. }
  135.  
  136. }
  137.  
  138.  
  139.  
  140. // The following block is mirrored in table_of_contents_everyw.user.js
  141.  
  142. // See also: resetProps
  143. function clearStyle(elem) {
  144. // We set some crucial defaults, so we don't inherit CSS from the page:
  145. elem.style.display = 'inline';
  146. elem.style.position = 'static';
  147. elem.style.top = 'auto';
  148. elem.style.right = 'auto';
  149. elem.style.bottom = 'auto';
  150. elem.style.left = 'auto';
  151. //elem.style.color = 'black';
  152. //elem.style.backgroundColor = 'white';
  153. return elem;
  154. }
  155.  
  156. function newNode(tag,data) {
  157. var elem = document.createElement(tag);
  158. if (data) {
  159. for (var prop in data) {
  160. elem[prop] = data[prop];
  161. }
  162. }
  163. return elem;
  164. }
  165.  
  166. function newSpan(text) {
  167. return clearStyle(newNode("span",{textContent:text}));
  168. }
  169.  
  170. /*
  171. function addCloseButtonTo(where, toc) {
  172. var closeButton = newSpan("[X]");
  173. // closeButton.style.float = 'right';
  174. // closeButton.style.cssFloat = 'right'; // Firefox
  175. // closeButton.style.styleFloat = 'right'; // IE7
  176. closeButton.style.cursor = 'pointer';
  177. closeButton.style.paddingLeft = '5px';
  178. closeButton.onclick = function() { toc.parentNode.removeChild(toc); };
  179. closeButton.id = "closeTOC";
  180. where.appendChild(closeButton);
  181. }
  182. */
  183.  
  184. function addCloseButtonTo(where, toc) {
  185. var closeSpan = newNode("span");
  186. var closeLink = newNode("a",{textContent:"close"});
  187. closeLink.onclick = function() { toc.parentNode.removeChild(toc); };
  188. closeLink.id = "closeTOC";
  189. closeLink.style.cursor = 'pointer';
  190. closeSpan.appendChild(document.createTextNode("["));
  191. closeSpan.appendChild(closeLink);
  192. closeSpan.appendChild(document.createTextNode("]"));
  193. //closeSpan.style.paddingLeft = '5px';
  194. where.appendChild(closeSpan);
  195. }
  196.  
  197. function addHideButtonTo(where, tocInner) {
  198. var rollupSpan = newNode("span");
  199. var rollupLink = newNode("a",{textContent:"hide"});
  200. rollupLink.onclick = toggleRollUp;
  201. rollupLink.id = "togglelink";
  202. rollupLink.className = "togglelink";
  203. rollupLink.style.cursor = 'pointer';
  204. rollupSpan.style.paddingLeft = '5px';
  205. rollupSpan.style.paddingRight = '5px';
  206. function toggleRollUp() {
  207. if (tocInner.style.display == 'none') {
  208. tocInner.style.display = '';
  209. rollupLink.textContent = "hide";
  210. } else {
  211. tocInner.style.display = 'none';
  212. rollupLink.textContent = "show";
  213. }
  214. setTimeout(function(){
  215. GM_setValue("WI_toc_rolledUp", tocInner.style.display=='none');
  216. },5);
  217. }
  218. rollupSpan.appendChild(document.createTextNode("["));
  219. rollupSpan.appendChild(rollupLink);
  220. rollupSpan.appendChild(document.createTextNode("]"));
  221. where.appendChild(rollupSpan);
  222. if (GM_getValue("WI_toc_rolledUp",false)) {
  223. toggleRollUp();
  224. }
  225. }
  226.  
  227. function addButtonsConditionally(toc) {
  228.  
  229. function verbosely(fn) {
  230. return function() {
  231. // GM_log("[WI] Calling: "+fn+" with ",arguments);
  232. return fn.apply(this,arguments);
  233. };
  234. };
  235.  
  236. // Provide a hide/show toggle button if the TOC does not already have one.
  237.  
  238. // Wikimedia's toc element is actually a table. We must put the
  239. // buttons in the title div, if we can find it!
  240.  
  241. var tocTitle = document.getElementById("toctitle"); // Wikipedia
  242. tocTitle = tocTitle || toc.getElementsByTagName("h2")[0]; // Mozdev
  243. // tocTitle = tocTitle || toc.getElementsByTagName("div")[0]; // Fingers crossed for general
  244. tocTitle = tocTitle || toc.firstChild; // Fingers crossed for general
  245.  
  246. // Sometimes Wikimedia does not add a hide/show button (if the TOC is small).
  247. // We cannot test this immediately, because it gets loaded in later!
  248. function addButtonsNow() {
  249. var hideShowButton = document.getElementById("togglelink") || toc.getElementsByClassName("togglelink")[0];
  250. if (!hideShowButton) {
  251. var tocInner = toc.getElementsByTagName("ol")[0]; // Mozdev (can't get them all!)
  252. tocInner = tocInner || toc.getElementsByTagName("ul")[0]; // Wikipedia
  253. tocInner = tocInner || toc.getElementsByTagName("div")[0]; // Our own
  254. if (tocInner) {
  255. verbosely(addHideButtonTo)(tocTitle || toc, tocInner);
  256. }
  257. }
  258.  
  259. // We do this later, to ensure it appears on the right of
  260. // any existing [hide/show] button.
  261. if (document.getElementById("closeTOC") == null) {
  262. verbosely(addCloseButtonTo)(tocTitle || toc, toc);
  263. }
  264. }
  265.  
  266. // Sometimes Wikimedia does not add a hide/show button (if the TOC is small).
  267. // We cannot test this immediately, because it gets loaded in later!
  268. if (document.location.href.indexOf("wiki") >= 0) {
  269. setTimeout(addButtonsNow,2000);
  270. } else {
  271. addButtonsNow();
  272. }
  273.  
  274. }
  275.  
  276. // End mirror.
  277.  
  278.  
  279.  
  280. // == Main == //
  281.  
  282. function doIt() {
  283.  
  284.  
  285.  
  286. //// Feature #1 : Hide the sidebar. Fullsize the content.
  287.  
  288. // Toggle the sidebar by clicking the "page background" (empty space outside
  289. // the main content). Sometimes clicking the content background is enough.
  290.  
  291. if (toggleSidebar) {
  292.  
  293. var content = document.getElementById("content")
  294. || document.getElementById("column-content");
  295. var sideBar = document.getElementById("column-one")
  296. || document.getElementById("panel")
  297. || /* WikiMedia: */ document.getElementById("mw-panel")
  298. || /* forgot: */ document.getElementById("jq-interiorNavigation")
  299. || /* pmwiki: */ document.getElementById('wikileft');
  300. var toToggle = [ document.getElementById("page-base"), document.getElementById("siteNotice"), document.getElementById("head") ];
  301. var cac = document.getElementById("p-cactions");
  302. var cacOldHome = ( cac ? cac.parentNode : null );
  303.  
  304. function toggleWikipediaSidebar(evt) {
  305.  
  306. // We don't want to act on all clicked body elements (notably not the WP
  307. // image). I detected two types of tag we wanted to click.
  308. /*if (!evt || evt.target.tagName == "UL" || evt.target.tagName == "DIV") {*/
  309.  
  310. // That was still activating on divs in the content! (Gaps between paragraphs.)
  311. // This only acts on the header area.
  312. var thisElementTogglesSidebar;
  313. var inStartup = (evt == null);
  314. if (inStartup) {
  315. thisElementTogglesSidebar = true;
  316. } else {
  317. var elem = evt.target;
  318. var clickedHeader = (elem.id == 'mw-head');
  319. // For wikia.com:
  320. clickedHeader |= (elem.id=="WikiHeader");
  321. // For Wikimedia:
  322. var clickedPanelBackground = elem.id == 'mw-panel' || elem.className.indexOf('portal')>=0;
  323. clickedPanelBackground |= elem.id == 'column-content'; // for beebwiki (old mediawiki?)
  324. // Hopefully for sites in general. Allow one level below body. Needed for Wikia's UL.
  325. var clickedAreaBelowSidebar = (elem.tagName == 'HTML' || elem.tagName == 'BODY');
  326. var clickedBackground = (elem.parentNode && elem.parentNode.tagName == "BODY");
  327. thisElementTogglesSidebar = clickedHeader || clickedPanelBackground || clickedAreaBelowSidebar || clickedBackground;
  328. }
  329. if (thisElementTogglesSidebar) {
  330.  
  331. if (evt)
  332. evt.preventDefault();
  333. if (debug) { GM_log("evt=",evt); }
  334. // if (evt) GM_log("evt.target.tagName="+evt.target.tagName);
  335. /* We put the GM_setValue calls on timers, so they won't slow down the rendering. */
  336. // Make the change animate smoothly:
  337. content.style.transition = 'all 150ms ease-in-out';
  338. if (sideBar) {
  339. if (sideBar.style.display == '') {
  340. // Wikipedia's column-one contains a lot of things we want to hide
  341. sideBar.style.display = 'none';
  342. if (content) {
  343. content.oldMarginLeft = content.style.marginLeft;
  344. content.style.marginLeft = minimisedSidebarSize+'px';
  345. }
  346. for (var i in toToggle) {
  347. if (toToggle[i]) { toToggle[i].style.display = 'none'; }
  348. }
  349. // but one of them we want to preserve
  350. // (the row of tools across the top):
  351. if (cac)
  352. sideBar.parentNode.insertBefore(cac,sideBar.nextSibling);
  353. setTimeout(function(){
  354. GM_setValue("sidebarVisible",false);
  355. },200);
  356. } else {
  357. function unhide() {
  358. sideBar.style.display = '';
  359. }
  360. setTimeout(unhide,delayUnhide);
  361. if (content) {
  362. content.style.marginLeft = content.oldMarginLeft;
  363. }
  364. for (var i in toToggle) {
  365. if (toToggle[i]) { toToggle[i].style.display = ''; }
  366. }
  367. if (cac && cacOldHome)
  368. cacOldHome.appendChild(cac); // almost back where it was :P
  369. setTimeout(function(){
  370. GM_setValue("sidebarVisible",true);
  371. },200);
  372. }
  373. }
  374.  
  375. }
  376. }
  377.  
  378. // log("sideBar="+sideBar+" and content="+content);
  379. if (sideBar) {
  380. // We need to watch window for clicks below sidebar (Chrome).
  381. document.documentElement.addEventListener('click',toggleWikipediaSidebar,false);
  382. } else {
  383. log("Did not have sideBar "+sideBar+" or content "+content); // @todo Better to warn or error?
  384. }
  385.  
  386. if (!GM_getValue("sidebarVisible",true)) {
  387. toggleWikipediaSidebar();
  388. }
  389.  
  390. // TODO: Make a toggle button for it!
  391.  
  392. // Fix for docs.jquery.com:
  393. /*
  394. var j = document.getElementById("jq-primaryContent");
  395. if (j) {
  396. j.style.setAttribute('display', 'block');
  397. j.style.setAttribute('float', 'none');
  398. j.style.setAttribute('width', '100%');
  399. }
  400. */
  401. GM_addStyle("#jq-primaryContent { display: block; float: none; width: 100%; }");
  402.  
  403. }
  404.  
  405.  
  406.  
  407. //// Feature #2: Make Table of Contents float
  408.  
  409. if (makeTableOfContentsFloat) {
  410.  
  411. /* @consider If the TOC has a "Hide/Show" link ("button") then we could
  412. * fire that instead of changing opacity.
  413. */
  414.  
  415. // document.getElementById('column-one').appendChild(document.getElementById('toc'));
  416.  
  417. // createFader basically worked but was a little bit buggy. (Unless the bugs were caused by conflict with other TOC script.)
  418. // Anyway createFader() has now been deprecated in favour of CSS :hover.
  419.  
  420. function createFader(toc) {
  421.  
  422. var timer = null;
  423.  
  424. // BUG: this didn't stop the two fades from conflicting when the user wiggles the mouse to start both!
  425. function resetTimeout(fn,ms) {
  426. if (timer) {
  427. clearTimeout(timer);
  428. }
  429. setTimeout(fn,ms);
  430. }
  431.  
  432. function fadeElement(elem,start,stop,speed,current) {
  433. if (current == null)
  434. current = start;
  435. if (speed == null)
  436. speed = (stop - start) / 8;
  437. if (Math.abs(current+speed-stop) > Math.abs(current-stop))
  438. current = stop;
  439. else
  440. current = current + speed;
  441. elem.style.opacity = current;
  442. if (current != stop)
  443. resetTimeout(function(){fadeElement(elem,start,stop,speed,current);},50);
  444. }
  445.  
  446. toc.style.opacity = 0.3;
  447. var listenElement = toc;
  448. // var listenElement = toc.getElementsByTagName('TD')[0];
  449. var focused = false;
  450. var visible = false;
  451. listenElement.addEventListener('mouseover',function(){
  452. if (!visible)
  453. setTimeout(function(){ if (focused) { visible=true; fadeElement(toc,0.4,1.0,0.2); } },10);
  454. focused = true;
  455. },false);
  456. listenElement.addEventListener('mouseout',function(){
  457. if (visible)
  458. setTimeout(function(){ if (!focused) { visible=false; fadeElement(toc,1.0,0.2,-0.1); } },10);
  459. focused = false;
  460. },false);
  461.  
  462. }
  463.  
  464.  
  465. function tryTOC() {
  466.  
  467. // Find the table of contents element:
  468. var toc = document.getElementById("toc") /* MediaWiki */
  469. || document.getElementsByClassName("table-of-contents")[0] /* BashFAQ */
  470. || document.getElementsByClassName("toc")[0] /* LeakyTap */
  471. || document.getElementsByClassName("wt-toc")[0]; /* Wikitravel */
  472.  
  473. if (toc) {
  474.  
  475. addButtonsConditionally(toc);
  476.  
  477. // toc.style.backgroundColor = '#eeeeee';
  478. // alert("doing it!");
  479. toc.style.position = 'fixed';
  480. toc.style.right = '16px';
  481. // toc.style.top = '16px';
  482. // A healthy gap from the top allows the user to access things fixed in the top right of the page, if they can scroll finely enough.
  483. // toc.style.top = '24px';
  484. //toc.style.right = '4%';
  485. //toc.style.top = '10%';
  486. toc.style.right = '4px';
  487. toc.style.top = '84px'; // We want to be below the search box!
  488. // toc.style.left = '';
  489. // toc.style.bottom = '';
  490. toc.style.zIndex = '5000';
  491. // fadeElement(toc,1.0,0.4);
  492. // This might work for a simple toc div
  493. toc.style.maxHeight = "80%";
  494. toc.style.maxWidth = "32%";
  495.  
  496. /*
  497. * Sometimes specifying max-height: 80% does not work, the toc won't shrink.
  498. * This may be when it's a table and not a div. Then we must set max-height on the content. (Maybe we don't actually need to set pixels if we find the right element.)
  499. */
  500. toc.id = "toc";
  501. var maxHeight = window.innerHeight * 0.8 | 0;
  502. var maxWidth = window.innerWidth * 0.4 | 0;
  503.  
  504. /*
  505. * WikiMedia tree looks like this: <table id="toc" class="toc"><tbody><tr><td><div id="toctitle"><h2>Contents</h2>...</div> <ul> <li class="toclevel-1 tocsection-1">
  506. Here is a long TOC: http://mewiki.project357.com/wiki/X264_Settings#Input.2FOutput
  507. */
  508. // GM_addStyle("#toc ul { overflow: auto; max-width: "+maxWidth+"px; max-height: "+maxHeight+"px; }");
  509. var rootUL = toc.getElementsByTagName("UL")[0];
  510. if (!rootUL)
  511. rootUL = toc;
  512. // DONE: If we can cleanly separate them, we might want to put a scrollbar on the content element, leaving the title outside it.
  513. rootUL.style.overflow = "auto";
  514. rootUL.style.maxWidth = maxWidth+'px';
  515. rootUL.style.maxHeight = maxHeight+'px';
  516.  
  517. // But if calc and vh are available, then we can make it adaptive
  518. // Of this 132px, 84px comes from the 'top', and the rest comes from the toc title and padding.
  519. rootUL.style.maxHeight = "calc(100vh - 128px)";
  520.  
  521. // Slide up into the corner as the page scrolls
  522. window.addEventListener('scroll', checkSize);
  523. window.addEventListener('resize', checkSize);
  524. function checkSize () {
  525. var top = Math.min(84, Math.max(4, 84 - document.body.scrollTop));
  526. document.getElementById('toc').style.top = top + 'px';
  527. rootUL.style.maxHeight = (window.innerHeight - top - 44) + 'px';
  528. }
  529.  
  530. /*
  531. createFader(toc);
  532. */
  533. //// Alternative rules from table_of_contents_everywhere script:
  534. toc.id = "toc";
  535. // GM_addStyle("#toc { position: fixed; top: 10%; right: 4%; background-color: white; color: black; font-weight: normal; padding: 5px; border: 1px solid grey; z-index: 5555; max-height: 80%; overflow: auto; }");
  536. GM_addStyle("#toc { opacity: 0.2; }");
  537. GM_addStyle("#toc:hover { opacity: 1.0; }");
  538.  
  539. var tocID = "toc";
  540. var resetProps = "";
  541. // This is a clone of the code in table_of_contents_everyw.user.js
  542. GM_addStyle(
  543. "#"+tocID+" {"
  544. + " position: fixed;"
  545. + " top: 84px;"
  546. + " right: 4px;"
  547. + " background-color: #f4f4f4;"
  548. + " color: black;"
  549. + " font-weight: normal;"
  550. + " padding: 5px;"
  551. //+ " border: 1px solid grey;"
  552. + " z-index: 9999999;"
  553. + " "+resetProps
  554. + "}"
  555. + "#"+tocID+" { opacity: 0.3; }"
  556. + "#"+tocID+" { border: 1px solid #0003; }"
  557. + "#"+tocID+" { border-radius: 3px; }"
  558. + "#"+tocID+":hover { box-shadow: 0px 2px 12px 0px rgba(0,0,0,0.1); }"
  559. + "#"+tocID+":hover { -webkit-box-shadow: 0px 2px 12px 0px rgba(0,0,0,0.1); }"
  560. + "#"+tocID+":hover { opacity: 1.0; }"
  561. + "#"+tocID+" > * > * { opacity: 0.0; }"
  562. + "#"+tocID+":hover > * > * { opacity: 1.0; }"
  563. + "#"+tocID+" , #"+tocID+" > * > * { transition: opacity; transition-duration: 400ms; }"
  564. + "#"+tocID+" , #"+tocID+" > * > * { -webkit-transition: opacity; -webkit-transition-duration: 400ms; }"
  565. + "#"+tocID+" { padding: 0; }"
  566. + "#"+tocID+" > div { padding: 4px 12px; }"
  567. + "#"+tocID+" > ul { padding: 0px 12px 2px 12px; margin-top: 0; }"
  568. );
  569.  
  570. // For Wikia (tested in Chrome):
  571. if (getComputedStyle(toc)["background-color"] == "rgba(0, 0, 0, 0)") {
  572. toc.style.backgroundColor = 'white';
  573. }
  574.  
  575. checkSize();
  576.  
  577. return true;
  578.  
  579. }
  580.  
  581. return false;
  582.  
  583. }
  584.  
  585. // Ideally we want to act before # anchor position occurs, but we may
  586. // need to wait for the toc if it is not added to the DOM until later.
  587. if (!tryTOC()) {
  588. setTimeout(tryTOC,400);
  589. }
  590.  
  591. }
  592.  
  593.  
  594.  
  595. // In case you have * in your includes, only continue for pages which have
  596. // "wiki" before "?" in the URL, or who have both toc and content elements.
  597. var isWikiPage = document.location.href.split("?")[0].match("wiki")
  598. || ( document.getElementById("toc") && document.getElementById("content") );
  599.  
  600. if (!isWikiPage)
  601. return;
  602.  
  603.  
  604.  
  605. // Delay. Feature 3 and 4 can run a bit later, without *too* much page
  606. // change, but with significant processor saving!
  607. setTimeout(function(){
  608.  
  609.  
  610.  
  611. //// Feature #3 : Indent the blocks so their tree-like structure is visible
  612.  
  613. // Oct 2012: Disabled - was making a right mess of the header/nav on Wikia
  614. if (document.location.host.match(/wikia.com/)) {
  615. indentSubBlocks = false;
  616. }
  617.  
  618. if (indentSubBlocks) {
  619.  
  620. function indent(tag) {
  621. // By targetting search we avoid indenting any blocks in left-hand-column (sidebar).
  622. var whereToSearch = document.getElementById('bodyContent') || document.getElementById('content') || document.getElementById('WikiaMainContent') || document.body;
  623. var elems = whereToSearch.getElementsByTagName(tag);
  624. if (elems.length == 1)
  625. return;
  626. // for (var i=0;i<elems.length;i++) {
  627. for (var i=elems.length;i-->0;) {
  628. var elem = elems[i];
  629. /* Don't fiddle with main heading, siteSub, or TOC. */
  630. if (elem.className == 'firstHeading')
  631. continue;
  632. if (elem.id == 'siteSub')
  633. continue;
  634. if (elem.textContent == 'Contents')
  635. continue;
  636.  
  637. // We have found a "heading" element. Every sibling after this
  638. // element should be indented a bit.
  639.  
  640. //// Current method of indenting: Create a UL and put everything
  641. //// inside that.
  642. // var newChild = document.createElement('blockquote');
  643. //// Unfortunately blockquotes tend to indent too much!
  644. // var newChild = document.createElement('DIV');
  645. //var newChild = document.createElement('UL'); // UL works better with my Folding script, but we must not do this to the TOC!
  646. var newChild = document.createElement('div'); // <ul>s look wrong on bitbucket wikis (indent too much). And since I haven't used my folding script recently, I am switching back to a nice <div>.
  647. newChild.style.marginLeft = '1.0em';
  648. var toAdd = elem.nextSibling;
  649. while (toAdd && toAdd.tagName != tag) {
  650. // That last condition means a h3 might swallow an h2 if they
  651. // are on the same level! But it *should* swallow an h4.
  652. // TODO: We should break if we encounter any marker with level
  653. // above or equal to our own, otherwise continue to swallow.
  654. var next = toAdd.nextSibling;
  655. newChild.appendChild(toAdd);
  656. toAdd = next;
  657. }
  658. elem.parentNode.insertBefore(newChild,elem.nextSibling);
  659.  
  660. // CONSIDER: Alternative: Do not swallow at all, do not create
  661. // newChild and change the page's tree. Just modify
  662. // style.marginLeft, resetting it if an incompatible element style
  663. // already exists there, updating it if we have already indented
  664. // this element!
  665.  
  666. // GM_log("Placed "+newChild+" after "+elem);
  667. }
  668. }
  669.  
  670. indent("H1"); indent("H2"); indent("H3"); indent("H4"); indent("H5"); indent("H6");
  671.  
  672. }
  673.  
  674.  
  675.  
  676. //// Feature #4: Change underlined headings to overlined headings.
  677.  
  678. if (fixUnderlinesToOverlines) {
  679.  
  680. // Hide any existing underlines
  681. // I made this !important to defeat the more specific `.markdown-body h*` rules on GitHub wikis.
  682. GM_addStyle("h1, h2, h3, h4, h5, h6 { border-bottom: 0 !important; }");
  683.  
  684. // Add our own overlines instead
  685. GM_addStyle("h1, h2, h3, h4, h5, h6 { border-top: 1px solid #AAAAAA; }");
  686.  
  687. // Do not use `text-decoration: underline;`. It will only appear as wide as the text (not filling the page width) and will make the text look like a hyperlink!
  688.  
  689. }
  690.  
  691.  
  692.  
  693. },1000);
  694.  
  695.  
  696.  
  697.  
  698. } // end doIt
  699.  
  700.  
  701. // setTimeout(doIt,2000);
  702. doIt();
  703.  
  704. })();
  705.