352 lines
9.1 KiB
JavaScript
352 lines
9.1 KiB
JavaScript
import Templates from '../templates/Views'
|
|
import { createNode, destroyNode, findDates, formatDate, parseURL, replaceURLPathname, ucWords } from '../helpers'
|
|
import NotesAPI from './NotesAPI'
|
|
import ValidationController from './ValidationController'
|
|
import Alert from './AlertController'
|
|
|
|
export default class DOMController {
|
|
|
|
constructor (root, routes) {
|
|
this.routes = routes
|
|
this.root = root
|
|
|
|
try {
|
|
this.root.innerHTML = Templates.grid
|
|
this.renderRoutes()
|
|
} catch (e) {
|
|
Alert.displayDialog(e.toString(), 0, 3)
|
|
}
|
|
|
|
this.btnCreateNote = this.root.querySelector(window.env.querySelectors.btnCreateNote)
|
|
this.btnPrepopulate = this.root.querySelector(window.env.querySelectors.btnPrepopulate)
|
|
this.createNotesGrid(window.env.prePopulateAmount || 0)
|
|
|
|
this.listener([
|
|
[this.btnCreateNote, 'click', (this.btnCreateNote.dataset.action || 'showError'), { legend: 'Create Note' }],
|
|
[this.btnPrepopulate, 'click', (this.btnPrepopulate.dataset.action || 'showError')],
|
|
])
|
|
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
renderRoutes () {
|
|
|
|
for (const [route, name] of Object.entries(this.routes.routes)) {
|
|
|
|
const tab = createNode('li')
|
|
tab.classList.add('nav-tab')
|
|
|
|
if (route === '/') {
|
|
tab.classList.add('initial')
|
|
tab.classList.add('uk-active')
|
|
}
|
|
|
|
tab.innerHTML = `<a href="${route}">${name}</a>`
|
|
const anchor = tab.querySelector('a')
|
|
this.routes.navbar.appendChild(tab)
|
|
|
|
this.listener([anchor, 'click', 'createNotesGridByRoute', anchor])
|
|
}
|
|
}
|
|
|
|
createNotesGridByRoute (navTab) {
|
|
const pathname = parseURL(navTab.href).pathname
|
|
const route = pathname.slice(1).split('\/')[0]
|
|
window.history.pushState('', navTab.innerText, pathname) //change url without reload
|
|
//history.pushState({}, null, pathname) //change url
|
|
|
|
this.routes.navbar.querySelector('.uk-active').classList.remove('uk-active')
|
|
navTab.closest('.nav-tab').classList.add('uk-active')
|
|
|
|
document.getElementById(window.env.querySelectors.analyticsGrid.slice(1)).classList.add('uk-hidden')
|
|
document.getElementById(window.env.querySelectors.notesGrid.slice(1)).classList.remove('uk-hidden')
|
|
|
|
switch (route) {
|
|
case 'all':
|
|
this.createNotesGrid(0, null)
|
|
break
|
|
case '':
|
|
this.createNotesGrid(window.env.prePopulateAmount || 0)
|
|
break
|
|
case 'archive':
|
|
this.createNotesGrid(window.env.prePopulateAmount || 0, true)
|
|
break
|
|
case 'analytics':
|
|
document.getElementById(window.env.querySelectors.notesGrid.slice(1)).classList.add('uk-hidden')
|
|
const analyticsGrid = document.getElementById(window.env.querySelectors.analyticsGrid.slice(1))
|
|
this.createAnalyticsGrid(analyticsGrid)
|
|
break
|
|
}
|
|
}
|
|
|
|
prePopulate () {
|
|
const fakerAmount = document.querySelector(env.querySelectors.selectPrepopulate)
|
|
|
|
if (+fakerAmount.value <= 0) {
|
|
return
|
|
}
|
|
env.fakerAmount = (+fakerAmount.value > 44) ? 44 : +fakerAmount.value
|
|
localStorage.removeItem(window.env.localStorageKey)
|
|
fakerAmount.selectedIndex = 0
|
|
document.querySelector('.nav-tab.uk-active > a').click()
|
|
|
|
}
|
|
|
|
/**
|
|
* The method is being called for typical DOM-event task inside the table row
|
|
* to manipulate with records: deleting, editing, archiving.
|
|
*
|
|
* @param node
|
|
* @param method
|
|
*/
|
|
noteToAction (node, method) {
|
|
|
|
const row = node.closest('tr')
|
|
|
|
NotesAPI[method](parseInt(row.dataset.id, 10))
|
|
row.classList.add('as-removing')
|
|
|
|
setTimeout(() => {
|
|
row.remove()
|
|
document.querySelector('.nav-tab.uk-active > a').click()
|
|
}, 1050)
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param node
|
|
*/
|
|
noteToArchive (node) {
|
|
this.noteToAction(node, 'archiveNote')
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param node
|
|
*/
|
|
noteFromArchive (node) {
|
|
this.noteToAction(node, 'unArchiveNote')
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param node
|
|
*/
|
|
noteToTrash (node) {
|
|
this.noteToAction(node, 'deleteNote')
|
|
}
|
|
|
|
createAnalyticsGrid (grid) {
|
|
grid.classList.remove('uk-hidden')
|
|
const aGrid = grid.querySelector(' tbody')
|
|
aGrid.innerHTML = ''
|
|
|
|
for (const [key, value] of Object.entries(NotesAPI.getAnalytics())) {
|
|
|
|
const row = createNode('tr')
|
|
const td = createNode('td', {}, ucWords(key))
|
|
row.appendChild(td)
|
|
|
|
for (const [key, val] of Object.entries( value ) ) {
|
|
const td = createNode('td', {}, val.toString())
|
|
row.appendChild(td)
|
|
}
|
|
|
|
aGrid.appendChild(row)
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param len
|
|
* @param archived
|
|
*/
|
|
createNotesGrid (len = window.env.prePopulateAmount || 0, archived = false) {
|
|
|
|
const notesGrid = document.querySelector(window.env.querySelectors.notesGrid + ' tbody')
|
|
notesGrid.innerHTML = ''
|
|
|
|
const notes = NotesAPI.getNotesSanitized(len, archived)
|
|
if (notes.length === 0) { return }
|
|
|
|
notes.forEach(el => {
|
|
|
|
const row = createNode('tr')
|
|
row.dataset.id = el.id
|
|
|
|
window.env.gridOrder.notes.forEach(key => {
|
|
let attrs = {}
|
|
let value = el[key] || ''
|
|
|
|
switch (key) {
|
|
case 'createdAt':
|
|
value = formatDate(value)
|
|
break
|
|
case 'category':
|
|
value = ucWords(value)
|
|
break
|
|
case 'title':
|
|
attrs.class = 'uk-text-bold'
|
|
break
|
|
case 'dates':
|
|
attrs.style = 'font-size: 12px'
|
|
value = findDates(el.content).join(', ')
|
|
break
|
|
case 'edit' :
|
|
attrs.class = 'grid-control icon icon-edit'
|
|
attrs['data-action'] = 'getEditForm'
|
|
break
|
|
case 'archive' :
|
|
attrs.class = 'grid-control icon ' + (value === 'on' ? 'icon-unarchive' : 'icon-archive')
|
|
attrs['data-action'] = value === 'on' ? 'noteFromArchive' : 'noteToArchive'
|
|
value = ''
|
|
break
|
|
case 'delete' :
|
|
attrs.class = 'icon icon-delete grid-control'
|
|
attrs['data-action'] = 'noteToTrash'
|
|
break
|
|
}
|
|
|
|
const td = createNode('td', attrs, value)
|
|
|
|
if (key.match(/^(edit|archive|delete)$/)) {
|
|
this.listener([td, 'click', td.dataset.action, td])
|
|
}
|
|
|
|
row.appendChild(td)
|
|
|
|
})
|
|
notesGrid.appendChild(row)
|
|
})
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param selector
|
|
* @returns {{}}
|
|
*/
|
|
static getFormData (selector = window.env.querySelectors.noteEditForm) {
|
|
const formData = new FormData(document.querySelector(selector))
|
|
const data = {}
|
|
|
|
for (let key of formData.keys()) {
|
|
data[key] = formData.get(key)
|
|
}
|
|
return data
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param args
|
|
*/
|
|
getEditForm (args = {}) {
|
|
|
|
const node = createNode('div', { class: window.env.querySelectors.modal.slice(1) },
|
|
Templates.templates.editForm)
|
|
|
|
if (args.legend) {
|
|
node.querySelector('legend').innerHTML = args.legend
|
|
} else {
|
|
DOMController.fillTheForm(node, args)
|
|
}
|
|
|
|
this.root.appendChild(node)
|
|
node.style.display = 'block'
|
|
|
|
const contentInput = node.querySelector('textarea[maxlength]')
|
|
const titleInput = node.querySelector('input[maxlength]')
|
|
|
|
this.listener([
|
|
[node.querySelector(window.env.querySelectors.btnDestroyModal), 'click', destroyNode, node], //Remove modal dialog
|
|
[node.querySelector('form'), 'submit', NotesAPI.saveNote],
|
|
[contentInput, 'keydown', ValidationController.lengthOnKeyUp, contentInput],
|
|
[titleInput, 'keydown', ValidationController.lengthOnKeyUp, titleInput],
|
|
])
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param $form
|
|
* @param $el
|
|
*/
|
|
static fillTheForm ($form, $el) {
|
|
if ($el instanceof Element) {
|
|
const note = NotesAPI.getNoteByID(+$el.closest('tr').dataset.id)
|
|
|
|
if (note.length === 1) {
|
|
for (const [key, value] of Object.entries(note[0])) {
|
|
const $input = $form.querySelector(`[name='${key}']`)
|
|
|
|
if ($input instanceof Element) {
|
|
|
|
if ($input.type === 'checkbox') {
|
|
|
|
if (value !== '') {
|
|
$input.click()
|
|
}
|
|
|
|
} else {
|
|
$input.value = value
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The function takes single DOM element or list of them
|
|
*
|
|
* @param els
|
|
* @returns {void|*}
|
|
*/
|
|
listener (els) { return els[0] instanceof Element ? this.on(els) : els.forEach(el => this.on(el)) }
|
|
|
|
/**
|
|
* TODO: guessed this should be rethought
|
|
* @param args
|
|
*/
|
|
on (args) {
|
|
|
|
const [selector, event, method] = args
|
|
|
|
if (!(selector instanceof Element)) {
|
|
Alert.displayDialog(`Internal Error: Try reload a page`, 3000, 3)
|
|
return false
|
|
}
|
|
|
|
try {
|
|
selector.addEventListener(event, evt => {
|
|
const params = args[3] || {}
|
|
|
|
if (selector.tagName === 'A') {
|
|
evt.preventDefault()
|
|
}
|
|
|
|
if (evt.type === 'submit') {
|
|
evt.preventDefault()
|
|
|
|
setTimeout(() => {
|
|
document.querySelector('.nav-tab.uk-active > a').click()
|
|
}, 300)
|
|
}
|
|
|
|
if (typeof this[method] === 'function') {
|
|
this[method](params)
|
|
} else if (typeof method === 'function') {
|
|
method(params)
|
|
}
|
|
})
|
|
|
|
return true
|
|
|
|
} catch (err) {
|
|
Alert.displayDialog(`Error: ${err.toString()}`, 3000, 3)
|
|
|
|
return false
|
|
}
|
|
}
|
|
|
|
} |