Guest User

Untitled

a guest
Jun 8th, 2014
318
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 27.35 KB | None | 0 0
  1. // ==UserScript==
  2. // @id hv_shop_filter_plus
  3. // @name HentaiVerse Shop Filter Plus
  4. // @version 1.1
  5. // @namespace
  6. // @author Razor320 (fix by AnimeAi)
  7. // @description Provides an easy way to sell and salvage multiple items at one go.
  8. // @include http://hentaiverse.org/?s=Bazaar&ss=es*
  9. // @run-at document-end
  10. // ==/UserScript==
  11.  
  12. /*
  13. - Character level parser
  14. +/- Equip parser + Params breakdown + Attribute descaler
  15. + Checkboxes generator
  16. + Selector API
  17. + Mass Processor API
  18. + Batch hide/show/check/uncheck using Selector API
  19. + Top menu builder
  20. +/- Seller, salvager and unlocker using Mass Processor API
  21. + HV Compat text renderer
  22. */
  23.  
  24. /* Settings */
  25. // Overrides original selection of hentaiverse, allowing to select more than 1 item. Neat, but requires browser with specific support.
  26. // Examples: Firefox 3.5+, Google Chrome with Tampermonkey (GC itself emulate only stub unsafeWindow - without real content).
  27. const USE_HOOKS = true;
  28. /*
  29. Define set of menu entries. All entries should be defined in next way:
  30.  
  31. Array(<display name>, <filter function>[, <input function>]);
  32.  
  33. where <filter function> is function, which has one argument (object hvEquipItem with item data) and should return true or false, based on where item should be hidden or not.
  34. There are also several function generators available to use:
  35. textFunction(String) - generates filter function that hides items, which title contain specified text
  36. regexpFunction(RegExp) - generates filter function that hides items, which title matches to specified regular expression
  37. invRegexpFunction(RegExp) - works similar way to regexpFunction, but hides all items, which title doesn't match to specified reguilar exression
  38. You can use any generator instead of writing manually specific filter function.
  39.  
  40. <input function> is special function which executes when user selects entry in menu. It can perform some additional setup actions, before filter could be applied to list of items. For example, this function used to implement custom text filter in default implementation.
  41.  
  42. */
  43. const MENU_ENTRIES = [
  44. ["Hide Shade armor", textFunction("Shade")],
  45. ["Hide Phase armor", textFunction("Phase")],
  46. ["Hide Power armor", textFunction("Power")],
  47. ["Hide Plate armor of Deflection", regexpFunction(/Plate.+Deflection/)],
  48. ["Hide Force Shields", textFunction("Force Shield")],
  49. ["Hide Magnificient+ items", regexpFunction(/Magnificent|Peerless|Legendary/)],
  50. ["Show only Battlecaster items", invRegexpFunction(/Battlecaster/)],
  51. ["Show only...", function(item){return !item.title.contains(storage.getCustomQuery());}, function(){
  52. var input = prompt("Enter custom text:", storage.getCustomQuery());
  53. if (input != null){
  54. if (input.length > 0){
  55. storage.setCustomQuery(input);
  56. storage.store();
  57. return true;
  58. }
  59. }
  60. return false;
  61. }]
  62. ];
  63. /*
  64. This structure inflated to fill "Selection" menu. Same rules applied as in MENU_ENTRIES structure.
  65. If you don't need this menu, just comment entire statement.
  66.  
  67. Notice, that selection procedure, unlike filtering, is exclusive - this means previous selection would be overwritten.
  68. */
  69. const SELECT_MENU_ENTRIES = [
  70. ["Select all", function(item){return true;}],
  71. ["Select none", function(item){return false;}],
  72. ["Invert selection", function(item){return !item.selected}],
  73. ];
  74.  
  75. /* End of settings */
  76.  
  77. /* Internal constants */
  78. const CHECKBOXES_CLASS = "item_checkboxes";
  79. const IAB_TYPES = [
  80. "Strength", "Dexterity", "Agility", "Endurance", "Intelligence", "Wisdom",
  81. "Fire", "Cold", "Holy", "Elec", "Dark", "Wind",
  82. "Crushing", "Slashing", "Piercing",
  83. "Supportive", "Deprecating", "Elemental", "Divine", "Forbidden"
  84. ];
  85. const EQUIP_TYPES = [
  86. ["One-handed", "1handed"],
  87. ["Two-handed", "2handed"],
  88. ["Staff", "staff"],
  89. ["Shield", "shield"],
  90. ["Cloth", "acloth"],
  91. ["Light", "alight"],
  92. ["Heavy", "aheavy"]
  93. ]
  94.  
  95. /* Regular expressions used to parse live data */
  96. const ITEM_SRC_REGEXP = /common\.show_popup_box\((?:.+?,){6}(.+?),(.+?),.+equips.set\((\d+),\s*(.+?)\)/;
  97. const IAB_REGEXP = /(\w+).+?(\d+(?:\.\d+))/
  98. const ITEM_TYPE_REGEXP = /(.+?)\s+Level\s+(\d+)\s+(?:(\d+)\s*\/\s*(\d+))?/;
  99. const ITEM_COST_REGEXP = /shops\.set_selected_item\(.+,\s*(\d+)/;
  100. const INTEGER_REGEXP = /\d+/;
  101. const CURRENT_CREDITS_REGEXP = /current_credits\s*=.+?(\d+)/;
  102. const SALVAGE_REGEXP = /Salvaged\s+(.+)/;
  103.  
  104. /* Results of some checks */
  105. var FULL_UNSAFE = false;
  106. try{
  107. //Unfortunately (for Chrome users though xD), Google Chrome doesn't support direct access to page context from chrome.
  108. //Maybe at some point in future i will write event-driven layer to overcome this injustice.
  109. var FULL_UNSAFE = "common" in unsafeWindow;
  110. } catch (e){}
  111. const USE_MAGIC = USE_HOOKS && FULL_UNSAFE;
  112. if (!("contains" in String)){
  113. //Google chrome is missing "contains(text)" function in String object.
  114. String.prototype.contains = function(text){
  115. return this.indexOf(text) > -1;
  116. }
  117. }
  118.  
  119.  
  120. var items = [];
  121. var storage = new filterStorage();
  122. var filterMenuButton = null;
  123. var AUTO_UPDATE_COST = true;
  124. var current_credits = parseInt(USE_MAGIC ? unsafeWindow.current_credits:CURRENT_CREDITS_REGEXP.exec(document.body.innerHTML)[1]);
  125.  
  126. main();
  127.  
  128. /*
  129. Short reference:
  130. title: contains full item title, like 'Exquisite Plate Sabatons of Protection'
  131. id: contains item id (required to perform an action with it)
  132. key: a hexadecimal string used in HV to generate equipment description links
  133. (http://hentaiverse.org/pages/showequip.php?eid=<insert id here>&key=<insert key here> and it could be used on forums, for example)
  134. attributes: an array with item attributes, each attribute has following format:
  135. name: title of attribute
  136. value: attribute value
  137. type: internal attribute type (integer). Compared using IAB_TYPES array
  138. node: html div, which represents this item in hentaiverse shop interface. Internally used to hide and show item in list
  139. equipType: type of equipment, as used on server. Internally used to sort out requests, so future client mod with panel, containing all items, could be implemented with lesser work
  140. potencyLVL: stands for equip potency level. Not used internally, available to use in filter functions.
  141. potencyCurExp: stands for gained potency experience at current potency level. Also parsed just in case and internally is not used
  142. potencyNextExp: stands for potency experience required to gain a new level. Parsed just in case, in other script used to calculate number of ItemWorld rounds
  143. const: item price for selling to the equipment shop
  144. selected: states for selection state of item. Read all you want, change at your own risk, as there could be invalid selection indication after untidy use.
  145. hidden: indicates that item was hidden from list. Same precaution as with previous.
  146.  
  147. */
  148. function hvEquipItem(source){
  149. var data = ITEM_SRC_REGEXP.exec(source.getAttribute("onmouseover"));
  150. data[1] = sanitize(data[1]); //This is an item title
  151. data[2] = sanitize(data[2]); //This is popup box data with item description
  152. data[4] = sanitize(data[4]); //This is an item key required to build link with item description
  153.  
  154. this.title = data[1];
  155. this.id = parseInt(INTEGER_REGEXP.exec(source.id)[0]);
  156. this.key = data[4];
  157. this.attributes = [];
  158. this.node = source;
  159.  
  160. // Ask browser's HTML parser for assistance in parsing equipment attributes and other information
  161. var e = document.createElement("div");
  162. e.innerHTML = data[2];
  163. data = e.getElementsByClassName("e9");
  164. for (var i = 0; i<data.length; i++){
  165. var m = IAB_REGEXP.exec(data[i].textContent);
  166. this.attributes.push({name: m[1], value: m[2], type: IABtypeof(m[1])});
  167. }
  168. data = ITEM_TYPE_REGEXP.exec(e.getElementsByClassName("e1")[0].textContent);
  169. console.log(data);
  170. this.equipType = EQUIPtypeof(data[1]);
  171. this.potencyLvl = data[2];
  172. if (data[3] != null){
  173. this.potencyCurExp = parseInt(data[3]);
  174. this.potencyNextExp = parseInt(data[4]);
  175. } else {
  176. this.potencyCurExp = 0;
  177. this.potencyNextExp = 0;
  178. }
  179.  
  180. //Try to retrieve item cost
  181. data = ITEM_COST_REGEXP.exec(source.getAttribute("onclick"));
  182. if (data != null){
  183. this.cost = parseInt(data[1]);
  184. } else {
  185. this.cost = 0;
  186. }
  187.  
  188. this.selected = false;
  189. this.hidden = false;
  190.  
  191. function IABtypeof(name){
  192. for (var i = 0; i<IAB_TYPES.length; i++){
  193. if (name == IAB_TYPES[i]){
  194. return i;
  195. }
  196. }
  197. return -1;
  198. }
  199.  
  200. function EQUIPtypeof(name){
  201. for (var i = 0; i<EQUIP_TYPES.length; i++){
  202. if (name.contains(EQUIP_TYPES[i][0])){
  203. return EQUIP_TYPES[i][1];
  204. }
  205. }
  206. return "unknown";
  207. }
  208. }
  209.  
  210. function filterStorage(){
  211. var flags = localStorage.getItem("HV_ITEM_FILTER_FLAGS");
  212. var customFilter = localStorage.getItem("HV_ITEM_FILTER_CUSTOM_STRING");
  213. if (isNaN(flags)) flags = 0;
  214.  
  215. this.store = function(){
  216. localStorage.setItem("HV_ITEM_FILTER_FLAGS", flags);
  217. localStorage.setItem("HV_ITEM_FILTER_CUSTOM_STRING", customFilter);
  218. };
  219. this.setFlag = function(flagPos){
  220. flags |= (1<<flagPos);
  221. };
  222. this.clearFlag = function(flagPos){
  223. flags &= ~(1<<flagPos);
  224. };
  225. this.isEnabled = function(flagPos){
  226. return (flags & (1<<flagPos)) == (1<<flagPos)
  227. }
  228. this.getCustomQuery = function(){
  229. return customFilter;
  230. }
  231. this.setCustomQuery = function(str){
  232. customFilter = str;
  233. }
  234. }
  235.  
  236. /* Main */
  237. function main(){
  238. //Retrieve all items and store them into an array
  239. var iblocks = document.getElementById("item_pane").getElementsByClassName("eqdp");
  240. for (var i = 0; i<iblocks.length; i++){
  241. items.push(new hvEquipItem(iblocks[i]));
  242. if (!USE_MAGIC) insertCheckbox(iblocks[i]);
  243. }
  244.  
  245. //Create menu
  246. generateMenu();
  247.  
  248. //Make some magic!
  249. if (USE_MAGIC){
  250. mpOverrideSelector();
  251. }
  252.  
  253. //Create new mass sell/salvage interface
  254. replaceShopSellInterface();
  255.  
  256. //Update list
  257. updateListEntries();
  258. }
  259.  
  260. function mpOverrideSelector(){
  261. unsafeWindow.common.set_text_selected = function (obj){
  262. obj = obj.getElementsByClassName("fd2")[0]
  263. if (obj != null)
  264. obj = obj.firstChild;
  265. else
  266. return;
  267. if (obj.getAttribute("hvsSelected") == "1"){
  268. obj.style.color = "";
  269. obj.setAttribute("hvsSelected", "0");
  270. } else {
  271. obj.style.color = "#0030CC";
  272. obj.setAttribute("hvsSelected", "1");
  273. }
  274. }
  275. const originalFunc = unsafeWindow.shops.set_selected_item;
  276. unsafeWindow.shops.set_selected_item = function (mode, iid, count, unk, title){
  277. if (mode == "item_pane"){
  278. selectorCallback(iid);
  279. }
  280. originalFunc.call(unsafeWindow.shops, mode, iid, count, unk, title);
  281. }
  282. }
  283.  
  284. function generateMenu(){
  285. const panelWidth = 130;
  286. if (SELECT_MENU_ENTRIES != undefined){
  287. if (SELECT_MENU_ENTRIES.length > 0) {
  288. var plusWidth = 30;
  289. } else {
  290. var plusWidth = 0;
  291. }
  292. }
  293. var heads = document.querySelectorAll(".cfb,.cfbs");
  294.  
  295. //Calculate width
  296. var fieldWidth = 0;
  297. for (var i = 0; i<heads.length; i++) fieldWidth += parseInt(INTEGER_REGEXP.exec(heads[i].style.width)[0]);
  298. var ratio = (fieldWidth-panelWidth-plusWidth)/fieldWidth;
  299.  
  300. //Create new tab's head
  301. filterMenuButton = heads[(heads[0].className == "cfb" ? 0:1)].cloneNode(true);
  302. filterMenuButton.children[0].children[0].innerHTML = "Filter";
  303. filterMenuButton.setAttribute("onclick", null);
  304. filterMenuButton.style.width = panelWidth + "px";
  305. for (var i = 0; i<heads.length; i++){
  306. heads[i].style.width = Math.floor(parseInt(INTEGER_REGEXP.exec(heads[i].style.width)[0])*ratio) + "px";
  307. }
  308.  
  309. heads[0].parentNode.insertBefore(filterMenuButton, heads[0].parentNode.firstElementChild);
  310.  
  311. //Generate submenu
  312. var root = document.createElement("div");
  313. root.className = "cnbc";
  314. root.style.borderWidth = "1px";
  315.  
  316. var template = document.getElementsByClassName("cnbs")[0].cloneNode(true);
  317. template.setAttribute("onclick", null);
  318.  
  319. for (var i = 0; i<MENU_ENTRIES.length; i++){
  320. var entry = template.cloneNode(true);
  321. travelToText(entry).innerHTML = "<input type='checkbox'" + (storage.isEnabled(i) ? " checked":"") + "></input>" + MENU_ENTRIES[i][0];
  322. entry.setAttribute("entryID", i);
  323. entry.addEventListener("click", menuEntryClickCallback, false);
  324. root.appendChild(entry);
  325. }
  326.  
  327. filterMenuButton.parentNode.insertBefore(root, filterMenuButton.nextSibling);
  328. root.style.top = (filterMenuButton.offsetHeight + filterMenuButton.offsetTop) + "px";
  329.  
  330. setupMenu(filterMenuButton, root);
  331.  
  332. //Create selection menu if required
  333. if (plusWidth > 0){
  334. var plusMenuButton = heads[(heads[0].className == "cfb" ? 0:1)].cloneNode(true);
  335. plusMenuButton.children[0].children[0].innerHTML = "+"
  336. plusMenuButton.setAttribute("onclick", null);
  337. plusMenuButton.style.width = plusWidth + "px";
  338. filterMenuButton.parentNode.insertBefore(plusMenuButton, filterMenuButton.nextElementSibling);
  339.  
  340. root = document.createElement("div");
  341. root.className = "cnbc";
  342. root.style.borderWidth = "1px";
  343.  
  344. for (var i = 0; i<SELECT_MENU_ENTRIES.length; i++){
  345. var entry = template.cloneNode(true);
  346. travelToText(entry).innerHTML = SELECT_MENU_ENTRIES[i][0];
  347. entry.setAttribute("entryID", i);
  348. entry.addEventListener("click", selectMenuEntryClickCallback, false);
  349. root.appendChild(entry);
  350. }
  351.  
  352. plusMenuButton.parentNode.insertBefore(root, plusMenuButton.nextSibling);
  353. root.style.top = (plusMenuButton.offsetHeight + plusMenuButton.offsetTop) + "px";
  354.  
  355. setupMenu(plusMenuButton, root);
  356. }
  357. }
  358.  
  359. function replaceShopSellInterface(){
  360. var root = document.getElementById("transaction_pane");
  361. root.style.textAlign = "left";
  362.  
  363. //Hide all unnecessary buttons and fields
  364. hideChildren(root);
  365. document.getElementById("sellall_pane").style.display = "none";
  366.  
  367. var container = document.createElement("div");
  368. container.style.marginLeft = "120px";
  369. container.style.marginTop = "8px";
  370. var elem = document.createElement("span");
  371. elem.id = "sell_selected_button";
  372. elem.innerHTML = mktext("Sell selected", true);
  373. elem.addEventListener("click", sellSelectedClickCallback, false);
  374. setupButton(elem);
  375. container.appendChild(elem);
  376. elem = document.createElement("span");
  377. elem.id = "total_cost_field";
  378. elem.style.display = "inline-block";
  379. elem.style.paddingLeft = "60px";
  380. elem.innerHTML = mktext("0 c", true);
  381. container.appendChild(elem);
  382. root.appendChild(container);
  383.  
  384. container = document.createElement("div");
  385. container.style.marginLeft = "120px";
  386. container.style.marginTop = "8px";
  387. elem = document.createElement("span");
  388. elem.id = "salvage_selected_button";
  389. elem.innerHTML = mktext("Salvage selected", true);
  390. elem.addEventListener("click", salvageSelectedClickCallback, false);
  391. setupButton(elem);
  392. container.appendChild(elem);
  393. root.appendChild(container);
  394. }
  395.  
  396. /* UI listeners */
  397. function selectorCallback(iid){
  398. for (var i = 0; i<items.length; i++){
  399. if (items[i].id == iid){
  400. items[i].selected = !items[i].selected;
  401. console.log("Item '" + items[i].title + "' " + (items[i].selected ? "selected":"deselected"));
  402. if (AUTO_UPDATE_COST) updateButtonsStateAndItemsCost();
  403. return items[i].selected;
  404. }
  405. }
  406. return false;
  407. }
  408.  
  409. function menuEntryClickCallback(e){
  410. var eid = parseInt(this.getAttribute("entryID"));
  411. var passed = true;
  412. var input = this.querySelector("input");
  413. if (storage.isEnabled(eid)){
  414. storage.clearFlag(eid);
  415. input.checked = false;
  416. } else {
  417. //Probe for initialization function
  418. if (MENU_ENTRIES[eid][2] != undefined){
  419. passed = MENU_ENTRIES[eid][2].call(this);
  420. }
  421. if (passed){
  422. storage.setFlag(eid);
  423. input.checked = true;
  424. }
  425. }
  426. if (passed){
  427. //Update field
  428. updateListEntries();
  429. //Store filter values
  430. storage.store();
  431. }
  432.  
  433. e.preventDefault();
  434. }
  435.  
  436. function selectMenuEntryClickCallback(e){
  437. var eid = parseInt(this.getAttribute("entryID"));
  438. var passed = true;
  439. if (SELECT_MENU_ENTRIES[eid][2] != undefined){
  440. passed = SELECT_MENU_ENTRIES[eid][2].call(this);
  441. }
  442. if (passed){
  443. //Select and deselect items based on filter function. Selection is exclusive
  444. var func = SELECT_MENU_ENTRIES[eid][1];
  445. //Since running cost check every time after selection changes before final selection made is pointless.
  446. AUTO_UPDATE_COST = false;
  447. for (var i = 0; i<items.length; i++){
  448. var state = items[i].selected;
  449. newstate = func(items[i]);
  450. if (state != newstate){
  451. //Switch state by issuing click event to target
  452. document.getElementById(items[i].id + "item_pane").click();
  453. }
  454. }
  455. AUTO_UPDATE_COST = true;
  456. updateButtonsStateAndItemsCost();
  457. }
  458. }
  459.  
  460. function sellSelectedClickCallback(e){
  461. var list = getSelectedItemsList();
  462. var totalCreds = 0;
  463. if (list.length > 0){
  464. if(confirm("Do you want to sell all selected items to eqiupment shop?")){
  465. var iter = BazaarUriIterator(list, "/?s=Bazaar&ss=es", "select_mode=item_pane&select_item=$1&select_count=1");
  466. var pwindow = createProgressWindow();
  467. pwindow.children[0].innerHTML = "Selling items to shop... [0/" + list.length + "]";
  468. requestConveyour(iter, function(){
  469. var pwindow = createProgressWindow();
  470. var d = document.createElement("div");
  471. d.innerHTML = "<span style='float:right'>Total: " + totalCreds + "<span>";
  472. pwindow.children[0].innerHTML = "Sold " + list.length + " items to shop";
  473. pwindow.children[1].appendChild(d);
  474. pwindow.children[1].scrollTop = pwindow.children[1].scrollTopMax;
  475. pwindow.children[2].innerHTML = "Click here to reload current page.";
  476. pwindow.children[2].addEventListener("click", function(){
  477. document.location = document.location.href;
  478. }, false);
  479. }, function(docroot){
  480. var creds = parseInt(CURRENT_CREDITS_REGEXP.exec(docroot.body.innerHTML)[1]);
  481. var diff = creds-current_credits;
  482. current_credits = creds;
  483. totalCreds += diff;
  484. var d = document.createElement("div");
  485. d.innerHTML = iter.get().title + "<span style='float:right'>" + diff + "</span>";
  486. var pwindow = createProgressWindow();
  487. pwindow.children[0].innerHTML = "Selling items to shop... [" + iter.position() + "/" + iter.length() + "]";
  488. pwindow.children[1].appendChild(d);
  489. pwindow.children[1].scrollTop = pwindow.children[1].scrollTopMax;
  490. });
  491. }
  492. }
  493. }
  494.  
  495. function salvageSelectedClickCallback(e){
  496. var list = getSelectedItemsList();
  497. var materials = [];
  498. materials.addMaterial = function(mat){
  499. for (var i = 0; i<this.length; i++){
  500. if (this[i][0] == mat){
  501. this[i][1]++;
  502. return;
  503. }
  504. }
  505. this.push([mat, 1]);
  506. };
  507. if (list.length > 0){
  508. if(confirm("Do you want to salvage all selected items?")){
  509. var iter = BazaarUriIterator(list, "/?s=Forge&ss=sa", "select_item=$1&select_action=salvage");
  510. var pwindow = createProgressWindow();
  511. pwindow.children[0].innerHTML = "Salvaging items... [0/" + list.length + "]";
  512. requestConveyour(iter, function(){
  513. var pwindow = createProgressWindow();
  514. var d = document.createElement("div");
  515. d.style.fontWeight = "bold";
  516. d.innerHTML = "Total:";
  517. pwindow.children[1].appendChild(d);
  518. for (var i = 0; i<materials.length; i++){
  519. d = document.createElement("div");
  520. d.innerHTML = materials[i][0] + "<span style='float:right'>x" + materials[i][1] + "</span>";
  521. pwindow.children[1].appendChild(d);
  522. }
  523. pwindow.children[0].innerHTML = "Salvaged " + list.length + " items";
  524. pwindow.children[1].scrollTop = pwindow.children[1].scrollTopMax;
  525. pwindow.children[2].innerHTML = "Click here to reload current page.";
  526. pwindow.children[2].addEventListener("click", function(){
  527. document.location = document.location.href;
  528. }, false);
  529. }, function(docroot){
  530. var item = docroot.getElementById("messagebox").getElementsByClassName("cmb6");
  531. item = SALVAGE_REGEXP.exec(item[item.length-1].textContent);
  532. if (item != null){
  533. item = item[1];
  534. } else {
  535. item = "Unknown resource";
  536. }
  537. materials.addMaterial(item);
  538. var d = document.createElement("div");
  539. d.innerHTML = iter.get().title + "<span style='float:right'>" + item + "</span>";
  540. var pwindow = createProgressWindow();
  541. pwindow.children[0].innerHTML = "Salvaging items... [" + iter.position() + "/" + iter.length() + "]";
  542. pwindow.children[1].appendChild(d);
  543. pwindow.children[1].scrollTop = pwindow.children[1].scrollTopMax;
  544. });
  545. }
  546. }
  547. }
  548.  
  549. /* */
  550. function insertCheckbox(node){
  551. var a = document.createElement("input");
  552. a.type = "checkbox";
  553. a.className = CHECKBOXES_CLASS;
  554. a.style = "margin-top: 3px";
  555. //a.setAttribute("itemID", parseInt(INTEGER_REGEXP.exec(node.id)[0]));
  556. //a.addEventListener("click", _checkboxClickEventGlue, false);
  557. node.addEventListener("click", _checkboxClickEventGlue, false);
  558. node.setAttribute("itemID", parseInt(INTEGER_REGEXP.exec(node.id)[0]));
  559. node = travelToText(node);
  560. node.insertBefore(a, node.firstChild);
  561. }
  562.  
  563. function updateListEntries(){
  564. var activeFilters = 0;
  565. var hiddenEntries = 0;
  566. for (var i = 0; i<items.length; i++) items[i].hidden = false;
  567. for (var i = 0; i<MENU_ENTRIES.length; i++){
  568. if (storage.isEnabled(i)){
  569. activeFilters++;
  570. var func = MENU_ENTRIES[i][1];
  571. for (var k = 0; k<items.length; k++){
  572. if (!items[k].hidden) items[k].hidden |= func(items[k]);
  573. }
  574. }
  575. }
  576. for (var i = 0; i<items.length; i++){
  577. if (items[i].hidden){
  578. items[i].node.parentNode.style.display = "none";
  579. hiddenEntries++;
  580. } else {
  581. items[i].node.parentNode.style.display = "";
  582. }
  583. }
  584. travelToText(filterMenuButton).innerHTML = "Filter" + (activeFilters > 0 ? ": <span style='color:red'>" + activeFilters + "</span> active":"");
  585. travelToText(document.getElementById("leftpane").firstElementChild).innerHTML = "Your inventory" + (hiddenEntries > 0 ? "[<span style='color:blue'>" + hiddenEntries + "</span> item(s) hidden]":"");
  586. updateButtonsStateAndItemsCost();
  587. }
  588.  
  589. function updateButtonsStateAndItemsCost(){
  590. var list = getSelectedItemsList();
  591. var cost = 0;
  592. for (var i = 0; i<list.length; i++){
  593. cost += list[i].cost;
  594. }
  595. document.getElementById("total_cost_field").innerHTML = mktext(cost + " c", true);
  596. var ttype = list.length > 0 ? "b":"g";
  597. swtextstyle(document.getElementById("sell_selected_button"), ttype);
  598. swtextstyle(document.getElementById("salvage_selected_button"), ttype);
  599. }
  600.  
  601. function requestConveyour(uriIterator, postExecuteCallback, progressCallback){
  602. const req = new XMLHttpRequest();
  603. req.addEventListener("load", function(){
  604. progressCallback(this.responseXML);
  605. requestConveyour(uriIterator, postExecuteCallback, progressCallback);
  606. }, false);
  607. var obj = uriIterator.next();
  608. if (obj.done){
  609. postExecuteCallback();
  610. } else {
  611. req.open("post", obj.uri, true);
  612. req.responseType = "document";
  613. req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  614. req.send(obj.post);
  615. }
  616. }
  617.  
  618. function getSelectedItemsList(){
  619. var newArr = [];
  620. for (var i = 0; i<items.length; i++){
  621. if (!items[i].hidden && items[i].selected){
  622. newArr.push(items[i]);
  623. }
  624. }
  625. return newArr;
  626. }
  627.  
  628. function createProgressWindow(){
  629. var rw = document.getElementById("progress_window");
  630. if (rw == null){
  631. rw = document.createElement("div");
  632. rw.className = "btcp";
  633. rw.innerHTML = "<div class='btc' style='font-weight:bold;margin-top:10px'></div><div class='btc' style='margin-top:10px;padding:4px;overflow-x:hidden;overflow-y:scroll;background-color:rgba(0,0,0,0.08);height:80px'></div><div class='btc' style='margin-top:5px'></div>";
  634. rw.id = "progress_window";
  635. rw.style.left = (window.innerWidth-360)/2 + "px";
  636. rw.style.top = (window.innerHeight-150)/2 + "px";
  637. document.body.appendChild(rw);
  638. }
  639. return rw;
  640. }
  641.  
  642. /* Glue */
  643. function _checkboxClickEventGlue(){
  644. //Used when inserting checkboxes as selection method
  645. this.querySelector("input").checked = selectorCallback(parseInt(this.getAttribute("itemID")));
  646. }
  647.  
  648. /* Miscellanoius functions */
  649. function sanitize(text){
  650. text = text.replace("&quot;", "\"");
  651. if (text.charAt(0) == "'" || text.charAt(0) == "\""){
  652. text = text.substring(1, text.length-1);
  653. }
  654. return text;
  655. }
  656.  
  657. function travelToText(node){
  658. var a = node.querySelector(".fd2,.fd4");
  659. while (a.firstElementChild != null && a.firstElementChild == a.firstChild){
  660. a = a.firstElementChild;
  661. }
  662. return a;
  663. }
  664.  
  665. function getOffsetTop(node){
  666. var acc = node.offsetTop;
  667. while (node.offsetParent != null){
  668. node = node.offsetParent;
  669. acc += node.offsetTop;
  670. }
  671. return acc;
  672. }
  673.  
  674. function getOffsetLeft(node){
  675. var acc = node.offsetLeft;
  676. while (node.offsetParent != null){
  677. node = node.offsetParent;
  678. acc += node.offsetLeft;
  679. }
  680. return acc;
  681. }
  682.  
  683. function setupMenu(button, menu){
  684. var id = "menu" + Math.floor(Math.random()*80000+10000);
  685. button.id = id + "_button";
  686. menu.id = id + "_panel";
  687. button.addEventListener("mouseover", function(){
  688. document.getElementById(id + "_panel").style.visibility = "visible";
  689. }, false);
  690. button.addEventListener("mouseout", function(e){
  691. if (e.clientY <= (getOffsetTop(this) + this.offsetHeight-5)){
  692. document.getElementById(id + "_panel").style.visibility = "hidden";
  693. }
  694. }, false);
  695. menu.addEventListener("mouseout", function(e){
  696. var top = getOffsetTop(this);
  697. var left = getOffsetLeft(this);
  698. if (e.clientX <= left || e.clientX >= (left + this.offsetWidth) || e.clientY <= top || e.clientY >= (top + this.offsetHeight)){
  699. this.style.visibility = "hidden";
  700. }
  701. }, false);
  702. }
  703.  
  704. function setupButton(button){
  705. const reg = /f([24])l[ba]/;
  706. button.style.cursor = "pointer";
  707. button.addEventListener("mouseover", function(){
  708. var t = this.getElementsByTagName("div");
  709. for (var i = 0; i<t.length; i++){
  710. t[i].className = t[i].className.replace(reg, "f$1la");
  711. }
  712. }, true);
  713. button.addEventListener("mouseout", function(){
  714. var t = this.getElementsByTagName("div");
  715. for (var i = 0; i<t.length; i++){
  716. t[i].className = t[i].className.replace(reg, "f$1lb");
  717. }
  718. }, true);
  719. }
  720.  
  721. function hideChildren(node){
  722. for (var i = 0; i<node.childNodes.length; i++){
  723. if (node.childNodes[i].nodeType == 1) node.childNodes[i].style.display = "none";
  724. }
  725. }
  726.  
  727. function mktext(text, isbig){
  728. const TYPESET = "0123456789.,!?%+-=/\\'\":;()[]_ ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  729. isbig = isbig || false;
  730. isbig = (isbig ? "<div class='f4lb f4":"<div class='f2lb f2");
  731. text = text.toUpperCase();
  732. var out = "";
  733. var ccode = "A".charCodeAt(0);
  734. for (var i = 0; i<text.length; i++){
  735. var t = TYPESET.indexOf(text.charAt(i));
  736. out += isbig + t + "'" + (text.charAt(i+1) == " " ? " style='width:16px'":"") + "></div>";
  737. }
  738. return out;
  739. }
  740.  
  741. function swtextstyle(node, target){
  742. var reg = /f([24])l[bag]/;
  743. target = "f$1l" + target;
  744. var t = node.getElementsByTagName("div");
  745. for (var i = 0; i<t.length; i++){
  746. t[i].className = t[i].className.replace(reg, target);
  747. }
  748. }
  749.  
  750. //"/?s=Bazaar&ss=es" shop
  751. //"/?s=Bazaar&ss=fr" forge
  752. function BazaarUriIterator(itemList, baseUri, postTemplate){
  753. var index = 0;
  754. var obj = null;
  755. return {
  756. next: function(){
  757. if (index<itemList.length){
  758. obj = { uri: baseUri + "&filter=" + itemList[index].equipType,
  759. post: postTemplate.replace("$1", itemList[index].id),
  760. done: false };
  761. index++;
  762. return obj;
  763. } else {
  764. return {done: true};
  765. }
  766. },
  767. get: function(){
  768. return itemList[index-1];
  769. },
  770. length: function(){
  771. return itemList.length;
  772. },
  773. position: function(){
  774. return index;
  775. }
  776. }
  777. }
  778.  
  779. function textFunction(text){
  780. return function(item){
  781. return item.title.contains(text);
  782. }
  783. }
  784. function regexpFunction(regexp){
  785. return function(item){
  786. return regexp.test(item.title);
  787. }
  788. }
  789. function invRegexpFunction(regexp){
  790. return function(item){
  791. return !regexp.test(item.title);
  792. }
  793. }
Advertisement
Add Comment
Please, Sign In to add comment