all repos — NoPaste @ 9069e4673cfe2da0bf258442e97af52d4afe2af1

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