Guest User

[Debug][v0.2.2.1]Greasyfork 快捷编辑收藏

a guest
Dec 8th, 2023
329
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
JavaScript 19.19 KB | Source Code | 0 0
  1. /* eslint-disable no-multi-spaces */
  2.  
  3. // ==UserScript==
  4. // @name               Greasyfork 快捷编辑收藏
  5. // @name:zh-CN         Greasyfork 快捷编辑收藏
  6. // @name:zh-TW         Greasyfork 快捷編輯收藏
  7. // @name:en            Greasyfork script-set-edit button
  8. // @name:en-US         Greasyfork script-set-edit button
  9. // @name:fr            Greasyfork Set Edit+
  10. // @namespace          Greasyfork-Favorite
  11. // @version            0.2.2.1
  12. // @description        在GF脚本页添加快速打开收藏集编辑页面功能
  13. // @description:zh-CN  在GF脚本页添加快速打开收藏集编辑页面功能
  14. // @description:zh-TW  在GF腳本頁添加快速打開收藏集編輯頁面功能
  15. // @description:en     Add / Remove script into / from script set directly in GF script info page
  16. // @description:en-US  Add / Remove script into / from script set directly in GF script info page
  17. // @description:fr     Ajouter un script à un jeu de scripts / supprimer un script d'un jeu de scripts directement sur la page d'informations sur les scripts GF
  18. // @author             PY-DNG
  19. // @license            GPL-3
  20. // @match              http*://*.greasyfork.org/*
  21. // @match              http*://*.sleazyfork.org/*
  22. // @match              http*://greasyfork.org/*
  23. // @match              http*://sleazyfork.org/*
  24. // @require            https://greasyfork.org/scripts/456034-basic-functions-for-userscripts/code/script.js?version=1226884
  25. // @require            https://greasyfork.org/scripts/460385-gm-web-hooks/code/script.js?version=1221394
  26. // @icon               data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAbBJREFUOE+Vk7GKGlEUhr8pAiKKDlqpCDpLUCzWBxCENBa+hBsL9wHsLWxXG4tNtcGH0MIiWopY7JSGEUWsbESwUDMw4Z7siLsZDbnlPff/7n/+e67G38sA6sAXIPVWXgA/gCdgfinRPuhfCoXCw3Q65XA4eLBl6zvw1S2eAZqmvTqOc5/NZhkMBqRSKWzbvgYxgbwquoAX4MGyLHK5HIlEgtFo9C+IOFEAo1gsWsvlUmyPx2MymYxAhsMh6XT6lpM7BXjWdf1xNpuRz+fl8GQywTAMGo0G1WpVnJxOJ692vinADPgcDAaZz+cCOR6PmKZJPB4XUb/fp1wuewF+KoBCf1JVBVE5dDodms3mWdDtdqlUKl6AX+8ALmS9XgtM0/5kvNlspKX9fv8RIgBp4bISCoXo9XqsVitKpRK6rrPb7STQ7XZ7eVRaeAYerz14OBxGOfL7/eIgmUwKzHEcJZEQ1eha1wBqPxqNihufzyeQWCzmtiPPqJYM0jWIyiISibBYLAgEAtTrdVqt1nmQXN0rcH/LicqmVqvRbrdN27bfjbKru+nk7ZD3Z7q4+b++82/YPKIrXsKZ3AAAAABJRU5ErkJggg==
  27. // @grant              GM_xmlhttpRequest
  28. // @grant              GM_setValue
  29. // @grant              GM_getValue
  30. // ==/UserScript==
  31.  
  32. /* global LogLevel DoLog Err $ $All $CrE $AEL $$CrE addStyle detectDom destroyEvent copyProp copyProps parseArgs escJsStr replaceText getUrlArgv dl_browser dl_GM AsyncManager */
  33. /* global GMXHRHook GMDLHook */
  34.  
  35. (function __MAIN__() {
  36.     'use strict';
  37.  
  38.     const CONST = {
  39.         Text: {
  40.             'zh-CN': {
  41.                 FavEdit: '收藏集:',
  42.                 Add: '加入此集',
  43.                 Remove: '移出此集',
  44.                 Edit: '手动编辑',
  45.                 EditIframe: '页内编辑',
  46.                 CloseIframe: '关闭编辑',
  47.                 CopySID: '复制脚本ID',
  48.                 Working: ['工作中...', '就快好了...'],
  49.                 InSetStatus: ['[ ]', '[✔]'],
  50.                 Error: {
  51.                     AlreadyExist: '脚本已经在此收藏集中了',
  52.                     NotExist: '脚本不在此收藏集中',
  53.                     Unknown: '未知错误'
  54.                 }
  55.             },
  56.             'zh-TW': {
  57.                 FavEdit: '收藏集:',
  58.                 Add: '加入此集',
  59.                 Remove: '移出此集',
  60.                 Edit: '手動編輯',
  61.                 EditIframe: '頁內編輯',
  62.                 CloseIframe: '關閉編輯',
  63.                 CopySID: '複製腳本ID',
  64.                 Working: ['工作中...', '就快好了...'],
  65.                 InSetStatus: ['[ ]', '[✔]'],
  66.                 Error: {
  67.                     AlreadyExist: '腳本已經在此收藏集中了',
  68.                     NotExist: '腳本不在此收藏集中',
  69.                     Unknown: '未知錯誤'
  70.                 }
  71.             },
  72.             'en': {
  73.                 FavEdit: 'Add to/Remove from favorite list: ',
  74.                 Add: 'Add',
  75.                 Remove: 'Remove',
  76.                 Edit: 'Edit Manually',
  77.                 EditIframe: 'In-Page Edit',
  78.                 CloseIframe: 'Close Editor',
  79.                 CopySID: 'Copy Script-ID',
  80.                 Working: ['Working...', 'Just a moment...'],
  81.                 InSetStatus: ['[ ]', '[✔]'],
  82.                 Error: {
  83.                     AlreadyExist: 'Script is already in set',
  84.                     NotExist: 'Script is not in set yet',
  85.                     Unknown: 'Unknown Error'
  86.                 }
  87.             },
  88.             'default': {
  89.                 FavEdit: 'Add to/Remove from favorite list: ',
  90.                 Add: 'Add',
  91.                 Remove: 'Remove',
  92.                 Edit: 'Edit Manually',
  93.                 EditIframe: 'In-Page Edit',
  94.                 CloseIframe: 'Close Editor',
  95.                 CopySID: 'Copy Script-ID',
  96.                 Working: ['Working...', 'Just a moment...'],
  97.                 InSetStatus: ['[ ]', '[✔]'],
  98.                 Error: {
  99.                     AlreadyExist: 'Script is already in set',
  100.                     NotExist: 'Script is not in set yet',
  101.                     Unknown: 'Unknown Error'
  102.                 }
  103.             },
  104.         }
  105.     }
  106.  
  107.     // Get i18n code
  108.     let i18n = $('#language-selector-locale') ? $('#language-selector-locale').value : navigator.language;
  109.     if (!Object.keys(CONST.Text).includes(i18n)) {i18n = 'default';}
  110.  
  111.     main()
  112.     function main() {
  113.         const HOST = getHost();
  114.         const API = getAPI();
  115.  
  116.         // Common actions
  117.         commons();
  118.  
  119.         // API-based actions
  120.         switch(API[1]) {
  121.             case "scripts":
  122.                 API[2] && centerScript(API);
  123.                 break;
  124.             default:
  125.                 DoLog('API is {}'.replace('{}', API));
  126.         }
  127.     }
  128.  
  129.     function centerScript(API) {
  130.         switch(API[3]) {
  131.             case undefined:
  132.                 pageScript();
  133.                 break;
  134.             case 'code':
  135.                 pageCode();
  136.                 break;
  137.             case 'feedback':
  138.                 pageFeedback();
  139.                 break;
  140.         }
  141.     }
  142.  
  143.     function commons() {
  144.         // Your common actions here...
  145.         GMXHRHook(5);
  146.     }
  147.  
  148.     function pageScript() {
  149.         addFavPanel();
  150.     }
  151.  
  152.     function pageCode() {
  153.         addFavPanel();
  154.     }
  155.  
  156.     function pageFeedback() {
  157.         addFavPanel();
  158.     }
  159.  
  160.     function addFavPanel() {
  161.         if (!getUserpage()) {return false;}
  162.         GUI();
  163.  
  164.         function GUI() {
  165.             // Get elements
  166.             const script_after = $('#script-feedback-suggestion+*') || $('#new-script-discussion');
  167.             const script_parent = script_after.parentElement;
  168.  
  169.             // My elements
  170.             const script_favorite = $CrE('div');
  171.             script_favorite.id = 'script-favorite';
  172.             script_favorite.style.margin = '0.75em 0';
  173.             script_favorite.innerHTML = CONST.Text[i18n].FavEdit;
  174.  
  175.             const favorite_groups = $CrE('select');
  176.             favorite_groups.id = 'favorite-groups';
  177.  
  178.             const stored_sets = GM_getValue('script-sets', {sets: []}).sets;
  179.             for (const set of stored_sets) {
  180.                 // Make <option>
  181.                 const option = $CrE('option');
  182.                 option.innerText = set.name;
  183.                 option.value = set.linkedit;
  184.                 $APD(favorite_groups, option);
  185.             }
  186.             adjustWidth();
  187.  
  188.             refresh();
  189.             favorite_groups.addEventListener('change', function(e) {
  190.                 favorite_edit.href = favorite_groups.value;
  191.             });
  192.  
  193.             const favorite_add = $CrE('a');
  194.             favorite_add.id = 'favorite-add';
  195.             favorite_add.innerHTML = CONST.Text[i18n].Add;
  196.             favorite_add.style.margin = favorite_add.style.margin = '0px 0.5em';
  197.             favorite_add.href = 'javascript:void(0);'
  198.             favorite_add.addEventListener('click', e => addFav());
  199.  
  200.             const favorite_remove = $CrE('a');
  201.             favorite_remove.id = 'favorite-add';
  202.             favorite_remove.innerHTML = CONST.Text[i18n].Remove;
  203.             favorite_remove.style.margin = favorite_remove.style.margin = '0px 0.5em';
  204.             favorite_remove.href = 'javascript:void(0);'
  205.             favorite_remove.addEventListener('click', e => removeFav());
  206.  
  207.             const favorite_edit = $CrE('a');
  208.             favorite_edit.id = 'favorite-edit';
  209.             favorite_edit.innerHTML = CONST.Text[i18n].Edit;
  210.             favorite_edit.style.margin = favorite_edit.style.margin = '0px 0.5em';
  211.             favorite_edit.target = '_blank';
  212.  
  213.             const favorite_iframe = $CrE('a');
  214.             favorite_iframe.id = 'favorite-edit-in-page';
  215.             favorite_iframe.href = 'javascript: void(0);';
  216.             favorite_iframe.innerHTML = CONST.Text[i18n].EditIframe;
  217.             favorite_iframe.style.margin = favorite_iframe.style.margin = '0px 0.5em';
  218.             favorite_iframe.target = '_blank';
  219.             $AEL(favorite_iframe, 'click', editInPage);
  220.  
  221.             const favorite_copy = $CrE('a');
  222.             favorite_copy.id = 'favorite-copy';
  223.             favorite_copy.href = 'javascript: void(0);';
  224.             favorite_copy.innerHTML = CONST.Text[i18n].CopySID;
  225.             favorite_copy.addEventListener('click', function() {
  226.                 copyText(getStrSID());
  227.             });
  228.  
  229.             // Append to document
  230.             $APD(script_favorite, favorite_groups);
  231.             script_parent.insertBefore(script_favorite, script_after);
  232.             [favorite_add, favorite_remove, favorite_edit, favorite_iframe, favorite_copy].forEach(button => $APD(script_favorite, button));
  233.  
  234.             function refresh() {
  235.                 getScriptSets(function(sets) {
  236.                     const old_value = favorite_groups.value;
  237.                     clearChildnodes(favorite_groups);
  238.  
  239.                     for (const set of sets) {
  240.                         // Make <option>
  241.                         const option = set.elmOption = $CrE('option');
  242.                         option.innerText = set.name;
  243.                         option.value = set.linkedit;
  244.                         $APD(favorite_groups, option);
  245.                     }
  246.                     adjustWidth();
  247.  
  248.                     // Recover selected <option>
  249.                     const selected = [...favorite_groups.children].find(option => option.value === old_value);
  250.                     selected && (selected.selected = true);
  251.  
  252.                     // Set edit-button.href
  253.                     favorite_edit.href = favorite_groups.value;
  254.  
  255.                     // Check script in-set status
  256.                     getInSets(sets, getStrSID(), inSets => {
  257.                         sets.forEach(set => {
  258.                             const inSet = inSets.includes(set);
  259.                             set.elmOption.innerText = `${CONST.Text[i18n].InSetStatus[inSet+0]} ${set.name}`;
  260.                         });
  261.                         adjustWidth();
  262.                     });
  263.                 })
  264.             }
  265.  
  266.             function adjustWidth() {
  267.                 favorite_groups.style.width = Math.max.apply(null, Array.from(favorite_groups.children).map((o) => (o.innerText.length))).toString() + 'em';
  268.                 favorite_groups.style.maxWidth = '40vw';
  269.             }
  270.  
  271.             function addFav() {
  272.                 const option = favorite_groups.selectedOptions[0];
  273.                 const set = GM_getValue('script-sets').sets.find(set => set.linkedit === option.value);
  274.                 const url = favorite_groups.value;
  275.  
  276.                 displayNotice(CONST.Text[i18n].Working[0]);
  277.                 modifyFav(favorite_groups.value, oDom => {
  278.                     const existingInput = [...$All(oDom, '#script-set-scripts>input[name="scripts-included[]"][type="hidden"]')].find(input => input.value === getStrSID());
  279.                     if (existingInput) {
  280.                         displayNotice(CONST.Text[i18n].Error.AlreadyExist);
  281.                         option.innerText = `${CONST.Text[i18n].InSetStatus[1]} ${set.name}`;
  282.                         return false;
  283.                     }
  284.  
  285.                     const input = $CrE('input');
  286.                     input.value = getStrSID();
  287.                     input.name = 'scripts-included[]';
  288.                     input.type = 'hidden';
  289.                     $APD($(oDom, '#script-set-scripts'), input);
  290.                     displayNotice(CONST.Text[i18n].Working[1]);
  291.                 }, oDom => {
  292.                     const status = $(oDom, 'p.notice');
  293.                     const status_text = status ? status.innerText : CONST.Text[i18n].Error.Unknown;
  294.                     displayNotice(status_text);
  295.                     option.innerText = `${CONST.Text[i18n].InSetStatus[1]} ${set.name}`;
  296.                 }, onerror);
  297.             }
  298.  
  299.             function removeFav() {
  300.                 const option = favorite_groups.selectedOptions[0];
  301.                 const set = GM_getValue('script-sets').sets.find(set => set.linkedit === option.value);
  302.                 const url = favorite_groups.value;
  303.  
  304.                 displayNotice(CONST.Text[i18n].Working[0]);
  305.                 modifyFav(favorite_groups.value, oDom => {
  306.                     const existingInput = [...$All(oDom, '#script-set-scripts>input[name="scripts-included[]"][type="hidden"]')].find(input => input.value === getStrSID());
  307.                     if (!existingInput) {
  308.                         displayNotice(CONST.Text[i18n].Error.NotExist);
  309.                         option.innerText = `${CONST.Text[i18n].InSetStatus[0]} ${set.name}`;
  310.                         return false;
  311.                     }
  312.  
  313.                     existingInput.remove();
  314.                     displayNotice(CONST.Text[i18n].Working[1]);
  315.                 }, oDom => {
  316.                     const status = $(oDom, 'p.notice');
  317.                     const status_text = status ? status.innerText : CONST.Text[i18n].Error.Unknown;
  318.                     displayNotice(status_text);
  319.                     option.innerText = `${CONST.Text[i18n].InSetStatus[0]} ${set.name}`;
  320.                 }, onerror);
  321.             }
  322.  
  323.             function modifyFav(url, editCallback, finishCallback, onerror) {
  324.                 getDocument(url, oDom => {
  325.                     if (editCallback(oDom) === false) {
  326.                         return false;
  327.                     }
  328.                     const form = $(oDom, '.change-script-set');
  329.                     const data = new FormData(form);
  330.                     data.append('save', '1');
  331.  
  332.                     // Use XMLHttpRequest insteadof GM_xmlhttpRequest before Tampermonkey 5.0.0 because of FormData posting issues
  333.                     if (GM_info.scriptHandler === 'Tampermonkey' && parseInt(GM_info.version.split('.')[0], '10') < '5') {
  334.                         DoLog('modifyFav: Using XMLHttpRequest');
  335.                         const xhr = new XMLHttpRequest();
  336.                         xhr.open('POST', toAbsoluteURL(form.getAttribute('action')));
  337.                         xhr.responseType = 'blob';
  338.                         xhr.onload = e => parseDocument(xhr.response, oDom => finishCallback(oDom));
  339.                         xhr.onerror = onerror;
  340.                         xhr.send(data);
  341.                     } else {
  342.                         DoLog('modifyFav: Using GM_xmlhttpRequest');
  343.                         GM_xmlhttpRequest({
  344.                             method: 'POST',
  345.                             url: toAbsoluteURL(form.getAttribute('action')),
  346.                             data,
  347.                             responseType: 'blob',
  348.                             onload: response => parseDocument(response.response, oDom => finishCallback(oDom)),
  349.                             onerror
  350.                         });
  351.                     }
  352.                 });
  353.             }
  354.  
  355.             function onerror() {
  356.                 displayNotice(CONST.Text[i18n].Error.Unknown);
  357.             }
  358.  
  359.             function editInPage(e) {
  360.                 e.preventDefault();
  361.  
  362.                 const _iframes = [...$All(script_favorite, '.script-edit-page')];
  363.                 if (_iframes.length) {
  364.                     // Iframe exists, close iframe
  365.                     favorite_iframe.innerText = CONST.Text[i18n].EditIframe;
  366.                     _iframes.forEach(ifr => ifr.remove());
  367.                 } else {
  368.                     // Iframe not exist, make iframe
  369.                     favorite_iframe.innerText = CONST.Text[i18n].CloseIframe;
  370.  
  371.                     const iframe = $$CrE({
  372.                         tagName: 'iframe',
  373.                         props: {
  374.                             src: favorite_groups.value
  375.                         },
  376.                         styles: {
  377.                             width: '100%',
  378.                             height: '60vh'
  379.                         },
  380.                         classes: ['script-edit-page'],
  381.                         listeners: [['load', e => {
  382.                             refresh();
  383.                             //iframe.style.height = iframe.contentDocument.body.parentElement.offsetHeight + 'px';
  384.                         }]]
  385.                     });
  386.                     script_favorite.appendChild(iframe);
  387.                 }
  388.             }
  389.  
  390.             function displayNotice(text) {
  391.                 const notice = $CrE('p');
  392.                 notice.classList.add('notice');
  393.                 notice.id = 'fav-notice';
  394.                 notice.innerText = text;
  395.                 const old_notice = $('#fav-notice');
  396.                 old_notice && old_notice.parentElement.removeChild(old_notice);
  397.                 $('#script-content').insertAdjacentElement('afterbegin', notice);
  398.             }
  399.         }
  400.     }
  401.  
  402.     function getScriptSets(callback, args=[]) {
  403.         const userpage = getUserpage();
  404.         getDocument(userpage, function(oDom) {
  405.             /*
  406.             const user_script_sets = oDom.querySelector('#user-script-sets');
  407.             const script_sets = [];
  408.  
  409.             for (const li of user_script_sets.querySelectorAll('li')) {
  410.                 // Get fav info
  411.                 const name = li.childNodes[0].nodeValue.trimRight();
  412.                 const link = li.children[0].href;
  413.                 const linkedit = li.children[1] ? li.children[1].href : 'https://greasyfork.org/' + $('#language-selector-locale').value + '/users/' + $('#nav-user-info>.user-profile-link>a').href.match(/[a-zA-Z\-]+\/users\/([^\/]*)/)[1] + '/sets/' + li.children[0].href.match(/[\?&]set=(\d+)/)[1] + '/edit';
  414.  
  415.                 // Append to script_sets
  416.                 script_sets.push({
  417.                     name: name,
  418.                     link: link,
  419.                     linkedit: linkedit
  420.                 });
  421.             }
  422.             */
  423.             const script_sets = Array.from($(oDom, 'ul#user-script-sets').children).map(li => {
  424.                 try {
  425.                     return {
  426.                         name: li.children[0].innerText,
  427.                         link: li.children[0].href,
  428.                         linkedit: li.children[1].href
  429.                     }
  430.                 } catch(err) {
  431.                     DoLog(LogLevel.Error, [li, err, li.children.length, li.children[0]?.innerHTML, li.children[2]?.innerHTML], 'error');
  432.                     Err(err);
  433.                 }
  434.             });
  435.  
  436.             // Save to GM_storage
  437.             GM_setValue('script-sets', {
  438.                 sets: script_sets,
  439.                 time: (new Date()).getTime(),
  440.                 version: '0.2'
  441.             });
  442.  
  443.             // callback
  444.             callback.apply(null, [script_sets].concat(args));
  445.         });
  446.     }
  447.  
  448.     function getUserpage() {
  449.         const a = $('#nav-user-info>.user-profile-link>a');
  450.         return a ? a.href : null;
  451.     }
  452.  
  453.     function getInSet(set, sid, callback) {
  454.         sid = sid.toString();
  455.         getDocument(set.linkedit, oDom => {
  456.             const inSet = [...$(oDom, '#script-set-scripts').children].some(input => input.value === sid);
  457.             callback(inSet);
  458.         });
  459.     }
  460.  
  461.     function getInSets(sets, sid, callback) {
  462.         const AM = new AsyncManager();
  463.         const inSets = [];
  464.         for (const set of sets) {
  465.             AM.add();
  466.             getInSet(set, sid, inSet => {
  467.                 inSet && inSets.push(set);
  468.                 AM.finish();
  469.             });
  470.         }
  471.         AM.onfinish = e => {
  472.             callback(inSets);
  473.         };
  474.         AM.finishEvent = true;
  475.     }
  476.  
  477.     function getStrSID(url=location.href) {
  478.         const API = getAPI(url);
  479.         const strSID = API[2].match(/\d+/)[0];
  480.         return strSID;
  481.     }
  482.  
  483.     function getSID(url=location.href) {
  484.         return Number(getStrSID(url));
  485.     }
  486.     // Basic functions
  487.     function $APD(a,b) {return a.appendChild(b);}
  488.  
  489.     // Remove all childnodes from an element
  490.     function clearChildnodes(element) {
  491.         const cns = []
  492.         for (const cn of element.childNodes) {
  493.             cns.push(cn);
  494.         }
  495.         for (const cn of cns) {
  496.             element.removeChild(cn);
  497.         }
  498.     }
  499.  
  500.     function getDocumentXHR(url, callback, args=[]) {
  501.         const xhr = new XMLHttpRequest();
  502.         xhr.open('GET', url);
  503.         xhr.responseType = 'blob';
  504.         xhr.onloadstart = e => DoLog(LogLevel.Info, 'getting document with normal xhr, url=\'' + url + '\'');
  505.         xhr.onload = e => {
  506.             const htmlblob = xhr.response;
  507.             parseDocument(htmlblob, callback, args);
  508.         };
  509.         xhr.send();
  510.     }
  511.  
  512.     // Download and parse a url page into a html document(dom).
  513.     // when xhr onload: callback.apply([dom, args])
  514.     function getDocument(url, callback, args=[], retry=5) {
  515.         GM_xmlhttpRequest({
  516.             method       : 'GET',
  517.             url          : url,
  518.             responseType : 'blob',
  519.             onloadstart  : function() {
  520.                 DoLog(LogLevel.Info, 'getting document, url=\'' + url + '\'');
  521.             },
  522.             onload       : function(response) {
  523.                 if (response.status === 200) {
  524.                     const htmlblob = response.response;
  525.                     parseDocument(htmlblob, callback, args);
  526.                 } else {
  527.                     re(response);
  528.                 }
  529.             },
  530.             onerror: err => re(err)
  531.         });
  532.  
  533.         function re(err) {
  534.             DoLog(`Get document failed, retrying: (${retry}) ${url}`);
  535.             --retry > 0 ? getDocument(url, callback, args=[], retry) : DoLog(LogLevel.Warning, err);
  536.         }
  537.     }
  538.  
  539.     function parseDocument(htmlblob, callback, args=[]) {
  540.         const reader = new FileReader();
  541.         reader.onload = function(e) {
  542.             const htmlText = reader.result;
  543.             const dom = new DOMParser().parseFromString(htmlText, 'text/html');
  544.             args = [dom].concat(args);
  545.             callback.apply(null, args);
  546.             //callback(dom, htmlText);
  547.         }
  548.         reader.readAsText(htmlblob, document.characterSet);
  549.     }
  550.  
  551.     // Copy text to clipboard (needs to be called in an user event)
  552.     function copyText(text) {
  553.         // Create a new textarea for copying
  554.         const newInput = document.createElement('textarea');
  555.         document.body.appendChild(newInput);
  556.         newInput.value = text;
  557.         newInput.select();
  558.         document.execCommand('copy');
  559.         document.body.removeChild(newInput);
  560.     }
  561.  
  562.     // get '/' splited API array from a url
  563.     function getAPI(url=location.href) {
  564.         return url.replace(/https?:\/\/(.*?\.){1,2}.*?\//, '').replace(/\?.*/, '').match(/[^\/]+?(?=(\/|$))/g);
  565.     }
  566.  
  567.     // get host part from a url(includes '^https://', '/$')
  568.     function getHost(url=location.href) {
  569.         const match = location.href.match(/https?:\/\/[^\/]+\//);
  570.         return match ? match[0] : match;
  571.     }
  572.  
  573.     function toAbsoluteURL(relativeURL, base=`${location.protocol}//${location.host}/`) {
  574.         return new URL(relativeURL, base).href;
  575.     }
  576.  
  577.     function randint(min, max) {
  578.         return Math.floor(Math.random() * (max - min + 1)) + min;
  579.     }
  580. })();
Add Comment
Please, Sign In to add comment