all repos — NoPaste @ 0ecc99d62c7bdbf397ae636090e88c6752d267f8

Resurrected - The PussTheCat.org fork of NoPaste

index.js (view raw)

  1const blob = new Blob(['importScripts("https://cdn.jsdelivr.net/npm/lzma@2.3.2/src/lzma_worker.min.js");']);
  2const lzma = new LZMA(window.URL.createObjectURL(blob));
  3
  4let editor = null;
  5let select = null;
  6let clipboard = null;
  7
  8const init = () => {
  9    initCodeEditor();
 10    initLangSelector();
 11    initCode();
 12    initClipboard();
 13};
 14
 15const initCodeEditor = () => {
 16    const readOnly = new URLSearchParams(window.location.search).has('readonly');
 17    CodeMirror.modeURL = 'https://cdn.jsdelivr.net/npm/codemirror@5.52.0/mode/%N/%N.js';
 18    editor = new CodeMirror(document.getElementById('editor'), {
 19        lineNumbers: true,
 20        theme: 'dracula',
 21        readOnly: readOnly,
 22        scrollbarStyle: 'simple',
 23    });
 24    if (readOnly) {
 25        document.body.classList.add('readonly');
 26    }
 27};
 28
 29const initLangSelector = () => {
 30    select = new SlimSelect({
 31        select: '#language',
 32        data: CodeMirror.modeInfo.map((e) => ({
 33            text: e.name,
 34            value: slugify(e.name),
 35            data: { mime: e.mime, mode: e.mode },
 36        })),
 37        showContent: 'down',
 38        onChange: (e) => {
 39            const language = e.data || { mime: null, mode: null };
 40            editor.setOption('mode', language.mime);
 41            CodeMirror.autoLoadMode(editor, language.mode);
 42        },
 43    });
 44
 45    select.set(decodeURIComponent(new URLSearchParams(window.location.search).get('lang') || 'plain-text'));
 46};
 47
 48const initCode = () => {
 49    const base64 = location.hash.substr(1);
 50    if (base64.length === 0) {
 51        return;
 52    }
 53    decompress(base64, (code, err) => {
 54        if (err) {
 55            alert('Failed to decompress data: ' + err);
 56            return;
 57        }
 58        editor.setValue(code);
 59    });
 60};
 61
 62const initClipboard = () => {
 63    clipboard = new ClipboardJS('.clipboard');
 64    clipboard.on('success', () => {
 65        hideCopyBar(true);
 66    });
 67};
 68
 69const generateLink = (mode) => {
 70    compress(editor.getValue(), (base64, err) => {
 71        if (err) {
 72            alert('Failed to compress data: ' + err);
 73            return;
 74        }
 75        const url = buildUrl(base64, mode);
 76        showCopyBar(url);
 77    });
 78};
 79
 80// Open the "Copy" bar and select the content
 81const showCopyBar = (dataToCopy) => {
 82    const linkInput = document.getElementById('copy-link');
 83    linkInput.value = dataToCopy;
 84    linkInput.setSelectionRange(0, dataToCopy.length);
 85    document.getElementById('copy').style.display = 'flex';
 86};
 87
 88// Close the "Copy" bar
 89const hideCopyBar = (success) => {
 90    const copyButton = document.getElementById('copy-btn');
 91    const copyBar = document.getElementById('copy');
 92    if (!success) {
 93        copyBar.style.display = 'none';
 94        return;
 95    }
 96    copyButton.innerText = 'Copied !';
 97    setTimeout(() => {
 98        copyBar.style.display = 'none';
 99        copyButton.innerText = 'Copy';
100    }, 800);
101};
102
103// Build a shareable URL
104const buildUrl = (rawData, mode) => {
105    const url =
106        `${location.protocol}//${location.host}${location.pathname}` +
107        `?lang=${encodeURIComponent(select.selected())}` +
108        (mode === 'iframe' ? '&readonly' : '') +
109        `#${rawData}`;
110    if (mode === 'markdown') {
111        return `[NoPaste snippet](${url})`;
112    }
113    if (mode === 'iframe') {
114        const height = document.getElementsByClassName('CodeMirror-sizer')[0].clientHeight + 8;
115        return `<iframe width="100%" height="${height}" frameborder="0" src="${url}"></iframe>`;
116    }
117    return url;
118};
119
120// Transform a compressed base64 string into a plain text string
121const decompress = (base64, cb) => {
122    const progressBar = document.getElementById('progress');
123
124    const req = new XMLHttpRequest();
125    req.open('GET', 'data:application/octet;base64,' + base64);
126    req.responseType = 'arraybuffer';
127    req.onload = (e) => {
128        lzma.decompress(
129            new Uint8Array(e.target.response),
130            (result, err) => {
131                progressBar.style.width = '0';
132                cb(result, err);
133            },
134            (progress) => {
135                progressBar.style.width = 100 * progress + '%';
136            }
137        );
138    };
139    req.send();
140};
141
142// Transform a plain text string into a compressed base64 string
143const compress = (str, cb) => {
144    const progressBar = document.getElementById('progress');
145
146    lzma.compress(
147        str,
148        1,
149        (compressed, err) => {
150            if (err) {
151                progressBar.style.width = '0';
152                cb(compressed, err);
153                return;
154            }
155            const reader = new FileReader();
156            reader.onload = () => {
157                progressBar.style.width = '0';
158                cb(reader.result.substr(reader.result.indexOf(',') + 1));
159            };
160            reader.readAsDataURL(new Blob([new Uint8Array(compressed)]));
161        },
162        (progress) => {
163            progressBar.style.width = 100 * progress + '%';
164        }
165    );
166};
167
168const slugify = (str) =>
169    str
170        .toString()
171        .toLowerCase()
172        .replace(/\s+/g, '-')
173        .replace(/\+/g, '-p')
174        .replace(/#/g, '-sharp')
175        .replace(/[^\w\-]+/g, '');
176
177/* Only for tests purposes */
178const testAllModes = () => {
179    for (const [index, language] of Object.entries(CodeMirror.modeInfo)) {
180        setTimeout(() => {
181            console.info(language.name);
182            select.set(slugify(language.name));
183        }, 1000 * index);
184    }
185};
186
187init();