//-----------------------------------------------------------------------------
// [WoD] Extra Statistics
// Copyright (c) Fenghou, Tomy, DotIN13, ShakeSS
// 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.
//-----------------------------------------------------------------------------
// 此版本的依赖项替换为gitee以保证国内访问
// ==UserScript==
// @name WoD 战报额外统计信息与导出
// @namespace fenghou
// @description Generate additional statistical data in the dungeon and duel report pages
// @icon http://info.world-of-dungeons.org/wod/css/WOD.gif
// @include http*://*.world-of-dungeons.*/wod/spiel/*dungeon/report.php*
// @include http*://*.world-of-dungeons.*/wod/spiel/tournament/*duell.php*
// @include http*://*.wannaexpresso.*/wod/spiel/*dungeon/report.php*
// @include http*://*.wannaexpresso.*/wod/spiel/tournament/*duell.php*
// @require https://code.jquery.com/jquery-3.3.1.min.js
// @require https://cdn.jsdelivr.net/npm/blob.js@1.0.1/Blob.min.js
// @require https://cdn.jsdelivr.net/npm/file-saver@2.0.5/dist/FileSaver.min.js
// @require https://cdn.jsdelivr.net/npm/jszip-sync@3.2.1-sync/dist/jszip.js
// @require https://cdn.jsdelivr.net/npm/jquery-form@4.3.0/dist/jquery.form.min.js
// @require https://cdn.jsdelivr.net/npm/dayjs@1.11.5/dayjs.min.js
// @require https://cdn.jsdelivr.net/npm/dayjs@1.11.5/plugin/customParseFormat.js
// @require https://code.jquery.com/ui/1.13.2/jquery-ui.min.js
// @modifier Christophero
// @version 2023.03.14.1
// @downloadURL https://update.greasyfork.icu/scripts/520627/WoD%20%E6%88%98%E6%8A%A5%E9%A2%9D%E5%A4%96%E7%BB%9F%E8%AE%A1%E4%BF%A1%E6%81%AF%E4%B8%8E%E5%AF%BC%E5%87%BA.user.js
// @updateURL https://update.greasyfork.icu/scripts/520627/WoD%20%E6%88%98%E6%8A%A5%E9%A2%9D%E5%A4%96%E7%BB%9F%E8%AE%A1%E4%BF%A1%E6%81%AF%E4%B8%8E%E5%AF%BC%E5%87%BA.meta.js
// ==/UserScript==
(function () {
// COMMON FUNCTIONS ///////////////////////////////////////////////////////////
// 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(), "zh-CN-u-co-pinyin");
}
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);
}
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function (needle) {
for (var i = 0; i < this.length; i++) {
if (this[i] === needle) {
return i;
}
}
return -1;
};
}
initJQUIStyle();
/**
* 初始化JqueryUI的样式表
*/
function initJQUIStyle() {
let $toolbarCss = $("");
$("head").prepend($toolbarCss);
$toolbarCss.attr({
rel: "stylesheet",
type: "text/css",
href: "https://code.jquery.com/ui/1.13.2/themes/humanity/jquery-ui.css",
});
document.querySelector("style").textContent +=
".ui-progressbar .ui-progressbar-value {transition: width 0.7s ease 0s;} " +
"#progressbar .progress-label {position: absolute; left: 48%; font-weight: bold; text-shadow: 1px 1px 0 #fff; height: 31px; display: flex; justify-content: enter; align-items: center;}" +
"@media (min-width:1px) { .ui-dialog { width: 95% !important; } } " +
"@media (min-width: 768px) { .ui-dialog { max-width:900px !important; width:95% !important; } }";
}
// COMMON STAT FUNCTIONS ///////////////////////////////////////////////////////////
function getSum(numArr) {
var nTotal = 0;
for (var i = 0; i < numArr.length; i++) {
nTotal = nTotal + Number(numArr[i]);
}
return nTotal;
}
function getAverage(numArr) {
return getSum(numArr) / numArr.length;
}
// see http://www.johndcook.com/blog/2008/09/26/comparing-three-methods-of-computing-standard-deviation/
// for discussion on choice of algorithm
function getVariance(numArr) {
if (numArr.length <= 1) {
return 0;
}
var nAvg = getAverage(numArr);
var nTempSum = 0;
for (var i = 0; i < numArr.length; i++) {
nTempSum = nTempSum + Math.pow(Number(numArr[i]) - nAvg, 2);
}
return nTempSum / (numArr.length - 1);
}
// sample standard deviation
function getSTD(numArr) {
return Number(Math.sqrt(getVariance(numArr)).toFixed(2));
}
function getMax(numArr) {
return Math.max.apply(null, numArr);
}
function getMin(numArr) {
return Math.min.apply(null, numArr);
}
// 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 == Node.COMMENT_NODE || // A comment node
(nod.nodeType == Node.TEXT_NODE && 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;
}
function split_id(id) {
const segs = id.split("_");
let obj = { a: 0, b: 0, c: 0, d: 0 };
if (segs[1]) obj.a = parseInt(segs[1]);
if (segs[2]) obj.a = parseInt(segs[1]);
if (segs[3]) obj.a = parseInt(segs[1]);
if (segs[4]) obj.a = parseInt(segs[1]);
return obj;
}
function compare_id(id1, id2) {
let obj1 = split_id(id1);
let obj2 = split_id(id2);
return obj1.a - obj2.a
? obj1.a - obj2.a
: obj1.b - obj2.b
? obj1.b - obj2.b
: obj1.c - obj2.c
? obj1.c - obj2.c
: obj1.d - obj2.d;
}
// CLASSES ////////////////////////////////////////////////////////////////////
// NextNode: the node next to the statistics node when it is created
function CStat(NextNode, InfoDiv) {
this._HTML = '';
this._reportInfoDiv = InfoDiv;
this._gInfoList = [];
this.iscurrentPage = true;
this.nTotalPages = 0;
this.nReadPages = 0;
this.nReadRows = 0;
this.nTotalRows = 0;
this.setNode = function (newNode) {
if (newNode.id == "stat_all") {
this._Node = newNode;
this._Node.innerHTML = '';
}
else {
if (this._Node) {
var divs = newNode.parentNode.getElementsByTagName('div');
for (var i = 0; i < divs.length; i++) {
if (divs[i].id == "stat_all") {
newNode.parentNode.removeChild(divs[i]);
break;
}
}
}
var NewSection = document.createElement("div");
NewSection.id = "stat_all";
NewSection.className = "stat_all tab";
if (newNode.parentNode)
this._Node = newNode.parentNode.insertBefore(NewSection, newNode);
else {
this._Node = NewSection;
newNode.appendChild(NewSection);
}
}
this._HTML = '';
};
this.setNode(NextNode);
this._reportInfoDiv.appendChild(document.createElement('table'));
}
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.getTab = function (isExport, showhide) {
function FactoryTabClick(Id) {
return function () {
CStat.OnTabClick(Id);
};
}
var tab = document.createElement('li');
tab.className = 'not_selected';
var title = Local.Text_Button_ShowAll;
var id = 'showall';
if (showhide === true) {
title = Local.Text_Button_ShowAll;
id = 'showall';
}
else {
tab.id = 'tab_hideall';
title = Local.Text_Button_HideAll;
id = 'hideall';
}
tab.id = 'tab_' + id;
var a = document.createElement('A');
a.id = 'show_all_a';
var name = document.createTextNode(title);
a.appendChild(name);
a.href = '#';
if (isExport)
a.setAttribute("onclick", "st('" + id + "');");
else
a.addEventListener("click", FactoryTabClick(id), false);
tab.appendChild(a);
return tab;
};
CStat.prototype.Show = function (isExport) {
this._Node.innerHTML = '';
var tabs = document.createElement("ul");
this._Node.appendChild(tabs);
var bar = document.createElement('div');
bar.id = 'stat_bar';
bar.className = 'bar';
this._Node.appendChild(bar);
var tabDivs = [];
var isFirst = true;
for (var i = 0; i < this._gInfoList.length; ++i) {
var infoNode = this._gInfoList[i].Show(isExport);
var tab = this._gInfoList[i].getTab(isExport);
if (tab && infoNode) {
tabs.appendChild(tab);
this._Node.appendChild(infoNode);
tabDivs.push(infoNode.id);
if (isFirst) {
tab.className = 'selected';
infoNode.style.display = '';
isFirst = false;
}
else {
tab.className = 'not_selected';
infoNode.style.display = 'none';
}
}
}
tabs.appendChild(this.getTab(isExport, true));
tabs.appendChild(this.getTab(isExport, false));
this._Node.setAttribute('tabs', tabDivs.join(','));
if (!isExport) {
this._Node.appendChild(document.createElement('hr'));
//this._Node.appendChild(this._reportInfoDiv);
this.ShowProgress();
}
if (!this.iscurrentPage) {
this._reportInfoDiv.style.display = 'none';
this._Node.appendChild(this._reportInfoDiv);
}
//this._reportInfoDiv.parentNode.removeChild(this._reportInfoDiv);
};
CStat.prototype.ShowProgress = function () {
var widthP = 1;
var currentP = 1;
if (reportInfoDiv) {
if (this.nReadPages < 1)
currentP = 1;
else
currentP = this.nReadPages
if (this.nTotalPages === 0 || this.nTotalRows === 0)
widthP = 1;
else
widthP = parseInt(((currentP - 1) / this.nTotalPages + this.nReadRows / (this.nTotalRows * this.nTotalPages)) * 100);
reportInfoDiv.style.width = widthP + '%';
}
};
CStat.prototype._AddEvents = function () {
function OnDelGMValues() {
try {
var ValueList = GM_listValues();
for (var name in ValueList) {
GM_deleteValue(ValueList[name]);
}
alert(Local.Text_DefaultMsg);
} catch (e) {
alert("OnDelGMValues(): " + e);
}
}
document.getElementById("stat_options_default").addEventListener("click", OnDelGMValues, false);
};
CStat.OnTabClick = function (id) {
var statdiv = document.getElementById('stat_all');
var tabs = statdiv.getAttribute('tabs').split(',');
var showall = false;
var lishowall = document.getElementById('tab_showall');
var lihideall = document.getElementById('tab_hideall');
lishowall.className = 'not_selected';
lihideall.className = 'not_selected';
for (var i = 0; i < tabs.length; i++) {
var tabid = tabs[i];
var tab = document.getElementById(tabid);
var li = document.getElementById('tab_' + tabid);
li.className = 'not_selected';
if (id == 'showall') {
lishowall.className = 'selected';
tab.style.display = '';
}
else if (id == 'hideall') {
lihideall.className = 'selected';
tab.style.display = 'none';
}
else {
if (tabid == id) {
tab.style.display = '';
li.className = 'selected';
}
else {
tab.style.display = 'none';
li.className = 'not_selected';
}
}
}
};
///////////////////////////////////////////////////////////////////////////////
function CTable(Title, Id, nColumns, isExport) {
this._Title = Title;
this._Id = Id;
this._filterId = "filter_" + Id;
this._nColumns = nColumns;
this._HeadCellContents = new Array(nColumns);
this._HeadCellLegends = new Array(nColumns);
this._BodyCellContentTypes = new Array(nColumns);
this._HeadCellContentFilters = [];
this._BodyCellContents = [];
this._HTML = '';
this._isExport = isExport;
this._bShow = true;
}
CTable._ContentAttrs = {
string: 'left',
number: 'right',
button: 'center'
};
CTable.prototype.SetHeadCellContentFilters = function ( /* Content1, Content2, ... */) {
for (var i = 0; i < arguments.length; ++i)
if (arguments[i] != null)
this._HeadCellContentFilters.push(arguments[i]);
};
CTable.prototype.SetHeadCellContents = function ( /* Content1, Content2, ... */) {
for (var i = 0; i < this._nColumns; ++i)
this._HeadCellContents[i] = arguments[i] != null ? arguments[i] : "";
};
CTable.prototype.SetHeadCellLegends = function ( /* Content1, Content2, ... */) {
for (var i = 0; i < this._nColumns; ++i)
this._HeadCellLegends[i] = arguments[i] != null ? arguments[i] : "";
};
// Type: a string that is the property name of CTable::ContentAttrs
CTable.prototype.SetBodyCellContentTypes = function ( /* Type1, Type2, ... */) {
for (var i = 0; i < this._nColumns; ++i)
this._BodyCellContentTypes[i] =
arguments[i] != null ? CTable._ContentAttrs[arguments[i]] : "";
};
CTable.prototype.SetBodyCellContents = function ( /* Content1, Content2, ... */) {
var Contents = new Array(this._nColumns);
for (var i = 0; i < this._nColumns; ++i)
Contents[i] = arguments[i] != null ? arguments[i] : "";
this._BodyCellContents.push(Contents);
};
CTable.prototype.CreateHTML = function () {
function Factory(Id) {
return function () {
CTable.OnClickTitle(Id);
};
}
function FactoryFilter(tableid, rowId) {
return function () {
CTable.OnChangeFilter(tableid, rowId);
};
}
function FactorySort(tableid, colId, numberId) {
return function () {
CTable.OnChangeOrder(tableid, colId, numberId);
};
}
function FactoryShowDetail(rowId, activeRows) {
return function () {
activeRows = activeRows.sort(compare_id)
CTable.OnShowDetail(rowId, activeRows);
};
}
var tableid = "table_" + this._Id;
var outputDiv = document.createElement('div');
outputDiv.id = this._Id;
outputDiv.className = 'content';
var headerDiv = document.createElement('div');
outputDiv.appendChild(headerDiv);
headerDiv.className = 'stat_header';
headerDiv.style.textAlign = 'center';
var spanTitle = document.createElement('span');
spanTitle.className = "stat_title clickable";
headerDiv.appendChild(spanTitle);
spanTitle.innerHTML = this._Title;
if (this._isExport)
spanTitle.setAttribute('onclick', "ct('" + tableid + "');");
else
spanTitle.addEventListener("click", Factory(tableid), false);
var table = document.createElement("table");
table.className = "content_table";
table.style.margin = '0px auto';
table.id = tableid;
if (!this._bShow)
table.setAttribute('hide', 'hide');
outputDiv.appendChild(table);
var trHeader = table.insertRow(0);
trHeader.className = "content_table_header";
for (var i = 0; i < this._nColumns; ++i) {
var th = document.createElement("th");
th.className = "content_table stat_order";
th.id = 'th_' + this._Id + i;
th.setAttribute('order', '-1');
var thSpan = document.createElement("span");
thSpan.id = this._Id + "_col" + i;
thSpan.innerHTML = this._HeadCellContents[i];
th.appendChild(thSpan);
var legend = this._HeadCellLegends[i];
var infospan = document.createElement("span");
infospan.id = tableid + '_orderInfo_' + i;
infospan.innerHTML = '';
thSpan.appendChild(infospan);
if (legend) {
infospan.className = legend.className;
if (i > 0) {
thSpan.innerHTML = thSpan.innerHTML + '
';
thSpan.appendChild(legend);
var legends = legend.getElementsByTagName('span');
for (var li = 0; li < legends.length; li++) {
var l = legends[li];
l.className = "clickable";
if (this._isExport)
l.setAttribute('onclick', "co('" + tableid + "'," + i + "," + li + ");");
else
l.addEventListener("click", FactorySort(tableid, i, li), false);
}
}
else {
th.appendChild(legend);
var checkboxs = legend.getElementsByTagName('input');
for (var ti = 0; ti < checkboxs.length; ti++) {
var c = checkboxs[ti];
c.id = tableid + '_checkbox_' + i + '_' + ti;
if (this._isExport) {
c.setAttribute('onclick', "cf('" + tableid + "','" + this._filterId + "');");
c.setAttribute('checked', '');
}
else
c.addEventListener("click", FactoryFilter(tableid, this._filterId), false);
}
}
}
else {
thSpan.className = "clickable";
if (this._isExport)
thSpan.setAttribute('onclick', "co('" + tableid + "'," + i + ",0);");
else
thSpan.addEventListener("click", FactorySort(tableid, i, 0), false);
}
trHeader.appendChild(th);
}
if (useFilter) {
var trfilter = table.insertRow(-1);
trfilter.id = this._filterId;
trfilter.className = "content_table_filter_row";
for (var i = 0; i < this._nColumns - 1; ++i) {
var cell = trfilter.insertCell(-1);
if (this._HeadCellContentFilters != null) {
if (this._HeadCellContentFilters[i] != null) {
var filter = this._HeadCellContentFilters[i];
var comboboxid = this._filterId + "_combobox_" + i;
var combobox = document.createElement("select");
cell.appendChild(combobox);
combobox.id = comboboxid;
if (this._isExport)
combobox.setAttribute('onchange', "cf('" + tableid + "','" + this._filterId + "');");
else
combobox.addEventListener("change", FactoryFilter(tableid, this._filterId), false);
combobox.options.add(new Option(Local.Text_Table_AllData, i + '_' + 'all'));
for (var j = 0; j < filter.length; j++)
combobox.options.add(new Option(filter[j], i + '_' + j));
var comboboxOrg = combobox.cloneNode(true);
comboboxOrg.id = 'org_' + comboboxid;
comboboxOrg.style.display = 'none';
cell.appendChild(comboboxOrg);
}
else {
var input = document.createElement("input");
var textid = this._filterId + "_textbox_" + i;
input.type = "text";
input.size = 6;
input.id = textid;
cell.appendChild(input);
}
}
}
var searchButton = document.createElement("input");
searchButton.type = 'button';
searchButton.id = this._filterId + "_button";
searchButton.value = "查询";
searchButton.className = "button";
if (this._isExport)
searchButton.setAttribute('onclick', "cf('" + tableid + "','" + this._filterId + "');");
else
searchButton.addEventListener("click", FactoryFilter(tableid, this._filterId), false);
var buttonCell = trfilter.insertCell(-1);
buttonCell.appendChild(searchButton);
buttonCell.style.textAlign = 'center';
}
for (var i = 0; i < this._BodyCellContents.length; ++i) {
var row = table.insertRow(-1);
row.className = "row" + i % 2;
row.setAttribute('oriorder', i);
var rowId = [];
var infoRowid = tableid + '_' + i;
var infoNode;
for (var j = 0; j < this._nColumns; ++j) {
var rowspan = "";
var content = this._BodyCellContents[i][j];
if (content.show) {
var cell = row.insertCell(-1);
cell.className = "content_table";
cell.style.textAlign = this._BodyCellContentTypes[j];
if (content.rowspan > 1) {
cell.rowSpan = content.rowspan;
cell.style.verticalAlign = 'middle';
}
var valueNode = content.value;
cell.appendChild(valueNode);
if (j == this._nColumns - 1) {
if (this._isExport)
valueNode.setAttribute("onclick", "sd('" + infoRowid + "',['" + content.activeRows.join("','") + "']);");
else
valueNode.addEventListener("click", FactoryShowDetail(infoRowid, this._BodyCellContents[i][0].activeRows), false);
infoNode = valueNode.getAttribute('data');
valueNode.removeAttribute('data');
}
}
rowId.push(j + "_" + this._BodyCellContents[i][j].filterId);
}
row.id = rowId.join(",");
var infoRow = table.insertRow(-1);
infoRow.className = row.className;
infoRow.id = infoRowid;
infoRow.style.display = 'none';
var infoCell = infoRow.insertCell(-1);
infoCell.colSpan = this._nColumns;
if (infoNode) {
infoCell.innerHTML = infoNode;
}
}
return outputDiv;
//this._HTML = outputDiv.outerHTML;
//return this._HTML;
};
CTable.prototype.GetHTML = function () {
return this._HTML;
};
CTable.OnClickTitle = function (Id) {
try {
var Table = document.getElementById(Id);
if (Table.hasAttribute("hide")) {
Table.removeAttribute("hide");
} else {
Table.setAttribute("hide", "hide");
}
} catch (e) {
alert("CTable.OnClickTitle(): " + e);
}
};
CTable.GetNumber = function (cell) {
var numberPatten = /^\s?([\d]+\.?[\d]*)\s?_?\s?([\d]*\.?[\d]*)\s?$/;
var pairTable = cell.firstChild;
var numberString = cell.textContent;
var numbers;
if (pairTable && pairTable.nodeName == "TABLE") {
numberString = pairTable.id;
}
if (numberPatten.test(numberString)) {
numbers = [];
var numberres = numberPatten.exec(numberString);
if (numberres[1])
numbers.push(numberres[1]);
if (numberres[2])
numbers.push(numberres[2]);
}
return numbers;
};
CTable.OnChangeFilter = function (tableId, filterRowId) {
try {
var Table = document.getElementById(tableId);
var filterRow = document.getElementById(filterRowId);
var stringfilters = [];
var orgstringfilters = [];
var numberfilters = [];
var filterString = "";
var showIds = [];
var refilter = 0;
var showHero_0 = document.getElementById(tableId + "_checkbox_0_0");
var showHero_1 = document.getElementById(tableId + "_checkbox_0_1");
var showHero = [showHero_0.checked, showHero_1.checked];
for (var i = 0; i < filterRow.cells.length; i++) {
var cell = filterRow.cells[i];
var stringfilter = document.getElementById(filterRow.id + "_combobox_" + i);
var orgstringfilter = document.getElementById('org_' + filterRow.id + "_combobox_" + i);
var numberfilter = document.getElementById(filterRow.id + "_textbox_" + i);
if (stringfilter) {
stringfilters.push(stringfilter.value);
refilter += stringfilter.selectedIndex > 0 ? 1 : 0;
}
else
stringfilters.push(null);
if (orgstringfilter) {
for (var ii = 0, ij = orgstringfilter.options.length; ii < ij; ++ii) {
if (orgstringfilter.options[ii].value === stringfilter.value) {
orgstringfilter.selectedIndex = ii;
break;
}
}
orgstringfilters.push([stringfilter, orgstringfilter]);
showIds.push([]);
}
if (numberfilter)
numberfilters.push(numberfilter.value);
else
numberfilters.push(null);
}
var index = 0;
var patten = /([\(|\[|>|<|=|]*)\s*([\d]*\.?[\d]*)\s*-?\s*([\d]*\.?[\d]*)\s*([\)|\]|\s]?)/;
for (var i = 2; i < Table.rows.length; i = i + 2) {
var row = Table.rows[i];
var rowInfo = Table.rows[i + 1];
var rowIds = row.id.split(",");
var show = true;
var hero = row.cells[0].getElementsByTagName('a')[0];
var heroKind = hero.getAttribute("kind");
show = showHero[heroKind];
if (show) {
for (var fi = 0; fi < stringfilters.length; fi++) {
var sfilter = stringfilters[fi];
if (!sfilter)
continue;
if (sfilter != fi + "_all" && sfilter != rowIds[fi]) {
show = false;
break;
}
}
}
if (show) {
for (var fi = 0; fi < numberfilters.length; fi++) {
var nfilter = numberfilters[fi];
if (!nfilter)
continue;
else {
var numbers = CTable.GetNumber(row.cells[fi]);
var nfilters = nfilter.split(/\s*[,|,]\s*/);
for (ni = 0; ni < numbers.length; ni++) {
var theFilter = nfilters[ni];
var testString = "";
if (theFilter && patten.test(theFilter)) {
var op = "==";
var res = patten.exec(theFilter);
if (res[1]) {
op = res[1];
if (res[3]) {
if (op == "[") op = ">=";
if (op == "(") op = ">";
if (op == "=") op = "==";
}
}
else {
if (res[3])
op = ">=";
}
testString = numbers[ni] + op + res[2];
if (res[3]) {
op = "<=";
if (res[4]) {
op = res[4];
if (op == "]") op = "<=";
if (op == ")") op = "<";
}
testString += " && " + numbers[ni] + op + res[3];
}
show = eval(testString);
if (!show)
break;
}
}
}
if (!show)
break;
}
}
row.style.display = show ? '' : 'none';
rowInfo.style.display = show ? rowInfo.style.display : 'none';
if (show) {
row.className = "row" + index % 2;
rowInfo.className = row.className;
index++;
for (var fi = 0; fi < orgstringfilters.length; fi++) {
var id = rowIds[fi];
if (showIds[fi].indexOf(id) <= -1)
showIds[fi].push(id);
}
}
}
if (orgstringfilters.length - refilter > 1) {
for (var fi = 0; fi < orgstringfilters.length; fi++) {
var sfilter = orgstringfilters[fi][0];
var sfilterorg = orgstringfilters[fi][1];
if (!sfilter)
continue;
if (refilter == 1 && sfilter.selectedIndex > 0)
continue;
for (var i = sfilter.options.length - 1; i > 0; i--)
sfilter.remove(i);
for (var i = 0; i < sfilterorg.options.length; i++) {
var opt = sfilterorg.options[i];
if (showIds[fi].indexOf(opt.value) > -1) {
var newopt = new Option(opt.text, opt.value);
newopt.selected = opt.selected;
sfilter.add(newopt);
}
}
}
}
} catch (e) {
alert("CTable.OnChangeFilter(): " + e);
}
};
CTable.OnChangeOrder = function (tableId, columnIndex, numberIndex) {
var Table = document.getElementById(tableId);
var index = numberIndex;
var ths = Table.getElementsByTagName("th");
if (index === null)
index = 0;
var th = ths[columnIndex];
var order = th.getAttribute("order");
for (var i = 0; i < ths.length - 1; i++) {
var span = document.getElementById(tableId + '_orderInfo_' + i);
var spans = span.getElementsByTagName('span');
if (spans && spans.length == 2) {
spans[0].innerHTML = '';
spans[1].innerHTML = '';
if (i == columnIndex)
spans[numberIndex].innerHTML = order > 0 ? '▲' : '▼';
}
}
for (var i = 2; i < Table.rows.length - 2; i = i + 2) {
for (var j = i + 2; j < Table.rows.length; j = j + 2) {
var row_1 = Table.rows[i];
var row_1_info = Table.rows[i + 1];
var row_2 = Table.rows[j];
var row_2_info = Table.rows[j + 1];
var cell_1 = row_1.cells[columnIndex];
var cell_2 = row_2.cells[columnIndex];
n1 = CTable.GetNumber(cell_1);
n2 = CTable.GetNumber(cell_2);
var change = false;
if (columnIndex == ths.length - 1) {
var n11 = Number(row_1.getAttribute("oriorder"));
var n12 = Number(row_2.getAttribute("oriorder"));
change = n11 > n12;
}
else {
var c1 = row_1.cells[0].firstChild.className.replace("my", "");
var c2 = row_2.cells[0].firstChild.className.replace("my", "");
var s1 = cell_1.textContent;
var s2 = cell_2.textContent;
var cc = CompareString(c1, c2);
if (cc < 0)
change = false;
else if (cc > 0)
change = true;
else {
if (n1 && n2 && n1.length > 0 && n2.length > 0) {
var number_1 = n1[index] * order;
var number_2 = n2[index] * order;
change = number_1 > number_2;
}
else
change = (CompareString(s1, s2) == order);
}
}
if (change) {
row_2.parentNode.insertBefore(row_2, row_1);
row_2_info.parentNode.insertBefore(row_2_info, row_1);
}
}
Table.rows[i].className = "row" + (i / 2) % 2;
Table.rows[i + 1].className = Table.rows[i].className;
}
th.setAttribute("order", -1 * order);
};
CTable.OnShowDetail = function (rowid, activeRows) {
var row = document.getElementById(rowid);
var cell = row.cells[0];
var button = row.previousSibling.getElementsByTagName('input')[0];
activeRows = activeRows || [];
if (cell) {
if (row.style.display == '') {
button.value = '显示';
row.style.display = 'none';
}
else {
button.value = '隐藏';
row.style.display = '';
}
var table = cell.getElementsByTagName('table')[0];
if (table.rows.length <= 1) {
if (activeRows.length > 0) {
var ids = activeRows[0].split('_');
var level = Number(ids[1]);
var ac = table.insertRow(-1).insertCell(-1);
ac.colSpan = '3';
ac.innerHTML = '