NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name FetishSort // @namespace http://tampermonkey.net/ // @version 0.2 // @description make FetLife's jaggiest feature a little bit less jaggy // @author WhyTrustTomHanks // @match *://fetlife.com/* // @grant none // ==/UserScript== // Helper function. Reports empty strings as TRUE. function isEmpty(str) { return (!str || 0 === str.length); } /** * This function takes in a set of interests, and returns formatted HTML. Interests * are defined in the function beneath this one: each is an array of URL/text * pairings. All this does is run through the array, grab the URL and the text, * and writes a new bunch of links. */ function makeBlock(interests) { var block = []; for (i = 0; i < interests.length; i++) { block[block.length] = " <a href=" + interests[i][0] + ">" + interests[i][1] + "</a>"; // "writes" the link } // creates the opening and closing tags for the block var blockOpen = "<div style='margin-left: 20px; margin-top: 5px;'>"; var blockClose = "</div>"; // converts the block array to a string, and wraps it up var blockWrapped = blockOpen + block.toString() + blockClose; return blockWrapped; } /** * FetLife's HTML output is garbage. The way this function works is: * * — Scan all the links in a particular space. * — See which ones are followed by "descriptions" (giving, receiving, etc) * — Use those descriptions to create a bunch of categories. * * The key phrase up there? "Followed by". The descriptions have NOTHING to do with * the links they accompany, programmatically speaking. They're just... text. Floatin' * about. Like a buncha grey parenthetical assholes. It's disgusting, and it makes for * ugly code. * * Anyway, we make those categories, run makeBlock() on each of them, and spit out the * appropriate formatting. This function can be run on any arbitrary HTML element, * which is important, because, on FetLife, all HTML elements are arbitrary. */ $.fn.formatList = function(){ // declare arrays, even the ones that'll be empty. var into = []; var giving = []; var receiving = []; var wearing = []; var watching = []; var everything = []; // find all links within this space, and break each one down. $(this).children('a').each(function(){ // does this link belong to a category? if ($(this).next().is('span')) { var fetishType = $(this).next().text(); // literally: "what's the thing after this link say?" if (fetishType == "(giving)") { giving[giving.length] = [$(this).attr('href') ,$(this).text()]; } if (fetishType == "(receiving)") { receiving[receiving.length] = [$(this).attr('href') ,$(this).text()]; } if (fetishType == "(wearing)") { wearing[wearing.length] = [$(this).attr('href') ,$(this).text()]; } if (fetishType == "(watching others wear)") { watching[watching.length] = [$(this).attr('href') ,$(this).text()]; } if (fetishType == "(everything to do with it)") { everything[everything.length] = [$(this).attr('href') ,$(this).text()]; } } else { into[into.length] = [$(this).attr('href') ,$(this).text()]; } /** * [$(this).attr('href') ,$(this).text()] is simply a pairing of "anchor link" and * "anchor text". */ }); // write empty strings for each potential category listInto = ""; listGiving = ""; listReceiving = ""; listWearing = ""; listWatching = ""; listEverything = ""; /** * If these categories _do_ exist, then they'll need additional formatting. The titles * here are unique per-category, so they can't be stuck into makeBlock—especially since * "into" has to function differently from all the rest. */ if (!isEmpty(into)) { into = makeBlock(into); listInto = "<div style='margin-bottom: 10px;'></div>" + into; } if (!isEmpty(giving)) { giving = makeBlock(giving); listGiving = "<br><span class='quiet'><em>Giving</em></span>" + giving; } if (!isEmpty(receiving)) { receiving = makeBlock(receiving); listReceiving = "<br><span class='quiet'><em>Receiving</em></span>" + receiving; } if (!isEmpty(wearing)) { wearing = makeBlock(wearing); listWearing = "<br><span class='quiet'><em>Wearing</em></span>" + wearing; } if (!isEmpty(watching)) { watching = makeBlock(watching); listWatching = "<br><span class='quiet'><em>Watching others wear</em></span>" + watching; } if (!isEmpty(everything)) { everything = makeBlock(everything); listEverything = "<br><span class='quiet'><em>Everything to do with</em></span>" + everything; } // The final assembled list! Hooray! completedList = listInto + listGiving + listReceiving + listWearing + listWatching + listEverything; // rewrite all of Fet's code, lololol $(this).html(completedList); }; /** * Here's where we actually format things. * * Note how I'm drilling down three levels here, then jumping right back out again * with "parent().parent()". Do you know _why_ I do that? It's because FetLife never * fucking declares a class name for these blocks. There's no such thing, in its HTML, * as your "fetish list". There's just an arbitrarily-placed title, and then an * arbitrary paragraph, and then INSIDE that paragraph is a styling span called "quiet", * and inside THAT is an arbitrary italic declaration, and THAT is where it finally says: * "Yes, I am into this shit." * * Not that this is hard to work around. It's just lazy, sloppy code. */ $('p > .quiet > em:contains("Into:")').each(function(){ $(this).parent().parent().formatList(); }); $('p > .quiet > em:contains("Curious about:")').each(function(){ $(this).parent().parent().before("<br><h3>Curious about</h3>"); $(this).parent().parent().formatList(); }); /*$('p > .quiet > em:contains("Soft limits:")').each(function(){ $(this).parent().parent().before("<br><h3>Soft limits</h3>"); $(this).parent().parent().formatList(); }); $('p > .quiet > em:contains("Hard limits:")').each(function(){ $(this).parent().parent().before("<br><h3>Hard limits</h3>"); $(this).parent().parent().formatList(); });*/ /** * Hard and soft limits break formatList, because formatList assumes fetishes will be * presented as anchors. For whatever reason, the profile I used to test this _did_ * that, so I initially thought there would be no problem. Turns out there were problems! * Now the code above is disabled. * * Formatting these will be tricky, because here there is _no fucking wrapper_ for * individual items. It's just a long block of text, with occasional, unreliable span * punctuations. You can't even use commas to delineate, because commas are of course * perfectly acceptable formatting within fetishes. Atrocious. Simply atrocious. * * Instead, I wrote the functions below, which find the initial formatting of these blocks, * and replace them with the pretty red headers I use everywhere else. */ $('p > .quiet > em:contains("Soft limits:")').each(function(){ $(this).parent().parent().before("<br><h3>Soft limits</h3>"); $(this).html(''); }); $('p > .quiet > em:contains("Hard limits:")').each(function(){ $(this).parent().parent().before("<br><h3>Hard limits</h3>"); $(this).html(''); });