// Copyright (c) 2015 JustLurking // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. (function () { // Check we are on the correct page ////////////////////////////////////// var url = location; if (url.host.toLowerCase () != 'inkbunny.net' || url.pathname != '/privatemessageview.php') return; // Some Values /////////////////////////////////////////////////////////// var xpr = XPathResult, doc = document, prefix1 = '//*[starts-with(@id, "irt_message_")]', prefix2 = './td[3]/div', ctime = (new Date ()).toLocaleString (), titleNode = node (prefix1+'/td[3]/div[2]//div/strong', doc), title = titleNode ? titleNode.innerText : "Untitled", originalURL = 'https://'+ url.host + url.pathname + url.search, outputDocument, messages, i, message, newTitle, messageBody, messageTime, authorName, authorAccount; // Utility Functions ///////////////////////////////////////////////////// // Simplified XPath evaluate function (assumes you are searching // the _page_ doc, do not set root to a Node, belonging to a different // doc). function xpath (expr, type, root) { return doc.evaluate (expr, root, doc.createNSResolver (doc), type); } // Get a trimmed string result from an XPath expression function string (expr, root) { return xpath (expr, xpr.STRING_TYPE, root).stringValue.trim (); } // Get a node snapshot from an XPath expression function nodes (expr, root) { return xpath (expr, xpr.UNORDERED_NODE_SNAPSHOT_TYPE, root); } // Get the first node that matches from an XPath expression function node (expr, root) { return xpath (expr, xpr.FIRST_ORDERED_NODE_TYPE, root).singleNodeValue; } // Encode the mandatory entities (since we're using UTF-8 everything else // can be left as-is). function encodeEntities (str) { return str.replace (/&/g, '&').replace (//g, '>').replace (/"/g, '"').replace (/'/g, '''); } // Convert Elements to their string representation, doing things this way // always yields well-formed XML (though not necessarily valid XHTML). function elementToString (elm) { var localName = elm.localName; var attrs = elm.attributes; var child = elm.firstNode; var ret = '<'+ localName; for (var i = 0; i < attrs.length; i++) ret += ' '+ attrs [i].name+ '="'+ encodeEntities (attrs [i].value)+ '"'; ret += '>'; for (var child = elm.firstChild; child; child = child.nextSibling) { var type = child.nodeType; if (type == 1) { ret += elementToString (child); } else if (type == 4) { ret += ''; } else if (type == 3) { ret += encodeEntities (child.nodeValue); } } ret += ''; return ret; } // The Program /////////////////////////////////////////////////////////// // output head outputDocument = ''+ ''+ ''+ ''+ title +''+ ''+ ''+ ''+ '
'+ '
Source: '+ ''+ originalURL +'
'+ '
Created: '+ ''+ ctime +'
'+ '
'; // Get all Messages messages = nodes (prefix1, doc); for (i = 0; i < messages.snapshotLength; ++i) { message = messages.snapshotItem (i); // Has the thread title changed? if (newTitle = string (prefix2+'[2]//div/strong', message)) outputDocument += '

'+ newTitle +'

'; // Get the Message if (!(messageBody = node (prefix2+'[2]//div/span', message))) continue; messageTime = string (prefix2+'[1]/text()[1]', message) || ''; // Get the Author authorName = string ('.//a[contains (@class, "widget_userNameSmall")]', message) || ''; authorAccount = string ('.//img[contains (@class, "shadowedimage")]/../@href', message) || ''; // Output the Message outputDocument += '
'+ '

'+ authorName+ ', '+ messageTime+ ':

'+ '
'+ elementToString (messageBody)+ '
'+ '
'; } // Output tail. outputDocument += ''+ ''; // Open a window with the results. window.open ( 'data:application/xhtml+xml;charset=utf-16,\uFEFF'+outputDocument, '_blank' ); }) ();