// ==UserScript== // @name Collapsing Paragraphs // @namespace http://chrislord.net/ // @description Collapses paragraphs to a GtkExpander-like structure // @include * // ==/UserScript== function getText (element, size) { for (var child = element.firstChild; child; child = child.nextSibling) { if ((child.nodeType == child.TEXT_NODE) && (child.nodeValue.length >= size)) { return child.nodeValue; } else { if ((element.tagName != "A") && (element.nodeType != child.COMMENT_NODE) && (element.tagName != "SCRIPT")) { var text = getText (child, size); if (text) return text; } } } return null; } function flatten (element) { if ((element.tagName == "TABLE") || (element.tagName == "TBODY") || (element.tagName == "THEAD") || (element.tagName == "TFOOT") || (element.tagName == "TR") || (element.tagName == "TD") || (element.tagName == "TH") || (element.tagName == "COL") || (element.tagName == "COLGROUP")) { element.setAttribute ("style", "display: block ! important;"); } for (var child = element.firstChild; child; child = child.nextSibling) flatten (child); } function flatten_table (element) { if ((!element) || (element.nodeType != element.ELEMENT_NODE)) return; if (element.tagName == "TABLE") { flatten (element); } flatten_table (element.parentNode); } function collapse (element, min_size, summary_size, ellipses_size) { var text, para, event; if (element.nodeType == element.TEXT_NODE) text = element.nodeValue; else { text = getText (element, min_size); if (!text) return; text = getText (element, summary_size); } if (text.length > ellipses_size) text = text.substr(0, ellipses_size - 3) + "..."; para = document.createElement ("p"); para.appendChild (document.createTextNode (text)); para.style.textDecoration = "underline"; para.style.cursor = "pointer"; element.parentNode.insertBefore (para, element); /* Note, some firefox bugs (or at least, things that go against docs): * - DOM elements have no 'click' function * http://www.mozilla.org/docs/dom/domref/dom_el_ref34.html#1028373 * - Can't set 'onclick' by doing element.onclick = ...; * http://www.mozilla.org/docs/dom/domref/dom_event_ref.html#998197 * - Works in Firefox < 1.5 * - dispatchEvent example is wrong * http://www.mozilla.org/docs/dom/domref/dom_el_ref36.html#1028419 */ para.addEventListener ("click", function (e) { var node = this.nextSibling; var j, new_display, old_display; if (node.hasAttribute ("old-display")) old_display = node.getAttribute ("old-display"); else old_display = "none"; node.setAttribute ("old-display", node.style.display); node.style.display = old_display; }, true); /* event = document.createEvent ("MouseEvents"); event.initEvent ("click", true, true); para.dispatchEvent (event);*/ } function collapse_image (image) { var para, event; para = document.createElement ("p"); para.appendChild (document.createTextNode ("Hide image")); para.style.textDecoration = "underline"; para.style.cursor = "pointer"; para.style.border = "1px dashed #CCCCCC"; image.parentNode.insertBefore (para, image); para.addEventListener ("click", function (e) { var node = this.nextSibling; var j, new_display, old_display; if (node.hasAttribute ("old-display")) old_display = node.getAttribute ("old-display"); else old_display = "none"; node.setAttribute ("old-display", node.style.display); node.style.display = old_display; if (node.style.display == "none") { this.firstChild.nodeValue = "View image"; } else { this.firstChild.nodeValue = "Hide image"; } }, true); /* event = document.createEvent ("MouseEvents"); event.initEvent ("click", true, true); para.dispatchEvent (event);*/ } function is_parent (parent, element) { if (!element) { return false; } if (element == parent) { return true; } else return is_parent (parent, element.parentNode); } function getTextParents (array, element, size) { /* Stop at certain tags */ if ((element.nodeType != element.ELEMENT_NODE) || (element.tagName == "A") || (element.tagName == "SCRIPT")) return array; for (var child = element.firstChild; child; child = child.nextSibling) { if (child.nodeType == child.TEXT_NODE) { if ((child.nodeValue.length >= size) && (element.tagName != "BODY")) { array.push (element); break; } } else getTextParents (array, child, size); } return array; } /* Flatten tables with images in them */ img_array = document.getElementsByTagName ("img"); for (i = 0; i < img_array.length; i++) { /* flatten_table (img_array[i]);*/ if ((img_array[i].width > 32) || (img_array[i].height > 32)) { if (img_array[i].parentNode.tagName == "A") collapse_image (img_array[i].parentNode); else collapse_image (img_array[i]); } } collapse_array = getTextParents (new Array (), document.body, 80); for (i = 0; i < collapse_array.length; i++) { /* Flatten tables with long paragraphs in them */ /* flatten_table (collapse_array[i]);*/ collapse (collapse_array[i], 80, 10, 40); }