function ajaxRequest(action, datalist, callback) { var request = false request = new XMLHttpRequest() request.open('POST', "./?page=ajax&action=" + action, true) request.send(datalist) request.onreadystatechange = function() { if (request.readyState == 4) { var json_response = '' try { json_response = JSON.parse(request.responseText) } catch(error) { console.log(request.responseText) } callback(json_response) } } } function showResult(result) { hideMessage() var contents = document.querySelector('#contents') var render = function(fragment) { var temp = document.createElement('template') fragment = replace(fragment, [ ['type', result.type], ['message', result.message] ]) temp.innerHTML = fragment contents.append(temp.content.firstChild) } getFragment('message', render) } function hideMessage() { var contents = document.querySelector('#contents') var message = contents.querySelector('#message') if(message) { contents.removeChild(message) } } function reloadOrError(result) { if(result.type == 'success') { window.location.reload(true) } else { showResult(result) } } function ucfirst(string) { return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase() } function fixDuplicateInputNames(fields) { var names = {} for(var i = 0; i < fields.length; i++) { var name = fields[i].name if(name.endsWith('[]')) { continue } if(names.hasOwnProperty(name)) { fields[i].name = name + '[]' fields[names[name]].name = name + '[]' } else { names[name] = i } } return true } function dataListFromForm(form, filter = function(field) {return true}) { var out = new FormData() var fields = form.querySelectorAll('input,textarea') fixDuplicateInputNames(fields) for(var i = 0; i < fields.length; i++) { var field = fields[i] if(filter(field)) { if(field.type == 'file') { var file = field.files[0] out.append(field.name, file, file.name) } else { out.append(field.name, field.value) } } } return out } function getFragment(name, callback) { var unpack = function(result) { if(result.type == 'success') { callback(result.message) } else { console.log(result); } } var data = new FormData() data.append('fragment', name) ajaxRequest('getfragment', data, unpack) } function replace(fragment, replacements) { var work = fragment for(const [key, value] of replacements) { var regex = new RegExp('¤' + key + '¤', 'g') work = work.replace(regex, value) } return work } function returnProduct(event) { event.preventDefault() var form = event.currentTarget var handleResult = function(result) { showResult(result) form.serial.value = '' form.serial.select() } ajaxRequest('return', dataListFromForm(form), handleResult) } function checkoutProduct(event) { event.preventDefault() var form = event.currentTarget var user = form.user.value var product = form.product.value if(!user) { showResult({'type':'error', 'message':'Ingen låntagare vald.'}) return } ajaxRequest('checkout', dataListFromForm(form), reloadOrError) } function showExtend(event) { event.preventDefault() var button = event.currentTarget var confirm = button.parentNode.querySelector('.renew_confirm') confirm.classList.remove('hidden') button.classList.add('hidden') } function extendLoan(event) { event.preventDefault() ajaxRequest('extend', dataListFromForm(event.currentTarget), reloadOrError) } function startInventory(event) { event.preventDefault() ajaxRequest('startinventory', new FormData(), reloadOrError) } function endInventory(event) { event.preventDefault() ajaxRequest('endinventory', new FormData(), reloadOrError) } function inventoryProduct(event) { event.preventDefault() ajaxRequest('inventoryproduct', dataListFromForm(event.currentTarget), reloadOrError) } function suggest(input, type) { var existing = [] var capitalize = true switch(type) { default: return showResult({'type':'error', 'message':'Invalid suggestion type.'}) break case 'field': var fieldlist = document.querySelectorAll('.info_item') for(var i = 0; i < fieldlist.length; i++) { existing.push(fieldlist[i].name) } break case 'tag': var taglist = document.querySelectorAll('#tags .tag > input') for(var i = 0; i < taglist.length; i++) { var tag = taglist[i].value existing.push(tag.toLowerCase()) } break case 'template': break case 'user': capitalize = false break } var render = function(result) { var suggestlist = input.list while(suggestlist.firstChild) { suggestlist.removeChild(suggestlist.firstChild) } var suggestions = result.message for(var i = 0; i < suggestions.length; i++) { var suggestion = suggestions[i].toLowerCase() if(existing.indexOf(suggestion) != -1) { continue } var next = document.createElement('option') if(capitalize) { next.value = ucfirst(suggestion) } else { next.value = suggestion } suggestlist.appendChild(next) } } data = new FormData() data.append('type', type) ajaxRequest('suggest', data, render) } function suggestContent(input) { var render = function(result) { var suggestlist = input.list while(suggestlist.firstChild) { suggestlist.removeChild(suggestlist.firstChild) } var suggestions = result.message for(var i = 0; i < suggestions.length; i++) { var next = document.createElement('option') next.value = suggestions[i] suggestlist.appendChild(next) } } data = new FormData() data.append('fieldname', input.name) ajaxRequest('suggestcontent', data, render) } function addField(event) { if(event.key && event.key != "Enter") { return } event.preventDefault() var tr = event.currentTarget.parentNode.parentNode var nameField = tr.querySelector('input') var form = nameField.form if(!nameField.value) { return showResult({'type': 'error', 'message': 'Fältet måste ha ett namn.'}) } var key = nameField.value.toLowerCase() if(form.querySelector('input[name="' + key + '"]')) { return showResult( {'type': 'error', 'message': 'Det finns redan ett fält med det namnet.'}) } var name = ucfirst(key) var render = function(fragment) { var temp = document.createElement('template') fragment = replace(fragment, [ ['name', name], ['key', key], ['value', ''] ]) temp.innerHTML = fragment temp = temp.content.firstChild var temptext = temp.firstChild.innerHTML var current = form.querySelector('#before_info').nextElementSibling var found = false while(!found) { if(current == tr || temptext < current.firstChild.innerHTML) { current.before(temp) found = true } current = current.nextElementSibling } nameField.value = '' } getFragment('info_item', render) } function escapeText(text) { return text .replace(/'/, ''') .replace(/"/, '"') } function addTag(event) { if(event.key && event.key != "Enter") { return suggest(event.currentTarget, 'tag') } event.preventDefault() var tr = event.currentTarget.parentNode.parentNode var field = tr.querySelector('.newtag') var tagname = escapeText(field.value) if(!tagname) { return showResult({'type': 'error', 'message': 'Taggen måste ha ett namn.'}) } tagname = ucfirst(tagname) var tagElements = tr.querySelectorAll('.tag > input') for(var i = 0; i < tagElements.length; i++) { var oldtag = tagElements[i].name if(tagname.toLowerCase() == oldtag.toLowerCase()) { return showResult({'type': 'error', 'message': 'Det finns redan en sån tagg på artikeln.'}) } } var render = function(fragment) { var temp = document.createElement('template') temp.innerHTML = replace(fragment, [['tag', tagname]]) temp = temp.content.firstChild var tag = field.parentNode.firstChild var found = false while(!found) { if(tag == field || temp.innerHTML < tag.innerHTML) { tag.before(temp) found = true } tag = tag.nextElementSibling } field.value = '' } getFragment('tag', render) } function removeTag(event) { event.preventDefault() var tag = event.currentTarget.parentNode var parent = tag.parentNode parent.remove(tag) } function loadTemplate(event) { var form = event.currentTarget var input = form.template var template = ucfirst(input.value.toLowerCase()) if(template === '') { return } var options = input.list.childNodes if(options.length == 0) { return } for(var i = 0; i < options.length; i++) { if(options[i].value == template) { return } } event.preventDefault() showResult({'type': 'error', 'message': 'Det finns ingen mall med det namnet.'}) } function saveTemplate(event) { event.preventDefault() var datalist = productDataList(document.querySelector('#product-data')) datalist.append('template', event.currentTarget.form.template.value) ajaxRequest('savetemplate', datalist, showResult) } function deleteTemplate(event) { var input = event.currentTarget.form.template event.preventDefault() var render = function(result) { if(result.type == 'success') { input.value = '' } showResult(result) } ajaxRequest('deletetemplate', dataListFromForm(event.currentTarget.form), render) } function saveProduct(event) { event.preventDefault() var action = document.activeElement.id if(action == 'reset') { return window.location.reload(true) } var form = event.currentTarget var prodid = form.id.value if(prodid == '') { action = 'save' } else { action = 'update' } var datalist = productDataList(form) var render = function(result) { if(action == 'save' && result.type == 'success') { showResult(result) var inputs = form.querySelectorAll('input[type="text"]') for(var i = 0; i < inputs.length; i++) { inputs[i].value = ''; } } else { reloadOrError(result) } } ajaxRequest('updateproduct', datalist, render) } function updateUser(event) { event.preventDefault() var action = document.activeElement.id if(action == 'reset') { return window.location.reload(true) } var form = event.currentTarget ajaxRequest('updateuser', dataListFromForm(form), reloadOrError) } function uploadAttachment(event) { event.preventDefault() var form = event.currentTarget var render = function(result) { if(result.type != 'success') { showResult(result) return } var classvalue = 'attachment-list' var list = form.parentNode.querySelector('.'+classvalue) if(list == null) { list = document.createElement('ul') list.classList.add(classvalue) var p = form.parentNode.querySelector('p') p.replaceWith(list) } var temp = document.createElement('template') temp.innerHTML = result.message list.appendChild(temp.content.firstChild) } var filter = function(input) { if(input.name == 'filename') { return false; } return true; } ajaxRequest('addattachment', dataListFromForm(form, filter), render) } function deleteAttachment(event) { event.preventDefault() var form = event.currentTarget var node = form.parentNode var name = form.name.value if(window.confirm("Är du säker på att du vill ta bort bilagan '" +name+"'?")) { var render = function(result) { if(result.type == 'success') { var list = node.parentNode list.removeChild(node) if(list.childElementCount == 0) { var p = document.createElement('p') p.append('Inga bilagor.') list.replaceWith(p) } } else { showResult(result); } } ajaxRequest('deleteattachment', dataListFromForm(form), render) } } function productDataList(form) { var filter = function(input) { var name = input.name if(name == 'new_key' || name == 'new_tag') { return false } return true } var datalist = dataListFromForm(form, filter) return datalist } function calendar(event) { var input = event.currentTarget if(!input.cal) { var cal = new dhtmlXCalendarObject(input.id) cal.hideTime() cal.setDate(input.value) input.cal = cal cal.show() } } function discardProduct(event) { event.preventDefault() if(!window.confirm( 'Är du säker på att du vill skrota artikeln? \n' + 'Den kommer fortsättningsvis kunna ses på Historik-sidan.')) { return } var form = event.currentTarget.parentNode var render = function(result) { if(result.type == 'success') { window.location.href = '?page=products' } else { showResult(result) } } ajaxRequest('discardproduct', dataListFromForm(form), render) } function toggleService(event) { event.preventDefault() var form = event.currentTarget.parentNode var render = function(result) { if(result.type == 'success') { window.location.reload(false) } else { showResult(result) } } ajaxRequest('toggleservice', dataListFromForm(form), render) } function searchInput(event) { if(event.key != "Enter") { return } var input = event.target var term = input.value.toLowerCase() if(term === '') { return } event.preventDefault() var terms = document.querySelector('#terms') var parts = escapeText(term).trim().split(':') var parsedTerm = 'Fritext: ' + parts[0] var key = 'fritext' var value = parts[0] if(parts.length > 1) { key = parts[0].trim() value = parts.slice(1).join(':').trim() parsedTerm = ucfirst(key) + ': ' + value } var render = function(fragment) { var temp = document.createElement('template') fragment = replace(fragment, [['term', parsedTerm], ['key', key], ['value', value]]) temp.innerHTML = fragment terms.append(temp.content.firstChild) input.value = '' } getFragment('search_term', render) } function doSearch(event) { var form = document.querySelector('#search') var fields = form.querySelectorAll('input,textarea') fixDuplicateInputNames(fields) } function removeTerm(event) { event.preventDefault() var term = event.currentTarget.parentNode var parent = term.parentNode parent.remove(term) } function selectFile(event) { var fileinput = event.currentTarget.parentNode.uploadfile fileinput.click() } function showFile(event) { var filefield = event.currentTarget.parentNode.filename filefield.value = event.currentTarget.files[0].name } function loanLength(event, length, unit) { event.preventDefault() var end = document.getElementById('end') var enddate = new Date() switch(unit) { case 'day': enddate.setDate(enddate.getDate() + length) break case 'year': enddate.setFullYear(enddate.getFullYear() + length) break; } // javascript zero-indexes months because of course var month = enddate.getMonth() + 1 if(month < 10) { month = '0' + month } var day = enddate.getDate() if(day < 10) { day = '0' + day } end.value = enddate.getFullYear() + '-' + month + '-' + day }