src/assets/js/app.js
/* global location */
import $ from 'jquery'
import 'datatables.net-bs5'
import { Modal } from 'bootstrap'
import { library, icon } from '@fortawesome/fontawesome-svg-core'
import { faTrashCan, faPlay } from '@fortawesome/free-solid-svg-icons'
const publicDomain = location.hostname
library.add(faTrashCan, faPlay)
const play = icon({ prefix: 'fas', iconName: 'play' }).html
const trashCan = icon({ prefix: 'fas', iconName: 'trash-can' }).html
let $copyMessage
let $status
let deleteConfirmation
let $deleteConfirmButton
let $deleteConfirmShort
let $deleteConfirmLong
let $copiedUrl
let listTable
let $shortRow
let dcModal
const setStatus = (data) => {
console.log(data)
const classes = 'p-4 fw-bold fs-5 text-center text-light bg-' + (data.status === 'success' ? 'success' : 'danger')
$status.removeClass().addClass(classes).text(data.message).show()
if (data.action === 'create' && data.short) {
$status.append(
'<p class="mt-3 mb-0">Click to copy: <a href="https://' +
publicDomain +
'/' +
data.short +
'" title="Copy Short URL" class="copy link-light me-1">' +
publicDomain +
'/' +
data.short +
'</a></p>'
)
}
setTimeout(
() => {
$status.fadeOut()
},
data.status === 'success' ? 5000 : 15000
)
}
const setSelectors = () => {
$copyMessage = $('#copyMessage')
$copiedUrl = $('#copiedUrl')
$status = $('#status')
$deleteConfirmButton = $('#deleteConfirmButton')
deleteConfirmation = document.getElementById('deleteConfirmation')
$deleteConfirmShort = $('#deleteConfirmShort')
$deleteConfirmLong = $('#deleteConfirmLong')
$shortRow = $('#shortRow')
dcModal = new Modal(deleteConfirmation)
dcModal.hide()
deleteConfirmation.addEventListener('shown.bs.modal', function () {
$deleteConfirmButton.focus()
})
}
const getShortUrl = (short, copy) => {
return (
'<a' +
(copy ? ' title="Copy Short URL"' : '') +
' class="btn btn-secondary' +
(copy ? ' copy' : '') +
' text-nowrap" href="https://' +
publicDomain +
'/' +
short +
'">' +
short +
'</a>'
)
}
const getLongUrl = (long, copy) => {
return '<a' + (copy ? ' class="copy" title="Copy Long URL"' : '') + ' href="' + long + '">' + long + '</a>'
}
const handleCopyClick = function (e) {
e.preventDefault()
e.stopPropagation()
e.stopImmediatePropagation()
const url = $(this).prop('href')
$copiedUrl.text(url)
navigator.clipboard.writeText(url)
$copyMessage.css('display', 'flex')
setTimeout(() => {
$copyMessage.fadeOut()
}, 1500)
return false
}
const handleFormSubmit = (e) => {
e.preventDefault()
$.ajax({
url: 'url',
method: 'POST',
dataType: 'json',
data: {
short: $('#short').val(),
long: $('#long').val()
}
})
.done((d) => {
setStatus(d)
updateTable()
})
.fail((d) => {
setStatus(JSON.parse(d.responseText))
})
}
const updateTable = () => {
listTable.ajax.reload()
}
const handleDeleteClick = function () {
const data = listTable.row($(this).parents('tr')[0]).data()
$deleteConfirmShort.html(getShortUrl(data.s, false))
$deleteConfirmLong.html(getLongUrl(data.l, false))
dcModal.show()
$deleteConfirmButton.data('short', data.s)
}
const handleConfirmDeleteClick = function () {
dcModal.hide()
$.ajax({
url: 'url',
method: 'DELETE',
dataType: 'json',
data: { short: $(this).data('short') }
})
.done((d) => {
setStatus(d)
updateTable()
})
.fail((d) => {
setStatus(JSON.parse(d.responseText))
})
}
const setupDataTable = () => {
listTable = $('#list').DataTable({
ajax: 'url',
columns: [{ data: 's' }, { data: 'l' }, { data: 'c' }],
columnDefs: [
{
targets: 0,
className: 'text-nowrap',
render: (data, type) => {
if (type === 'display') {
return getShortUrl(data, true)
}
return data
}
},
{
targets: 1,
className: 'dt-overflow align-middle',
render: (data, type) => {
if (type === 'display') {
return '<span>' + getLongUrl(data, true) + '</span>'
}
return data
}
},
{
targets: 2,
className: 'd-none d-md-table-cell text-nowrap align-middle text-center',
render: (data, type) => {
if (type === 'display') {
return new Date(data * 1000).toLocaleString('en-US', { dateStyle: 'short', timeStyle: 'short' })
}
return data
}
},
{
targets: 3,
className: 'text-center text-nowrap',
data: null,
defaultContent:
'<button class="btn btn-danger text-nowrap" title="Delete">' +
trashCan +
'<span class="d-none d-lg-inline-block ms-2">Delete</span></button>'
}
],
deferRender: true,
dom: 'frtip',
lengthMenu: [5, 10, 25, 50, 100],
pageLength: 5
})
$('#list tbody').on('click', 'button', handleDeleteClick)
}
window.addEventListener('load', () => {
$('button[type="submit"]').html(play)
setSelectors()
$('#addForm').on('submit', handleFormSubmit)
$('#customShort').on('change', () => {
$shortRow.toggleClass('d-none')
})
$('main').on('click', 'a.copy', handleCopyClick)
$deleteConfirmButton.prepend(trashCan).on('click', handleConfirmDeleteClick)
setupDataTable()
})