You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

365 lines
16 KiB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
  1. <!doctype html>
  2. <html>
  3. <head>
  4. <title>Orna Tools - atr0phy.net</title>
  5. <meta charset="utf-8">
  6. <meta name="viewport" contents="width=device-width, initial-scale=1">
  7. <!-- <link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}"> -->
  8. <!-- UIkit CSS -->
  9. <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/uikit@3.2.4/dist/css/uikit.min.css" />
  10. <!-- UIkit JS -->
  11. <script src="https://cdn.jsdelivr.net/npm/uikit@3.2.4/dist/js/uikit.min.js"></script>
  12. <script src="https://cdn.jsdelivr.net/npm/uikit@3.2.4/dist/js/uikit-icons.min.js"></script>
  13. <script src="https://cdn.jsdelivr.net/combine/npm/tablesort@5.2.0,npm/tablesort@5.2.0/src/sorts/tablesort.number.min.js"></script>
  14. </head>
  15. <body>
  16. <nav class="uk-navbar-container" uk-navbar>
  17. <div class="uk-navbar-center">
  18. <a href="" class="uk-navbar-item uk-logo">Orna Tools - Equipment Combinations</a>
  19. </div>
  20. </nav>
  21. <div class="uk-container">
  22. <div id="help-container" class="uk-padding-large uk-text-center uk-text-muted uk-margin-large-left uk-margin-large-right">
  23. <div>Use the three tabs to input your options for each equipment slot (head/chest/leg). Click the calculate button to populate a table with possible combinations. Click on the column headers to sort results.<br/><br/><strong>Ctrl+Enter</strong> adds a new row to existing table, or use the green <strong>+</strong> to input additional items.</div>
  24. </div>
  25. <div id="equipment-container" class="uk-padding-large">
  26. <ul class="uk-flex-center" uk-tab>
  27. <li class="uk-active" tbl="head-table"><a href="">Head</a></li>
  28. <li tbl="chest-table"><a href="">Chest</a></li>
  29. <li tbl="leg-table"><a href="">Leg</a></li>
  30. </ul>
  31. <ul class="uk-switcher">
  32. {% for slot in ["Head", "Chest", "Leg"] %}
  33. <li>
  34. <div class="uk-padding-large uk-padding-remove-vertical">
  35. <table id="{{ slot | lower }}-table" class="uk-table">
  36. <caption>{{ slot }} Gear</caption>
  37. <thead>
  38. <tr>
  39. <th class="uk-table-shrink"></th>
  40. <th class="uk-table-expand">Item Name</th>
  41. <th class="uk-table-shrink">Defense</th>
  42. <th class="uk-table-shrink">Resistance</th>
  43. <th class="uk-table-shring"></th>
  44. </tr>
  45. </thead>
  46. <tbody>
  47. <tr>
  48. <td>1</td>
  49. <td><input type="text" class="uk-input" autocomplete="off"/></td>
  50. <td><input type="text" class="uk-input" autocomplete="off"/></td>
  51. <td><input type="text" class="uk-input" autocomplete="off"/></td>
  52. <td><a class="uk-icon-button del-row-button" uk-icon="icon:minus-circle;ratio:1"></a></td>
  53. </tr>
  54. </tbody>
  55. </table>
  56. <div class="uk-text-center">
  57. <a id="{{ slot | lower }}-button" class="uk-icon-button add-row-button" uk-icon="icon:plus-circle;ratio:2"></a>
  58. </div>
  59. </div>
  60. </li>
  61. {% endfor %}
  62. </ul>
  63. </div>
  64. <div class="uk-text-center uk-margin-bottom">
  65. <button id="clear-button" class="uk-button uk-button-danger">Clear</button>
  66. <button id="calculate-button" class="uk-button uk-button-primary">Calculate</button>
  67. </div>
  68. <div id="results-panel" class="uk-section uk-overflow-auto" hidden>
  69. <hr class="uk-divider-icon" />
  70. <table id="results-table" class="uk-table uk-table-divider uk-table-striped uk-table-hover">
  71. <thead>
  72. <th data-sort-default>Total</th>
  73. <th>Defense</th>
  74. <th>Resistance</th>
  75. <th class="uk-table-expand" data-sort-method='none'>Head</th>
  76. <th class="uk-table-expand" data-sort-method='none'>Chest</th>
  77. <th class="uk-table-expand" data-sort-method='none'>Legs</th>
  78. </thead>
  79. <tbody></tbody>
  80. </table>
  81. </div>
  82. <!-- Footer -->
  83. <footer class="uk-text-center uk-margin-large-top uk-margin-small-bottom">
  84. &copy; <script>document.write(new Date().getFullYear());</script> by <a href="http://binaryatrocity.name">binaryatrocity</a>
  85. &nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;
  86. Created for the <span class="uk-text-success">Legends of Palisma</span> Kingdom
  87. &nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;
  88. <a href="http://playorna.com">OrnaRPG</a>
  89. </footer>
  90. </div>
  91. </body>
  92. <script>
  93. // Support adding rows to the equipment tables
  94. function addEquipmentTableRow(findByQuery=false) {
  95. let input_element = document.createElement("input");
  96. input_element.className="uk-input";
  97. input_element.type = "text";
  98. // Create the delete button
  99. let delete_button = document.createElement("a");
  100. delete_button.className="uk-icon-button del-row-button";
  101. delete_button.setAttribute("uk-icon", "icon:minus-circle;ratio:1");
  102. delete_button.addEventListener("click", deleteEquipmentTableRow, false);
  103. // If called manually, find specific table, otherwise determine based on event element
  104. let tbody = findByQuery ? document.querySelector(findByQuery) : this.parentElement.previousElementSibling.children[2];
  105. let new_row = tbody.insertRow(-1);
  106. // Append all of the child cells needed
  107. new_row.insertCell(0).appendChild(delete_button);
  108. new_row.insertCell(0).appendChild(input_element.cloneNode());
  109. new_row.insertCell(0).appendChild(input_element.cloneNode());
  110. new_row.insertCell(0).appendChild(input_element.cloneNode());
  111. new_row.insertCell(0).appendChild(document.createTextNode(tbody.children.length))
  112. if(findByQuery) {
  113. // If this was a hotkey, then focus the new field
  114. new_row.children[1].firstChild.focus();
  115. }
  116. }
  117. // Support deleting rows from the equipment table
  118. function deleteEquipmentTableRow() {
  119. this.parentElement.parentElement.remove();
  120. }
  121. // Process results and display table
  122. function processEquipmentResults(results) {
  123. var results_tbody = document.querySelector("table#results-table > tbody");
  124. for(result of results) {
  125. let new_row = results_tbody.insertRow(-1);
  126. // Append all of the child cells
  127. new_row.insertCell(0).appendChild(document.createTextNode(result['eq'][2]));
  128. new_row.insertCell(0).appendChild(document.createTextNode(result['eq'][1]));
  129. new_row.insertCell(0).appendChild(document.createTextNode(result['eq'][0]));
  130. new_row.insertCell(0).appendChild(document.createTextNode(result['res']));
  131. new_row.insertCell(0).appendChild(document.createTextNode(result['def']));
  132. new_row.insertCell(0).appendChild(document.createTextNode(result['def'] + result['res']));
  133. }
  134. table_sort.refresh();
  135. document.querySelector("div#results-panel").hidden = false;
  136. results_tbody.scrollIntoView();
  137. }
  138. // Send data to backend
  139. function calculateEquipment() {
  140. let data = gatherEquipmentData();
  141. // Store data in localStorage
  142. localStorage.setItem('eq_data', JSON.stringify(data));
  143. // Clear out existing table rows
  144. for(let row of document.querySelectorAll("table#results-table > tbody > tr")) {
  145. row.remove();
  146. }
  147. fetch('/results', {
  148. method: 'POST',
  149. headers: { 'Content-Type': 'application/json' },
  150. body: JSON.stringify(data)
  151. }).then((response) => response.json()).then((data) => {
  152. processEquipmentResults(data);
  153. }).catch((error) => {
  154. console.log(error);
  155. alert("There was a problem...");
  156. });
  157. }
  158. function gatherEquipmentData() {
  159. var eq_head = [], eq_chest = [], eq_legs = [];
  160. // Gather head gear
  161. for(let row of document.querySelectorAll("table#head-table > tbody > tr")) {
  162. eq_head.push([
  163. row.children[1].firstChild.value,
  164. parseInt(row.children[2].firstChild.value) || 0,
  165. parseInt(row.children[3].firstChild.value) || 0
  166. ]);
  167. }
  168. // Gather chest gear
  169. for(let row of document.querySelectorAll("table#chest-table > tbody > tr")) {
  170. eq_chest.push([
  171. row.children[1].firstChild.value,
  172. parseInt(row.children[2].firstChild.value) || 0,
  173. parseInt(row.children[3].firstChild.value) || 0
  174. ]);
  175. }
  176. // Gather leg gear
  177. for(let row of document.querySelectorAll("table#leg-table > tbody > tr")) {
  178. eq_legs.push([
  179. row.children[1].firstChild.value,
  180. parseInt(row.children[2].firstChild.value) || 0,
  181. parseInt(row.children[3].firstChild.value) || 0
  182. ]);
  183. }
  184. let data = {
  185. "head": eq_head,
  186. "chest": eq_chest,
  187. "legs": eq_legs
  188. };
  189. return data;
  190. }
  191. function clearExistingData() {
  192. localStorage.clear();
  193. // Clear out existing table rows
  194. for(let row of document.querySelectorAll("table > tbody > tr")) {
  195. row.remove();
  196. }
  197. }
  198. function loadExistingData() {
  199. var data = localStorage.getItem('eq_data');
  200. function appendToTable(eq, table_id) {
  201. let input_element = document.createElement("input");
  202. input_element.className="uk-input";
  203. input_element.type = "text";
  204. input_element.autocomplete = "off";
  205. // Create the delete button
  206. let delete_button = document.createElement("a");
  207. delete_button.className="uk-icon-button del-row-button";
  208. delete_button.setAttribute("uk-icon", "icon:minus-circle;ratio:1");
  209. delete_button.addEventListener("click", deleteEquipmentTableRow, false);
  210. let query = "table#" + table_id + " > tbody";
  211. let tbody = document.querySelector(query);
  212. let new_row = tbody.insertRow(-1);
  213. // Append all of the child cells needed
  214. new_row.insertCell(0).appendChild(delete_button);
  215. input_element.value = eq[2];
  216. new_row.insertCell(0).appendChild(input_element.cloneNode());
  217. input_element.value = eq[1];
  218. new_row.insertCell(0).appendChild(input_element.cloneNode());
  219. input_element.value = eq[0];
  220. new_row.insertCell(0).appendChild(input_element.cloneNode());
  221. new_row.insertCell(0).appendChild(document.createTextNode(tbody.children.length))
  222. }
  223. if(data) {
  224. data = JSON.parse(data);
  225. // Remove existing rows from all tables
  226. clearExistingData();
  227. // Populate new rows in all eq tables
  228. for(let hg of data['head']) {
  229. appendToTable(hg, "head-table");
  230. }
  231. for(let cg of data['chest']) {
  232. appendToTable(cg, "chest-table");
  233. }
  234. for(let lg of data['legs']) {
  235. appendToTable(lg, "leg-table");
  236. }
  237. }
  238. }
  239. function confirmDataCleanse() {
  240. if(confirm("Are you sure you want to clear all existing data?")) {
  241. clearExistingData();
  242. }
  243. }
  244. function listenForHotkeys(e) {
  245. if(e.ctrlKey && e.which == 13) {
  246. // Determine the active tab
  247. let tbl_id = "table#" + document.querySelector(".uk-active").getAttribute("tbl") + " > tbody";
  248. addEquipmentTableRow(tbl_id);
  249. }
  250. }
  251. // Add event listeners to our table buttons
  252. const add_row_buttons = document.querySelectorAll("a.add-row-button");
  253. for(let button of add_row_buttons) {
  254. button.addEventListener("click", addEquipmentTableRow, false);
  255. }
  256. const del_row_buttons = document.querySelectorAll("a.del-row-button");
  257. for(let button of del_row_buttons) {
  258. button.addEventListener("click", deleteEquipmentTableRow, false);
  259. }
  260. // Add event listener to Calculate button, call backend
  261. document.querySelector("#calculate-button").addEventListener("click", calculateEquipment, false);
  262. document.querySelector("#clear-button").addEventListener("click", confirmDataCleanse, false);
  263. // Enable sorting for our results table
  264. var table_sort = new Tablesort(document.querySelector("table#results-table"), {descending: true});
  265. // Configure keyboard hotkeys
  266. document.onkeyup = listenForHotkeys;
  267. // Load any existing data from LocalStorage
  268. loadExistingData();
  269. </script>
  270. <style type="text/css">
  271. table:not(#results-table) > tbody > tr > td:first-child {
  272. color: #999;
  273. }
  274. div > a.add-row-button {
  275. color: #32d296;
  276. }
  277. table a.del-row-button {
  278. color: #f0506e;
  279. }
  280. table#results-table > tbody > tr > td:first-child {
  281. font-weight: bold;
  282. color: #6c9f12;
  283. }
  284. /* Result Table from Tablesort.css */
  285. th:not(.no-sort) {
  286. cursor: pointer;
  287. }
  288. th[role=columnheader]:not(.no-sort):after {
  289. content: '';
  290. float: right;
  291. margin-top: 7px;
  292. border-width: 0 4px 4px;
  293. border-style: solid;
  294. border-color: #404040 transparent;
  295. visibility: hidden;
  296. opacity: 0;
  297. -ms-user-select: none;
  298. -webkit-user-select: none;
  299. -moz-user-select: none;
  300. user-select: none;
  301. }
  302. th[aria-sort=ascending]:not(.no-sort):after {
  303. border-bottom: none;
  304. border-width: 4px 4px 0;
  305. }
  306. th[aria-sort]:not(.no-sort):after {
  307. visibility: visible;
  308. opacity: 0.4;
  309. }
  310. th[role=columnheader]:not(.no-sort):hover:after {
  311. visibility: visible;
  312. opacity: 1;
  313. }
  314. </style>
  315. </html>