Make links shorter
Boris Kubiak kubiakboris@gmail.com
Thu, 14 May 2020 18:32:34 +0200
6 files changed,
68 insertions(+),
42 deletions(-)
M
README.md
→
README.md
@@ -64,6 +64,6 @@ # Windows / WSL
echo -n 'Hello World' | xz --format=lzma | base64 -w0 | printf "https://nopaste.ml/#%s" "$(cat -)" ``` -[intro-img]: https://nopaste.ml/?lang=python#XQAAAQA6BAAAAAAAAAAFYH9Ev4Ly6wIDoAZQ25VXENWodOrWpmx8bfd8j6jeNeL/0fGICEpU6gh9GhXuFjqBBpJFOvefaxUXJquUWRQarmV+S0SHFOLUFyg/dw8OQI6RB6Y1yliOBWGL916HxAGqgwyLqjkH4w450OLk+q9oJYS6PrZfXU5uBC5DLe76OkG25ibvbsasKN51JuVyRedgoF/d7F9d6L7p02q0jHAM9pnPpKOKqlIVsNnXwYKXK10tnZ0GdiwJ3EeT//52uhw= -[example]: https://nopaste.ml/?lang=css#XQAAAQB2DQAAAAAAAAAXioAj/ZZaukKWizx++f8w08qY+xe+w0AeNB0EtEDMR1jPECOrMSz2rcy5XqUVTzusmFXo407ujwufsB1Va3cy02BV4Chx15I+SbM8Ei2WS8/MaZa0wIOjHf0s6B9Kcwi1J73qYeIcKm39PEWGnBM4Ym5aXFOF1Irrn1N95vEcl4YI+98rydudZHmsNCmt995GvCpLImwH7yj3SlMadWaQA0jHCrY1ZBvhjSJ9mAAdYjCJLduITZuXomgpqtr3sYI1WKeRGNmPSD8J8WRLtCx0BZl3yWZZrUxJbmVod8cYiPJnlO+CzQA03qA/GZnxhMYd9TPc2Xlq8UIhBX6gmvo/xhHJc/WHnuBFB32xJ37O5FZlZuXGy6wFE/lakVteoqEqgvyan4LfaiL0pMfYapWjV8YoPa/KyVGugANNjvtRw0hRr+Z1IgKoVL2a1xqvQiB65vIXkw68/ui82O1ko9HTbsLMHX/2/CgWZ8TkTEvgr0+dzVqQYIpaWpB3hDnUTHMkG2UehM5iJyJXAgODNqk8IiWCJn5k/j2FeFpchSTWdgi7AeaCowubmWnFTNgNFXLf5zzARWBUGQFT55TiC0ah4HL17jG3rY6fXvAXlm6CWc88ne7wF0opHkLnhfPslssDYo75hDmCfYwJ6asQ/YBkSuuLJjdCEXVjF7Pdw2FhsOiiB0gNXC6ehieM28M+PMGSDRqt0Q0KveMgE44YJ8zFOvpu2Gg41qDkrsYS7Xb/iMnHz66tt69I1rGzrHx88PuI2/CZx+kv+z7a+/Eiq4JC3KTDx4IbNUYptmrIOC2bxGrcjd8TBKGe+dNi8a/PEnXrUXc/OD7D680/Awo+scE8VKuRVN5R7OPg0tmKVQSQkyCf+I3//kGmREyhh6/bCv6tvbEc7hNPNE1js2svlVBF001JlLY7g1w6ls2pjxrKxuCLrkjba1n4s5WlfrbwcX18rqgbfL2tVibHggsy3Lgq4i7fXtuO3JifxfauO66YIRjEWFnACrHbZ14FbHDMylN7GMvo5TusxestU0s6+kiibWq2qZVpi7C5JVKURNQrGEabICn5nUDoOPMZSfNrdmlTOhu4qjKW09XdQPNazTMc83KjG1YOKNjRP23i1oav5muBFRGMDkSXt7wCgv5PCpLZM9w2jC5GCa5oHuH92IWJu5d80fvTRw3GxNQzfMRxgjzfH6xxrzu+EghhbzayUhb3U5aSRSxOtPTPfjT9mxgk7j3f1mRlbYheuhko4/LBIKYvfA5CnN2Yr3VyBYqoZ/ZgP871LU0ix8ZLeaecao0SDj6V35bZ6RB53mcU8BRPfcyZhj0H6BrFcrcfXKVwnNVro/cIrwnoG3GwlpCXGYJmDDeUdlbBj2HrVmvMncd3w8SzPtxw5RAWQP9YPJdE4Tc490BMX4zAkPqirRHLcxG/K5ECLtKtGsnCkg24+XwFo4XRcGfMsbkSSYD7oZ2HkD+1NXYqJKgk+7uee+yrYCZF6xbsb0ca/7r3w8nU9DueSa6XPiaCLSeJ+phw8iK1U4+FcCzqLW4LzgfcGjz64+HM+Xst0YuqzrAI2RU80H2Mr0FnC/qL+klbM+p0yNUBxBd4IQ64SJmh6Irgi7fZq2wfuTuVEAI1qKKwGwBQ6x9UDyY/OqkD63mtRL//oHeipA== +[intro-img]: https://nopaste.ml/?l=tcl#XQAAAQA6BAAAAAAAAAAFYH9MXlzSsUdj4vga48M86Ff/Bo1HzNmlXzjCWCN1Q/EliRJg00jhrYF9eDKWzDi+Su+Pv1o8yGz3V06CtGOt8u9dUN10KuOrmkUrjI/kUqitUUD34YXmq9twyrkxmOl5kaHPNqE2PWTRhnKWCEntngrOOlXC4kxxnXuGB2v4zJ75fIM0htURHr9ysHH+1nHvSRng4zpcYju3Y/RqpGTIowXGoUcIOeKKG8PpYf/9t33i +[example]: https://nopaste.ml/?l=css#XQAAAQB2DQAAAAAAAAAXioAj/ZZaukKWizx++f8w08qY+xe+w0AeNB0EtEDMR1jPECOrMSz2rcy5XqUVTzusmFXo407ujwufsB1Va3cy02BV4Chx15I+SbM8Ei2WS8/MaZa0wIOjHf0s6B9Kcwi1J73qYeIcKm39PEWGnBM4Ym5aXFOF1Irrn1N95vEcl4YI+98rydudZHmsNCmt995GvCpLImwH7yj3SlMadWaQA0jHCrY1ZBvhjSJ9mAAdYjCJLduITZuXomgpqtr3sYI1WKeRGNmPSD8J8WRLtCx0BZl3yWZZrUxJbmVod8cYiPJnlO+CzQA03qA/GZnxhMYd9TPc2Xlq8UIhBX6gmvo/xhHJc/WHnuBFB32xJ37O5FZlZuXGy6wFE/lakVteoqEqgvyan4LfaiL0pMfYapWjV8YoPa/KyVGugANNjvtRw0hRr+Z1IgKoVL2a1xqvQiB65vIXkw68/ui82O1ko9HTbsLMHX/2/CgWZ8TkTEvgr0+dzVqQYIpaWpB3hDnUTHMkG2UehM5iJyJXAgODNqk8IiWCJn5k/j2FeFpchSTWdgi7AeaCowubmWnFTNgNFXLf5zzARWBUGQFT55TiC0ah4HL17jG3rY6fXvAXlm6CWc88ne7wF0opHkLnhfPslssDYo75hDmCfYwJ6asQ/YBkSuuLJjdCEXVjF7Pdw2FhsOiiB0gNXC6ehieM28M+PMGSDRqt0Q0KveMgE44YJ8zFOvpu2Gg41qDkrsYS7Xb/iMnHz66tt69I1rGzrHx88PuI2/CZx+kv+z7a+/Eiq4JC3KTDx4IbNUYptmrIOC2bxGrcjd8TBKGe+dNi8a/PEnXrUXc/OD7D680/Awo+scE8VKuRVN5R7OPg0tmKVQSQkyCf+I3//kGmREyhh6/bCv6tvbEc7hNPNE1js2svlVBF001JlLY7g1w6ls2pjxrKxuCLrkjba1n4s5WlfrbwcX18rqgbfL2tVibHggsy3Lgq4i7fXtuO3JifxfauO66YIRjEWFnACrHbZ14FbHDMylN7GMvo5TusxestU0s6+kiibWq2qZVpi7C5JVKURNQrGEabICn5nUDoOPMZSfNrdmlTOhu4qjKW09XdQPNazTMc83KjG1YOKNjRP23i1oav5muBFRGMDkSXt7wCgv5PCpLZM9w2jC5GCa5oHuH92IWJu5d80fvTRw3GxNQzfMRxgjzfH6xxrzu+EghhbzayUhb3U5aSRSxOtPTPfjT9mxgk7j3f1mRlbYheuhko4/LBIKYvfA5CnN2Yr3VyBYqoZ/ZgP871LU0ix8ZLeaecao0SDj6V35bZ6RB53mcU8BRPfcyZhj0H6BrFcrcfXKVwnNVro/cIrwnoG3GwlpCXGYJmDDeUdlbBj2HrVmvMncd3w8SzPtxw5RAWQP9YPJdE4Tc490BMX4zAkPqirRHLcxG/K5ECLtKtGsnCkg24+XwFo4XRcGfMsbkSSYD7oZ2HkD+1NXYqJKgk+7uee+yrYCZF6xbsb0ca/7r3w8nU9DueSa6XPiaCLSeJ+phw8iK1U4+FcCzqLW4LzgfcGjz64+HM+Xst0YuqzrAI2RU80H2Mr0FnC/qL+klbM+p0yNUBxBd4IQ64SJmh6Irgi7fZq2wfuTuVEAI1qKKwGwBQ6x9UDyY/OqkD63mtRL//oHeipA== [topaz-example]: https://topaz.github.io/paste/#XQAAAQADAQAAAAAAAAAFFgvDUiqpf8dDPleMqfsqtbQYE28suCtDTB9iyFgGByXgSRMepMuokjoACV4UPgBzwM3p+V/N2rCi8m90FkQfsRuMJ4LrZVFgr81wKDc2okcywbJBz7OGNPpc8xu2lAkpSekqRO+I/OYUUvgB2ckKBp+2avxmAKn6H73WV3t1D5Ip9hwthecGUnLwFSGpPFNI0zb4Ettx7QnIu6NiftBuencR3Bn/l3BNoh8M5NQL2MoInMQAnQ1gGwSQg6uEnIvK70ERxjllyP2v2fH/N5CRAA==
M
index.html
→
index.html
@@ -20,7 +20,7 @@ npm/codemirror@5.52.0/addon/scroll/simplescrollbars.css,
npm/codemirror@5.52.0/theme/dracula.min.css " /> - <link rel="stylesheet" href="/style.css" /> + <link rel="stylesheet" href="style.css" /> <link href="favicon.ico" rel="icon" type="image/x-icon" /> <link rel="canonical" href="https://nopaste.ml/" /> <meta@@ -72,10 +72,21 @@ <div class="col-auto mb-1">
<h1 class="my-0"><span>{</span> NoPaste <span>}</span></h1> </div> <div class="col-auto"> - <a href="https://github.com/bokub/nopaste" rel="noopener" target="_blank" class="mx-1"> + <a + href="https://github.com/bokub/nopaste" + rel="noopener" + target="_blank" + class="mx-1" + title="Source code" + > <svg class="icon"><use xlink:href="#icon-github"></use></svg> </a> - <a href="javascript:void(0)" onclick="byId('overlay').classList.remove('hidden')" class="mx-1"> + <a + href="javascript:void(0)" + onclick="byId('overlay').classList.remove('hidden')" + class="mx-1" + title="What is NoPaste?" + > <svg class="icon mx-2"><use xlink:href="#icon-question"></use></svg> </a> </div>@@ -196,6 +207,6 @@ npm/codemirror@5.52.0/addon/mode/simple.min.js,
npm/codemirror@5.52.0/addon/scroll/simplescrollbars.js, npm/codemirror@5.52.0/mode/meta.min.js "></script> - <script src="/index.js"></script> + <script src="index.js"></script> </body> </html>
M
index.js
→
index.js
@@ -7,6 +7,7 @@ let clipboard = null;
let statsEl = null; const init = () => { + handleLegacyUrl(); initCodeEditor(); initLangSelector(); initCode();@@ -38,7 +39,7 @@ select = new SlimSelect({
select: '#language', data: CodeMirror.modeInfo.map((e) => ({ text: e.name, - value: hash(e.name), + value: shorten(e.name), data: { mime: e.mime, mode: e.mode }, })), showContent: 'down',@@ -49,24 +50,13 @@ CodeMirror.autoLoadMode(editor, language.mode);
}, }); - // Retro-compatibility - const legacyLang = new URLSearchParams(window.location.search).get('lang'); - if (legacyLang) { - const langObj = CodeMirror.modeInfo.find((e) => slugify(e.name) === legacyLang); - if (langObj) { - select.set(hash(langObj.name)); - return; - } - } // Set lang selector - select.set(window.location.hash.charAt(5) === '-' ? window.location.hash.substr(1, 4) : hash('Plain Text')); + const l = new URLSearchParams(window.location.search).get('l'); + select.set(l ? decodeURIComponent(l) : shorten('Plain Text')); }; const initCode = () => { - let base64 = location.pathname.substr(1) || location.hash.substr(1); - if (base64.charAt(4) === '-') { - base64 = base64.substr(5); - } + let base64 = location.hash.substr(1); if (base64.length === 0) { return; }@@ -79,6 +69,22 @@ editor.setValue(code);
}); }; +const handleLegacyUrl = () => { + const lang = new URLSearchParams(window.location.search).get('lang'); + const base = `${location.protocol}//${location.host}`; + if (location.hash.charAt(5) === '-') { + const hashedLang = location.hash.substr(1, 4); + const newLang = CodeMirror.modeInfo.find((e) => hash(e.name) === hashedLang); + const queryParams = newLang ? '?l=' + shorten(newLang.name) : ''; + location.replace(`${base}/${queryParams}#${location.hash.substr(6)}`); + throw new Error('waiting for page to reload'); + } + if (lang) { + location.replace(`${base}/${'?l=' + shorten(lang)}${location.hash}`); + throw new Error('waiting for page to reload'); + } +}; + const initClipboard = () => { clipboard = new ClipboardJS('.clipboard'); clipboard.on('success', () => {@@ -145,13 +151,13 @@
// Build a shareable URL const buildUrl = (rawData, mode) => { const base = `${location.protocol}//${location.host}/`; - const lang = hash('Plain Text') === select.selected() ? '' : select.selected() + '-'; - const url = base + '#' + lang + rawData; + const query = shorten('Plain Text') === select.selected() ? '' : `?l=${encodeURIComponent(select.selected())}`; + const url = base + query + '#' + rawData; if (mode === 'markdown') { return `[NoPaste snippet](${url})`; } if (mode === 'iframe') { - const height = Math.min(editor['doc'].height + 45, 800); + const height = editor['doc'].height + 45; return `<iframe width="100%" height="${height}" frameborder="0" src="${url}"></iframe>`; } return url;@@ -211,15 +217,37 @@ };
const slugify = (str) => str + .trim() .toString() .toLowerCase() .replace(/\s+/g, '-') .replace(/\+/g, '-p') .replace(/#/g, '-sharp') .replace(/[^\w\-]+/g, ''); + +const shorten = (name) => { + let n = slugify(name).replace('script', '-s').replace('python', 'py'); + const nov = (s) => s[0] + s.substr(1).replace(/[aeiouy-]/g, ''); + if (n.replace(/-/g, '').length <= 4) { + return n.replace(/-/g, ''); + } + if (n.split('-').length >= 2) { + return n + .split('-') + .map((x) => nov(x.substr(0, 2))) + .join('') + .substr(0, 4); + } + n = nov(n); + if (n.length <= 4) { + return n; + } + return n.substr(0, 2) + n.substr(n.length - 2, 2); +}; const byId = (id) => document.getElementById(id); +// Legacy code, only for retro-compatibility const hash = function (str, seed = 0) { let h1 = 0xdeadbeef ^ seed; let h2 = 0x41c6ce57 ^ seed;@@ -234,28 +262,15 @@ const h = 4294967296 * (2097151 & h2) + (h1 >>> 0);
return h.toString(36).substr(0, 4).toUpperCase(); }; -/* Only for tests purposes */ +// Only for tests purposes const testAllModes = () => { for (const [index, language] of Object.entries(CodeMirror.modeInfo)) { + CodeMirror.autoLoadMode(editor, language.mode); setTimeout(() => { console.info(language.name); - select.set(slugify(language.name)); + select.set(shorten(language.name)); }, 1000 * index); } -}; - -/* Only for tests purposes */ -const testHashCollisions = () => { - const hashes = {}; - console.time('Hash test'); - for (const lang of CodeMirror.modeInfo) { - const hashed = hash(lang.name); - if (hashes[hashed]) { - console.error(`${lang.name} and ${hashes[hashed]} share the same hash: ${hashed}`); - } - hashes[hashed] = lang.name; - } - console.timeEnd('Hash test'); }; init();