From c865a3a9a42c6a2d9acfdf0b80a09111e5bb53f0 Mon Sep 17 00:00:00 2001 From: Sarjuuk Date: Fri, 14 Mar 2014 16:32:15 +0100 Subject: [PATCH] Profiler - draft MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit basic stuff is working with examplary static data need to sit down and collect mods from talents and class-spells from profession perks loadOnDemandData not implemented as the structure needs more research some visual bugs remember to generate your realm-file. i used these example realms [ ["us","US & Oceanic",null,[["pure-pwnage","Pure Pwnage",null,[["trinity","Trinity"]]]]], ["eu","Europe",null,[["pure-pwnage","Pure Pwnage",null,[["dafuque","da'Fuqú]]] ] --- data.php | 24 +- includes/defines.php | 15 +- includes/types/achievement.class.php | 7 +- includes/types/basetype.class.php | 17 +- includes/types/item.class.php | 9 + includes/types/spell.class.php | 125 +- localization/locale_enus.php | 9 +- pages/item.php | 31 +- pages/items.php | 20 +- pages/profile.php | 617 + pages/profiles.php | 164 + power/aowowPower.js | 11 +- search.php | 22 +- setup/tools/dataset/statistics.php | 140 + template/bricks/listviews/achievement.tpl | 2 +- template/bricks/listviews/character.tpl | 28 + template/bricks/listviews/profile.tpl | 56 + template/bricks/redButtons.tpl | 8 +- template/css/Profiler.css | 927 ++ template/css/global.css | 178 +- template/images/Profiler/button-grey.png | Bin 0 -> 2294 bytes .../images/Profiler/character-header-bg.gif | Bin 0 -> 1106 bytes template/images/Profiler/disabled_classes.png | Bin 0 -> 15710 bytes template/images/Profiler/error.png | Bin 0 -> 2858 bytes template/images/Profiler/jumpto.png | Bin 0 -> 3639 bytes template/images/Profiler/lookup.gif | Bin 0 -> 982 bytes template/images/Profiler/search.2.png | Bin 0 -> 851 bytes template/images/Profiler/search.png | Bin 0 -> 1088 bytes template/images/Profiler/text-input.2.png | Bin 0 -> 3059 bytes template/images/Profiler/text-input.png | Bin 0 -> 483 bytes template/images/Profiler/toggle-b.2.png | Bin 0 -> 1101 bytes template/images/Profiler/toggle-b.png | Bin 0 -> 3986 bytes template/images/Profiler/toggle.2.png | Bin 0 -> 3785 bytes template/images/Profiler/toggle.png | Bin 0 -> 3975 bytes template/images/cog.gif | Bin 0 -> 655 bytes template/item.tpl | 3 + template/js/Book.js | 99 + template/js/Profiler.js | 10059 ++++++++++++++++ template/js/locale_enus.js | 283 +- template/js/profile.js | 806 ++ template/profile.tpl | 40 + template/profiles.tpl | 114 + 42 files changed, 13685 insertions(+), 129 deletions(-) create mode 100644 pages/profile.php create mode 100644 pages/profiles.php create mode 100644 setup/tools/dataset/statistics.php create mode 100644 template/bricks/listviews/character.tpl create mode 100644 template/bricks/listviews/profile.tpl create mode 100644 template/css/Profiler.css create mode 100644 template/images/Profiler/button-grey.png create mode 100644 template/images/Profiler/character-header-bg.gif create mode 100644 template/images/Profiler/disabled_classes.png create mode 100644 template/images/Profiler/error.png create mode 100644 template/images/Profiler/jumpto.png create mode 100644 template/images/Profiler/lookup.gif create mode 100644 template/images/Profiler/search.2.png create mode 100644 template/images/Profiler/search.png create mode 100644 template/images/Profiler/text-input.2.png create mode 100644 template/images/Profiler/text-input.png create mode 100644 template/images/Profiler/toggle-b.2.png create mode 100644 template/images/Profiler/toggle-b.png create mode 100644 template/images/Profiler/toggle.2.png create mode 100644 template/images/Profiler/toggle.png create mode 100644 template/images/cog.gif create mode 100644 template/js/Book.js create mode 100644 template/js/Profiler.js create mode 100644 template/js/profile.js create mode 100644 template/profile.tpl create mode 100644 template/profiles.tpl diff --git a/data.php b/data.php index b3e0efd7..56ae754d 100644 --- a/data.php +++ b/data.php @@ -15,15 +15,36 @@ foreach ($datasets as $data) { switch ($data) { + // Profiler + case 'factions': + case 'quests': + case 'companions': + case 'recipes': + case 'mounts': + if (empty($_GET['callback']) || empty($_GET['t'])) + break; + + $token = intVal($_GET['t']); + $callback = $_GET['callback']; + if (!$token || substr($callback, 0, 17) != '$WowheadProfiler.') + break; + +/* + get data via token: + > echo data in unknown format here + echo '$WowheadProfiler.loadOnDemand('.$data.', );'; +*/ + break; // locale independant case 'zones': case 'weight-presets': case 'item-scaling': case 'realms': + case 'statistics': if (file_exists('datasets/'.$data)) echo file_get_contents('datasets/'.$data); else if ($AoWoWconf['debug']) - echo "/* could not fetch static data: ".$data." */"; + echo "alert('could not fetch static data: ".$data."');"; echo "\n\n"; break; case 'user': @@ -50,6 +71,7 @@ foreach ($datasets as $data) echo "alert('could not fetch static data: ".$data.$params." for locale: ".User::$localeString."');"; echo "\n\n"; break; + case 'quick-excludes': // generated per character in profiler default: break; } diff --git a/includes/defines.php b/includes/defines.php index cbccd130..12a63ad3 100644 --- a/includes/defines.php +++ b/includes/defines.php @@ -87,7 +87,7 @@ define('LOCALE_DE', 3); define('LOCALE_ES', 6); define('LOCALE_RU', 8); -// red buttons on the top of the page (ASC:: right -> left) +// red buttons on the top of the page define('BUTTON_WOWHEAD', 0); define('BUTTON_UPGRADE', 1); define('BUTTON_COMPARE', 2); @@ -95,6 +95,7 @@ define('BUTTON_VIEW3D', 3); define('BUTTON_LINKS', 4); define('BUTTON_FORUM', 5); define('BUTTON_TALENT', 6); +define('BUTTON_EQUIP', 7); // generic filter handler define('FILTER_CR_BOOLEAN', 1); @@ -121,6 +122,8 @@ define('ITEMINFO_MODEL', 0x20); define('NPCINFO_TAMEABLE', 0x1); define('NPCINFO_MODEL', 0x2); +define('ACHIEVEMENTINFO_PROFILE', 0x1); + define('SPAWNINFO_ZONES', 1); // not a mask, mutually exclusive define('SPAWNINFO_SHORT', 2); define('SPAWNINFO_FULL', 3); @@ -163,6 +166,14 @@ define('OBJECT_CU_NOT_PERSISTANT', 0x80); define('NPC_CU_INSTANCE_BOSS', 0x01); define('NPC_CU_DIFFICULTY_DUMMY', 0x02); +define('NPC_CU_DUNGEON_ENCOUNTER', 0x04); + +// as seen in wFlags +define('QUEST_CU_REPEATABLE', 0x01); +define('QUEST_CU_DAILY', 0x02); +define('QUEST_CU_WEEKLY', 0x04); +define('QUEST_CU_SEASONAL', 0x08); +define('QUEST_CU_SKIP_LOG', 0x10); // no idea... define('MAX_LEVEL', 80); @@ -341,6 +352,8 @@ define('NPC_FLAG_CLASS_TRAINER', 0x00000020); define('NPC_FLAG_VENDOR', 0x00000080); define('NPC_FLAG_REPAIRER', 0x00001000); define('NPC_FLAG_FLIGHT_MASTER', 0x00002000); +define('NPC_FLAG_SPIRIT_HEALER', 0x00004000); // civil +define('NPC_FLAG_SPIRIT_GUIDE', 0x00008000); // battleground define('NPC_FLAG_INNKEEPER', 0x00010000); define('NPC_FLAG_BANKER', 0x00020000); define('NPC_FLAG_GUILD_MASTER', 0x00080000); diff --git a/includes/types/achievement.class.php b/includes/types/achievement.class.php index ae0273b0..045e2e76 100644 --- a/includes/types/achievement.class.php +++ b/includes/types/achievement.class.php @@ -68,7 +68,7 @@ class AchievementList extends BaseType } } - public function getListviewData() + public function getListviewData($addInfoMask = 0x0) { $data = []; @@ -81,9 +81,12 @@ class AchievementList extends BaseType 'points' => $this->curTpl['points'], 'faction' => $this->curTpl['faction'], 'category' => $this->curTpl['category'], - 'parentCat' => $this->curTpl['parentCat'], + 'parentcat' => $this->curTpl['parentCat'], ); + if ($addInfoMask & ACHIEVEMENTINFO_PROFILE) + $data[$this->id]['icon'] = $this->curTpl['iconString']; + // going out on a limb here: type = 1 if in level 3 of statistics tree, so, IF (statistic AND parentCat NOT statistic (1)) i guess if ($this->curTpl['flags'] & ACHIEVEMENT_FLAG_COUNTER && $this->curTpl['parentCat'] != 1) $data[$this->id]['type'] = 1; diff --git a/includes/types/basetype.class.php b/includes/types/basetype.class.php index 1a394201..c1c3f204 100644 --- a/includes/types/basetype.class.php +++ b/includes/types/basetype.class.php @@ -297,6 +297,14 @@ abstract class BaseType } // read-access to templates + public function getEntry($id) + { + if (isset($this->templates[$id])) + return $this->templates[$id]; + + return null; + } + public function getField($field, $localized = false) { if (!$this->curTpl || (!$localized && !isset($this->curTpl[$field]))) @@ -306,7 +314,14 @@ abstract class BaseType return Util::localizedString($this->curTpl, $field); $value = $this->curTpl[$field]; - return Util::checkNumeric($value) ? floatVal($value) : $value; + if (Util::checkNumeric($value)) + { + $intVal = intVal($value); + $floatVal = floatVal($value); + return $intVal == $floatVal ? $intVal : $floatVal; + } + else + return $value; } public function getRandomId() diff --git a/includes/types/item.class.php b/includes/types/item.class.php index 89023732..dc7aefd4 100644 --- a/includes/types/item.class.php +++ b/includes/types/item.class.php @@ -1884,6 +1884,15 @@ class ItemListFilter extends Filter // upgrade for [form only] if (isset($_v['upg'])) { + /* notice! + profiler can send $_GET['upg'] as an array + this should results in in N listviews-sets (weapons generate more more than one listview per slot) for N items +
+
+ var tabsGroups = new Tabs({parent: $WH.ge('jkbfksdbl4')}); + {template: 'item', id: 'ranged', name: 'Ranged', tabs: tabsGroups, parent: 'lkljbjkb574', hideCount: 1, note: $WH.sprintf(LANG.lvnote_viewmoreslot, '', 'sl=15;maxrl=80;si=1;ub=1;cr=161;crs=1;crv=0;upg=45498'), customFilter: fi_filterUpgradeListview, _upgradeIds: [45498], extraCols: fi_getExtraCols(fi_extraCols, 0, 0, 0), onAfterCreate: fi_addUpgradeIndicator, data:[]} + */ + // valid item? if (!is_int($_v['upg'])) unset($_v['upg']); diff --git a/includes/types/spell.class.php b/includes/types/spell.class.php index 78e9eefa..9bfca507 100644 --- a/includes/types/spell.class.php +++ b/includes/types/spell.class.php @@ -146,9 +146,9 @@ class SpellList extends BaseType for ($i = 1; $i <= 3; $i++) { - $mv = $this->curTpl['effect'.$i.'MiscValue']; - $bp = $this->curTpl['effect'.$i.'BasePoints'] + 1; - $au = $this->curTpl['effect'.$i.'AuraId']; + $pts = $this->calculateAmountForCurrent($i)[1]; + $mv = $this->curTpl['effect'.$i.'MiscValue']; + $au = $this->curTpl['effect'.$i.'AuraId']; // Enchant Item Permanent (53) / Temporary (54) if (in_array($this->curTpl['effect'.$i.'Id'], [53, 54])) @@ -159,10 +159,6 @@ class SpellList extends BaseType continue; } - // Aura Effects - if (!in_array($au, [8, 13, 22, 29, 34, 35, 83, 84, 85, 99, 124, 135, 143, 158, 161, 189, 220, 230, 235, 240, 250])) - continue; - switch ($au) { case 29: // ModStat MiscVal:type @@ -170,10 +166,10 @@ class SpellList extends BaseType if ($mv < 0) // all stats { for ($j = 0; $j < 5; $j++) - @$stats[ITEM_MOD_AGILITY + $j] += $bp; + @$stats[ITEM_MOD_AGILITY + $j] += $pts; } else // one stat - @$stats[ITEM_MOD_AGILITY + $mv] += $bp; + @$stats[ITEM_MOD_AGILITY + $mv] += $pts; break; } @@ -181,7 +177,7 @@ class SpellList extends BaseType case 230: case 250: { - @$stats[ITEM_MOD_HEALTH] += $bp; + @$stats[ITEM_MOD_HEALTH] += $pts; break; } case 13: // damage splpwr + physical (dmg & any) @@ -189,80 +185,80 @@ class SpellList extends BaseType // + weapon damage if ($mv == (1 << SPELL_SCHOOL_NORMAL)) { - @$stats[ITEM_MOD_WEAPON_DMG] += $bp; + @$stats[ITEM_MOD_WEAPON_DMG] += $pts; break; } // full magic mask, also counts towards healing if ($mv == 0x7E) { - @$stats[ITEM_MOD_SPELL_POWER] += $bp; - @$stats[ITEM_MOD_SPELL_DAMAGE_DONE] += $bp; + @$stats[ITEM_MOD_SPELL_POWER] += $pts; + @$stats[ITEM_MOD_SPELL_DAMAGE_DONE] += $pts; } else { // HolySpellpower (deprecated; still used in randomproperties) if ($mv & (1 << SPELL_SCHOOL_HOLY)) - @$stats[ITEM_MOD_HOLY_POWER] += $bp; + @$stats[ITEM_MOD_HOLY_POWER] += $pts; // FireSpellpower (deprecated; still used in randomproperties) if ($mv & (1 << SPELL_SCHOOL_FIRE)) - @$stats[ITEM_MOD_FIRE_POWER] += $bp; + @$stats[ITEM_MOD_FIRE_POWER] += $pts; // NatureSpellpower (deprecated; still used in randomproperties) if ($mv & (1 << SPELL_SCHOOL_NATURE)) - @$stats[ITEM_MOD_NATURE_POWER] += $bp; + @$stats[ITEM_MOD_NATURE_POWER] += $pts; // FrostSpellpower (deprecated; still used in randomproperties) if ($mv & (1 << SPELL_SCHOOL_FROST)) - @$stats[ITEM_MOD_FROST_POWER] += $bp; + @$stats[ITEM_MOD_FROST_POWER] += $pts; // ShadowSpellpower (deprecated; still used in randomproperties) if ($mv & (1 << SPELL_SCHOOL_SHADOW)) - @$stats[ITEM_MOD_SHADOW_POWER] += $bp; + @$stats[ITEM_MOD_SHADOW_POWER] += $pts; // ArcaneSpellpower (deprecated; still used in randomproperties) if ($mv & (1 << SPELL_SCHOOL_ARCANE)) - @$stats[ITEM_MOD_ARCANE_POWER] += $bp; + @$stats[ITEM_MOD_ARCANE_POWER] += $pts; } break; } case 135: // healing splpwr (healing & any) .. not as a mask.. { - @$stats[ITEM_MOD_SPELL_HEALING_DONE] += $bp; + @$stats[ITEM_MOD_SPELL_HEALING_DONE] += $pts; break; } case 35: // ModPower - MiscVal:type see defined Powers only energy/mana in use { if ($mv == POWER_HEALTH) - @$stats[ITEM_MOD_HEALTH] += $bp; + @$stats[ITEM_MOD_HEALTH] += $pts; if ($mv == POWER_ENERGY) - @$stats[ITEM_MOD_ENERGY] += $bp; + @$stats[ITEM_MOD_ENERGY] += $pts; else if ($mv == POWER_MANA) - @$stats[ITEM_MOD_MANA] += $bp; + @$stats[ITEM_MOD_MANA] += $pts; else if ($mv == POWER_RUNIC_POWER) - @$stats[ITEM_MOD_RUNIC_POWER] += $bp; + @$stats[ITEM_MOD_RUNIC_POWER] += $pts; break; } case 189: // CombatRating MiscVal:ratingMask case 220: if ($mod = Util::itemModByRatingMask($mv)) - @$stats[$mod] += $bp; + @$stats[$mod] += $pts; break; case 143: // Resistance MiscVal:school case 83: case 22: if ($mv == 1) // Armor only if explicitly specified { - @$stats[ITEM_MOD_ARMOR] += $bp; + @$stats[ITEM_MOD_ARMOR] += $pts; break; } if ($mv == 2) // holy-resistance ONLY if explicitly specified (shouldn't even exist...) { - @$stats[ITEM_MOD_HOLY_RESISTANCE] += $bp; + @$stats[ITEM_MOD_HOLY_RESISTANCE] += $pts; break; } @@ -274,19 +270,19 @@ class SpellList extends BaseType switch ($j) { case 2: - @$stats[ITEM_MOD_FIRE_RESISTANCE] += $bp; + @$stats[ITEM_MOD_FIRE_RESISTANCE] += $pts; break; case 3: - @$stats[ITEM_MOD_NATURE_RESISTANCE] += $bp; + @$stats[ITEM_MOD_NATURE_RESISTANCE] += $pts; break; case 4: - @$stats[ITEM_MOD_FROST_RESISTANCE] += $bp; + @$stats[ITEM_MOD_FROST_RESISTANCE] += $pts; break; case 5: - @$stats[ITEM_MOD_SHADOW_RESISTANCE] += $bp; + @$stats[ITEM_MOD_SHADOW_RESISTANCE] += $pts; break; case 6: - @$stats[ITEM_MOD_ARCANE_RESISTANCE] += $bp; + @$stats[ITEM_MOD_ARCANE_RESISTANCE] += $pts; break; } } @@ -294,22 +290,22 @@ class SpellList extends BaseType case 8: // hp5 case 84: case 161: - @$stats[ITEM_MOD_HEALTH_REGEN] += $bp; + @$stats[ITEM_MOD_HEALTH_REGEN] += $pts; break; case 85: // mp5 - @$stats[ITEM_MOD_MANA_REGENERATION] += $bp; + @$stats[ITEM_MOD_MANA_REGENERATION] += $pts; break; case 99: // atkpwr - @$stats[ITEM_MOD_ATTACK_POWER] += $bp; + @$stats[ITEM_MOD_ATTACK_POWER] += $pts; break; // ?carries over to rngatkpwr? case 124: // rngatkpwr - @$stats[ITEM_MOD_RANGED_ATTACK_POWER] += $bp; + @$stats[ITEM_MOD_RANGED_ATTACK_POWER] += $pts; break; case 158: // blockvalue - @$stats[ITEM_MOD_BLOCK_VALUE] += $bp; + @$stats[ITEM_MOD_BLOCK_VALUE] += $pts; break; case 240: // ModExpertise - @$stats[ITEM_MOD_EXPERTISE_RATING] += $bp; + @$stats[ITEM_MOD_EXPERTISE_RATING] += $pts; break; } } @@ -320,6 +316,42 @@ class SpellList extends BaseType return $data; } + public function getProfilerMods() + { + $data = $this->getStatGain(); // flat gains + + foreach ($this->iterate() as $id => $__) + { + for ($i = 1; $i < 4; $i++) + { + $pts = $this->calculateAmountForCurrent($i)[1]; + $mv = $this->curTpl['effect'.$i.'MiscValue']; + $au = $this->curTpl['effect'.$i.'AuraId']; + + /* ISSUE! + mods formated like ['' => [, 'percentOf', '']] are applied as multiplier and not + as a flat value (that is equal to the percentage, like they should be). So the stats-tabe won't show the actual deficit + */ + + switch ($this->curTpl['effect'.$i.'AuraId']) + { + case 101: + $data[$id][] = ['armor' => [$pts / 100, 'percentOf', 'armor']]; + break; + case 13: // damage done flat + // per magic school, omit physical + break; + case 30: // mod skill + // diff between character skills and trade skills + break; + case 36: // shapeshift + } + } + } + + return $data; + } + // halper public function getReagentsForCurrent() { @@ -773,14 +805,14 @@ class SpellList extends BaseType // Aura giving combat ratings $rType = 0; - if (in_array($aura, [189, 220])) + if ($aura == 189) if ($rType = Util::itemModByRatingMask($mv)) $usesScalingRating = true; // Aura end - if ($rType && $this->interactive) + if ($rType && $this->interactive && $aura == 189) return ''.abs($base).' ('.sprintf(Util::$setRatingLevelString, $this->charLevel, $rType, abs($base), Util::setRatingLevel($this->charLevel, $rType, abs($base))).')'; - else if ($rType) + else if ($rType && $aura == 189) return ''.abs($base).' ('.Util::setRatingLevel($this->charLevel, $rType, abs($base)).')'; else return $base; @@ -872,16 +904,16 @@ class SpellList extends BaseType // Aura giving combat ratings $rType = 0; - if (in_array($aura, [189, 220])) + if ($aura == 189) if ($rType = Util::itemModByRatingMask($mv)) $usesScalingRating = true; // Aura end - if ($rType && $equal && $this->interactive) + if ($rType && $equal && $this->interactive && $aura == 189) return ''.$min.' ('.sprintf(Util::$setRatingLevelString, $this->charLevel, $rType, $min, Util::setRatingLevel($this->charLevel, $rType, $min)).')'; - else if ($rType && $equal) + else if ($rType && $equal && $aura == 189) return ''.$min.' ('.Util::setRatingLevel($this->charLevel, $rType, $min).')'; - else if ($this->interactive) + else if ($this->interactive && $aura == 189) return $modStrMin.$min . (!$equal ? Lang::$game['valueDelim'] . $modStrMax.$max : null); else return $min . (!$equal ? Lang::$game['valueDelim'] . $max : null); @@ -1069,7 +1101,7 @@ class SpellList extends BaseType $g / $G - Gender-Switch $Gmale:female; $h / $H - ProcChance $i - MaxAffectedTargets - $l - LastValue-Switch; last value as condiition $Ltrue:false; + $l - LastValue-Switch; last value as condition $Ltrue:false; $m / $M - BasePoints; per EffectIdx; m/M +1/+effectDieSides $n - ProcCharges $o - TotalAmount (for periodic auras); per EffectIdx @@ -1577,6 +1609,7 @@ Lasts 5 min. $?$gte($pl,68)[][Cannot be used on items level 138 and higher.] 'skill' => count($this->curTpl['skillLines']) > 4 ? array_merge(array_splice($this->curTpl['skillLines'], 0, 4), [-1]): $this->curTpl['skillLines'], // display max 4 skillLines (fills max three lines in listview) 'reagents' => array_values($this->getReagentsForCurrent()), 'source' => [] + // 'talentspec' => $this->curTpl['skillLines'][0] not used: g_chr_specs has the wrong structure for it; also setting .cat and .type does the same ); // Sources diff --git a/localization/locale_enus.php b/localization/locale_enus.php index 04ee60b5..b2200c36 100644 --- a/localization/locale_enus.php +++ b/localization/locale_enus.php @@ -261,7 +261,8 @@ $lang = array( 'focusDesc' => "Spells requiring this Focus can be cast near this Object", 'trap' => "Trap", 'triggeredBy' => "Triggered by", - 'capturePoint' => "Capture Point" + 'capturePoint' => "Capture Point", + 'foundIn' => "This object can be found in" ), 'npc' => array( 'classification'=> "Classification", @@ -279,6 +280,7 @@ $lang = array( 'melee' => "Melee", 'ranged' => "Ranged", 'armor' => "Armor", + 'foundIn' => "This NPC can be found in", 'rank' => [0 => "Normal", 1 => "Elite", 4 => "Rare", 2 => "Rare Elite", 3 => "Boss"], 'textTypes' => [null, "yells", "says", "whispers"], 'modes' => array( @@ -328,6 +330,7 @@ $lang = array( 'Miscellaneous' => "Miscellaneous", 'Azeroth' => "Azeroth", 'CosmicMap' => "Cosmic Map", + 'selectorLink' => " and ", ), 'zone' => array( // 'zone' => "Zone", @@ -526,8 +529,8 @@ $lang = array( ), 'combatRating' => array( "Weapon Skill", "Defense Skill", "Dodge", "Parry", "Block", - "Melee Hit Chance", "Ranged Hit Chance", "Spell Hit Chance", "Casting Melee Hit Chance", "Casting Ranged Hit Chance", - "Casting Spell Hit Chance", "Taken Melee Hit Chance", "Taken Ranged Hit Chance", "Taken Spell Hit Chance", "Taken Critical Melee Hit Chance", + "Melee Hit Chance", "Ranged Hit Chance", "Spell Hit Chance", "Critical Melee Hit Chance", "Critical Ranged Hit Chance", + "Critical Spell Hit Chance", "Taken Melee Hit Chance", "Taken Ranged Hit Chance", "Taken Spell Hit Chance", "Taken Critical Melee Hit Chance", "Taken Critical Ranged Hit Chance", "Taken Critical Spell Hit Chance", "Melee Haste", "Ranged Haste", "Spell Haste", "Mainhand Weapon Skill", "Offhand Weapon Skill", "Ranged Weapon Skill", "Expertise", "Armor Penetration" ), diff --git a/pages/item.php b/pages/item.php index 782cd15d..64fc7caf 100644 --- a/pages/item.php +++ b/pages/item.php @@ -11,7 +11,11 @@ require 'includes/community.class.php'; $_id = intVal($pageParam); $_path = [0, 0]; -$_visSlots = [SLOT_HEAD, SLOT_SHOULDERS, SLOT_SHIRT, SLOT_CHEST, SLOT_WAIST, SLOT_LEGS, SLOT_FEET, SLOT_WRISTS, SLOT_HANDS, SLOT_BACK, SLOT_MAIN_HAND, SLOT_OFF_HAND, SLOT_RANGED, SLOT_TABARD]; +$_visSlots = array( + INVTYPE_HEAD, INVTYPE_SHOULDERS, INVTYPE_BODY, INVTYPE_CHEST, INVTYPE_WAIST, INVTYPE_LEGS, INVTYPE_FEET, INVTYPE_WRISTS, + INVTYPE_HANDS, INVTYPE_WEAPON, INVTYPE_SHIELD, INVTYPE_RANGED, INVTYPE_CLOAK, INVTYPE_2HWEAPON, INVTYPE_TABARD, INVTYPE_ROBE, + INVTYPE_WEAPONMAINHAND, INVTYPE_WEAPONOFFHAND, INVTYPE_HOLDABLE, INVTYPE_THROWN, INVTYPE_RANGEDRIGHT +); $cacheKeyPage = implode('_', [CACHETYPE_PAGE, TYPE_ITEM, $_id, -1, User::$localeId]); @@ -73,7 +77,7 @@ if (!$smarty->loadCache($cacheKeyPage, $item)) { $item = new ItemList(array(['i.id', $_id])); if ($item->error) - $smarty->notFound(Lang::$game['item']); + $smarty->notFound(Lang::$game['item'], $_id); $item->addGlobalsToJscript($smarty, GLOBALINFO_EXTRA | GLOBALINFO_SELF); @@ -317,6 +321,7 @@ if (!$smarty->loadCache($cacheKeyPage, $item)) BUTTON_LINKS => ['color' => 'ff'.Util::$rarityColorStings[$item->getField('quality')], 'linkId' => 'item:'.$_id.':0:0:0:0:0:0:0:0'], BUTTON_VIEW3D => $view3D ? ['displayId' => $item->getField('displayId'), 'slot' => $_slot, 'type' => TYPE_ITEM, 'typeId' => $_id] : false, BUTTON_COMPARE => $cmpUpg, // bool required + BUTTON_EQUIP => $cmpUpg, BUTTON_UPGRADE => $cmpUpg ? ['class' => $_class, 'slot' => $_slot] : false ), ), @@ -348,19 +353,19 @@ if (!$smarty->loadCache($cacheKeyPage, $item)) } // factionchange-equivalent - $pendant = DB::Aowow()->selectCell('SELECT IF(horde_id = ?d, alliance_id, -horde_id) FROM player_factionchange_items WHERE alliance_id = ?d OR horde_id = ?d', $_id, $_id, $_id); - if ($pendant) + if ($pendant = DB::Aowow()->selectCell('SELECT IF(horde_id = ?d, alliance_id, -horde_id) FROM player_factionchange_items WHERE alliance_id = ?d OR horde_id = ?d', $_id, $_id, $_id)) { $altItem = new ItemList(array(['id', abs($pendant)])); if (!$altItem->error) { - $pageData['page']['transfer'] = array( - 'id' => $altItem->id, - 'quality' => $altItem->getField('quality'), - 'icon' => $altItem->getField('iconString'), - 'name' => $altItem->getField('name', true), - 'facInt' => $pendant > 0 ? 'alliance' : 'horde', - 'facName' => $pendant > 0 ? Lang::$game['si'][1] : Lang::$game['si'][2] + $pageData['page']['transfer'] = sprintf( + Lang::$item['_transfer'], + $altItem->id, + $altItem->getField('quality'), + $altItem->getField('iconString'), + $altItem->getField('name', true), + $pendant > 0 ? 'alliance' : 'horde', + $pendant > 0 ? Lang::$game['si'][1] : Lang::$game['si'][2] ); } } @@ -743,10 +748,10 @@ if (!$smarty->loadCache($cacheKeyPage, $item)) $currency[] = [-$id, $qty]; } - $row['stock'] = $vendors[$k]['maxcount']; + $row['stock'] = $vendors[$k]['stock']; $row['cost'] = [$item->getField('buyPrice')]; - if ($e = $vendors[$k]['eventId']) + if ($e = $vendors[$k]['event']) { if (count($extraCols) == 3) $extraCols[] = 'Listview.extraCols.condition'; diff --git a/pages/items.php b/pages/items.php index aabb3463..ca622f01 100644 --- a/pages/items.php +++ b/pages/items.php @@ -168,7 +168,11 @@ if (!$smarty->loadCache($cacheKey, $pageData, $filter)) * Filter is used as a subSystem to each TypeList * but here we would need to preemptive check for $filter['gb'] * .. bummer .. this is to be removed when the issue is _really_ solved + * + * ALSO upgradeItems .. Profiler can send them as lists, so multiple lv-tabs would occur + * */ + if (preg_match('/gb\=(1|2|3)/i', $_SERVER['QUERY_STRING'], $match)) $filter['gb'] = $match[1]; @@ -226,14 +230,16 @@ if (!$smarty->loadCache($cacheKey, $pageData, $filter)) // upgrade-item got deleted by filter if (empty($pageData['lv']['data'][$filter['upg']])) { - $w = $items->filterGetForm('setWeights', true); - $upgItem = new ItemList(array(['id', $filter['upg']]), false, ['wt' => $w[0], 'wtv' => $w[1]]); - - // still it may not be found if you apply really weired filters (e.g. search for a melee item with caster-weights) .. not my fault :[ - if (!$upgItem->error) + if ($w = $items->filterGetForm('setWeights', true)) { - $upgItem->addGlobalsToJScript($smarty); - $pageData['lv']['data'][$filter['upg']] = $upgItem->getListviewData($infoMask)[$filter['upg']]; + $upgItem = new ItemList(array(['id', $filter['upg']]), false, ['wt' => $w[0], 'wtv' => $w[1]]); + + // still it may not be found if you apply really weired filters (e.g. search for a melee item with caster-weights) .. not my fault :[ + if (!$upgItem->error) + { + $upgItem->addGlobalsToJScript($smarty); + $pageData['lv']['data'][$filter['upg']] = $upgItem->getListviewData($infoMask)[$filter['upg']]; + } } } diff --git a/pages/profile.php b/pages/profile.php new file mode 100644 index 00000000..f5ae33cc --- /dev/null +++ b/pages/profile.php @@ -0,0 +1,617 @@ +'; + $tt .= ''.$name.''; + if (true /*CharacterHasGuild*/) + $tt .= '<'.$guild.'> ('.$gRankName.')'; + else if (true /*ProfileHasDescription*/) + $tt .= ''.$desc.''; + + $tt .= 'Level 80 Tauren Druid (Player)'; + $tt .= ''; + + + $x = '$WowheadPower.registerProfile('.($custom ? $data : "'".implode('.', $data)."'").', '.User::$localeId.", {\n"; + $x .= "\tname_".User::$localeString.": '".Util::jsEscape($name)."',\n"; + $x .= "\ttooltip_".User::$localeString.": '".$tt."',\n"; + $x .= "\ticon: \$WH.g_getProfileIcon(2, 1, 1, 60, 'class_druid'),\n"; // (race, class, gender, level, iconOrId, 'medium') + $x .= "});"; + + die($x); +} + +function handleAvatar() // image +{ + // something happened in the last years: those textures do not include tiny icons + $s = [/* 'tiny' => 15, */'small' => 18, 'medium' => 36, 'large' => 56]; + $size = empty($_GET['size']) ? 'medium' : $_GET['size']; + + if (empty($_GET['id']) || !preg_match('/^([0-9]+)\.(jpg|gif)$/', $_GET['id'], $matches) || !in_array($size, array_keys($s))) + return; + + header('Content-Type: image/'.$matches[2]); + + $id = $matches[1]; + + if (file_exists(getcwd().'/uploads/avatars/'.$id.'.jpg')) + { + $offsetX = $offsetY = 0; + + switch ($size) + { + case 'tiny': + $offsetX += $s['small']; + case 'small': + $offsetY += $s['medium']; + case 'medium': + $offsetX += $s['large']; + } + + $src = imageCreateFromJpeg('uploads/avatars/'.$id.'.jpg'); + $dest = imageCreateTruecolor($s[$size], $s[$size]); + + imagecopymerge($dest, $src, 0, 0, $offsetX, $offsetY, $s[$size], $s[$size], 100); + + if ($matches[2] == 'gif') + imageGif($dest); + else + imageJpeg($dest); + } +} + +function handlePinToggle($id, $mode) // (un)favorite +{ + /* params + id: + user: [optional] + return: null + */ +} + +function handleLinkToggle($id, $mode) // links char with account +{ + /* params + id: + user: [optional] + return: null + */ +} + +function handlePrivacyToggle($id, $mode) // ... +{ + /* params + id: + user: [optional] + return: null + */ +} + +function handleResync($initNew = true) // ... +{ + /* params + id: + user: [optional] + return + null [onOK] + int or str [onError] + */ + + if ($initNew) + return '1'; + else + { + /* + not all fields are required, if zero they are omitted + statusCode: + 0: end the request + 1: waiting + 2: working... + 3: ready; click to view + 4: error / retry + errorCode: + 0: unk error + 1: char does not exist + 2: armory gone + + [ + processId, + [StatusCode, timeToRefresh, iCount, errorCode, iNResyncs], + []... + ] + */ + return '[0, [4, 10000, 1, 2]]'; + } +} + +function handleSave() // unKill a profile +{ + /* params GET + id: + params POST + name, level, class, race, gender, nomodel, talenttree1, talenttree2, talenttree3, activespec, talentbuild1, glyphs1, talentbuild2, glyphs2, gearscore, icon, public [always] + description, source, copy, inv { inventory: array containing itemLinks } [optional] + } + return + int > 0 [profileId, if we came from an armoryProfile create a new one] + int < 0 [onError] + str [onError] + */ + + return 'NYI'; +} + +function handleDelete() // kill a profile +{ + /* params + id: + return + null + */ + + return 'NYI'; +} + +function handlePurge() // removes certain saved information but not the entire character +{ + /* params + id: + data: [string, tabName?] + return + null + */ + + return 'NYI'; +} + +function handleSummary() // can probably be removed +{ + /* params + null + return + null [jScript sets content] + */ +} + +function handleLoad() +{ + /* params + id: profileId + items: string [itemIds joined by :] + unnamed: unixtime [only to force the browser to reload instead of cache] + return + lots... + */ + + // titles, achievements, characterData, talents (, pets) + // and some onLoad-hook to .. load it registerProfile($data) + // check: equipItem, equipSubitem, socketItem, enchantItem, selectPet, updateMenu + // everything ele goes through data.php .. strangely enough + + $buff = ''; + $character = array( + 'id' => 2, + 'name' => 'CharName', + 'region' => ['eu', 'Europe'], + 'battlegroup' => ['pure-pwnage', 'Pure Pwnage'], + 'realm' => ['dafuque', 'da\'Fuqúe'], + + 'level' => 80, + 'classs' => 11, + 'race' => 6, + 'faction' => 1, // 0:alliance; 1:horde? + 'gender' => 1, + 'skincolor' => 0, // playerbytes % 256 + 'hairstyle' => 0, // (playerbytes >> 16) % 256 + 'haircolor' => 0, // (playerbytes >> 24) % 256 + 'facetype' => 0, // faceStyle = (playerbytes >> 8) % 256 [maybe features] + 'features' => 0, // playerBytes2 % 256 [maybe facetype] + + 'source' => 2, // source: used if you create a profile from a genuine character. It inherites region, realm and bGroup + 'sourcename' => 'SourceCharName', // > if these three are false we get a 'genuine' profile [0 for genuine characters..?] + 'user' => 0, //User::$id, // > 'genuine' is the parameter for _isArmoryProfile(allowCustoms) ['' for genuine characters..?] + 'username' => '', //User::$displayName, // > also, if 'source' <> 0, the char-icon is requestet via profile.php?avatar + 'published' => 1, // public / private ? + 'nomodel' => 0xFFFF, // remove slotIdx form modelvewer (so its a bitmask) + 'title' => 22, // titleId + 'guild' => 'Godlike HD', + 'description' => '', // only in custom profiles + + 'bookmarks' => [2], // UNK pinned or claimed profileIds..? + 'arenateams' => [2 => 'Dead in the water', 3 => 'Hier kommt die Maus', 5 => 'High Five'], + // 'lastupdated' => 1394407364000, // UNK at some points it should be a date, at others an integer + 'talents' => array( + 'builds' => array( + ['talents' => '55322331200212', 'glyphs' => '45623:45625'], + ['talents' => '51213102410', 'glyphs' => '45623:45625'] + ), + 'active' => 0 + ), + 'pets' => array( // UNK + [/*oneArrayPerPet*/], + ), + 'skills' => [333 => [150, 450]], // can contain anything, should be limited to prim/sec professions + 'reputation' => [], + 'achievements' => [], + 'achievementpoints' => 9001, // max you have + 'statistics' => [574 => 5, 575 => 20], // UNK all statistics [id => cnt] + 'activity' => [574 => 2], // UNK recent achievements? [id => cnt] + 'titles' => [111 => 1, 144 => 1], + 'quests' => [], + 'spells' => [], + // 'glyphs' => [], // not really used .. i guess..? + 'inventory' => [], + 'playedtime' => 1 * YEAR + 10 * MONTH + 21 * DAY, // exact to the day + 'auras' => [770, 24858, 48470, 48560] // custom list of buffs, debuffs + ); + + $inventory = array( + 1 => [46161, 0, 3817, 0, 41398, 40112 ], + 2 => [44664, 0, 0, 0, 40112, 0 ], + 3 => [46157, 0, 3808, 0, 40112, 0 ], + 5 => [46159, 0, 3832, 0, 40112, 40112 ], + 9 => [40186, 0, 3756, 0, 0, 0 ], + 7 => [46160, 0, 3328, 0, 40112, 40112 ], + 8 => [45232, 0, 983, 0, 40112, 0 ], + 6 => [45547, 0, 0, 0, 40112, 0 ], + 10 => [46158, 0, 3222, 0, 40112, 0 ], + 11 => [43993, 0, 3839, 0, 49110, 0 ], + 12 => [45157, 0, 3839, 0, 0, 0 ], + 13 => [44253, 0, 0, 0, 0, 0 ], + 14 => [40256, 0, 0, 0, 0, 0 ], + 15 => [40403, 0, 1099, 0, 0, 0 ], + 16 => [45498, 0, 3789, 0, 0, 0 ], + 18 => [39757, 0, 0, 0, 0, 0 ], + 19 => [40643, 0, 0, 0, 0, 0 ] + ); + + $character['achievements'] = array( + 13 => 1226439600, + 12 => 1226439600, + 11 => 1226439600, + 10 => 1226439600, + 9 => 1226439600, + 883 => 1226439600, + 7 => 1226439600, + 1563 => 1226439600, + 705 => 1226439600, + 16 => 1226439600, + 546 => 1226439600 + ); + + + foreach ($inventory as &$iv) + while (count($iv) < 8) + $iv[] = 0; + + $character['inventory'] = $inventory; + + $itemz = new ItemList(array(['id', array_column($inventory, 0)])); + $data = $itemz->getListviewData(ITEMINFO_JSON | ITEMINFO_SUBITEMS); + foreach ($itemz->iterate() as $iId => $__) + { + if (empty($data[$iId])) + continue; + + $buff .= "\r\ng_items.add(".$iId.', {name_'.User::$localeString.':"'.Util::jsEscape($itemz->getField('name', true)).'", quality:'.$itemz->getField('quality').', icon:"'.$itemz->getField('iconString').'", jsonequip:'.json_encode($data[$iId], JSON_NUMERIC_CHECK).'})'; + } + +/* CUSTOM AURAS */ + + $auraz = new SpellList(array(['id', $character['auras']])); + $dataz = $auraz->getListviewData(); + $modz = $auraz->getProfilerMods(); + + $buff .= "\r\n"; + foreach ($dataz as $id => $data) + { + if (!empty($modz[$id])) + { + $mods = []; + foreach ($modz[$id] as $k => $v) + if ($str = @Util::$itemMods[$k]) + $mods[$str] = $v; + else + $mods[$k] = $v; + + $data['modifier'] = $mods; + } + + $json = preg_replace('/"\$([^$"]+)"/', '\1', json_encode($data, JSON_NUMERIC_CHECK)); + $buff .= "\r\ng_spells.add(".$id.', '.$json.');'; + } + +/* END CUSTOM */ + + $mountz = new SpellList(array(['typeCat', -5])); + $dataz = $mountz->getListviewData(); + foreach ($dataz as $id => $data) + echo "\r\ng_spells.add(".$id.', '.json_encode($data, JSON_NUMERIC_CHECK).');'; + + + + +/*** STATIC DATA ***/ +/*** CACHE THIS! ***/ + // by locale and faction + + // buffer title + $titlez = new TitleList(array(SQL_LIMIT_NONE, [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0])); // all available + $dataz = $titlez->getListviewData(); + + $buff .= "\r\n\r\nvar _ = g_titles;"; + foreach ($dataz as $id => $data) + { + $s = !empty($data[$id]['source']) ? ', source: '.($data[$id]['source']) : null; + $buff .= "\r\n_[".$id."] = {name:'".Util::jsEscape($character['gender'] && !empty($data['namefemale']) ? $data['namefemale'] : $data['name'])."', gender:".$data['gender'].', category:'.$data['category'].$s.'};'; + } + + // buffer achievements / statistics + $cnd = array( + SQL_LIMIT_NONE, + [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0], // no unachievable + [['flags', 1, '&'], 0], // no statistics + // [faction matches our faction] + ); + $achievez = new AchievementList($cnd); + $dataz = $achievez->getListviewData(ACHIEVEMENTINFO_PROFILE); + + $sumPoints = 0; + $buff .= "\r\n\r\nvar _ = g_achievements;"; + foreach ($dataz as $id => $data) + { + $sumPoints += $data['points']; + $buff .= "\r\n_[".$id.'] = '.json_encode($data, JSON_NUMERIC_CHECK).';'; + } + + // this list below is correct and expected. HOW THE HELL DOES THE SCRIPT GENERATE A TREE FROM THAT?! [ORDER BY parentId, posOrChildCount ASC] + $buff .= "\r\n\r\ng_achievement_catorder = [96, 97, 95, 168, 169, 201, 155, 81, 1, 130, 141, 128, 122, 133, 14807, 132, 134, 131, 21, 152, 153, 154, 165, 14801, 14802, 14803, 14804, 14881, 14901, 15003, 14861, 14862, 14863, 14777, 14778, 14779, 14780, 123, 124, 125, 126, 127, 135, 136, 137, 140, 145, 147, 191, 178, 173, 160, 187, 159, 163, 161, 162, 158, 14981, 156, 14941, 14808, 14805, 14806, 14921, 14922, 14923, 14961, 14962, 15001, 15002, 15041, 15042, 170, 171, 172, 14864, 14865, 14866, 14821, 14822, 14823, 14963, 15021, 15062]"; + + // max achievable achievementpoints come separately .. as array.. with only one element .. seriously? + $buff .= "\r\n\r\ng_achievement_points = [".$sumPoints."];"; + +/*** END STATIC ***/ + + + // excludes + $buff .= "\r\n\r\ng_excludes = {};"; + + // add profile to buffer + $buff .= "\r\n\r\n\$WowheadProfiler.registerProfile(".json_encode($character, JSON_PRETTY_PRINT, JSON_NUMERIC_CHECK).");"; + + return $buff; +} + +/**********/ +/* HALPer */ +/**********/ + +function getModelForForm($form, $char) +{ + switch ($form) + { + case 1: // FORM_CAT + if ($char['race'] == 4) // RACE_NIGHTELF + { + if ($char['hairColor'] >= 0 && $char['hairColor'] <= 2) + return 29407; + else if ($char['hairColor'] == 3) + return 29406; + else if ($char['hairColor'] == 4) + return 29408; + else if ($char['hairColor'] == 7 || $char['hairColor'] == 8) + return 29405; + else + return 892; + } + + if ($char['race'] == 6) // RACE_TAUREN + { + if ($char['gender'] == GENDER_MALE) + { + if ($char['skinColor'] >= 0 && $char['skinColor'] <= 5) + return 29412; + else if ($char['skinColor'] >= 0 && $char['skinColor'] <= 8) + return 29411; + else if ($char['skinColor'] >= 0 && $char['skinColor'] <= 11) + return 29410; + else if (in_array($char['skinColor'], [12, 13, 14, 18])) + return 29410; + else + return 8571; + } + else // if gender == GENDER_FEMALE + { + if ($char['skinColor'] >= 0 && $char['skinColor'] <= 3) + return 29412; + else if ($char['skinColor'] >= 0 && $char['skinColor'] <= 5) + return 29411; + else if ($char['skinColor'] >= 0 && $char['skinColor'] <= 7) + return 29410; + else if ($char['skinColor'] == 10) + return 29410; + else + return 8571; + } + } + case 5: // FORM_DIREBEAR + case 8: // FORM_BEAR + if ($char['race'] == 4) // RACE_NIGHTELF + { + if ($char['hairColor'] >= 0 && $char['hairColor'] <= 2) + return 29413; // 29415 + else if ($char['hairColor'] == 3) + return 29417; + else if ($char['hairColor'] == 4) + return 29416; + else if ($char['hairColor'] == 6) + return 29414; + else + return 2281; + } + + if ($char['race'] == 6) // RACE_TAUREN + { + if ($char['gender'] == GENDER_MALE) + { + if ($char['skinColor'] >= 0 && $char['skinColor'] <= 2) + return 29415; + else if (in_array($char['skinColor'], [3, 4, 5, 12, 13, 14])) + return 29419; + else if (in_array($char['skinColor'], [9, 10, 11, 15, 16, 17])) + return 29420; + else if ($char['skinColor'] == 18) + return 29421; + else + return 2289; + } + else // if gender == GENDER_FEMALE + { + if ($char['skinColor'] == 0 && $char['skinColor'] == 1) + return 29418; + else if ($char['skinColor'] == 2 && $char['skinColor'] == 3) + return 29419; + else if ($char['skinColor'] >= 6 && $char['skinColor'] <= 9) + return 29420; + else if ($char['skinColor'] == 10) + return 29421; + else + return 2289; + } + } + } + + // hey, still here? you're not a Tauren/Nelf as bear or cat, are you? + return DB::Aowow()->selectCell('SELECT IF(?d == 1, IFNULL(displayIdA, displayIdH), IFNULL(displayIdH, displayIdA)) FROM ?_shapeshiftForm WHERE id = ?d AND XXX', Util::sideByRaceMask(1 << ($char['race'] - 1)), $form); +} + +/******************/ +/* select handler */ +/******************/ + + +switch ($pageParam) +{ + case 'link': + case 'unlink': + die(handleLinkToggle()); + case 'pin': + case 'unpin': + die(handlePinToggle()); + case 'public': + case 'private': + die(handlePrivacyToggle()); + case 'resync': + case 'status': + die(handleResync($pageParam == 'resync')); + case 'save': + die(handleSave()); + case 'delete': + die(handleDelete()); + case 'purge': + die(handlePurge()); + case 'summary': + die(handleSummary()); + case 'avatar': + die(handleAvatar()); + case 'load': + die(handleLoad()); + case '': + if (isset($_GET['new'])) + { + $_profileId = 0; + break; + } + + die(); + default: + $_ = explode('.', $pageParam); + if (count($_) == 1 && intVal($_)) + { + $_custom = true; + $_profile = intVal($_); + } + else if (count($_) == 3) + $_profile = $_; + else + Util::$pageTemplate->error(); + + // AowowPower-request + if (isset($_GET['power'])) + handlePower($_custom, $_profile); + else if ($_custom) // validate existance of profile + $_profileId = 0; + else if ($_ = DB::Aowow()->selectCell('SELECT 2')) // some query to validate existence of char + $_profileId = $_; + else + Util::$pageTemplate->notFound(Util::ucFirst(Lang::$game['profile']), $pageParam); +} + + // required by progress in JScript + Util::$pageTemplate->extendGlobalIds(TYPE_NPC, [29120, 31134, 29306, 29311, 23980, 27656, 26861, 26723, 28923, 15991]); + + +$pageData = array( + 'page' => array( + 'profileId' => $_profileId, + 'dataKey' => $_profileId, // should be some unique integer to manage ?data=-requests + 'path' => json_encode($_path, JSON_NUMERIC_CHECK), + 'title' => Util::ucFirst(Lang::$game['profile']), // actual name is set per jScript + 'tab' => 1, + 'reqJS' => array( + 'template/js/filters.js', + 'template/js/TalentCalc.js', + 'template/js/swfobject.js', + 'template/js/profile_all.js', + 'template/js/profile.js', + 'template/js/Profiler.js', + '?data=enchants.gems.glyphs.itemsets.pets.pet-talents.quick-excludes.realms.statistics.weight-presets' // quick-excludes?! + // ?data=user&1270968639 + ), + 'reqCSS' => array( + ['path' => 'template/css/TalentCalc.css'], + ['path' => 'template/css/Profiler.css'] + ) + ) +); + + +$smarty->updatePageVars($pageData['page']); +$smarty->assign('lang', array_merge(Lang::$main, Lang::$game, ['colon' => Lang::$colon])); + +// load the page +$smarty->display('profile.tpl'); + + + +?> diff --git a/pages/profiles.php b/pages/profiles.php new file mode 100644 index 00000000..f1f9da9e --- /dev/null +++ b/pages/profiles.php @@ -0,0 +1,164 @@ + '0', + 'name' => 'Helluvah', + 'acvPts' => '6095', + 'guildName' => 'Been There Done That', + 'guildRank' => '-1', + 'realmInternal' => 'aszune', + 'realmName' => 'Aszune', + 'bgInternal' => 'blackout', + 'bgName' => 'Blackout', + 'region' => 'eu', + 'level' => '85', + 'race' => '1', + 'gender' => '1', + 'class' => '2', + 'faction' => '0', + 'tree' => [31, 5, 5], + 'spec' => '1' + ), + array( + 'id' => '0', + 'name' => 'Vetzew', + 'acvPts' => '9830', + 'guildName' => 'SPQ', + 'guildRank' => '-1', + 'realmInternal' => 'aszune', + 'realmName' => 'Aszune', + 'bgInternal' => 'blackout', + 'bgName' => 'Blackout', + 'region' => 'eu', + 'level' => '85', + 'race' => '1', + 'gender' => '0', + 'class' => '5', + 'faction' => '0', + 'tree' => [9, 32, 0], + 'spec' => '2' + ), + array( + 'id' => '0', + 'name' => 'Winry', + 'acvPts' => '9065', + 'guildName' => 'Momentum', + 'guildRank' => '-1', + 'realmInternal' => 'aszune', + 'realmName' => 'Aszune', + 'bgInternal' => 'blackout', + 'bgName' => 'Blackout', + 'region' => 'eu', + 'level' => '85', + 'race' => '10', + 'gender' => '1', + 'class' => '3', + 'faction' => '1', + 'tree' => [1, 31, 9], + 'spec' => '2' + ), + array( + 'id' => '0', + 'name' => 'Enfisk', + 'acvPts' => '12370', + 'guildName' => 'Postal', + 'guildRank' => '-1', + 'realmInternal' => 'aszune', + 'realmName' => 'Aszune', + 'bgInternal' => 'blackout', + 'bgName' => 'Blackout', + 'region' => 'eu', + 'level' => '85', + 'race' => '3', + 'gender' => '1', + 'class' => '5', + 'faction' => '0', + 'tree' => [9, 0, 32], + 'spec' => '3' + ), + array( + 'id' => '71', + 'name' => 'Erchenmar', + 'acvPts' => '10570', + 'guildName' => 'Psychosomatic Assassins', + 'guildRank' => '-1', + 'realmInternal' => 'aszune', + 'realmName' => 'Aszune', + 'bgInternal' => 'blackout', + 'bgName' => 'Blackout', + 'region' => 'eu', + 'level' => '85', + 'race' => '5', + 'gender' => '0', + 'class' => '9', + 'faction' => '0', + 'tree' => [3, 7, 31], + 'spec' => '3' + ) + ); + + + // dont send ID for real chars unless they have some kind of custom avatar + // on second thought .. ids are required, but the function that generates the icon is faulty + +$pageData = array( + 'file' => 'class', + 'data' => $lv, + 'params' => [ + 'id' => 'characters', + 'name' => '$LANG.tab_characters', + 'hideCount' => 1, + '_truncated' => 1, + 'visibleCols' => "$['race','classs','level','talents','achievementpoints']", + 'note' => '$$WH.sprintf(LANG.lvnote_charactersfound, \'20,592,390\', 200) + LANG.dash + LANG.lvnote_tryfiltering.replace(\'\', \'\')', + 'onBeforeCreate' => '$pr_initRosterListview' // $_GET['roster'] = 1|2|3|4 .. 2,3,4 arenateam-size (4 => 5-man), 1 guild .. it puts a resync button on the lv... + ] +); + + +// menuId 5: Profiler g_initPath() +// tabId 1: Tools g_initHeader() +$smarty->updatePageVars(array( + 'tab' => 1, + 'title' => Util::ucFirst(Lang::$game['profiles']), + 'path' => "[1, 5, 0, 'us', 'pure-pwnage', 'trinity']", // [1,5,'eu','cyclone-wirbelsturm','silvermoon'] + 'tab' => 1, + 'reqJS' => array( + 'template/js/filters.js?978', + 'template/js/profile_all.js?978', + 'template/js/profile.js?978', + '?data=weight-presets.realms&978', + // '?data=user&1280640186' + ), + 'reqCSS' => array( + ['path' => 'template/css/profiler.css'] + ) +)); +$smarty->assign('lang', array_merge(Lang::$main, Lang::$game, ['colon' => Lang::$colon])); +$smarty->assign('lvData', $pageData); + +// load the page +$smarty->display('profiles.tpl'); + +?> diff --git a/power/aowowPower.js b/power/aowowPower.js index a8ad930f..5aef6361 100644 --- a/power/aowowPower.js +++ b/power/aowowPower.js @@ -473,12 +473,6 @@ if (typeof $WowheadPower == "undefined") { html = html.replace(new RegExp('', "g"), '$2
'); } - // custom start - if ($WH.gc('compare_level') && window.location.href.match(/\?compare/i)) { - html = $WH.g_setTooltipLevel(html, $WH.gc('compare_level'), currentParams.buff); - } - // custom end - if (currentParams.know && currentParams.know.length) { html = $WH.g_setTooltipSpells(html, currentParams.know, spellData); } @@ -486,6 +480,11 @@ if (typeof $WowheadPower == "undefined") { if (currentParams.lvl) { html = $WH.g_setTooltipLevel(html, currentParams.lvl, currentParams.buff); } + // custom start + else if ($WH.gc('compare_level') && window.location.href.match(/\?compare/i)) { + html = $WH.g_setTooltipLevel(html, $WH.gc('compare_level'), currentParams.buff); + } + // custom end if (currentParams.who && currentParams.when) { html = html.replace("

", '

' + $WH.sprintf(_LANG.achievementcomplete, currentParams.who, currentParams.when.getMonth() + 1, currentParams.when.getDate(), currentParams.when.getFullYear()) + "

"); diff --git a/search.php b/search.php index 60351fff..2d0a704d 100644 --- a/search.php +++ b/search.php @@ -37,13 +37,23 @@ $maxResults = SQL_LIMIT_SEARCH; $_wt = isset($_GET['wt']) ? explode(':', $_GET['wt']) : null; $_wtv = isset($_GET['wtv']) ? explode(':', $_GET['wtv']) : null; +$_slots = []; if (isset($_GET['json'])) { if ($_ = intVal($search)) // allow for search by Id $query = $_; - if ($type == TYPE_ITEMSET) + if (!empty($_GET['slots'])) + { + $_slots = explode(':', $_GET['slots']); + array_walk($_slots, function(&$v, $k) { + $v = intVal($v); + }); + + $searchMask |= SEARCH_TYPE_JSON | 0x40; + } + else if ($type == TYPE_ITEMSET) $searchMask |= SEARCH_TYPE_JSON | 0x60; else if ($type == TYPE_ITEM) $searchMask |= SEARCH_TYPE_JSON | 0x40; @@ -314,16 +324,20 @@ if (!$smarty->loadCache($cacheKey, $found)) if ($searchMask & 0x0000040) { $miscData = []; - $cndAdd = is_int($query) ? ['id', $query] : ['name_loc'.User::$localeId, $query]; + $cndAdd = empty($query) ? [] : (is_int($query) ? ['id', $query] : ['name_loc'.User::$localeId, $query]); if (($searchMask & SEARCH_TYPE_JSON) && $type == TYPE_ITEMSET && isset($found['itemset'])) { $cnd = [['i.id', array_keys($found['itemset']['pcsToSet'])], SQL_LIMIT_NONE]; $miscData = ['pcsToSet' => @$found['itemset']['pcsToSet']]; } - else if (($searchMask & SEARCH_TYPE_JSON) && $type == TYPE_ITEM) + else if (($searchMask & SEARCH_TYPE_JSON) && ($type == TYPE_ITEM || $_slots)) { - $cnd = array_merge($cndBase, [['AND', ['i.class', [ITEM_CLASS_WEAPON, ITEM_CLASS_GEM, ITEM_CLASS_ARMOR]], $cndAdd]]); + $iCnd = ['AND', ['i.class', [ITEM_CLASS_WEAPON, ITEM_CLASS_GEM, ITEM_CLASS_ARMOR]], $cndAdd]; + if ($_slots) + $iCnd[] = ['slot', $_slots]; + + $cnd = array_merge($cndBase, [$iCnd]); $miscData = ['wt' => $_wt, 'wtv' => $_wtv]; } else diff --git a/setup/tools/dataset/statistics.php b/setup/tools/dataset/statistics.php new file mode 100644 index 00000000..f1b11606 --- /dev/null +++ b/setup/tools/dataset/statistics.php @@ -0,0 +1,140 @@ + [[-20, 2, 0, 3], [-10, 0, 1, 1], null, 0.9560, 3.6640, 88.129021, 5, 47.003525, 5, 0, 0], + 2 => [[-20, 2, 0, 3], [-10, 0, 1, 0], null, 0.9560, 3.4943, 88.129021, 5, 47.003525, 5, 0, 0], + 3 => [[-20, 1, 1, 2], [-10, 0, 2, 2], null, 0.9880, -4.0873, 145.560408, 5, 145.560408, 0, 0, 0], + 4 => [[-20, 1, 1, 2], [-10, 0, 1, 1], null, 0.9880, 2.0957, 145.560408, 5, 145.560408, 0, 0, 0], + 5 => [[-10, 1, 0, 0], [-10, 0, 1, 0], null, 0.9830, 3.4178, 150.375940, 0, 0.0, 0, 0, 0], + 6 => [[-20, 2, 0, 3], [-10, 0, 1, 0], null, 0.9560, 3.6640, 88.129021, 5, 47.003525, 0, 0, ['parryrtng' => [0.25, 'percentOf', 'str']]], // Forcefull Deflection (49410) + 7 => [[-20, 1, 1, 2], [-10, 0, 1, 0], null, 0.9880, 2.1080, 145.560408, 0, 145.560408, 5, 0, 0], + 8 => [[-10, 1, 0, 0], [-10, 0, 1, 0], null, 0.9830, 3.6587, 150.375940, 0, 0.0, 0, 0, 0], + 9 => [[-10, 1, 0, 0], [-10, 0, 1, 0], null, 0.9830, 2.4211, 150.375940, 0, 0.0, 0, 0, 0], + 11 => [[-20, 2, 0, 0], [-10, 0, 1, 0], null, 0.9720, 5.6097, 116.890707, 0, 0.0, 0, 0, 0] + ); + + foreach ($dataz as $class => &$data) + $data[2] = array_values(DB::Aowow()->selectRow('SELECT mle.chance*100 cMle, spl.chance*100 cSpl FROM dbc.gtChanceToMeleeCritBase mle, dbc.gtChanceToSpellCritBase spl WHERE mle.idx = spl.idx AND mle.idx = ?d', $class - 1)); + + return $dataz; + } + + function race() + { + // { str, agi, sta, int, spi, hp, mana, directMod1, directMod2 } + + return array( + 1 => [20, 20, 20, 20, 20, 0, ['spi' => [0.05, 'percentOf', 'spi']]], // The Human Spirit (20598) + 2 => [23, 17, 22, 17, 23, 0, 0], + 3 => [22, 16, 23, 19, 19, 0, 0], + 4 => [17, 25, 19, 20, 20, 0, 0], + 5 => [19, 18, 21, 18, 25, 0, 0], + 6 => [25, 15, 22, 15, 22, 0, ['health' => [0.05, 'functionOf', '$function(p) { return g_statistics.combo[p.classs][p.level][5]; }']]], // Endurance (20550) ... if you are looking for something elegant, look away! + 7 => [15, 23, 19, 24, 20, 0, ['int' => [0.05, 'percentOf', 'int']]], // Expansive Mind (20591) + 8 => [21, 22, 21, 16, 21, 0, ['healthrgn' => [0.1, 'percentOf', 'healthrgn']]], // Regeneration (20555) + 10 => [17, 22, 18, 24, 19, 0, 0], + 11 => [21, 17, 19, 21, 22, 0, 0] // ['mlehitpct' => [1, 'add'], 'splhitpct' => [1, 'add'], 'rgdhitpct' => [1, 'add']] // Heroic Presence (6562, 28878) (not actually shown..?) + ); + } + + function combo() + { + $result = []; + $critToDodge = array( + 1 => 0.85/1.15, 2 => 1.00/1.15, 3 => 1.11/1.15, + 4 => 2.00/1.15, 5 => 1.00/1.15, 6 => 0.85/1.15, + 7 => 1.60/1.15, 8 => 1.00/1.15, 9 => 0.97/1.15, 11 => 2.00/1.15 + ); + + // TrinityCore claims, DodgePerAgi per level and class can be constituted from critPerAgi (and level (and class)) + // who am i to argue + // rebase stats to a specific race. chosen human as all stats are 20 + // level:{ str, agi, sta, int, spi, hp, mana, mleCrt%Agi, splCrt%Int, dodge%Agi, HealthRegenModToBaseStat, HealthRegenModToBonusStat } + + foreach ($critToDodge as $class => $mod) + { + // humans can't be hunter, shaman, druids (use tauren here) + if (in_array($class, [3, 7, 11])) + $offset = [25, 15, 22, 15, 22]; + else + $offset = [20, 20, 20, 20, 20]; + + $rows = DB::Aowow()->select('SELECT pls.level AS ARRAY_KEY, str-?d, agi-?d, sta-?d, inte-?d, spi-?d, basehp, IF(basemana <> 0, basemana, 100), mlecrt.chance*100, splcrt.chance*100, mlecrt.chance*100 * ?f, baseHP5.ratio*1, extraHP5.ratio*1 ' . + 'FROM world.player_levelstats pls JOIN world.player_classlevelstats pcls ON pls.level = pcls.level AND pls.class = pcls.class JOIN' . + ' dbc.gtchancetomeleecrit mlecrt ON mlecrt.idx = ((pls.class - 1) * 100) + (pls.level - 1) JOIN' . + ' dbc.gtchancetospellcrit splcrt ON splcrt.idx = ((pls.class - 1) * 100) + (pls.level - 1) JOIN' . + ' dbc.gtoctregenhp baseHP5 ON baseHP5.idx = ((pls.class - 1) * 100) + (pls.level - 1) JOIN' . + ' dbc.gtregenhpperspt extraHP5 ON extraHP5.idx = ((pls.class - 1) * 100) + (pls.level - 1) ' . + 'WHERE pls.race = ?d AND pls.class = ?d ORDER BY pls.level ASC', + $offset[0], $offset[1], $offset[2], $offset[3], $offset[4], + $mod, + in_array($class, [3, 7, 11]) ? 6 : 1, + $class + ); + + $result[$class] = []; + foreach ($rows as $k => $row) + $result[$class][$k] = array_values($row); + } + + return $result; + } + + function level() + { + // base mana regeneration per level + // identical across classes (just use one, that acutally has mana (offset: 100)) + // content of gtRegenMPPerSpt.dbc + + return DB::Aowow()->selectCol('SELECT idx-99 AS ARRAY_KEY, ratio FROM dbc.gtregenmpperspt WHERE idx >= 100 AND idx < 100 + ?d', MAX_LEVEL); + } + + function skills() + { + // profession perks (skinning => +crit, mining => +stam) and maybe some others; skillId:{rankNo:someJSON, ..}? + + return []; + } + + // todo: x + $sub = ['classs', 'race', 'combo', 'level', 'skills']; + $out = []; + + foreach($sub as $s) + $out[$s] = $s(); + + $json = json_encode($out, JSON_NUMERIC_CHECK | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); + $json = preg_replace('/"\$([^$"]+)"/', '\1', $json); + + $handle = fOpen('datasets\\statistics', "w"); + fWrite($handle, 'g_statistics = '.$json.';'); + fClose($handle); + + echo 'all done'; +?> \ No newline at end of file diff --git a/template/bricks/listviews/achievement.tpl b/template/bricks/listviews/achievement.tpl index 6525f093..e5ad2b8b 100644 --- a/template/bricks/listviews/achievement.tpl +++ b/template/bricks/listviews/achievement.tpl @@ -20,7 +20,7 @@ side:{$curr.faction}, points:{$curr.points}, category:{$curr.category}, - parentcat:{$curr.parentCat} + parentcat:{$curr.parentcat} {if isset($curr.type)}, type:{$curr.type}{/if} {if isset($curr.rewards)}, rewards:{$curr.rewards}{/if} {if isset($curr.reward)}, reward:'{$curr.reward|escape:"javascript"}'{/if} diff --git a/template/bricks/listviews/character.tpl b/template/bricks/listviews/character.tpl new file mode 100644 index 00000000..229f5fb1 --- /dev/null +++ b/template/bricks/listviews/character.tpl @@ -0,0 +1,28 @@ +{strip} + us_addCharactersTab([ + {ldelim} + id:763, + "name":"Lilywhite", + "achievementpoints":"0", + "guild":"whatever", + "guildrank":"0", + "realm":"draenor", + "realmname":"Draenor", + "battlegroup":"cyclone", + "battlegroupname":"Cyclone", + "region":"us", + "level":"10", + "race":"7", + "gender":"0", + "classs":"1", + "faction":"0", + "gearscore":"0", + "talenttree1":"0", + "talenttree2":"0", + "talenttree3":"0", + "talentspec":0, + "published":1, + "pinned":0 + {rdelim} + ]); +{/strip} \ No newline at end of file diff --git a/template/bricks/listviews/profile.tpl b/template/bricks/listviews/profile.tpl new file mode 100644 index 00000000..1ed2db3b --- /dev/null +++ b/template/bricks/listviews/profile.tpl @@ -0,0 +1,56 @@ +{strip} + new Listview({ldelim} + template:'profile', + {if !isset($params.id)}id:'profiles',{/if} + {if !isset($params.name)}name:LANG.tab_profiles,{/if} + {if !isset($params.parent)}parent:'lv-generic',{/if} + {foreach from=$params key=k item=v} + {if $v[0] == '$'} + {$k}:{$v|substr:1}, + {else if $v} + {$k}:'{$v}', + {/if} + {/foreach} + data:[ + {foreach name=i from=$data item=curr} + {ldelim} + id:{$curr.id}, + name:'{$curr.name|escape:"javascript"}', + race:{$curr.race}, + classs:{$curr.class}, + gender:{$curr.gender}, + level:{$curr.level}, + faction:{$curr.faction}, + talenttree1:{$curr.tree[0]}, + talenttree2:{$curr.tree[1]}, + talenttree3:{$curr.tree[2]}, + talentspec:{$curr.spec}, + achievementpoints:{$curr.acvPts}, + guild:'{$curr.guildName|escape:"javascript"}', {* 0 if none *} + guildrank:{$curr.guildRank}, + {if isset($curr.description)} + description:'{$curr.description|escape:"javascript"}', + {/if} + {if isset($curr.icon)} + icon:'{$curr.icon|escape:"javascript"}', + {/if} + {if isset($curr.published)} + published:1, + {/if} + {if isset($curr.pinned)} + pinned:1, + {/if} + {if isset($curr.deleted)} + deleted:1, + {/if} + realm:'{$curr.realmInternal|escape:"javascript"}', + realmname:'{$curr.realmName|escape:"javascript"}', + battlegroup:'{$curr.bgInternal|escape:"javascript"}', + battlegroupname:'{$curr.bgName|escape:"javascript"}', + region:'{$curr.region|escape:"javascript"}' + {rdelim} + {if $smarty.foreach.i.last}{else},{/if} + {/foreach} + ] + {rdelim}); +{/strip} \ No newline at end of file diff --git a/template/bricks/redButtons.tpl b/template/bricks/redButtons.tpl index 0a31a476..d958642f 100644 --- a/template/bricks/redButtons.tpl +++ b/template/bricks/redButtons.tpl @@ -1,8 +1,3 @@ -{* -found this button(?) in item.tpl .. no script, data or style found for this id -
-*} - {if isset($redButtons[$smarty.const.BUTTON_WOWHEAD])} {assign var='b' value=$redButtons[$smarty.const.BUTTON_WOWHEAD]} {if $b} @@ -59,3 +54,6 @@ found this button(?) in item.tpl .. no script, data or style found for this id {$lang.forum}{$lang.forum} {/if} {/if} +{if isset($redButtons[$smarty.const.BUTTON_EQUIP])} +
{* content is added by jScript *} +{/if} diff --git a/template/css/Profiler.css b/template/css/Profiler.css new file mode 100644 index 00000000..74f8698b --- /dev/null +++ b/template/css/Profiler.css @@ -0,0 +1,927 @@ +.profiler-home { + clear: both; + margin: 40px 0px 20px; + display: block; +} + +.profiler-home > div { + float: left; + height: 67px; + margin-right: 10px; +} + +.profiler-home > div.profiler-buttons { + height: 40px; + padding-top: 27px; +} + +.profiler-home > div h2 { + border: none; + font-size: 14px; + font-weight: bold; + margin: 0px 0px 10px; + padding: 0px; +} + +.profiler-home input[type="text"], .profiler-home a: link, .profiler-home a: visited { + font-family: Helvetica,Arial,sans-serif; +} + +.profiler-home input[type="text"] { + background: url(../images/Profiler/text-input.2.png) no-repeat; + border: none; + color: #383838; + font-size: 12px; + height: 22px; + line-height: 22px; + margin: 0px; + padding: 0px 7px; + width: 105px; +} + +.profiler-home input[type="text"]: focus { + outline: none; +} + +.profiler-home input[type="text"].oops { + color: #ff0000; + + -moz-box-shadow: 0 0 10px #ff0000; + -webkit-box-shadow: 0 0 10px #ff0000; + -o-box-shadow: 0 0 10px #ff0000; +} + +.profiler-home input[type="radio"] { + display: none; +} + +.profiler-autocomplete { + display: none; + width: 194px; + background: #484848; + border: 1px solid #202020; + padding: 0 2px 2px 2px; + position: absolute; + font-size: 12px; + + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.35); + -webkit-box-shadow: 0 1px 3px #111; + -o-box-shadow: 0 1px 3px #111; +} + +.profiler-autocomplete span { + display: block; + background: #282828; + border-bottom: 1px solid #101010; + border-top: 1px solid #484848; + cursor: pointer; + height: 23px; + line-height: 23px; + text-indent: 6px; +} + +.profiler-autocomplete span: hover, .profiler-autocomplete span.active { + background: #383838; + border-bottom: solid 1px #202020; +} + +/*********************************************/ + +.profiler-charlookup { + position: relative; + height: 22px; + width: 124px; + display: inline-block; +} + +.profiler-charlookup input { + border: 1px solid #a7a6aa; + height: 18px; + width: 120px; + padding-left: 2px; + font-size: 13px; + font-family: Arial,sans-serif; + background: white; + color: black; +} + +.profiler-charlookup-go { + position: absolute; + top: 0; + right: -12px; + z-index: 1; + width: 22px; + height: 22px; + background: url(../images/Profiler/lookup.gif) left top no-repeat; + display: block; +} + +.profiler-charlookup-go: hover { + background-position: left bottom; +} + +input.search-character { + background: white url(../images/enus/character.gif) 0.2em center no-repeat !important; +} + +/*********************************************/ + +.profiler-header { + height: 69px; + background: url(../images/Profiler/character-header-bg.gif) repeat-x left top; + border-bottom: 1px solid #505050; + position: relative; + margin-bottom: 13px; + padding-right: 8px; +} + +.profiler-header .iconlarge, .profiler-header .iconlargepremium { + position: absolute; + left: 2px; + top: -1px; +} + +.profiler-header a { + text-decoration: none; +} + +.profiler-header a: hover { + text-decoration: underline; +} + +.profiler-header-line1, .profiler-header-line2, .profiler-header-line3 { + position: absolute; + left: 74px; +} + +.profiler-header-line1 { + top: 0; + font-size: 15px; + line-height: 1.1em; + color: #EEEEEE; +} + +.profiler-header-line1 a { + color: #EEEEEE; +} + +.profiler-header-line1 b { + font-size: 20px; + font-weight: normal; + color: white; +} + +.profiler-header-line2 { + top: 25px; + color: #dddddd; +} + +.profiler-header-line2 var { + font-size: 12px; + font-family: Verdana,sans-serif; + color: #CCCCCC; + font-style: normal; +} + +.profiler-header-line2 a { + font-size: 14px; +} + +.profiler-header-line3 { + top: 48px; + font-size: 11px; + color: #EEEEEE; +} + +.profiler-header-line3 span { + display: block; + float: left; +} + +.profiler-header-line3 span a { + color: white; +} + +a.profiler-header-editlink { + float: left; + margin-left: 16px; + font-size: 11px; + font-weight: bold; + text-decoration: underline; +} + +/*********************************************/ + +.profiler-message { + padding: 8px; + color: #dddddd; + margin-bottom: 10px; + text-align: center; + border: 1px solid #101010; + background: url(../images/ajax.gif) no-repeat 8px #141414; + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.profiler-message b { + color: white; +} + +/*********************************************/ + +.profiler-tablinks { + position: relative; + z-index: 1; +} + +.profiler-tablinks a { + padding-top: 5px; + padding-bottom: 5px; +} + +.profiler-tablinks-armory { + z-index: 1; + float: right; + font-size: 13px; + background: url(../images/link.gif) no-repeat left center; + padding: 5px 5px 5px 19px; + margin-left: 6px; +} + +.profiler-tablinks-help { + z-index: 1; + float: right; + font-size: 13px; + background: url(../images/help.gif) no-repeat left center; + padding: 5px 5px 5px 21px; + margin-left: 6px; +} + +.profiler-tablinks-print { + z-index: 1; + float: right; + font-size: 13px; + background: url(../images/print.gif) no-repeat left center; + padding: 5px 5px 5px 21px; +} + +/*********************************************/ + +.profiler-tabs { + border-bottom: 1px solid #404040; + margin-bottom: 10px; +} + +/*********************************************/ + +.profiler-infobox-skill { + line-height: 1em; +} + +.profiler-infobox-skill a { + text-decoration: none; +} + +.profiler-infobox-raids { + line-height: 18px!important; + vertical-align: top; +} + +.profiler-infobox-raids .progressbar { + height: 18px; + margin: 4px auto; +} + +.profiler-infobox-raids .progressbar-text { + width: auto; + padding-left: 22px; + text-align: left; +} + +.profiler-infobox-raids .progressbar-hidden { + padding-left: 8px; +} + +.profiler-infobox-gear { + width: 20px; + line-height: 18px!important; + vertical-align: top; +} + +.profiler-infobox-gear .completion { + display: block; + height: 20px; + width: 16px; + margin: 2px auto; + background: left center no-repeat; +} + +.profiler-infobox-gear .progressbar { + width: 20px; + margin: 0 auto 1px; + + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.profiler-infobox-gear .progressbar div { + height: 100%; + border-top-width: 0; + + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.profiler-infobox-gear .progressbar-first, .profiler-infobox-gear .progressbar-first div { + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; +} + +.profiler-infobox-gear .progressbar-first div { + border-top-width: 1px; + margin-bottom: 2px; +} + +.profiler-infobox-gear .progressbar-last, .profiler-infobox-gear .progressbar-last div { + -webkit-border-radius: 0 0 3px 3px; + -moz-border-radius: 0 0 3px 3px; + border-radius: 0 0 3px 3px; +} + +.profiler-infobox-gear .progressbar-rep0 { + border: 1px solid #9c2319; + border-top: 1px solid #b82e21; +} + +.profiler-infobox-gear .progressbar-rep1 { + border: 1px solid #b05421; + border-top: 1px solid #c9662b; +} + +.profiler-infobox-gear .progressbar-rep2 { + border: 1px solid #bf8626; + border-top: 1px solid #d59b31; +} + +.profiler-infobox-gear .progressbar-rep3 { + border: 1px solid #bb9b25; + border-top: 1px solid #d2b130; +} + +.profiler-infobox-gear .progressbar-rep4 { + border: 1px solid #8d8b01; + border-top: 1px solid #a4a201; +} + +.profiler-infobox-gear .progressbar-rep5 { + border: 1px solid #638701; + border-top: 1px solid #74a001; +} + +.profiler-infobox-gear .progressbar-rep6 { + border: 1px solid #288b01; + border-top: 1px solid #30a601; +} + +.profiler-infobox-gear .progressbar-rep7 { + border: 1px solid #068870; + border-top: 1px solid #0aa087; +} + +.profiler-infobox-gear .progressbar-ach0 { + border: 1px solid #2082af; + border-top: 1px solid #0aa087; +} + +.profiler-infobox-gear .progressbar-ach1 { + border: 1px solid #686868; + border-top: 1px solid #7a7a7a; +} + +.profiler-infobox-gear .progressbar-green { + border: 1px solid #2b9401; + border-top: 1px solid #3aca01; +} + +.profiler-infobox-gear .progressbar-yellow { + border: 1px solid #b1ae00; + border-top: 1px solid #e6e200; +} + +.profiler-infobox-gear .progressbar-red { + border: 1px solid #b10c00; + border-top: 1px solid #e60f00; +} + +/*********************************************/ + +.profiler-model-outer { + position: relative; +} + +.profiler-model { + position: absolute; + top: 6px; + left: 50px; + height: 345px; + width: 275px; + z-index: 10; +} + +.profiler-search { + position: absolute; + top: 0; + left: 0; + z-index: 20; +} + +.profiler-search input { + width: 235px; +} + +.profiler-inventory { + background-color: #141414; + border: 1px solid #101010; + width: 369px; + height: 408px; + position: relative; + margin-bottom: 10px; + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.profiler-inventory-inner { + padding: 3px; +} + +.profiler-inventory-left, .profiler-inventory-right, .profiler-inventory-bottom { + position: absolute; +} + +.profiler-inventory-left { + top: 3px; + left: 3px; +} + +.profiler-inventory-right { + top: 3px; + right: 3px; +} + +.profiler-inventory-bottom { + bottom: 3px; + left: 119px; +} + +.profiler-inventory-bottom .iconmedium { + float: left; +} + +.profiler-inventory-buttons { + position: absolute; + bottom: -25px; + right: 0; +} + +.profiler-inventory-bars { + float: left; + width: 25%; +} + +.profiler-inventory-resists { + float: right; +} + +.profiler-inventory-stats { + border-collapse: collapse; + border: 0; + width: 100%; +} + +.profiler-inventory-stats td { + padding: 0; + vertical-align: top; +} + +.profiler-inventory-stats p { + margin: 0; + margin-right: 10px; + background-color: #141414; + border: 1px solid #101010; + padding: 0 10px 10px 10px; + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.profiler-inventory-stats small { + display: block; + font-size: 11px; + padding: 0 7px; +} + +.profiler-inventory-stats h3 { + display: block; + font-weight: bold; + font-size: 14px; + text-align: center; + margin: 0; + padding: 8px 0; +} + +.profiler-inventory-stats a { + display: block; + color: white; + padding: 2px 3px; + text-decoration: none; +} + +.profiler-inventory-stats a: hover { + background-color: #222222; +} + +.profiler-inventory-stats a: hover em { + text-decoration: underline; +} + +.profiler-inventory-stats a: hover span { + text-decoration: underline; +} + +.profiler-inventory-stats em { + float: left; + display: block; + font-style: normal; + width: 70%; + color: #dddddd; + white-space: nowrap; + overflow: hidden; +} + +.profiler-inventory-stats var { + float: right; + display: block; + width: 30%; + font-style: normal; + text-align: right; + white-space: nowrap; + font-weight: bold; +} + +.progressbar-health { + border-top: 1px solid #3aca01; + border-bottom: 1px solid #2b9401; + background-color: #207001; + + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.progressbar-mana { + border-top: 1px solid #3472bf; + border-bottom: 1px solid #235a9d; + background-color: #174a89; + + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.progressbar-rage { + border-top: 1px solid #e60f00; + border-bottom: 1px solid #b10c00; + background-color: #930900; + + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.progressbar-energy { + border-top: 1px solid #e6e200; + border-bottom: 1px solid #b1ae00; + background-color: #939000; + + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.progressbar-runic { + border-top: 1px solid #30cfeb; + border-bottom: 1px solid #30aac0; + background-color: #3095a7; + + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +/*********************************************/ + +.profiler-talents-specs { + width: 946px; + margin: 0 auto; + padding-bottom: 10px; +} + +a.profiler-talents-button,a.profiler-pets-button { + float: left; + display: block; + padding: 3px 8px 3px 5px; + margin-right: 10px; + background-color: #404040; + border: 1px solid #202020; + text-decoration: none; + color: white; + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +a.profiler-talents-button: hover, a.profiler-pets-button: hover { + background-color: #484848; + border-color: #181818; + text-decoration: underline; + color: white; +} + +a.profiler-talents-button span, a.profiler-pets-button span { + display: block; + padding: 3px 0 3px 18px; + background: no-repeat left center; +} + +a.profiler-talents-button small, a.profiler-pets-button small { + color: #CCCCCC; +} + +a.profiler-talents-button: hover small, a.profiler-pets-button: hover small { + color: white; +} + +.profiler-talents-specs a.selected, .profiler-pets-specs a.selected { + background-color: #505050; + text-decoration: none!important; +} + +.profiler-talents-specs a.selected small, .profiler-pets-specs a.selected small { + color: white; +} + +/*********************************************/ + +a.profiler-pets-button { + height: 26px; +} + +a.profiler-pets-button span { + padding: 5px 0 5px 28px; +} + +.profiler-pets-model { + width: 360px; + height: 364px; + position: absolute; + background-color: #181818; + border: 1px solid #383838; + margin-top: 43px; +} + +.talentcalc-pet .talentcalc-main, .talentcalc-pet .talentcalc-lower { + margin-left: 370px; +} + +/*********************************************/ + +.profiler-reputation h2 { + clear: none; +} + +h2 .disclosure-on,h2 .disclosure-off { + font-weight: normal; +} + +.profiler-reputation th, .profiler-reputation td { + padding: 2px 0 0 0; +} + +.profiler-reputation th { + width: 250px; + text-align: left; + vertical-align: middle; + font-weight: normal; +} + +.profiler-reputation td { + width: 200px; +} + +/*********************************************/ + +.profiler-achievements-source { + margin-bottom: 10px; +} + +.profiler-achievements-summary { + width: 600px; + float: left; + background-color: #141414; + border: 1px solid #101010; + margin-bottom: 10px; + + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.profiler-achievements-summary-points { + position: relative; +} + +.profiler-achievements-summary-points span { + display: block; + position: absolute; + right: 8px; + top: 8px; +} + +.profiler-achievements-summary-inner { + padding: 6px; + font-size: 12px; +} + +.profiler-achievements-summary a { + display: block; + color: white; +} + +.profiler-achievements-summary a: hover { + background-color: #222222; +} + +.profiler-achievements-summary a.selected { + background-color: #282828; +} + +.profiler-achievements-summary a: hover em { + text-decoration: underline; +} + +.profiler-achievements-summary a.selected: hover em { + text-decoration: none; +} + +.profiler-achievements-summary var { + display: block; + padding: 5px; + font-style: normal; +} + +.profiler-achievements-summary em { + font-style: normal; +} + +a.profiler-achievements-total { + width: 188px; + margin-top: 6px; + margin-right: 11px; + float: left; +} + +a.profiler-achievements-total-right { + width: 190px; + margin-top: 6px; + float: left; +} + +/*********************************************/ + +.profiler-picker { + font-size: 13px; + width: 780px; + height: 554px; + background-color: #303030; + border: 10px solid #303030; + border-bottom: 0; +} + +.profiler-picker .listview { + border: 0; +} + +.profiler-picker .listview-band-top { + background-color: #303030; +} + +/*********************************************/ + +.profiler-exclusion label { + width: 49%; + display: inline-block; + text-align: center; +} + +.profiler-exclusion label b { + padding: 0 4px; +} + +/*********************************************/ + +.moneyschoolarc, .moneyschoolfir, .moneyschoolfro, .moneyschoolhol, .moneyschoolnat, .moneyschoolsha { + padding-left: 18px; + background: no-repeat left center; +} + +.moneyschoolarc { background-image: url(../../images/icons/resist-arcane.gif); } +.moneyschoolfir { background-image: url(../../images/icons/resist-fire.gif); } +.moneyschoolfro { background-image: url(../../images/icons/resist-frost.gif); } +.moneyschoolhol { background-image: url(../../images/icons/resist-holy.gif); } +.moneyschoolnat { background-image: url(../../images/icons/resist-nature.gif); } +.moneyschoolsha { background-image: url(../../images/icons/resist-shadow.gif); } + + +/**************/ +/* OVERWRITES */ +/**************/ + +.infobox { + border-color: #101010; +} + +/********************/ +/* PROFILER BUTTONS */ +/********************/ + +.profiler-button { + float: left; + margin-right: 5px; + cursor: pointer; + outline: 0; + white-space: nowrap; + line-height: 24px; + text-decoration: none; + font-weight: bold; + font-size: 11px; + color: white; + text-shadow: #333 0px -1px 0px; + background: url(../images/Profiler/button-grey.png) left 0 no-repeat; +} + +.profiler-button em { + display: block; + margin-left: 15px; /* Endcap */ + padding-right: 15px; /* Endcap */ + background: url(../images/Profiler/button-grey.png) right 0 no-repeat; +} + +.profiler-button.selected { + cursor: default; + color: #aaaaaa; + text-shadow: none; +} + +.profiler-button i, .profiler-button em { + font-style: normal; +} + +.profiler-option-left, .profiler-option-right { + margin-right: 0; +} + +.profiler-option-right em { + margin-left: 0; +} + +.profiler-option-right i { + display: block; + padding-left: 15px; /* Endcap */ + background: url(../images/Profiler/button-grey.png) -204px 0 no-repeat; +} + +.profiler-button: hover { background-position: left -48px; } +.profiler-button: hover em { background-position: right -48px; } +.profiler-button: active { background-position: left -72px; } +.profiler-button: active em { background-position: right -72px; } +.profiler-button.selected { background-position: left -24px; } +.profiler-button.selected em { background-position: right -24px; } + +.profiler-option-left em { background-position: -120px 0; } +.profiler-option-left: hover em { background-position: -120px -48px; } +.profiler-option-left: active em { background-position: -120px -72px; } +.profiler-option-left.selected em { background-position: -120px -24px; } + +.profiler-option-right i { background-position: -204px 0; } +.profiler-option-right: hover i { background-position: -204px -48px; } +.profiler-option-right: active i { background-position: -204px -72px; } +.profiler-option-right.selected i { background-position: -204px -24px; } diff --git a/template/css/global.css b/template/css/global.css index 3080e59b..0e10a240 100644 --- a/template/css/global.css +++ b/template/css/global.css @@ -1097,10 +1097,16 @@ span.menu-buttons span.hassubmenu { width: 47%; } -a.icontiny -{ - text-decoration: none; -} +/****************/ +/* INLINE ICONS */ +/****************/ + +.icontiny { background: left center no-repeat; } +.icontinyr { padding-right: 18px; background: right center no-repeat; } +.icontinyl { padding-left: 18px; background: left center no-repeat; } +a.icontiny { text-decoration: none; } +/* a.icontiny span span { text-decoration:underline; } */ +span.icontiny, a.tinyspecial { padding-left:18px !important; background:left center no-repeat; } span.icontiny { @@ -1108,23 +1114,6 @@ span.icontiny padding-left: 18px !important; } -.icontiny -{ - background: left center no-repeat; -} - -.icontinyr -{ - padding-right: 18px; - background: right center no-repeat; -} - -span.icontiny, a.tinyspecial -{ - padding-left:18px !important; - background:left center no-repeat; -} - .iconsmall, .iconmedium, .iconlarge { position: relative; @@ -1473,6 +1462,31 @@ a.star-icon-right span padding-left: 20px !important; } +.icon-instance1, .icon-instance2, .icon-instance3, .icon-instance4, .icon-instance5, .icon-instance7, .icon-instance8 { + padding-left: 19px; + background: url(../../images/icons/instance-icons.gif) no-repeat; +} + +.icon-instance1 { /* Transit (white) */ + background-position: left center; +} + +.icon-instance2 { /* Dungeon (blue) */ + background-position: -152px center; +} + +.icon-instance3, .icon-instance7, .icon-instance8 { /* Raid (green) */ + background-position: -357px center; +} + +.icon-instance4 { /* Battleground (red) */ + background-position: -564px center; +} + +.icon-instance5 { /* Heroic dungeon (purple) */ + background-position: -734px center; +} + .ffapvp-icon { background: url(../../images/icons/money_ffa.gif) left center no-repeat; @@ -2613,18 +2627,31 @@ a:hover.pet-zoom border-right: 1px solid #282828; } +/****************/ +/* PROGRESS BAR */ +/****************/ + .progressbar { display: block; - border: 1px solid #404040; - background: black; + border: none; + background-color: black; font-size: 11px; font-weight: bold; line-height: 1.5em; color: white; - text-decoration: none; + text-decoration: none !important; position: relative; - margin: 1px 0 3px; + margin: 2px 1px 4px 1px; + + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.progressbar del +{ + text-decoration: none; } .progressbar ins @@ -2638,16 +2665,16 @@ a.progressbar cursor: default; } -a.progressbar:hover -{ - border: 1px solid #606060; -} - a.progressbar:hover ins { display: inline; } +a.progressbar:hover del +{ + display: none; +} + .progressbar-text { position: absolute; @@ -2658,11 +2685,24 @@ a.progressbar:hover ins text-align: center; } +.progressbar-hidden +{ + position: relative; + visibility: hidden; + height: 1px; + width: auto; + margin-top: -1px; +} + .progressbar-rep0 { border-top: 1px solid #b82e21; border-bottom: 1px solid #9c2319; background-color: #861c10; + + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; } .progressbar-rep1 @@ -2670,6 +2710,10 @@ a.progressbar:hover ins border-top: 1px solid #c9662b; border-bottom: 1px solid #b05421; background-color: #994515; + + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; } .progressbar-rep2 @@ -2677,6 +2721,10 @@ a.progressbar:hover ins border-top: 1px solid #d59b31; border-bottom: 1px solid #bf8626; background-color: #aa7419; + + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; } .progressbar-rep3 @@ -2684,6 +2732,10 @@ a.progressbar:hover ins border-top: 1px solid #d2b130; border-bottom: 1px solid #bb9b25; background-color: #a68818; + + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; } .progressbar-rep4 @@ -2691,6 +2743,10 @@ a.progressbar:hover ins border-top: 1px solid #a4a201; border-bottom: 1px solid #8d8b01; background-color: #777601; + + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; } .progressbar-rep5 @@ -2698,6 +2754,10 @@ a.progressbar:hover ins border-top: 1px solid #74a001; border-bottom: 1px solid #638701; background-color: #527001; + + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; } .progressbar-rep6 @@ -2705,6 +2765,10 @@ a.progressbar:hover ins border-top: 1px solid #30a601; border-bottom: 1px solid #288b01; background-color: #217201; + + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; } .progressbar-rep7 @@ -2712,6 +2776,10 @@ a.progressbar:hover ins border-top: 1px solid #0aa087; border-bottom: 1px solid #068870; background-color: #007564; + + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; } .progressbar-ach0 @@ -2719,6 +2787,10 @@ a.progressbar:hover ins border-top: 1px solid #2b98c9; border-bottom: 1px solid #2082af; background-color: #157099; + + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; } .progressbar-ach1 @@ -2726,6 +2798,48 @@ a.progressbar:hover ins border-top: 1px solid #7a7a7a; border-bottom: 1px solid #686868; background-color: #575757; + + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.progressbar-green +{ + border-top: 1px solid #3aca01; + border-bottom: 1px solid #2b9401; + background-color: #207001; + + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.progressbar-yellow +{ + border-top: 1px solid #e6e200; + border-bottom: 1px solid #b1ae00; + background-color: #939000; + + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.progressbar-red +{ + border-top: 1px solid #e60f00; + border-bottom: 1px solid #b10c00; + background-color: #930900; + + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.listview .progressbar +{ + margin: 3px; } .article-footer @@ -3612,12 +3726,12 @@ a:hover, a.open, .infobox li div, .text b cursor: default; } -.tooltip a, .listview-mode-default tbody a, .progressbar del +.tooltip a, .listview-mode-default tbody a { text-decoration: none; } -.listview-void, a.progressbar:hover del +.listview-void { display: none; } diff --git a/template/images/Profiler/button-grey.png b/template/images/Profiler/button-grey.png new file mode 100644 index 0000000000000000000000000000000000000000..56c7185548170e0159411b1c24254bf9d885e4fa GIT binary patch literal 2294 zcmai$c{tQ-8^?b$W6YSb%$tnuOpTKyy9Qmykg=PSED^F#5wdF-+hoR4w8-f69#le` zDPzgf*fSIogY0XfBx5_4Ea4r_b>8>S_n+sv@9TQ5`=9&!{d}Jk8!K}WgbV@z01={v z$yopZrSWS|xFG+;Im?symo(YbiEI~qiA*7dc>{)C!56%-#6Xgd_gQa}S5#=Lw;lk% zGl(XJ_K`!p(RP1v7pdkYTxJ<1eL&tp>Bg_g$k54m_t?ttZnp)i&iRp9XEqx(3g3b3 z2!%xNDW}r%Q~HT-~_(Nkcn4JUaVl2kw}9 zc1h3(n}Ltp`T5Y96;V4FaA zjqg}Zl(?Y9;+M8RGr5lpWOc{(vIT z0BV1|*W1m_==Fs~^uI^?^ArKFz(C+OvQ?N7UZ1nqS%_ojr!@#u?r2lc%5(>uDd8)I zazxGn69C3S65E5&D%#BkCeY}#t1vSbAqLic1$om=f&c>xkI+K|!B5n&m!U&=R0jdj zMR_h@;67NwCPu0pJhxW@7^r@6c{r*nJl{s~U`6b>Sg`kC0ldFHMxyW5 z_Ln0YhC2z$C=qJ}A*=jA9J9LTx-1QyE^-z!ULPm6>!yN^gIX}{5%@ccHi;Y{T1RHd z+CNQ~0rC|_F%z6w6&S3V-shyH>g#X}TyW;pXL^GfQl_=)PH?_SUs4iMOf|`H>0%m? z@<^mAnj~WALbJd$;qoxpQR6n2kmu{$W-CT_QyZ`7$aOj)N2M8aY67aJhD%50%o>y6 zv#>-9p9IF4O(+K5IY^i9h01~F%HNzO0)R2GCh2VlVqo6B+CN@~{#8xBZVgv91<-Qw zX_1j3$)YO}azy`Y+5&;2<`h-0@>7*z$*H8_h#(T(dHv|)k}Y8EvE5VmoLV$H3EIg7 z8@DRxGsBR`Z-K*;s||tzJ>Ufh=-Rx!(7$|(pg|-M`NbQXNC~t?)1?FvI0|a<^U7G% z1!%;00GpBzk(q6v8d&K>f3l9*7^ar|(RU1r^?OK;dm7kHNd)TgKUfc5t%+fD%P?5J zy?##jv0Of`H6LR+oPPV#5{?o+fGrGhl@roM`65wr6AbS3nbJWmcV5bh7~brOTE+_q zcUy$mx*NB%<6V{0pPlKAGs9&h34i~8J0u@B8L2kw2|7Fla!h6r+Ajb zY!#-tvKF$EUf~uH5YPm=-V9O|zhd7n;T082;p2F`(I5XsK;ucEH( zYe!}g3HzqzRqRX}h+_c|SoknDEOOtrl9@Kjorkc6=phhCxtK-<8L}iWi zDp)Ggn$Hy4;whA83&4j%)b=q!c(oEA0#a-U!}|OaMH(4uviF2-{Z$0gv|OW&e}7Q0 z7*}V5D2TgwBGb|w)_qw^hMRz8D~#)yCi6$9mF*nWoAM8ol$0C>osIcxsx^VhWX9&& zWR&fy*AhLnlSJ}IsLykJ01)uQ*N{)9l+V&;p4-PfstKaTvM z>|}L?%cHSvmXd!6wAlK+naekQEO98$qb@dTrH5%3*E_p9TcK~zVGpVet8|ULSIQ|Y z23?JDEOK{C$NkmYdk$w{a5y_9k+s=+_t=7}s_JNg!^=6bR&eL>N8IcEw{MFmK)$P} zsAL4_`2YSi{Wt1nS?2xwNQiuKgJx+(1-cI0R&o5p!L$($#T67d>)}rL^?c}53qwPl z1C-!jg!-8)3ey14CM&M>Ms#f*6?wA*!bhmqtOq$(CU`yC{Ra5k>Fc zzxoIB&mf?01lj~1H3s`9G}5vGk|UHq1wz3-p#M$$vi*{beKWR~DYTXSNidG8if0Qr zZ!bNn##8DpnGaG;)c4ZMdAFO|LZPz(zw_MXji1^Zg+Bic1V-DJ5B)_Rdm>ol4epDe z#OVQF1l43vG0R2~g|&ID<{fr&c{sWK4D=NLR#g0{SXidEsacfvpNt;8)_+Bmh z&3B+7$TQ@BDwqdV4@SQw8xmnB_GM7wYySUa5aTy!d(&*z03-<1>BE)}1KdphM+P98 LTA36YdB*<-9XuQ} literal 0 HcmV?d00001 diff --git a/template/images/Profiler/character-header-bg.gif b/template/images/Profiler/character-header-bg.gif new file mode 100644 index 0000000000000000000000000000000000000000..12e7ae1f5b16f631d178a40da20a03f9e6cef2e5 GIT binary patch literal 1106 zcmbV{`!gE`0D#l0L$S@y&N+`VCGtYNBHrx6>jNEiFas z6+#k8NJu0>2&IT1N;8m&KYYJ^KYTHgpOB8;iwaeSCakVqzj9BErJL0s;bDTwFjP5Eu-GLZNYSacDFe2n0q(Mj{Xh zZ*T9Ys3;E)kMQtt7!2m=>4`$2AP`7kV4$zBFB}dJ3JMAd3Bh16{{H@cetuqFUZJ6( z!NI{uBr-8E(ZRvN+1c67&d$-%5%7Qc{*%#vDeQ~CJOPXiqb0c*m~GW`N1iY{uyujr z8$h|qSfl5QG`|TX%z}82MsY^Y-MO5hZ5{7H0%Ki!#{a|9OTU4*ab-8~FuZy$@@&*Ab028Z}8JHhDK z>+y*K2gXl9RL62i?*tsp7W%(n4T%PVnBnBE`p6*fM&jp<(ERFzX?xqa+n zk+24IjhZ6t>lD?)@60sCwv*->k@u7vLKazUXhjv7b)wjmw?s@059k8te~m0yk6;4^%ZPOd~)%=sKF;|Yj%Jo6B8mUF8|)nRxDAj(NgCI`&FyVJEA1i z5J$7lyQkWk8{%rWM~loI6ZpI%=}-XZ_B?+;FIymDTN8!{KdK!2vbN`khfcMU@e0SQ zBm7^jM;*sI=Q=L@QdQ}iwc7CQ;ZHom0g8^U+k`x-%rAZ!|0x6P576`ed$Px|O zDZX?)W2eL>ow9?s&zBo^N}cea-7=TDjNQkeJjz%(j3eKzfKP&?mA)$((kIANg7j(d ziCkKRG6wHeM_Fg?Ju`Lb+It?4Q0&ztqQU#M*OM~$U))H))M=EGuh_3o!-EeR?$%`< zyv!gakG;y~C=MEPC&99&`zx8U<^nT`RnbhKxT@(^kNu_g?N*Z$#qN1}`W^ksw1FEWrf1*?| zMvb9r=7cqNw09avQ}@jxRBF}&8meKxOUlypucgzvS>N1OX}A(R^pLk#mvuNGC((XB z98`0#ITv)3P%Zz%N|tu`?0}{n`Fx_%3IHZB-RS9ioNnwUkPbJq@K@``En{Fu6W@jL zU%#>WiGDO`|BL!)%9iYOJnd4SeJli#>3KpJTYW5oPr>xFzN;22Go*~JpASA&>%}Oo Iy%8YjUm|%j@&Et; literal 0 HcmV?d00001 diff --git a/template/images/Profiler/disabled_classes.png b/template/images/Profiler/disabled_classes.png new file mode 100644 index 0000000000000000000000000000000000000000..81502d6c9debaa8e34f3bcae2fcf71618b67994b GIT binary patch literal 15710 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 X9YR_rbXfoV<5^NnPP9hYAn^YHOc5C) literal 0 HcmV?d00001 diff --git a/template/images/Profiler/error.png b/template/images/Profiler/error.png new file mode 100644 index 0000000000000000000000000000000000000000..36d1df86d136d781b72a8ff3304c786b76b73f52 GIT binary patch literal 2858 zcmaJ@c|25mA0AmNNm;TRW2+mp*oH9}X2`w_F^U*72b0;%3^VAuu4GF{%GM=`ib%z9 zQz4S2xan4+aI=;@TT<6My48LEcze(1bIx!1JkRspo*l+MhpS)0FfLO-T|ONAYm}Yi@+hc zIHO1m8kD$+f%0ff0UHEDTk)7gQW(Gi2LT}zx&>sep%DV6kS!oS#x8IdCKd>#*hjMf z&uCXKQgj%}j0~}|1fzKkUJ;NlL( zGFSlE7z)=X!A;;`69g1tXoN%}^}q&j1RMr8fFTU@5lEDw0SXQWe|;c=Xe@Ft3Xik< z8cT4pfP`{5OcV^p<#M51Lnwn40z;UYnQdwq80ZTS`s^q=hse{Xvo*gd-~cv>MPYI% z3_5sIkr>2?;8;Kenf_A(jrm=c&i>jaLBn7?A`^yy!Z%C$26S=x|4Lw$DN)KlzgQ|L_msVURlRVBO(VMfO*c~is z#Rj+W(!z654;?LkdH>gm)eOt|H&;*Qq#*EdFC-?bx2%6^s2}Ea_#XQ_XS{AFomxKO zU*Qy`dcG!WTIckoU(9_ZjWgzZti@$qp88GJ&we^jOL0qA%M2Lu3y7L}vHx;-M^1Kf zrOqDT!3}C9Yx3-VWUHfsHoK5ZY|OT5Zg%1k&ZM6;m-OC~0FfCVUh_njqIu62)f#7S zA2{-PEH&!m{QbeY1fIQUeExIs6Gx3cW2#zv^XKoB3WH+2lG);a8KSATDnN5ap&aTT zvR4TzKm#O7HLXZ)Nfx-_yak~sk)pK_4VqK74B!IvoakB zZ_#lYpn1^{!#$Cj*7W3oGT* zQc3%sNrZp{UExQc_h620UwzcQ0{Z)?#`bV!38!=*<`1(J4(!P2S{O6fFcviGuc#K6_&<@j%x5l-xfe|UY4k*_; z?(EZYz{#mb`&)@RK!lf?r+k+p%r0hqkXpP1s;BPpOyWswW8GKW~4>~slSFO_hcN}rUZRi zGJ%@ThL*)vXe-NVUmcjrw7=)<-T5{GcqmWfofwqN7I`R!?oL*WeC4Qf+#4zTwCdCl z24|upub@u^FU4vZCb0|qLNBM4mzvAeJXsNUx|mUA_mg%4cxT{c-ExZ8mFDGRI?ZP_ zb~wh<(xh6>*;S$y=1pyHIbBFZm04Z}osZ+2Z>F8$W(&(4&cBiklGe@!Vw- zcIFWaoOTzj-o^@J>0%xK;6G|sN*|l_u<6wL&7O?6YO&VknCEGYP)n+GE5_n|5+Rz& z;)drlE@O3tg5?XB?tUuOst*mVyxDEipZ~(ucWz=fw$$&Ym?7G=T>AcJS9-HXL7Gbb zWBp1WL+_9e$P%hG`4%WKwM;qUmI;xG73XN~1 z9VOI4o?HpeBY=jibyZ~&z-b2JE8gI$ODao z4GIKdr19TPH#aVHvLjmJ!}215gR>^W25 z7A2qi*BR>~pBUZ>Syn5g#Pow!8uY^3?R|CCbJPd3Rv$&*jDR_pD3+^{3XlDrCQss2 z?3&(|TlmcC!L(m>JGVmW3UX27TiU3z4RUi=Pf{ECRp}+?<@XEUq0BKj2^>!iNo$ichXy=!u{O~I=Jh?B&UvHz3G^~p6ZH$l2&}xy=(2%y^vYa;Rw<9 z+#UP?y2hUe@|T2@2bb@OmsVgFokEH1nE)X%kV?r7eEoou{pR1RgRLvB$|f-WKUMeC A9smFU literal 0 HcmV?d00001 diff --git a/template/images/Profiler/jumpto.png b/template/images/Profiler/jumpto.png new file mode 100644 index 0000000000000000000000000000000000000000..6a8df1e3cfcf539481d22a162fc81b956e0678a7 GIT binary patch literal 3639 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 JPDHLkV1g@7$5sFU literal 0 HcmV?d00001 diff --git a/template/images/Profiler/lookup.gif b/template/images/Profiler/lookup.gif new file mode 100644 index 0000000000000000000000000000000000000000..398674d58c56da434e3d65da7af94b346650ad67 GIT binary patch literal 982 zcmZ?wbhEHb6l2g~c$UMkb?erpOP4x1IsO0t-@?M;_wU~?Uc4wMDDd#`m^EvbgM-7I zIdivU26hl$4a_=H}Yk+S|8p+u7MIU$)A}$LIU^@3FD5 zZ{NNR4h{|v4|jKWfAZu>VPWCSnKR$Ld-v(nr;8UaIyyQYIB;Om!ljokU79?3@}EC{ ze0_ZvEn4*N-@g?rRxDe(vaYV~)TvWTm#m12iptE)%+JrSsj11!%j@XqsIIO~OG`^i zO6uw9advjTe*OBFFJD?(TIS7LID7W&s;ZiXhKAKE*Lrz*ojZ4K_3G7+A3uKh@Zq;_ z-@?Nq{{H>@^5x4PKYl!T@E|EE+0D(Zv!iF`j5&`UJ+iT}*|1^r*RNmSym@18Za#Cy z>|@7{6&DxV+uP^n=EudwO`0_6^5x5i4jn2lFJHB4Rb*u3lqpksdwc!-{1z`>Y+zu( zKrT@H$->CMkOPbiAOOV)1N;952?+yZ4X2op1mEEB=$!ru6PWc_rIf`KS!T_iI9E?w zD#}Q5mY}c*C#Q(8;M^R)0A(XJ7IAjQ9Xofhi%(=#5nIB5=cqe)6^tQME;F7|#IZWh5^CT0q3Y)Vget!0a25kAUg7WV1OnTN9u zxOuWOiS&H^ZSH?iAV%bd&QB+W#*GYIr%o78c*eYrMMyJBXB*=|&Pq)g8|F*_MbF6^ zvK1{S*yh{Cs`^WLSQaZtm%b_LY}gr`wlVD1j)y@D+uASl*p}NyU3)W=OE%)7$nI}1 z!VQ=X>pgQ~YG%+<@0n(qMXa6ziq0J(hDArF_uhAk z=m}9&TH44j+y8Q?#pZrG_jxI<#U*zz<8*UZJh?YaKi$ohU**R!yN=x zeo7bPPI}F@p`mq&=ybs+Y#W*z3)ys&^cUz_a;05oIPyl~^J8~zHqNB*3KNCS2DXjm zcP<1hIKcg8W1zT((u0OPHuFtW?C1YAwNguDak#-7zps)lZ4Voxw1bRd1Iup40}cXD zMGab**LylFXykYm=FF}-h5ZoQVb6~Fbz(^?9aaM*ZK_KR&Y<;(>Iw+lEwJ(Hd?H}!y2 m$?mgZv$N*cs!L@qTNoyuJ}q@wWMccm2{)2@ZN(xL7_0#_*Pbo_ literal 0 HcmV?d00001 diff --git a/template/images/Profiler/search.2.png b/template/images/Profiler/search.2.png new file mode 100644 index 0000000000000000000000000000000000000000..08b22e28c525a584f3baccd16861f9117d020643 GIT binary patch literal 851 zcmV-Z1FZasP)w|E?h3xRF>sNuh*;8>-DV@zIVjq z@mjy%FU;q2vET27)kBh`NH`oW0&WQ&e<2C-bUMvVCKF+01>DDOw-boh?RMwj@wZOG zVzCHmnkFa(;zituUoQvf1LAx>3u=M55kHck6F`v!6SGbN_5z9|m_6`H0+putlmspZ zRs#0~Rs#0~?g?L&fFmSD63nXtmjjmrH^xULFbS7XY&KhfQc2*N4RM|fH{~`$vNI&FH zNL)AJ^3i7HRsf0H3`XOy{E&orAAE<+ zW)s2_fdT>dgA(Evrtd&S0Z(p`7vI5{p2(44ysdH_n@N&jV!kTDWQCPLSqU&akW>QV z=5pY2;Kuk>2|OpT61XR@61XRDIea@YDv;!S2gGfXpg}afUN0%%!Q=5DR`wm(cVOS) d(RcVSzyLU;M_HdZq$B_U002ovPDHLkV1l1Rg#G{k literal 0 HcmV?d00001 diff --git a/template/images/Profiler/search.png b/template/images/Profiler/search.png new file mode 100644 index 0000000000000000000000000000000000000000..2ca38f359a8bbabc404fd4fe50b240ab528df1fc GIT binary patch literal 1088 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 BwqpPQ literal 0 HcmV?d00001 diff --git a/template/images/Profiler/text-input.png b/template/images/Profiler/text-input.png new file mode 100644 index 0000000000000000000000000000000000000000..e144f24e31a8648e19fd0fc56d424e234d8ac580 GIT binary patch literal 483 zcmV<90UZ8`P)si> zd9$txzC@v=wSA9*tG-#G(A+kfcnLOV+K{-26e+Zj|APS&cf!w^5skH6F5SUk@DK#S zjqAFhWm!rV&^O29(X8EW_m=1RYO~oq>*;j*G@H$C$K$c`eP20_!zYE_D$7z8MG%1lVdJ%$kJL92YMgL;czgo*X#A% zmTi?x4&nfmX+T<#CZr857q)Gi1>h?Z>A|#7-vDqLiO}_-oJfGvK+JZleF1<80{nP_ za54wZV1fYW&L9K=5C}jZz^@0=z5vh!!XX`Civ4#5@+ z;0yu~2tXhJfdKy`5dJU)oWa+;K*t0zfw08_*kS>fZL#>N3D7-7?6NFB>Ze)*XrA&e zZPZeOhru9Ek$S ze}FaxbxNxIgcSUSh{^>&AQA;7N)!G1w=x!&M2{SclK>&?)DsG zkp|^0D=O*0rtU5lY|%o2$ApmKCcIS;mME}1OWuF2*+_^BLDRK{QM&g ze>?Q!4MiK&*h&2qDaC-|2gT4apUJu51J_lutccxOKUwrHCp4G9v;<0teJ8LT;Rp7`_Vuw26E! zfcnzVbS?@3@`VpE3#!)zPYM7B*g?L)_ag`7aDcTsFr61*z6NMGpjOQDtWg7Gi}0fq zltTck0_0B#pizXa6k+`@0pI{Z2cQNB)_}zx04b>cJ|JJ51)&iWoQ7%?VQWp8UKkew zI3_o7xTpcOk?$COnRCCdcu6svubar;O*X?%8^Mda0@4=2GL{YTS>2!9twzdKi1m^|W#&|qdS65eja8r3+ z5MEIdcpgD~Q`RZZ3&I;RGMJqg1P92uplHM(fUp2~QCkMH7q$7K8UR89zyX2+pa!4_ zueJb_$pke(0L(iafD{A)FbhH-00H0t^Z}~}oEIbrKC*^SO@RPHqmzz%p{P#A_sH#awXy4WQ; zt_+L_G-O3hfCEIEGF3RBQUibkR?h*{7{CEC4H;4pQV>!Q93buh^Z`pC033iCfEoax z1|S6i0x1Xr$lU$Z3C9pXi2P==$tz>!zMxjC1p(})9qbDd1oj0j0UqrO`Xj&qyiA~z T-#_^d00000NkvXXu0mjfbdb^s literal 0 HcmV?d00001 diff --git a/template/images/Profiler/toggle-b.png b/template/images/Profiler/toggle-b.png new file mode 100644 index 0000000000000000000000000000000000000000..73a92f3eae90149d4071b3ad0c80879b13c0ccba GIT binary patch literal 3986 zcmV;D4{h*?P)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z000ENNklf_C3vA0Y+L5Tyzd4-kohlC73k z2sCJs7Ks*1RJ#pA6c7m!Y*t|GVP>}QB{GO@R#B8W^L^4tmZ7?z|8veA+t+S$bF=FA z`vMzy@6~FxF0w4!K0ZEP-`d(5B;9UTH#aw|jv>-CU6`Mr|FFEgoJxA1R8^&_s#qCA z42MIVpP#GUZoiZC(X%8rDa%sV*Vl8BGLmeVJkKR5AlWdFUMbfNfFw5{$w+R31p>8vx~+o(vWwQ?8BTy_fgCN0JQ-PLf176ZA?)}x{p`kB>fr9 z=aL>I@qw=zw_{0(q@JWdB>i4hRh~%tN77xip2t@K)K_v#QYz_JNlwyliKN>J(W97V zsJG-PNxAp_mq*F>QS@zmjN}>*)=_dUsVvL#jbi;CNg7HTOq6V>r(ib`(hw7^BtH2N zBE$S65eak}@P4CeL$83P`rRkK#8d?87g-H7UtR zZb-T2m(Y!uYkD$08R*GCPX@|0{GcQkMM08{QWOPArY8eE8R*GCPX>B2(39bRBpJ!Z zlT5j$T!V#jjb!%8z&;r$*MMX|GJG$|+zhda_g>Dq9!WMVILk7PMx)P?ie!3vnpH7` zb54?a!{Km$cX#)bq|1 zVu%pJMZ4YJK07;G-`m?8B&VmR;`AR|BuTO`J3ISfadB~cFpP8Vu~~zaT3rxWI!?? z8ITM=R5H^w(=|}80m<-FNanU?14z90-x@U79K5jGgd~R$NU~8v2qc-F4D@8EQIgpw z+utW6xe1bagTj7KCdrg*uppV~n&}$o$?#JP4k7d?*MKLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z000B@Nkl`Q| zuKF$f3U{Gjq#MDNe~_Rilxoc6oYO^Sys6kt+d1cg&jUjc$>#m#d7txdjse))+iR_@ zt$iE}20MA4FFNOts@Lr7EHxlqU0wZjc6PSk?RFUshpJ2<&CJYD1De;@*Sl9&SLl}? zR^IzDfV;c9d26jI5(z+>=Q-YcRU{Gsy!QeS6M%D003yga_XU6gI3fVGps%0>$pMjD zkQ|^4PzFfKfVb%YYpno8khNAVNG(V$NDheZ00D^X0H9}#nNu4I?|>9&uB@zlpQh=W zX2fAtuh%g^dwP2M-TM0aVZC1e;Ju$yX~L+{XkdU8m<7HC=7A}|s60V*Z@l*yV^W}5 zJgMpuOnDi?3Gg%UBQOVy03~uYN`M+r2c}8~{0jU8JOEEX4*24c{$Hg<@tZ(a14xqO zy>qS){0Tf30OWvbR4Z~eEC0YbmjFHB4*>`QpjmX6TA2ZZqWw%dKrN`E;eT0tpj84G z7QO%JMFvO}tUwewFq|9(*;gK^IsmThFs}g^2|%SX6Sa1=2`YYqjsiH01O5iUPJGG% z)jGhvbbz05fR_U*m47V*oI*J0QpBqn-~=Ej0QVXIuMiFr!v3EC$N>=@pbUtZ0WaqO zYC+Y{1Ki{&NW;*`6EX8*oT`=3Fd^*A4Vj^HuFiOgG%X%Ms77g#0|{Vi0G&?f_uJds zAAmMr)~Z$fYE%bWK!b8m`1ts^eQ2|-4_%YfL_uQfHw|6 zFKWlp^NZTnT8)5W1CRqE0#F7hgx@xR(P*R$h@jDEBnPMk34lgHngKLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z000ECNklRWXTi)CfY0Ocq1WN^s%Ajf;UE+$gi3#pr6>>kCMO z;EVVQ{V=l-L6Er65F_IlQ@QufA{EK>*qfp0p-z1t6a;luAOAV$R+6KWq@$yw=H}++ z$Kh~zkmvbY2tiyo?u;Q87Z;UDYIM8Z!)~`L5^Rqc zqY_Dte!sthV7p|J(mc-#DUfn?j|8Y)n(NiyXcOh^tPAlWD(1d>d-2BvE$ z(R3X`;E|@`o=lRfl4S2aNj8f2o+Q(gfu0N{N;2nU+vj8?BN@y{<_!wlgBMArTmzB; z$$(^Fx`wYcUGrG80#L5$$zVZpB1uV-JR}K~+bXG~MyJ#HAxV-=1~7ZnYBf1Yt%Ze! z_gh1RpHlE#ww&{ug$isNxj(wr+K|1RklNq3{Ca&ZInIcN@-lT9W+lfrE-;qlIAfl2Z6nFyOOi>l@gxV5 zY%ad7L>=8`OuT)`yAH(o<|lPr321(W=b!!wdiB>B}PM<|X^U~%vw$%d0WYu*Dt1%BD%xUsXxDjQ$^wbKssiZWMq;|XgN3YlWQIoGahT;z> z+2xkpkW`mcb1_C;TwJtHPEL0F{r>kMgjl4RccRKK`8!E%H?z{IUi^}NYz)WVt_nz& zq_eZL=FZN}NALZC_kIoWc9@@^pG;ue+uP^Y*Vo54H#Zs%huj%Mtgfz3c1zsf-ydFG zUCDc9Eo)4-_z9$*e%O3;*Gbat-FnHUA0Sc)6x0 z)02Uo4D@86T*Eg?viF`O8^wE1lIh7nPX>B2(363l4D@994@pL{@g!5ODc4}3TqBut zGH^}?$~7PvkPKf-vUBdiIk(L4W%r!yN2AfFMx*iD^Yb%Pw!tJjNv(Ff{eEw6@3da8 ze~`3H>9#|w)soX>*VB@ucal~#+2zG@7(4W*GE+@f0yT=)V23=Dq}|=!xlX5Z`ttH} z;JshtzSyDJY)&=}tgo-1-`?IHKR!N+wGy_NZvSZv27|-FV4x6!oTD9E!Z|mQ{Pgs+ z5@STLQOSvH9Z-S3`hnf!#9=8bj@@P zlxsjT{O^)^tXTnG2d^Z-x7EQ5vsFoQnx-V#C~2CKWO_2tlc7XO=A3N%oQ&kENahU+ z+dY{iQ?9{+WTxvXos&tj@p7G}=|h^PEQT>$u6>^8pPJ1kPra;)R2qBcZc34{Ou002ovPDHLkV1fh`f;a#G literal 0 HcmV?d00001 diff --git a/template/images/cog.gif b/template/images/cog.gif new file mode 100644 index 0000000000000000000000000000000000000000..ff64418fbf4e8786033cf047a70331bc599c8244 GIT binary patch literal 655 zcmZ?wbhEHb6krfwc$UqerlzK>tgNc4djI}?MMcG9$Bro}DXFWg-?(vO@7}$~j~{>c z?%jn87iP_xb>+&HhYug_+O_Na`SW}B>^XPt-2VOh3knLJK7IP^*|Q%%esp(tA3AjC z%a<=NU%ote@L*|a>CT-y4;(mf?b@{?M~+;+eEIO= z?d|PtY;5k`ySH)U#vMC$1P2GdfB!x*GVasCDebH>BNBOxInFE7u}&u_wn32)xKnKWtA zi4!N1l9KG~?1F-Vva_>q-@aX5UVifA$vb!M%$PBwqM{-rBjdq?2fKIg-n41c|Ns9P zC;*B-Sr{1@vKe$hW`N>^f&EQGc2g6BHZQL^Lvu4b6FVb|x~gh0P+4CSQ-rvrB!`5A zyRE5AJW~s^7q_$_D{GK6cNBA1Hlwo`cUEeq0I!~mxGQ5e1B(N*yb3=*a|$PCVmb>$ zoTgf!ub{k^k3OG(tX`6~s3VskD~}Bun-+(Vg0Qk&f)u9{Yly)+GbJ?v4T<8`qkJMF zY#tFxhfi^f@bCDu;=rRDoSYe44FZgcjvUG=B_X?~DmC)6@R(R!Fm-b5OFCv1pkdH> zutAK^X~CRCZwFCU4;z7*0*y_QQvL-CqAqhdFfe;Y@w`alyxi#8GAHFG)6r`S92l$t D`+f$W literal 0 HcmV?d00001 diff --git a/template/item.tpl b/template/item.tpl index 32e1513b..ac32b672 100644 --- a/template/item.tpl +++ b/template/item.tpl @@ -14,6 +14,9 @@ {include file='bricks/community.tpl'} var g_pageInfo = {ldelim}type: {$type}, typeId: {$typeId}, name: '{$name|escape:"quotes"}'{rdelim}; g_initPath({$path}); +{if $user.id && $redButtons[$smarty.const.BUTTON_EQUIP]} + DomContentLoaded.addEvent(function() {ldelim} pr_addEquipButton('equip-pinned-button', {$typeId}); {rdelim}); +{/if} //]]> {include file='bricks/infobox.tpl'} diff --git a/template/js/Book.js b/template/js/Book.js new file mode 100644 index 00000000..6ecedf22 --- /dev/null +++ b/template/js/Book.js @@ -0,0 +1,99 @@ +function Book(opt) { + if (!opt.parent || !opt.pages || opt.pages.length == 0) { + return; + } + + opt.parent = $WH.ge(opt.parent); + + var + d, + a, + _; + + this.nPages = opt.pages.length; + + this.parent = $WH.ge(opt.parent); + this.parent.className += ' book'; + + d = $WH.ce('div'); + d.className = 'paging'; + if (this.nPages == 1) { + d.style.display = 'none'; + } + $WH.ns(d); + + _ = $WH.ce('div'); + _.style.visibility = 'hidden'; + _.className = 'previous'; + a = $WH.ce('a'); + a.appendChild($WH.ct(String.fromCharCode(8249) + LANG.lvpage_previous)); + a.href = 'javascript:;'; + a.onclick = this.previous.bind(this); + _.appendChild(a); + d.appendChild(_); + + _ = $WH.ce('div'); + _.style.visibility = 'hidden'; + _.className = 'next'; + a = $WH.ce('a'); + a.appendChild($WH.ct(LANG.lvpage_next + String.fromCharCode(8250))); + a.href = 'javascript:;'; + a.onclick = this.next.bind(this); + _.appendChild(a); + d.appendChild(_); + + _ = $WH.ce('b'); + _.appendChild($WH.ct('1')); + d.appendChild(_); + + d.appendChild($WH.ct(LANG.lvpage_of)); + + _ = $WH.ce('b'); + _.appendChild($WH.ct(this.nPages)); + d.appendChild(_); + + opt.parent.appendChild(d); + + for (var i = 0; i < this.nPages; ++i) { + d = $WH.ce('div'); + d.className = 'page'; + d.style.display = 'none'; + + d.innerHTML = opt.pages[i]; + + opt.parent.appendChild(d); + } + + this.page = 1; + this.changePage(opt.page || 1); +} + +Book.prototype = { + changePage: function(page) { + if (page < 1) { + page = 1; + } + else if (page > this.nPages) { + page = this.nPages; + } + + var _ = this.parent.childNodes; + _[this.page].style.display = 'none'; + _[page].style.display = ''; + this.page = page; + + _ = _[0].childNodes; + _[0].style.visibility = (page == 1) ? 'hidden': 'visible'; + _[1].style.visibility = (page == this.nPages) ? 'hidden': 'visible'; + + _[2].innerHTML = page; + }, + + next: function() { + this.changePage(this.page + 1); + }, + + previous: function() { + this.changePage(this.page - 1); + } +}; diff --git a/template/js/Profiler.js b/template/js/Profiler.js new file mode 100644 index 00000000..a282cf56 --- /dev/null +++ b/template/js/Profiler.js @@ -0,0 +1,10059 @@ +var $WowheadProfiler; + +function Profiler() { + $WowheadProfiler = this; + + var + STATUS_NONE = 0, + STATUS_WAITING = 1, + STATUS_SYNCING = 2, + STATUS_READY = 3, + STATUS_ERROR = 4, + STATUS_LOWPRIORITY = 5, + + _versionBuild = 14, + + _self = this, + + _profile = {}, + _filter = {}, + _items = [], + _activity = 0, + + _pageTitle, + + _container, + _divHeader, + _btnCharacter, + _btnProfile, + _icoProfile, + _divLine1, + _divLine2, + _divLine3, + _lnkEdit, + _divMessage, + _divTabLinks, + _lnkFeedback, + _lnkHelp, + _lnkArmory, + _divTabs, + _divInventory, + _btnCompare, + _btnUpgrades, + _tblInfobox, + _ulQuickFacts, + _spGearScore, + _spAverageLevel, + _divSpec, + _spSkills, + _trRaidProgress, + _tdRaidActivity, + _tdRaidCompletion, + _tdRaidGearMeter, + _divStatistics, + _divAuras, + _divTalents, + _divPets, + _divReputation, + _divAchievements, + _divTitles, + _divQuests, + _divCompanions, + _divMounts, + _divRecipes, + + _dialog, + _tabs, + _inventory, + _statistics, + _talents, + _pets, + _reputation, + _achievements, + _titles, + _quests, + _companions, + _mounts, + _recipes, + + _replaceJson = { + atkpwr: ['mleatkpwr', 'rgdatkpwr'], + critstrkrtng: ['mlecritstrkrtng', 'rgdcritstrkrtng', 'arcsplcritstrkrtng', 'firsplcritstrkrtng', 'frosplcritstrkrtng', 'holsplcritstrkrtng', 'natsplcritstrkrtng', 'shasplcritstrkrtng'], + hastertng: ['mlehastertng', 'rgdhastertng', 'splhastertng'], + hitrtng: ['mlehitrtng', 'rgdhitrtng', 'splhitrtng'], + splpwr: ['splheal', 'arcspldmg', 'firspldmg', 'frospldmg', 'holspldmg', 'natspldmg', 'shaspldmg'], + spldmg: ['arcspldmg', 'firspldmg', 'frospldmg', 'holspldmg', 'natspldmg', 'shaspldmg'], + splcritstrkpct: ['arcsplcritstrkpct', 'firsplcritstrkpct', 'frosplcritstrkpct', 'holsplcritstrkpct', 'natsplcritstrkpct', 'shasplcritstrkpct'], + splcritstrkrtng: ['arcsplcritstrkrtng', 'firsplcritstrkrtng', 'frosplcritstrkrtng', 'holsplcritstrkrtng', 'natsplcritstrkrtng', 'shasplcritstrkrtng'], + arcsplpwr: ['arcspldmg'], + firsplpwr: ['firspldmg'], + frosplpwr: ['frospldmg'], + holsplpwr: ['holspldmg'], + natsplpwr: ['natspldmg'], + shasplpwr: ['shaspldmg'] + }, + + _progress = [ /* some example data */ + { level: 150, instance: 2, name: LANG.pr_dungeons, icon: 'spell_holy_championsbond', achievs: [477,478,479,480,481,482,483,484,485,486,487,488,3778,4296,4516,4517,4518], kills: [[1232, 29120], [1235, 31134], [1236, 29306], [1233, 29311], [1242, 23980], [1231, 26723], [1240, 26861], [1239, 27656], [1238, 28923], ] }, // some lvl 80 Dungeons normal + { level: 187, instance: 2, heroic: 1, name: LANG.pr_dungeons, icon: 'ability_rogue_feigndeath', achievs: [489,490,491,492,493,494,495,496,497,498,499,500,4297,4298,4519,4520,4521], kills: [[1506, 29120], [1509, 31134], [1510, 29306], [1507, 29311], [1504, 23980], [1505, 26723], [1514, 26861], [1513, 27656], [1512, 28923], ] }, // some lvl 80 Dungeons heroic + { level: 200, instance: 7, zone: 3456, icon: 'achievement_zone_firelands', achievs: [574], kills: [[1377, 15991]] }, // 10-man naxxramas + { level: 213, instance: 7, heroic: 1, zone: 3456, icon: 'achievement_zone_firelands', achievs: [575], kills: [[1390, 15991]] } // 25-man naxxramas + ]; + + + // ************************************************************* + // ************************************************************* + // Function Hooks + // ************************************************************* + // ************************************************************* + + + g_items.add = function (id, json) { + if (json.jsonequip) { + _fixJson(json.jsonequip); + + if (json.jsonequip.socketbonusstat) { + _fixJson(json.jsonequip.socketbonusstat); + } + + if (json.jsonequip.subitems) { + for (var i in json.jsonequip.subitems) { + if (json.jsonequip.subitems[i].jsonequip) { + _fixJson(json.jsonequip.subitems[i].jsonequip); + } + } + } + } + + if (g_items[id] != null) { + $WH.cO(g_items[id], json); + } + else { + g_items[id] = json; + } + }; + + // ************************************************************* + // ************************************************************* + // Public Methods + // ************************************************************* + // ************************************************************* + + this.initialize = function (container, opt) { + _container = $WH.ge(container); + if (!_container) { + return; + } + + _initData(); + _initHeader(); + _initProfiler(); + _initInfobox(); + + if (opt && opt.id) { + _requestProfile(opt.id); + } + else { + _registerProfile({ + id: 0, + name: LANG.pr_header_noname, + region: ['', ''], + battlegroup: ['', ''], + realm: ['', ''], + level: 80, + classs: 1, + race: 1, + faction: 0, + gender: 0, + source: 0, + sourcename: '', + user: g_user.id, + username: g_user.name, + published: 1, + nomodel: 0, + talents: {}, + pets: [], + skills: {}, + reputation: {}, + achievements: {}, + statistics: {}, + activity: {}, + titles: {}, + quests: {}, + spells: {}, + glyphs: {} + }); + + _talents.resetAll(); + _pets.resetAll(); + _lnkEdit.onclick(); + } + }; + + this.requestProfile = function (id) { + _requestProfile(id); + }; + + this.registerProfile = function (data) { + _registerProfile(data); + }; + + this.isArmoryProfile = function (allowCustoms) { + return _isArmoryProfile(allowCustoms); + }; + + this.showGearScoreTooltip = function (total, e) { + _showGearScoreTooltip(total, e); + }; + + this.updateInfoboxSpec = function () { + _updateInfoboxSpec(); + }; + + this.setPlayedTime = function (time) { + _profile.playedtime = time; + _updateInfobox(); + }; + + this.setGlyphs = function (glyphs, who, when) { + _profile.glyphs = $WH.dO(glyphs); + + _talents.setGlyphData(_profile.glyphs, who, when); + }; + + this.resetExclusions = function () { + if (!confirm(LANG.confirm_resetexclusions)) { + return; + } + + g_user.excludegroups = 1; + g_user.excludes = {}; + g_user.includes = {}; + + $.post('?account=exclude', { reset: 1 }); + + _mounts.updateExclusions(); + _companions.updateExclusions(); + _recipes.updateExclusions(); + _quests.updateExclusions(); + _achievements.updateExclusions(); + _titles.updateExclusions(); + _reputation.updateExclusions(); + + Lightbox.hide(); + }; + + this.loadOnDemand = function (wut, catg) { + _mounts.onLoad(wut, catg); + _companions.onLoad(wut, catg); + _recipes.onLoad(wut, catg); + _quests.onLoad(wut, catg); + _achievements.onLoad(wut, catg); + _titles.onLoad(wut, catg); + _reputation.onLoad(wut, catg); + }; + + this.resync = function () { + if (!_isArmoryProfile()) { + return; + } + + _divMessage.innerHTML = LANG.pr_queue_addqueue; + _divMessage.style.display = ''; + + new Ajax('?profile=resync&id=' + _profile.source, { + method: 'POST', + onSuccess: function (xhr, opt) { + var result = parseInt(xhr.responseText); + + if (isNaN(result)) { + alert(LANG.message_resyncerror + ' ' + result); + } + else if (result < 0 && result != -102) { + alert(LANG.message_resyncerror + '#' + result); + } + + pr_updateStatus('profile', _divMessage, _profile.source, true); + } + }); + }; + + this.link = function () { + if (!_isArmoryProfile() || !g_user.id) { + return; + } + + $WH.Tooltip.hide(); + if (confirm(LANG.confirm_linkcharacter)) { + _profile.bookmarks.push(g_user.id); + + new Ajax('?profile=link&id=' + _profile.source); + + if (confirm(LANG.confirm_linkedcharacter)) { + window.open('?user=' + g_user.name + '#characters'); + } + } + }; + + this.unlink = function () { + if (!_isArmoryProfile() || !g_user.id) { + return; + } + + $WH.Tooltip.hide(); + if (confirm(LANG.confirm_unlinkcharacter)) { + $.each(g_user.characters, function (index, character) { + if (character.id == _profile.source) { + character.pinned = false; + } + }); + + _profile.bookmarks = $WH.array_filter(_profile.bookmarks, function (x) { + return x != g_user.id + }); + + new Ajax('?profile=unlink&id=' + _profile.source); + } + }; + + this.save = function () { + if (_profile.user != g_user.id) { + return; + } + + if (_profile.id == 0) { + if (!confirm(LANG.confirm_newprofile)) { + return; + } + } + + var buildData = _talents.getTalentBuilds(); + + // @TODO@ Update save format + var params = [ + 'name=' + $WH.urlencode(_profile.name), + 'level=' + $WH.urlencode(_profile.level), + 'class=' + $WH.urlencode(_profile.classs), + 'race=' + $WH.urlencode(_profile.race), + 'gender=' + $WH.urlencode(_profile.gender), + 'nomodel=' + $WH.urlencode(_profile.nomodel), + 'talenttree1=' + $WH.urlencode(buildData.spent[0]), + 'talenttree2=' + $WH.urlencode(buildData.spent[1]), + 'talenttree3=' + $WH.urlencode(buildData.spent[2]), + 'activespec=' + $WH.urlencode(buildData.active), + 'talentbuild1=' + $WH.urlencode(buildData.talents[0]), + 'glyphs1=' + $WH.urlencode(buildData.glyphs[0]), + 'talentbuild2=' + $WH.urlencode(buildData.talents[1]), + 'glyphs2=' + $WH.urlencode(buildData.glyphs[1]), + 'gearscore=' + $WH.urlencode(_profile.gearscore), + 'icon=' + $WH.urlencode(_profile.icon), + 'public=' + $WH.urlencode(_profile.published) + ]; + + if (_profile.description) { + params.push('description=' + $WH.urlencode(_profile.description)); + } + + if (_profile.source) { + params.push('source=' + _profile.source); + } + + if (_profile.copy) { + params.push('copy=' + _profile.copy); + } + + var inventory = _inventory.getInventory(); + + for (var i in inventory) { + params.push('inv[]=' + i + ',' + inventory[i].join(',')); + } + + new Ajax('?profile=save&id=' + _profile.id, { + method: 'POST', + params: params.join('&'), + onSuccess: function (xhr, opt) { + var result = parseInt(xhr.responseText); + + if (isNaN(result)) { + alert(LANG.message_saveerror); + } + else { + if (result < 0) { + alert(LANG.message_saveerror); + } + else if (result != _profile.id) { + _updateSavedChanges(1); + + location.href = '?profile=' + result; + } + else { + _profile.lastupdated = g_serverTime; + + _updateSavedChanges(1); + _updateInfobox(); + + alert(LANG.message_saveok); + } + } + } + }); + }; + + this.saveAs = function () { + var name = prompt(LANG.prompt_nameprofile, _profile.name); + + if (!name) { + return; + } + else if (name.match(/`~!@#$%^&*()_\-+={[}\]|:;"'<,>.?\/]/)) { + return alert(LANG.message_saveasinvalidname); + } + + _editProfile({ id: 0, name: name, copy: _profile.id }); + + _self.save(); + }; + + // Named "remove" instead of "delete" to avoid syntax issues + this.remove = function () { + if (_profile.user != g_user.id) { + return; + } + + if (!confirm(LANG.confirm_deleteprofile2)) { + return; + } + + new Ajax('?profile=delete&id=' + _profile.id, { + method: 'POST', + onSuccess: function (xhr, opt) { + location.href = '?user=' + g_user.name + '#profiles'; + } + }); + }; + + this.signature = function () { + if (!_isArmoryProfile() || !g_user.id || !g_user.premium) { + return; + } + + window.open('?signature&profile=' + $WH.g_getGets().profile); + }; + + this.pin = function () { + if (!_isArmoryProfile() || !g_user.id || !$WH.array_index(_profile.bookmarks, g_user.id) || _profile.pinned) { + return; + } + + $WH.Tooltip.hide(); + if (!confirm(LANG.confirm_pincharacter)) { + return; + } + + $.each(g_user.characters, function (index, character) { + character.pinned = (character.id == _profile.source); + }); + + _profile.pinned = true; + + new Ajax('?profile=pin&id=' + _profile.source); + }; + + this.unpin = function () { + if (!_isArmoryProfile() || !g_user.id || !$WH.array_index(_profile.bookmarks, g_user.id) || !_profile.pinned) { + return; + } + + $WH.Tooltip.hide(); + if (!confirm(LANG.confirm_unpincharacter)) { + return; + } + + $.each(g_user.characters, function (index, character) { + character.pinned = false; + }); + + _profile.pinned = false; + + new Ajax('?profile=unpin&id=' + _profile.source); + }; + + this.updateSavedChanges = function (saved) { + return _updateSavedChanges(saved); + }; + + this.updateGearScore = function () { + return _updateGearScore(); + }; + + this.equipItem = function (itemId, itemSlotId) { + return _inventory.equipItem(itemId, itemSlotId); + }; + + this.equipSubitem = function (subitemId, slotId) { + return _inventory.equipSubitem(subitemId, slotId); + }; + + this.socketItem = function (gemId, socketId, slotId) { + return _inventory.socketItem(gemId, socketId, slotId); + }; + + this.enchantItem = function (enchantId, slotId) { + return _inventory.enchantItem(enchantId, slotId); + }; + + this.selectPet = function (petId) { + Lightbox.hide(); + return _selectPet(petId); + }; + + this.updateMenu = function (slotId, a) { + return _inventory.updateMenu(slotId, a); + }; + + this.onMouseUpSlot = function (slotId, a, e) { + return _inventory.onMouseUpSlot(slotId, a, e); + }; + + this.fixJson = function (json, scale) { + _fixJson(json, scale); + }; + + this.unfixJson = function (json) { + _unfixJson(json); + }; + + this.getVars = function () { + return { + profile: _profile, + statistics: _statistics, + inventory: _inventory, + talents: _talents, + tabs: _tabs, + dialog: _dialog + }; + }; + + + // ************************************************************* + // ************************************************************* + // Private Methods + // ************************************************************* + // ************************************************************* + + + function _initData() { + for (var i in g_itemsets) { + for (var j in g_itemsets[i].setbonus) { + _fixJson(g_itemsets[i].setbonus[j]); + } + } + + for (var i in g_gems) { + _fixJson(g_gems[i].jsonequip); + } + + for (var i in g_enchants) { + _fixJson(g_enchants[i].jsonequip); + } + } + + function _fixJson(json, scale) { + for (var i in _replaceJson) { + var + value = json[i], + replace = _replaceJson[i]; + + if (value && replace.length) { + for (var j = 0, len = replace.length; j < len; ++j) { + json[replace[j]] = (typeof value == 'object' ? (value.length ? value.slice(0) : $WH.dO(value)) : value); + } + + + delete json[i]; + + if (scale) { // First value only + break; + } + } + } + } + + function _unfixJson(json) { + var value; + + for (var i in _replaceJson) { + var replace = _replaceJson[i]; + + for (var j = 0, len = replace.length; j < len; ++j) { + if (value = json[replace[j]]) { + json[i] = (typeof value == 'object' ? (value.length ? value.slice(0) : $WH.dO(value)) : value); + } + + delete json[replace[j]]; + } + } + } + + function _initProfiler() { + var + _, + __, + a, + tabIndex; + + + _divTabs = _ = $WH.ce('div'); + _.className = 'profiler-tabs'; + $WH.ae(_container, _); + + _tabs = new Tabs({ parent: _, onShow: _onShowTabs }); + _statistics = new ProfilerStatistics(_self); + _talents = new ProfilerTalents(_self); + + _ = $WH.ce('div'); + _.id = 'tab-inventory'; + _.style.display = 'none'; + _divInventory = __ = $WH.ce('div'); + __.style.display = 'none'; + $WH.ae(_, _divInventory); + $WH.ae(_container, _); + + _inventory = new ProfilerInventory(_self); + tabIndex = _tabs.add(LANG.tab_character, { id: 'inventory' }); + _inventory.initialize(_divInventory, tabIndex); + + _divStatistics = $WH.ce('div'); + _divInventory.insertBefore(_divStatistics, _divInventory.childNodes[3]); + + _statistics.initialize(_divStatistics, tabIndex); + +/* custom auras */ + + var tbl = $WH.ce('table'); + + _divAuras = $WH.ce('div'); + _divAuras.id = 'aura-container'; + _divAuras.style.cssFloat = 'left'; + _divAuras.style.marginLeft = '390px'; + _divAuras.style.width = '350px'; + _divAuras.style.display = 'none'; + + _ = $WH.ce('h3'); + $WH.ae(_, $WH.ct('[Auras]')); + $WH.ae(_divAuras, _); + + tbl.className = 'iconlist'; + + $WH.ae(_divAuras, tbl); + $WH.aef(_divInventory, _divAuras); + +/* end custom */ + + _ = $WH.ce('div'); + _.id = 'tab-talents'; + _.style.display = 'none'; + _divTalents = __ = $WH.ce('div'); + __.style.display = 'none'; + $WH.ae(_, _divTalents); + $WH.ae(_container, _); + + tabIndex = _tabs.add(LANG.tab_talents, { id: 'talents' }); + _talents.initialize(_divTalents, tabIndex); + + _ = $WH.ce('div'); + _.id = 'tab-pets'; + _.style.display = 'none'; + _divPets = __ = $WH.ce('div'); + __.style.display = 'none'; + $WH.ae(_, _divPets); + $WH.ae(_container, _); + + _pets = new ProfilerTalents(_self); + tabIndex = _tabs.add(LANG.tab_pets, { id: 'pets', hidden: 1 }); + _pets.initialize(_divPets, tabIndex); + + _ = $WH.ce('div'); + _.id = 'tab-mounts'; + _.style.display = 'none'; + _divMounts = __ = $WH.ce('div'); + __.style.display = 'none'; + $WH.ae(_, _divMounts); + $WH.ae(_container, _); + + _mounts = new ProfilerCompletion(_self); + tabIndex = _tabs.add(LANG.tab_mounts, { id: 'mounts' }); + _mounts.initialize(_divMounts, tabIndex, { + template: 'gallery', + noAd: 1, + onDemand: 1, + source: 'g_spells', + catgid: 'skill', + subcat: 'cat', + typeid: 6, + filter: function (spell) { + return (spell.cat == -5 || spell.cat == 7); + }, + models: 1 + }); + + _ = $WH.ce('div'); + _.id = 'tab-companions'; + _.style.display = 'none'; + _divCompanions = __ = $WH.ce('div'); + __.style.display = 'none'; + $WH.ae(_, _divCompanions); + $WH.ae(_container, _); + + _companions = new ProfilerCompletion(_self); + tabIndex = _tabs.add(LANG.tab_companions, { id: 'companions' }); + _companions.initialize(_divCompanions, tabIndex, { + template: 'gallery', + noAd: 1, + onDemand: 1, + source: 'g_spells', + catgid: 'skill', + subcat: 'cat', + typeid: 6, + filter: function (spell) { + return spell.cat == -6; + }, + models: 1 + }); + + _ = $WH.ce('div'); + _.id = 'tab-recipes'; + _.style.display = 'none'; + _divRecipes = __ = $WH.ce('div'); + __.style.display = 'none'; + $WH.ae(_, _divRecipes); + $WH.ae(_container, _); + + _recipes = new ProfilerCompletion(_self); + tabIndex = _tabs.add(LANG.tab_recipes, { id: 'recipes' }); + _recipes.initialize(_divRecipes, tabIndex, { + template: 'spell', + onDemand: 1, + dataArgs: function (x) { + var _ = [185, 129, 356]; + + for (var i in x.skills) { + _.push(i); + } + + return '&skill=' + _.join(','); + }, + source: 'g_spells', + order: 'g_skill_order', + catgs: 'g_spell_skills', + catgid: 'skill', + subcat: 'cat', + typeid: 6, + filter: function (spell) { + return spell.cat == 11 || spell.cat == 9; + }, + reqcatg: 1, + noempty: 1 + }); + + _ = $WH.ce('div'); + _.id = 'tab-quests'; + _.style.display = 'none'; + _divQuests = __ = $WH.ce('div'); + __.style.display = 'none'; + $WH.ae(_, _divQuests); + $WH.ae(_container, _); + + _quests = new ProfilerCompletion(_self); + tabIndex = _tabs.add(LANG.tab_quests, { id: 'quests' }); + _quests.initialize(_divQuests, tabIndex, { + template: 'quest', + onDemand: 1, + partial: 1, + dataArgs: function (x) { + return '&partial'; + }, + source: 'g_quests', + order: 'g_quest_catorder', + catgs: 'g_quest_categories', + catgid: 'category2', + subcat: 'category', + typeid: 5, + overall: -1, + reqcatg: 1, + nosubcatg: [4], + subname: function (c) { + return Listview.funcBox.getQuestCategory(c) + } + }); + + _ = $WH.ce('div'); + _.id = 'tab-achievements'; + _.style.display = 'none'; + _divAchievements = __ = $WH.ce('div'); + __.style.display = 'none'; + $WH.ae(_, _divAchievements); + $WH.ae(_container, _); + + _achievements = new ProfilerCompletion(_self); + tabIndex = _tabs.add(LANG.tab_achievements, { id: 'achievements' }); + _achievements.initialize(_divAchievements, tabIndex, { + template: 'achievement', + source: 'g_achievements', + order: 'g_achievement_catorder', + catgs: 'g_achievement_categories', + catgid: 'parentcat', + subcat: 'category', + typeid: 10, + nototal: [81], + points: 1, + overall: 0, + compute: function (achievement, x) { + if (achievement.parentcat == -1) { + achievement.parentcat = achievement.category; + } + + return x; + }, + subname: function (c) { + return g_achievement_categories[c]; + } + }); + + _ = $WH.ce('div'); + _.id = 'tab-titles'; + _.style.display = 'none'; + _divTitles = __ = $WH.ce('div'); + __.style.display = 'none'; + $WH.ae(_, _divTitles); + $WH.ae(_container, _); + + _titles = new ProfilerCompletion(_self); + tabIndex = _tabs.add(LANG.tab_titles, { id: 'titles' }); + _titles.initialize(_divTitles, tabIndex, { + template: 'title', + noAd: 1, + source: 'g_titles', + catgid: 'category', + typeid: 11 + }); + + _ = $WH.ce('div'); + _.id = 'tab-reputation'; + _.style.display = 'none'; + _divReputation = __ = $WH.ce('div'); + __.style.display = 'none'; + $WH.ae(_, _divReputation); + $WH.ae(_container, _); + + _reputation = new ProfilerCompletion(_self); + tabIndex = _tabs.add(LANG.tab_reputation, { id: 'reputation' }); + _reputation.initialize(_divReputation, tabIndex, { + template: 'faction', + onDemand: 'factions', + source: 'g_factions', + order: 'g_faction_order', + catgs: 'g_faction_categories', + catgid: 'category2', + subcat: 'category', + typeid: 8, + compute: function (faction, x) { + faction.standing = x | 0; + return x >= 42000 || _achievements.isComplete(faction.achievement); + } + }); + + _tabs.flush(); + } + + function _updateSavedChanges(saved) { + if (saved) { + _divMessage.style.display = 'none'; + _divMessage.style.backgroundImage = ''; + } + else { + _divMessage.innerHTML = $WH.sprintf(LANG.message_profilenotsaved, '', ''); + _divMessage.style.display = ''; + _divMessage.style.backgroundImage = 'none'; + } + // can't have javascript:; hrefs all over the place with an onbeforeunload on IE + if (!$.browser.msie) { + window.onbeforeunload = (saved ? null : function (e) { + return LANG.message_savebeforeexit; + }); + } + } + + function _updateDefaultIcon() { + var icon = $WH.g_getProfileIcon(_profile.race, _profile.classs, _profile.gender, _profile.level, _profile.source, 'large'); + + if (!_profile.icon) { + _profile.icon = icon; + } + + _profile.defaulticon = (_profile.icon == icon); + } + + function _initHeader() { + var + _, + __, + a; + + _dialog = new Dialog(); + + _divHeader = _ = $WH.ce('div'); + _.className = 'profiler-header'; + _btnProfile = RedButton.create(LANG.button_customprofile, true, _showProfileMenu); + _btnCharacter = RedButton.create(LANG.button_armorychar, true, _showCharacterMenu); + + $WH.ae(_, _btnCharacter); + $WH.ae(_, _btnProfile); + + _icoProfile = __ = Icon.create(null, 2); + $WH.ae(_, __); + + _divLine1 = __ = $WH.ce('div'); + __.className = 'profiler-header-line1'; + $WH.ae(_, __); + + _divLine2 = __ = $WH.ce('div'); + __.className = 'profiler-header-line2'; + $WH.ae(_, __); + + _divLine3 = __ = $WH.ce('div'); + __.className = 'profiler-header-line3'; + $WH.ae(__, $WH.ce('span')); + _lnkEdit = a = $WH.ce('a'); + a.className = 'profiler-header-editlink icon-edit'; + a.href = 'javascript:;'; + a.onclick = _dialog.show.bind(null, 'profileredit', { data: _profile, onSubmit: _editProfile }); + $WH.ae(a, $WH.ct(LANG.pr_header_edit)); + $WH.ae(__, a); + $WH.ae(_, __); + + $WH.ae(_container, _); + + _divMessage = _ = $WH.ce('div'); + _.className = 'profiler-message'; + _.style.display = 'none'; + $WH.ae(_container, _); + + _divTabLinks = _ = $WH.ce('div'); + _.className = 'profiler-tablinks'; + $WH.ae(_container, _); + + _lnkHelp = _ = $WH.ce('a'); + _.className = 'profiler-tablinks-help'; + _.href = '?help=profiler'; + _.target = '_blank'; + $WH.ae(_, $WH.ct(LANG.pr_header_help)); + $WH.ae(_divTabLinks, _); + + _lnkArmory = _ = $WH.ce('a'); + _.className = 'profiler-tablinks-armory'; + _.href = '#'; + _.style.display = 'none'; + $WH.ae(_, $WH.ct(LANG.pr_header_armory)); + $WH.ae(_divTabLinks, _); + } + + function _updateHeader() { + var _; + + // ************************ + // Page Title + + if (_pageTitle == null) { + _pageTitle = document.title; + } + + var buff = _profile.name; + if (_isArmoryProfile()) { + buff += ' ('; + buff += _profile.realm[1] + LANG.hyphen + _profile.region[1]; + buff += ')'; + } + buff += LANG.hyphen + _pageTitle; + document.title = buff; + + // ************************ + // Breadcrumb + + if (_isArmoryProfile(_profile.genuine)) { + // PageTemplate.set({ breadcrumb: [1, 5, 0, _profile.region[0], _profile.battlegroup[0], _profile.realm[0]] }); + g_initPath([1, 5, 0, _profile.region[0], _profile.battlegroup[0], _profile.realm[0]]); + } + else { + // PageTemplate.set({ breadcrumb: [1, 5, 1] }); + g_initPath([1, 5, 1]); + } + + // ************************ + // Buttons + + if (!_isArmoryProfile()) { + _btnCharacter.style.display = 'none'; + } + + // ************************ + // Header + + // Icon + Icon.setTexture(_icoProfile, 2, _profile.icon); + + // Line 1 + $WH.ee(_divLine1); + + if (_isArmoryProfile() && _profile.title && g_titles[_profile.title]) { + var + title = g_titles[_profile.title].name, + affix = $WH.str_replace(title, '%s', ''); + + var n = $WH.ce('b'); + $WH.st(n, _profile.name); + + if (!_tabs.tabs[8].hidden) { + var sp = $WH.ce('a'); + sp.href = '#titles'; + sp.onclick = Tabs.onClick.bind(_tabs.tabs[8], sp); + $WH.ns(sp); + } + else { + sp = $WH.ce('span'); + } + + $WH.st(sp, $WH.trim(affix)); + + if (title.indexOf('%s') > 0) { // Prefix title + $WH.ae(_divLine1, sp); + if ($WH.trim(affix) != affix) { + $WH.ae(_divLine1, $WH.ct(' ')); + } + $WH.ae(_divLine1, n); + } + else if (title.indexOf('%s') == 0) { // Suffix title + $WH.ae(_divLine1, n); + if ($WH.trim(affix) != affix) { + $WH.ae(_divLine1, $WH.ct(' ')); + } + $WH.ae(_divLine1, sp); + } + } + else { + _ = $WH.ce('b'); + $WH.ae(_, $WH.ct(_profile.name)); + $WH.ae(_divLine1, _); + } + + // Line 2 + $WH.ee(_divLine2); + + if (_isArmoryProfile(_profile.genuine) && !_profile.description) { + if (_profile.guild) { + _ = $WH.ce('var'); + $WH.ae(_, $WH.ct('<')); + $WH.ae(_divLine2, _); + + _ = $WH.ce('a'); + _.href = '?guild=' + _profile.region[0] + '.' + _profile.realm[0] + '.' + g_urlize(_profile.guild); + $WH.ae(_, $WH.ct(_profile.guild)); + $WH.ae(_divLine2, _); + + _ = $WH.ce('var'); + $WH.ae(_, $WH.ct('>')); + $WH.ae(_divLine2, _); + } + } + else if (_profile.description) { + $WH.ae(_divLine2, $WH.ct(_profile.description)); + } + + // Line 3 + _divLine3.firstChild.innerHTML = $WH.sprintfa(LANG.pr_header_character, _profile.level, g_chr_races[_profile.race], g_chr_classes[_profile.classs], _profile.race, _profile.classs); + + // Armory Link + if (_isArmoryProfile(_profile.genuine)) { + _lnkArmory.href = 'http://' + _profile.region[0] + '.battle.net/wow/' + Locale.getName().substr(0, 2) + '/character/' + _profile.realm[0] + '/' + g_cleanCharacterName(_profile.name) + '/'; + _lnkArmory.style.display = ''; + _lnkArmory.target = '_blank'; + } + else { + _lnkArmory.style.display = 'none'; + } + } + + function _updateAuras() { + var + show = false, + tbl = $WH.gE(_divAuras, 'table')[0]; + + for (j in _profile.auras) { + if (!g_spells[ _profile.auras[j]]) { + continue; + } + + spl = g_spells[_profile.auras[j]]; + + // can use jsonstats for flat modifiers + _statistics.addModifiers('spell', spl.id, spl.modifier || 0); + + var + tr = $WH.ce('tr'), + th = $WH.ce('th'), + td = $WH.ce('td'), + a = $WH.ce('a') + + var toggleAura = function (spell, td, e) { + e = $WH.$E(e); + + if (e._button != 3 && !e.shiftKey && !e.ctrlKey) + return true; + + if (td.className == 'q1') { + td.className = 'q0'; + td.previousSibling.style.opacity = 0.5; + _statistics.removeModifiers('spell', spell.id) + } + else { + td.className = 'q1'; + td.previousSibling.style.opacity = 1; + _statistics.addModifiers('spell', spell.id, spell.modifier || 0); + } + + return false; + }; + + th.align = 'right'; + th.appendChild(g_spells.createIcon(spl.id, 0, 0)); + $WH.ae(tr, th); + + $WH.ae(a, $WH.ct(spl['name'])); + a.href = '?spell=' + spl.id; + a.rel = 'buff'; + $WH.ae(td, a); + + td.className = 'q1'; + td.onmouseup = toggleAura.bind(null, spl, td); + td.oncontextmenu = $WH.rf; + td.onclick = function (e) { + e = $WH.$E(e); + if (e.shiftKey || e.ctrlKey) { + return false ; + } + }; + + $WH.ae(tr, td); + + $WH.ae(tbl, tr); + show = true; + } + + _divAuras.style.display = show ? 'block' : 'none'; + + } + + function _showCharacterMenu(e) { + if (!_isArmoryProfile()) { + return; + } + + e = $WH.$E(e); + + var menu = [[0, LANG.button_resync, _self.resync]]; + + if (g_user.id) { + if (!$WH.array_index(_profile.bookmarks, g_user.id)) { + menu.push([1, LANG.button_claimchar, _self.link]); + } + else { + menu.push([1, LANG.button_remove, _self.unlink]); + + if (_profile.pinned) { + menu.push([2, LANG.button_unpin, _self.unpin]); + } + else { + menu.push([2, LANG.button_pin, _self.pin]); + } + + menu.push([3, LANG.button_signature, _self.signature]); + } + } + + var pos = $WH.g_getCursorPos(e); + Menu.showAtXY(menu, pos.x, pos.y); + } + + function _showProfileMenu(e) { + e = $WH.$E(e); + + var menu = [[0, LANG.button_new, '?profile&new']]; + + if (g_user.id) { + if (_profile.id > 0 && g_user.id == _profile.user) { // Own profile + menu.push([1, LANG.button_save, _self.save]); + } + menu.push([2, LANG.button_saveas, _self.saveAs]); + if (_profile.id > 0 && g_user.id == _profile.user) { // Own profile + menu.push([3, LANG.button_delete, _self.remove]); + } + } + + var pos = $WH.g_getCursorPos(e); + Menu.showAtXY(menu, pos.x, pos.y); + } + + function _isArmoryProfile(allowCustoms) { + return ( + _profile.region && _profile.region[0] && + _profile.battlegroup && _profile.battlegroup[0] && + _profile.realm && _profile.realm[0] && + (allowCustoms || !_profile.user) + ); + } + + function _initInfobox() { + var + tb = $WH.ce('tbody'), + tr = $WH.ce('tr'), + th = $WH.ce('th'), + td = $WH.ce('td'), + div = $WH.ce('div'), + ul = $WH.ce('ul'); + + _tblInfobox = $WH.ce('table'); + _tblInfobox.className = 'infobox'; + + th.colSpan = 3; + td.colSpan = 3; + + $WH.ae(th, $WH.ct(LANG.pr_qf_quickfacts)); + $WH.ae(tr, th); + $WH.ae(tb, tr); + + tr = $WH.ce('tr'); + + div.className = 'infobox-spacer'; + $WH.ae(td, div); + + _ulQuickFacts = ul; + $WH.ae(td, ul); + + $WH.ae(tr, td); + $WH.ae(tb, tr); + + _trRaidProgress = tr = $WH.ce('tr'); + $WH.ae(tb, tr); + + var a = $WH.ce('a'); + a.className = 'tip'; + a.onclick = function (e) { + $WH.Tooltip.hide(); + _activity = 1 - _activity; + _updateInfoboxActivity(); + }; + a.onmouseover = function (e) { + $WH.Tooltip.showAtCursor(e, LANG['pr_qf_activitytip' + (_activity ? 1 : 2)], 0, 0, 'q'); + }; + a.onmousemove = $WH.Tooltip.cursorUpdate; + a.onmouseout = $WH.Tooltip.hide; + + th = $WH.ce('th'); + th.style.paddingLeft = '6px'; + th.style.paddingRight = 0; + + $WH.ae(th, a); + $WH.ae(tr, th); + + th = $WH.ce('th'); + th.colSpan = 2; + th.style.paddingLeft = 0; + th.style.paddingRight = '6px'; + + $WH.st(th, LANG.pr_qf_gearmeter); + $WH.ae(tr, th); + + tr = $WH.ce('tr'); + $WH.ae(tb, tr); + + _tdRaidActivity = $WH.ce('td'); + _tdRaidActivity.className = 'profiler-infobox-raids'; + _tdRaidActivity.style.padding = '0 0 0 6px'; + $WH.ae(tr, _tdRaidActivity); + + _tdRaidCompletion = $WH.ce('td'); + _tdRaidCompletion.className = 'profiler-infobox-gear'; + _tdRaidCompletion.style.padding = 0; + $WH.ae(tr, _tdRaidCompletion); + + _tdRaidGearMeter = $WH.ce('td'); + _tdRaidGearMeter.className = 'profiler-infobox-gear'; + _tdRaidGearMeter.style.padding = '2px 6px 0 0'; + $WH.ae(tr, _tdRaidGearMeter); + + $WH.ae(_tblInfobox, tb); + + $WH.aef(_divInventory, _tblInfobox); + } + + function _updateInfobox() { + var + li, + div, + sp, + a; + + // ************************ + // Quick Facts + + $WH.ee(_ulQuickFacts); + + // Updated + if (_profile.lastupdated) { + var elapsed = (g_serverTime - _profile.lastupdated) / 1000; + + li = $WH.ce('li'); + div = $WH.ce('div'); + sp = $WH.ce('span'); + + $WH.ae(div, $WH.ct((_isArmoryProfile() ? LANG.pr_qf_resynced : LANG.pr_qf_updated))); + g_formatDate(sp, elapsed, _profile.lastupdated); + + if (elapsed > (60 * 60 * 24)) { // 1 Day + sp.style.color = 'red'; + sp.style.fontWeight = 'bold'; + } + + $WH.ae(div, sp); + $WH.ae(li, div); + $WH.ae(_ulQuickFacts, li); + } + + // Owner + if (_profile.user && _profile.username) { + li = $WH.ce('li'); + div = $WH.ce('div'); + a = $WH.ce('a'); + + a.href = '?user=' + _profile.username; + + $WH.st(a, _profile.username); + $WH.ae(div, $WH.ct(LANG.pr_qf_owner)); + $WH.ae(div, a); + $WH.ae(li, div); + $WH.ae(_ulQuickFacts, li); + } + + // Source character + if (_profile.user && _profile.source) { + li = $WH.ce('li'); + div = $WH.ce('div'); + a = $WH.ce('a'); + + a.href = g_getProfileUrl({ + id: _profile.id, + region: _profile.region[0], + realm: _profile.realm[0], + name: _profile.sourcename + }); + + $WH.st(a, _profile.sourcename + ' (' + _profile.realm[1] + ' - ' + _profile.region[0].toUpperCase() + ')'); + $WH.ae(div, $WH.ct(LANG.pr_qf_character)); + $WH.ae(div, a); + $WH.ae(li, div); + $WH.ae(_ulQuickFacts, li); + } + + // Played time + if (_profile.playedtime) { + li = $WH.ce('li'); + div = $WH.ce('div'); + + $WH.st(div, LANG.pr_qf_playedtime + g_formatTimeElapsed(_profile.playedtime)); + $WH.ae(li, div); + $WH.ae(_ulQuickFacts, li); + } + + // Custom profiles - disabled for now + /*if (false && _isArmoryProfile() && _profile.customs) + { + var + t = $WH.ce('table'), + tb = $WH.ce('tbody'), + li = $WH.ce('li'), + div = $WH.ce('div'), + k = 0; + + t.className = 'iconlist'; + + $WH.ae(t, tb); + $WH.ae(div, $WH.ct(LANG.pr_qf_profiles)); + $WH.ae(div, t); + $WH.ae(li, div); + + // Sorting + var temp = [] + for (var i in _profile.customs) + temp.push([i, _profile.customs[i][0]]); + temp.sort(function(a, b) { return $WH.strcmp(a[1], b[1]) }); + + for (var j = 0, len = temp.length; j < len; ++j) + { + i = temp[j][0]; + + if (_profile.customs[i][1] && _profile.customs[i][1] != g_user.id) + continue; + + var + tr = $WH.ce('tr'), + th = $WH.ce('th'), + td = $WH.ce('td'), + a = $WH.ce('a'); + + $WH.ae(th, Icon.create((_profile.customs[i].length == 3 && _profile.customs[i][2] ? _profile.customs[i][2] : 'inv_misc_questionmark'), 0, null, '?profile=' + i)); + $WH.ae(tr, th); + + a.href = '?profile=' + i; + + $WH.st(a, _profile.customs[i][0]); + $WH.ae(td, a); + $WH.ae(tr, td); + $WH.ae(tb, tr); + + k++; + } + + if (k > 0) + $WH.ae(_ulQuickFacts, li); + }*/ + + // Gear Score + li = $WH.ce('li'); + div = $WH.ce('div'); + sp = $WH.ce('a'); + sp.href = '#gear-summary'; + + $WH.ae(div, $WH.ct(LANG.pr_qf_gearscore)); + + _spGearScore = sp; + + $WH.ae(div, sp); + $WH.ae(li, div); + $WH.ae(_ulQuickFacts, li); + + // Average Level + li = $WH.ce('li'); + div = $WH.ce('div'); + sp = $WH.ce('a'); + sp.href = '#gear-summary'; + + $WH.ae(div, $WH.ct(LANG.pr_qf_itemlevel)); + + _spAverageLevel = sp; + + $WH.ae(div, sp); + $WH.ae(li, div); + $WH.ae(_ulQuickFacts, li); + + // Spec + li = $WH.ce('li'); + _divSpec = div = $WH.ce('div'); + $WH.ae(div, $WH.ct(LANG.pr_qf_talents)); + + sp = $WH.ce('a'); + sp.href = '#talents'; + sp.onclick = Tabs.onClick.bind(_tabs.tabs[1], sp); + sp.className = 'icontinyl q1 tip'; + sp.onmousemove = $WH.Tooltip.cursorUpdate; + sp.onmouseout = $WH.Tooltip.hide; + $WH.ae(div, sp); + + $WH.ae(li, div); + $WH.ae(_ulQuickFacts, li); + + _updateInfoboxSpec(); + + // Achievement Points + if (_profile.achievementpoints) { + li = $WH.ce('li'); + div = $WH.ce('div'); + + sp = $WH.ce('a'); + sp.href = '#achievements'; + sp.style.textDecoration = 'none'; + $WH.ns(sp); + sp.onclick = Tabs.onClick.bind(_tabs.tabs[7], sp); + + $WH.ae(div, $WH.ct(LANG.pr_qf_achievements)); + Listview.funcBox.appendMoney(sp, 0, null, 0, 0, _profile.achievementpoints); + $WH.ae(div, sp); + + $WH.ae(li, div); + $WH.ae(_ulQuickFacts, li); + } + + // Skills + _spSkills = []; + if (_profile.skills) { + var skills = g_sortJsonArray(_profile.skills, g_spell_skills); + for (var i = 0, len = skills.length; i < len; ++i) { + var + skillId = skills[i], + skill = _profile.skills[skillId]; + + if (!skill[1]) { + skill[1] = 525; + } + + var opt = { + text: g_spell_skills[skillId], + hoverText: skill[0] + ' / ' + skill[1], + color: 'rep' + Math.min(6, Math.ceil(skill[1] / 75)), + width: Math.min(100, (skill[0] / skill[1]) * 100) + }; + + li = $WH.ce('li'); + div = $WH.ce('div'); + + li.className = 'profiler-infobox-skill'; + + var sp = g_createProgressBar(opt); + sp.skill = skillId; + sp.rel = 'np'; + $WH.ns(sp); + + _spSkills.push(sp); + + $WH.ae(div, sp); + $WH.ae(li, div); + $WH.ae(_ulQuickFacts, li); + } + } + + _updateInfoboxSkills(); + + // Arena Teams + if (_profile.arenateams) { + for (var i in _profile.arenateams) { + i = parseInt(i); + if (_profile.arenateams[i]) { + li = $WH.ce('li'); + div = $WH.ce('div'); + + $WH.ae(div, $WH.ct($WH.sprintfa(LANG.pr_qf_xvxteam, i))); + a = $WH.ce('a'); + a.href = '?arena-team=' + _profile.region[0] + '.' + _profile.realm[0] + '.' + g_urlize(_profile.arenateams[i]); + $WH.ae(a, $WH.ct(_profile.arenateams[i])); + $WH.ae(div, a); + + $WH.ae(li, div); + $WH.ae(_ulQuickFacts, li); + } + } + } + + _updateInfoboxActivity(); + } + + function _updateGearScore() { + var + sp = _spGearScore, + sp2 = _spAverageLevel; + + if (!sp || !sp2) { + return; + } + + // Calculate Gear Score + var + total = _inventory.getGearScore(), + avg = _inventory.getAverageLevel(); + + _profile.gearscore = total.item + total.ench + total.gems; + _profile.gearsubtotal = total; + + sp.className = sp2.className = 'q' + pr_getGearScoreQuality(_profile.level, _profile.gearscore, $WH.array_index([2, 6, 7, 11], _profile.classs)); + + if (_profile.gearsubtotal) { + sp.className += ' tip'; + sp.onmouseover = _showGearScoreTooltip.bind(0, _profile.gearsubtotal); + sp.onmousemove = $WH.Tooltip.cursorUpdate; + sp.onmouseout = $WH.Tooltip.hide; + } + else { + sp.onmouseover = sp.onmousemove = sp.onmouseout = null; + } + + $WH.st(sp, $WH.number_format(_profile.gearscore)); + $WH.st(sp2, $WH.number_format(avg)); + + _updateInfoboxActivity(); + } + + function _updateInfoboxSpec() { + if (!_divSpec) { + return; + } + + var + buildData = _talents.getTalentBuilds(), + specData = pr_getSpecFromTalents(_profile.classs, buildData.spent), + spSpec = _divSpec.childNodes[1]; + + spSpec.style.backgroundImage = 'url(' + g_staticUrl + '/images/icons/tiny/' + specData.icon.toLowerCase() + '.gif)'; + $WH.st(spSpec, (buildData.spent ? buildData.spent.join('/') : '0/0/0')); + + spSpec.onmouseover = function (e) { + $WH.Tooltip.showAtCursor(e, specData.name, 0, 0, 'q'); + }; + } + + function _updateInfoboxSkills() { + for (var i = 0, len = _spSkills.length; i < len; ++i) { + var sp = _spSkills[i]; + + if (_tabs.tabs[5].hidden) { + sp.className = sp.className.replace('tip', ''); + sp.href = null; + sp.onclick = $WH.rf; + } + else { + sp.className += ' tip'; + sp.href = '#recipes'; + sp.onclick = function (e) { + (Tabs.onClick.bind(_tabs.tabs[5], this, e))(); + _recipes.filterData(0, this.skill); + }; + } + } + } + + function _updateInfoboxActivity() { + _trRaidProgress.style.display = 'none'; + $WH.ee(_tdRaidActivity); + $WH.ee(_tdRaidCompletion); + $WH.ee(_tdRaidGearMeter); + + if (!_isArmoryProfile(_profile.genuine) || _profile.level != 80 || !_progress.length) { + return; + } + + _trRaidProgress.style.display = ''; + + var a = $WH.gE(_trRaidProgress, 'a')[0]; + $WH.st(a, LANG['pr_qf_raidactivity' + (_activity ? 1 : 2)]); + + var + avgLevel = _inventory.getAverageLevel(), + tierZones = {}, + activity = 0, + previous = null; + + if (!_activity) { // Recent Activity + for (var i in _profile.activity) { + activity += _profile.activity[i]; + } + } + + for (var i = _progress.length - 1; i >= 0; --i) { + var raid = _progress[i]; + if (!tierZones[raid.level]) { + tierZones[raid.level] = 0; + } + tierZones[raid.level]++; + + if (_activity) { // All Activity + for (var j = 0, len = raid.kills.length; j < len; ++j) { + activity += _profile.statistics[raid.kills[j][0]] | 0; + } + } + } + + for (var i = _progress.length - 1; i >= 0; --i) { + var + raid = _progress[i], + hasMeta = true, + nKills = 0, + nRecent = 0, + nBosses = 0; + + for (var j = 0, len = raid.achievs.length; j < len; ++j) { + hasMeta = hasMeta && (_profile.achievements[raid.achievs[j]]); + } + + for (var j = 0, len = raid.kills.length; j < len; ++j) { + nKills += _profile.statistics[raid.kills[j][0]] | 0; + nRecent += _profile.activity[raid.kills[j][0]] | 0; + nBosses += _profile.statistics[raid.kills[j][0]] ? 1 : 0; + } + + if (hasMeta) { + nBosses = raid.kills.length; + } + + if (_activity) { + nRecent = nKills; + } + + var gearLevel = (avgLevel >= raid.level ? + (avgLevel - 13 >= raid.level ? 0 : 1) : + (avgLevel + 27 < raid.level ? 5 : + (avgLevel + 18 < raid.level ? 4 : + (avgLevel + 9 < raid.level ? 3 : 2)))); + + // Raid Activity + var opt = { + text: (raid.zone ? g_zones[raid.zone] : raid.name), + hoverText: $WH.sprintf(LANG['pr_qf_activitypct' + (_activity ? 1 : 2)], (activity ? Math.round((nRecent / activity) * 100) : 0)), + color: 'ach0', + width: (activity ? Math.round((nRecent / activity) * 100) : 0) + }; + + var sp = g_createProgressBar(opt); + sp.className += (raid.heroic ? ' icon-heroic' : ' icon-instance' + raid.instance); + sp.onmouseover = _showActivityTooltip.bind(sp, raid, nBosses); + sp.onmousemove = $WH.Tooltip.cursorUpdate; + sp.onmouseout = $WH.Tooltip.hide; + $WH.ae(_tdRaidActivity, sp); + + // Completion + var sp = $WH.ce('span'); + sp.style.backgroundImage = 'url(' + g_staticUrl + '/template/images/' + (hasMeta ? 'tick.png' : (nKills ? 'cog.gif' : 'delete.gif')) + ')'; + sp.className = 'completion'; + sp.onmouseover = _showActivityTooltip.bind(sp, raid, nBosses); + sp.onmousemove = $WH.Tooltip.cursorUpdate; + sp.onmouseout = $WH.Tooltip.hide; + $WH.ae(_tdRaidCompletion, sp); + + // Gear + if (tierZones[raid.level]) { + var opt = { + text: '', + color: (gearLevel < 2 ? 'ach' + (1 - gearLevel) : 'rep' + (10 - (2 * gearLevel))) + }; + + var sp = g_createProgressBar(opt); + sp.style.height = ((22 * tierZones[raid.level]) - (previous ? 1 : 2)) + 'px'; + sp.onmouseover = (function (g, e) { + $WH.Tooltip.showAtCursor(e, LANG['pr_qf_gear' + g], 0, 0, 'q'); + }).bind(sp, gearLevel); + sp.onmousemove = $WH.Tooltip.cursorUpdate; + sp.onmouseout = $WH.Tooltip.hide; + $WH.ae(_tdRaidGearMeter, sp); + + if (!previous) { + sp.className += ' progressbar-first'; + } + if (i == 0) { + sp.className += ' progressbar-last'; + } + + tierZones[raid.level] = null; + previous = true; + } + } + } + + function _showActivityTooltip(raid, nBosses) { + var html = ''; + + html += ''; + html += (raid.heroic ? LANG.pr_print_heroic : LANG.pr_print_normal) + ' '; + html += (raid.zone ? g_zones[raid.zone] : raid.name) + '
'; + + html += $WH.sprintf(LANG.pr_qf_raidcomplete, Math.round((nBosses / raid.kills.length) * 100)); + html += ' (' + nBosses + '/' + raid.kills.length + ')
'; + + for (var i = 0, len = raid.kills.length; i < len; ++i) { + var + statisticId = raid.kills[i][0], + nameId = raid.kills[i][1], + nKills = (_profile.statistics[statisticId] | 0), + name = (raid.zone ? g_npcs[nameId]['name_' + Locale.getName()] : g_zones[nameId]); + + if (!name) { + continue; + } + + html += '' + nKills + ' × ' + name + '
'; + } + + $WH.Tooltip.setIcon(raid.icon); + $WH.Tooltip.show(this, html); + } + + function _requestProfile(id) { + if (!id) { + return; + } + + var + url = '?profile=load&id=' + id + '&' + (new Date().getTime()), + get = $WH.g_getGets(); + + if (get.items) { + _items = get.items.split(':'); + url += '&items=' + _items.join(':'); + } + + $WH.g_ajaxIshRequest(url); + } + + function _registerProfile(data) { + $WH.eO(_profile); + $WH.cO(_profile, data); + + _profile.genuine = (!_profile.sourcename && !_profile.user && !_profile.username); + + _profile.pinned = false; + if (_isArmoryProfile() && g_user && g_user.characters && g_user.characters.length) { + $.each(g_user.characters, function (index, character) { + if (character.id == _profile.source && character.pinned) { + _profile.pinned = true; + } + }); + } + + _updateDefaultIcon(); + _updateHeader(); + + if (_profile.talents.builds && _profile.talents.builds.length) { + _talents.setTalents(_profile.talents.active, _profile.talents.builds); + } + + if (_profile.pets && _profile.pets.length) { + _tabs.hide(2, 1); // Pets + _pets.setTalents(0, _profile.pets); + } + + _inventory.setInventory(_profile.inventory); + _inventory.addItems(_items); + + for (var i in g_spells) { + _fixJson(g_spells[i].modifier || 0); + } + _updateAuras(); + + _statistics.updateModifiers(); + + _updateInfobox(); + + if (_isArmoryProfile()) { + _tabs.hide(3, 1); // Mounts + _mounts.setData(_profile.spells); + + _tabs.hide(4, 1); // Companions + _companions.setData(_profile.spells); + + _tabs.hide(5, 1); // Recipes + _recipes.setData(_profile.spells); + + _tabs.hide(6, 1); // Quests + _quests.setData(_profile.quests); + + _tabs.hide(7, 1); // Achievements + _achievements.setData(_profile.achievements); + + _tabs.hide(8, 1); // Titles + _titles.setData(_profile.titles); + + _tabs.hide(9, 1); // Reputation + _reputation.setData(_profile.reputation); + } + else { + _tabs.hide(2, _profile.classs == 3); // Pets + _tabs.hide(3); // Mounts + _tabs.hide(4); // Companions + _tabs.hide(5); // Recipes + _tabs.hide(6); // Quests + _tabs.hide(7); // Achievements + _tabs.hide(8); // Titles + _tabs.hide(9) // Reputation + } + + if ((g_serverTime - data.lastupdated) >= 3600000) { // Auto-resync armory characters older than 1 hour + setTimeout(_self.resync, 1000); + } + + _updateSavedChanges(1); + + _onTabChange(); + } + + function _editProfile(data) { + var + charName = _profile.name, + raceId = _profile.race, + genderId = _profile.gender, + classId = _profile.classs, + level = _profile.level, + armory = _isArmoryProfile(); + + if (data.description) { + data.description = $WH.str_replace(data.description, "\n", ' '); + } + + $WH.cO(_profile, data); + + _profile.gender = parseInt(_profile.gender); + _profile.published = parseInt(_profile.published); + + if (!_profile.user || _profile.user != g_user.id) { + _profile.sourcename = (armory ? charName : ''); + _profile.username = g_user.name; + _profile.user = g_user.id; + _profile.id = 0; + + delete _profile.lastupdated; + } + + delete _profile.customs; + + if (_profile.classs != classId) { + _talents.resetAll(); + _pets.resetAll(); + _inventory.updateAllIcons(); + } + + if (_profile.level != level) { + _inventory.updateAllHeirlooms(); + } + + _talents.updateAll(); + _pets.updateAll(); + + _updateDefaultIcon(); + _updateHeader(); + _updateInfobox(); + _updateSavedChanges(); + + if (_profile.race != raceId || _profile.gender != genderId) { + _inventory.updateModel(null, 1); + } + + if (_profile.classs != classId || _profile.race != raceId || _profile.level != level) { + _statistics.updateModifiers(); + } + } + + function _showGearScoreTooltip(total, e) { + var + html = '', + sum = parseInt(total.item + total.gems + total.ench); + + html += ''; + html += ''; + html += ''; + html += ''; + html += '
' + LANG.pr_tt_items + '' + total.item + '' + (!total.item ? 0 : Math.round(total.item / sum * 100)) + '%
' + LANG.pr_tt_gems + '' + total.gems + '' + (!total.gems ? 0 : Math.round(total.gems / sum * 100)) + '%
' + LANG.pr_tt_enchants + '' + total.ench + '' + (!total.ench ? 0 : Math.round(total.ench / sum * 100)) + '%
'; + + $WH.Tooltip.showAtCursor(e, html); + } + + function _onShowTabs(newTab, oldTab) { + Tabs.onShow(newTab, oldTab); + + if (oldTab) { + _onTabChange(newTab.index); + } + } + + function _onTabChange(currentTab) { + if (currentTab == null) { + currentTab = _tabs.getSelectedTab(); + } + + _inventory.showModel(currentTab == 0); + + switch (currentTab) { + case 0: // Inventory + _divInventory.style.display = ''; + break; + case 1: // Talents + _talents.onShow(); + _divTalents.style.display = ''; + break; + case 2: // Pets + _pets.onShow(); + _divPets.style.display = ''; + break; + case 3: // Mounts + _mounts.onShow(); + _divMounts.style.display = ''; + break; + case 4: // Companions + _companions.onShow(); + _divCompanions.style.display = ''; + break; + case 5: // Recipes + _recipes.onShow(); + _divRecipes.style.display = ''; + break; + case 6: // Quests + _quests.onShow(); + _divQuests.style.display = ''; + break; + case 7: // Achievements + _achievements.onShow(); + _divAchievements.style.display = ''; + break; + case 8: // Titles + _titles.onShow(); + _divTitles.style.display = ''; + break; + case 9: // Reputation + _reputation.onShow(); + _divReputation.style.display = ''; + break; + } + } +} + +function ProfilerTalents(_parent) { + var + _self = this, + + _talentCalc, + _parentVars, + _profile, + _tabs, + + _tabIndex, + + _active, + _builds, + _glyphs, + + _inited, + _updated, + _displayed, + _loading, + + _container, + _divBuilds, + _spButtons, + _divTalentCalc, + _divGlyphs, + + _mode, + _export; + + this.initialize = function (container, tabIndex) { + _container = $WH.ge(container); + if (!_container) { + return; + } + + _parentVars = _parent.getVars(); + _profile = _parentVars.profile; + _statistics = _parentVars.statistics; + _inventory = _parentVars.inventory; + _talents = _parentVars.talents; + _tabs = _parentVars.tabs; + + _tabIndex = tabIndex; + + if (!_tabs.tabs[_tabIndex]) { + return; + } + + _mode = _tabs.tabs[_tabIndex].id; + + _self.resetAll(); + }; + + this.setTalents = function (active, builds) { + _setTalents(active, builds); + }; + + this.setGlyphData = function (data, who, when) { + if (data) { + _divGlyphs.parentNode.style.display = ''; + } + + _glyphs.setData(data, who, when); + }; + + this.resetAll = function () { + _active = 0; + _builds = []; + + for (var i = 0, len = (_mode == 'pets' ? 25 : 2); i < len; ++i) { + var _ = { talents: '' }; + + if (_mode == 'pets') { + _.spent = 0; + _.name = ''; + _.family = 0; + _.npcId = 0; + _.displayId = 0; + } + else { + _.name = LANG.pr_queue_unknown; + _.glyphs = ''; + _.spent = [0, 0, 0]; + _.spec = -1; + _.scale = {}; + _.filter = ''; + } + + _builds.push(_); + } + + _updated = false; + _displayed = false; + + if (_tabs.getSelectedTab() == _tabIndex) { + _self.onShow(); + } + }; + + this.updateAll = function () { + _updateBuilds(); + _updateTalents(); + }; + + this.getTalentBuilds = function () { + if (!_export) { + _getWeightScale(true); + + _export = $WH.dO(_builds[_active]); + _export.active = _active; + _export.talents = []; + + if (_mode != 'pets') { + _export.glyphs = []; + } + + for (var i = 0, len = _builds.length; i < len; ++i) { + _export.talents.push(_builds[i].talents); + + if (_mode != 'pets') { + _export.glyphs.push(_builds[i].glyphs); + } + } + } + + return _export; + }; + + this.getTalentRanks = function (talent) { + if (!_inited) { + return; + } + + return _talentCalc.getTalentRanks(talent); + }; + + this.hasTitansGrip = function () { + return _talents.getTalentRanks(1867) + }; + + this.hasBeastMastery = function () { + return _talents.getTalentRanks(2139) + }; + + this.getWeightScale = function (refresh) { + return _getWeightScale(refresh); + }; + + this.onShow = function (noShow) { + if (!_inited) { + _initBuilds(); + _initTalents(); + _initGlyphs(); + + _inited = true; + } + + if (!_updated) { + _updateBuilds(); + _updateTalents(); + + _updated = true; + } + }; + + function _setTalents(active, builds) { + _active = active; + _builds = $WH.dO(builds); + _updated = false; + _self.onShow(); + } + + function _getBuildClass(build) { + if (_mode != 'pets') { + return _profile.classs; + } + + if (build == null) { + build = _active; + } + + if (_builds[build].npc && g_pets[_builds[build].npc]) { + return g_pets[_builds[build].npc].family; + } + } + + function _initBuilds() { + _divBuilds = $WH.ce('div'); + _divBuilds.className = 'profiler-talents-specs'; + + _spButtons = []; + for (var i = 0, len = _builds.length; i < len; ++i) { + var a = $WH.ce('a'); + a.className = 'profiler-' + _mode + '-button'; + a.onclick = _setActiveBuild.bind(0, i); + a.href = 'javascript:;'; + + _spButtons[i] = $WH.ce('span'); + + if (_mode == 'pets') { + var icon = Icon.create('inv_misc_questionmark', 0); + icon.style.position = 'absolute'; + $WH.ae(a, icon); + + _spButtons[i].icon = icon; + } + + $WH.ae(a, _spButtons[i]); + $WH.ae(_divBuilds, a); + } + + var div = $WH.ce('div'); + div.className = 'clear'; + $WH.ae(_divBuilds, div); + $WH.ae(_container, _divBuilds); + } + + function _updateBuilds() { + if (!_inited) { + return; + } + + g_setSelectedLink(_divBuilds.childNodes[_active], 'active' + _mode); + + for (var i = 0, len = _builds.length; i < len; ++i) { + _updateBuild(i); + } + } + + function _updateBuild(build) { + if (build == null) { + build = _active; + } + + if (!_builds[build]) { + return; + } + + _builds[build].spent = _talentCalc.getSpentFromBlizzBuild(_builds[build].talents, _profile.classs); + + var + sp = _spButtons[build], + sm = $WH.ce('small'); + + if (sp) { + $WH.ee(sp); + } + + if (_mode == 'pets') { + var family = _getBuildClass(build); + Icon.setTexture(sp.icon, 0, (family ? g_pet_icons[family] : 'inv_misc_questionmark')); + $WH.ae(sp, $WH.ct(family ? _builds[build].name : LANG.pr_nonepet)); + } + else { + var + basePoints = Math.max(0, _profile.level - 9), + spentPoints = _builds[build].spent[0] + _builds[build].spent[1] + _builds[build].spent[2], + reduce = spentPoints - basePoints; + + for (var i = 2; i >= 0; --i) { + if (reduce <= 0) { + break; + } + else if (_builds[build].spent[i] >= reduce) { + _builds[build].spent[i] -= reduce; + reduce = 0; + } + else if (_builds[build].spent[i] > 0) { + reduce -= _builds[build].spent[i]; + _builds[build].spent[i] = 0; + } + } + + var specData = pr_getSpecFromTalents(_profile.classs, _builds[build].spent); + + if (sp) { + sp.style.backgroundImage = 'url(' + g_staticUrl + '/images/icons/tiny/' + specData.icon.toLowerCase() + '.gif)'; + + $WH.ae(sp, $WH.ct(specData.name + ' ')); + $WH.st(sm, '(' + _builds[build].spent.join('/') + ')'); + $WH.ae(sp, sm); + } + + return specData; + } + } + + function _setActiveBuild(active) { + _active = active; + _updated = false; + + if (_tabs.getSelectedTab() == _tabIndex) { + _self.onShow(); + } + } + + function _initTalents() { + _divTalentCalc = $WH.ce('div'); + _divTalentCalc.style.display = 'none'; + $WH.ae(_container, _divTalentCalc); + + _talentCalc = new TalentCalc(); + _talentCalc.initialize(_divTalentCalc, { + onChange: _onChangeTalents, + noAd: 1, + profiler: 1, + mode: (_mode == 'pets' ? TalentCalc.MODE_PET : TalentCalc.MODE_DEFAULT) + }); + } + + function _updateTalents() { + if (!_inited) { + return; + } + + var classId = _getBuildClass(); + + if (classId) { + _loading = _active; + _active = 2; + + _builds[_active] = $WH.dO(_builds[_loading]); + + _talentCalc.setClass(classId); + + if (_builds[_loading].talents) { + _talentCalc.setBlizzBuild(classId, _builds[_loading].talents); + } + else { + _talentCalc.resetBuild(); + } + + if (_builds[_loading].glyphs) { + _talentCalc.setBlizzGlyphs(_builds[_loading].glyphs); + } + else { + _talentCalc.resetGlyphs(); + } + + if (_mode == 'pets') { + _talentCalc.setPetModel(_builds[_loading].npc); + } + else { + _builds[_loading].name = LANG.pr_queue_unknown; + _builds[_loading].spec = -1; + _builds[_loading].scale = {}; + _builds[_loading].filter = ''; + } + + if (_displayed) { + _talentCalc.setLevelCap(_profile.level); + } + + _active = _loading; + _loading = null; + } + } + + function _onChangeTalents(tc, info, data) { + if (_loading === null) { + _builds[_active].talents = _talentCalc.getBlizzBuild(); + _builds[_active].spent = info.pointsSpent; + + if (_mode != 'pets') { + _builds[_active].glyphs = _talentCalc.getBlizzGlyphs(); + } + + if (_displayed) { + _parent.updateSavedChanges(); + } + } + + if (!_displayed) { + // sarjuuk: causes infinite loop and it works fine without this + // _talentCalc.setLevelCap(_profile.level); + if (_mode != 'pets') { + _updateBuilds(); + } + _displayed = true; + + _divTalentCalc.style.display = ''; + } + + if (_mode != 'pets') { + _parent.updateInfoboxSpec(); + + var + specData = _updateBuild(), + changedSpec = (_builds[_active].spec != specData.id), + weightScale = _getWeightScale(changedSpec); + + _parent.updateGearScore(); + + var t = tc.getTalents(); + + _statistics.removeAllModifiers('talent'); + for (var i = 0, len = t.length; i < len; ++i) { + if (t[i].j) { + _statistics.addModifiers('talent', t[i].s[t[i].k - 1], t[i].j[t[i].k - 1]); + } + } + + _inventory.updateInventory(); + } + else if (_talents.hasBeastMastery() && !_talentCalc.getBonusPoints()) { + _talentCalc.setBonusPoints(); + } + + _export = null; + } + + function _getWeightScale(refresh) { + if (!wt_presets[_profile.classs] || !_builds[_active]) { + return; + } + + var + specData = pr_getSpecFromTalents(_profile.classs, _builds[_active].spent), + spec = specData.id, + pve = wt_presets[_profile.classs].pve, + t = spec - 1; + + if (_profile.classs == 11 && spec == 2) { // Feral Druid (2 specs) + // Protector of the Pack, Natural Reaction + var tankTalents = [2241, 2242]; + t += 2; + for (var i = 0, len = tankTalents.length; i < len; ++i) { + if (!_self.getTalentRanks(tankTalents[i])) { + continue; + } + + t -= 2; + break; + } + } + + var + scale = pr_getScaleFromSpec(_profile.classs, t), + name = pr_getScaleFromSpec(_profile.classs, t, 1); + + if (refresh) { + _builds[_active].name = (name ? name : LANG.pr_queue_unknown); + _builds[_active].spec = specData.id; + _builds[_active].scale = scale; + _builds[_active].filter = pr_getScaleFilter(scale); + } + + _parent.fixJson(scale); + + return scale; + } + + function _initGlyphs() { + var + _, + __; + + _ = $WH.ce('div'); + _.className = 'clear pad'; + $WH.ae(_container, _); + + _ = $WH.ce('div'); + _.className = 'text'; + _.style.display = 'none'; + __ = $WH.ce('h2'); + __.className = 'clear'; + $WH.st(__, LANG.tc_glyphs); + $WH.ae(_, __); + $WH.ae(_container, _); + + _divGlyphs = __ = $WH.ce('div'); + $WH.ae(_, __); + + _glyphs = new ProfilerCompletion(_parent); + _glyphs.initialize(_divGlyphs, _tabIndex, { + template: 'item', + noAd: 1, + source: 'g_glyph_items', + typeid: 3, + order: 'g_glyph_order', + catgs: 'g_item_glyphs', + catgid: 'glyph', + visibleCols: ['glyph'], + hiddenCols: ['slot', 'type'] + }); + } +} + +function ProfilerStatistics(_parent) { + var + _self = this, + + _parentVars, + _profile, + _inventory, + + _timer, + + _divStatBars, + _divStatResists, + _tblStatBoxes, + + _magicSchools = ['arc', 'fir', 'fro', 'hol', 'nat', 'sha'], + + _modifiers = {}, + _statistics = { + // ***** Base Attributes ***** + str: { + getTooltip: function () { + return LANG['pr_statstt_str' + (_profile.classs == 1 || _profile.classs == 2 || _profile.classs == 7 ? 2 : '')]; + }, + tooltipModifiers: ['mleatkpwr', 'block'], + addModifiers: function () { + var classData = g_statistics.classs[_profile.classs]; + + return { + mleatkpwr: [classData[0][1], 'percentOf', ['str', (classData[0][1] ? (classData[0][0] / (classData[0][2] ? 2 : 1)) : 0)]], + rgdatkpwr: [classData[1][1], 'percentOf', ['str', (classData[1][1] ? (classData[1][0] / (classData[1][2] ? 2 : 1)) : 0)]], + block: [0.5, 'percentOf', ['str', -10]] + }; + } + }, + + agi: { + tooltipModifiers: ['mleatkpwr', 'mlecritstrkpct', 'armor'], + addModifiers: function () { + var + raceData = g_statistics.race[_profile.race], + classData = g_statistics.classs[_profile.classs], + levelData = g_statistics.combo[_profile.classs][_profile.level]; + + return { + mleatkpwr: [classData[0][2], 'percentOf', ['agi', (classData[0][2] ? (classData[0][0] / (classData[0][1] ? 2 : 1)) : 0)]], + rgdatkpwr: [classData[1][2], 'percentOf', ['agi', (classData[1][2] ? (classData[1][0] / (classData[1][1] ? 2 : 1)) : 0)]], + mlecritstrkpct: [levelData[7], 'percentOf', ['agi', classData[2][0]]], + rgdcritstrkpct: [levelData[7], 'percentOf', ['agi', classData[2][0]]], + armor: [2, 'percentOf', 'agi'], + dodgepct: [levelData[9], 'percentOf', ['agi', -levelData[9] * ((raceData ? raceData[1] : 0) + levelData[1])]] + }; + } + }, + + sta: { + getTooltip: function () { + return LANG['pr_statstt_sta' + (_profile.classs == 3 || _profile.classs == 9 ? 2 : '')]; + }, + tooltipModifiers: ['health', 'petsta'], + addModifiers: function () { + return { + health: [10 + ((Math.max(_profile.level, 80) - 80) * 0.8), 'percentOf', ['sta', -180]], + petsta: [0.3, 'percentOf', 'sta'] + }; + } + }, + + 'int': { + getTooltip: function () { + return LANG['pr_statstt_int' + (_profile.classs == 9 ? 2 : '')]; + }, + tooltipModifiers: ['mana', 'arcsplcritstrkpct', 'petint'], + addModifiers: function () { + if (_profile.classs == 1 || _profile.classs == 4 || _profile.classs == 6) { + return {}; + } + + var + classData = g_statistics.classs[_profile.classs], + levelData = g_statistics.combo[_profile.classs][_profile.level]; + + return { + mana: [15, 'percentOf', ['int', -280]], + arcsplcritstrkpct: [levelData[8], 'percentOf', ['int', classData[2][1]]], + firsplcritstrkpct: [levelData[8], 'percentOf', ['int', classData[2][1]]], + frosplcritstrkpct: [levelData[8], 'percentOf', ['int', classData[2][1]]], + holsplcritstrkpct: [levelData[8], 'percentOf', ['int', classData[2][1]]], + natsplcritstrkpct: [levelData[8], 'percentOf', ['int', classData[2][1]]], + shasplcritstrkpct: [levelData[8], 'percentOf', ['int', classData[2][1]]], + petint: (_profile.classs == 9 ? [0.3, 'percentOf', 'int'] : 0) + }; + } + }, + + spi: { + tooltipModifiers: ['healthrgn', 'spimanargn'], + addModifiers: function () { + return { + healthrgn: [1, 'functionOf', function () { + // taken from TrinityCore//Player::OCTRegenHPPerSpirit(), which is taken from PaperDollFrame script + var + spiBase = _statistics.spi.subtotal[0], + spiMore = _statistics.spi.subtotal[1] + + if (spiBase > 50) { + spiMore += spiBase - 50; + spiBase = 50; + } + + return Math.round( + (spiBase * g_statistics.combo[_profile.classs][_profile.level][10]) + + (spiMore * g_statistics.combo[_profile.classs][_profile.level][11])); + }], + spimanargn: [5, 'functionOf', function () { + return (0.001 + Math.sqrt(_statistics['int'].total) * _statistics.spi.total * g_statistics.level[_profile.level]); + }] + }; + } + }, + + health: {}, + + mana: {}, + + rage: {}, + + energy: {}, + + runic: {}, + + // ********** Melee ********** + mledps: { + decimals: 1 + }, + + mleatkpwr: { + tooltipModifiers: ['mledps'], + addModifiers: function () { + return { + mledps: [1 / 14, 'percentOf', 'mleatkpwr'] + }; + } + }, + + mlecritstrkpct: { + decimals: 2, + rating: { id: 19, stat: 'mlecritstrkrtng' } + }, + + mlehastepct: { + decimals: 2, + rating: { id: 28, stat: 'mlehastertng' } + }, + + mlehitpct: { + decimals: 2, + rating: { id: 16, stat: 'mlehitrtng' } + }, + + armorpenpct: { + rating: { id: 44, stat: 'armorpenrtng' }, + decimals: 2 + }, + + 'exp': { + rating: { id: 37, stat: 'exprtng' }, + tooltipCompute: function (total) { + return [(0.25 * total).toFixed(2)]; + } + }, + + // ********** Ranged ********* + rgddps: { + decimals: 1 + }, + + rgdatkpwr: { + getTooltip: function () { + return LANG['pr_statstt_rgdatkpwr' + (_profile.classs == 3 ? 2 : '')]; + }, + tooltipModifiers: ['rgddps', 'petatkpwr', 'petspldmg'], + addModifiers: function () { + return { + rgddps: [1 / 14, 'percentOf', 'rgdatkpwr'], + petatkpwr: (_profile.classs == 3 ? [0.22, 'percentOf', 'rgdatkpwr'] : 0), + petspldmg: (_profile.classs == 3 ? [0.1287, 'percentOf', 'rgdatkpwr'] : 0) + }; + } + }, + + rgdhitpct: { + decimals: 2, + rating: { id: 17, stat: 'rgdhitrtng' } + }, + + rgdcritstrkpct: { + decimals: 2, + rating: { id: 20, stat: 'rgdcritstrkrtng' } + }, + + rgdhastepct: { + decimals: 2, + rating: { id: 29, stat: 'rgdhastertng' } + }, + + + // ********** Spell ********** + splheal: {}, + + spldmg: { + magic: 1, + getTooltip: function () { + return LANG['pr_statstt_spldmg' + (_profile.classs == 9 ? 2 : '')]; + }, + tooltipModifiers: ['spldmg', 'petatkpwr', 'petspldmg'], + addModifiers: function () { + var maxSpellDmg = function () { + var result = _statistics[_magicSchools[0] + 'spldmg'].total; + + for (var i = 1, len = _magicSchools.length; i < len; ++i) { + if (_statistics[_magicSchools[i] + 'spldmg'].total > result) { + result = _statistics[_magicSchools[i]]; + } + } + + return result; + }; + + return { + petatkpwr: (_profile.classs == 9 ? [0.57, 'functionOf', maxSpellDmg] : 0), + petspldmg: (_profile.classs == 9 ? [0.15, 'functionOf', maxSpellDmg] : 0) + }; + } + }, + + splhitpct: { + decimals: 2, + rating: { id: 18, stat: 'splhitrtng' } + }, + + splcritstrkpct: { + decimals: 2, + rating: { id: 21, stat: 'splcritstrkrtng' }, + magic: 1 + }, + + splhastepct: { + decimals: 2, + rating: { id: 30, stat: 'splhastertng' } + }, + + splpen: {}, + + healthrgn: {}, + + manargn: { + addModifiers: function () { + return { + oocmanargn: [1, 'percentOf', 'manargn'] + }; + } + }, + + spimanargn: { + addModifiers: function () { + return { + oocmanargn: [1, 'percentOf', 'spimanargn'] + }; + } + }, + + oocmanargn: { + tooltipCompute: function (total) { + return [total, _statistics.manargn.total]; + } + }, + + // ********* Defenses ******** + armor: { + getTooltip: function () { + return LANG['pr_statstt_armor' + (_profile.classs == 3 || _profile.classs == 9 ? 2 : '')]; + }, + excludeModifiers: ['armorbonus'], + tooltipModifiers: ['petarmor'], + tooltipCompute: function (total) { + var + levelMod = (_profile.level > 59 ? _profile.level + (4.5 * (_profile.level - 59)) : _profile.level), + pct = (0.1 * total) / ((8.5 * levelMod) + 40); + + pct /= 1 + pct; + return [Math.min(75, pct * 100).toFixed(2)]; + }, + addModifiers: function () { + return { + petarmor: [0.35, 'percentOf', 'armor'] + } + } + }, + + def: { + rating: { id: 12, stat: 'defrtng' }, + tooltipModifiers: ['parrypct', 'dodgepct'], + addModifiers: function () { + var diminishedPct = function () { + var + classData = g_statistics.classs[_profile.classs], + missCap = 16.0, // TrinityCore says its the same for all classes + toPercent = 0.04, + actualDef = _statistics.def.total - (_profile.level * 5); + + return (actualDef * missCap * toPercent) / ((missCap * classData[3]) + (actualDef * toPercent)); + }; + return { + dodgepct: [1, 'functionOf', diminishedPct], + parrypct: [1, 'functionOf', diminishedPct], + blockpct: [1, 'functionOf', diminishedPct] + } + } + }, + + /* + baseDodge = from g_statistics[classs][4] + baseAgi = raceAgi + levelAgi (e.g. for a 80 tauren druid = 16 + 61) + dodgePerAgi = gathered from the client->database + H = rating to % modifier calculated with g_convertRatingToPercent + + @dodgepct modifiers: + 0 + diminish: true + percent: H + percentOf: dodgerating + subtotal: dodgerating*H + 1 + diminish: true + percent: dodgePerAgi + percentBase: -dodge%FromBaseAgi (-dodgePerAgi*baseAgi) + percentOf: agi + subtotal: dodgePerAgi*totalAgi - dodge%FromBaseAgi + 2 + diminish: false + add: baseDodge + baseAgi*dodgePerAgi (!!!!!missing dodgeFromTalents!!!!!) + subtotal: add + + @final dodgepct = diminish(0 + 1) + 2 + */ + dodgepct: { + decimals: 2, + rating: { id: 13, stat: 'dodgertng' }, + computeDiminished: function (subtotal) { + var classData = g_statistics.classs[_profile.classs]; + return subtotal * classData[5] / ((classData[5] * classData[3]) + subtotal); + } + }, + + parrypct: { + decimals: 2, + rating: { id: 14, stat: 'parryrtng' }, + computeDiminished: function (subtotal) { + var classData = g_statistics.classs[_profile.classs]; + return (classData[7] ? subtotal * classData[7] / ((classData[7] * classData[3]) + subtotal) : 0); + } + }, + + blockpct: { + decimals: 2, + rating: { id: 15, stat: 'blockrtng'}, + tooltipCompute: function (total) { + return [_statistics.block.total]; + } + }, + + block: {}, + + resipct: { + decimals: 2, + rating: { id: 35, stat: 'resirtng' }, + tooltipCompute: function (total) { + return [total, (2.2 * total).toFixed(2), (2 * total).toFixed(2)]; + } + }, + + // ********* Resistances ******** + arcres: { + icon: 'spell_arcane_blast', + getTooltip: function () { + return $WH.sprintf(LANG['pr_statstt_resist'], LANG['pr_statstt_arc']); + }, + tooltipCompute: function (total) { + return [Math.min(75, (total / (_profile.level * 5)) * 75).toFixed(2)]; + }, + addModifiers: function () { + return { + petarcres: [0.4, 'percentOf', 'arcres'] + } + } + }, + + firres: { + icon: 'spell_fire_burnout', + getTooltip: function () { + return $WH.sprintf(LANG['pr_statstt_resist'], LANG['pr_statstt_fir']); + }, + tooltipCompute: function (total) { + return [Math.min(75, (total / (_profile.level * 5)) * 75).toFixed(2)]; + }, + addModifiers: function () { + return { + petfirres: [0.4, 'percentOf', 'firres'] + } + } + }, + + frores: { + icon: 'spell_frost_arcticwinds', + getTooltip: function () { + return $WH.sprintf(LANG['pr_statstt_resist'], LANG['pr_statstt_fro']); + }, + tooltipCompute: function(total) { + return [Math.min(75, (total / (_profile.level * 5)) * 75).toFixed(2)]; + }, + addModifiers: function () { + return { + petfrores: [0.4, 'percentOf', 'frores'] + } + } + }, + + holres: { + icon: 'spell_holy_powerwordbarrier', + getTooltip: function() { + return $WH.sprintf(LANG['pr_statstt_resist'], LANG['pr_statstt_hol']); + }, + tooltipCompute: function(total) { + return [Math.min(75, (total / (_profile.level * 5)) * 75).toFixed(2)]; + }, + addModifiers: function () { + return { + petholres: [0.4, 'percentOf', 'holres'] + } + } + }, + + natres: { + icon: 'ability_druid_flourish', + getTooltip: function() { + return $WH.sprintf(LANG['pr_statstt_resist'], LANG['pr_statstt_nat']); + }, + tooltipCompute: function(total) { + return [Math.min(75, (total / (_profile.level * 5)) * 75).toFixed(2)]; + }, + addModifiers: function () { + return { + petnatres: [0.4, 'percentOf', 'natres'] + } + } + }, + + shares: { + icon: 'spell_shadow_shadowfury', + getTooltip: function() { + return $WH.sprintf(LANG['pr_statstt_resist'], LANG['pr_statstt_sha']); + }, + tooltipCompute: function(total) { + return [Math.min(75, (total / (_profile.level * 5)) * 75).toFixed(2)]; + }, + addModifiers: function () { + return { + petshares: [0.4, 'percentOf', 'shares'] + } + } + }, + + // ********** Pet Stats ********* + + petsta: {}, + + petint: {}, + + petatkpwr: { + dependent: { rgdatkpwr: 1, spldmg: 1 }, + ndependent: 2 + }, + + petspldmg: { + dependent: { rgdatkpwr: 1, spldmg: 1 }, + ndependent: 2 + }, + + petarmor: {}, + + petarcres: {}, + + petfirres: {}, + + petfrores: {}, + + petholres: {}, + + petnatres: {}, + + petshares: {} + }, + + _statBoxes = [ + // Base + [ + { id: 'base', type: 'title' }, + { id: 'health', type: 'bar' }, + { id: 'mana', type: 'bar' }, + { id: 'rage', type: 'bar' }, + { id: 'energy', type: 'bar' }, + { id: 'runic', type: 'bar' }, + { id: 'str' }, + { id: 'agi' }, + { id: 'sta' }, + { id: 'int' }, + { id: 'spi' } + ], + // Melee + [ + {id: 'melee', type: 'title'}, + { id: 'mleatkpwr'}, + { id: 'mlehitpct' }, + { id: 'mlecritstrkpct' }, + { id: 'mlehastepct' }, + { id: 'armorpenpct' }, + { id: 'exp' } + ], + // Ranged + [ + {id: 'ranged', type: 'title' }, + { id: 'rgdatkpwr' }, + { id: 'rgdhitpct' }, + { id: 'rgdcritstrkpct' }, + { id: 'rgdhastepct' }, + { id: 'armorpenpct' } + ], + // Spell + [ + {id: 'spell', type: 'title' }, + { id: 'spldmg' }, + { id: 'splheal' }, + { id: 'splhitpct' }, + { id: 'splcritstrkpct' }, + { id: 'splhastepct' }, + { id: 'splpen' }, + { id: 'oocmanargn' } + ], + // Defenses + [ + {id: 'defenses', type: 'title' }, + { id: 'armor' }, + { id: 'def' }, + { id: 'dodgepct' }, + { id: 'parrypct' }, + { id: 'blockpct' }, + { id: 'resipct' }, + + // Resistances + { id: 'arcres', type: 'resist' }, + { id: 'firres', type: 'resist' }, + { id: 'frores', type: 'resist' }, + { id: 'natres', type: 'resist' }, + { id: 'shares', type: 'resist' } + ] + ]; + + this.initialize = function (container, tabIndex) { + _container = $WH.ge(container); + if (!_container) { + return; + } + + _parentVars = _parent.getVars(); + _profile = _parentVars.profile; + _inventory = _parentVars.inventory; + + _initStatistics(); + _initStatBoxes(); + }; + + this.addModifiers = function (source, sourceId, json) { + _addModifiers(source, sourceId, json); + }; + + this.removeModifiers = function (source, sourceId) { + _removeModifiers(source, sourceId); + }; + + this.removeAllModifiers = function (source) { + _removeAllModifiers(source); + }; + + this.updateModifiers = function () { + _updateModifiers(); + }; + + function _checkPowerType(stat) { + if ($WH.in_array(['rage', 'energy', 'runic', 'mana'], stat) != -1) { + return (stat == _checkPowerType()); + } + + switch (_profile.classs) { + case 1: return 'rage'; + case 4: return 'energy'; + case 6: return 'runic'; + default: return 'mana'; + } + } + + function _addModifiers(source, sourceId, json) { + for (var i in json) { // Check to make sure the json has some property + var modifiers = $WH.dO(json); + + modifiers.source = source; + modifiers.sourceId = sourceId; + + if (source != 'class' && source != 'talent') { + modifiers.diminish = true; + } + + _modifiers.push(modifiers); + + _prepareStatistics(); + + break; // Don't actually loop + } + } + + function _getModifiers(source, sourceId, statId) { + var + stat = _statistics[statId], + result = 0; + + for (var i = 0, len = stat.modifiers.length; i < len; ++i) { + var + mod = stat.modifiers[i], + multiple = (stat.slotMultiple[mod.slot] || 0) + stat.multiple; + + if (mod.source == source && mod.sourceId == sourceId) { + result += _calcModifiers(mod, multiple); + } + } + + if (!stat.decimals) { + result = Math.floor(result); + } + + return result.toFixed(stat.decimals); + } + + function _calcModifiers(mod, multiple) { + if (mod.subtotal != null) { + return mod.subtotal; + } + + mod.subtotal = 0; + + if (mod.functionOf) { + mod.subtotal += multiple * mod.percent * mod.functionOf(_profile, _statistics); + } + + if (mod.percentOf) { + mod.subtotal += multiple * mod.percent * (mod.percentOf == 'level' ? _profile.level : _statistics[mod.percentOf].total) + mod.percentBase; + } + + if (mod.add) { + mod.subtotal += multiple * (mod.add - mod.exclude) + mod.exclude; + } + + return mod.subtotal; + } + + function _removeModifiers(source, sourceId) { + var result = []; + + for (var i = 0, len = _modifiers.length; i < len; ++i) { + if (_modifiers[i].source != source || _modifiers[i].sourceId != sourceId) { + result.push(_modifiers[i]); + } + } + + _modifiers = result; + + _prepareStatistics(); + } + + function _removeAllModifiers(source) { + var result = []; + + for (var i = 0, len = _modifiers.length; i < len; ++i) { + if (_modifiers[i].source != source) { + result.push(_modifiers[i]); + } + } + + _modifiers = result; + + _prepareStatistics(); + } + + function _refreshModifiers(statId) { + var stat = _statistics[statId]; + + stat.modifiers = []; + + for (var i = 0, len = _modifiers.length; i < len; ++i) { + if (_modifiers[i][statId] != null) { + stat.modifiers.push(_parseModifiers(_modifiers[i], statId)); + } + } + + stat.modifiers.sort(function (a, b) { + if (a.multiple != b.multiple) { + return - $WH.strcmp(a.multiple, b.multiple); + } + if (a.percentOf != b.percentOf) { + return - $WH.strcmp(a.percentOf, b.percentOf); + } + return $WH.strcmp(a.slot, b.slot); + }); + } + + function _parseModifiers(json, statId) { + var + mod = json[statId], + source = json.source, + sourceId = json.sourceId, + stat = _statistics[statId], + result = {}; + + if (typeof mod == 'object' && mod.length) { + for (var i = 1, len = mod.length; i < len; i += 2) { + result[mod[i]] = mod[i + 1]; + } + + if (result.percentOf != null) { + result.percentBase = 0; + + if (typeof result.percentOf == 'object' && result.percentOf.length) { + result.percentBase = result.percentOf[1]; + result.percentOf = result.percentOf[0]; + } + + if (result.percentOf == statId) { + result.multiple = mod[0]; + + if (result.percentBase) { + result.add = result.percentBase; + } + + delete result.percentOf; + delete result.percentBase; + } + else { + result.percent = mod[0]; + } + } + + if (result.functionOf != null) { + result.percent = mod[0]; + } + + if (result.percentOf && result.percentOf != 'level' && stat.dependent[result.percentOf] == null) { + stat.dependent[result.percentOf] = 1; + stat.ndependent++; + } + + if (result.forSlots != null) { + result.slotMultiple = {}; + + for (var i = 0, len = result.forSlots.length; i < len; ++i) { + result.slotMultiple[result.forSlots[i]] = mod[0]; + } + + delete result.forSlots; + } + + // Check if character has buff + if (result.forStance != null) { + return {}; + } + + // Check if character has item class + if (result.forClass != null) { + if (!_inventory.hasItemClassQty(result.forClass[0], result.forClass[1], result.forClass[2])) { + return {}; + } + } + + if (!result.percent && !result.multiple && !result.forSlots) { + result.add = mod[0]; + } + } + else if (!isNaN(mod)) { + result = { add: mod }; + } + + result.source = source; + result.sourceId = sourceId; + + if (source != 'class' && source != 'talent') { + result.diminish = true; + } + + if (source == 'item' && sourceId != null) { + result.slot = sourceId; + } + + result.exclude = 0; + if (stat.excludeModifiers) { + for (var i = 0, len = stat.excludeModifiers.length; i < len; ++i) { + result.exclude += json[stat.excludeModifiers[i]] || 0; + } + } + + return result; + } + + function _updateModifiers() { + // Modifiers from stats + _removeAllModifiers('stat'); + + for (var statId in _statistics) { + var stat = _statistics[statId]; + + if (stat.addModifiers) { + _addModifiers('stat', statId, stat.addModifiers()); + } + + if (stat.rating) { + var + rating = _statistics[stat.rating.stat], + ratingMod = {}; + + ratingMod[statId] = [$WH.g_convertRatingToPercent(_profile.level, stat.rating.id, 1, _profile.classs), 'percentOf', stat.rating.stat]; + + _addModifiers('stat', stat.rating.stat, ratingMod); + } + } + + // Modifiers from race + _removeAllModifiers('race'); + + var + raceData = g_statistics.race[_profile.race], + baseAttribs = { + str: (raceData ? raceData[0] : 0), + agi: (raceData ? raceData[1] : 0), + sta: (raceData ? raceData[2] : 0), + 'int': (raceData ? raceData[3] : 0), + spi: (raceData ? raceData[4] : 0) + }; + + _addModifiers('race', _profile.race, baseAttribs); + _addModifiers('race', _profile.race, (raceData ? raceData[5] : 0)); + _addModifiers('race', _profile.race, (raceData ? raceData[6] : 0)); + + // Modifiers from class + _removeAllModifiers('class'); + + var + classData = g_statistics.classs[_profile.classs], + levelData = g_statistics.combo[_profile.classs][_profile.level], + baseAttribs = { + str: levelData[0], + agi: levelData[1], + sta: levelData[2], + 'int': levelData[3], + spi: levelData[4], + health: levelData[5], + mleatkpwr: [classData[0][3], 'percentOf', 'level'], + rgdatkpwr: [classData[1][3], 'percentOf', 'level'], + dodgepct: classData[4] + levelData[9] * ((raceData ? raceData[1] : 0) + levelData[1]), // may need to add http://www.wowhead.com/spell=13789 here (there are also 2 druid talents but they require bear/cat form so that's not a problem + parrypct: classData[6], + blockpct: classData[8], + def: _profile.level * 5 + }; + + baseAttribs[_checkPowerType()] = levelData[6]; + + _addModifiers('class', _profile.classs, baseAttribs); + _addModifiers('class', _profile.classs, classData[9]); + _addModifiers('class', _profile.classs, classData[10]); + + // Modifiers from tradeskills + _removeAllModifiers('skill'); + + for (var i in _profile.skills) { + var skillRank = Math.max(1, Math.floor(_profile.skills[i][0] / 75) * 75); + + if (g_statistics.skills[i] && g_statistics.skills[i][skillRank]) { + _parent.fixJson(g_statistics.skills[i][skillRank]); + _addModifiers('skill', i, g_statistics.skills[i][skillRank]); + } + } + } + + function _initStatistics() { + var statistics = {}; + + for (var statId in _statistics) { + var stat = _statistics[statId]; + + stat.total = 0; + stat.subtotal = [0, 0]; + stat.modifiers = []; + + if (stat.decimals == null) { + stat.decimals = 0; + } + + if (stat.multiple == null) { + stat.multiple = 1; + } + + if (stat.slotMultiple == null) { + stat.slotMultiple = {}; + } + + if (stat.dependent == null) { + stat.dependent = {}; + stat.ndependent = 0; + } + + if (stat.magic) { + for (var i = 0, len = _magicSchools.length; i < len; ++i) { + var school = { + total: 0, + subtotal: [0, 0], + modifiers: [], + dependent: {}, + ndependent: 0, + decimals: stat.decimals, + multiple: stat.multiple, + slotMultiple: {} + }; + + $WH.cO(school.slotMultiple, stat.slotMultiple); + + if (stat.rating) { + var rating = { + total: 0, + subtotal: [0, 0], + modifiers: [], + dependent: {}, + ndependent: 0, + decimals: 0, + multiple: 1, + slotMultiple: {} + }; + + school.rating = { + id: stat.rating.id, + stat: _magicSchools[i] + stat.rating.stat + }; + + school.tooltipRatings = [school.rating.stat]; + + statistics[school.rating.stat] = rating; + school.dependent[school.rating.stat] = 1; + school.ndependent++; + } + + statistics[_magicSchools[i] + statId] = school; + stat.dependent[_magicSchools[i] + statId] = 1; + stat.ndependent++; + } + + delete stat.rating; + } + else if (stat.rating) { + var rating = { + total: 0, + subtotal: [0, 0], + modifiers: [], + dependent: {}, + ndependent: 0, + decimals: 0, + multiple: 1, + slotMultiple: {} + }; + + if (!stat.tooltipRatings) { + stat.tooltipRatings = [stat.rating.stat]; + } + + statistics[stat.rating.stat] = rating; + stat.dependent[stat.rating.stat] = 1; + stat.ndependent++; + } + } + + $WH.cO(_statistics, statistics); + } + + function _prepareStatistics() { + if (_timer > 0) { + clearTimeout(_timer); + _timer = 0; + } + + _timer = setTimeout(_updateStatistics, 750); + } + + function _updateStatistics() { + var + statOrder = [], + statArray = [], + statProcd = {}; + + for (var statId in _statistics) { + var stat = _statistics[statId]; + + stat.multiple = 1; + stat.slotMultiple = {}; + + if (!stat.magic) { // Don't get modifiers + _refreshModifiers(statId); + } + + statArray.push(statId); + statProcd[statId] = 0; + } + + var sortStatistics = function (statList) { + var tryAgain = []; + + for (var i = 0, len = statList.length; i < len; ++i) { + var + statId = statList[i], + stat = _statistics[statId], + nProc = 0; + + for (var j in stat.dependent) { + if (statProcd[j]) { + nProc++; + } + } + + if (nProc == stat.ndependent) { + statOrder.push(statId); + statProcd[statId] = 1; + } + else { + tryAgain.push(statId); + } + } + + if (tryAgain.length && tryAgain.length != statList.length) { + sortStatistics(tryAgain); + } + }; + + sortStatistics(statArray); + + for (var i = 0, len = statOrder.length; i < len; ++i) { + var + statId = statOrder[i], + stat = _statistics[statId], + subtotalDR = [0, 0]; + + stat.total = 0; + stat.subtotal = [0, 0]; + + if (stat.magic) { + stat.subtotal[0] = _statistics[_magicSchools[0] + statId].total; + + for (var j = 1, len2 = _magicSchools.length; j < len2; ++j) { + var school = _statistics[_magicSchools[j] + statId]; + if (school.total < stat.subtotal[0]) { + stat.subtotal[0] = school.total; + } + subtotalDR[0] = stat.subtotal[0]; + } + } + else { + for (var j = 0, len2 = stat.modifiers.length; j < len2; ++j) { + var mod = stat.modifiers[j]; + + if (mod.multiple) { + stat.multiple += mod.multiple; + } + else if (mod.slotMultiple) { + for (var slot in mod.slotMultiple) { + if (stat.slotMultiple[slot] == null) { + stat.slotMultiple[slot] = 0; + } + stat.slotMultiple[slot] += mod.slotMultiple[slot]; + } + } + else { + var + multiple = (stat.slotMultiple[mod.slot] || 0) + stat.multiple, + subType = (mod.source == 'race' || mod.source == 'class' || mod.source == 'stat' || (mod.source == 'talent' && statId != 'manargn') || (mod.source == 'item' && statId == 'armor') ? 0 : 1), + useDR = (stat.computeDiminished && mod.diminish ? 1 : 0); + + stat.subtotal[subType] += _calcModifiers(mod, multiple); + subtotalDR[useDR] += _calcModifiers(mod, multiple); + } + } + } + + if (!stat.decimals) { + for (var j = 0; j < 2; ++j) { + stat.subtotal[j] = Math.floor(stat.subtotal[j]); + subtotalDR[j] = Math.floor(subtotalDR[j]); + } + } + + if (stat.computeDiminished) { + subtotalDR[1] = stat.computeDiminished(subtotalDR[1]); + stat.total = parseFloat(subtotalDR[0]) + parseFloat(subtotalDR[1]); + } + else { + stat.total = parseFloat(stat.subtotal[0]) + parseFloat(stat.subtotal[1]); + } + + stat.total = stat.total.toFixed(stat.decimals); + } + + _updateStatBoxes(); + } + + function _initStatBoxes() { + var + _, + __, + t = $WH.ce('table'), + tb = $WH.ce('tbody'), + tr = $WH.ce('tr'), + td = $WH.ce('td'), + a, + p, + h3; + + t.className = 'profiler-inventory-stats'; + _tblStatBoxes = t; + + _ = $WH.ce('div'); + _.className = 'text'; + __ = $WH.ce('h2'); + __.className = 'clear'; + __.id = 'statistics'; + a = $WH.ce('a'); + a.className = 'header-link'; + a.href = '#statistics'; + $WH.ae(a, $WH.ct(LANG.pr_stats_title)); + $WH.ae(__, a); + $WH.ae(_, __); + $WH.ae(_container, _); + + $WH.ae(__, $WH.ct(String.fromCharCode(160))); + + p = $WH.ce('small'); + p.className = "q0"; + $WH.ae(p, $WH.ct(LANG.pr_stats_beta)); + $WH.ae(__, p); + + _divStatBars = _ = $WH.ce('div'); + _.className = 'profiler-inventory-bars'; + $WH.ae(_container, _divStatBars); + + _divStatResists = _ = $WH.ce('div'); + _.className = 'profiler-inventory-resists'; + $WH.ae(_container, _divStatResists); + + _ = $WH.ce('div'); + _.className = 'clear pad'; + $WH.ae(_container, _); + + for (var i = 0, len = _statBoxes.length; i < len; ++i) { + td = $WH.ce('td'); + p = $WH.ce('p'); + h3 = $WH.ce('h3'); + + td.style.width = (100 / len) + '%'; + + if (i == len - 1) { + p.style.marginRight = '0'; + } + + $WH.ae(p, h3); + + var boxContent = _statBoxes[i]; + for (var j = 0, len2 = boxContent.length; j < len2; ++j) { + var + boxStat = boxContent[j], + statId = boxStat.id, + stat = _statistics[statId], + a, + div, + sp1, + sp2; + + switch (boxStat.type) { + case 'title': + a = $WH.ce('a'); + a.className = 'disclosure-off'; + a.href = 'javascript:;'; + $WH.ns(a); + + boxContent.disclosure = a; + + a.onclick = _expandStatBox.bind(0, boxContent); + + $WH.st(a, _getStatBoxLabel(statId, boxStat)); + $WH.ae(h3, a); + + break; + case 'bar': + var bar = g_createProgressBar({ color: statId }); + + bar.style.display = 'none'; + + boxStat.bar = bar; + + $WH.ae(_divStatBars, bar); + + break; + case 'resist': + var icon = Icon.create(stat.icon, 1, null, 'javascript:;'); + + icon.style.cssFloat = icon.style.styleFloat = 'left'; + + a = Icon.getLink(icon); + a.onmouseover = _showStatBoxTooltip.bind(sp2, statId, boxStat); + a.onmouseout = $WH.Tooltip.hide; + + boxStat.icon = icon; + + $WH.ae(_divStatResists, icon); + + break; + default: + a = $WH.ce('a'); + a.href = 'javascript:;'; + a.onmouseover = _showStatBoxTooltip.bind(sp2, statId, boxStat); + a.onmousemove = $WH.Tooltip.cursorUpdate; + a.onmouseout = $WH.Tooltip.hide; + + sp2 = $WH.ce('var'); + $WH.ae(a, sp2); + + boxStat.span = sp2; + + sp1 = $WH.ce('em'); + $WH.ae(sp1, $WH.ct(_getStatBoxLabel(statId))); + $WH.ae(a, sp1); + + div = $WH.ce('div'); + div.className = 'clear'; + $WH.ae(a, div); + + $WH.ae(p, a); + + div = $WH.ce('small'); + div.className = 'q2'; + div.style.display = 'none'; + + boxStat.detail = div; + + a.onclick = _toggleStatBoxDetail.bind(div, statId, boxStat, null, boxContent); + + $WH.ae(p, div); + + break; + } + } + + $WH.ae(td, p); + $WH.ae(tr, td); + } + + $WH.ae(tb, tr); + $WH.ae(t, tb); + $WH.ae(_container, _tblStatBoxes); + + _ = $WH.ce('div'); + _.className = 'pad'; + $WH.ae(_container, _); + + div = $WH.ce('div'); + div.className = 'text'; + $WH.ae(div, $WH.ct(LANG.pr_stats_warning)); + $WH.ae(_container, div); + } + + function _updateStatBoxes() { + for (var i = 0, len = _statBoxes.length; i < len; ++i) { + var boxContent = _statBoxes[i]; + for (var j = 0, len2 = boxContent.length; j < len2; ++j) { + var + boxStat = boxContent[j], + statId = boxStat.id, + stat = _statistics[statId], + value; + + switch (boxStat.type) { + case 'title': + break; + case 'bar': + if (_checkPowerType(statId)) { + value = _getStatBoxValue(statId); + $WH.st(boxStat.bar.firstChild.firstChild, _getStatBoxLabel(statId) + ' ' + value); + boxStat.bar.style.display = (value > 0 ? '' : 'none'); + } + + break; + case 'resist': + value = [_getStatBoxValue(statId)]; + Icon.setNumQty(boxStat.icon, value); + + break; + default: + value = _getStatBoxValue(statId); + $WH.st(boxStat.span, value); + boxStat.span.className = (stat.subtotal[1] > 0 ? 'q2' : (stat.subtotal[1] < 0 ? 'q10' : '')); + boxStat.detail.innerHTML = _getStatBoxTooltip(statId, boxStat, true); + + break; + } + } + } + } + + function _expandStatBox(boxContent) { + var display = (boxContent.disclosure.className == 'disclosure-off'); + + for (var j = 0, len2 = boxContent.length; j < len2; ++j) { + var + boxStat = boxContent[j], + statId = boxStat.id; + + if (boxStat.type == 'title' || boxStat.type == 'bar' || boxStat.type == 'resist') { + continue; + } + + (_toggleStatBoxDetail.bind(div, statId, boxStat, display, boxContent))(); + } + + boxContent.disclosure.className = 'disclosure-' + (display ? 'on' : 'off'); + } + + function _getStatBoxValue(statId) { + var stat = _statistics[statId]; + return (stat.total < 0 ? 0 : stat.total) + (stat.decimals > 0 && !stat.nopct ? '%' : ''); + } + + function _getStatBoxLabel(statId, boxStat) { + var stat = (boxStat ? boxStat : _statistics[statId]); + + if (stat.label != null && LANG[stat.label] != null) { + return LANG[stat.label]; + } + + if (LANG['pr_stats_' + statId] != null) { + return LANG['pr_stats_' + statId]; + } + + return statId; + } + + function _getStatBoxTooltip(statId, boxStat, noLabel) { + var + stat = _statistics[statId], + tooltip = (stat.getTooltip ? stat.getTooltip() : LANG['pr_statstt_' + statId]) + buff = ''; + + if (!noLabel) { + buff += '' + _getStatBoxLabel(statId); + + buff += ' ' + (stat.total < 0 ? 0 : stat.total) + (stat.decimals > 0 ? '%' : ''); + + if (stat.subtotal[1] > 0 || stat.subtotal[1] < 0) { + buff += ' (' + stat.subtotal[0].toFixed(stat.decimals) + '' : 'q2">+') + stat.subtotal[1].toFixed(stat.decimals) + ')'; + } + + buff += ''; + } + + if (tooltip != null) { + var args = [tooltip]; + + if (stat.magic) { + var + ttSchools = '', + ttRating = []; + + for (var i = 0, len = _magicSchools.length; i < len; ++i) { + var + schoolId = _magicSchools[i] + statId, + school = _statistics[schoolId]; + + ttSchools += '' + + ''; + + if (school.tooltipRatings && i == 0) { + for (var j = 0, len2 = school.tooltipRatings.length; j < len2; ++j) { + ttRating.push(_statistics[school.tooltipRatings[j]].total); + ttRating.push(_getModifiers('stat', school.tooltipRatings[j], schoolId)); + } + } + } + + ttSchools += '
' + LANG['pr_statstt_' + _magicSchools[i]] + '' + school.total + (stat.decimals > 0 ? '%' : '') + '
'; + + args.push(ttSchools); + args = args.concat(ttRating); + } + + if (stat.tooltipRatings) { + for (var i = 0, len = stat.tooltipRatings.length; i < len; ++i) { + args.push(_statistics[stat.tooltipRatings[i]].total); + args.push(_getModifiers('stat', stat.tooltipRatings[i], statId)); + } + } + + if (stat.tooltipModifiers) { + for (var i = 0, len = stat.tooltipModifiers.length; i < len; ++i) { + args.push(_getModifiers('stat', statId, stat.tooltipModifiers[i])); + } + } + + if (stat.tooltipCompute) { + args = args.concat(stat.tooltipCompute(stat.total)); + } + + args.push(stat.total); + args.push(_profile.level); + + if (!noLabel) { + buff += '
' + $WH.sprintfo(args) + ''; + } + else { + buff = $WH.str_replace($WH.str_replace('- ' + $WH.str_replace($WH.sprintfo(args), '
', '(.+?)<\/span>', 'g'), '$1
' + $WH.sprintf(LANG.pr_tt_enchreq, e.jsonequip.reqlevel) + '<\/span>'); + } + + // Gem requirements + var s = html.match(new RegExp('<(a|span)( href=.+?)? class="[^"]*socket.+?', 'g')); + if (s != null) { + for (var j = 0; j < 4; ++j) { + if (s[j] && item[j + 4] && g_gems[item[j + 4]] && g_gems[item[j + 4]].socketlevel > g_items[item[0]].jsonequip.level) { + html = html.replace(s[j], s[j].replace(new RegExp('q[0-9]+', 'g'), 'q10')); + } + } + } + + // Item Set Pieces + if (g_items[item[0]].jsonequip.itemset) { + for (var i = 0, len = _data.length; i < len; ++i) { + var p = _getSlotItem(i)[0]; + if (g_items[p] && g_items[p].jsonequip.itemset == g_items[item[0]].jsonequip.itemset) { + pcs.push(p); + } + } + } + + var + row = _getItemErrors(slotId), + errors = row.errors; + + if (errors['level'] || errors['ench'] || errors['gems'] || errors['sock']) { + html += '
'; + } + + if (errors['level']) { + html += $WH.sprintf(LANG.pr_inv_item, LANG.pr_inv_lowlevel.replace(': ', '')); + } + + if (errors['ench'] || errors['gems'] || errors['sock']) { + if (errors['level']) { + html += LANG.dash; + } + + html += LANG.pr_inv_missing; + + if (errors['gems']) { + html += $WH.sprintf(errors['gems'] == 1 ? LANG.pr_inv_gem : LANG.pr_inv_gems, errors['gems']); + } + + if (errors['sock'] && errors['gems']) { + html += LANG.comma; + } + + if (errors['sock']) { + html += $WH.sprintf(errors['sock'] == 1 ? LANG.pr_inv_socket : LANG.pr_inv_sockets, errors['sock']); + } + + if (errors['ench'] && (errors['gems'] || errors['sock'])) { + html += LANG.comma; + } + + if (errors['ench']) { + html += $WH.sprintf(errors['ench'] == 1 ? LANG.pr_inv_enchant : LANG.pr_inv_enchants, errors['ench']); + } + } + + if (errors['level'] || errors['ench'] || errors['gems'] || errors['sock']) { + html += ''; + } + + return html; + } + + function _getItemRel(slotId) { + var item = _getSlotItem(slotId), + extraSocket = _hasExtraSocket(slotId), + rel = [], + gems = [], + pcs = []; + + if (!g_items[item[0]]) { + return; + } + + if (item[1]) { + rel.push('rand=' + item[1]); + } + + if (item[2]) { + rel.push('ench=' + item[2]); + } + + for (var i = 0, len = (g_items[item[0]].jsonequip.nsockets | 0) + extraSocket; i < len; ++i) { + gems.push(item[4 + i] > 0 ? item[4 + i] : 0); + } + + if (gems.length) { + rel.push('gems=' + gems.join(':')); + } + + if (extraSocket) { + rel.push('sock'); + } + + if (g_items[item[0]].jsonequip.itemset) { + for (var i = 0, len = _data.length; i < len; ++i) { + var p = _getSlotItem(i)[0]; + if (g_items[p] && g_items[p].jsonequip.itemset) { + pcs.push(p); + } + } + rel.push('pcs=' + pcs.join(':')); + } + + if (_profile.level) { + rel.push('lvl=' + _profile.level); + } + + if (_profile.classs) { + rel.push('c=' + _profile.classs); + } + + var result = rel.join('&'); + + if (result) { + result = '&' + result; + } + + return result; + } + + function _getItemHilite(slotId) { + var itemId = _getSlotItem(slotId)[0]; + + if (!g_items[itemId]) { + return; + } + + var item = g_items[itemId].jsonequip; + + if ((item.reqlevel > _profile.level) || + (item.reqclass && !(item.reqclass & 1 << _profile.classs - 1)) || + (item.subclass > 0 && item.subclass != 14 && item.subclass != 20 && _proficiencies[_profile.classs][item.classs] && !$WH.array_index(_proficiencies[_profile.classs][item.classs], item.subclass))) + { + return 'q10'; // Invalid item + } + + return 'q' + g_items[itemId].quality; + } + + function _getItemErrors(slotId, metaCondition) { + var item = _getSlotItem(slotId); + + if (!item[0] || !g_items[item[0]] || !_isSlotNeeded(slotId)) { + return; + } + + var + targetItemLvl = 0, + row = {}, + inventory = _getInventory(), + jsonequip = g_items[item[0]].jsonequip, + extraSocket = _hasExtraSocket(slotId), + enchantId = item[2]; + + if (_profile.level >= 70) { + targetItemLvl = ((_profile.level - 70) * 9.5) + 105; + } + else if (_profile.level >= 60) { + targetItemLvl = ((_profile.level - 60) * 4.5) + 60; + } + else { + targetItemLvl = _profile.level; + } + + for (var k in jsonEquipCopy) { + row[k] = jsonequip[k]; + } + + if (item[1] && g_items[item[0]].jsonequip.subitems != null && g_items[item[0]].jsonequip.subitems[item[1]] != null) { + row.name += ' ' + g_items[item[0]].jsonequip.subitems[item[1]].name; + } + + row.profileslot = slotId; + row.rel = _getItemRel(slotId); + row.score = _getGearScore(slotId); + row.use2h = (jsonequip.slot == 17 && !inventory[17][0]); + row.gems = []; + row.matchSockets = {}; + row.errors = {}; + + if (jsonequip.level < targetItemLvl && (slotId != 5 && slotId != 6 && slotId != 20) && (!jsonequip.scadist || !jsonequip.scaflags)) { + row.errors['level'] = 1; + } + + // Gems + for (var j = 0, len2 = (jsonequip.nsockets | 0) + extraSocket; j < len2; ++j) { + var + gemId = (item[j + 4] > 0 ? item[j + 4] : 0), + socketColor = (extraSocket && j == len2 - 1 ? 14 : jsonequip['socket' + (j + 1)]); + + row.matchSockets[j] = (gemId && g_gems[gemId] && _matchGemSocket(g_gems[gemId].colors, socketColor)); + row.gems.push(gemId); + + for (var k in metaCondition) { + if (k == 't' || !(metaCondition[k] > 0)) { + continue; + } + + if (gemId && g_gems[gemId] && _matchGemSocket(g_gems[gemId].colors, k)) { + metaCondition[k]--; + metaCondition.t--; + } + } + + if (gemId <= 0) { + row.errors['gems'] = (row.errors['gems'] | 0) + 1; + } + } + + // Sockets + if (_canBeSocketed(slotId) && !extraSocket && (_data[slotId].socket != 2 || _parent.isArmoryProfile())) {// Always show warnings for armory profiles + row.errors['sock'] = 1; + } + + // Enchant + if (enchantId || _canBeEnchanted(slotId)) { + row.enchant = 0; + + if (enchantId && g_enchants[enchantId]) { + var + enchant = g_enchants[enchantId], + slotMask = 1 << (jsonequip.slot - 1); + + if (typeof enchant.name == 'string') { + if (enchant.slots & slotMask) { + row.enchant = enchant.source; + row.enchantid = enchantId; + } + } + else { + for (var j = 0, len2 = enchant.slots.length; j < len2; ++j) { + if (enchant.slots[j] & slotMask) { + row.enchant = enchant.source[j]; + row.enchantid = enchantId; + break; + } + } + } + + if (row.enchant) { + var + ref = (row.enchant < 0 ? g_items : g_spells), + refId = Math.abs(row.enchant); + + if (ref[refId] == null) { + ref[refId] = { icon: enchant.icon }; + } + } + } + + if (!row.enchant) { + if (_data[slotId].enchant != 2 || _parent.isArmoryProfile()) { // Always show warnings for armory profiles + row.errors['ench'] = 1; + } + else { + delete row.enchant; + } + } + } + + return row; + } + + function _initListview(tabIndex) { + var + _, + __, + a; + + _ = $WH.ce('div'); + _.className = 'text'; + + __ = $WH.ce('h2'); + __.id = 'gear-summary'; + + _lnkPrint = $WH.ce('a'); + _lnkPrint.className = 'profiler-tablinks-print'; + _lnkPrint.href = 'javascript:;'; + _lnkPrint.onclick = _printSummary.bind(0); + $WH.ae(_lnkPrint, $WH.ct(LANG.pr_header_print)); + $WH.ae(__, _lnkPrint); + + a = $WH.ce('a'); + a.className = 'header-link'; + a.href = '#gear-summary'; + $WH.ae(a, $WH.ct(LANG.pr_inv_title)); + $WH.ae(__, a); + $WH.ae(_, __); + $WH.ae(_container, _); + + _ = $WH.ce('div'); + _.className = 'listview'; + $WH.ae(_container, _); + + var extraCols = [ + { + id: 'score', + name: LANG.score, + compute: function (item, td) { + if (!item.score) { + return; + } + + var + sum = item.score.item + item.score.ench + item.score.gems, + sp = $WH.ce('span'); + + td.className = 'q' + pr_getGearScoreQuality(_profile.level, sum - (item.score.bonus | 0), null, _data[item.profileslot].id, item.use2h); + + if (sum > 0) { + sp.className = 'tip'; + sp.onmouseover = _parent.showGearScoreTooltip.bind(0, item.score); + sp.onmousemove = $WH.Tooltip.cursorUpdate; + sp.onmouseout = $WH.Tooltip.hide; + } + + $WH.ae(sp, $WH.ct($WH.number_format(sum))); + $WH.ae(td, sp); + }, + getVisibleText: function (item) { + if (!item.score) { + return; + } + + return item.score.item + item.score.ench + item.score.gems; + }, + sortFunc: function (a, b, col) { + var + ascore = (a.score ? a.score.item + a.score.ench + a.score.gems : 0), + bscore = (b.score ? b.score.item + b.score.ench + b.score.gems : 0); + + return $WH.strcmp(ascore, bscore); + } + }, + { + id: 'gems', + name: LANG.gems, + compute: function (item, td) { + if (item.errors['gems'] || item.errors['sock']) { + td.style.backgroundColor = '#8C0C0C'; + } + + if (!item.gems.length) { + return; + } + + td.style.padding = '0'; + + var + sockets = [], + i; + + for (i = 0; i < item.nsockets; ++i) { + sockets.push(item['socket' + (i + 1)]); + } + + if (i < item.gems.length) { + sockets.push(14); + } + + Listview.funcBox.createSocketedIcons(sockets, td, item.gems, item.matchSockets); + + var d = td.firstChild, + buildData = _talents.getTalentBuilds(); + + for (var i = 0, len = sockets.length; i < len; ++i) { + var a = Icon.getLink(d.childNodes[i]); + + a.oncontextmenu = $WH.rf; + a.onclick = ($WH.Browser.opera || $WH.OS.mac ? function (e) { + e = $WH.$E(e); + if (e.shiftKey || e.ctrlKey) { + return false; + } + } : null); + a.onmouseup = _onMouseUpSlot.bind(0, item.profileslot, a); + + if (!(item.gems[i] > 0)) { + a.onclick = $WH.rf; + a.onmouseover = _showEmptyGemTooltip.bind(a, sockets[i]); + a.onmouseout = $WH.Tooltip.hide; + } + + a.menu = [ + [, g_socket_names[sockets[i]]], + [0, (item.gems[i] > 0 ? LANG.pr_menu_replace : LANG.pr_menu_add), _openGemPicker.bind(this, sockets[i], i + 4, item.profileslot)] + ]; + + if (item.gems[i] > 0) { + a.menu.push([0, LANG.pr_menu_remove, _unsocketItem.bind(this, 4 + i, item.profileslot, false)]); + } + + a.menu.push([, LANG.pr_menu_links]); + + var + url = '?items=3&filter=maxrl=' + _profile.level + ';ub=' + _profile.classs + (sockets[i] == 1 ? ';cr=81;crs=1;crv=0' : (sockets[i] == 32 ? ';cr=81;crs=6;crv=0': ';cr=81:81:81;crs=2:3:4;crv=0:0:0;ma=1')) + '$1' + (item.gems[i] ? ';gb=1;upg=' + item.gems[i] : ''), + _ = [0, LANG.pr_menu_upgrades, null, []]; + + _[3].push([0, buildData.name, $WH.sprintf(url, buildData.filter), null, { newWindow: true }]); + + if (g_user.weightscales && g_user.weightscales.length) { + for (var j = 0, len2 = g_user.weightscales.length; j < len2; ++j) { + var scale = g_user.weightscales[j]; + _[3].push([0, scale.name, $WH.sprintf(url, pr_getScaleFilter(scale)), null, { newWindow: true }]); + } + } + + a.menu.push(_); + } + }, + getVisibleText: function (item) { + if (!item.gems.length) { + return; + } + + var buff = ''; + + for (var i = 0, len = item.gems.length; i < len; ++i) { + var gemId = item.gems[i]; + + if (gemId > 0) { + if (i > 0) { + buff += ' '; + } + + buff += g_gems[item.gems[i]].name; + } + } + + return buff; + }, + getValue: function (item) { + return item.gems.length; + }, + sortFunc: function (a, b, col) { + var + suma = 0, + sumb = 0; + + $.each(a.gems, function (k) { + suma += a['socket' + (k + 1)]; + }); + $.each(b.gems, function (k) { + sumb += b['socket' + (k + 1)]; + }); + + return $WH.strcmp(a.gems.length, b.gems.length) || -$WH.strcmp(suma, sumb); + } + }, + { + id: 'enchant', + name: LANG.enchant, + compute: function (item, td) { + if (item.errors['ench']) { + td.style.backgroundColor = '#8C0C0C'; + } + + if (item.enchant == null) { + return; + } + + td.style.padding = '0'; + + Listview.funcBox.createCenteredIcons([Math.abs(item.enchant)], td, null, (item.enchant > 0 ? 1 : null)); + + var a = Icon.getLink(td.firstChild.childNodes[0]), + buildData = _talents.getTalentBuilds(); + + a.oncontextmenu = $WH.rf; + a.onclick = ($WH.Browser.opera || $WH.OS.mac ? function (e) { + e = $WH.$E(e); + if (e.shiftKey || e.ctrlKey) { + return false ; + } + } : null); + a.onmouseup = _onMouseUpSlot.bind(0, item.profileslot, a); + $WH.ns(a); + + if (!item.enchant) { + a.onclick = $WH.rf; + a.onmouseover = _showEmptyItemTooltip.bind(a, item.profileslot); + a.onmouseout = $WH.Tooltip.hide; + } + + a.menu = [ + [, g_item_slots[item.slot]], + [0, (item.enchant ? LANG.pr_menu_replace : LANG.pr_menu_add), _openEnchantPicker.bind(this, item.profileslot)] + ]; + + if (item.enchant) { + a.menu.push([0, LANG.pr_menu_remove, _unenchantItem.bind(this, item.profileslot)]); + } + + a.menu.push([, LANG.pr_menu_links]); + + var url = '?items=0.6&filter=sl=' + item.slot + ';maxrl=' + _profile.level + ';ub=' + _profile.classs + '$1' + (item.enchant < 0 ? ';gb=1;upg=' + Math.abs(item.enchant) : ''), + _ = [0, LANG.pr_menu_upgrades, null, []]; + + _[3].push([0, buildData.name, $WH.sprintf(url, buildData.filter), null, { newWindow: true }]); + + if (g_user.weightscales && g_user.weightscales.length) { + for (var i = 0, len = g_user.weightscales.length; i < len; ++i) { + var scale = g_user.weightscales[i]; + _[3].push([0, scale.name, $WH.sprintf(url, pr_getScaleFilter(scale)), null, { newWindow: true }]); + } + } + + a.menu.push(_); + }, + getVisibleText: function (item) { + if (item.enchant == null) { + return; + } + + return g_enchants[item.enchantid].name; + }, + getValue: function (item) { + return (item.enchant == null ? 0 : 1); + }, + sortFunc: function (a, b, col) { + if (g_enchants[a.enchantid] && g_enchants[b.enchantid]) { + return $WH.strcmp(g_enchants[a.enchantid].gearscore, g_enchants[b.enchantid].gearscore); + } + return $WH.strcmp(a.enchant, b.enchant); + } + } + ]; + + _listview = new Listview({ + template: 'inventory', + id: 'inventory', + parent: _, + extraCols: extraCols + }); + + if (tabIndex != null) { + _listview.tabs = _tabs; + _listview.tabIndex = tabIndex; + } + + _ = $WH.ce('div'); + _.className = 'pad'; + $WH.ae(_container, _); + + _divTipRclk = _ = $WH.ce('div'); + _.className = 'text'; + _.style.display = 'none'; + $WH.ae(_, $WH.ct(_shiftClick ? LANG.pr_tip_sclkopt2 : LANG.pr_tip_rclkopt2)); + $WH.ae(_container, _); + } + + function _updateListview() { + if (!_inited) { + return; + } + + var + dataz = [], + metaCondition = _getMetaCondition(), + targetItemLvl = 0, + lowLevelItems = 0, + missingItems = 0, + missingGems = 0, + missingEnchants = 0, + missingSockets = 0; + + _parent.updateGearScore(); + + // Data + for (var i = 0, len = _data.length; i < len; ++i) { + var + slotId = i, + item = _getSlotItem(slotId); + + if (_isSlotNeeded(slotId, 1) && !item[0] && (slotId != 5 && slotId != 6 && slotId != 20) && ( + (_profile.level > 55) || + (_profile.level > 25 && (slotId != 14 || slotId != 15 || slotId != 19)) || // Trinkets or Relics + (_profile.level > 20 && (slotId != 0 || slotId != 1)) || // Head or Neck + (slotId != 2 || slotId != 12 || slotId != 13))) // Shoulder or Trinkets + { + missingItems++; + } + + if (!item[0] || !g_items[item[0]] || !_isSlotNeeded(slotId)) { + continue; + } + + var row = _getItemErrors(slotId, metaCondition); + + if (row.errors['level']) { + lowLevelItems++; + } + + if (row.errors['gems']) { + missingGems += row.errors['gems']; + } + + if (row.errors['sock']) { + missingSockets++; + } + + if (row.errors['ench']) { + missingEnchants++; + } + + dataz.push(row); + } + + // Note + var + note = _listview.getNoteTopDiv().firstChild, + buff = ''; + + if (lowLevelItems) { + buff += LANG.pr_inv_lowlevel + $WH.sprintf(lowLevelItems == 1 ? LANG.pr_inv_item : LANG.pr_inv_items, lowLevelItems); + + if (missingItems || missingEnchants || missingGems || missingSockets || metaCondition.t > 0) { + buff += LANG.dash; + } + } + + if (missingItems || missingEnchants || missingGems || missingSockets) { + buff += LANG.pr_inv_missing; + + if (missingItems) { + buff += $WH.sprintf(missingItems == 1 ? LANG.pr_inv_item : LANG.pr_inv_items, missingItems); + } + + if (missingGems && missingItems) { + buff += LANG.comma; + } + + if (missingGems) { + buff += $WH.sprintf(missingGems == 1 ? LANG.pr_inv_gem : LANG.pr_inv_gems, missingGems); + } + + if (missingSockets && (missingItems || missingGems)) { + buff += LANG.comma; + } + + if (missingSockets) { + buff += $WH.sprintf(missingSockets == 1 ? LANG.pr_inv_socket : LANG.pr_inv_sockets, missingSockets); + } + + if (missingEnchants && (missingItems || missingGems || missingSockets)) { + buff += LANG.comma; + } + + if (missingEnchants) { + buff += $WH.sprintf(missingEnchants == 1 ? LANG.pr_inv_enchant : LANG.pr_inv_enchants, missingEnchants); + } + + if (metaCondition.t > 0) { + buff += LANG.dash; + } + } + + if (metaCondition.t > 0) { + buff += LANG.pr_inv_metareq; + + var i = 0; + for (var k in metaCondition) { + if (k == 't' || !(metaCondition[k] > 0)) { + continue; + } + + if (i++>0) { + buff += LANG.comma; + } + + buff += $WH.sprintf(metaCondition[k] == 1 ? LANG.pr_inv_gem : LANG.pr_inv_gems, metaCondition[k] + ' ' + g_gem_colors[k]); + } + } + + $WH.st(note, (buff.length ? buff : String.fromCharCode(160))); + + _listview.setData(dataz); + _listview.updateFilters(true); + + _divTipRclk.style.display = (dataz.length ? '' : 'none'); + } + + function _printSummary() { + var + buff = '' + document.title + ''; + + buff += '

' + _profile.name + ' ' + LANG.pr_inv_title + '

'; + + for (var i = 0, len = _slots.length; i < len; ++i) { + var + slotId = i, + item = _getSlotItem(slotId); + + if (!item[0] || !g_items[item[0]] || !_isSlotNeeded(slotId)) { + continue; + } + + var + row = {}, + jsonequip = g_items[item[0]].jsonequip, + subitems = g_items[item[0]].jsonequip.subitems, + extraSocket = _hasExtraSocket(slotId); + + buff += g_item_slots[_slots[slotId].itemslots[0]] + ': ' + jsonequip.name.substring(1); + + if (item[1] && subitems != null && subitems[item[1]] != null) { + buff += ' ' + subitems[item[1]].name; + } + + buff += ''; + buff += '
    '; + + // Source + if (jsonequip.source) { + buff += '
  • ' + LANG.source + ' - '; + + for (var j = 0, len2 = jsonequip.source.length; j < len2; ++j) { + var + sm = (jsonequip.sourcemore && jsonequip.sourcemore[j] ? jsonequip.sourcemore[j] : {}), + ls = Listview.funcBox.getLowerSource(jsonequip.source[j], sm, (sm.t | 0)); + + if (j > 0) { + buff += ', '; + } + + if (sm.t) { + buff += sm.n; + } + else { + buff += Listview.funcBox.getUpperSource(jsonequip.source[j], sm); + } + + buff += ' (' + g_sources[jsonequip.source[j]]; + + if (ls != null) { + buff += '; ' + ls.text; + + if (sm.dd) { + if (sm.dd < 0) { // Dungeon + buff += ' ' + (sm.dd < -1 ? LANG.pr_print_heroic : LANG.pr_print_normal); + } + else { // 10 or 25 Player Raid + buff += ' ' + (sm.dd & 1 ? LANG.lvitem_raid10 : LANG.lvitem_raid25) + ' ' + (sm.dd > 2 ? LANG.pr_print_heroic : LANG.pr_print_normal); + } + } + } + + buff += ')'; + } + + buff += '
  • '; + } + + // Enchant + if (item[2] || _canBeEnchanted(slotId)) { + buff += '
  • ' + LANG.enchant + ' - '; + + if (item[2] && g_enchants[item[2]]) { + var + enchant = g_enchants[item[2]], + slotMask = 1 << (jsonequip.slot - 1); + + if (typeof enchant.name == 'string') { + if (enchant.slots & slotMask) { + buff += enchant.name; + } + } + else { + for (var j = 0, len2 = enchant.slots.length; j < len2; ++j) { + if (enchant.slots[j] & slotMask) { + buff += enchant.name[j]; + break; + } + } + } + } + else { + buff += '' + LANG.pr_print_none + ''; + } + + buff += '
  • '; + } + + // Extra Socket + if (_canBeSocketed(slotId)) { + buff += '
  • ' + LANG.pr_menu_extrasock + ' - ' + (extraSocket ? LANG.pr_print_yes : '' + LANG.pr_print_no + '') + '
  • '; + } + + // Gems + if (jsonequip.nsockets || extraSocket) { + buff += '
  • ' + LANG.gems + ' - '; + + for (var j = 0, len2 = (jsonequip.nsockets | 0) + extraSocket; j < len2; ++j) { + if (j > 0) { + buff += ', '; + } + + if (item[j + 4] && g_gems[item[j + 4]]) { + buff += g_gems[item[j + 4]].name; + } + else { + buff += '' + LANG.pr_print_none + ''; + } + + buff += ' (' + g_socket_names[(extraSocket && j == len2 - 1 ? 14 : jsonequip['socket' + (j + 1)])] + ')'; + } + + buff += '
  • '; + } + + buff += '
'; + } + + buff += ''; + + profileSummary = buff; + window.open('?profile=summary', '', 'toolbar=no,menubar=yes,status=yes,scrollbars=yes,resizable=yes'); + } + + function _prepareSearch(search, delay) { + if (isNaN(delay)) { + delay = 1000; + } + + if (_timer > 0) { + clearTimeout(_timer); + _timer = 0; + } + + if (search) { + $WH.st(_searchMsg, $WH.sprintf(LANG['pr_searching'], search)); + } + _searchMsg.className = ''; + + _timer = setTimeout(_searchItems.bind(0, search, _currentSlot), delay); + } + + function _searchItems(search, slotId) { + var + lv = g_listviews.items; + + _searchResults = [{ none: 1, __alwaysvisible: 1 }]; + + lv.searchable = false; + lv.setData(_searchResults); + lv.clearSearch(); + lv.updateFilters(true); + _searchMsg.className = ''; + + if (!search && !_currentScale) { + $WH.st(_searchMsg, LANG['pr_specifyitem']); + return; + } + $WH.st(_searchMsg, $WH.sprintf(LANG['pr_searching'], search)); + + new Ajax('?search=' + $WH.urlencode(search) + '&json&slots=' + _data[slotId].itemslots.join(':') + pr_getScaleFilter(_currentScale, 1), { + method: 'POST', + search: search, + onSuccess: function (xhr, opt) { + var text = xhr.responseText; + if (text.charAt(0) != '[' || text.charAt(text.length - 1) != ']') { + $WH.st(_searchMsg, $WH.sprintf(LANG.su_noresults, opt.search)); + _searchMsg.className = 'q10'; + return; + } + + var a = eval(text); + if (search == opt.search && a.length == 3 && a[1].length) { + for (var i = 0, len = a[1].length; i < len; ++i) { + var row = {}; + row.id = a[1][i].id; + row.name = row['name_' + Locale.getName()] = a[1][i].name.substring(1); + row.quality = 7 - a[1][i].name.charAt(0); + row.icon = a[1][i].icon; + row.level = a[1][i].level; + row.classs = a[1][i].classs; + row.subclass = a[1][i].subclass; + row.gearscore = a[1][i].gearscore; + row.jsonequip = $WH.dO(a[1][i]); + + g_items.add(a[1][i].id, row); + _searchResults.push(row); + } + $WH.ee(_searchMsg); + } + else { + $WH.st(_searchMsg, $WH.sprintf(LANG.pr_noresults, opt.search)); + _searchMsg.className = 'q10'; + } + + lv.setData(_searchResults); + lv.clearSearch(); + lv.updateFilters(true); + + _sortPickerWindow(lv); + } + }); + } + + function _isValidItem(item) { + if (item.none) { + return true; + } + + var itemTypes = _proficiencies[_profile.classs][item.classs]; + + return ( + // Item Class + ( + _itemType == null || !itemTypes || item.subclass < 1 || item.subclass == 14 || + ((_itemType == 1 || item.classs == 2 || item.subclass > 4) && $WH.array_index(itemTypes, item.subclass)) || + (_itemType == 2 && item.subclass == itemTypes[itemTypes.length - 1]) + ) + ); + } + + function _filterItems(wut, value) { + switch (wut) { + case 0: + _itemType = value; + break; + default: + return; + } + + if (this && this.nodeName == 'A') { + g_setSelectedLink(this, 'items' + wut); + } + + _lvItems.updateFilters(true); + + return false; + } + + function _createItemsNote(div) { + var + sm = $WH.ce('small'), + sp = $WH.ce('span'), + a; + + $WH.ae(sm, $WH.ct(LANG.pr_note_type)); + + a = $WH.ce('a'); + a.href = 'javascript:;'; + a.onclick = _filterItems.bind(a, 0, null); + $WH.ae(a, $WH.ct(LANG.pr_note_all)); + + $WH.ae(sm, a); + $WH.ae(sm, $WH.ct(LANG.comma)); + + a = $WH.ce('a'); + a.href = 'javascript:;'; + a.onclick = _filterItems.bind(a, 0, 1); + $WH.ae(a, $WH.ct(LANG.pr_note_usable)); + + $WH.ae(sm, a); + $WH.ae(sm, sp); + $WH.ae(sp, $WH.ct(LANG.comma)); + + a = $WH.ce('a'); + a.href = 'javascript:;'; + a.onclick = _filterItems.bind(a, 0, 2); + + _itemType = 2; + g_setSelectedLink(a, 'items0'); + + $WH.ae(sp, a); + + sp = $WH.ce('span'); + sp.style.padding = '0 8px'; + sp.style.color = 'white'; + $WH.ae(sp, $WH.ct('|')); + $WH.ae(sm, sp); + + $WH.ae(div, sm); + + sm = $WH.ce('small'); + $WH.ae(sm, $WH.ct(LANG.pr_note_name)); + + _spSearchName = $WH.ce('input'); + _spSearchName.type = 'text'; + _spSearchName.value = _currentSearch; + + $WH.aE(_spSearchName, 'keyup', _onKeyUpSearch.bind(0, 333)); + $WH.aE(_spSearchName, 'keydown', _onKeyDownSearch); + + $WH.ae(sm, _spSearchName); + + _searchMsg = $WH.ce('span'); + _searchMsg.style.fontWeight = 'bold'; + $WH.ae(sm, _searchMsg); + + $WH.ae(div, sm); + } + + function _isValidEnchant(enchant) { + if (enchant.none) { + return true; + } + + var + slotMask = 1 << (g_items[_getSlotItem(_currentSlot)[0]].jsonequip.slot - 1), + classMask = 1 << (_profile.classs - 1); + + return ( + // Class + (enchant.classes <= 0 || enchant.classes & classMask) && + + // Slot + (enchant.slots & slotMask) && + + // Source + ( + _enchantSource == null || + (_enchantSource == 1 && enchant.source < 0) || + (_enchantSource == 2 && enchant.source > 0) + ) && + + // StatType + ( + _enchantStat == null || + ( + _enchantStat == -1 && + !enchant.jsonequip.hasOwnProperty('sta') && + !enchant.jsonequip.hasOwnProperty('str') && + !enchant.jsonequip.hasOwnProperty('agi') && + !enchant.jsonequip.hasOwnProperty('int') && + !enchant.jsonequip.hasOwnProperty('spi') + ) || + ( + enchant.jsonequip.hasOwnProperty(_enchantStat) + ) + ) + ); + } + + function _filterEnchants(wut, value) { + switch (wut) { + case 0: + _enchantSource = value; + break; + case 1: + _enchantStat = value; + break; + default: + return; + } + + if (this && this.nodeName == 'A') { + g_setSelectedLink(this, 'enchants' + wut); + } + + _lvEnchants.updateFilters(true); + + return false; + } + + function _createEnchantsNote(div) { + var + sm = $WH.ce('small'), + a; + + $WH.ae(sm, $WH.ct(LANG.pr_note_source)); + + a = $WH.ce('a'); + a.href = 'javascript:;'; + a.onclick = _filterEnchants.bind(a, 0, null); + $WH.ae(a, $WH.ct(LANG.pr_note_all)); + + g_setSelectedLink(a, 'enchants0'); + + $WH.ae(sm, a); + $WH.ae(sm, $WH.ct(LANG.comma)); + + a = $WH.ce('a'); + a.href = 'javascript:;'; + a.onclick = _filterEnchants.bind(a, 0, 1); + $WH.ae(a, $WH.ct(LANG.pr_note_items)); + + $WH.ae(sm, a); + $WH.ae(sm, $WH.ct(LANG.comma)); + + a = $WH.ce('a'); + a.href = 'javascript:;'; + a.onclick = _filterEnchants.bind(a, 0, 2); + $WH.ae(a, $WH.ct(LANG.pr_note_profs)); + + $WH.ae(sm, a); + $WH.ae(div, sm); + + sm = $WH.ce('small'); + var sp = $WH.ce('span'); + sp.style.padding = '0 8px'; + sp.style.color = 'white'; + $WH.ae(sp, $WH.ct('|')); + $WH.ae(sm, sp); + $WH.ae(sm, $WH.ct(LANG.su_note_stats + ': ')); + + a = $WH.ce('a'); + a.href = 'javascript:;'; + a.onclick = _filterEnchants.bind(a, 1, null); + $WH.ae(a, $WH.ct(LANG.pr_note_all)); + + g_setSelectedLink(a, 'enchants1'); + + $WH.ae(sm, a); + $WH.ae(sm, $WH.ct(LANG.comma)) + + a = $WH.ce('a'); + a.href = 'javascript:;'; + a.onclick = _filterEnchants.bind(a, 1, 'sta'); + $WH.ae(a, $WH.ct(LANG.traits.sta[0])); + $WH.ae(sm, a); + $WH.ae(sm, $WH.ct(LANG.comma)); + + a = $WH.ce('a'); + a.href = 'javascript:;'; + a.onclick = _filterEnchants.bind(a, 1, 'str') + $WH.ae(a, $WH.ct(LANG.traits.str[0])); + $WH.ae(sm, a); + $WH.ae(sm, $WH.ct(LANG.comma)); + + a = $WH.ce('a'); + a.href = 'javascript:;'; + a.onclick = _filterEnchants.bind(a, 1, 'agi'); + $WH.ae(a, $WH.ct(LANG.traits.agi[0])) + $WH.ae(sm, a); + $WH.ae(sm, $WH.ct(LANG.comma)); + + a = $WH.ce('a'); + a.href = 'javascript:;'; + a.onclick = _filterEnchants.bind(a, 1, 'int'); + $WH.ae(a, $WH.ct(LANG.traits['int'][0])); + $WH.ae(sm, a); + $WH.ae(sm, $WH.ct(LANG.comma)); + + a = $WH.ce('a'); + a.href = 'javascript:;'; + a.onclick = _filterEnchants.bind(a, 1, 'spi'); + $WH.ae(a, $WH.ct(LANG.traits['spi'][0])); + $WH.ae(sm, a); + $WH.ae(sm, $WH.ct(LANG.comma)); + + a = $WH.ce('a'); + a.href = 'javascript:;'; + a.onclick = _filterEnchants.bind(a, 1, -1); + $WH.ae(a, $WH.ct(LANG.su_note_other)); + + _enchantStat = null; + $WH.ae(sm, a); + $WH.ae(div, sm); + } + + function _hasSocketBonus(slotId) { + var + item = _getSlotItem(slotId), + nMatches = 0; + + if (!g_items[item[0]] || !g_items[item[0]].jsonequip.nsockets) { + return false; + } + + for (var j = 0; j < 3; ++j) { + if (item[j + 4] && g_gems[item[j + 4]]) { + if (_matchGemSocket(g_gems[item[j + 4]].colors, g_items[item[0]].jsonequip['socket' + (j + 1)])) { + ++nMatches; + } + } + } + + return (nMatches == g_items[item[0]].jsonequip.nsockets); + } + + function _matchGemSocket(gemColor, socketColor) { + for (var i = 1; i <= 32; i *= 2) { + if ((socketColor & i) && (gemColor & i)) { + return true; + } + } + + return false; + } + + function _isValidGem(gem) { + if (gem.none) { + return true; + } + + return ( + // Source + (_gemSource == null || gem.expansion == _gemSource) && + + // Color + ( + ((_currentColor != 1 && gem.colors != 1) && // Always match meta gems and sockets + _gemColor == null) || + _matchGemSocket(gem.colors, _currentColor) + ) + ); + } + + function _filterGems(wut, value) { + switch (wut) { + case 0: + _gemSource = value; + break; + case 1: + _gemColor = value; + break; + default: + return; + } + + if (this && this.nodeName == 'A') { + g_setSelectedLink(this, 'gems' + wut); + } + + _lvGems.updateFilters(true); + + return false; + } + + function _createGemsNote(div) { + var + sm = $WH.ce('small'), + a; + + $WH.ae(sm, $WH.ct(LANG.pr_note_source)); + + a = $WH.ce('a'); + a.href = 'javascript:;'; + a.onclick = _filterGems.bind(a, 0, null); + $WH.ae(a, $WH.ct(LANG.pr_note_all)); + + $WH.ae(sm, a); + $WH.ae(sm, $WH.ct(LANG.comma)); + + a = $WH.ce('a'); + a.href = 'javascript:;'; + a.onclick = _filterGems.bind(a, 0, 1); + $WH.ae(a, $WH.ct(LANG.pr_note_bc)); + + $WH.ae(sm, a); + $WH.ae(sm, $WH.ct(LANG.comma)); + + a = $WH.ce('a'); + a.href = 'javascript:;'; + a.onclick = _filterGems.bind(a, 0, 2); + $WH.ae(a, $WH.ct(LANG.pr_note_wotlk)); + + _gemSource = 2; + g_setSelectedLink(a, 'gems0'); + + $WH.ae(sm, a); + $WH.ae(div, sm); + + sm = $WH.ce('small'); + + var sp = $WH.ce('span'); + sp.style.padding = '0 8px'; + sp.style.color = 'white'; + $WH.ae(sp, $WH.ct('|')); + $WH.ae(sm, sp); + + $WH.ae(sm, $WH.ct(LANG.pr_note_color)); + + a = $WH.ce('a'); + a.href = 'javascript:;'; + a.onclick = _filterGems.bind(a, 1, null); + $WH.ae(a, $WH.ct(LANG.pr_note_all)); + + $WH.ae(sm, a); + $WH.ae(sm, $WH.ct(LANG.comma)); + + a = $WH.ce('a'); + a.href = 'javascript:;'; + a.onclick = _filterGems.bind(a, 1, 1); + $WH.ae(a, $WH.ct(LANG.pr_note_match)); + + _gemColor = 1; + g_setSelectedLink(a, 'gems1'); + + $WH.ae(sm, a); + $WH.ae(div, sm); + } + + function _calcScores(data, scale) { + for (var i = 0, len = data.length; i < len; ++i) { + var row = data[i]; + + row.__tr = null; + row.score = (scale ? 0 : null); + + if (row.jsonequip && scale) { + var + f = 0, + json = $WH.dO(row.jsonequip); + _parent.unfixJson(json); + + for (var w in scale) { + if (!LANG.traits[w]) { + continue; + } + + f += scale[w]; + if (!isNaN(json[w])) { + row.score += json[w] * scale[w]; + } + } + + row.score = (row.score / f).toFixed(2); + } + } + + return data; + } + + function _sortPickerWindow(lv, search) { + if (!_spSortWeighted) { + return; + } + + if ($('option:selected', _spSortWeighted)[0]) { + _currentScale = $('option:selected', _spSortWeighted)[0].scale; + } + + lv.setSort([1], true, false); + lv.setData(_calcScores(lv.data, _currentScale)); + + if (_currentScale) { + lv.setSort([2], true, false); + } + + if (search && lv.id == 'items') { + _onKeyUpSearch(0); + } + } + + function _openItemPicker(slotId) { + _currentSlot = _getValidSlot(slotId); + + Lightbox.show('itempicker', { onShow: _onShowItemPicker }); + } + + function _openSubitemPicker(slotId) { + _currentSlot = _getValidSlot(slotId); + + Lightbox.show('subitempicker', { onShow: _onShowSubitemPicker }); + } + + function _openEnchantPicker(slotId) { + _currentSlot = _getValidSlot(slotId); + + Lightbox.show('enchantpicker', { onShow: _onShowEnchantPicker }); + } + + function _openGemPicker(socketColor, socketId, slotId) { + _currentSlot = _getValidSlot(slotId); + _currentSocket = socketId; + _currentColor = socketColor; + + Lightbox.show('gempicker', { onShow: _onShowGemPicker }); + } + + function _onShowItemPicker(dest, first, opt) { + Lightbox.setSize(800, 564); + + var lv; + + if (first) { + dest.className = 'profiler-picker listview'; + + var + d = $WH.ce('div'), + a = $WH.ce('a'), + clear = $WH.ce('div'); + + d.className = 'listview'; + $WH.ae(dest, d); + + a = $WH.ce('a'); + a.className = 'screenshotviewer-close'; + a.href = 'javascript:;'; + a.onclick = Lightbox.hide; + $WH.ae(a, $WH.ce('span')); + $WH.ae(dest, a); + + clear.className = 'clear'; + $WH.ae(dest, clear); + + _lvItems = lv = new Listview({ + template: 'itempicker', + id: 'items', + parent: d, + data: [], + clip: { w: 780, h: 478 }, + createNote: _createItemsNote, + customFilter: _isValidItem + }); + + if ($WH.Browser.firefox) { + $WH.aE(lv.getClipDiv(), 'DOMMouseScroll', g_pickerWheel); + } + else { + lv.getClipDiv().onmousewheel = g_pickerWheel; + } + } + else { + lv = g_listviews.items; + } + + var + div = lv.getNoteTopDiv(), + sms = $WH.gE(div, 'small'); + + if (!$WH.array_index([0, 2, 4, 7, 8, 9, 10, 11, 16, 17, 18, 19], _currentSlot)) { // Not armor or weapons + sms[0].style.display = 'none'; // Hide 'Type' filter + } + else { + var + ss = $WH.gE(div, 'span'), + as = $WH.gE(div, 'a'); + + sms[0].style.display = ''; // Show 'Type' filter + + if (_currentSlot > 15) { // Weapons + ss[0].style.display = 'none'; + if (_itemType == 2) { + as[1].onclick(); + } + } + else { // Armor + var itemTypes = _proficiencies[_profile.classs][4]; + + ss[0].style.display = ''; + $WH.st(as[2], g_itemset_types[itemTypes[itemTypes.length - 1]]); // Set best armor type + } + } + + _updateWeightedSort(lv); + + setTimeout(function () { + _spSearchName.focus(); + }, 1); + } + + function _onShowSubitemPicker(dest, first, opt) { + Lightbox.setSize(800, 564); + + var + lv, + itemId = _getSlotItem(_currentSlot)[0], + dataz = []; + + for (var subitemId in g_items[itemId].jsonequip.subitems) { + var subitem = g_items[itemId].jsonequip.subitems[subitemId]; + + subitem.id = subitemId; + subitem.item = itemId; + + dataz.push(subitem); + } + + if (first) { + dest.className = 'profiler-picker listview'; + + var + d = $WH.ce('div'), + a = $WH.ce('a'), + clear = $WH.ce('div'); + + d.className = 'listview'; + $WH.ae(dest, d); + + a = $WH.ce('a'); + a.className = 'screenshotviewer-close'; + a.href = 'javascript:;'; + a.onclick = Lightbox.hide; + $WH.ae(a, $WH.ce('span')); + $WH.ae(dest, a); + + clear.className = 'clear'; + $WH.ae(dest, clear); + + _lvSubitems = lv = new Listview({ + template: 'subitempicker', + id: 'subitems', + parent: d, + data: dataz + }); + + if ($WH.Browser.firefox) { + $WH.aE(lv.getClipDiv(), 'DOMMouseScroll', g_pickerWheel); + } + else { + lv.getClipDiv().onmousewheel = g_pickerWheel; + } + } + else { + lv = g_listviews.subitems; + + lv.setData(dataz); + lv.clearSearch(); + lv.updateFilters(true); + } + + _updateWeightedSort(lv); + + setTimeout(function () { + lv.focusSearch(); + }, 1); + } + + function _onShowEnchantPicker(dest, first, opt) { + Lightbox.setSize(800, 564); + + var + lv, + dataz = []; + + dataz.push({ none: 1, __alwaysvisible: 1 }); + + for (var enchantId in g_enchants) { + var enchant = $WH.dO(g_enchants[enchantId]); + enchant.id = enchantId; + + if (typeof enchant.name == 'string') { + dataz.push(enchant); + } + else { + for (var i = 0, len = g_enchants[enchantId].name.length; i < len; ++i) { + var row = $WH.dO(enchant); + + row.name = enchant.name[i]; + row.source = enchant.source[i]; + row.slots = enchant.slots[i]; + + dataz.push(row); + } + } + } + + if (first) { + dest.className = 'profiler-picker listview'; + + var + d = $WH.ce('div'), + a = $WH.ce('a'), + clear = $WH.ce('div'); + + d.className = 'listview'; + $WH.ae(dest, d); + + a = $WH.ce('a'); + a.className = 'screenshotviewer-close'; + a.href = 'javascript:;'; + a.onclick = Lightbox.hide; + $WH.ae(a, $WH.ce('span')); + $WH.ae(dest, a); + + clear.className = 'clear'; + $WH.ae(dest, clear); + + _lvEnchants = lv = new Listview({ + template: 'enchantpicker', + id: 'enchants', + parent: d, + data: dataz, + createNote: _createEnchantsNote, + customFilter: _isValidEnchant + }); + + if ($WH.Browser.firefox) { + $WH.aE(lv.getClipDiv(), 'DOMMouseScroll', g_pickerWheel); + } + else { + lv.getClipDiv().onmousewheel = g_pickerWheel; + } + } + else { + lv = g_listviews.enchants; + + lv.setData(dataz); + lv.clearSearch(); + lv.updateFilters(true); + } + + _updateWeightedSort(lv); + + setTimeout(function () { + lv.focusSearch(); + }, 1); + } + + function _onShowGemPicker(dest, first, opt) { + Lightbox.setSize(800, 564); + + var lv; + + if (first) { + dest.className = 'profiler-picker listview'; + + var + dataz = [], + d = $WH.ce('div'), + a = $WH.ce('a'), + clear = $WH.ce('div'); + + dataz.push({ none: 1, __alwaysvisible: 1 }); + + for (var gemId in g_gems) { + var gem = g_gems[gemId]; + + gem.id = gemId; + + dataz.push(gem); + } + + d.className = 'listview'; + $WH.ae(dest, d); + + a = $WH.ce('a'); + a.className = 'screenshotviewer-close'; + a.href = 'javascript:;'; + a.onclick = Lightbox.hide; + $WH.ae(a, $WH.ce('span')); + $WH.ae(dest, a); + + clear.className = 'clear'; + $WH.ae(dest, clear); + + _lvGems = lv = new Listview({ + template: 'gempicker', + id: 'gems', + parent: d, + data: dataz, + createNote: _createGemsNote, + customFilter: _isValidGem + }); + + if ($WH.Browser.firefox) { + $WH.aE(lv.getClipDiv(), 'DOMMouseScroll', g_pickerWheel); + } + else { + lv.getClipDiv().onmousewheel = g_pickerWheel; + } + } + else { + lv = g_listviews.gems; + + lv.clearSearch(); + lv.updateFilters(true); + } + + var + div = lv.getNoteTopDiv(), + sms = $WH.gE(div, 'small'), + as = $WH.gE(div, 'a'); + + if (_currentColor == 1 || _currentColor == 14) { // Meta, Prismatic + sms[1].style.display = 'none'; // Hide 'Color' filter + } + else { + sms[1].style.display = ''; // Show 'Color' filter + } + + _updateWeightedSort(lv); + + setTimeout(function () { + lv.focusSearch(); + }, 1); + } +} + +function ProfilerCompletion(_parent) { + var + _self = this, + + _parentVars, + _profile, + _tabs, + + _dialog, + + _tabIndex, + + _who, + _when, + _data, + + _total, + _subtotal, + + _summary, + _validation, + + _category, + _subcategory, + _complete, + + _rawdata, + _loading, + _timer, + + _loaded, + _inited, + _updated, + _displayed, + + _container, + _imgLoading, + _divSource, + _divSummary, + _divPoints, + _divTotals, + _divTipQuests, + _divTabs, + _divSubcatgs, + _divListview, + _divExcluded, + + _tabsListview, + + _subcategories, + _listview, + _excluded, + + _mode, + _opt = {}, + + extraCols = [ + { + id: 'completed', + name: LANG.completed, + type: 'text', + width: '16%', + value: 'completed', + compute: function (row, td) { + var img = $WH.ce('img'); + img.src = (row.completed ? g_staticUrl + '/template/images/' + (!row._included() ? 'star' : 'tick') + '.png' : g_staticUrl + '/template/images/delete.gif'); + img.onmouseover = function (e) { + $WH.Tooltip.showAtCursor(e, LANG[(row.completed ? (row._included() ? 'pr_note_complete' : 'pr_tt_excldone') : 'pr_note_incomplete')], 0, 0, 'q'); + }; + img.onmousemove = $WH.Tooltip.cursorUpdate; + img.onmouseout = $WH.Tooltip.hide; + img.style.border = 'none'; + $WH.ae(td, img); + + if (row.completed && row.completed.getTime) { + $WH.ae(td, $WH.ct(' ' + g_formatDateSimple(row.completed))); + } + else if (_opt.showQuantity && row.completed) { + $WH.ae(td, $WH.ct(' ' + row.completed)); + } + }, + getVisibleText: function (row) { + var buff = LANG[(row.completed ? 'pr_note_complete' : 'pr_note_incomplete')]; + if (row.completed && row.completed.getTime) { + buff += ' ' + g_formatDateSimple(row.completed); + } + return buff; + }, + sortFunc: function (a, b, col) { + return ( + $WH.strcmp(a.completed, b.completed) || + $WH.strcmp(a._included(), b._included()) + ); + } + } + ]; + + this.initialize = function (container, tabIndex, opt) { + _container = $WH.ge(container); + if (!_container) { + return; + } + + _parentVars = _parent.getVars(); + _profile = _parentVars.profile; + _tabs = _parentVars.tabs; + _dialog = _parentVars.dialog; + + _tabIndex = tabIndex; + + if (!_tabs.tabs[_tabIndex]) { + return; + } + + _mode = _tabs.tabs[_tabIndex].id; + + $WH.cO(_opt, opt); + + _imgLoading = $WH.ce('img'); + _imgLoading.src = g_staticUrl + '/template/images/ui/misc/progress-anim.gif'; + _imgLoading.style.clear = 'both'; + _imgLoading.style.display = (_opt.onDemand ? 'block' : 'none'); + _imgLoading.style.margin = '0 auto'; + $WH.ae(_container, _imgLoading); + + _divTipQuests = $WH.ce('div'); + + if (!_opt.onDemand) { + _loaded = true; + } + else if (typeof _opt.onDemand != 'string') { + _opt.onDemand = _mode; + } + + if (!_opt.reqcatg) { + _opt.partial = false; + } + }; + + this.updateExclusions = function () { + _updateExclusions(); + }; + + this.isComplete = function (id) { + if (id) { + for (var i = 0, len = _data.length; i < len; ++i) { + var row = _data[i]; + if (row.id == id) { + return row.completed; + } + } + } + return false; + }; + + this.setData = function (data, who, when) { + _setData(data, who, when); + }; + + this.filterData = function (wut, value) { + if (!_timer) { + _timer = {}; + } + + if (_timer[wut] > 0) { + clearTimeout(_timer[wut]); + _timer[wut] = 0; + } + + if (!_data || _loading) { // Filter load on demand + return _timer[wut] = setTimeout(_self.filterData.bind(_self, wut, value), 750); + } + + var _ = 0; + + if (wut === 0) { // Simulate category click + var a = $WH.gE(_divTotals, 'a'); + + for (var i = 0, len = a.length; i < len; ++i) { + if (a[i].category == value) { + _ = a[i]; + break; + } + } + } + + (_filterData.bind(_, wut, value))(); + }; + + this.purgeData = function () { + if (_who.toLowerCase() != g_user.name.toLowerCase()) { + return; + } + + if (!confirm($WH.sprintf(LANG.confirm_purgedata, LANG['tab_' + _mode].toLowerCase()))) { + return; + } + + new Ajax('?profile=purge&id=' + _profile.source + '&data=' + _mode, { + method: 'POST', + onSuccess: function (xhr, opt) { + location.href = g_getProfileUrl({ + id: _profile.id, + region: _profile.region[0], + realm: _profile.realm[0], + name: _profile.name + }); + } + }); + }; + + this.onLoad = function (wut, catg) { + if (wut == _opt.onDemand) { + var a = _loading; + + _loading = null; + _imgLoading.style.display = 'none'; + _divTipQuests.style.display = (_mode == 'quests' ? '' : 'none'); + + _setData(_rawdata, _who, _when, 1); + + if (catg !== null) { + _loaded[catg] = 1; + _displayed = false; + _self.filterData(0, catg); + } + } + }; + + this.onShow = function () { + if (_tabs.tabs[_tabIndex].locked) { + return window.open('?client'); + } + + if (_opt.onDemand && !_loading && !_loaded) { + // $WH.g_ajaxIshRequest(g_host + '?data=' + _opt.onDemand + (_opt.dataArgs ? _opt.dataArgs(_profile) : '') + '&locale=' + Locale.getId() + '&t=' + g_dataKey + '&callback=$WowheadProfiler.loadOnDemand&' + (new Date().getTime())); + $WH.g_ajaxIshRequest(g_staticUrl + '?data=' + _opt.onDemand + (_opt.dataArgs ? _opt.dataArgs(_profile) : '') + '&t=' + g_dataKey + '&callback=$WowheadProfiler.loadOnDemand&' + (new Date().getTime())); + _imgLoading.style.display = 'block'; + _divTipQuests.style.display = 'none'; + _loading = this; + _loaded = {}; + } + + if (!_data || _loading) { + return; + } + + if (!_inited) { + _initSource(); + _initSummary(); + _initDataTabs(); + _initSubcategories(); + _initListview(); + _initExcluded(); + + _inited = true; + } + + if (!_updated) { + _category = null; + _subcategory = null; + _complete = (window[_opt.order] ? null : true); + _calcDataTotal(); + + _updateSource(); + _updateSummary(); + _updateDataTabs(); + _updateSubcategories(); + _updateExcluded(); + _updateListview(); + + _updated = true; + } + }; + + function _setData(data, who, when) { + _data = []; + _who = who; + _when = when; + _rawdata = data; + + var hasData = false; + + if (window[_opt.source] && !$WH[_opt.source]) { + $WH[_opt.source] = window[_opt.source]; + } + + for (var i in window[_opt.source]) { + var row = $WH.dO(window[_opt.source][i]); + row.id = parseInt(i); + + if (_opt.filter && !_opt.filter(row)) { + continue; + } + + if ((!_opt.compute || _opt.compute(row, data[i])) && data[i]) { + // row.completed = (data[i].getTime ? data[i] : (_opt.showQuantity ? data[i] : 1)); // sarjuuk: idk a way to generate a jScript-TimeObject in php (there probably isn't), but one is expected here + row.completed = (data[i] > 946681200 ? new Date(data[i] * 1000) : (_opt.showQuantity ? data[i] : 1)); // so we create a dateObject from data[i] if it is a unixtime past the 1.1.2000 - 0:00 (wich probably isn't used as a sensible int anyway) + hasData = true; + } + else { + row.completed = null; + } + + row.who = _profile.name; + row.faction = _profile.faction + 1; + row._included = _isIncludedData.bind(0, row, 1); + + if ( (!row.side || (row.side & (_profile.faction + 1))) && + (!row.reqclass || row.reqclass & 1 << _profile.classs - 1) && + (!row.reqrace || row.reqrace & 1 << _profile.race - 1) && + (!row.gender || row.gender & 1 << _profile.gender) && + (!row.wflags || !(row.wflags & 31)) && // Quest flags - 1 repeatable, 2 daily, 4 weekly, 8 seasonal, 16 skiplog + (!row.historical || (row.historical && row.completed)) && // Only show completed historical quests + (!_opt.models || (row.npcId && row.displayId && row.displayName))) { + _data.push(row); + } + } + + // Attempt to pre-filter data without source info + if (!hasData && _opt.onDemand) { + for (var i in data) { + if (typeof data[i] == 'object' && data[i].length) { + var row = {}; + row.id = parseInt(i); + + if (_opt.catgid) { + row[_opt.catgid] = data[i][1]; + } + if (_opt.subcat) { + row[_opt.subcat] = data[i][0]; + } + + if (_opt.filter && !_opt.filter(row)) { + continue; + } + } + + hasData = true; + break; + } + } + + _updated = false; + _displayed = false; + + if (!hasData) { + return; + } + + _tabs.setTabTooltip(_tabIndex); + _tabs.setTabPound(_tabIndex); + _tabs.unlock(_tabIndex); + + if (_tabs.getSelectedTab() == _tabIndex) { + _self.onShow(); + } + } + + function _calcDataTotal(subtotal) { + var + result = { + all: {}, + complete: {}, + incomplete: {}, + bonus: {}, + excluded: {} + }, + overall = (subtotal == null ? _opt.overall : subtotal), + + complete = _complete, + category = _category, + subcategory = _subcategory; + + _complete = null; + _category = (subtotal != null ? subtotal : null); + _subcategory = null; + _summary = true; + + result.all[overall] = 0; + result.complete[overall] = 0; + result.incomplete[overall] = 0; + result.bonus[overall] = 0; + result.excluded[overall] = 0; + + for (var i = 0, len = _data.length; i < len; ++i) { + var + row = _data[i], + catg = (subtotal == null ? _getTopCategory(row) : _getSubCategory(row)); + + if (catg == subtotal) { + catg = 'current'; + } + else if (catg == overall) { + continue; + } + + if (result.all[catg] == null) { + result.all[catg] = 0; + } + if (result.complete[catg] == null) { + result.complete[catg] = 0; + } + if (result.incomplete[catg] == null) { + result.incomplete[catg] = 0; + } + if (result.bonus[catg] == null) { + result.bonus[catg] = 0; + } + if (result.excluded[catg] == null) { + result.excluded[catg] = 0; + } + + if (_isValidData(row)) { + if (_isIncludedData(row)) { + if (!_isIncludedData(row, 1)) { + result.bonus[catg]++; + result.bonus[overall]++; + result.excluded[catg]++; + result.excluded[overall]++; + continue; + } + + if (!$WH.array_index(_opt.nototal, catg)) { + result.all[catg]++; + result.all[overall]++; + + if (row.completed) { + result.complete[overall]++; + } + else { + result.incomplete[overall]++; + } + } + else { + result.all[catg]++; + } + + if (row.completed != null) { + result.complete[catg]++; + } + else { + result.incomplete[catg]++; + } + } + else { + result.excluded[catg]++; + result.excluded[overall]++; + } + } + } + + if (_opt.noempty) { + for (var catg in result.complete) { + if (catg == overall) { + continue; + } + + if (!result.complete[catg] && !$WH.array_index(_opt.nototal, catg)) { + result.all[overall] -= result.all[catg]; + } + } + } + + _complete = complete; + _category = category; + _subcategory = subcategory; + _summary = false; + + if (subtotal != null) { + _subtotal[subtotal] = result; + } + else { + _total = result; + } + } + + function _initSource() { + _divSource = _ = $WH.ce('div'); + _.className = 'text profiler-achievements-source'; + $WH.ae(_container, _); + } + + function _updateSource() { + $WH.ee(_divSource); + + if (_who && _when.getDate) { + var + uploadedOn = new Date(_when), + elapsed = (g_serverTime - uploadedOn) / 1000, + s = $WH.ce('span'), + _ = $WH.ce('span'); + + $WH.ae(_, s); + g_formatDate(s, elapsed, uploadedOn); + _divSource.innerHTML = '' + $WH.sprintfa(LANG.pr_datasource, _who, _.innerHTML) + ''; + + if (_who.toLowerCase() == g_user.name.toLowerCase()) { + var a = $WH.ce('a'); + a.href = 'javascript:;'; + a.onclick = _self.purgeData; + a.className = 'delete-icon'; + a.style.marginLeft = '10px'; + g_addTooltip(a, LANG.pr_purgedata, 'q2'); + $WH.ae(a, $WH.ct(LANG.purge)); + $WH.ae(_divSource.firstChild, a); + } + + var a = $WH.ce('a'); + a.href = 'javascript:;'; + a.onclick = ContactTool.show.bind(ContactTool, { mode: 4, profile: _profile }); + a.className = 'report-icon'; + a.style.marginLeft = '10px'; + g_addTooltip(a, LANG.report_tooltip, 'q2'); + $WH.ae(a, $WH.ct(LANG.report)); + $WH.ae(_divSource.firstChild, a); + } + } + + function _initSummary() { + var + _, + __; + + _divSummary = _ = $WH.ce('div'); + _.className = 'profiler-achievements-summary'; + + if (_opt.points) { + _divPoints = __ = $WH.ce('div'); + __.className = 'profiler-achievements-summary-points'; + $WH.ae(_, __); + } + + _divTotals = __ = $WH.ce('div'); + __.className = 'profiler-achievements-summary-inner'; + $WH.ae(_, __); + + $WH.ae(_container, _); + $WH.ae(_container, _imgLoading); + + __ = _divTipQuests; + __.className = 'text clear'; + __.innerHTML = LANG.pr_tip_quests; + __.style.display = (_mode == 'quests' && _loaded ? '' : 'none'); + + _ = $WH.gE(__, 'span')[0]; + _.onmouseover = function () { + $WH.Tooltip.show(this, LANG.pr_tt_questtip, 0, 0, 'q'); + }; + _.onmousemove = $WH.Tooltip.cursorUpdate; + _.onmouseout = $WH.Tooltip.hide; + + _ = $WH.ce('div'); + _.className = 'pad'; + + $WH.ae(__, _); + $WH.ae(_container, __); + } + + function _updateSummary() { + var _; + + if (_opt.points) { + $WH.ee(_divPoints); + Listview.funcBox.appendMoney(_divPoints, 0, null, 0, 0, _profile.achievementpoints); + $WH.ae(_divPoints.firstChild, $WH.ct(' / ' + $WH.number_format(g_achievement_points[0]))); + } + + $WH.ee(_divTotals); + + $WH.ae(_divTotals, _createCategoryLink(_opt.overall, 0)); // Overall Progress + + if (window[_opt.order]) { + var j = 1; + for (var i = 0, len = window[_opt.order].length; i < len; ++i) { + if (!_total.all[window[_opt.order][i]] && !_total.excluded[window[_opt.order][i]]) { + continue; + } + + if (_opt.noempty && !(_total.complete[window[_opt.order][i]] || _total.excluded[window[_opt.order][i]])) { + continue; + } + + $WH.ae(_divTotals, _createCategoryLink(window[_opt.order][i], j)); + ++j; + } + } + + _ = $WH.ce('div'); + _.className = 'clear'; + $WH.ae(_divTotals, _); + } + + function _createCategoryLink(category, idx) { + var + a = $WH.ce('a'), + v = $WH.ce('var'), + em = $WH.ce('em'); + + if (idx > 0) { + a.className = (idx % 3 != 0 ? 'profiler-achievements-total' : 'profiler-achievements-total-right'); + } + + a.category = category; + a.onclick = _filterData.bind(a, 0, (category != _opt.overall ? category : null)); + + if (idx == 0) { + $WH.ae(em, $WH.ct(LANG.pr_ach_overall)); + } + else { + $WH.ae(em, $WH.ct(window[_opt.catgs][category])); + } + + $WH.ae(v, em); + $WH.ae(v, g_createAchievementBar(_total.complete[category], (!$WH.array_index(_opt.nototal, category) ? _total.all[category] : -1), (category == _opt.overall), _total.bonus[category])); + + $WH.ae(a, v); + + if (category == _category || (idx == 0 && _category == null)) { + g_setSelectedLink(a, _mode + '0'); + } + + return a; + } + + function _initDataTabs() { + _divTabs = $WH.ce('div'); + _divTabs.className = 'clear'; + $WH.ae(_container, _divTabs); + + _tabsListview = new Tabs({ parent: _divTabs, onShow: _onShowDataTab }); + _tabsListview.add(LANG.pr_note_subcategories, { id: _mode }); + _tabsListview.add(LANG.pr_note_all, { id: _mode }); + _tabsListview.add(LANG.pr_note_complete, { id: _mode }); + _tabsListview.add(LANG.pr_note_incomplete, { id: _mode }); + _tabsListview.add(LANG.pr_note_excluded, { id: _mode }); + _tabsListview.flush(); + } + + function _updateDataTabs() { + var catg = (_category === null ? _opt.overall : _category); + + _divTabs.style.display = (_category !== null || !_opt.reqcatg ? '' : 'none'); + _tabsListview.setTabName(1, LANG.pr_note_all + ' (' + _total.all[catg] + ')'); + _tabsListview.setTabName(2, LANG.pr_note_complete + ' (' + _total.complete[catg] + (_total.bonus[catg] ? '+' + _total.bonus[catg] : '') + ')'); + _tabsListview.setTabName(3, LANG.pr_note_incomplete + ' (' + _total.incomplete[catg] + ')'); + _tabsListview.setTabName(4, LANG.pr_note_excluded + ' (' + _total.excluded[catg] + ')'); + } + + function _onShowDataTab(newTab, oldTab) { + if (!_inited) { + return; + } + + if (_loading) { + _divSubcatgs.style.display = 'none'; + _divListview.style.display = 'none'; + _divExcluded.style.display = 'none'; + } + else { + _validation = false; + switch (newTab.index) { + case 0: // Subcategory + _divSubcatgs.style.display = ''; + _divListview.style.display = 'none'; + _divExcluded.style.display = 'none'; + break; + case 1: // All + _filterData(1, null); + _divSubcatgs.style.display = 'none'; + _divListview.style.display = ''; + break; + case 2: // Complete + _filterData(1, true); + _divSubcatgs.style.display = 'none'; + _divListview.style.display = ''; + _divExcluded.style.display = 'none'; + break; + case 3: // Incomplete + _filterData(1, false); + _divSubcatgs.style.display = 'none'; + _divListview.style.display = ''; + _divExcluded.style.display = 'none'; + break; + case 4: // Excluded + _validation = true; + _updateExcluded(); + _divSubcatgs.style.display = 'none'; + _divListview.style.display = 'none'; + _divExcluded.style.display = ''; + break; + } + } + } + + function _initSubcategories() { + _divSubcatgs = $WH.ce('div'); + _divSubcatgs.className = 'listview'; + + _subcategories = new Listview({ + template: 'completion', + id: _mode + '-subcatgs', + parent: _divSubcatgs, + onNoData: _onNoData, + onClickRow: _filterData + }); + + $WH.ae(_container, _divSubcatgs); + } + + function _updateSubcategories(fixed) { + _filterData(2, null); + + if (_subtotal == null) { + _subtotal = {}; + } + + var hasData = false; + + var dataz = []; + if (_category !== null && _opt.subname) { + if (_subtotal[_category] == null) { + _calcDataTotal(_category); + } + + for (var i in _subtotal[_category].all) { + // Hide same-category children + if (i == _category) { + continue; + } + + // Hide empty subcategories + if (!_subtotal[_category].all[i] && !_subtotal[_category].excluded[i]) { + continue; + } + + if (i !== 'current') { + hasData = true; + } + + dataz.push({ + id: i, + name: (i == 'current' ? _opt.subname(_category) : _opt.subname(i)), + current: (i == 'current'), + total: _subtotal[_category].all[i], + complete: _subtotal[_category].complete[i] + }); + } + } + + _subcategories.setData(dataz); + + if (!fixed) { + _tabsListview.hide(0, hasData); + _tabsListview.show((hasData ? 0 : 2), 1); + } + } + + function _initListview() { + _divListview = $WH.ce('div'); + _divListview.className = 'listview'; + _divListview.style.display = 'none'; + + var + sort = null, + hiddenCols = ['side', 'location', 'rewards', 'reagents'], + visibleCols = ['category', 'standing', 'source']; + + switch (_mode) { + case 'achievements': + sort = [ -6]; + break; + case 'recipes': + sort = [ -7]; + break; + case 'quests': + hiddenCols.shift(); + break; + } + + if (_opt.visibleCols) { + for (var i = 0, len = _opt.visibleCols.length; i < len; ++i) { + visibleCols.push(_opt.visibleCols[i]); + } + } + + if (_opt.hiddenCols) { + for (var i = 0, len = _opt.hiddenCols.length; i < len; ++i) { + hiddenCols.push(_opt.hiddenCols[i]); + } + } + + _listview = new Listview({ + template: _opt.template, + id: _mode + '-includes', + parent: _divListview, + visibleCols: visibleCols, + hiddenCols: hiddenCols, + extraCols: extraCols, + sort: sort, + customFilter: _isValidData, + onBeforeCreate: _onBeforeCreate, + onNoData: _onNoData, + onEmptyFilter: _onEmptyFilter + }); + + $WH.ae(_container, _divListview); + } + + function _updateListview() { + if (_opt.reqcatg && _category === null) { + return; + } + + _listview.setData($WH.array_filter(_data, function (x) { + return _isIncludedData(x); + })); + _listview.updateFilters(true); + + _displayed = true; + } + + function _initExcluded() { + _divExcluded = $WH.ce('div'); + _divExcluded.className = 'listview'; + _divExcluded.style.display = 'none'; + + var + sort = null, + hiddenCols = ['side', 'location', 'rewards', 'reagents']; + + switch (_mode) { + case 'achievements': + sort = [ -6]; + break; + case 'recipes': + sort = [ -7]; + break; + case 'quests': + hiddenCols.shift(); + break; + } + + _excluded = new Listview({ + template: _opt.template, + id: _mode + '-excludes', + parent: _divExcluded, + visibleCols: ['category', 'standing', 'source'], + hiddenCols: hiddenCols, + extraCols: extraCols, + sort: sort, + customFilter: _isValidData, + onBeforeCreate: _onBeforeCreate, + include: 1, + onNoData: _onNoData, + onEmptyFilter: _onEmptyFilter + }); + + $WH.ae(_container, _divExcluded); + } + + function _updateExcluded() { + if (_opt.reqcatg && _category === null) { + return; + } + + _excluded.setData($WH.array_filter(_data, function (x) { + return ! _isIncludedData(x) || !_isIncludedData(x, 1); + })); + + _excluded.updateFilters(); + _excluded.refreshRows(); + } + + function _onNoData(div) { + // Its filtered! + if ((! (_opt.reqcatg && _category == null) && this.filtered) || (!this.include && (_category !== null || _subcategory !== null))) { + return -1; + } + + if (this.quickSearchBox.value != '') { + $WH.ae(div, $WH.ct(LANG.lvnodata2)); + return; + } + + this.bandTop.style.display = this.bandBot.style.display = this.mainContainer.style.display = (_category !== null || _subcategory !== null ? '' : 'none'); + $WH.ae(div, $WH.ct(this.include ? LANG.lvnodata4 : LANG.lvnodata3)); + } + + function _onEmptyFilter(col) { + if (col.id == 'category') { + this.removeIndicators(); + } + } + + function _onBeforeCreate() { + if (!g_user) { + g_user = {}; + } + if (!g_user.excludes) { + g_user.excludes = {}; + } + if (!g_user.includes) { + g_user.includes = {}; + } + if (!g_user.excludes[_opt.typeid]) { + g_user.excludes[_opt.typeid] = []; + } + if (!g_user.includes[_opt.typeid]) { + g_user.includes[_opt.typeid] = []; + } + + this.poundable = 0; + this.createCbControls = function (d, topBar) { + var f = function (mode) { + var rows = this.getCheckedRows(); + + if (!rows.length) { + alert($WH.sprintf(LANG.message_norowselected, mode)); + } + else { + var ids = []; + $WH.array_walk(rows, function (x) { + g_user.includes[_opt.typeid] = $WH.array_filter(g_user.includes[_opt.typeid], function (z) { + return z != x.id; + }); + g_user.excludes[_opt.typeid] = $WH.array_filter(g_user.excludes[_opt.typeid], function (z) { + return z != x.id; + }); + g_user[mode + 's'][_opt.typeid].push(x.id); + x.__tr = null; // Force row to recompute + ids.push(x.id); + }); + + if (ids.length) { + $.post('?account=exclude', { + type: _opt.typeid, + id: ids.join(','), + mode: 1 + }); + _updateExclusions(); + } + } + }; + + var + iSelectAll = $WH.ce('input'), + iDeselect = $WH.ce('input'), + iExclude = $WH.ce('input'), + iInclude = $WH.ce('input'), + iManage = $WH.ce('input'); + + iSelectAll.type = iDeselect.type = iExclude.type = iInclude.type = iManage.type = 'button'; + + iSelectAll.value = LANG.button_selectall; + iDeselect.value = LANG.button_deselect; + iExclude.value = LANG.button_exclude; + iInclude.value = LANG.button_include; + iManage.value = LANG.button_quickexclude; + + iSelectAll.onclick = Listview.cbSelect.bind(this, true); + iDeselect.onclick = Listview.cbSelect.bind(this, false); + iExclude.onclick = f.bind(this, 'exclude'); + iInclude.onclick = f.bind(this, 'include'); + iManage.onclick = _dialog.show.bind(null, 'quickexclude', { data: { empty: _isEmptyExcludeGroup }, onSubmit: _updateExcludeGroups }); + + iExclude.onmouseover = function (e) { + $WH.Tooltip.showAtCursor(e, LANG.pr_tt_exclude); + }; + iInclude.onmouseover = function (e) { + $WH.Tooltip.showAtCursor(e, LANG.pr_tt_include); + }; + + iExclude.onmousemove = iInclude.onmousemove = $WH.Tooltip.cursorUpdate; + iExclude.onmouseout = iInclude.onmouseout = $WH.Tooltip.hide; + + iExclude.style.display = (this.include ? 'none' : ''); + iInclude.style.display = (this.include ? '' : 'none'); + + $WH.ae(d, iSelectAll); + $WH.ae(d, iExclude); + $WH.ae(d, iInclude); + $WH.ae(d, iDeselect); + $WH.ae(d, $WH.ct('| ')); + + $WH.ae(d, iManage); + }; + + if (!_opt.models) { + this.mode = 1; + } + } + + function _isEmptyExcludeGroup(mask) { + if (mask == null) { + var empty = true; + + for (var i in g_excludes[_opt.typeid]) { + empty = (empty && _isEmptyExcludeGroup(1 << i - 1)); + } + + return empty; + } + + for (var i in g_excludes[_opt.typeid]) { + if (!(mask & 1 << i - 1)) { + continue; + } + + for (var j = 0, len = _data.length; j < len; ++j) { + if ($WH.array_index(g_excludes[_opt.typeid][i], _data[j].id)) { + return false; + } + } + } + + return true; + } + + function _updateExcludeGroups(groups) { + var g = (g_user.settings ? g_user.excludegroups | 0 : 1); + + for (var i in groups) { + if (isNaN(i)) { + continue; + } + + var action = groups[i] = parseInt(groups[i]); + + if (action == 1 && (g & i)) { // Include + g -= parseInt(i); + } + if (action == 2 && !(g & i)) { // Exclude + g += parseInt(i); + } + } + + g_user.excludegroups = g; + + $.post('?account=exclude', { groups: g }); + _updateExclusions(); + } + + function _updateExclusions() { + if (!_updated || !_displayed) { + return; + } + + _subtotal = null; + + _calcDataTotal(); + + _updateSummary(); + _updateDataTabs(); + _updateSubcategories(1); + _updateExcluded(); + _updateListview(); + } + + function _isIncludedData(row, strict) { + // Include complete stuff + if (!strict && row.completed) { + return true; + } + + // Nothing is excluded + if (!g_excludes[_opt.typeid] && (!g_user.excludes || !g_user.excludes[_opt.typeid])) { + return true; + } + + // Explicitly included + if (g_user.includes && g_user.includes[_opt.typeid] && $WH.array_index(g_user.includes[_opt.typeid], row.id)) { + return true; + } + + // Explicitly excluded + if (g_user.excludes && g_user.excludes[_opt.typeid] && $WH.array_index(g_user.excludes[_opt.typeid], row.id)) { + return false; + } + + var mask = (g_user.settings ? g_user.excludegroups | 0 : 1); + + for (var i in g_excludes[_opt.typeid]) { + if (!$WH.array_index(g_excludes[_opt.typeid][i], row.id)) { + continue; + } + + if (! (mask & 1 << i - 1)) { + continue; + } + + if (i < 6 || i > 10) { + return false; + } + if (i == 6 && !((_profile.faction + 1) & 1)) { // Alliance favored + return false; + } + if (i == 7 && !((_profile.faction + 1) & 2)) { // Horde favored + return false; + } + if (i == 8 && !_profile.skills[356]) { // Fishing bop disabled + continue; + } + if (i == 9 && !_profile.skills[202]) { // Engineer bop + return false; + } + if (i == 10 && !_profile.skills[197]) { // Tailor bop + return false; + } + } + + return true; + } + + function _getTopCategory(row) { + var id = row[_opt.catgid]; + if (typeof id == 'object' && id.length) { + id = id[0]; + } + return id; + } + + function _getSubCategory(row) { + var id = row[_opt.subcat]; + if (typeof id == 'object' && id.length) { + id = id[0]; + } + return ($WH.array_index(_opt.nosubcatg, _getTopCategory(row)) ? _getTopCategory(row) : id); + } + + function _isValidData(row) { + if (!row.id || (_category === null && _opt.reqcatg && !_summary)) { + return; + } + + return ( + // Included + (_validation || _summary || _isIncludedData(row, !_complete)) && + + // Category + ((_category === null && (!$WH.array_index(_opt.nototal, _getTopCategory(row)) || _summary)) || _category == _getTopCategory(row)) && + + // Subcategory + (!_summary || (_subcategory === null || _subcategory == _getSubCategory(row))) && + + // Complete + ( + _validation || + _complete == null || + ( _complete && row.completed) || + (!_complete && row.completed == null) + ) + ); + } + + function _filterData(wut, value) { + switch (wut) { + case 0: + var _ = _category; + _category = value; + + if (_category !== null) { + if (_opt.onDemand && _opt.partial && !_loaded[_category] && !_loading) { + // $WH.g_ajaxIshRequest(g_host + '/data=' + _opt.onDemand + '&locale=' + Locale.getId() + '&catg=' + _category + '&t=' + g_dataKey + '&callback=$WowheadProfiler.loadOnDemand&' + (new Date().getTime())); + $WH.g_ajaxIshRequest(g_staticUrl + '?data=' + _opt.onDemand + '&catg=' + _category + '&t=' + g_dataKey + '&callback=$WowheadProfiler.loadOnDemand&' + (new Date().getTime())); + _imgLoading.style.display = 'block'; + _divTipQuests.style.display = 'none'; + _loading = this; + _category = null; + } + else if (!_displayed) { + _updateListview(); + _updateExcluded(); + } + } + + _listview.resetFilters(); + _listview.clearSearch(); + _listview.quickSearchBox.onblur(); + break; + case 1: + _complete = value; + + var btns = $WH.gE(_listview.cbBarTop, 'input'); + for (var i = 0, len = btns.length; i < len; ++i) { + if (btns[i].value == LANG.button_include) { + btns[i].style.display = (_complete === false ? 'none' : ''); + break; + } + } + break; + case 2: + _subcategory = (value == 'current' ? _category : value); + _listview.removeIndicators(); + _excluded.removeIndicators(); + break; + default: + return; + } + + _listview.updateFilters(true); + _excluded.updateFilters(true); + + if (this && this.nodeName == 'A') { + g_setSelectedLink(this, _mode + wut); + } + + if (wut == 0) { // Category change + _updateSubcategories(); + _updateDataTabs(); + } + + if (wut == 2) { // Subcategory change + if (!_subcategory && this && this.nodeName == 'TR') { + this.className = ''; + } + + _updateDataTabs(); + + if (_subcategory) { + if (_subtotal[_category] == null) { + _calcDataTotal(_category); + } + + _tabsListview.show((_subtotal[_category].complete[_subcategory] ? 2 : 3)); + + if (_opt.subname) { + _listview.createIndicator($WH.sprintf(LANG['lvnote_' + _mode + 'ind'], _category, _subcategory, _opt.subname(_subcategory)), Listview.headerFilter.bind(_listview, _listview.columns[_listview.columns.length - 2], '')); + _excluded.createIndicator($WH.sprintf(LANG['lvnote_' + _mode + 'ind'], _category, _subcategory, _opt.subname(_subcategory)), Listview.headerFilter.bind(_excluded, _listview.columns[_listview.columns.length - 2], '')); + setTimeout(Listview.headerFilter.bind(_listview, _listview.columns[_listview.columns.length - 2], _opt.subname(_subcategory)), 1); + setTimeout(Listview.headerFilter.bind(_excluded, _excluded.columns[_excluded.columns.length - 2], _opt.subname(_subcategory)), 1); + } + } + } + + return false; + } +} + +Listview.templates.inventory = { + searchable: 1, + filtrable: 1, + + createNote: function (div) { + var + sp = $WH.ce('span'); + + sp.style.color = 'red'; + sp.style.fontWeight = 'bold'; + + $WH.st(sp, String.fromCharCode(160)); + + $WH.ae(div, sp); + }, + + columns: [ + { + id: 'name', + name: LANG.name, + type: 'text', + align: 'left', + span: 2, + value: 'name', + compute: function (item, td, tr) { + var + iconTd = $WH.ce('td'), + icon = g_items.createIcon(item.id, 0, null, 'javascript:;'), + a = Icon.getLink(icon); + + a.oncontextmenu = $WH.rf; + a.onclick = ($WH.Browser.opera || $WH.OS.mac ? function (e) { + e = $WH.$E(e); + if (e.shiftKey || e.ctrlKey) { + return false; + } + } : null); + a.onmouseup = $WowheadProfiler.onMouseUpSlot.bind(0, item.profileslot, a); + a.href = '?item=' + item.id; + + icon.className += ' iconsmall-q' + (7 - parseInt(item.name.charAt(0)));// Don't use _getItemHilite because it is confusing + + $WowheadProfiler.updateMenu(item.profileslot, a); + + iconTd.style.width = '1px'; + iconTd.style.padding = '0'; + iconTd.style.borderRight = 'none'; + + $WH.ae(iconTd, icon); + $WH.ae(tr, iconTd); + + td.style.borderLeft = 'none'; + + a = $WH.ce('a'); + a.oncontextmenu = $WH.rf; + a.onclick = ($WH.Browser.opera || $WH.OS.mac ? function(e) { + e = $WH.$E(e); + if (e.shiftKey || e.ctrlKey) { + return false; + } + } : null); + a.onmouseup = $WowheadProfiler.onMouseUpSlot.bind(0, item.profileslot, a); + a.className = 'q' + (7 - parseInt(item.name.charAt(0))); + a.style.fontFamily = 'Verdana, sans-serif'; + a.href = '?item=' + item.id; + + $WowheadProfiler.updateMenu(item.profileslot, a); + + if (item.rel) { + Icon.getLink(icon).rel = item.rel; + a.rel = item.rel; + } + + $WH.ae(a, $WH.ct(item.name.substring(1))); + + $WH.ae(td, a); + }, + getVisibleText: function (item) { + return item.name.substring(1); + } + }, + { + id: 'level', + name: LANG.level, + value: 'level', + compute: function (item, td, tr) { + if (item.errors['level']) { + td.style.color = 'red'; + td.style.fontWeight = 'bold'; + } + + return item.level; + } + }, + { + id: 'slot', + name: LANG.slot, + type: 'text', + compute: function (item, td) { + $WH.nw(td); + + return g_item_slots[item.slot]; + }, + getVisibleText: function (item) { + return g_item_slots[item.slot]; + }, + sortFunc: function (a, b, col) { + return $WH.strcmp(g_item_slots[a.slot], g_item_slots[b.slot]); + } + }, + { + id: 'source', + name: LANG.source, + type: 'text', + compute: function (item, td) { + td.className = 'small'; + + if (item.source != null) { + if (item.source.length == 1) { + $WH.nw(td); + + var sm = (item.sourcemore ? item.sourcemore[0] : {}); + var type = 0; + + if (sm.t) { + type = sm.t; + + var a = $WH.ce('a'); + if (sm.q != null) { + a.className = 'q' + sm.q; + } + else { + a.className = 'q1'; + } + + if (sm.t == 5) { + a.className += ' icontinyl'; + a.style.backgroundImage = 'url(' + g_staticUrl + '/images/icons/quest_start.gif)'; + } + + a.href = '?' + g_types[sm.t] + '=' + sm.ti; + + $WH.ae(a, $WH.ct(sm.n)); + $WH.ae(td, a); + } + else if (sm.z) { + if (item.source[0] == 5) { + $WH.ae(td, $WH.ct(LANG.pr_vendorsin)); + } + + var a = $WH.ce('a'); + a.className = 'q1'; + a.href = '?zone=' + sm.z; + $WH.ae(a, $WH.ct(g_zones[sm.z])); + $WH.ae(td, a); + } + else { + $WH.ae(td, $WH.ct(Listview.funcBox.getUpperSource(item.source[0], sm))); + } + + if (sm.dd) { + if (sm.dd < 0) { // Dungeon + $WH.ae(td, $WH.ct($WH.sprintf(LANG.lvitem_dd, '', (sm.dd < -1 ? LANG.lvitem_heroic : LANG.lvitem_normal)))); + } + else { // 10 or 25 Player Raid + $WH.ae(td, $WH.ct($WH.sprintf(LANG.lvitem_dd, (sm.dd & 1 ? LANG.lvitem_raid10 : LANG.lvitem_raid25), (sm.dd > 2 ? LANG.lvitem_heroic : LANG.lvitem_normal)))); + } + } + } + else { + var buff = ''; + for (var i = 0, len = item.source.length; i < len; ++i) { + if (i > 0) { + buff += LANG.comma; + } + buff += g_sources[item.source[i]]; + } + return buff; + } + } + }, + getVisibleText: function (item) { + if (item.source != null) { + if (item.source.length == 1) { + var buff = ''; + + var sm = (item.sourcemore ? item.sourcemore[0] : {}); + var type = 0; + + if (sm.t) { + type = sm.t; + buff += ' ' + sm.n; + } + else { + buff += ' ' + Listview.funcBox.getUpperSource(item.source[0], sm); + } + + ls = Listview.funcBox.getLowerSource(item.source[0], sm, type); + + if (ls != null) { + if (ls.pretext) { + buff += ' ' + ls.pretext; + } + + buff += ' ' + ls.text; + + if (ls.posttext) { + buff += ' ' + ls.posttext; + } + } + + return buff; + } + else { + return Listview.funcBox.arrayText(item.source, g_sources); + } + } + }, + sortFunc: function (a, b, col) { + var res = Listview.funcBox.assocArrCmp(a.source, b.source, g_sources); + + if (res != 0) { + return res; + } + + var + na = (a.sourcemore && a.source.length == 1 ? a.sourcemore[0].n : null), + nb = (b.sourcemore && b.source.length == 1 ? b.sourcemore[0].n : null); + + return $WH.strcmp(na, nb); + } + } + ], + + getItemLink: function (item) { + return '?item=' + item.id; + } +}; + +Listview.templates.completion = { + sort: [1], + nItemsPerPage: -1, + searchable: 1, + poundable: 0, + + createNote: function (div) { + var sm = $WH.ce('small'); + $WH.st(sm, LANG.lvnote_clicksubcatg); + $WH.ae(div, sm); + }, + + columns: [ + { + id: 'name', + name: LANG.name, + type: 'text', + align: 'left', + value: 'name', + compute: function (row, td, tr) { + var img = $WH.ce('img'); + img.style.margin = '0 6px -3px 0'; + img.src = (row.complete == row.total ? g_staticUrl + '/template/images/tick.png' : g_staticUrl + '/template/images/delete.gif'); + img.onmouseover = function (e) { + $WH.Tooltip.showAtCursor(e, LANG[(row.complete == row.total ? 'pr_note_complete' : 'pr_note_incomplete')], 0, 0, 'q'); + }; + img.onmousemove = $WH.Tooltip.cursorUpdate; + img.onmouseout = $WH.Tooltip.hide; + img.style.border = 'none'; + $WH.ae(td, img); + + if (row.current) { + var b = $WH.ce('b'); + $WH.st(b, row.name); + $WH.ae(td, b); + } + else { + $WH.ae(td, $WH.ct(row.name)); + } + }, + sortFunc: function (a, b, col) { + return -$WH.strcmp(a.current, b.current) || $WH.strcmp(a.name, b.name); + } + }, + { + id: 'progress', + name: LANG.progress, + width: '250px', + compute: function (row, td, tr) { + td.style.padding = 0; + $WH.ae(td, g_createAchievementBar(row.complete, row.total)); + tr.onclick = this.onClickRow.bind(tr, 2, row.id); + }, + sortFunc: function (a, b, col) { + var pctA = Math.floor((a.complete / a.total) * 1000); + var pctB = Math.floor((b.complete / b.total) * 1000); + + if (pctA == pctB) { + return a.total - b.total; + } + return pctA - pctB; + } + } + ] +}; + +Listview.templates.gallery = { + sort: [1], + mode: 3, // Grid mode + nItemsPerPage: -1, + nItemsPerRow: 8, + searchable: 1, + poundable: 2, // Yes but w/o sort + + columns: [{ value: 'displayName' }], + + compute: function (spell, td, i) { + td.className = 'screenshot-cell'; + td.vAlign = 'top'; + + Listview.funcBox.ssCreateCb(td, spell); + + var a = $WH.ce('a'); + a.href = 'javascript:;'; + a.onclick = this.template.modelShow.bind(this.template, spell.npcId, spell.displayId, false); + a.style.position = 'relative'; + + var img = $WH.ce('img'); + img.src = (spell.completed ? g_staticUrl + '/template/images/' + (!spell._included() ? 'star' : 'tick') + '.png' : g_staticUrl + '/template/images/delete.gif'); + img.onmouseover = function (e) { + $WH.Tooltip.showAtCursor(e, LANG[(spell.completed ? (spell._included() ? 'pr_note_complete' : 'pr_tt_excldone') : 'pr_note_incomplete')], 0, 0, 'q'); + }; + img.onmousemove = $WH.Tooltip.cursorUpdate; + img.onmouseout = $WH.Tooltip.hide; + img.style.border = 'none'; + img.style.position = 'absolute'; + img.style.right = '6px'; + img.style.bottom = '9px'; + $WH.ae(a, img); + + img = $WH.ce('img'); + img.src = g_staticUrl + '/modelviewer/thumbs/npc/' + spell.displayId + '.png'; + img.height = img.width = 75; + $WH.ae(a, img); + + $WH.ae(td, a); + + d = $WH.ce('div'); + d.className = 'screenshot-cell-user'; + + a = $WH.ce('a'); + a.href = '?spell=' + spell.id; + $WH.ae(a, $WH.ct(spell.displayName)); + $WH.ae(d, a); + + $WH.ae(td, d); + + var item = spell.item; + + if (item && item.source) { + d = $WH.ce('div'); + d.style.position = 'relative'; + d.style.height = '1em'; + + var d2 = $WH.ce('div'); + d2.className = 'screenshot-caption'; + + var s = $WH.ce('small'); + + if (item.source.length == 1) { + var sm = (item.sourcemore ? item.sourcemore[0] : {}); + var type = 0; + + if (sm.t) { + type = sm.t; + + var a = $WH.ce('a'); + if (sm.q != null) { + a.className = 'q' + sm.q; + } + else { + a.className = 'q1'; + } + + if (sm.t == 5) { + a.className += ' icontinyl'; + a.style.backgroundImage = 'url(' + g_staticUrl + '/images/icons/quest_start.gif)'; + } + + a.href = '?' + g_types[sm.t] + '=' + sm.ti; + + $WH.ae(a, $WH.ct(sm.n)); + $WH.ae(s, a); + } + else if (sm.z) { + if (item.source[0] == 5) { + $WH.ae(s, $WH.ct(LANG.pr_vendorsin)); + } + + var a = $WH.ce('a'); + a.className = 'q1'; + a.href = '?zone=' + sm.z; + $WH.ae(a, $WH.ct(g_zones[sm.z])); + $WH.ae(s, a); + } + else { + $WH.ae(s, $WH.ct(Listview.funcBox.getUpperSource(item.source[0], sm))); + } + + if (sm.dd) { + if (sm.dd < 0) { // Dungeon + $WH.ae(s, $WH.ct($WH.sprintf(LANG.lvitem_dd, '', (sm.dd < -1 ? LANG.lvitem_heroic : LANG.lvitem_normal)))); + } + else { // 10 or 25 Player Raid + $WH.ae(s, $WH.ct($WH.sprintf(LANG.lvitem_dd, (sm.dd & 1 ? LANG.lvitem_raid10 : LANG.lvitem_raid25), (sm.dd > 2 ? LANG.lvitem_heroic : LANG.lvitem_normal)))); + } + } + } + else { + for (var i = 0, len = item.source.length; i < len; ++i) { + if (i > 0) { + $WH.ae(s, $WH.ct(LANG.comma)); + } + + $WH.ae(s, $WH.ct(g_sources[item.source[i]])); + } + } + + $WH.ae(s, $WH.ce('br')); + $WH.ae(d2, s); + $WH.ae(d, d2); + $WH.ae(td, d); + } + + $WH.aE(td, 'click', this.template.modelShow.bind(this.template, spell.npcId, spell.displayId, true)); + }, + + getVisibleText: function (spell) { + var buff = spell.displayName; + + var item = spell.item; + + if (item && item.source != null) { + if (item.source.length == 1) { + var sm = (item.sourcemore ? item.sourcemore[0] : {}); + var type = 0; + + if (sm.t) { + type = sm.t; + buff += ' ' + sm.n; + } + else if (sm.z) { + buff += ' ' + g_zones[sm.z]; + } + + buff += ' ' + Listview.funcBox.getUpperSource(item.source[0], sm); + + if (sm.dd) { + buff += ' ' + (sm.dd < -1 || sm.dd > 2 ? LANG.pr_print_heroic : LANG.pr_print_normal); + } + } + else { + for (var i = 0, len = item.source.length; i < len; ++i) { + buff += ' ' + g_sources[item.source[i]]; + } + } + } + + return buff; + }, + + modelShow: function (npcId, displayId, sp, e) { + if (sp) { + e = $WH.$E(e); + + if (e.shiftKey || e.ctrlKey) { + return; + } + + var + j = 0, + el = e._target; + + while (el && j < 3) { + if (el.nodeName == 'A') { + return; + } + if (el.nodeName == 'IMG') { + break; + } + el = el.parentNode; + } + } + + ModelViewer.show({ type: 1, typeId: npcId, displayId: displayId, noPound: 1 }); + } +}; + +Listview.templates.itempicker = { + sort: [1], + nItemsPerPage: -1, + hideBands: 2, + hideNav: 1 | 2, + hideHeader: 1, + searchable: 1, + searchDelay: 100, + poundable: 0, + filtrable: 0, + clip: { + w: 780, + h: 486 + }, + + onBeforeCreate: function () {}, + + onSearchSubmit: function (item) { + if (this.nRowsVisible != 2 || !item.id) { // None + return; + } + + $WowheadProfiler.equipItem(item.id); + }, + + columns: [ + { + id: 'item', + type: 'text', + align: 'left', + value: 'name', + span: 2, + compute: function (item, td, tr) { + if (item.none) { + return; + } + + var i = $WH.ce('td'); + i.style.width = '1px'; + i.style.padding = '0'; + i.style.borderRight = 'none'; + + var + icon = Icon.create(item.icon, 0, null, '?item=' + item.id), + link = Icon.getLink(icon); + + $WH.ae(i, icon); + $WH.ae(tr, i); + td.style.borderLeft = 'none'; + + link.onclick = $WH.rf; + + var a = $WH.ce('a'); + a.className = 'q' + item.quality; + a.style.fontFamily = 'Verdana, sans-serif'; + a.href = '?item=' + item.id; + + $WH.ae(a, $WH.ct(item.name)); + + $WH.nw(td); + $WH.ae(td, a); + + $(tr).click(function (e) { + if (e.which != 2 || e.target != a) { + e.preventDefault(); + ($WowheadProfiler.equipItem.bind(this, item.id, item.slot))(); + } + }); + }, + sortFunc: function (a, b, col) { + if (a.none) { + return -1; + } + if (b.none) { + return 1; + } + + return ( + -$WH.strcmp(a.level, b.level) || + -$WH.strcmp(a.quality, b.quality) || + $WH.strcmp(a.name, b.name) + ); + } + }, + { + id: 'level', + name: LANG.level, + value: 'level', + sortFunc: function (a, b, col) { + if (a.none) { + return -1; + } + if (b.none) { + return 1; + } + + return ( + -$WH.strcmp(a.score, b.score) || + $WH.strcmp(a.name, b.name) + ); + } + }, + { + id: 'type', + name: LANG.type, + type: 'text', + compute: function (item, td, tr) { + if (item.none) { + return; + } + + td.className = 'small q1'; + $WH.nw(td); + var a = $WH.ce('a'); + + var it = Listview.funcBox.getItemType(item.classs, item.subclass, item.subsubclass); + + a.href = it.url; + $WH.ae(a, $WH.ct(it.text)); + $WH.ae(td, a); + }, + getVisibleText: function (item) { + return Listview.funcBox.getItemType(item.classs, item.subclass, item.subsubclass).text; + } + }, + { + id: 'score', + align: 'center', + compute: function (item, td, tr) { + if (item.none) { + $WH.ee(tr); + + $(tr).click($WowheadProfiler.equipItem.bind(this, 0, item.slot)); + td.colSpan = 5; + td.style.fontWeight = 'bold'; + td.style.textAlign = 'center'; + + return LANG.dash + LANG.pr_noneitem + LANG.dash; + } + + if (item.score != null) { + var + n = parseFloat(item.score), + s = $WH.ce('div'); + + s.className = 'small q' + (n ? (n > 0 ? 2 : 10) : 0); + $WH.st(s, (n ? (n > 0 ? '+' : '-') + item.score: 0)); + $WH.ae(td, s); + } + } + } + ] +}; + +Listview.templates.subitempicker = { + sort: [1], + nItemsPerPage: -1, + hideBands: 2, + hideNav: 1 | 2, + hideHeader: 1, + searchable: 1, + searchDelay: 100, + poundable: 0, + filtrable: 0, + clip: { + w: 780, + h: 486 + }, + + onBeforeCreate: function () {}, + + onSearchSubmit: function (subitem) { + if (this.nRowsVisible != 2 || !subitem.id) { // None + return; + } + + $WowheadProfiler.equipSubitem(subitem.id); + }, + + columns: [ + { + id: 'subitem', + type: 'text', + align: 'left', + value: 'name', + span: 2, + compute: function (subitem, td, tr) { + if (subitem.none) { + return; + } + + var + url = '?item=' + subitem.item, + item = g_items[subitem.item]; + + var i = $WH.ce('td'); + i.style.width = '1px'; + i.style.padding = '0'; + i.style.borderRight = 'none'; + + var + icon = Icon.create(item.icon, 0, null, url), + link = Icon.getLink(icon); + + $WH.ae(i, icon); + $WH.ae(tr, i); + td.style.borderLeft = 'none'; + + link.onclick = $WH.rf; + link.rel = 'rand=' + subitem.id; + + var a = $WH.ce('a'); + + if (subitem.quality != -1) { + a.className = 'q' + item.quality; + } + + a.style.fontFamily = 'Verdana, sans-serif'; + a.href = url; + a.rel = 'rand=' + subitem.id; + + $WH.ae(a, $WH.ct(item['name_' + Locale.getName()] + ' ' + subitem.name)); + + $WH.nw(td); + $WH.ae(td, a); + + $(tr).click(function (e) { + if (e.which != 2 || e.target != a) { + e.preventDefault(); + ($WowheadProfiler.equipSubitem.bind(this, subitem.id))(); + } + }); + } + }, + { + id: 'enchantment', + type: 'text', + align: 'left', + value: 'enchantment', + compute: function (subitem, td, tr) { + if (subitem.none) { + return; + } + + var d = $WH.ce('div'); + d.className = 'small crop'; + td.title = subitem.enchantment; + $WH.ae(d, $WH.ct(subitem.enchantment)); + $WH.ae(td, d); + }, + sortFunc: function (a, b, col) { + if (a.none) { + return -1; + } + if (b.none) { + return 1; + } + + return ( + -$WH.strcmp(a.score, b.score) || + $WH.strcmp(a.name, b.name) + ); + } + }, + { + id: 'score', + align: 'center', + compute: function (subitem, td, tr) { + if (subitem.none) { + return; + } + + if (subitem.score != null) { + var + n = parseFloat(subitem.score), + s = $WH.ce('div'); + + s.className = 'small q' + (n ? (n > 0 ? 2 : 10) : 0); + $WH.st(s, (n ? (n > 0 ? '+' : '-') + subitem.score: 0)); + $WH.ae(td, s); + } + } + } + ] +}; + +Listview.templates.gempicker = { + sort: [1], + nItemsPerPage: -1, + hideBands: 2, + hideNav: 1 | 2, + hideHeader: 1, + searchable: 1, + searchDelay: 100, + poundable: 0, + filtrable: 0, + clip: { + w: 780, + h: 486 + }, + + onBeforeCreate: function () {}, + + onSearchSubmit: function (gem) { + if (this.nRowsVisible != 2 || !gem.id) { // None + return; + } + + $WowheadProfiler.socketItem(gem.id); + }, + + columns: [ + { + id: 'gem', + type: 'text', + align: 'left', + value: 'name', + span: 2, + compute: function (gem, td, tr) { + if (gem.none) { + return; + } + + var i = $WH.ce('td'); + i.style.width = '1px'; + i.style.padding = '0'; + i.style.borderRight = 'none'; + + var + icon = Icon.create(gem.icon, 0, null, '?item=' + gem.id), + link = Icon.getLink(icon); + + $WH.ae(i, icon); + $WH.ae(tr, i); + td.style.borderLeft = 'none'; + + link.onclick = $WH.rf; + + var a = $WH.ce('a'); + a.className = 'q' + gem.quality; + a.style.fontFamily = 'Verdana, sans-serif'; + a.href = '?item=' + gem.id; + + $WH.ae(a, $WH.ct(gem.name)); + + $WH.nw(td); + $WH.ae(td, a); + + $(tr).click(function (e) { + if (e.which != 2 || e.target != a) { + e.preventDefault(); + ($WowheadProfiler.socketItem.bind(this, gem.id, gem.socket, gem.slot))(); + } + }); + }, + sortFunc: function (a, b, col) { + if (a.none) { + return -1; + } + if (b.none) { + return 1; + } + + return ( + -$WH.strcmp(a.quality, b.quality) || + $WH.strcmp(a.colors, b.colors) || + $WH.strcmp(a.icon, b.icon) || + $WH.strcmp(a.name, b.name) + ); + } + }, + { + id: 'enchantment', + type: 'text', + align: 'left', + value: 'enchantment', + compute: function (gem, td, tr) { + if (gem.none) { + return; + } + + var d = $WH.ce('div'); + d.className = 'small crop'; + td.title = gem.enchantment; + $WH.ae(d, $WH.ct(gem.enchantment)); + $WH.ae(td, d); + }, + sortFunc: function (a, b, col) { + if (a.none) { + return -1; + } + if (b.none) { + return 1; + } + + return ( + -$WH.strcmp(a.score, b.score) || + $WH.strcmp(a.name, b.name) + ); + } + }, + { + id: 'colors', + compute: function (gem, td, tr) { + if (gem.none) { + return; + } + + td.className = 'small gem' + gem.colors; + $WH.nw(td); + + return g_gem_colors[gem.colors]; + }, + getVisibleText: function (gem) { + if (gem.none) { + return; + } + + return g_gem_colors[gem.colors]; + } + }, + { + id: 'score', + align: 'center', + compute: function (gem, td, tr) { + if (gem.none) { + $WH.ee(tr); + + $(tr).click($WowheadProfiler.socketItem.bind(this, 0, gem.socket, gem.slot)); + td.colSpan = 5; + td.style.fontWeight = 'bold'; + td.style.textAlign = 'center'; + + return LANG.dash + LANG.pr_nonegem + LANG.dash; + } + + if (gem.score != null) { + var + n = parseFloat(gem.score), + s = $WH.ce('div'); + + s.className = 'small q' + (n ? (n > 0 ? 2 : 10) : 0); + $WH.st(s, (n ? (n > 0 ? '+' : '-') + gem.score: 0)); + $WH.ae(td, s); + } + } + } + ] +}; + +Listview.templates.enchantpicker = { + sort: [1], + nItemsPerPage: -1, + hideBands: 2, + hideNav: 1 | 2, + hideHeader: 1, + searchable: 1, + searchDelay: 100, + poundable: 0, + filtrable: 0, + clip: { + w: 780, + h: 486 + }, + + onBeforeCreate: function () {}, + + onSearchSubmit: function (enchant, n) { + if (this.nRowsVisible != 2 || !enchant.id) { // None + return; + } + + $WowheadProfiler.enchantItem(enchant.id); + }, + + columns: [ + { + id: 'enchant', + type: 'text', + align: 'left', + value: 'name', + span: 2, + compute: function (enchant, td, tr) { + if (enchant.none) { + return; + } + + var url = (enchant.source > 0 ? '?spell=' : '?item=') + Math.abs(enchant.source); + + var i = $WH.ce('td'); + i.style.width = '1px'; + i.style.padding = '0'; + i.style.borderRight = 'none'; + + var + icon = Icon.create(enchant.icon, 0, null, url), + link = Icon.getLink(icon); + + $WH.ae(i, icon); + $WH.ae(tr, i); + td.style.borderLeft = 'none'; + + link.onclick = $WH.rf; + + var a = $WH.ce('a'); + + if (enchant.quality != -1) { + a.className = 'q' + enchant.quality; + } + + a.style.fontFamily = 'Verdana, sans-serif'; + a.href = url; + + $WH.ae(a, $WH.ct(enchant.name)); + + $WH.nw(td); + $WH.ae(td, a); + + $(tr).click(function (e) { + if (e.which != 2 || e.target != a) { + e.preventDefault(); + ($WowheadProfiler.enchantItem.bind(this, enchant.id))(); + } + }); + }, + sortFunc: function (a, b, col) { + if (a.none) { + return -1; + } + if (b.none) { + return 1; + } + + return $WH.strcmp(a.name, b.name); + } + }, + { + id: 'enchantment', + type: 'text', + align: 'left', + value: 'enchantment', + compute: function (enchant, td, tr) { + if (enchant.none) { + return; + } + + var d = $WH.ce('div'); + d.className = 'small crop'; + td.title = enchant.enchantment; + $WH.ae(d, $WH.ct(enchant.enchantment)); + $WH.ae(td, d); + }, + sortFunc: function (a, b, col) { + if (a.none) { + return -1; + } + if (b.none) { + return 1; + } + + return ( + -$WH.strcmp(a.score, b.score) || + $WH.strcmp(a.name, b.name) + ); + } + }, + { + id: 'skill', + type: 'text', + compute: function (enchant, td, tr) { + if (enchant.none) { + return; + } + + td.className = 'small q0'; + $WH.nw(td); + + if (enchant.skill > 0) { + return g_spell_skills[enchant.skill]; + } + else { + return LANG.types[3][0]; + } + }, + getVisibleText: function (enchant) { + if (enchant.none) { + return; + } + + if (enchant.skill > 0) { + return g_spell_skills[enchant.skill]; + } + else { + return LANG.types[3][0]; + } + } + }, + { + id: 'score', + align: 'center', + compute: function (enchant, td, tr) { + if (enchant.none) { + $WH.ee(tr); + + $(tr).click($WowheadProfiler.enchantItem.bind(this, 0)); + td.colSpan = 5; + td.style.fontWeight = 'bold'; + td.style.textAlign = 'center'; + return LANG.dash + LANG.pr_noneenchant + LANG.dash; + } + + if (enchant.score != null) { + var + n = parseFloat(enchant.score), + s = $WH.ce('div'); + + s.className = 'small q' + (n ? (n > 0 ? 2 : 10) : 0); + $WH.st(s, (n ? (n > 0 ? '+' : '-') + enchant.score: 0)); + $WH.ae(td, s); + } + } + } + ] +}; + +Listview.templates.petpicker = { + sort: [1], + nItemsPerPage: -1, + hideBands: 2, + hideNav: 1 | 2, + hideHeader: 1, + searchable: 1, + searchDelay: 100, + poundable: 0, + filtrable: 0, + clip: { + w: 780, + h: 486 + }, + + onBeforeCreate: function () {}, + + onSearchSubmit: function (pet, n) { + if (this.nRowsVisible != 2 || !pet.id) { // None + return; + } + + $WowheadProfiler.selectPet(pet.id); + }, + + columns: [ + { + id: 'pet', + type: 'text', + align: 'left', + value: 'name', + span: 2, + compute: function (pet, td, tr) { + if (pet.none) { + return; + } + + var url = '?npc=' + pet.id; + + var i = $WH.ce('td'); + i.style.width = '1px'; + i.style.padding = '0'; + i.style.borderRight = 'none'; + + var + icon = Icon.create(pet.icon, 0, null, url), + link = Icon.getLink(icon); + + $WH.ae(i, icon); + $WH.ae(tr, i); + td.style.borderLeft = 'none'; + + link.onclick = $WH.rf; + + var a = $WH.ce('a'); + a.style.fontFamily = 'Verdana, sans-serif'; + a.href = url; + + $WH.ae(a, $WH.ct(pet.name)); + + $WH.nw(td); + $WH.ae(td, a); + + $(tr).click(function (e) { + if (e.which != 2 || e.target != a) { + e.preventDefault(); + ($WowheadProfiler.selectPet.bind(this, pet.id))(); + } + }); + }, + sortFunc: function (a, b, col) { + if (a.none) { + return -1; + } + + if (b.none) { + return 1; + } + + if (a.family != b.family) { + return $WH.strcmp(g_pet_families[a.family], g_pet_families[b.family]); + } + + if (a.skin != b.skin) { + return $WH.strcmp(a.skin, b.skin); + } + + return $WH.strcmp(a.name, b.name); + } + }, + { + id: 'skin', + type: 'text', + value: 'skin', + compute: function (pet, td, tr) { + if (pet.none) { + return; + } + + var d = $WH.ce('div'); + d.className = 'small crop'; + td.title = pet.skin; + $WH.ae(d, $WH.ct(pet.skin)); + $WH.ae(td, d); + } + }, + { + id: 'level', + type: 'range', + getMinValue: function (pet) { + return pet.minlevel; + }, + getMaxValue: function (pet) { + return pet.maxlevel; + }, + compute: function (pet, td, tr) { + if (pet.none) { + $WH.ee(tr); + + $(tr).click($WowheadProfiler.selectPet.bind(this, 0)); + td.colSpan = 4; + td.style.fontWeight = 'bold'; + td.style.textAlign = 'center'; + return LANG.dash + LANG.pr_nonepet + LANG.dash; + } + + if (pet.minlevel > 0 && pet.maxlevel > 0) { + if (pet.minlevel != pet.maxlevel) { + return pet.minlevel + LANG.hyphen + pet.maxlevel; + } + else { + return pet.minlevel; + } + } + else { + return -1; + } + } + } + ] +}; + +Dialog.templates.profileredit = { + + title: LANG.pr_dialog_chardetails, + width: 400, + buttons: [['okay', LANG.ok], ['cancel', LANG.cancel]], + + fields: + [ + { + id: 'savewarning', + type: 'caption', + compute: function(field, value, form, td) { + if (this.data.region && this.data.region[0] && + this.data.battlegroup && this.data.battlegroup[0] && + this.data.realm && this.data.realm[0] && + !this.data.user) + { + td.style.whiteSpace = 'normal'; + td.style.lineHeight = 'normal'; + td.style.paddingBottom = '10px'; + $WH.st(td, LANG.dialog_losechanges); + } + } + }, + { + id: 'name', + type: 'text', + label: LANG.pr_dialog_name, + size: 30, + required: 1, + validate: function (value, data) { + if (value.match(/`~!@#$%^&*()_\-+={[}\]|:;"'<,>.?\/]/)) { + alert(LANG.message_saveasinvalidname); + return false; + } + return true; + } + }, + { + id: 'level', + type: 'select', + label: LANG.pr_dialog_level, + options: g_createRange(10, 80), + value: 80, + sort: -1, + compute: function(field, value, form) { + field.onchange = this.updateIcon; + } + }, + { + id: 'race', + type: 'select', + label: LANG.pr_dialog_race, + options: g_chr_races, + sort: 1, + compute: function(field, value, form) { + field.onchange = this.updateIcon; + } + }, + { + id: 'classs', + type: 'select', + label: LANG.pr_dialog_class, + options: g_chr_classes, + sort: 1, + compute: function(field, value, form) { + field.onchange = this.updateIcon; + }, + validate: function (value, data) { + if (value != 6 || data.level >= 55) { // Death Knight + return true; + } + else { + alert(LANG.message_invalidlevel); + + return false; + } + } + }, + { + id: 'gender', + type: 'radio', + label: LANG.pr_dialog_gender, + options: { 0 : LANG.male, 1 : LANG.female }, + compute: function(field, value, form) { + field.onclick = this.updateIcon; + } + }, + { + id: 'icon', + type: 'text', + label: LANG.pr_dialog_icon, + caption: LANG.pr_dialog_iconeg, + size: 30, + required: 1, + compute: function(field, value, form, td) { + var wrapper = $WH.ce('div'); + wrapper.style.position = 'relative'; + + var divIcon = $WH.ce('div'); + divIcon.style.position = 'absolute'; + divIcon.style.left = '151px'; + divIcon.style.top = '-71px'; + + var btn = this.btnPreview = $WH.ce('input'); + btn.type = 'button'; + btn.value = LANG.preview; + btn.onclick = function () { + field.value = $WH.trim(field.value); + + $WH.ee(divIcon); + $WH.ae(divIcon, Icon.create(field.value, 2)); + }; + + var _self = this; + field.onchange = function () { + _self.data.defaulticon = false; + }; + + $WH.ae(wrapper, field); + $WH.ae(wrapper, btn); + $WH.ae(wrapper, divIcon); + $WH.ae(td, wrapper); + } + }, + { + id: 'description', + type: 'textarea', + label: LANG.pr_dialog_description, + width: '98%', + size: [5, 30] + }, + { + id: 'published', + type: 'radio', + label: LANG.pr_dialog_public, + options: { 0 : LANG.privateprofile, 1 : LANG.publicprofile } + } + ], + + onInit: function(form) { + this.updateIcon = this.template.updateIcon.bind(this, form); + }, + + onShow: function() { + this.updateIcon(); + }, + + updateIcon: function(form) { + if (this.data.defaulticon) { + var + r = this.getSelectedValue('race'), + c = this.getSelectedValue('classs'), + g = this.getCheckedValue('gender'), + l = this.getSelectedValue('level'); + + this.setValue('icon', $WH.g_getProfileIcon(r, c, g, l)); + } + + this.btnPreview.onclick(); + } +}; + +Dialog.templates.quickexclude = { + + title: LANG.dialog_manageexclusions, + width: 480, + buttons: [['okay', LANG.ok], ['cancel', LANG.cancel]], + + fields: + [ + { + id: 'excludeexplain', + type: 'caption', + compute: function (field, value, form, td, tr) { + td.style.whiteSpace = 'normal'; + td.style.lineHeight = '1.4em'; + + td.innerHTML = LANG.dialog_exclude; + + var d = $WH.ce('div'); + d.className = 'pad'; + $WH.ae(td, d); + } + }, + { + id: 'miniheader', + type: 'caption', + compute: function (field, value, form, td, tr) { + $WH.ae(tr, $WH.ce('td')); + td.setAttribute('colSpan', null); + + var + l = $WH.ce('label'), + b = $WH.ce('b'); + + $WH.st(b, LANG.button_exclude); + $WH.ae(l, b); + $WH.ae(td, l); + + l = $WH.ce('label'); + b = $WH.ce('b'); + + $WH.st(b, LANG.button_include); + $WH.ae(l, b); + $WH.ae(td, l); + } + }, + { + id: 'noquickexcl', + type: 'caption', + compute: function (field, value, form, td, tr) { + td.style.whiteSpace = 'normal'; + td.style.lineHeight = '1.4em'; + + td.innerHTML = LANG.pr_tt_noqexcl; + + var d = $WH.ce('div'); + d.className = 'pad'; + $WH.ae(td, d); + } + }, + { + id: 1, + label: LANG.dialog_notavail + }, + { + id: 2, + label: LANG.dialog_tcg + }, + { + id: 4, + label: LANG.dialog_collector + }, + { + id: 8, + label: LANG.dialog_promo + }, + { + id: 16, + label: LANG.dialog_nonus + }, + { + id: 96, + label: LANG.dialog_faction + }, + { + id: 896, + label: LANG.dialog_profession + }, + { + id: 1024, + label: LANG.dialog_noexalted + }, + { + id: 'resetall', + type: 'caption', + compute: function(field, value, form, td, tr) { + td.style.textAlign = 'center'; + + var d = $WH.ce('div'); + d.className = 'pad'; + $WH.ae(td, d); + + var a = $WH.ce('a'); + a.href = 'javascript:;'; + a.onclick = $WowheadProfiler.resetExclusions; + $WH.st(a, LANG.dialog_resetexclusions); + $WH.ae(td, a); + } + } + ], + + onInit: function (form, opt) { + var + fields = [], + temp = []; + + for (var i = 0, len = this.template.fields.length; i < len; ++i) { + var field = this.template.fields[i]; + + if (isNaN(field.id)) { // Caption + fields = fields.concat(temp.sort(function (a, b) { + return $WH.strcmp(a.label, b.label); + })); + temp = []; + + fields.push(field); + } + else { + $WH.cO(field, { + type: 'radio', + noInputBr: 1, + options: { 2 : '', 1 : '' }, + optorder: [2, 1] + }); + + temp.push(field); + } + } + + fields = fields.concat(temp.sort(function (a, b) { + return $WH.strcmp(a.label, b.label); + })); + + this.template.fields = fields; + }, + + onBeforeShow: function (form) { + $WH.gE(form, 'table')[0].className = 'profiler-exclusion'; + + var + j = 0, + ngroups = 0; + for (var i = 0, len = this.template.fields.length; i < len; ++i) { + var field = this.template.fields[i]; + + if (!isNaN(field.id)) { + this.data[field.id] = (g_user.excludegroups & field.id ? 2 : 1); + + field.__tr.firstChild.style.textAlign = 'left'; + field.__tr.style.display = (this.data.empty(field.id) ? 'none' : ''); + + if (!this.data.empty(field.id)) { + if (j++ % 2) { + field.__tr.style.backgroundColor = '#202020'; + } + ngroups++; + } + } + else { + j = 0; + } + } + + this.template.fields[1].__tr.style.display = (ngroups ? '' : 'none'); + this.template.fields[2].__tr.style.display = (ngroups ? 'none' : ''); + } +}; + +var profileSummary; \ No newline at end of file diff --git a/template/js/locale_enus.js b/template/js/locale_enus.js index 1d2b3b14..06c5e9ee 100644 --- a/template/js/locale_enus.js +++ b/template/js/locale_enus.js @@ -3776,14 +3776,156 @@ var LANG = { message_nosigbookmarks: "You have not bookmarked any characters. Please add some to continue.", message_bookmarkforsig: "Please bookmark this character before creating a signature.", - pr_dialog_level: "Level:", + confirm_linkcharacter: "This character will be added to your list of characters.\n\nDo you want to continue?", + confirm_linkedcharacter: "This character has been added to your list.\n\nDo you want to be taken there?", + confirm_unlinkcharacter: "Are you sure that you want to remove the selected characters from your list?", + confirm_deleteprofile: "Are you sure that you want to delete the selected profiles?", + confirm_deleteprofile2: "Are you sure that you want to delete this profile?", + confirm_privateprofile: "Are you sure that you want to make the selected profiles private?", + confirm_publicprofile: "Are you sure that you want to make the selected profiles public?", + confirm_purgedata: "Are you sure you wish to purge your $1?", + confirm_newprofile: "Create a new profile?\n\nYou will be redirected upon saving the profile.", + confirm_resetexclusions: "This will reset your exclusion settings to the default. Are you sure you want to proceed?", + confirm_pincharacter: "This character will be pinned as your default character throughout the site.\n\nDo you want to continue?", + confirm_unpincharacter: "You will no longer have a pinned character.\n\nDo you want to continue?", + confirm_deletesigimages: "Are you sure you want to delete these signature backgrounds?", + confirm_deletesignature: "Are you sure that you want to delete the selected signatures?", + + loremasteryes_tip: "This quest counts towards
loremaster achievements", + loremasterno_tip: "This quest does not count
towards loremaster achievements", + + prompt_charlookup: "Please enter the name of the character you wish to view:", + prompt_nameprofile: "Please provide a name for this profile.\n(i.e. Resistance Gear, PvP Set, Wishlist, etc.)\n\nYou will be redirected upon saving the profile.", + + dialog_notavail: "Not available to players", + dialog_tcg: "Obtained via TCG loot redemption", + dialog_collector: "Reward from a Collector's Edition", + dialog_promo: "Obtained from a promotion", + dialog_nonus: "Not available on US servers", + dialog_faction: "Favored by opposite faction", + dialog_profession: "Requires another profession", + dialog_exclude: "Excluding entries lets you remove things you can't or don't plan on completing. Individual inclusions/exclusions will override the quick categories below.

Your exclusion settings are shared between all characters.", + dialog_noexalted: "Impossible to reach exalted", + + dialog_manageexclusions: "Manage Personal Exclusions", + dialog_resetexclusions: "Reset all exclusions", + + tab_arenateams: "Arena teams", + tab_character: "Character", + tab_characters: "Characters", + tab_guilds: "Guilds", + tab_reputation: "Reputation", + + lvnote_clicksubcatg: "Click on a subcategory below to filter the other tabs.", + + button_save: "Save", + button_saveas: "Save as", + button_bookmark: "Bookmark", + button_pin: "Pin", + button_unpin: "Unpin", + button_claimchar: "Claim character", + button_resync: "Resync", + button_signature: "Signature", + + button_customprofile: "Custom profile", + button_armorychar: "Manage character", + + pr_clienttab: "$1
If this is your character, you can track your
$2 using the Wowhead Client!

Click to learn more", + pr_lookup: "Lookup: ", + pr_noneitem: "None", + pr_nonegem: "None", + pr_noneenchant: "None", + pr_nonepet: "None", + pr_specifyitem: "Please enter an item name to search for.", + pr_searching: 'Searching for items named "$1"...', + pr_noresults: 'No results found for "$1"!', + pr_region: "(Region)", + pr_realm: "(Realm)", + pr_selectregion: "Select a region", + pr_vendorsin: "Vendors in ", + pr_yes: "Yes", + pr_dungeons: "Dungeons", + + pr_tt_items: "Items", + pr_tt_enchants: "Enchants", + pr_tt_gems: "Gems", + pr_tt_normal: "$1 (10-player)", + pr_tt_heroic: "$1 (25-player)", + pr_tt_earned: "$1 has earned $2 of $3 achievements ($4%).", + pr_tt_earned2: "$1 has killed all bosses in this instance.", + pr_tt_progress: "Progress", + pr_tt_obtained: "Total number obtained: $1", + pr_tt_nodata: "This statistic is not currently available in-game
and cannot be tracked by Wowhead.", + pr_tt_enchreq: "Enchantment Requires Level $1", + pr_tt_new: 'New
Create a new custom profile from scratch.', + pr_tt_saveas: 'Save as
Save the current character as a custom
profile tied to your Wowhead account.', + pr_tt_resync: 'Resync
Resync the character with the latest
version available on the Armory.', + pr_tt_claim: 'Claim character
Add this character to your list of characters.', + pr_tt_include: 'Include
Move selected entries out of your exclusion list.', + pr_tt_exclude: 'Exclude
Move selected entries to your exclusion list.
This can be useful to hide things you don\'t
consider important to reach 100% completion.', + pr_tt_noqexcl: '
Note: Quick exclusions aren\'t currently available for this tab.', + pr_tt_excldone: "Complete but excluded", + pr_tt_questtip: "Repeatable quests and quests that don't
appear in your quest log aren't tracked.", + + pr_tip_rclkopt: "Tip: Right-click slots for more options.", + pr_tip_sclkopt: "Tip: Shift-click items for more options.", + pr_tip_rclkopt2: "Tip: Right-click items, gems and enchants for more options.", + pr_tip_sclkopt2: "Tip: Shift-click items, gems and enchants for more options.", + pr_tip_quests: "Note: Certain quests aren't tracked by Blizzard's API.", + + pr_header_noname: "Noname", + pr_header_character: 'Level $1 $2 $3', + pr_header_edit: "Edit", + pr_header_armory: "Armory", + pr_header_help: "Help", + pr_header_print: "Print", + + pr_dialog_chardetails: "Character Details", + pr_dialog_name: "Name: ", + pr_dialog_level: "Level: ", + pr_dialog_class: "Class: ", + pr_dialog_race: "Race: ", + pr_dialog_gender: "Gender: ", + pr_dialog_icon: "Icon: ", + pr_dialog_iconeg: "e.g. INV_Axe_54", + pr_dialog_description: "Description: ", + pr_dialog_public: "Visibility: ", + + pr_qf_quickfacts: "Quick Facts", + pr_qf_progress: "Progress", + pr_qf_toc: "Table of Contents", + pr_qf_owner: "Owner: ", + pr_qf_character: "Character: ", + pr_qf_profiles: "Profiles: ", + pr_qf_playedtime: "Played time: ", + pr_qf_itemlevel: "Item Level: ", + pr_qf_gearscore: "Gear score: ", + pr_qf_talents: "Talents: ", + pr_qf_achievements: "Achievements: ", + pr_qf_xvxteam: "$1v$1 team: ", + pr_qf_updated: "Updated ", + pr_qf_resynced: "Resynced ", + pr_qf_notsaved: "Profile has not been saved!", + pr_qf_gearmeter: "Gear", + pr_qf_raidactivity1: "All Raid Activity", + pr_qf_raidactivity2: "Recent Raid Activity", + pr_qf_activitytip1: "Click to display recent raid activity", + pr_qf_activitytip2: "Click to display all raid activity", + pr_qf_activitypct1: "$1% of all activity", + pr_qf_activitypct2: "$1% of recent activity", + pr_qf_raidcomplete: "$1% complete", + + pr_qf_gear0: "Trivial", + pr_qf_gear1: "Easy", + pr_qf_gear2: "Ideal", + pr_qf_gear3: "Challenging", + pr_qf_gear4: "Difficult", + pr_qf_gear5: "Futile", menu_charlookup: "Lookup by name...", menu_newprofile: "New Custom Profile", menu_chooseclassspec: "Choose Your Class/Spec", - pr_selectregion: "Select a region", - pr_menu_equip: "Equip...", pr_menu_replace: "Replace...", pr_menu_add: "Add...", @@ -3803,9 +3945,134 @@ var LANG = { pr_menu_upgrades: "Find Upgrades", pr_menu_whowears: "Who Wears This?", - pr_noneitem: "None", - pr_nonegem: "None", - pr_noneenchant: "None", + pr_queue_unknown: "Unknown", + pr_queue_noprocess: "The queue is not currently running.", + pr_queue_resyncreq: "An Armory resync has been requested.", + pr_queue_addqueue: "Adding to the Armory queue...", + pr_queue_status1: "Position in queue: $1 – Estimated time: $2", + pr_queue_status2: "Fetching data now...", + pr_queue_status3: 'Data is ready! Reload to view.', + pr_queue_status4: 'Unable to resync from the Armory: $1. Try resyncing again.', + pr_queue_batch: "Queue: $1 – Processing: $2 – Ready: $3 – Error: $4", + + pr_error_armory0: "Error unknown", + pr_error_armory1: "Character does not exist", + pr_error_armory2: "The Armory could not be reached", + + pr_inv_title: "Gear Summary", + pr_inv_missing: "Missing: ", + pr_inv_lowlevel: "Low level: ", + pr_inv_metareq: "Meta condition: ", + pr_inv_item: "$1 item", + pr_inv_items: "$1 items", + pr_inv_gem: "$1 gem", + pr_inv_gems: "$1 gems", + pr_inv_enchant: "$1 enchant", + pr_inv_enchants: "$1 enchants", + pr_inv_socket: "$1 socket", + pr_inv_sockets: "$1 sockets", + + pr_print_none: "None", + pr_print_yes: "Yes", + pr_print_no: "No", + pr_print_normal: "Normal", + pr_print_heroic: "Heroic", + + pr_stats_warning: "Warning: Some statistics (particularly dodge) may not be entirely accurate.", + + pr_stats_title: "Statistics", + pr_stats_base: "Base", + pr_stats_melee: "Melee", + pr_stats_ranged: "Ranged", + pr_stats_spell: "Spell", + pr_stats_defenses: "Defenses", + pr_stats_resistances: "Resistances", + pr_stats_beta: "beta", + + pr_stats_agi: "Agility", + pr_stats_arcres: "Arcane resistance", + pr_stats_armor: "Armor", + pr_stats_armorpenpct: "Penetration", + pr_stats_blockpct: "Block", + pr_stats_def: "Defense", + pr_stats_dodgepct: "Dodge", + pr_stats_energy: "Energy", + pr_stats_exp: "Expertise", + pr_stats_firres: "Fire resistance", + pr_stats_frores: "Frost resistance", + pr_stats_health: "Health", + pr_stats_holres: "Holy resistance", + pr_stats_int: "Intellect", + pr_stats_mana: "Mana", + pr_stats_mleatkpwr: "Power", + pr_stats_mlecritstrkpct: "Critical", + pr_stats_mlehastepct: "Haste", + pr_stats_mlehitpct: "Hit", + pr_stats_natres: "Nature resistance", + pr_stats_oocmanargn: "Mana Regen", + pr_stats_parrypct: "Parry", + pr_stats_rage: "Rage", + pr_stats_resipct: "Resilience", + pr_stats_rgdatkpwr: "Power", + pr_stats_rgdcritstrkpct: "Critical", + pr_stats_rgdhastepct: "Haste", + pr_stats_rgdhitpct: "Hit", + pr_stats_runic: "Runic Power", + pr_stats_shares: "Shadow resistance", + pr_stats_spi: "Spirit", + pr_stats_splcritstrkpct: "Critical", + pr_stats_spldmg: "Bonus Damage", + pr_stats_splhastepct: "Haste", + pr_stats_splheal: "Bonus Healing", + pr_stats_splhitpct: "Hit", + pr_stats_splpen: "Penetration", + pr_stats_sta: "Stamina", + pr_stats_str: "Strength", + + pr_statstt_arc: "Arcane", + pr_statstt_fir: "Fire", + pr_statstt_fro: "Frost", + pr_statstt_hol: "Holy", + pr_statstt_nat: "Nature", + pr_statstt_sha: "Shadow", + + pr_statstt_agi: "Increases attack power by $1
Increases physical critical hit chance by $2%
Increases armor by $3", + pr_statstt_armor: "Reduces physical damage taken by $2%", + pr_statstt_armor2: "Reduces physical damage taken by $2%
Increases your pet's armor by $1", + pr_statstt_armorpenpct: 'Armor penetration rating $1 (+$2% armor penetration)
Reduces enemy armor by $3%', + pr_statstt_blockpct: 'Block rating $1 (+$2% block)
Increases chance to block by $4%
Your block stops $3 damage', + pr_statstt_def: 'Defense rating $1 (+$2 defense)
Increases chance to dodge, block and parry by $3%
Decreases chance to be hit and critically hit by $4%', + pr_statstt_dodgepct: 'Dodge rating $1 (+$2% dodge)
Increases chance to dodge by $3%
(Before diminishing returns)', + pr_statstt_exp: 'Expertise rating $1 (+$2 expertise)
Reduces chance to be dodged or parried by $3%', + pr_statstt_int: "Increases mana by $1
Increases spell critical hit chance by $2%", + pr_statstt_int2: "Increases mana by $1
Increases spell critical hit chance by $2%
Increases your pet's intellect by $3", + pr_statstt_mleatkpwr: "Increases damage with melee weapons by $1 per second", + pr_statstt_mlecritstrkpct: 'Crit rating $1 (+$2% crit chance)
Increases melee critical strike chance by $3%', + pr_statstt_mlehastepct: 'Haste rating $1 (+$2% haste)
Increases melee attack speed by $3%', + pr_statstt_mlehitpct: 'Hit rating $1 (+$2% hit chance)
Increases melee chance to hit a level $4 target by $3%', + pr_statstt_oocmanargn: "$1 mana regenerated every 5 seconds while not casting
$2 mana regenerated every 5 seconds while casting", + pr_statstt_parrypct: 'Parry rating $1 (+$2% parry)
Increases chance to parry by $3%
(Before diminishing returns)', + pr_statstt_resipct: 'Resilience rating $1 (+$2% resilience)
Reduces chance to be critically hit by $3%
Reduces the effect of mana-drains and the damage of critical strikes by $4%
Provides $5% additional damage reduction against all damage done by players and their pets or minions', + pr_statstt_resist: "Increases resistance to $1-based attacks, spells, and abilities.
Average resistance against spells cast by level $3: $1%", + pr_statstt_rgdatkpwr: "Increases damage with ranged weapons by $1 per second", + pr_statstt_rgdatkpwr2: "Increases damage with ranged weapons by $1 per second
Increases your pet's attack power by $2
Increases your pet's spell damage by $3", + pr_statstt_rgdcritstrkpct: 'Crit rating $1 (+$2% crit chance)
Increases ranged critical strike chance by $3%', + pr_statstt_rgdhastepct: 'Haste rating $1 (+$2% haste)
Increases ranged attack speed by $3%', + pr_statstt_rgdhitpct: 'Hit rating $1 (+$2% hit chance)
Increases ranged chance to hit a level $4 target by $3%', + pr_statstt_spi: "Increases health regeneration by $1 per 5 seconds while not in combat
Increases mana regeneration by $2 per 5 seconds while not casting", + pr_statstt_splcritstrkpct: 'Crit rating $2 (+$3% crit chance)
$1', + pr_statstt_spldmg: "$1", + pr_statstt_spldmg2: "$1
Increases your pet's attack power by $3
Increases your pet's spell damage by $4", + pr_statstt_splhastepct: 'Haste rating $1 (+$2% haste)
Increases spell casting speed by $3%', + pr_statstt_splheal: "Increases healing by up to $1", + pr_statstt_splhitpct: 'Hit rating $1 (+$2% hit chance)
Increases spell chance to hit a level $4 target by $3%', + pr_statstt_splpen: "Reduces enemy resistances by $1", + pr_statstt_sta: "Increases health by $1", + pr_statstt_sta2: "Increases health by $1
Increases your pet's stamina by $2", + pr_statstt_str: "Increases attack power by $1", + pr_statstt_str2: "Increases attack power by $1
Increases block value by $2", + + pr_ach_overall: "Overall Progress", pr_note_color: "Color: ", pr_note_source: "Source: ", @@ -3815,7 +4082,7 @@ var LANG = { pr_note_family: "Family: ", pr_note_sort: "Sort by: ", - ddaysago: "$1 days ago", + ddaysago: "$1 days ago", pr_note_all: "All", pr_note_bc: "BC", @@ -3833,6 +4100,8 @@ var LANG = { pr_note_missing: "Missing", pr_note_normal: "Normal", pr_note_exotic: "Exotic", + pr_note_gearscore: "Gear score", + pr_note_weighted: "Weighted", su_note_stats: "Stats", su_note_other: "Other", diff --git a/template/js/profile.js b/template/js/profile.js new file mode 100644 index 00000000..3c8ba614 --- /dev/null +++ b/template/js/profile.js @@ -0,0 +1,806 @@ +function pr_setRegionRealm(f, region, server) +{ + if(!f) return; + + var + r = f.elements['rg'] || f.elements[0], + s = f.elements['sv'] || f.elements[1]; + + if(!r || !s) return; + + for(var i = 0, len = r.options.length; i < len; ++i) + { + if(r.options[i].value == region) + { + r.options[i].selected = true; + break; + } + } + + pr_onChangeRegion(f, region, server); + + if(s.onchange) + s.onchange(); +} + + + +function pr_onChangeRegion(f, region, server) +{ + if(!f) return; + + var + r = f.elements['rg'] || f.elements[0], + s = f.elements['sv'] || f.elements[1]; + + if(!r || !s) return; + + var o = r.options[0]; + + o.value = ''; + o.style.color = '#999999'; + + $WH.ee(s); + + o = $WH.ce('option'); + o.value = ''; + o.style.color = '#999999'; + $WH.ae(s, o); + + if(s.onchange == null) + s.onchange = function() { this.className = (this.selectedIndex ? '' : 'search-character'); }; + + if(region == null) + region = r.options[r.selectedIndex].value; + + if(!region) + { + r.className = 'search-character'; + s.className = 'search-character'; + + var o = $WH.ce('option'); + o.disabled = true; + $WH.ae(o, $WH.ct(LANG.pr_selectregion)); + $WH.ae(s, o); + } + else + { + var realms; + + r.className = ''; + s.className = 'search-character'; + + realms = pr_getRealms(region); + + for(var i = 0, len = realms.length; i < len; ++i) + { + var + realmId = realms[i], + realm = g_realms[realmId]; + + o = $WH.ce('option'); + + o.value = g_urlize(realm.name, true, true); + $WH.ae(o, $WH.ct(realm.name)); + + if(server != null && realm.name == server) + { + s.className = ''; + o.selected = true; + } + + $WH.ae(s, o); + } + } +} +pr_onChangeRegion.C = {}; + + + +function pr_onChangeRace() +{ + if($('select[name=ra[]] option:selected').length) + $('select[name=si]').attr('disabled', true).val(''); + else + $('select[name=si]').attr('disabled', false); +} + + + +function pr_suggestRealms(region, realm, autoComplete) +{ + autoComplete.empty(); + if(realm.val().length >= 2) + { + var realms = pr_getRealms(region.val(), realm.val()); + if(realms.length) + { + $.each(realms, function(i, realmId) { + autoComplete.append('' + g_realms[realmId].name + ''); + }); + realm.removeClass('oops'); + autoComplete.show(); + } + else + { + realm.addClass('oops'); + autoComplete.hide(); + } + } + else + { + realm.removeClass('oops'); + autoComplete.hide(); + } +} + + + +function pr_highlightRealm(selectedRealm, autoComplete, realm) +{ + var spans = $('span', autoComplete), + active = $(spans.get(selectedRealm - 1)); + spans.removeClass('active'); + active.addClass('active'); + realm.val(active.text()).focus(); +} + + + +function pr_getRealms(region, text) +{ + if(pr_onChangeRegion.C[region] != null) + realms = pr_onChangeRegion.C[region]; + else + { + realms = pr_onChangeRegion.C[region] = g_sortJsonArray( + g_realms, + g_realms, + function(a, b) { return $WH.strcmp(g_realms[a].name, g_realms[b].name) }, + function(x) { return x.region == region } + ); + } + + if(text != null) + realms = $WH.array_filter(realms, function(x) { return g_realms[x].name.toLowerCase().match(text.toLowerCase()) }); + + return realms; +} + + + +function pr_updateStatus(page, div, id, request, tryAgain) +{ + if (tryAgain == null) { + tryAgain = function(noUpdate) { + new Ajax('?' + page + '=resync&id=' + id, { + method: 'POST', + onSuccess: function(xhr, opt) { + if (!noUpdate) { + pr_updateStatus(page, div, id, request, null); + } + } + }); + }; + } + + new Ajax('?' + page + '=status&id=' + id + '&t=' + (new Date().getTime()), { + onSuccess: function(xhr, opt) { + var text = xhr.responseText; + + if (text.charAt(0) != '[' || text.charAt(text.length - 1) != ']') { + return; + } + + var + a = eval(text), + processes = a[0], + profile = (location.search || location.pathname).substr(1), + working = false, + action = false, + statusTotal = { 1: 0, 2: 0, 3: 0, 4: 0 }, + duration; + + $WH.ee(div); + + for (var i = 1; i < a.length; ++i) { + var + status = a[i][0], + refresh = a[i][1], + count = a[i][2], + errcode = a[i][3], + nresyncs = a[i][4]; + + if (!statusTotal[status]) { + statusTotal[status] = 0; + } + + statusTotal[status]++; + + if (status == 3 && !nresyncs) { + request = true; + } + + if (status && (status != 3 || request)) { + if (a.length == 2) { // single status + duration = (count && processes ? g_formatTimeElapsed((count * 15 / processes) + 2) : LANG.pr_queue_unknown); + count = (!isNaN(count) ? $WH.number_format(count) : LANG.pr_queue_unknown); + + div.innerHTML = LANG.pr_queue_resyncreq; + + if (!processes) { + div.innerHTML += ' ' + LANG.pr_queue_noprocess; + } + + div.innerHTML += ''; + div.innerHTML += '
' + (status < 3 && !refresh && !nresyncs ? LANG.pr_queue_addqueue : (status > 2 ? $WH.sprintf(LANG['pr_queue_status' + status], LANG['pr_error_armory' + errcode], profile) : $WH.sprintf(LANG['pr_queue_status' + status], count, duration, profile))); + div.style.backgroundImage = ''; + + if (status == 4) { + var _ = $WH.gE(div, 'a')[1]; + _.onclick = tryAgain.bind(null, false); + } + } + + if (status == 4) { + $('a', div).click(tryAgain); + } + else if (refresh && !action) { + setTimeout(pr_updateStatus.bind(null, page, div, id, request, tryAgain), refresh); + working = true; + action = true; + } + } + } + + if (!div.childNodes) { + div.style.display = 'none'; + } + + if (!working) { + div.style.backgroundImage = 'none'; + } + + if (a.length > 2) { // Multiple status returned + div.innerHTML = LANG.pr_queue_resyncreq + (!processes ? ' ' + LANG.pr_queue_noprocess : '') + '
' + $WH.sprintf(LANG['pr_queue_batch'], statusTotal[1], statusTotal[2], statusTotal[3], statusTotal[4]); + } + } + }); +} + + + +function pr_resyncRoster(id, mode) +{ + var div = $WH.ge('roster-status'); + div.innerHTML = LANG.pr_queue_addqueue; + div.style.display = ''; + + new Ajax( + '/' + mode + '=resync&id=' + id + '&profile', + { + method: 'POST', + onSuccess: function(xhr, opt) + { + var result = parseInt(xhr.responseText); + + if(isNaN(result)) + alert(LANG.message_resyncerror + result); + else if(result < 0 && result != -102) + alert(LANG.message_resyncerror + '#' + result); + + pr_updateStatus('profile', div, id + '&' + mode, true); + } + } + ); +} + +// imported from deprecated version +function pr_initRosterListview() { + this.applySort(); + if (g_user.roles & (U_GROUP_ADMIN | U_GROUP_BUREAU)) { + this.mode = 1; + this.createCbControls = function (c, b) { + if (!b && this.data.length < 15) { + return + } + var a = $WH.ce("input"); + a.type = "button"; + a.value = LANG.button_resync; + a.onclick = (function () { + var e = this.getCheckedRows(); + if (!e.length) { + alert(LANG.message_nocharacterselected) + } else { + var d = ""; + $WH.array_walk(e, function (f) { + d += f.id + "," + }); + d = $WH.rtrim(d, ","); + if (d != "") { + new Ajax("?profile=resync&id=" + d) + } (Listview.cbSelect.bind(this, false))(); + alert(LANG.message_characterresync) + } + }).bind(this); + $WH.ae(c, a) + } + } +} + +function pr_getGearScoreQuality(level, gearScore, relics, slotId, use2h) +{ + var baseScore, totalMod, quality; + + if(!gearScore) + return 0; + + if(slotId == null) + { + totalMod = 12.25390625; + + if(level < 55) + { + if(relics) + totalMod -= 81/256; // Relic + + totalMod -= 18/16; // Trinkets x2 + if(level < 25) + { + totalMod -= 25/16; // Head and Neck + if(level < 20) + totalMod -= 30/16; // Shoulder and Rings x2 + } + } + } + else + { + switch(slotId) + { + case 1: // Head + case 5: // Chest + case 7: // Legs + case 16: // Main Hand (Modified) + case 17: // Off Hand (Modified) + totalMod = 1; + break; + + case 3: // Shoulder + case 10: // Hands + case 6: // Waist + case 8: // Feet + totalMod = 3/4; + break; + + case 9: // Wrists + case 2: // Neck + case 15: // Back + case 11: // Finger #1 + case 12: // Finger #2 + case 13: // Trinket #1 + case 14: // Trinket #2 + totalMod = 9/16; + break; + + case 18: // Ranged, Relic + totalMod = 81/256; + break; + } + + if(use2h) + totalMod *= 2; + } + + if(level > 80) + baseScore = ((level - 80) * 12) + 293; + else if(level > 70) + baseScore = ((level - 70) * 6) + 140; + else if(level > 60) + baseScore = ((level - 60) * 4) + 80; + else + baseScore = level + 5; + + if(level <= 80) + baseScore *= 1.2; + + if(gearScore >= baseScore * totalMod * 1.25) + quality = 5; // Legendary + else + { + quality = 4; // Epic + while(gearScore < baseScore * totalMod && quality > 0) + { + baseScore -= (level > 80 ? (5 - quality) * 12 : 0.6 * baseScore); + quality--; + } + } + + return quality; +} + + + +function pr_getSpecFromTalents(classs, spent) +{ + var spec = 0; // Hybrid + + if(spent == null || (spent[0] == 0 && spent[1] == 0 && spent[2] == 0)) + spec = -1; // Untalented + else if(spent[0] - spent[1] > 5 && spent[0] - spent[2] > 5) + spec = 1; + else if(spent[1] - spent[0] > 5 && spent[1] - spent[2] > 5) + spec = 2; + else if(spent[2] - spent[0] > 5 && spent[2] - spent[1] > 5) + spec = 3; + + var specName; + var specIcon; + + if(spec <= 0) + { + specName = g_chr_specs[spec]; + + if(spec == -1) + specIcon = 'spell_shadow_sacrificialshield'; // Untalented + else + specIcon = 'spell_nature_elementalabsorption'; // Hybrid + } + else + { + specName = g_chr_specs[classs][spec - 1]; + + if(wt_presets && wt_presets[classs] && wt_presets[classs].pve) + { + var j = 1; + for(var p in wt_presets[classs].pve) + { + if(j++ == spec) + { + specIcon = wt_presets[classs].pve[p].__icon; + break; + } + } + } + } + + return { + id: spec, + name: specName || '', + icon: specIcon || '' + }; +} + + + +function pr_getScaleFromSpec(classs, spec, getName) +{ + var pve = wt_presets[classs].pve, + temp = []; + + for(var p in pve) + temp.push(getName ? LANG.presets[p] : pve[p]); + + return (getName? temp[spec] : $WH.dO(temp[spec])); +} + + + +function pr_getScaleFilter(scale, noFilter) { + var temp = []; + + if (scale) { + for (var i = 0, len = fi_filters.items.length; i < len; ++i) { + var f = fi_filters.items[i]; + + if (LANG.traits[f.name] && scale[f.name]) { + temp.push([f.id, scale[f.name]]); + } + } + } + + temp.sort(function(a, b) { + return -$WH.strcmp(a[1], b[1]); + }); + + var + wt = [], + wtv = []; + + for (var i = 0, len = temp.length; i < len; ++i) { + wt.push(temp[i][0]); + wtv.push(temp[i][1]); + } + + if (wt.length && wtv.length) { + return (noFilter ? '&' : ';gm=3;') + 'wt=' + wt.join(':') + (noFilter ? '&' : ';') + 'wtv=' + wtv.join(':'); + } + + return ''; +} + + + +function pr_showClassPresetMenu(a, itemId, itemClass, itemSlot, event) +{ + var menu = [[, LANG.menu_chooseclassspec]]; + if(itemId && itemClass && (itemClass != 2 || itemSlot)) + { + if(g_user.weightscales && g_user.weightscales.length) + { + var __ = [0, LANG.ficustom,, []]; + menu.push(__); + + for(var i = 0, len = g_user.weightscales.length; i < len; ++i) + { + var scale = g_user.weightscales[i]; + __[3].push([scale.id, scale.name, '?items=' + itemClass + '&filter=cr=161;crs=1;crv=0' + pr_getScaleFilter(scale) + (itemClass == 2 ? ';gb=1' : ';gb=3') + ';upg=' + itemId + (itemClass == 2 && g_item_slots[itemSlot] ? '#' + g_urlize(g_item_slots[itemSlot]) : '')]); + } + } + + for(var c in wt_presets) + { + var __ = [c, g_chr_classes[c],, [], {className:'c'+c,tinyIcon:'class_'+g_file_classes[c]}]; + menu.push(__); + + var j = 0; + for(var p in wt_presets[c].pve) + { + __[3].push([j, LANG.presets[p], '?items=' + itemClass + '&filter=ub=' + c + ';cr=161;crs=1;crv=0' + pr_getScaleFilter(wt_presets[c].pve[p]) + (itemClass == 2 ? ';gb=1' : ';gb=3') + ';upg=' + itemId + (itemClass == 2 && g_item_slots[itemSlot] ? '#' + g_urlize(g_item_slots[itemSlot]) : ''),, {tinyIcon:wt_presets[c].pve[p].__icon}]); + j++; + } + } + + var pos = $WH.g_getCursorPos(event); + + Menu.sort(menu); + Menu.showAtXY(menu, pos.x, pos.y); + } +} + + + +function pr_addEquipButton(id, itemId) +{ + $.each(g_user.characters, function(idx, character) + { + if(character.pinned) + { + var button = RedButton.create(LANG.button_equip, true, function() { + location.href = g_getProfileUrl(character) + '&items=' + itemId; + }); + + g_addTooltip(button, LANG.tooltip_equip, 'q1'); + + $('#' + id).append(button); + + return; + } + }); +} + + + +function pr_onBreadcrumbUpdate() // Add character lookup textbox to the breadcrumb +{ + // var breadcrumb = PageTemplate.get('breadcrumb'); + var breadcrumb = temp_path; + // end + + if(!breadcrumb || breadcrumb.length != 6) // Realm is required + return; + + var path = Menu.getFullPath(mn_path, breadcrumb); + var menuItem = path[path.length - 1]; + + // var span = PageTemplate.expandBreadcrumb()[0]; + $('.path').children('span:last').addClass('breadcrumb-arrow'); + var span = ($('').appendTo($('.path')))[0]; + // end + + var f = $WH.ce('form'), + i = $WH.ce('input'), + a = $WH.ce('a'); + + span.className = 'profiler-charlookup'; + + f.onsubmit = pr_DirectLookup.bind(0, f, false); + + i.name = 'na'; + i.className = 'search-character'; + i.type = 'text'; + + i.onfocus = function() + { + this.className = ''; + }; + + i.onblur = function() + { + if($WH.trim(this.value) == '') + { + this.className = 'search-character'; + this.value = ''; + } + }; + + a.className = 'profiler-charlookup-go'; + a.href = 'javascript:;'; + a.onclick = f.onsubmit.bind(f); + + $WH.ae(f, i); + $WH.ae(f, a); + $WH.ae(span, f); +} + +function pr_DirectLookup(form, browse) +{ + var region = $('*[name="rg"]', form), + server = $('*[name="sv"]', form), + name = $('*[name="na"]', form), + usePath; + + if(region.length > 1) // Radio + region = $('*[name="rg"]:checked', form); + + if(browse) + { + if(region.val() || server.val() || name.val()) + location.href = '/profiles' + (region.val() ? '=' + region.val() + (server.val() ? '.' + g_urlize(server.val(), false, true) : '') : '') + (name.val() ? '?filter=na=' + name.val() + ';ex=on' : ''); + return false; + } + + var breadcrumb = PageTemplate.get('breadcrumb'); + if(usePath = (breadcrumb && breadcrumb.length == 6)) // Realm is required + { + var path = Menu.getFullPath(mn_path, breadcrumb), + menuItem = path[path.length - 1]; + } + + if(!name.val()) + { + alert(LANG.message_missingcharacter); + name.focus().addClass('oops'); + return false; + } + + if(!region.val() && !usePath) + { + alert(LANG.message_missingregion); + region.focus().addClass('oops'); + return false; + } + + if(!server.val() && !usePath) + { + alert(LANG.message_missingrealm); + server.focus().addClass('oops'); + return false; + } + + if(region.val() && server.val()) + usePath = false; + + location.href = (usePath ? menuItem[2].replace('profiles', 'profile') : '/profile=' + region.val() + '.' + g_urlize(server.val(), false, true)) + '.' + g_cleanCharacterName(name.val()); + return false; +} + + + +function pr_lookupOrSearch(forceLookup) +{ + if(!forceLookup) + { + if($('input[name="sv"]').val()) + { + var realmName = $('input[name="sv"]').val().toLowerCase(), + valid = false; + + $.each(g_realms, function(i, realm) { + if(realm.name.toLowerCase() == realmName) + valid = true; + }); + + if(!valid) + { + alert(LANG.message_missingrealm); + $('input[name="sv"]').focus().addClass('oops'); + return; + } + } + + forceLookup = ($('input[name="na"]').val() && $('input[name="sv"]').val()); + } + + pr_DirectLookup($('.profiler-home'), !forceLookup); +} + + + +function pr_initProfilerHome() +{ + $('input[name="na"]') + .keyup(function(e) { + $(this).removeClass('oops'); + if(e.keyCode == 13) // Enter + pr_lookupOrSearch(false); + }) + .focus(); + + $('input[type="radio"]') + .change(function() { + $('label').removeClass('selected'); + $('label[for="' + $(this).attr('id') + '"]').addClass('selected'); + pr_suggestRealms($('input[name="rg"]:checked'), $('input[name="sv"]'), $('.profiler-autocomplete')); + $('input[name="sv"]').focus(); + }); + + $('input[name="sv"]') + .keyup(function(e) { + switch(e.keyCode) + { + case 13: // Enter + $('.profiler-autocomplete').hide(); + pr_lookupOrSearch(false); + break; + + case 27: // Escape + $('.profiler-autocomplete').hide(); + break; + + case 38: // Up + selectedRealm--; + if(selectedRealm < 0) + selectedRealm = $('.profiler-autocomplete span').length - 1; + pr_highlightRealm(selectedRealm, $('.profiler-autocomplete'), $('input[name="sv"]')); + break; + + case 40: // Down + selectedRealm++; + if(selectedRealm >= $('.profiler-autocomplete span').length) + selectedRealm = 0; + pr_highlightRealm(selectedRealm, $('.profiler-autocomplete'), $('input[name="sv"]')); + break; + + default: + pr_suggestRealms($('input[name="rg"]:checked'), $('input[name="sv"]'), $('.profiler-autocomplete')); + selectedRealm = 0; + break; + } + }); + + $('.profiler-autocomplete') + .delegate('span', 'mouseover', function() { + $('.profiler-autocomplete span').removeClass('active'); + }) + .delegate('span', 'click', function() { + $('input[name="sv"]').val($(this).text()).focus(); + $('.profiler-autocomplete').hide(); + }); + + $('#profiler-lookup, #profiler-search') + .click(function(e) { + pr_lookupOrSearch(this.id == 'profiler-lookup'); + }); + + $('body') + .click(function() { + $('.profiler-autocomplete').hide(); + }); +} + + + +if($WH.isset('mn_profiles')) +{ + // Add submenu to "Tools > Profiler" + Menu.findItem(mn_path, [1,5,0])[MENU_IDX_SUB] = mn_profiles; + Menu.findItem(mn_path, [1,5,2])[MENU_IDX_SUB] = mn_guilds; + Menu.findItem(mn_path, [1,5,3])[MENU_IDX_SUB] = mn_arenateams; + + + // todo (low): understand and use pageTemplate + // PageTemplate.getBreadcrumb().bind('update', pr_onBreadcrumbUpdate); + DomContentLoaded.addEvent(function() { + pr_onBreadcrumbUpdate(); + }); +} \ No newline at end of file diff --git a/template/profile.tpl b/template/profile.tpl new file mode 100644 index 00000000..fbc833d8 --- /dev/null +++ b/template/profile.tpl @@ -0,0 +1,40 @@ +{include file='header.tpl'} + +
+
+
+ +{if !empty($announcements)} + {foreach from=$announcements item=item} + {include file='bricks/announcement.tpl' an=$item} + {/foreach} +{/if} + + + +
+ + +
+
+
+ +{include file='footer.tpl'} \ No newline at end of file diff --git a/template/profiles.tpl b/template/profiles.tpl new file mode 100644 index 00000000..e672f238 --- /dev/null +++ b/template/profiles.tpl @@ -0,0 +1,114 @@ +{include file='header.tpl'} + +
+
+
+ +{if !empty($announcements)} + {foreach from=$announcements item=item} + {include file='bricks/announcement.tpl' an=$item} + {/foreach} +{/if} + + + +
+
+
{$lang.class|ucfirst}{$lang.colon}
+
{$lang.clear} +
+ +
+ +
+
{$lang.race|ucfirst}{$lang.colon}
+ {$lang.clear} +
+ +
+ + + + + + + + + + + + + + + + + + + +
Name{$lang.colon} + + + + +
  
+
Region{$lang.colon}   +    Realm{$lang.colon} 
Side{$lang.colon}  +    {$lang.level}{$lang.colon}  -
+ +
+ + +
+ {$lang.match}{$lang.colon} +
+ +
+ +
+ + +
+
+
+ + + +
+ + +
+
+
+ +{include file='footer.tpl'}