Klatu's Elements script

Deck manager

  1. // ==UserScript==
  2. // @name Klatu's Elements script
  3. // @namespace Klatu
  4. // @version 18
  5. // @description Deck manager
  6. // @author Klatu
  7. // @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js
  8. // @require https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.js
  9. // @require https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/1.6.0/clipboard.min.js
  10. // @require https://cdnjs.cloudflare.com/ajax/libs/notify/0.4.2/notify.min.js
  11. // @match http://www.kongregate.com/games/zanzarino/elements*
  12. // @grant none
  13. // @noframes
  14. // ==/UserScript==
  15.  
  16. jQuery.noConflict();
  17.  
  18. //main function
  19. window.addEventListener('load', () => {
  20. var copyDeckCodeClipboard,
  21. createDeckPopup,
  22. createDeckButton,
  23. createDeckCodeInput,
  24. createDeckNameInput,
  25. deckBeingDeleted,
  26. deckBeingModified,
  27. decks,
  28. decksDiv,
  29. deleteConfirmButton,
  30. deleteConfirmPopup,
  31. deleteConfirmSpan,
  32. div,
  33. exportClipboard,
  34. exportImportContainer,
  35. exportButton,
  36. importButton,
  37. importPopup,
  38. importPopupButton,
  39. importPopupInput,
  40. modifyDeckButton,
  41. modifyDeckPopup,
  42. modifyDeckCodeInput,
  43. modifyDeckNameInput,
  44. popupContainer,
  45. style,
  46. styleElement,
  47. tab,
  48. tabLink;
  49.  
  50. function showPopup(popup) {
  51. popupContainer.style.display = 'flex';
  52. for (var child of popupContainer.children) child.style.display = 'none';
  53. popup.style.display = 'block';
  54. }
  55.  
  56. function hidePopups() {
  57. popupContainer.style.display = 'none';
  58. }
  59.  
  60. function createCloseCross() {
  61. var cross = document.createElement('span');
  62. cross.className = 'klatu-close-cross';
  63. cross.addEventListener('click', hidePopups);
  64. return cross;
  65. }
  66.  
  67. function saveDecks() {
  68. localStorage.setItem('elementsDecks', JSON.stringify(decks));
  69. }
  70.  
  71. function createDeck() {
  72. var deck = {
  73. name: createDeckNameInput.value,
  74. code: createDeckCodeInput.value
  75. };
  76. decks.push(deck);
  77. saveDecks();
  78. hidePopups();
  79. updateDecksDiv();
  80. }
  81.  
  82. function focusWhenUserPressesTab(e) {
  83. if (e.which === 9 || e.keyCode === 9) {
  84. e.preventDefault();
  85. this.focus();
  86. }
  87. }
  88.  
  89. function createForm(submitFunction) {
  90. function submit(e) {
  91. if (e.which === 13 || e.keyCode === 13) {
  92. e.preventDefault();
  93. submitFunction();
  94. }
  95. }
  96.  
  97. //link the last element with the first one and add the submit listener to it
  98. arguments[arguments.length - 1].addEventListener('keydown', focusWhenUserPressesTab.bind(arguments[1]));
  99. arguments[arguments.length - 1].addEventListener('keydown', submit);
  100. //link the each of the other elements with the next ones
  101. for (var i = 1; arguments[i + 1]; i++) {
  102. arguments[i].addEventListener('keydown', focusWhenUserPressesTab.bind(arguments[i + 1]));
  103. arguments[i].addEventListener('keydown', submit);
  104. }
  105. }
  106.  
  107. function modifyDeck() {
  108. deckBeingModified.name = modifyDeckNameInput.value;
  109. deckBeingModified.code = modifyDeckCodeInput.value;
  110. saveDecks();
  111. hidePopups();
  112. updateDecksDiv();
  113. }
  114.  
  115. function deleteDeck() {
  116. decks.splice(decks.indexOf(deckBeingDeleted), 1);
  117. saveDecks();
  118. updateDecksDiv();
  119. hidePopups();
  120. }
  121.  
  122. function showCreateDeckPopup() {
  123. createDeckNameInput.value = '';
  124. createDeckCodeInput.value = '';
  125. showPopup(createDeckPopup);
  126. createDeckNameInput.focus();
  127. }
  128.  
  129. function copyDeckCode() {
  130. if (!Clipboard.isSupported()) {
  131. alert('Wait for the script\'s next version please :(');
  132. }
  133. }
  134.  
  135. function showModifyDeckPopup() {
  136. var index = this.parentNode.parentNode.getAttribute('data-klatu-index');
  137. deckBeingModified = decks[index];
  138. modifyDeckNameInput.value = deckBeingModified.name;
  139. modifyDeckCodeInput.value = deckBeingModified.code;
  140. showPopup(modifyDeckPopup);
  141. }
  142.  
  143. function showDeleteConfirmPopup() {
  144. var index = this.parentNode.parentNode.getAttribute('data-klatu-index');
  145. deckBeingDeleted = decks[index];
  146. deleteConfirmSpan.innerText = 'Do you want to delete the deck "'+deckBeingDeleted.name+'"?';
  147. showPopup(deleteConfirmPopup);
  148. }
  149.  
  150. function returnElementWhenItExists(id) {
  151. return new Promise((resolve, reject) => {
  152. var element = $(id),
  153. interval;
  154. if (element) resolve(element);
  155. interval = setInterval(() => {
  156. var element = $(id);
  157. if (element) {
  158. clearInterval(interval);
  159. resolve(element);
  160. }
  161. }, 1000);
  162. });
  163. }
  164.  
  165. function updateDecksDiv() {
  166. for (var i = decksDiv.children.length - 1; 0 <= i; i--) decksDiv.children[i].remove();
  167. for (i = 0; i < decks.length; i++) {
  168. var deck = decks[i];
  169. var deckDiv = document.createElement('div');
  170. var deckNameDiv = document.createElement('div');
  171. var deckActionsDiv=document.createElement('div');
  172. var deckCopySpan = document.createElement('span');
  173. var deckModifySpan = document.createElement('span');
  174. var deckDeleteSpan = document.createElement('span');
  175. deckDiv.setAttribute('data-klatu-index', i);
  176. deckDiv.className = 'klatu-deck-div klatu-flex klatu-spaced-flex';
  177. deckNameDiv.innerText = deck.name;
  178. deckNameDiv.className = 'klatu-deck-name-div';
  179. deckDiv.appendChild(deckNameDiv);
  180. deckCopySpan.setAttribute('data-clipboard-text', deck.code);
  181. deckCopySpan.addEventListener('click', copyDeckCode);
  182. deckActionsDiv.appendChild(deckCopySpan);
  183. deckActionsDiv.className='klatu-deck-actions-div';
  184. deckModifySpan.className = 'klatu-deck-modify-span';
  185. deckModifySpan.addEventListener('click', showModifyDeckPopup);
  186. deckActionsDiv.appendChild(deckModifySpan);
  187. deckCopySpan.className = 'klatu-deck-copy-span';
  188. deckDeleteSpan.className = 'klatu-deck-delete-span';
  189. deckDeleteSpan.addEventListener('click', showDeleteConfirmPopup);
  190. deckActionsDiv.appendChild(deckDeleteSpan);
  191. deckDiv.appendChild(deckActionsDiv);
  192. if (i % 2) deckDiv.className += ' even';
  193. decksDiv.appendChild(deckDiv);
  194. }
  195. }
  196.  
  197. function importDecks(event){
  198. try{
  199. var decksBeingImported=JSON.parse(importPopupInput.value);
  200. if(decksBeingImported instanceof Array){
  201. for(var deckBeingImported of decksBeingImported){
  202. isInDecks=false;
  203. for(var i=0; i<decks.length&&!isInDecks; i++){
  204. var deck=decks[i];
  205. if(deck.name===deckBeingImported.name&&deck.code===deckBeingImported.code) isInDecks=true;
  206. }
  207. if(!isInDecks) decks.push(deckBeingImported);
  208. }
  209. saveDecks();
  210. updateDecksDiv();
  211. hidePopups();
  212. }
  213. else jQuery.notify("Invalid code.", "error");
  214. }
  215. catch(error){
  216. jQuery.notify("Invalid code.", "error");
  217. }
  218. }
  219.  
  220. //add own style
  221. style =
  222. '.klatu-close-cross {' +
  223. ' position: absolute;' +
  224. ' top: 4px;' +
  225. ' right: 4px;' +
  226. ' background-color: #E95420;' +
  227. ' border-radius: 50%;' +
  228. ' width: 18px;' +
  229. ' height: 18px;' +
  230. ' text-align: center;' +
  231. ' line-height: 18px;' +
  232. ' cursor: pointer;' +
  233. '}' +
  234. '.klatu-close-cross:before {' +
  235. ' content: "×";' +
  236. ' font-size: 15px;' +
  237. '}' +
  238. '.klatu-popup {' +
  239. ' padding: 26px 26px 8px 26px;' +
  240. ' position: relative;' +
  241. ' background-color: #333;' +
  242. ' text-align: center;' +
  243. ' font-size: 22px;' +
  244. ' color: white;' +
  245. '}' +
  246. '.klatu-popup>input {' +
  247. ' margin: 0 auto;' +
  248. ' display: block;' +
  249. ' width: 750px;' +
  250. ' font-family: monospace;' +
  251. '}' +
  252. '.klatu-flex {' +
  253. ' display: flex;' +
  254. ' align-items: center;' +
  255. '}' +
  256. '.klatu-centered-flex {'+
  257. ' justify-content: center;' +
  258. '}'+
  259. '.klatu-spaced-flex {'+
  260. ' justify-content: space-between;' +
  261. '}'+
  262. '.klatus-elements-script-button {' +
  263. ' display: block;' +
  264. ' padding: 6px 12px;' +
  265. ' margin: 8px auto 0 auto;' +
  266. ' font-size: 14px;' +
  267. ' font-weight: 400;' +
  268. ' line-height: 1.42857143;' +
  269. ' text-align: center;' +
  270. ' white-space: nowrap;' +
  271. ' vertical-align: middle;' +
  272. ' -ms-touch-action: manipulation;' +
  273. ' touch-action: manipulation;' +
  274. ' cursor: pointer;' +
  275. ' -webkit-user-select: none;' +
  276. ' -moz-user-select: none;' +
  277. ' -ms-user-select: none;' +
  278. ' user-select: none;' +
  279. ' width: 120px;' +
  280. ' background-image: none;' +
  281. ' border: 1px solid transparent;' +
  282. ' border-radius: 4px;' +
  283. ' color: #fff;' +
  284. ' background-color: #337ab7;' +
  285. ' border-color: #2e6da4;' +
  286. '}' +
  287. '.klatus-elements-script-button.export, .klatus-elements-script-button.import {' +
  288. ' background-color: #666;' +
  289. ' border-color: #af9052;' +
  290. '}' +
  291. '.klatu-deck-actions-div>span {' +
  292. ' font-size: 20px;' +
  293. ' font-weight: bold;' +
  294. ' padding: 1px 3px 1px 3px;' +
  295. ' cursor: pointer;' +
  296. '}' +
  297. '.klatu-deck-div.even {' +
  298. ' background-color: #333;' +
  299. '}' +
  300. '.klatu-deck-delete-span:before {' +
  301. ' content: "×";' +
  302. ' color: red;' +
  303. '}' +
  304. '.klatu-deck-copy-span:before {' +
  305. ' content: "?";' +
  306. ' color: #0275d8' +
  307. '}' +
  308. '.klatu-deck-modify-span:before {' +
  309. ' content: "✍";' +
  310. ' color: #f0ad4e' +
  311. '}' +
  312. '.tabpane {' +
  313. ' height: 489px' +
  314. '}' +
  315. '#klatu-popup-container {' +
  316. ' justify-content: center;' +
  317. ' align-items: center;' +
  318. ' position: fixed;' +
  319. ' z-index: 9999;' +
  320. ' top: 0;' +
  321. ' left: 0;' +
  322. ' width: 100vw;' +
  323. ' height: 100vh;' +
  324. ' background-color: rgba(0, 0, 0, 0.75);' +
  325. '}' +
  326. '.notiyjs-corner {' +
  327. ' z-index: 99999;' +
  328. '}'+
  329. '.klatu-deck-div {' +
  330. ' font-size: 15px;' +
  331. ' font-family: sans-serif;' +
  332. ' padding: 6px;' +
  333. ' background-color: #111;' +
  334. ' color: #eee;' +
  335. '}';
  336. styleElement = document.createElement('style');
  337. styleElement.innerHTML = style;
  338. document.head.appendChild(styleElement);
  339.  
  340. //create the popup container
  341. popupContainer = document.createElement('div');
  342. popupContainer.id = 'klatu-popup-container';
  343. popupContainer.style.display = 'none';
  344. popupContainer.addEventListener('click', function(e) {
  345. if (e.target === this) hidePopups();
  346. });
  347. document.body.appendChild(popupContainer);
  348.  
  349. //hide visible popups when the user presses escape
  350. window.addEventListener('keyup', (e) => {
  351. if (e.which === 27 || e.keyCode === 27) hidePopups();
  352. });
  353.  
  354. //create the delete confirm popup
  355. deleteConfirmPopup = document.createElement('div');
  356. deleteConfirmPopup.className = 'klatu-popup';
  357. deleteConfirmSpan = document.createElement('span');
  358. deleteConfirmButton = document.createElement('button');
  359. deleteConfirmButton.className = 'klatus-elements-script-button';
  360. deleteConfirmButton.innerText = 'Yes';
  361. deleteConfirmButton.addEventListener('click', deleteDeck);
  362. deleteConfirmPopup.appendChild(deleteConfirmSpan);
  363. deleteConfirmPopup.appendChild(deleteConfirmButton);
  364. deleteConfirmPopup.appendChild(createCloseCross());
  365. popupContainer.appendChild(deleteConfirmPopup);
  366.  
  367. //create the create deck popup
  368. createDeckPopup = document.createElement('div');
  369. createDeckPopup.className = 'klatu-popup';
  370. createDeckNameInput = document.createElement('input');
  371. createDeckNameInput.placeholder = 'Enter your deck\'s name';
  372. createDeckPopup.appendChild(createDeckNameInput);
  373. createDeckCodeInput = document.createElement('input');
  374. createDeckCodeInput.placeholder = 'Enter your deck\'s code';
  375. createDeckPopup.appendChild(createDeckCodeInput);
  376. createDeckButton = document.createElement('button');
  377. createDeckButton.className = 'klatus-elements-script-button';
  378. createDeckButton.innerText = 'Add deck';
  379. createDeckButton.addEventListener('click', createDeck);
  380. createDeckPopup.appendChild(createDeckButton);
  381. createDeckPopup.appendChild(createCloseCross());
  382. popupContainer.appendChild(createDeckPopup);
  383. createForm(createDeck, createDeckNameInput, createDeckCodeInput);
  384.  
  385. //create the modify deck popup
  386. modifyDeckPopup = document.createElement('div');
  387. modifyDeckPopup.className = 'klatu-popup';
  388. modifyDeckNameInput = document.createElement('input');
  389. modifyDeckNameInput.placeholder = 'Enter your deck\'s new name';
  390. modifyDeckPopup.appendChild(modifyDeckNameInput);
  391. modifyDeckCodeInput = document.createElement('input');
  392. modifyDeckCodeInput.placeholder = 'Enter your deck\'s new code';
  393. modifyDeckPopup.appendChild(modifyDeckCodeInput);
  394. modifyDeckButton = document.createElement('button');
  395. modifyDeckButton.className = 'klatus-elements-script-button';
  396. modifyDeckButton.innerText = 'Modify deck';
  397. modifyDeckButton.addEventListener('click', modifyDeck);
  398. modifyDeckPopup.appendChild(modifyDeckButton);
  399. modifyDeckPopup.appendChild(createCloseCross());
  400. popupContainer.appendChild(modifyDeckPopup);
  401. createForm(modifyDeck, modifyDeckNameInput, modifyDeckCodeInput);
  402.  
  403. //create the deck manager div
  404. div = document.createElement('div');
  405. div.style.display='none';
  406. div.id = 'klatus-elements-script-tab-pane';
  407. div.className = 'tabpane';
  408.  
  409. //create the DECKS tab
  410. tab = document.createElement('li');
  411. tab.id = 'klatus-elements-script-tab';
  412. tab.className = 'tab';
  413. tabLink = document.createElement('a');
  414. tabLink.innerText = 'Decks';
  415. tabLink.key = div.id;
  416. tabLink.href = '#' + div.id;
  417. tabLink.addEventListener('click', function(e) {
  418. holodeck._tabs.setActiveTab(this);
  419. e.preventDefault();
  420. });
  421. tab.appendChild(tabLink);
  422.  
  423. //load saved decks
  424. decks = localStorage.getItem('elementsDecks') ? JSON.parse(localStorage.getItem('elementsDecks')) : [];
  425.  
  426. //create the decks div
  427. decksDiv = document.createElement('div');
  428. div.appendChild(decksDiv);
  429. jQuery(decksDiv).sortable({
  430. update: (event, deckDivObject) => {
  431. var item = deckDivObject.item;
  432. var deck = decks.splice(item[0].getAttribute('data-klatu-index'), 1)[0];
  433. decks.splice(item.index(), 0, deck);
  434. saveDecks();
  435. updateDecksDiv();
  436. },
  437. axis: 'y'
  438. });
  439. updateDecksDiv();
  440.  
  441. //create the add deck button
  442. var button = document.createElement('button');
  443. button.innerText = 'Add deck';
  444. button.className = 'klatus-elements-script-button';
  445. button.addEventListener('click', showCreateDeckPopup);
  446. div.appendChild(button);
  447.  
  448. //create the export/import container
  449. exportImportContainer = document.createElement('div');
  450. exportImportContainer.className = 'klatu-flex klatu-centered-flex';
  451. div.appendChild(exportImportContainer);
  452.  
  453. //create the export button
  454. exportButton = document.createElement('button');
  455. exportButton.className = 'export klatus-elements-script-button';
  456. exportButton.innerText = 'Export decks';
  457. exportImportContainer.appendChild(exportButton);
  458.  
  459. //create the import button
  460. importButton = document.createElement('button');
  461. importButton.className = 'import klatus-elements-script-button';
  462. importButton.innerText = 'Import decks';
  463. importButton.addEventListener('click', ()=>{
  464. showPopup(importPopup);
  465. importPopupInput.value = '';
  466. importPopupInput.focus();
  467. });
  468. exportImportContainer.appendChild(importButton);
  469.  
  470. //create the import popup
  471. importPopup = document.createElement('div');
  472. importPopup.className = 'klatu-popup';
  473. importPopupInput = document.createElement('input');
  474. importPopupInput.placeholder = 'Enter your decks\' import code';
  475. importPopupInput.addEventListener('keydown', e=>{
  476. if(e.which===13||e.keyCode===13){ //if the user pressed enter...
  477. importDecks();
  478. }
  479. });
  480. importPopup.appendChild(importPopupInput);
  481. importPopupButton = document.createElement('button');
  482. importPopupButton.className = 'klatus-elements-script-button';
  483. importPopupButton.innerText = 'Import';
  484. importPopupButton.addEventListener('click', importDecks);
  485. importPopup.appendChild(importPopupButton);
  486. importPopup.appendChild(createCloseCross());
  487. popupContainer.appendChild(importPopup);
  488.  
  489. //append my elements to the body when the appropriate elements are ready
  490. returnElementWhenItExists('main_tab_set').then((element) => element.appendChild(tab));
  491. returnElementWhenItExists('kong_game_ui').then((element) => element.appendChild(div));
  492.  
  493. //add the tab and the div to the holodeck
  494. new Promise((resolve, reject) => {
  495. var interval;
  496. if (window.holodeck && window.holodeck._tabs) resolve(window.holodeck._tabs);
  497. interval = setInterval(() => {
  498. if (window.holodeck && window.holodeck._tabs) {
  499. clearInterval(interval);
  500. resolve(window.holodeck._tabs);
  501. }
  502. }, 1000);
  503. }).then(tabs => {
  504. tabs.links.push(tabLink);
  505. tabs.containers._object[div.id] = div;
  506. });
  507.  
  508. //instantiate Clipboard to allow copying deck codes by clicking the appropriate icons
  509. copyDeckCodeClipboard = new Clipboard('.klatu-deck-copy-span');
  510. copyDeckCodeClipboard.on('success', () => jQuery.notify("Your deck code has been copied to your clipboard.", "success"));
  511. copyDeckCodeClipboard.on('error', () => jQuery.notify("There was an error while copying your deck code to your clipboard.", "error"));
  512.  
  513. //instantiate Clipboard to allow exporting all the user's decks
  514. exportClipboard = new Clipboard(exportButton, {
  515. text: ()=>JSON.stringify(decks)
  516. });
  517. exportClipboard.on('success', () => jQuery.notify("Your export code has been copied to your clipboard.", "success"));
  518. exportClipboard.on('error', () => jQuery.notify("There was an error while copying your export code to your clipboard.", "error"));
  519. });

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址