Anime Website Buttons Plus

A script that adds buttons on Anime Planet, MAL and Anilist for searching various sites.

当前为 2020-03-31 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @author Deathwing
  3. // @name Anime Website Buttons Plus
  4. // @include https://www.anime-planet.com/anime/*
  5. // @include http://myanimelist.net/anime/*
  6. // @include https://myanimelist.net/anime/*
  7. // @include https://anilist.co/anime/*
  8. // @include https://anilist.co/search/*
  9. // @exclude https://www.anime-planet.com/anime/
  10. // @exclude https://www.anime-planet.com/anime/all?name=*
  11. // @exclude https://www.anime-planet.com/anime/recommendations/*
  12. // @description A script that adds buttons on Anime Planet, MAL and Anilist for searching various sites.
  13. // @version 2.5.7
  14. // @grant GM_setValue
  15. // @grant GM_getValue
  16. // @grant GM_listValues
  17. // @grant GM_deleteValue
  18. // @namespace https://greasyfork.org/users/18375
  19. // ==/UserScript==
  20.  
  21.  
  22. //Find h1
  23. var header;
  24. var host = document.location.host;
  25. var malHost = 'myanimelist.net';
  26. var apHost = 'www.anime-planet.com';
  27. var alHost = 'anilist.co';
  28.  
  29. var hideList = [];
  30.  
  31. var buttDivLeft = 0;
  32. var autoHide = GM_getValue('setting:autoHide', false);
  33.  
  34. var iconEyeGray = 'https://previews.dropbox.com/p/thumb/AAuWCCOL6JyGmMweL1F-_5DiAS2zJYRa5Lir0SbwC5DvS_0nQEwjuJvONWL8a5aBxxvBhMbmATHXk6HOq_p16qq_FCjHezpZK-WG59CrRBfTl2mY7-e1lE-Ce2r1JEgpQFmo0LllAXnpcbeH7-68AxkfuMN4g6ChfpHCoaX7r9YH8MCQVu01ect1cCdqHDYlJBqgRWUrbTjwrlIlV9Y545Eldz5Xp948EIoHnNVeov_ybS2u-oGDZWwFtN5FLGCtJTyXK2sLylpQ8cvH7DVl0DAVcGO0YF6_RqIwbCpt-yCS58gfClH3lTEmPKunqrBwfNQe0SxXvyXTr-1GbCDiP_Lq/p.png?size=2048x1536&size_mode=3';
  35. var iconEye = 'https://previews.dropbox.com/p/thumb/AAvAf0hVyAwc9SRprGbA731CezYJ5amifW_2ApUxlRa0i98WlQoS13M3EQNGLv9kNTHsle6RsiUTlNZPtimWZM1ccs4i0orerrn0SwuPcsaGnU0cKho2IWWE-mEAhhoh779w04r8yWqJrAZZcYiy1mLZINV6SKIRq797-RW0gsZXZ8tgvcWa_nIAF2cpttnklJ93I0h2FFtmlrdX7WCzUBo2eML71mGMfRebI4b9wYnfFNT_77xWPeA1RoOaFLkYBKWF3wIsfnSCVGjodq_yHC6xjJJ2mwSbiRxuTO0glpiiT0AGN3hUTD0th5IbY5EPF-R4H1zPJMnPScAKax9RlrW5/p.png?fv_content=true&size_mode=5';
  36. var arrowIcon = 'https://previews.dropbox.com/p/thumb/AAu9RWVjB27yYf1IBTB2kIUi34QfZswYDWKQ4e5_vutzZSLP6q0ju6FtFEo6uqIoRbIy3yS2DxS6iiKhJP7rwtbbaWmNqdFBA1gmw4Xk7wAU3stUxDgxTXfGPW5lAI6af3ndevX2PRm4aqPcE_jcvWtP6CdKGOCW08b1ej4dxF6i62M97T96fered6dQYu7xw8HtuXsuHG1wndmjr71iwgGYOa40ucoHunZ-SkPiUqy6PQkG3frzFn8fTvaee1gR_8Jx5Be_lwh3A9so8ZvCaODcjuJYL54OzfUm9o19jKbpWVEnDQuwMIACydwIbxmRxy8IOtPzVm303mOT8Y1rONnT/p.png?size=2048x1536&size_mode=3';
  37. var editIcon = 'https://previews.dropbox.com/p/thumb/AAs_uEIlA0XGqQKA3-9SaVvSNTEfLD9T59ZRlYGPzHmrabhLYbrFL_7v07jrFvFwmHhfCyYTmwFjeC-00XVF7LE4zkSnA7q1f_dvUrhH-M9rDEL7ZaqzQLC_2lO3oxevjm235o8NS3R3-fBVijSrtHcdKgG_0B3FnCEYM5LHkvZO6P0HbrQQ2gmwo4m4JE4EbD44oSCMXcGqy0kU5kzBtKFgbP57Cv-k9HHw3SnNNsFiPC9HGRIiYA9PhCAjxFzy8gRFJlWwR5V7iIJJq9-ImQ_FLxlX_bn27k7IexLJvWHaf4UmK3nifCisIb0oMVUeyBfBhXd04kIVfmwFnwXgjnud/p.png?size=2048x1536&size_mode=3';
  38.  
  39.  
  40. if (host === apHost) {
  41. header = getElement("#siteContainer h1");
  42. main();
  43. }
  44. else if (host === malHost) {
  45. header = getElement('#contentWrapper span span');
  46. main();
  47. }
  48. else if (host === alHost) {
  49. getAlHeader();
  50. }
  51.  
  52. function getAlHeader() {
  53. header = getElement('div.content h1');
  54.  
  55. if (header) {
  56. main();
  57. }
  58. else {
  59. setTimeout(getAlHeader, 300);
  60. }
  61. }
  62.  
  63. function getElement(atr) {
  64. return document.querySelector(atr);
  65. }
  66.  
  67.  
  68.  
  69. function main() {
  70.  
  71. //Cut anime name
  72. var animeName;
  73.  
  74. if (host === apHost) {
  75. animeName = getAnimeName();
  76. }
  77. else if (host === malHost) {
  78. animeName = header.childNodes[0].nodeValue;
  79. }
  80. else if (host === alHost) {
  81. animeName = getAnimeName();
  82. document.addEventListener('click', () => {
  83. if (getAnimeName() !== animeName) {
  84. animeName = getAnimeName();
  85. var urlsObjs = setSearchURLs();
  86. var animeButtons = document.querySelectorAll('.animeButton');
  87. var customButtonsObjs = getAnimeButtonsFromStorage();
  88.  
  89. animeButtons.forEach(b => {
  90. if (b.className.includes('stockButton')) {
  91. b.href = urlsObjs.find(o => `animeButton${makeButtonId(o.n)}` === b.id).u;
  92. }
  93. else {
  94. b.href = customButtonsObjs.find(o => `animeButton${makeButtonId(o.title)}` === b.id).url.replace('ANIMENAME', animeName);
  95. }
  96. });
  97. }
  98. });
  99. }
  100.  
  101.  
  102. function getAnimeName() {
  103. return header.textContent.trim();
  104. }
  105.  
  106.  
  107. function creteButton(icon, searchUrl, title, isStock) {
  108. var buttImg = createHTMLElement("img", null, null, [{ n: 'style', v: 'width:16px;height:16px;margin-right:2px;' }]);
  109.  
  110. if (icon) {
  111. buttImg.src = icon;
  112. }
  113. else {
  114. buttImg.src = getIconUrl(searchUrl);
  115. }
  116.  
  117. var button = createHTMLElement("a", null, 'animeButton', [{ n: 'id', v: `animeButton${makeButtonId(title)}` },
  118. { n: 'href', v: searchUrl }, { n: 'target', v: "_blank" }, { n: 'title', v: title }]);
  119.  
  120. if (isStock) {
  121. button.className += ' stockButton';
  122. }
  123. button.appendChild(buttImg);
  124. return button;
  125. }
  126.  
  127. //Set buttons with information
  128. var malSearchUrl;
  129. var alSearchUrl;
  130. var apSearchUrl;
  131. var ytSearchUrl;
  132. var gSearchUrl;
  133. var nySearchUrl;
  134. var kaSearchUrl;
  135.  
  136. function setSearchURLs() {
  137. malSearchUrl = 'http://myanimelist.net/anime.php?q=' + animeName;
  138. alSearchUrl = 'https://anilist.co/search/anime?search=' + animeName + '&sort=SEARCH_MATCH';
  139. apSearchUrl = 'https://www.anime-planet.com/anime/all?name=' + animeName;
  140. ytSearchUrl = 'https://www.youtube.com/results?search_query=' + animeName + ' trailer';
  141. gSearchUrl = 'https://google.com/search?tbm=isch&biw=&bih=&gbv=2&q=' + animeName;
  142. nySearchUrl = 'https://nyaa.si/?f=0&c=0_0&q=' + animeName;
  143. kaSearchUrl = 'https://kissanime.ru/Search/Anime?keyword=' + animeName;
  144.  
  145. return [{ n: malTitle, u: malSearchUrl }, { n: apTitle, u: apSearchUrl }, { n: ytTitle, u: ytSearchUrl },
  146. { n: gTitle, u: gSearchUrl }, { n: nyTitle, u: nySearchUrl }, { n: kaTitle, u: kaSearchUrl }];
  147. }
  148.  
  149. setSearchURLs();
  150.  
  151. //MAL Button
  152. var icon = null;
  153. var malTitle = "Search MyAnimeList";
  154.  
  155. var malButton = creteButton(icon, malSearchUrl, malTitle, true);
  156.  
  157.  
  158. //Anilist Button
  159. var alTitle = "Search Anilist";
  160.  
  161. var alButton = creteButton(icon, alSearchUrl, alTitle, true);
  162.  
  163.  
  164. //Anime-Planet Button
  165. var apTitle = "Search Anime-Planet";
  166.  
  167. var apButton = creteButton(icon, apSearchUrl, apTitle, true);
  168.  
  169.  
  170. //YouTube Button
  171. var ytTitle = 'YouTube Trailer';
  172.  
  173. var ytButton = creteButton(icon, ytSearchUrl, ytTitle, true);
  174.  
  175.  
  176. //Google Images button
  177. var gTitle = "Search with Google Images";
  178.  
  179. var giButton = creteButton(icon, gSearchUrl, gTitle, true);
  180.  
  181.  
  182. //Nyaa button
  183. var nyTitle = "Search Nyaa";
  184.  
  185. var nyButton = creteButton(icon, nySearchUrl, nyTitle, true);
  186.  
  187.  
  188. //KissAnime button
  189. var kaTitle = "Search KissAnime";
  190.  
  191. var kaButton = creteButton(icon, kaSearchUrl, kaTitle, true);
  192.  
  193.  
  194. //Edit button
  195. alTitle = "Edit Custom Buttons";
  196.  
  197. var arrowButtonImg = createHTMLElement('img', null, 'arrowButton', [{ n: 'src', v: arrowIcon }, { n: 'title', v: alTitle },
  198. { n: 'style', v: 'width:16px;height:16px;transition: all 0.3s linear 0s;left:-18px;position: relative;' }]);
  199.  
  200. var editButtonImg = createHTMLElement('img', null, 'editButton', [{ n: 'src', v: editIcon }, { n: 'title', v: alTitle },
  201. { n: 'style', v: 'width:16px;height:16px;transition: all 0.3s linear 0s;opacity:0;' }]);
  202.  
  203. var editButton = createHTMLElement('div', null, null, [{ n: 'style', v: 'width:16px;height:16px;margin-right:2px;display:inline;' }]);
  204.  
  205. if (!autoHide) {
  206. editButtonImg.style.opacity = '1';
  207. arrowButtonImg.style.opacity = '0';
  208. }
  209.  
  210. header.addEventListener('mouseover', showEditButton);
  211. header.addEventListener('mouseout', hideEditButton);
  212.  
  213. appendChildren(editButton, [editButtonImg, arrowButtonImg]);
  214.  
  215. editButton.addEventListener('click', () => { togglePopup(true); });
  216.  
  217.  
  218. var customButtons = [];
  219. var customButtonsObj = [];
  220.  
  221. if (!(GM_listValues()).includes('setting:buttonsNames')) {
  222. var values = GM_listValues();
  223. for (var i = 0; i < values.length; i++) {
  224. if (!values[i].includes('setting:')) {
  225. customButtonsObj.push(JSON.parse(GM_getValue(values[i], '{}')));
  226. GM_deleteValue(values[i]);
  227. }
  228. }
  229.  
  230. setAnimeButtonsToStorage(customButtonsObj);
  231. }
  232. else {
  233. customButtonsObj = getAnimeButtonsFromStorage();
  234. }
  235.  
  236. customButtonsObj.forEach((b) => {
  237. customButtons.push(creteButton(b.icon, b.url.replace('ANIMENAME', animeName), b.title));
  238. });
  239.  
  240.  
  241.  
  242. //Add Website Buttons
  243. if (host === apHost) {
  244. appendButtons([malButton, alButton]);
  245. getElement('.animeButtons').parentElement.style.top = '6px';
  246. }
  247. else if (host === alHost) {
  248. appendButtons([malButton, apButton]);
  249. getElement('.animeButtons').parentElement.style.top = '8px';
  250. }
  251. else if (host === malHost) {
  252. appendButtons([apButton, alButton]);
  253. getElement('.animeButtons').parentElement.style.top = '2px';
  254. }
  255.  
  256.  
  257. function appendButtons(mainButtonsArray) {
  258. header.appendChild(document.createTextNode(" "));
  259.  
  260. var allButtons = mainButtonsArray.concat([ytButton, giButton, nyButton, kaButton], customButtons, editButton);
  261. var buttonsDiv = createHTMLElement('div', null, 'animeButtons', [{ n: 'style', v: 'position:relative;transition: all 0.4s cubic-bezier(0.79, 0.88, 0.16, 0.98) 0s;' }]);
  262. var outerButtonsDiv = createHTMLElement('div', null, null, [{ n: 'style', v: 'display:inline-block;position:relative;overflow:hidden;' }]);
  263.  
  264. appendChildren(buttonsDiv, allButtons);
  265. outerButtonsDiv.appendChild(buttonsDiv);
  266.  
  267. allButtons.forEach((b) => {
  268. if (b.id !== '') {
  269. hideList.push({
  270. bId: b.id,
  271. h: 'show'
  272. });
  273. }
  274. });
  275.  
  276. header.appendChild(outerButtonsDiv);
  277.  
  278. getHideList();
  279. hideButtons();
  280. addButtonPopup();
  281. hideEditButton();
  282. }
  283.  
  284.  
  285.  
  286.  
  287. function getHideList() {
  288. var hideListNew;
  289. if ((GM_listValues()).includes('hideList')) {
  290. hideListNew = GM_getValue('hideList', '[]');
  291. GM_deleteValue('hideList');
  292. }
  293. else {
  294. hideListNew = GM_getValue('setting:hideList', '[]');
  295. }
  296.  
  297. if (!hideListNew || hideListNew === undefined || hideListNew === 'undefined') {
  298. hideListNew = '[]';
  299. }
  300.  
  301. concatHideList(JSON.parse(hideListNew));
  302. }
  303.  
  304. function concatHideList(v) {
  305. v.forEach(b => {
  306. var item = hideList.find(n => n.bId === b.bId);
  307. if (item) {
  308. return Object.assign(item, b);
  309. }
  310. hideList.push(b);
  311. });
  312. }
  313.  
  314. function hideButtons() {
  315. buttDivLeft = 0;
  316.  
  317. hideList.forEach((o) => {
  318. var button = getElement(`#${o.bId}`);
  319.  
  320. if (button) {
  321. if (o.h === 'show') {
  322. button.style.display = '';
  323. buttDivLeft++;
  324. }
  325. else if (o.h === 'hide') {
  326. button.style.display = 'none';
  327. }
  328. }
  329. });
  330. }
  331.  
  332. function makeButtonId(buttonName) {
  333. var result = 0;
  334. for (var i = 0; i < buttonName.length; i++) {
  335. result += buttonName.charCodeAt(i);
  336. }
  337.  
  338. return result * buttonName.charCodeAt(buttonName.length - 1);
  339. }
  340.  
  341.  
  342. function getPopup() {
  343. return getElement('.buttonPopup');
  344. }
  345.  
  346. function showEditButton() {
  347. var editButton = getElement('.editButton');
  348.  
  349. if (autoHide) {
  350. var arrowButton = getElement('.arrowButton');
  351. var buttonsDiv = getElement('.animeButtons');
  352. buttonsDiv.style.left = '0%';
  353. arrowButton.style.opacity = '0';
  354. }
  355.  
  356. editButton.style.opacity = '1';
  357. }
  358.  
  359. function hideEditButton() {
  360. var editButton = getElement('.editButton');
  361.  
  362. if (autoHide) {
  363. var buttonsDiv = getElement('.animeButtons');
  364. var arrowButton = getElement('.arrowButton');
  365. buttonsDiv.style.left = `-${buttDivLeft * 18}px`;
  366. arrowButton.style.opacity = '1';
  367. }
  368.  
  369. editButton.style.opacity = '0';
  370. }
  371.  
  372. function addAndCancelButtonsHandler(e) {
  373. var targetEl = e.target;
  374.  
  375. if (targetEl.className === 'addButton') {
  376. addButtonLogic(GM_listValues());
  377. }
  378. else if (targetEl.className === 'cancelButton') {
  379. togglePopup(false);
  380. }
  381. else if (targetEl.className === 'deleteButton') {
  382. GM_deleteValue(getElement('.titleInput').value);
  383. togglePopup(false);
  384. }
  385. }
  386.  
  387. function addAndEditTabButtonsHandler(e) {
  388. var target = e.target;
  389.  
  390. if (target.className.includes('Text')) {
  391. target = e.target.parentElement;
  392. }
  393.  
  394. if (target.className === 'addTab' && target.style.color === 'white') {
  395. var editTab = target.parentElement.children[1];
  396. hideTabSection(editTab, target);
  397. }
  398. else if (target.className === 'editTab' && target.style.color === 'white') {
  399. var addTab = target.parentElement.firstElementChild;
  400. hideTabSection(addTab, target);
  401. }
  402. }
  403.  
  404. function hideTabSection(toHide, toShow) {
  405. toHide.style.color = 'white';
  406. toHide.style.backgroundColor = '#d8d8d8';
  407. toShow.style.color = 'black';
  408. toShow.style.backgroundColor = 'white';
  409.  
  410. var sectionToHide;
  411. var sectionToShow;
  412.  
  413. if (toHide.className === 'addTab') {
  414. sectionToHide = getElement('.addSection');
  415. sectionToShow = getElement('.editSection');
  416. }
  417. else {
  418. sectionToHide = getElement('.editSection');
  419. sectionToShow = getElement('.addSection');
  420. }
  421.  
  422. sectionToHide.style.opacity = '0';
  423.  
  424. setTimeout(() => {
  425. sectionToHide.style.display = 'none';
  426. sectionToShow.style.display = 'block';
  427. setTimeout(() => sectionToShow.style.opacity = '1', 50);
  428. }, 200);
  429. }
  430.  
  431. function togglePopup(show) {
  432. var popUp = getPopup();
  433.  
  434. if (show) {
  435. header.removeEventListener('mouseout', hideEditButton);
  436. popUp.style.opacity = '1';
  437. popUp.style.top = '50%';
  438. }
  439. else {
  440. header.addEventListener('mouseout', hideEditButton);
  441. hideEditButton();
  442. popUp.style.opacity = '0';
  443. popUp.style.top = '-100%';
  444. }
  445. }
  446.  
  447. function getAnimeButtonsFromStorage() {
  448. return JSON.parse(GM_getValue('setting:buttonsNames', '[]'));
  449. }
  450.  
  451. function setAnimeButtonsToStorage(buttonsNames) {
  452. GM_setValue('setting:buttonsNames', JSON.stringify(buttonsNames));
  453. }
  454.  
  455. function addButtonLogic() {
  456. var titleField = getElement('.titleInput');
  457. var searchField = getElement('.URLInput');
  458. var iconField = getElement('.iconInput');
  459.  
  460. var buttonsNames = getAnimeButtonsFromStorage();
  461.  
  462. if (titleField.value === '') {
  463. toggleMsgBox(true, 'Title cannot be empty!');
  464. }
  465. else if (searchField.value === '') {
  466. toggleMsgBox(true, 'Search URL cannot be empty!');
  467. }
  468. else if (buttonsNames.find((o) => o.title === titleField.value)) {
  469. toggleMsgBox(true, 'Button with the same name already exists!');
  470. }
  471. else {
  472. if (iconField.value === '') {
  473. iconField.value = getIconUrl(searchField.value);
  474. }
  475.  
  476. var newButton = {
  477. title: titleField.value,
  478. url: searchField.value,
  479. icon: iconField.value
  480. };
  481.  
  482. buttonsNames.push(newButton);
  483.  
  484. setAnimeButtonsToStorage(buttonsNames);
  485.  
  486. toggleMsgBox(true, `Button ${titleField.value} added succsessfully! Reload to see it!`, true);
  487.  
  488. hideList.push({ bId: `animeButton${makeButtonId(titleField.value)}`, h: 'show' });
  489. GM_setValue('setting:hideList', JSON.stringify(hideList));
  490.  
  491. titleField.value = '';
  492. searchField.value = '';
  493. iconField.value = '';
  494. }
  495. }
  496.  
  497. function getIconUrl(fromUrl) {
  498. var regex = /(?:https?:\/\/)(w{0,3}\.?[\s\S]+?\.\w+)\//;
  499. var result = '';
  500.  
  501. if (regex.test(fromUrl)) {
  502. result = `https://www.google.com/s2/favicons?domain=${fromUrl.match(regex)[1]}`;
  503. }
  504.  
  505. return result;
  506. }
  507.  
  508. function toggleMsgBox(toggle, msg, showReload) {
  509. var msgBox = getElement('.addMsgBox');
  510.  
  511. if (msg) {
  512. msgBox.firstElementChild.textContent = msg;
  513. }
  514.  
  515. if (showReload) {
  516. msgBox.children[1].style.display = 'inline';
  517. }
  518. else {
  519. msgBox.children[1].style.display = 'none';
  520. }
  521.  
  522. if (toggle) {
  523. msgBox.style.opacity = '1';
  524. msgBox.style.bottom = '15%';
  525. }
  526. else {
  527. msgBox.style.opacity = '0';
  528. setTimeout(() => { msgBox.style.bottom = '150%'; }, 250);
  529. }
  530. }
  531.  
  532. function hideAndDeleteHandler(e) {
  533. var target = e.target;
  534. var buttParent = target.parentElement;
  535. var button = getElement(`#${buttParent.className}`);
  536.  
  537. if (target.className === "removeButton") {
  538. button.remove();
  539. target.parentElement.remove();
  540. var buttonsObjs = getAnimeButtonsFromStorage();
  541. buttonsObjs = buttonsObjs.filter((o) => buttParent.textContent !== o.title);
  542. setAnimeButtonsToStorage(buttonsObjs);
  543. hideList = hideList.filter(obj => obj.bId !== button.id);
  544.  
  545. GM_setValue('setting:hideList', JSON.stringify(hideList));
  546. }
  547. else if (target.className === 'hideButton') {
  548. if (button.style.display === 'none') {
  549. button.style.display = '';
  550. concatHideList([{ bId: button.id, h: 'show' }]);
  551. target.setAttribute('src', iconEye);
  552. }
  553. else {
  554. button.style.display = 'none';
  555. concatHideList([{ bId: button.id, h: 'hide' }]);
  556. target.setAttribute('src', iconEyeGray);
  557. }
  558.  
  559. GM_setValue('setting:hideList', JSON.stringify(hideList));
  560.  
  561. hideButtons();
  562. }
  563. }
  564.  
  565. function msgButtonsHandler(e) {
  566. var target = e.target;
  567.  
  568. if (target.className === 'reloadButton') {
  569. location.reload();
  570. }
  571. else if (target.className === 'closeButton') {
  572. toggleMsgBox(false);
  573. }
  574. }
  575.  
  576. function settingsHandler(e) {
  577. var target = e.target;
  578.  
  579. if (target.className === 'editCheckbox') {
  580. autoHide = target.checked;
  581. GM_setValue('setting:autoHide', autoHide);
  582. }
  583. }
  584.  
  585. function popupClickHandler(e) {
  586. if (!e.target.className.includes('infoBox')) {
  587. var infoBoxes = document.querySelectorAll('.infoBox');
  588. infoBoxes.forEach(b => {
  589. if (b.style.opacity === '1') {
  590. hideInfoBox(b);
  591. }
  592. });
  593. }
  594. }
  595.  
  596. function URLQuestionmarkHandler(e) {
  597. showInfoBox(e.target.parentElement.lastElementChild);
  598. var iconInfoBox = getElement('.iconInfoBox');
  599. hideInfoBox(iconInfoBox);
  600. }
  601.  
  602. function iconQuestionmarkHandler(e) {
  603. showInfoBox(e.target.parentElement.lastElementChild);
  604. var URLInfoBox = getElement('.URLInfoBox');
  605. hideInfoBox(URLInfoBox);
  606. }
  607.  
  608. function hideInfoBox(infoBox) {
  609. infoBox.style.opacity = '0';
  610. setTimeout(() => infoBox.style.display = 'none', 300);
  611. }
  612.  
  613. function showInfoBox(infoBox) {
  614. infoBox.style.display = 'inline-block';
  615. setTimeout(() => infoBox.style.opacity = '1', 100);
  616. }
  617.  
  618. function addButtonPopup() {
  619. var questionmarkIcon = 'https://previews.dropbox.com/p/thumb/AAs9PpoNBbIv4yP0RKqnNKTZEYjDtwtWT-24ZkhGOTR9w-CeCdnwqQFvjYSk4YJM8SPo7Pi85ndYpE5ZsJ85Zysho9UfAcqaVYATZ_2UW-y7JtKdKiu1Y7jmPVb9Gv5fRLw20phAXqhEx7EbC6JsRkBvZ6aujPDiiEg8-X0F41jb-wFJ-DW9vrSMOVGyM4dHIxaQNcuCcESUAc6sCfD9Y7iKR3SVd7tWfcAp9SquCdf6aFTIOVXNASu_jFM35cRNpPOQ-i3kO32mPLs98SGDNjszVPGsCBeUKQE6BKnKMb_PVT7l-rx6C1QY6W_VejIUHOtt7_ID4xuFjgLqGSNRpfC6/p.png?size=2048x1536&size_mode=3';
  620.  
  621. var style = 'margin:auto;text-align: center;display:block;margin-bottom: 5px;';
  622. var popUp = createHTMLElement('div', null, 'buttonPopup', [{ n: 'style', v: 'position:absolute;top:-100%;left:50%;margin-top:-280px;margin-left:-200px;background-color:white;width:400px;height:560px;box-shadow: 0 0 15px rgba(0, 0, 0, 0.4);border-radius: 8px;font-size:medium;z-index:9999;opacity:0;transition: all 0.7s cubic-bezier(0.45, -0.24, 0.43, 1.14) 0s;' }]);
  623.  
  624. var tabs = createHTMLElement('div', null, 'popupTabs', [{ n: 'style', v: 'width: 100%;height: 40px;' }]);
  625. var addTab = createHTMLElement('div', null, 'addTab', [{ n: 'style', v: 'height: 100%;width: 50%;background-color: white;left: 50%;border-top-left-radius: 8px;text-align: center;transition: all 0.2s linear 0s;' }]);
  626. var textTabsStyle = 'position: relative;top: 11px;font-weight: bold;';
  627. var addTabText = createHTMLElement('div', 'ADD', 'addTabText', [{ n: 'style', v: textTabsStyle }]);
  628. addTab.appendChild(addTabText);
  629.  
  630. var editTab = createHTMLElement('div', null, 'editTab', [{ n: 'style', v: 'top: -40px;height: 100%;width: 50%;background-color: #d8d8d8;left: 50%;position: relative;border-top-right-radius: 8px;text-align: center;color: white;transition: all 0.2s linear 0s;' }]);
  631. var editTabText = createHTMLElement('div', 'EDIT', 'editTabText', [{ n: 'style', v: textTabsStyle }]);
  632. editTab.appendChild(editTabText);
  633.  
  634. appendChildren(tabs, [addTab, editTab]);
  635.  
  636. var addSection = createHTMLElement('div', null, 'addSection', [{ n: 'style', v: 'height:100%;width:100%;transition: all 0.2s linear 0s;' }]);
  637. var addSectionTitle = createHTMLElement('h2', 'ADD CUSTOM BUTTON', null, [{ n: 'style', v: style + 'margin-top: 25px' }]);
  638. var title = createHTMLElement('h3', 'Title', null, [{ n: 'style', v: style + 'margin-top: 20px' }]);
  639. var titleInput = createHTMLElement('input', null, 'titleInput', [{ n: 'placeholder', v: 'Button title' }, { n: 'style', v: style }]);
  640. var URLTitle = createHTMLElement('h3', 'Search URL', null, [{ n: 'style', v: style + 'margin-top: 20px' }]);
  641. var URLQm = createHTMLElement('img', null, 'URLQuestionmark questionmark', [{ n: 'src', v: questionmarkIcon }, { n: 'style', v: 'heaight:16px;width:16px;margin-left:5px;' }]);
  642. var URLInfoBox = createHTMLElement('div', 'To get the search URL first go the site you want to add and search the term "ANIMENAME" in the search field. Then copy the full URL (including http://) in the field below. (exaple: https://myanimelist.net/search/all?q=ANIMENAME)', 'URLInfoBox infoBox', [{ n: 'style', v: 'width: 90%;display: inline-block;position: absolute;margin-left: 10px;background-color: white;border-radius: 8px;box-shadow: rgba(0,0,0, 0.3) 0px 0px 10px;transition: opacity 0.3s linear;opacity: 0;padding: 10px;font-weight: normal;font-size: medium;' }]);
  643. appendChildren(URLTitle, [URLQm, URLInfoBox]);
  644. var URLInput = createHTMLElement('input', null, 'URLInput', [{ n: 'placeholder', v: 'Search URL' }, { n: 'style', v: style + 'width:80%' }]);
  645. var iconTitle = createHTMLElement('h3', 'Icon URL', null, [{ n: 'style', v: style + 'margin-top: 20px' }]);
  646. var iconQm = createHTMLElement('img', null, 'iconQuestionmark questionmark', [{ n: 'src', v: questionmarkIcon }, { n: 'style', v: 'heaight:16px;width:16px;margin-left:5px;' }]);
  647. var iconInfoBox = createHTMLElement('div', null, 'iconInfoBox infoBox', [{ n: 'style', v: 'width: 90%;display: inline-block;position: absolute;margin-left: 10px;background-color: white;border-radius: 8px;box-shadow: rgba(0,0,0, 0.3) 0px 0px 10px;transition: opacity 0.3s linear;opacity: 0;padding: 10px;font-weight: normal;font-size: medium;' }]);
  648. iconInfoBox.innerHTML = '(<b>Leave empty for automatic icon parse</b>)<br />Link to icon for the button. <br />The easiest way to get it is to copy this link "https://www.google.com/s2/favicons?domain=" and place the website url at the end (example: https://www.google.com/s2/favicons?domain=myanimelist.net).';
  649. appendChildren(iconTitle, [iconQm, iconInfoBox]);
  650. var iconInput = createHTMLElement('input', null, 'iconInput', [{ n: 'placeholder', v: 'Icon URL' }, { n: 'style', v: style + 'width:80%' }]);
  651.  
  652. var msgBoxDiv = createHTMLElement('div', null, 'addMsgBox', [{ n: 'style', v: 'width: 86%;position: absolute;margin-left: 7%;bottom: 150%;background-color: white;border-radius: 8px;box-shadow: rgba(0,0,0, 0.4) 0px 0px 15px;text-align: center;transition: opacity 0.2s linear;opacity:0' }]);
  653. var msgText = createHTMLElement('div', 'Button added succsessfully! Reload to see it!', 'addMgsText', [{ n: 'style', v: 'margin: 10px;' }]);
  654. var reloadButton = createHTMLElement('button', 'RELOAD', 'reloadButton', [{ n: 'style', v: 'margin: 10px;margin-right:0px;width:90px;' }]);
  655. var closeButton = createHTMLElement('button', 'CLOSE', 'closeButton', [{ n: 'style', v: 'margin: 10px;width:90px;' }]);
  656. appendChildren(msgBoxDiv, [msgText, reloadButton, closeButton]);
  657.  
  658. var buttonsDiv = createHTMLElement('div', null, 'addAndCancelButtons', [{ n: 'style', v: style + 'bottom:10px;position:absolute;width:100%' }]);
  659. var addButton = createHTMLElement('button', 'ADD', 'addButton', [{ n: 'style', v: 'width:90px;margin:5px' }]);
  660. var cancelButton = createHTMLElement('button', 'CANCEL', 'cancelButton', [{ n: 'style', v: 'width:90px;margin:5px' }]);
  661.  
  662. var editSection = createHTMLElement('div', null, 'editSection', [{ n: 'style', v: 'height:100%;width:100%;display:none;transition: all 0.2s linear 0s;' }]);
  663. var editSectionTitle = createHTMLElement('h2', 'EDIT CUSTOM BUTTONS', null, [{ n: 'style', v: style + 'margin-top: 25px' }]);
  664. var animeButtonsList = createHTMLElement('ul', null, 'buttonsList', [{ n: 'style', v: 'list-style: none;margin-top: 25px;padding-left: 40px;overflow: hidden;overflow-y: auto;height: 340px;' }]);
  665. var animeButtons = document.querySelectorAll('.animeButton');
  666.  
  667. var settingsDiv = createHTMLElement('div', null, 'settingsDiv', [{ n: 'style', v: 'padding: 0px 30px;' }]);
  668. var hideEditCheckbox = createHTMLElement('input', null, 'editCheckbox', [{ n: 'id', v: 'editCheckbox' }, { n: 'type', v: 'checkbox' }, { n: 'value', v: 'editCheckbox' }]);
  669.  
  670. if (autoHide) {
  671. hideEditCheckbox.setAttribute('checked', true);
  672. }
  673.  
  674. var hideEditCheckboxLabel = createHTMLElement('label', 'Auto hide buttons (show on mouseover)', null, [{ n: 'for', v: 'editCheckbox' }, { n: 'style', v: 'padding-left:5px;' }]);
  675. appendChildren(settingsDiv, [hideEditCheckbox, hideEditCheckboxLabel]);
  676.  
  677. var editButtonsDiv = createHTMLElement('div', null, 'addAndCancelButtons', [{ n: 'style', v: style + 'bottom:10px;position:absolute;width:100%' }]);
  678. var cancelButtonEdit = createHTMLElement('button', 'CLOSE', 'cancelButton', [{ n: 'style', v: 'width:90px;margin:5px' }]);
  679. editButtonsDiv.appendChild(cancelButtonEdit);
  680.  
  681. createAndAppendEditListEntry(animeButtonsList, animeButtons);
  682.  
  683. popUp.appendChild(tabs);
  684. appendChildren(buttonsDiv, [addButton, cancelButton]);
  685. appendChildren(addSection, [addSectionTitle, title, titleInput, URLTitle, URLInput, iconTitle, iconInput, msgBoxDiv, buttonsDiv]);
  686.  
  687. appendChildren(editSection, [editSectionTitle, animeButtonsList, settingsDiv, editButtonsDiv]);
  688.  
  689. appendChildren(popUp, [addSection, editSection]);
  690. var html = getElement('html');
  691. html.appendChild(popUp);
  692.  
  693. buttonsDiv.addEventListener('click', addAndCancelButtonsHandler);
  694. editButtonsDiv.addEventListener('click', addAndCancelButtonsHandler);
  695. tabs.addEventListener('click', addAndEditTabButtonsHandler);
  696. animeButtonsList.addEventListener('click', hideAndDeleteHandler);
  697. msgBoxDiv.addEventListener('click', msgButtonsHandler);
  698. settingsDiv.addEventListener('click', settingsHandler);
  699. URLQm.addEventListener('mouseover', URLQuestionmarkHandler);
  700. iconQm.addEventListener('mouseover', iconQuestionmarkHandler);
  701. popUp.addEventListener('click', popupClickHandler);
  702. }
  703.  
  704. function createAndAppendEditListEntry(animeButtonsList, animeButtons) {
  705. animeButtons.forEach((b) => {
  706. var listEl = createHTMLElement('li', null, b.id, [{ n: 'style', v: 'width:90%;margin-top:5px;border-bottom-style: inset;border-bottom-width: thin;' }]);
  707. var imgUrl = b.firstElementChild.getAttribute('src');
  708. var img = createHTMLElement('img', null, null, [{ n: 'src', v: imgUrl }, { n: 'style', v: 'width: 16px;height: 16px;' }]);
  709. var hideIcon = createHTMLElement('img', null, 'hideButton', [{ n: 'src', v: iconEye }, { n: 'title', v: 'Toggle Hide' }, { n: 'style', v: 'height:16px;width:16px;position: relative;left: 82%;' }]);
  710. var removeIcon = createHTMLElement('img', null, 'removeButton', [{ n: 'src', v: 'https://previews.dropbox.com/p/thumb/AAv_J1gX163dhysBBA0GBSGRBMMdRoTT2EVqs_xTg5PdES0EF5geKh9gJg0kCbmtTGSzjkZFZQ6qCVpKFmUKobTWUTYu-t6yYVdWg_ldZE8GBUfXu0NWx3q0RfyeelWLgApIOskJParENLlfHXLyKT_FeTPtESh3rNqWCr-7iY1v_snaIZo5WsajqOSeUoJ3jS6M0_lD_PN410Xv-hUbqlNejWUNJDoWz9nkQdhzLX3bFpErrb75jnys7fwG8NV0YYL-HDOKCOFnh0MCviaq_r-YeioUpcwdxVXv9AnHdgsfGnTSmfVdgY6oG5nk0IOjDfYs_R9-3zcOz5pClF6-9uM6/p.png?fv_content=true&size_mode=5' }, { n: 'title', v: 'DELETE' }, { n: 'style', v: 'height:16px;width:16px;position: relative;left: 85%;' }]);
  711. var span = createHTMLElement('span', b.getAttribute('title'), null, [{ n: 'style', v: 'margin-left:5px;bottom: 2px;position: relative;right: 16px;' }]);
  712.  
  713. if (b.style.display === 'none') {
  714. hideIcon.setAttribute('src', iconEyeGray);
  715. }
  716.  
  717. appendChildren(listEl, [img, hideIcon, span]);
  718.  
  719. if (!b.className.includes('stockButton')) {
  720. listEl.insertBefore(removeIcon, span);
  721. span.style.right = '32px';
  722. }
  723. animeButtonsList.appendChild(listEl);
  724. });
  725. }
  726.  
  727. function createHTMLElement(tag, textContent, className, attributes) {
  728. var element = document.createElement(tag);
  729.  
  730. if (className) {
  731. element.className = className;
  732. }
  733. if (textContent) {
  734. element.textContent = textContent;
  735. }
  736. if (attributes) {
  737. attributes.forEach((a) => {
  738. element.setAttribute(a.n, a.v);
  739. });
  740. }
  741.  
  742. return element;
  743. }
  744.  
  745. function appendChildren(element, children) {
  746. children.forEach((c) => {
  747. element.appendChild(c);
  748. });
  749. }
  750. }