//----------------------------------------------------------------------------- // [WoD] Extra Statistics // Version 1.20, 2010-04-15 // Copyright (c) Fenghou, Tomy // This script can generate additional statistical data in the dungeon and duel report pages. // When you entered the details or statistics page of reports, a new button will appear beside // the details button. At the details page, the new button is "Extra Stat", which will show // the statistics of the current level when you click it. At the statistics page, the new // button is "Entire Extra Stat", which will show the statistics of entire dungeon. //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // If you want to add a new Stat table, you should create a new sub class of CInfoList, // and use CStat::RegInfoList() to register your new info list. // A detailed example is CILItemDamage. //----------------------------------------------------------------------------- // ==UserScript== // @name Extra Statistics // @namespace fenghou // @version 1.20 // @description Generate additional statistical data in the dungeon and duel report pages // @include http*://*.world-of-dungeons.*/wod/spiel/*dungeon/report.php* // @include http*://*.world-of-dungeons.*/wod/spiel/tournament/*duell.php* // @include file:///*f1.htm // @downloadURL none // ==/UserScript== // COMMON FUNCTIONS /////////////////////////////////////////////////////////// function $(id) {return document.getElementById(id);} // Choose contents of the corresponding language // Contents: {Name1 : [lang1, lang2, ...], Name2 : [lang1, lang2, ...], ...} // return: Local contents, or null // It will edit the input contents directly, so the returned object is not necessary function GetLocalContents(Contents) { function GetLanguageId() { var langText = null; var allMetas = document.getElementsByTagName("meta"); for (var i = 0; i < allMetas.length; ++i) { if (allMetas[i].httpEquiv == "Content-Language") { langText = allMetas[i].content; break; } } if (langText == null) return false; switch (langText) { case "en": return 0; case "cn": return 1; default: return null; } } var nLangId = GetLanguageId(); if (nLangId == null) return null; if (Contents instanceof Object) { for (var name in Contents) Contents[name] = Contents[name][nLangId]; return Contents; } else return null; } function CompareString(a, b) { a = a || ""; b = b || ""; return a.toLowerCase().localeCompare( b.toLowerCase() ); } function CreateElementHTML(Name, Content /* , [AttrName1, AttrValue1], [AttrName2, AttrValue2], ... */) { var HTML = '<' + Name; for (var i = 2; i < arguments.length; ++i) HTML += ' ' + arguments[i][0] + '="' + arguments[i][1] + '"'; HTML += (Content != null && Content != "") ? ('>' + Content + '' + Name + '>') : (' />'); return HTML; } function DbgMsg(Text) {if (DEBUG) alert(Text);} // EXTERN FUNCTIONS /////////////////////////////////////////////////////////// /** * A utility function for defining JavaScript classes. * * This function expects a single object as its only argument. It defines * a new JavaScript class based on the data in that object and returns the * constructor function of the new class. This function handles the repetitive * tasks of defining classes: setting up the prototype object for correct * inheritance, copying methods from other types, and so on. * * The object passed as an argument should have some or all of the * following properties: * * name: The name of the class being defined. * If specified, this value will be stored in the classname * property of the prototype object. * * extend: The constructor of the class to be extended. If omitted, * the Object( ) constructor will be used. This value will * be stored in the superclass property of the prototype object. * * construct: The constructor function for the class. If omitted, a new * empty function will be used. This value becomes the return * value of the function, and is also stored in the constructor * property of the prototype object. * * methods: An object that specifies the instance methods (and other shared * properties) for the class. The properties of this object are * copied into the prototype object of the class. If omitted, * an empty object is used instead. Properties named * "classname", "superclass", and "constructor" are reserved * and should not be used in this object. * * statics: An object that specifies the static methods (and other static * properties) for the class. The properties of this object become * properties of the constructor function. If omitted, an empty * object is used instead. * * borrows: A constructor function or array of constructor functions. * The instance methods of each of the specified classes are copied * into the prototype object of this new class so that the * new class borrows the methods of each specified class. * Constructors are processed in the order they are specified, * so the methods of a class listed at the end of the array may * overwrite the methods of those specified earlier. Note that * borrowed methods are stored in the prototype object before * the properties of the methods object above. Therefore, * methods specified in the methods object can overwrite borrowed * methods. If this property is not specified, no methods are * borrowed. * * provides: A constructor function or array of constructor functions. * After the prototype object is fully initialized, this function * verifies that the prototype includes methods whose names and * number of arguments match the instance methods defined by each * of these classes. No methods are copied; this is simply an * assertion that this class "provides" the functionality of the * specified classes. If the assertion fails, this method will * throw an exception. If no exception is thrown, any * instance of the new class can also be considered (using "duck * typing") to be an instance of these other types. If this * property is not specified, no such verification is performed. **/ function DefineClass(data) { // Extract the fields we'll use from the argument object. // Set up default values. var classname = data.name; var superclass = data.extend || Object; var constructor = data.construct || function(){}; var methods = data.methods || {}; var statics = data.statics || {}; var borrows; var provides; // Borrows may be a single constructor or an array of them. if (!data.borrows) borrows = []; else if (data.borrows instanceof Array) borrows = data.borrows; else borrows = [ data.borrows ]; // Ditto for the provides property. if (!data.provides) provides = []; else if (data.provides instanceof Array) provides = data.provides; else provides = [ data.provides ]; // Create the object that will become the prototype for our class. var proto = new superclass( ); // Delete any noninherited properties of this new prototype object. for(var p in proto) if (proto.hasOwnProperty(p)) delete proto[p]; // Borrow methods from "mixin" classes by copying to our prototype. for(var i = 0; i < borrows.length; i++) { var c = data.borrows[i]; borrows[i] = c; // Copy method properties from prototype of c to our prototype for(var p in c.prototype) { if (typeof c.prototype[p] != "function") continue; proto[p] = c.prototype[p]; } } // Copy instance methods to the prototype object // This may overwrite methods of the mixin classes for(var p in methods) proto[p] = methods[p]; // Set up the reserved "constructor", "superclass", and "classname" // properties of the prototype. proto.constructor = constructor; proto.superclass = superclass; // classname is set only if a name was actually specified. if (classname) proto.classname = classname; // Verify that our prototype provides all of the methods it is supposed to. for(var i = 0; i < provides.length; i++) { // for each class var c = provides[i]; for(var p in c.prototype) { // for each property if (typeof c.prototype[p] != "function") continue; // methods only if (p == "constructor" || p == "superclass") continue; // Check that we have a method with the same name and that // it has the same number of declared arguments. If so, move on if (p in proto && typeof proto[p] == "function" && proto[p].length == c.prototype[p].length) continue; // Otherwise, throw an exception throw new Error("Class " + classname + " does not provide method "+ c.classname + "." + p); } } // Associate the prototype object with the constructor function constructor.prototype = proto; // Copy static properties to the constructor for(var p in statics) constructor[p] = statics[p]; // Finally, return the constructor function return constructor; } /** * Throughout, whitespace is defined as one of the characters * "\t" TAB \u0009 * "\n" LF \u000A * "\r" CR \u000D * " " SPC \u0020 * * This does not use Javascript's "\s" because that includes non-breaking * spaces (and also some other characters). */ /** * Determine whether a node's text content is entirely whitespace. * * @param nod A node implementing the |CharacterData| interface (i.e., * a |Text|, |Comment|, or |CDATASection| node * @return True if all of the text content of |nod| is whitespace, * otherwise false. */ function is_all_ws( nod ) { // Use ECMA-262 Edition 3 String and RegExp features return !(/[^\t\n\r ]/.test(nod.data)); } /** * Determine if a node should be ignored by the iterator functions. * * @param nod An object implementing the DOM1 |Node| interface. * @return true if the node is: * 1) A |Text| node that is all whitespace * 2) A |Comment| node * and otherwise false. */ function is_ignorable( nod ) { return ( nod.nodeType == 8) || // A comment node ( (nod.nodeType == 3) && is_all_ws(nod) ); // a text node, all ws } /** * Version of |previousSibling| that skips nodes that are entirely * whitespace or comments. (Normally |previousSibling| is a property * of all DOM nodes that gives the sibling node, the node that is * a child of the same parent, that occurs immediately before the * reference node.) * * @param sib The reference node. * @return Either: * 1) The closest previous sibling to |sib| that is not * ignorable according to |is_ignorable|, or * 2) null if no such node exists. */ function node_before( sib ) { while ((sib = sib.previousSibling)) { if (!is_ignorable(sib)) return sib; } return null; } /** * Version of |nextSibling| that skips nodes that are entirely * whitespace or comments. * * @param sib The reference node. * @return Either: * 1) The closest next sibling to |sib| that is not * ignorable according to |is_ignorable|, or * 2) null if no such node exists. */ function node_after( sib ) { while ((sib = sib.nextSibling)) { if (!is_ignorable(sib)) return sib; } return null; } /** * Version of |lastChild| that skips nodes that are entirely * whitespace or comments. (Normally |lastChild| is a property * of all DOM nodes that gives the last of the nodes contained * directly in the reference node.) * * @param par The reference node. * @return Either: * 1) The last child of |sib| that is not * ignorable according to |is_ignorable|, or * 2) null if no such node exists. */ function last_child( par ) { var res=par.lastChild; while (res) { if (!is_ignorable(res)) return res; res = res.previousSibling; } return null; } /** * Version of |firstChild| that skips nodes that are entirely * whitespace and comments. * * @param par The reference node. * @return Either: * 1) The first child of |sib| that is not * ignorable according to |is_ignorable|, or * 2) null if no such node exists. */ function first_child( par ) { var res=par.firstChild; while (res) { if (!is_ignorable(res)) return res; res = res.nextSibling; } return null; } /** * Version of |data| that doesn't include whitespace at the beginning * and end and normalizes all whitespace to a single space. (Normally * |data| is a property of text nodes that gives the text of the node.) * * @param txt The text node whose data should be returned * @return A string giving the contents of the text node with * whitespace collapsed. */ function data_of( txt ) { var data = txt.data; // Use ECMA-262 Edition 3 String and RegExp features data = data.replace(/[\t\n\r ]+/g, " "); if (data.charAt(0) == " ") data = data.substring(1, data.length); if (data.charAt(data.length - 1) == " ") data = data.substring(0, data.length - 1); return data; } // CLASSES //////////////////////////////////////////////////////////////////// // NextNode: the node next to the statistics node when it is created function CStat(NextNode) { var NewSection = document.createElement("div"); NewSection.id = "stat_all"; this._Node = NextNode.parentNode.insertBefore(NewSection, NextNode); this._HTML = ''; this._gInfoList = []; this.nTotalPages = 0; this.nReadPages = 0; } CStat.prototype._Write = function(Text) {this._HTML += Text;}; CStat.prototype._Flush = function() {this._Node.innerHTML = this._HTML;}; CStat.prototype.RegInfoList = function(InfoList) { if (InfoList instanceof CInfoList) { this._gInfoList.push(InfoList); return true; } return false; }; CStat.prototype.SaveInfo = function(Info) { for (var i = 0; i < this._gInfoList.length; ++i) this._gInfoList[i].SaveInfo(Info); }; CStat.prototype.Show = function() { this._Write("
| ' + this._HeadCellContents[i] + ' | '; this._HTML += '
|---|
| ' + this._BodyCellContents[i][j] + ' | '; } this._HTML += '
| ' + ((this._nAvgValue[0] !== 0) ? String(this._nAvgValue[0]) : '') + ' | ' + ((this._nAvgValue[1] !== 0) ? String(this._nAvgValue[1]) : '') + ' |
| ' + this._nAvgValue[1] + ' | ' + this._nAvgValue[0] + ' |