您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Reconfigures a number of items on various pages within TrueAchievements.
当前为
// ==UserScript== // @name TA improver // @namespace mobiusevalon.tibbius.com // @version 0.2 // @description Reconfigures a number of items on various pages within TrueAchievements. // @author Mobius Evalon // @include /^https{0,1}:\/\/\w{0,}\.?trueachievements\.com.*$/ // @grant none // ==/UserScript== /* == SCRIPT OPTIONS == */ // change_chat: basic chat restructuring like moving the clear button, hiding the // userlist key, etc. // minimalize_chat: extreme vertical space-saving measures that leaves nothing but // the chat and the site header // normalize_dates: change all date/time displays to the same format // use_fuzzy_dates: keep the terms "tomorrow", "today", "yesterday" instead of replacing them // with an explicit date // change_user_session_links: when viewing a session page, change the default link on a // person's gamertag to take you to the comparison page instead // hide_session_user_status: remove user status strings from the table on the session page // add_feed_permalinks: add the permalink icons on the right side of each friend // feed comment // hide_ads: does what it says on the tin var change_chat = 1; var minimalize_chat = 1; var normalize_dates = 1; var use_fuzzy_dates = 1; var change_session_user_links = 1; var hide_session_user_status = 1; var add_feed_permalinks = 1; var hide_ads = 1; /* == END SCRIPT OPTIONS == */ function exists(element) { if(element !== null && element !== undefined) return 1; return 0; } function splode(element) { if(exists(element)) { if(element.parentNode) element.parentNode.removeChild(element); else if(element.style) element.style.display = "none"; else console.log("element could not be hidden"); } } function splode_nodelist(nodelist) { for(var i=nodelist.length;i>-1;i--) splode(nodelist[i]); } function remove_by_class_name() { for(var i=0;i<arguments.length;i++) splode_nodelist(document.getElementsByClassName(arguments[i])); } function remove_by_tag_name() { for(var i=0;i<arguments.length;i++) splode_nodelist(document.getElementsByTagName(arguments[i])); } function remove_by_id() { for(var i=0;i<arguments.length;i++) splode(document.getElementById(arguments[i])); } function urldecode(string) { return string.replace("+"," "); } Date.prototype.getMonthString = function () { n = this.getMonth(); if(n === 0) return "Jan"; else if(n == 1) return "Feb"; else if(n == 2) return "Mar"; else if(n == 3) return "Apr"; else if(n == 4) return "May"; else if(n == 5) return "Jun"; else if(n == 6) return "Jul"; else if(n == 7) return "Aug"; else if(n == 8) return "Sep"; else if(n == 9) return "Oct"; else if(n == 10) return "Nov"; else return "Dec"; }; Date.prototype.getDayString = function () { n = this.getDay(); if(n === 0) return "Sun"; else if(n == 1) return "Mon"; else if(n == 2) return "Tue"; else if(n == 3) return "Wed"; else if(n == 4) return "Thu"; else if(n == 5) return "Fri"; else return "Sat"; }; Date.prototype.isSameDate = function(d) { if(this.getDate() == d.getDate() && this.getMonthString() == d.getMonthString()) return 1; return 0; }; Date.prototype.fuzzify = function() { var d = new Date(); if(this.isSameDate(d)) return "Today"; d.setDate(d.getDate()+1); if(this.isSameDate(d)) return "Tomorrow"; d.setDate(d.getDate()-2); if(this.isSameDate(d)) return "Yesterday"; return ""; }; Date.prototype.outputDate = function () { var r = ""; if(use_fuzzy_dates) r = this.fuzzify(); if(!r.length) r = (this.getDayString()+" "+this.getDate()+" "+this.getMonthString()); return (r+", "+this.doubleUp(this.getHours())+":"+this.doubleUp(this.getMinutes())); }; Date.prototype.doubleUp = function (n) { n = (""+n); if(n.length < 2) n = ("0"+n); return n; }; function strip_undefined(a) { var r = []; for(var i=0;i<a.length;i++) { if(a[i] !== undefined) r.push(a[i]); } return r; } function date_format_a() { var args = strip_undefined(arguments); // because i have to counter the regex engine trying to be helpful var date = new Date(); if(args.length == 10) date = new Date(args[1]+", "+args[6]+":"+args[7]); else if(args.length == 9) date = new Date(args[1]+" "+date.getFullYear()+", "+args[5]+":"+args[6]); else if(args.length == 6) { date.setHours(parseInt(args[2]),parseInt(args[3])); if(args[1].toLowerCase() == "yesterday") date.setDate(date.getDate()-1); else if(args[1].toLowerCase() == "tomorrow") date.setDate(date.getDate()+1); } return date.outputDate(); } function date_format_b() { var args = strip_undefined(arguments); // because i have to counter the regex engine trying to be helpful var date = new Date(); if(args.length == 9) date = new Date(args[1]+", "+args[5]+":"+args[6]); else if(args.length == 8) date = new Date(args[1]+" "+date.getFullYear()+", "+args[4]+":"+args[5]); else if(args.length == 6) { date.setHours(parseInt(args[2]),parseInt(args[3])); if(args[1].toLowerCase() == "yesterday") date.setDate(date.getDate()-1); else if(args[1].toLowerCase() == "tomorrow") date.setDate(date.getDate()+1); } return date.outputDate(); } function format_dates(element,format) { if(exists(element)) { // sun[day], 1 jan [2015] at 00:00 (gaming sessions box, session pages) if(format == 1) element.innerHTML = element.innerHTML.replace(/((\w{3,9}), (\d{1,2}) (\w{3,9})( \d{4})?|today|yesterday|tomorrow) at (\d{2}):(\d{2})/gi,date_format_a); // 1 jan at 00:00 (my gaming sessions page, my upcoming sessions box) else if(format == 2) element.innerHTML = element.innerHTML.replace(/((\d{1,2}) (\w{3,9})( \d{2})?|yesterday|today|tomorrow) at (\d{2}):(\d{2})/gi,date_format_b); } } function format_gamer_count(element) { element.innerHTML = element.innerHTML.replace(/(\d{1,2}) gamer(s)? still needed/gi,"$1 slot$2 left"); element.innerHTML = element.innerHTML.replace("This session is unlimited","unlimited"); } if(hide_ads) { // oopsie daisy, the ads disappeared remove_by_id("topad-wrap","divTAProHolder"); remove_by_class_name("rightintergi","internalad","followuson"); } if(normalize_dates) { if(window.location.href.indexOf("mygamingsessions.aspx") > -1) { var sessions = document.getElementById("oGamerGamingSessionListHolder"); if(exists(sessions) && sessions.tagName == "DIV") format_dates(sessions,2); } var panels = document.getElementsByClassName("smallpanel"); for(var i=0;i<panels.length;i++) { if(exists(panels[i])) { var header = panels[i].getElementsByTagName("h4")[0]; if(exists(header)) { if(header.innerHTML.indexOf("Sessions For This Game") > -1) format_dates(panels[i],1); else if(header.innerHTML.indexOf("Gaming Sessions") > -1) { format_dates(panels[i],1); format_gamer_count(panels[i]); } else if(header.innerHTML.indexOf("My Upcoming Sessions") > -1) format_dates(panels[i],2); } } } } if(window.location.href.indexOf("gamingsessionfeedback.aspx") > -1) remove_by_class_name("gsdisclaimer"); if(window.location.href.indexOf("gamingsession.aspx") > -1) { // gsdisclaimer is that thing that says ta is not responsible for the developer resetting your stats or whatever // if you get caught boosting, and that they won't change feedback remove_by_class_name("gsdisclaimer"); // reformat the date stated at the top of a session page if(normalize_dates) { var session_header = document.getElementsByClassName("gamingsession")[0]; if(exists(session_header) && session_header.tagName == "DIV") format_dates(session_header,1); } // this whole bit changes the links of the gamertags listed on a session to the comparison page by default, // instead of just the list of achievements that person has (except for yourself, of course) if(change_session_user_links) { var game_id = ""; var my_id = ""; var my_tag = ""; // first we gotta find the game id var panel = document.getElementsByClassName("smallpanel")[0]; if(exists(panel) && panel.tagName == "DIV") { var content = panel.getElementsByClassName("panelcontent")[0]; if(exists(content) && content.tagName == "DIV") { // the easiest place i could locate the game id is that link to create a new session on the right var anchors = content.getElementsByTagName("a"); var new_session_link = anchors[anchors.length-1]; if(exists(new_session_link) && new_session_link.innerHTML == "make a new session") game_id = new_session_link.href.substring(new_session_link.href.indexOf("=")+1); } } // now we gotta find your id and tag var menu = document.getElementById("mnuMyPages"); if(exists(menu) && menu.tagName == "LI") { var items = menu.getElementsByTagName("li"); for(var i=0;i<items.length;i++) { var anchor = items[i].getElementsByTagName("a")[0]; if(exists(anchor)) { if(anchor.innerHTML.indexOf("My Homepage") > -1) my_tag = urldecode(anchor.href.substring(anchor.href.lastIndexOf("/")+1,anchor.href.length-4)); else if(anchor.innerHTML.indexOf("My Stats") > -1) my_id = anchor.href.substring(anchor.href.indexOf("=")+1); } if(my_id.length && my_tag.length) break; } } if(my_id && my_tag) { var gamers = document.getElementsByClassName("gamer"); for(var i=0;i<gamers.length;i++) { var td = gamers[i]; if(exists(td) && td.tagName == "TD") { // i get rid of the gamer statuses in the table while i'm at it, considering it unnecessarily stetches // the table and the page vertically with information you're unlikely to care about if(hide_session_user_status) { var gamer_status = td.getElementsByClassName("sitestatus")[0]; if(exists(gamer_status) && gamer_status.tagName == "SPAN") splode(gamer_status); } var link = td.getElementsByTagName("a")[0]; if(exists(link) && my_tag != link.innerHTML) { var other_gamer_id = link.href.substring(link.href.indexOf("=")+1); link.href = ("comparison.aspx?gameid="+game_id+"&gamerid="+my_id+"&friendid="+other_gamer_id); } } } } } } // this section only applies when you're looking at someone's gamerpage. since each person has the option to // turn their friend feed off apparently (i've seen some pages without them), i check for the existence of the // feed by checking for the named div that contains it if(add_feed_permalinks) { var friend_feed = document.getElementById("oFriendFeed"); if(exists(friend_feed) && friend_feed.tagName == "DIV") { // every comment in a friend feed is conveniently contained in a div named "comment" var comments = friend_feed.getElementsByClassName("Comment"); for(var i=0;i<comments.length;i++) { // the p element references a paragraph node inside the comment div that contains the little button // for commenting on an item. even when the comment button is not there, this p element still exists // and is a perfect place to put the permalink icon var p = comments[i].getElementsByTagName("p")[0]; // using ta's own permalink icon for this purpose if(exists(p)) p.innerHTML = ('<a href="?gfcid='+comments[i].id.substring(5)+'"><img src="images/icons/permalink.png" class="AddComment" title="Permalink" alt="Permalink"></a>'+p.innerHTML); } } } // this section only applies when you're viewing the chat room if(change_chat && window.location.href.indexOf("chat.aspx") > -1) { var rules_banner = document.getElementById("divChatInformation"); // this is the large grey banner at the bottom that simply contains a link to the chatroom rules and etiquette. // i simply get rid of it here, but an icon is generated to point to the same page and placed unobtrusively // next to the textbox you type into later if(exists(rules_banner) && rules_banner.tagName == "DIV") splode(rules_banner); // this whole css section is overriding the default styling of the page when viewing the chatroom to change a whole // bunch of things, including: // # changing the font of the whole chat interface // # extending the height of the userlist to be the same as the chatbox // # shrinking the vertical display slightly so it all fits on the page at the same time (i always had to scroll a // bit to get to the textbox) // # extending the width of the input box // # giving the timestamp a fixed width // # giving the gamertag a fixed width // # positioning the buttons we'll be adding after the text input later var css = "div#divChatHolder {font-family: 'Droid Sans Mono',monospace !important} "+ "div#divChatList {width: 175px !important; height: 450px !important;}" + "div#divChatBody {margin-right: 190px !important; height: 450px !important;} "+ "input#txtChatMessage {width: 720px !important;} "+ "span.chattime {display: inline-block !important; width: 65px !important; font-style: normal !important;} "+ "span.gamertag {display: inline-block !important; width: 105px !important;} "+ "a#btnClearChat {position: relative !important; top: -4px !important; right: auto !important; padding-right: 8px !important;} "+ "img#btnChatRules {position: relative !important; top: -4px !important;} "; if(minimalize_chat) { // this section enforces additional options that leaves basically nothing on the page besides the chat // elements, collapsing vertical space and removing elements from the page to even fit the whole thing // on one screen and prevent vertical scrolling css = css + "div#main {padding: 10px 10px 0px 10px !important; min-height: 0 !important;} "+ "div#page-wrap {padding-bottom: 0 !important;} "+ "div#page {min-height: 0 !important;}"; // the "header" variable points to the large bold text at the top of the page that says "TrueAchievements Chat" var header = document.getElementsByClassName("pagetitle")[0]; if(exists(header) && header.tagName == "H1") splode(header); // the footer is a huge bar of information that stretches the page var footer = document.getElementById("footer-wrap"); if(exists(footer) && footer.tagName == "DIV") splode(footer); } // simply injecting the above css rules into the document var head = document.getElementsByTagName("head")[0]; var style = document.createElement("style"); style.type = "text/css"; style.innerHTML = css; head.appendChild(style); // this section moves the clear chat button and creates a new rules button to the right of the input box at the bottom var clear_chat = document.getElementById("btnClearChat"); var rules_button = document.createElement("a"); rules_button.href = "forumpolicy.aspx"; rules_button.target = "_blank"; rules_button.innerHTML = '<img src="images/itemflags/MainStoryline.png" id="btnChatRules" title="Chat Guidelines" alt="Chat Guidelines">'; // chat_key is our reference for inserting the new buttons. javascript DOM only provides functions to insert a new // element at the end of the whole container or insert the element before another element. since chat_key appears // in the page code just after the send message button, it's perfect var chat_key = document.getElementById("divChatKey"); if(exists(chat_key) && chat_key.tagName == "DIV") { if(exists(clear_chat) && clear_chat.tagName == "A") { // remove the clear chat button from its current location clear_chat.parentNode.removeChild(clear_chat); // insert the clear chat button before the icon key chat_key.parentNode.insertBefore(clear_chat,chat_key); } // insert the rule buttons just before the icon key (and just after the clear chat button) chat_key.parentNode.insertBefore(rules_button,chat_key); // remove the icon key element. this same information is found in the chat rules anyway splode(chat_key); } }