{"version":3,"file":"bundle.min.js","sources":["../../js/dom.js","../../js/tag_input.js","../../js/data_tables.js","../../js/main.js"],"sourcesContent":["const $ = function(selector) {\n    return document.querySelector(selector);\n};\n\nconst $$ = function(selector) {\n    return document.querySelectorAll(selector) || [];\n};\n\nconst makeEl = function(html) {\n    const template = document.createElement('template');\n\n    template.innerHTML = html.trim();\n\n    return template.content.firstChild;\n};\n\nconst clearEl = function(el) {\n    while (el.firstChild) {\n        el.removeChild(el.firstChild);\n    }\n};\n\nconst toggleEl = function(el) {\n    if (el.classList.contains('is-hidden')) {\n        el.classList.remove('is-hidden');\n    } else {\n        el.classList.add('is-hidden');\n    }\n};\n\nconst escape = function(unsafe) {\n    return unsafe\n        .replace(/&/g, \"&amp;\")\n        .replace(/</g, \"&lt;\")\n        .replace(/>/g, \"&gt;\")\n        .replace(/\"/g, \"&quot;\")\n        .replace(/'/g, \"&#039;\");\n}\n\n\nexport { $, $$, makeEl, clearEl, toggleEl, escape };","import { makeEl, escape } from \"./dom\";\n\nclass TagsInput {\n    constructor(element, options = {}) {\n        this.element = element;\n        this.tags = [];\n        this.options = options\n\n        this.maxTags = options.maxTags || 10;\n        this.inputNode = null;\n        this.containerNode = null;\n    }\n\n    attach() {\n        this.element.style.display = 'none';\n\n        this.containerNode = makeEl('<div class=\"tags-input\"></div>');\n        this.inputNode = makeEl('<input class=\"input\" type=\"text\" placeholder=\"10 tags maximum\" value=\"\" />');\n        this.containerNode.appendChild(this.inputNode);\n\n        this.element.parentNode.insertBefore(this.containerNode, this.element.nextSibling);\n\n        /* Load existing tags from input */\n        if (this.element.value) {\n            for (const tag of this.element.value.split(',')) {\n                this.addTag(tag);\n            }\n        }\n\n        /* Handle addition and removal of tags via key-presses */\n        this.containerNode.addEventListener('keydown', this._handleInputKeyUp.bind(this));\n\n        /* Handle deletions by clicking the delete button */\n        this.containerNode.addEventListener('click', this._handleContainerClick.bind(this));\n    }\n\n    detach() {\n        this.tags.clear();\n        this.containerNode.remove();\n        this.element.style.display = 'inline-block';\n    }\n\n    updateHiddenInputValue() {\n        this.element.value = this.tags.join(',');\n    }\n\n    deleteTagNode(node) {\n        this.tags.splice(this.tags.indexOf(node.dataset.value.toLowerCase()), 1);\n        node.remove();\n\n        /* Below the limit? Make sure the input is enabled. */\n        if (this.tags.length < this.maxTags) {\n            this.inputNode.disabled = false;\n        }\n    }\n\n    addTag(tagValue) {\n        tagValue = tagValue.trim();\n\n        /* Tag value is probably not empty and we don't already have the same tag. */\n        if (tagValue !== '' && this.tags.indexOf(tagValue.toLowerCase()) === -1) {\n            this.tags.push(tagValue.toLowerCase());\n\n            this.inputNode.parentNode.insertBefore(\n                makeEl('<span class=\"tag is-info\" data-value=\"' + escape(tagValue) + '\">' + escape(tagValue) + '<span class=\"delete is-small\" /></span>'),\n                this.inputNode\n            );\n\n            /* Too many tags, disable the input for now. */\n            if (this.tags.length >= this.maxTags) {\n                this.inputNode.disabled = true;\n            }\n        }\n    }\n\n    _handleInputKeyUp(evt) {\n        let tagValue = this.inputNode.value;\n\n        if (evt.key === 'Backspace' && tagValue === '') {\n            // Remove the child\n            if (this.inputNode.previousSibling) {\n                this.deleteTagNode(this.inputNode.previousSibling);\n\n                this.updateHiddenInputValue();\n            }\n        } else if (evt.key === ',') {\n            this.addTag(tagValue);\n\n            this.inputNode.value = ''\n            this.updateHiddenInputValue();\n\n            evt.preventDefault();\n        }\n    }\n\n    _handleContainerClick(evt) {\n        if (evt.target && evt.target.classList.contains('delete')) {\n            this.deleteTagNode(evt.target.closest('.tag'));\n            this.updateHiddenInputValue();\n        }\n    }\n}\n\nexport { TagsInput };\n","import { makeEl, clearEl } from \"./dom\";\n\n\nclass SimplePaginator {\n    constructor(element) {\n        this.element = element;\n    }\n\n    attach(pageCallback) {\n        this.element.addEventListener('click', evt => {\n            if (evt.target && evt.target.classList.contains('paginator__button')) {\n                pageCallback(+evt.target.dataset.page);\n            }\n        });\n    }\n\n    update(totalRecords, perPage, currentPage) {\n        clearEl(this.element);\n\n        /* First and last page in existence */\n        const firstPage = 0;\n        const lastPage = Math.floor(totalRecords / perPage); // ish?\n        const numPagesToShow = 2;\n\n        /* First and last page the main paginator will show */\n        const firstPageShow = (currentPage - firstPage) < numPagesToShow ? firstPage : ((currentPage - numPagesToShow < 0) ? currentPage : currentPage - numPagesToShow);\n        const lastPageShow = (firstPageShow + numPagesToShow) > lastPage ? lastPage : (firstPageShow + numPagesToShow + numPagesToShow);\n\n        /* Whether to show the first and last pages in existence at the ends of the paginator */\n        const showFirstPage = (Math.abs(firstPage - currentPage)) > (numPagesToShow);\n        const showLastPage = (Math.abs(lastPage - currentPage)) > (numPagesToShow);\n\n\n        const prevButtonDisabled = currentPage === firstPage ? 'disabled' : ''\n\n        /* Previous button */\n        this.element.appendChild(makeEl(\n            `<a class=\"paginator__button previous ${prevButtonDisabled}\" data-page=\"${currentPage - 1}\">Previous</a>`\n        ));\n\n        /* First page button */\n        if (showFirstPage) {\n            this.element.appendChild(makeEl(\n                `<a class=\"paginator__button\" data-page=\"${firstPage}\">${firstPage}</a>`\n            ));\n            this.element.appendChild(makeEl(`<span class=\"ellipsis\">…</span>`));\n        }\n\n        /* \"window\" buttons */\n        for (let i = firstPageShow; i <= lastPageShow; i++) {\n            const selected = (i === currentPage ? 'paginator__button--selected' : '');\n            this.element.appendChild(makeEl(\n                `<a class=\"paginator__button ${selected}\" data-page=\"${i}\">${i}</a>`\n            ));\n        }\n\n        /* Last page button */\n        if (showLastPage) {\n            this.element.appendChild(makeEl(`<span class=\"ellipsis\">…</span>`));\n            this.element.appendChild(makeEl(\n                `<a class=\"paginator__button\" data-page=\"${lastPage}\">${lastPage}</a>`\n            ));\n        }\n\n        const nextButtonDisabled = currentPage === lastPage ? 'disabled' : ''\n        /* Next button */\n        this.element.appendChild(makeEl(\n            `<a class=\"paginator__button next ${nextButtonDisabled}\" data-page=\"${currentPage + 1}\">Next</a>`\n        ));\n    }\n}\n\nclass DataTable {\n    constructor(element, options) {\n        this.element = element;\n        this.container = element.parentElement;\n        this.options = options;\n\n        this.ajaxCallback = options.ajaxCallback;\n        this.data = [];\n\n        this.totalRecords = -1;\n        this.perPage = 20;\n        this.currentPage = 0;\n\n        this.paginator = new SimplePaginator(this.container.querySelector('.paginator'));\n\n    }\n\n    attach() {\n        this.paginator.attach(this._updatePage.bind(this));\n        this._loadEntries();\n    }\n\n    /* Load the requested data from the server, and when done, update the DOM. */\n    _loadEntries() {\n        new Promise(this.ajaxCallback)\n            .then(this._updateEntries.bind(this));\n    }\n\n    /* Update the DOM to reflect the current state of the data we have loaded */\n    _updateEntries(data) {\n        this.data = data.data;\n        this.totalRecords = this.data.length;\n\n        const bodyElement = this.element.querySelector('tbody');\n        clearEl(bodyElement);\n\n        const firstIndex = (this.perPage * this.currentPage);\n        const lastIndex = (firstIndex + this.perPage) > this.totalRecords ? this.totalRecords : (firstIndex + this.perPage);\n\n\n        for (let i = firstIndex; i < lastIndex; i++) {\n            const rowElem = makeEl(this.options.rowCallback(this.data[i]));\n            rowElem.classList.add(i % 2 === 0 ? 'odd' : 'even');\n\n            bodyElement.appendChild(rowElem);\n        }\n\n        this.paginator.update(this.totalRecords, this.perPage, this.currentPage);\n    }\n\n    _updatePage(n) {\n        this.currentPage = n;\n        this.paginator.update(this.totalRecords, this.perPage, this.currentPage);\n        this._updateEntries({data: this.data});\n    }\n\n    _updateSort(field, direction) {\n\n    }\n}\n\nexport { DataTable };\n","import { $, $$, escape, toggleEl } from './dom';\nimport { TagsInput } from \"./tag_input\";\nimport { DataTable } from \"./data_tables\";\n\nconst setupSite = function() {\n    Array.prototype.forEach.call($$('.js-tag-input'), (el) => {\n        new TagsInput(el).attach();\n    });\n\n    if (document.querySelector('#archive')) {\n        const table = new DataTable(document.querySelector('#archive'), {\n            ajaxCallback: (resolve) => {\n                fetch('/api/ajax_pastes.php')\n                    .then(r => r.json())\n                    .then(resolve);\n            },\n            rowCallback: (rowData) => {\n                const tags = rowData.tags.map((tagData) => {\n                    let tagColorClass;\n                    if (tagData.name.indexOf('nsfw') !== -1) {\n                        tagColorClass = 'is-danger';\n                    } else if (tagData.name.indexOf('safe') !== -1) {\n                        tagColorClass = 'is-success';\n                    } else if (tagData.name.indexOf('/') !== -1) {\n                        tagColorClass = 'is-primary';\n                    } else {\n                        tagColorClass = 'is-info';\n                    }\n\n                    return `<a href=\"/tags/${tagData.slug}\">\n                                <span class=\"tag ${tagColorClass}\">${escape(tagData.name)}</span>\n                            </a>`;\n                }).join('');\n\n                return `<tr>\n                            <td><a href=\"/${rowData.id}\">${escape(rowData.title)}</a></td>\n                            <td><a href=\"/user/${escape(rowData.author)}\">${escape(rowData.author)}</a></td>\n                            <td>${tags}</td>\n                        </tr>`;\n            }\n        });\n        table.attach();\n    }\n\n    const signupButton = $('[data-target~=\"#signin\"],[data-target~=\"#signup\"]');\n\n    if (signupButton) {\n        signupButton.addEventListener('click', () => {\n            $('.modal').classList.add('is-active');\n        });\n\n        $('.modal-button-close').addEventListener('click', () => {\n            $('.modal').classList.remove('is-active');\n        });\n    }\n\n    const embedButton = $('.panel-tools .embed-tool');\n\n    if (embedButton){\n        embedButton.addEventListener('click', (evt) => {\n            if (evt.target && evt.target.closest('.panel-tools')) {\n                toggleEl(evt.target.closest('.panel-tools').querySelector('.panel-embed'));\n            }\n        });\n    }\n\n    const expandButton = $('.expand-tool');\n\n    if (expandButton) {\n        expandButton.addEventListener('click', (evt) => {\n            if (evt.target && evt.target.closest('.panel')) {\n                const panel = evt.target.closest('.panel');\n\n                if (panel.classList.contains('panel-fullsize')) {\n                    panel.classList.remove('panel-fullsize');\n                } else {\n                    panel.classList.add('panel-fullsize');\n                }\n            }\n        });\n    }\n};\n\nif (document.readyState !== 'loading') {\n    setupSite();\n} else {\n    document.addEventListener('DOMContentLoaded', setupSite);\n}\n"],"names":["$","selector","document","querySelector","makeEl","html","template","createElement","innerHTML","trim","content","firstChild","clearEl","el","removeChild","escape","unsafe","replace","TagsInput","element","options","tags","maxTags","inputNode","containerNode","style","display","appendChild","this","parentNode","insertBefore","nextSibling","value","split","tag","addTag","addEventListener","_handleInputKeyUp","bind","_handleContainerClick","clear","remove","join","node","splice","indexOf","dataset","toLowerCase","length","disabled","tagValue","push","evt","key","previousSibling","deleteTagNode","updateHiddenInputValue","preventDefault","target","classList","contains","closest","SimplePaginator","pageCallback","page","totalRecords","perPage","currentPage","lastPage","Math","floor","firstPageShow","lastPageShow","showFirstPage","abs","showLastPage","prevButtonDisabled","i","selected","nextButtonDisabled","DataTable","container","parentElement","ajaxCallback","data","paginator","attach","_updatePage","_loadEntries","Promise","then","_updateEntries","bodyElement","firstIndex","lastIndex","rowElem","rowCallback","add","update","n","field","direction","setupSite","Array","prototype","forEach","call","querySelectorAll","resolve","fetch","r","json","rowData","map","tagData","tagColorClass","name","slug","id","title","author","signupButton","embedButton","expandButton","panel","readyState"],"mappings":"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"}