Files
term_portal/express/public/javascripts/scripts.js
T

1252 lines
34 KiB
JavaScript

/* global $, bootstrap, axios, i18next, i18nextHttpBackend */
// eslint-disable-next-line no-unused-vars
const isI18nReady = i18next.use(i18nextHttpBackend).init({
lng: document.documentElement.lang ?? 'sl',
ns: 'core',
nsSeparator: false,
keySeparator: false,
...(window.inDevEnv && { saveMissing: true }),
...(!window.inDevEnv && { fallbackLng: false })
})
const windows = ['#suggestions-root', '.advanced-search-root', '.kbd-root']
let isAdvancedSearchButtonPressedOddTimes = false
let isVirtualKeyboardPressedOddTimes = false
// Search field and virtual keyboard javascript
// ex. keyboard js
/* Render suggestion for the virtual keyboard */
// Presumably used in other files, like consultancy.js.
// eslint-disable-next-line no-unused-vars
function nthParent(element, num) {
if (num < 1) {
return element
} else {
element = element.parentNode
return nthParent(element, num - 1)
}
}
// TODO refactor code below
// All is a huge try block because the pages not containing any of the search items should NOT throw errors
function renderSuggestionsVK(text) {
renderSuggestions(
suggestions.filter(f => {
return f.substring(0, text.length).toLowerCase() === text.toLowerCase()
}),
root,
boundingBox,
'suggestions-root'
)
setVisibleSuggestionsRoot(true)
}
// ex. search-field js
// Depends on -> keyboard.js
// Definitions
// const rtcnt = '.search-suggestion-container'
const rootClass = '.search-suggestion-container'
const childOfRootId = 'suggestions-root'
const root = document.querySelector(rootClass)
// const rootRect = root.getBoundingClientRect()
/* paddingSearchRoot is linked to
.search-root-main {
padding: 0 20px;
...
} */
/* SEARCH FIELD INTERACTIONS */
/*
Intention of this file is to make tags in the advanced search.
Miha Stele 2021-12-01
*/
/* Classes */
class InputHandler {
constructor(element) {
this._id = element.id
// this.nameIsVisible = true
this.tags = []
this.focused = false
this.domElement = element
this.input = '' // select2-search__field TEXTAREA
// element.children[0].children[1].children[1].children[0].children[0].children[1].children[0]
this.labelText = element.children[0].children[1].children[1]
}
get id() {
return this._id
}
addTag(value) {
this.tags.push(value)
return value
}
removeTag(value) {
// console.log('removing ' + value)
this.tags = this.tags.filter(e => e !== value)
}
labelJump() {
// label text logic
if (this.tags.length > 0 || this.input.value.length > 0 || this.focused) {
this.labelText.classList = ['advanced-input-label jumped']
} else {
this.labelText.classList = ['advanced-input-label']
}
}
/*
evaluate press enter logic
1. check if input value is empty
2. if not go onward
3. create Tag element and append it to taglist, and create an HTML dom that represnts UI of the tag
----structure as a pug file of the tag element: --------------
.search-filter-keyword-item.pt-1.pb-1.m-1.rounded-2
span.ps-2.pe-2= searchstring
button.pe-2.border-0.bg-transparent
img.text-white(src="/images/x-black.svg")
----------- end structure, see search-filter-keyword-item for the latest struct---
4. edit elements and sub elements
5. Update UI with the new DOM element
*/
}
/* Declarations */
const inputIds = [
'area',
'src-lang',
'dest-lang',
'dict',
'source',
'consultant'
]
const inputs = []
let activeInput = null
/* Functions */
function refreshLabels(inputs) {
inputs.forEach(inpt => inpt.labelJump())
}
/*
function handleInputTextToTag(event, activeInput) {
if (event.target.localName === 'input' && event.target.type === 'text') {
activeInput.evaluatePressEnter()
}
}
function imageOrbuttonQuery(event) {
return (
event.target.localName === 'img' || event.target.localName === 'button'
)
}
*/
/*
function inputAndTextQuery(event) {
return event.target.localName === 'input' && event.target.type === 'text'
}
function deleteImageButtonSelectedQuery(event) {
return (
event.target.localName === 'img' &&
event.target.parentNode.parentNode.id.length > 0
)
}
/*
function removeTag(event) {
let elt = null
if (event.target) {
if (deleteImageButtonSelectedQuery(event)) {
elt = event.target.parentNode.parentNode
} else if (
event.target.localName === 'button' &&
event.target.parentNode.id > 0
) {
elt = event.target.parentNode
}
} else {
return
}
if (elt !== null) {
activeInput.removeTag(elt)
}
}
function removeTag(event) {
if (event) activeInput.removeTag(event.target.value)
}
*/
function selectActiveElementFromInput(eventElement) {
if (
eventElement.target.localName === 'select' &&
eventElement.target.type === 'select-multiple'
) {
activeInput = inputs.filter(
e => e.id === eventElement.target.parentNode.parentNode.parentNode.id
)[0]
}
}
/* Logic */
let count = 0
inputIds.forEach(e => {
try {
const elt = document.getElementById(e)
// elt.onclick = inputFocusedLogic
const element = new InputHandler(elt)
element.enumeratedId = count
// add listener to the input element
inputs.push(element)
count++
} catch (e) {
// console.log("DEBUG: One or more elements don't exist in the list")
}
})
/* FILTERING RESULTS */
/*
Intention of this file is to render suggestions when typing in the search bar.
Miha Stele 2021-12-01
*/
// let bodyWidth = document.getElementsByTagName('body')
const boundingBox = document.querySelector('#searchbar-main')
// const boundingBoxRect = boundingBox.getBoundingClientRect()
let init
init = false
const suggestions = [
'cenik',
'cepivo',
'cisterna',
'copat',
'cokli',
'miza',
'milo',
'mir',
'minuta',
'minotaver'
]
function ajustElementSettings(element, options) {
if (element.localName === 'button') {
element.type = 'button'
} else if (element.type === 'a') {
element.href = options.href
}
}
function applyStyles(obb, styles) {
for (let i = 0; i < styles.length; i++) {
obb.style[Object.keys(styles[i])[0]] = styles[i][Object.keys(styles[i])[0]]
}
}
// Creation od DOM Elements
/* RENDER SUGGESTIONS ONLY GENERATES THE LIST, NOT THE PROPER CONTAINERS... */
function renderSuggestions(
suggestions,
root,
boundingBox,
childOfRootId = 'suggestions-root',
type = 'button',
prepend = true,
options = {
css: ['d-none-weak flex-column suggestion-popup'],
styles: [], // root styles (absolute positioning for example)
childStyles: [] // child of root styles(relative of the absolute for example)
}
) {
const existingElement = document.querySelector(`#${childOfRootId}`)
if (existingElement) {
existingElement.parentElement.removeChild(existingElement)
}
const searchSuggestionElementRoot = document.createElement('div')
searchSuggestionElementRoot.id = childOfRootId
searchSuggestionElementRoot.classList = options.css
/* searchSuggestionElementRoot.style.left = rootRect.left + 'px'
searchSuggestionElementRoot.style.top = rootRect.bottom - 7 + 'px'
searchSuggestionElementRoot.style.width = rootRect.right - rootRect.left + 'px' */
searchSuggestionElementRoot.style['z-index'] = '1000'
const preElement = document.createElement(type)
ajustElementSettings(preElement, options)
preElement.textContent = i18next.t('Za to besedo še ni podatkov.')
preElement.disabled = true
preElement.classList = ['w-100']
preElement.classList += ` ${type}-sugg`
// searchSuggestionElementRoot.appendChild(preElement)
for (const suggestion in suggestions) {
const currElement = document.createElement(type)
ajustElementSettings(currElement, options)
currElement.textContent = suggestions[suggestion]
currElement.classList = ['w-100']
currElement.classList += ` ${type}-sugg`
searchSuggestionElementRoot.append(currElement)
}
if (suggestions.length < 1) {
searchSuggestionElementRoot.append(preElement)
}
applyStyles(root, options.styles)
applyStyles(searchSuggestionElementRoot, options.childStyles)
/*
for (let i = 0; i < options.styles.length; i++) {
root.style[Object.keys(options.styles[i])[0]] =
options.styles[i][Object.keys(options.styles[i])[0]]
}
*/
if (prepend) {
root.prepend(searchSuggestionElementRoot)
} else {
root.append(searchSuggestionElementRoot)
}
// updatePopupDimensions(rootCont, boundingBox)
return searchSuggestionElementRoot
}
function removeSuggestions(root, childOfRootId) {
root.removeChild(document.getElementById(childOfRootId))
// updatePopupDimensions(rootCont, boundingBox)
}
/* UPDATE POSITIONING IN CASE SCROLLER GIVES AN UNUSUAL OFFSET TO THE SUGGESTION POPUP */
// function updatePopupDimensions(rootCont, boundingBox) {
// const boundingBoxRect = boundingBox.getBoundingClientRect()
// const offset = 0
// if (
// document.getElementsByTagName('body').clientWidth > bodyWidth.clientWidth
// ) {
// bodyWidth = document.getElementsByTagName('Body')
// offset = bodyWidth.offsetWidth - bodyWidth.clientWidth
// }
/* rootCont.style.position = 'absolute' */
/* rootCont.style.left = `${boundingBoxRect.left - offset / 2}px`
rootCont.style.right = `${boundingBoxRect.right - offset / 2}px`
rootCont.style.top = `${boundingBoxRect.bottom - 5}px`
rootCont.style.width = `${boundingBoxRect.right - boundingBoxRect.left}px` */
// }
// function moveContainer(rootClass, boundingBoxRect) {
// move suggestions container borders
// const rootCont = document.querySelector(rootClass)
/* rootCont.style.position = 'absolute' */
/* rootCont.style.left = `${boundingBoxRect.left}px`
rootCont.style.right = `${boundingBoxRect.right}px`
rootCont.style.top = `${boundingBoxRect.bottom - 5}px`
rootCont.style.width = `${boundingBoxRect.right - boundingBoxRect.left}px`
*/
// return rootCont
// }
// const rootCont = moveContainer(rootClass, boundingBox)
/* Handler for each input on the advanced window (deprecated?) */
// functions and listeners
/*
document.querySelector('.dropdown-btn').addEventListener('click', function () {
isAdvancedSearchButtonPressedOddTimes = !isAdvancedSearchButtonPressedOddTimes
})
document
.querySelector('.search-button-keyboard')
.addEventListener('click', function () {
isVirtualKeyboardPressedOddTimes = !isVirtualKeyboardPressedOddTimes
})
*/
/* visibilty updated to display to change the viewport */
/* search-field-interction.js logic visibility */
function setVisibleAdvancedSearch(isVisible) {
isVisible
? (document.querySelector(windows[1]).style.display = 'flex')
: (document.querySelector(windows[1]).style.display = 'none')
}
function setVisibleVirtualKeyboard(isVisible) {
isVisible
? (document.querySelector(windows[2]).style.display = 'flex')
: (document.querySelector(windows[2]).style.display = 'none')
}
/* search-field-filtering-results.js logic visibility */
function setVisibleSuggestionsRoot(isVisible) {
if (document.querySelector(windows[0])) {
isVisible
? (document.querySelector(windows[0]).style.display = 'flex')
: (document.querySelector(windows[0]).style.display = 'none')
}
}
/* DECLARATIONS */
// MOVED FUNCTIONS BECAUSE OF REQUIREMENT OF COMMON LOGIC
function virtualKeyboardCheck(keyboardButtonElement) {
if (keyboardButtonElement) {
keyboardButtonElement.addEventListener('click', () => {
isVirtualKeyboardPressedOddTimes = !isVirtualKeyboardPressedOddTimes
setVisibleVirtualKeyboard(isVirtualKeyboardPressedOddTimes)
})
}
}
const kbdBtn = document.querySelector('#keyboard')
virtualKeyboardCheck(kbdBtn)
const kbdBtnSmall = document.querySelector('#keyboard-sec')
virtualKeyboardCheck(kbdBtnSmall)
// REMOVED AFTER REBASE keyboardInit('#keyboard')
// REMOVED AFTER REBASE keyboardInit('#keyboard-sec')
const toggleShowHideFilterModal = () => {
isAdvancedSearchButtonPressedOddTimes = !isAdvancedSearchButtonPressedOddTimes
setVisibleAdvancedSearch(isAdvancedSearchButtonPressedOddTimes)
}
const advSrch = document.querySelector('#advanced-search')
if (advSrch) {
advSrch.addEventListener('click', toggleShowHideFilterModal)
}
function initAdvancedSearch(ASQueryElt) {
const el = document.querySelector(ASQueryElt)
if (el) {
el.addEventListener('click', toggleShowHideFilterModal)
}
}
initAdvancedSearch('#advanced-search')
initAdvancedSearch('#advanced-search-sec')
// close advanced search and virtual keyboard
function closeUtilityContainers() {
isAdvancedSearchButtonPressedOddTimes = false
setVisibleAdvancedSearch(isAdvancedSearchButtonPressedOddTimes)
isVirtualKeyboardPressedOddTimes = false
setVisibleVirtualKeyboard(isVirtualKeyboardPressedOddTimes)
}
// document.addEventListener('click', event => {
// try {
// // selectActiveElementFromAll(event)
// // moveContainer(rootClass, boundingBox)
// // updatePopupDimensions(rootCont, boundingBox)
// /*
// // remove the Tag node logic if clicked on delete
// if (
// event &&
// event.pointerType &&
// event.pointerType.length > 0 &&
// imageOrbuttonQuery(event) &&
// event.target.parentNode.parentNode.id &&
// event.target.parentNode.parentNode.id !== 'keyboard'
// ) {
// removeTag(event.target.value)
// }
// */
// refreshLabels(inputs)
// // console.log(event)
// if (event.target.classList[1].slice(-5) === '-sugg') {
// document.querySelector('#search-query.search-input').value =
// event.target.textContent
// }
// // updatePopupDimensions(rootCont, boundingBox)
// } catch (e) {
// // console.log(e)
// // console.log(e)
// }
// setVisibleSuggestionsRoot(false)
// // Below code is just calibration of the popup windows
// // moveContainer(rootClass, boundingBoxRect)
// // updatePopupDimensions(rootCont, boundingBox)
// })
if (advSrch) {
setVisibleAdvancedSearch(false)
}
if (kbdBtn) {
setVisibleVirtualKeyboard(false)
}
if (kbdBtnSmall) {
setVisibleVirtualKeyboard(false)
}
if (activeInput) {
activeInput.labelJump()
}
// TODO Uncomment when used.
let opened = false
const navButton = document.getElementById('nav-button')
const navContentButton = document.getElementById('nav-content-button')
if (navButton !== null)
navButton.addEventListener('click', () => {
toggleNav('slidable')
})
if (navContentButton !== null)
navContentButton.addEventListener('click', () => {
toggleNav('content-nav-content')
})
function openNav(classname) {
// document.getElementById(classname).style.right = "0px";
// document.getElementsByClassName(classname)[0].style.left = "0px";
document.getElementsByClassName(classname)[0].classList.add('opened')
document.getElementsByClassName(classname)[0].classList.remove('closed')
document
.getElementById('burger-menu-img')
.setAttribute('src', '/images/left-arrow.svg')
}
function closeNav(classname) {
// document.getElementById(classname).style.width = "400px";
// document.getElementsByClassName(classname)[0].style.left = "-320px";
document.getElementsByClassName(classname)[0].classList.add('closed')
document.getElementsByClassName(classname)[0].classList.remove('opened')
document
.getElementById('burger-menu-img')
.setAttribute('src', '/images/burger-menu-button-icon.svg')
}
function toggleNav(classname) {
if (opened) {
closeNav(classname)
} else {
openNav(classname)
}
opened = !opened
}
// jump-label-common.js
function addJumpLogic(element, labelElement) {
if (!labelElement.className.includes(' jumped-common'))
labelElement.className += ' jumped-common'
}
function removeJumpLogic(element, labelElement) {
// console.log(element.value.length)
if (element.value.length < 1) {
labelElement.className = labelElement.className.replace(
' jumped-common',
''
)
}
}
function addJumpLogicListener(element, labelElement) {
return function (event) {
addJumpLogic(element, labelElement)
}
}
function removeJumpLogicListener(element, labelElement) {
return function (event) {
removeJumpLogic(element, labelElement)
}
}
/*
function removeJumpLogicListenerIfNotEmpty(
element,
labelElement,
notEmptyCondition
) {
return function (event) {
removeJumpLogic(element, labelElement)
}
}
*/
const sfm = document.querySelector('#search-in-filter-modal')
if (sfm) {
sfm.addEventListener('click', toggleShowHideFilterModal)
sfm.addEventListener('click', () => {
isVirtualKeyboardPressedOddTimes = false
setVisibleVirtualKeyboard(isVirtualKeyboardPressedOddTimes)
})
}
// LOGIN AND REGISTER LOGIC
document.querySelectorAll('.loginregisterlabel').forEach(label => {
const inputEltRelated = label.parentElement.children[1]
inputEltRelated.addEventListener(
'focus',
addJumpLogicListener(inputEltRelated, label)
)
inputEltRelated.addEventListener(
'blur',
removeJumpLogicListener(inputEltRelated, label)
)
})
// PAGINATION LOGIC. Used on all pages with pagination.
/* eslint-disable no-unused-vars */
/**
* Enables pagination logic for the specified pager UI.
*
* @param {(string|string[])} paginationRootElIds - Pager element id.
* @param {function} onPageChange - Gets called with the number of the page the user requested.
* @returns {function} - Call it with (newCurrentPage, newNumOfAllPages) to update the ui. Or without arguments, after handling a potential error.
*/
function initPagination(paginationRootElIds, onPageChange, currentPage = 1) {
let reqLock = false
let numOfAllPages
const backwardBtnEls = []
const forwardBtnEls = []
const pageInputEls = []
const pagesCountDisplayEls = []
if (Array.isArray(paginationRootElIds)) {
paginationRootElIds.forEach(id => initControls(id))
} else {
initControls(paginationRootElIds)
}
const allControlEls = [...backwardBtnEls, ...forwardBtnEls, ...pageInputEls]
function initControls(paginationRootElId) {
const rootEl = document.getElementById(paginationRootElId)
const btnFirstPage = rootEl.querySelector('.first-page')
const btnPreviousPage = rootEl.querySelector('.previous-page')
const btnNextPage = rootEl.querySelector('.next-page')
const btnLastPage = rootEl.querySelector('.last-page')
const formEl = rootEl.querySelector('form')
const pageInputEl = formEl.querySelector('input')
const pagesCountDisplayEl = formEl.querySelector('.pages-total')
numOfAllPages = +pagesCountDisplayEl.textContent
backwardBtnEls.push(btnFirstPage, btnPreviousPage)
forwardBtnEls.push(btnNextPage, btnLastPage)
pageInputEls.push(pageInputEl)
pagesCountDisplayEls.push(pagesCountDisplayEl)
rootEl.addEventListener('click', e => {
handleButtonClick(e, paginationRootElId)
})
formEl.addEventListener('submit', e => handleFormSubmit(e, pageInputEl))
}
function handleButtonClick({ target }, paginationRootElId) {
if (reqLock) return
const buttonEl = target.closest(`#${paginationRootElId} button`)
if (!buttonEl) return
if (buttonEl.classList.contains('first-page')) {
if (currentPage === 1) return
enableLock()
onPageChange(1)
} else if (buttonEl.classList.contains('previous-page')) {
if (currentPage === 1) return
enableLock()
onPageChange(currentPage - 1)
} else if (buttonEl.classList.contains('next-page')) {
if (currentPage === numOfAllPages) return
enableLock()
onPageChange(currentPage + 1)
} else if (buttonEl.classList.contains('last-page')) {
if (currentPage === numOfAllPages) return
enableLock()
onPageChange(numOfAllPages)
}
}
function handleFormSubmit(e, pageInputEl) {
e.preventDefault()
if (reqLock) return
const inputValue = +pageInputEl.value
if (!(inputValue > 0 && inputValue <= numOfAllPages)) {
alert(i18next.t('Nepravilna vrednost strani'))
pageInputEl.value = currentPage
return
}
enableLock()
onPageChange(inputValue)
}
function enableLock() {
reqLock = true
allControlEls.forEach(el => (el.disabled = true))
}
function disableLock() {
reqLock = false
allControlEls.forEach(el => (el.disabled = false))
}
function updatePagerUi(newCurrentPage, newNumOfAllPages) {
disableLock()
if (!newCurrentPage) return
currentPage = newCurrentPage
numOfAllPages = newNumOfAllPages
pageInputEls.forEach(el => (el.value = newCurrentPage))
pagesCountDisplayEls.forEach(el => (el.textContent = newNumOfAllPages))
if (newCurrentPage === 1) {
backwardBtnEls.forEach(el => (el.disabled = true))
} else {
backwardBtnEls.forEach(el => (el.disabled = false))
}
if (newCurrentPage === newNumOfAllPages) {
forwardBtnEls.forEach(el => (el.disabled = true))
} else {
forwardBtnEls.forEach(el => (el.disabled = false))
}
}
return updatePagerUi
}
// Helper function to easily remove all child nodes. Useful for pagination.
function removeAllChildNodes(parent) {
while (parent.firstChild) {
parent.removeChild(parent.firstChild)
}
}
/* eslint-enable no-unused-vars */
{
// Rewrite "back" link URLs to referrer value if its host is the same as current page's.
const { referrer } = document
const currentPageHost = location.host
const previousPageHost = referrer.split('/')[2]
if (previousPageHost === currentPageHost) {
const backLinks = document.getElementsByClassName('link-back')
for (const link of backLinks) link.href = referrer
}
}
// Redundant function, but required to do so because of the form structure
function displayTheLoginScreen() {
const regBtn = document.querySelector('#regbtn')
const logintBtn = document.querySelector('#loginbtn')
const regForm = document.querySelector('#register-form')
const loginForm = document.querySelector('#login-form')
const regHeader = document.querySelector('.regtitle')
const loginHeader = document.querySelector('.logintitle')
const regDescription = document.querySelector('.regdesc')
const loginDescription = document.querySelector('.logindesc')
// Reset the values
const lUE = document.querySelector('#login-username-or-email')
lUE.value = ''
removeJumpLogic(lUE, lUE.parentElement.children[0])
const lPL = document.querySelector('#login-password')
lPL.value = ''
removeJumpLogic(lPL, lPL.parentElement.children[0])
const lUR = document.querySelector('#register-username')
lUR.value = ''
removeJumpLogic(lUR, lUR.parentElement.children[0])
const lRN = document.querySelector('#register-name')
lRN.value = ''
removeJumpLogic(lRN, lRN.parentElement.children[0])
const lRS = document.querySelector('#register-surname')
lRS.value = ''
removeJumpLogic(lRS, lRS.parentElement.children[0])
const lRE = document.querySelector('#register-email')
lRE.value = ''
removeJumpLogic(lRE, lRE.parentElement.children[0])
const lRP = document.querySelector('#register-password')
lRP.value = ''
removeJumpLogic(lRP, lRP.parentElement.children[0])
const lRPR = document.querySelector('#register-password-repeat')
lRPR.value = ''
removeJumpLogic(lRPR, lRPR.parentElement.children[0])
if (window.getComputedStyle(loginForm, null).display === 'none') {
regBtn.className = regBtn.className.replace('d-none', '')
logintBtn.className = logintBtn.className + ' d-none'
loginForm.className = loginForm.className.replace('d-none', '')
regForm.className = regForm.className + ' d-none'
loginHeader.className = loginHeader.className.replace('d-none', '')
regHeader.className = regHeader.className + ' d-none'
loginDescription.className = loginDescription.className.replace(
'd-none',
''
)
regDescription.className = regDescription.className + ' d-none'
}
}
function focusOnTheLoginRegisterPrompt() {
const registerForm = document.getElementById('register-form')
const loginForm = document.getElementById('login-form')
const loginUsernameField = document.getElementById('login-username-or-email')
const registerUsernameField = document.getElementById('register-username')
// element.style.display === 'block' only works for inline style CSS
if (
loginUsernameField &&
window.getComputedStyle(registerForm, null).display === 'none'
) {
loginUsernameField.focus()
} else if (
registerUsernameField &&
window.getComputedStyle(loginForm, null).display
) {
registerUsernameField.focus()
}
}
const myModal = document.getElementById('staticBackdrop')
myModal.addEventListener('show.bs.modal', displayTheLoginScreen)
myModal.addEventListener('shown.bs.modal', focusOnTheLoginRegisterPrompt)
const loginSwitchBtn = document.getElementById('loginbtn')
const registerSwithcButton = document.getElementById('regbtn')
if (loginSwitchBtn) {
loginSwitchBtn.addEventListener('click', focusOnTheLoginRegisterPrompt)
}
if (registerSwithcButton) {
registerSwithcButton.addEventListener('click', focusOnTheLoginRegisterPrompt)
}
{
let unsaved = false
function unsavedData(form, sideMenu, ajaxFunction) {
form.addEventListener('input', () => {
unsaved = true
})
$('.without-addition').on('change.select2', () => {
unsaved = true
})
sideMenu.addEventListener('click', () =>
handleMenuClick(form, event, ajaxFunction)
)
}
/* SELECT 2 */
function evaluateAlerModalTarget(pf, form, ajaxFunction) {
if (unsaved) {
event.preventDefault()
openUnsavedMixin(form, pf, ajaxFunction)
}
}
function handleMenuClick(form, event, ajaxFunction) {
// alert(event.target.tagName)
// alert(event.target.href)
if (event.target.tagName === 'A') {
evaluateAlerModalTarget(event.target.href, form, ajaxFunction)
} else if (event.target.tagName === 'P') {
evaluateAlerModalTarget(
event.target.parentElement.href,
form,
ajaxFunction
)
}
}
function openUnsavedMixin(form, goToHref, ajaxFunction) {
const unsavedModal = new bootstrap.Modal(
document.getElementById('unsaved-data')
)
unsavedModal.show()
const acceptBtn = document.getElementById('modal-save-btn')
if (ajaxFunction) {
acceptBtn.addEventListener('click', () => ajaxFunction(event))
} else acceptBtn.addEventListener('click', () => form.submit())
const dontSaveBtn = document.getElementById('modal-dont-save-btn')
dontSaveBtn.addEventListener(
'click',
() => (window.location.href = goToHref)
)
}
/* SELECT 2 */
function initSelect2(querySelector, placeholder) {
$(querySelector).select2({
// allowClear: true,
placeholder: placeholder
})
// $(querySelector).val(null).trigger('change')
}
$(document).ready(function () {
// TODO refactor wth specific select2
isI18nReady.then(t => {
$('.select-search-field').select2({})
initSelect2('.select-domain-field', t('Področje'))
initSelect2('.select-src-lang-field', t('Jezik iskanja'))
initSelect2('.select-dest-lang-field', t('Ciljni jezik'))
initSelect2('.select-dict-field', t('Slovar'))
initSelect2('.select-source-field', t('Vir'))
$('b[role="presentation"]').hide()
$('.select2-selection__arrow').append(
'<img src="/images/chevron-down-darker.svg" alt="V"></img>'
)
$('.select-search-field').on('select2:select', function (e) {
selectActiveElementFromInput(e)
// console.log(activeInput)
// console.log(e.target.parentNode.children[2])
// const label = e.target.parentNode.children[2]
// console.log(activeInput)
// console.log(activeInput)
activeInput.addTag(e.params.data._resultId)
activeInput.labelJump()
})
$('.select-search-field').on('select2:unselect', function (e) {
selectActiveElementFromInput(e)
// console.log(activeInput)
// console.log(activeInput)
activeInput.removeTag(e.params.data._resultId)
activeInput.labelJump()
// console.log('DELETED ' + e)
})
inputs.forEach(e => {
e.input = e.domElement.querySelector('.select2-search__field')
})
})
})
/* TODO REMOVE OTHER SCRIPTS WHEN YOU FINISH MODULARIZING THINGS THAT COULD BE MODULARIZED */
/* window.addEventListener('resize', () => {
moveContainer(rootClass, boundingBoxRect)
// updatePopupDimensions(rootCont, boundingBox)
}) */
// select2.utils
inputs.forEach(e => {
$(`#${e.id}`).on('select2:open', function () {
e.focused = true
e.labelJump()
})
$(`#${e.id}`).on('select2:close', function () {
e.focused = false
e.labelJump()
})
})
try {
// Jquery for Select2
/*
$('#select-cerif').select2({
maximumSelectionLength: 1,
language: {
maximumSelected: function (e) {
return 'Izberete lahko največ 1 področje.'
}
}
})
*/
$('.multiple').select2({
minimumResultsForSearch: Infinity,
tags: true
})
$('.without-addition').select2({
minimumResultsForSearch: Infinity,
language: {
noResults: function () {
return 'Ni zadetkov.'
}
}
})
$('.without-addition').on('select2:select', function (evt) {
const element = evt.params.data.element
const $element = $(element)
$element.detach()
$(this).append($element)
$(this).trigger('change')
})
$('.without-dropdown').select2({
minimumResultsForSearch: Infinity,
tags: true,
dropdownCssClass: 'hide-dropdown'
})
} catch (e) {
// console.log(e)
}
}
function removeDisposableBreakOnSmallScreens() {
const optionalBreak = document.getElementById('disposable-break')
if (document.body.clientWidth <= 1200) {
optionalBreak.style.display = 'none'
} else {
optionalBreak.style.display = 'block'
}
}
function transferText(sideMenuText, removeOptionalBreak = false) {
const siteHeading = document.getElementById('site-heading')
const siteHeadingTextContent = siteHeading.textContent
const navTitle = document.getElementById('nav-title')
const optionalBreak = document.getElementById('disposable-break')
if (window.innerWidth < 1200) {
navTitle.textContent = siteHeadingTextContent
siteHeading.style.display = 'none'
if (removeOptionalBreak) {
removeDisposableBreakOnSmallScreens()
}
} else {
navTitle.textContent = sideMenuText
siteHeading.style.display = 'block'
if (removeOptionalBreak) {
removeDisposableBreakOnSmallScreens()
}
}
}
function replaceContainer(id, HTMLContent) {
const el = document.getElementById(id)
if (el) {
el.innerHTML = HTMLContent
}
}
// STATE MANAGER FOR WINDOWS IN FORGOT PASSWORD
class StateManager {
constructor() {
this.state = {}
}
setState(newState) {
this.state = { ...this.state, ...newState }
}
getState() {
return this.state
}
}
class StateManagerInvoker {
constructor(stateManager, invokeFunction) {
this.stateManager = stateManager
this.invokeFn = invokeFunction
}
setState(newState) {
this.stateManager.setState(newState)
this.invoke()
}
invoke() {
this.invokeFn()
}
}
const stateManager = new StateManager()
const forgottenPasswordInvoker = new StateManagerInvoker(stateManager, () => {
function closeAllFPRelatedModals() {
$('#staticBackdrop').modal('hide')
$('#reset-pass-modal').modal('hide')
$('#reset-pass-info').modal('hide')
}
function showLoginModal() {
$('#staticBackdrop').modal('show')
}
function showResetPasswordModal() {
$('#reset-pass-modal').modal('show')
}
function showResetPasswordModalSuccessOrFail() {
$('#reset-pass-info').modal('show')
}
function apllyDescriptionAccordingToState() {
$('#fpi-text').text(stateManager.getState().fpassWindowDescription)
}
closeAllFPRelatedModals()
switch (stateManager.getState().fpassWindowState) {
case ForgotPasswordState.LOGIN_SIGNUP:
showLoginModal()
break
case ForgotPasswordState.FORGOT_PASSWORD_MODAL:
showResetPasswordModal()
break
case ForgotPasswordState.FORGOT_PASSWORD_ERROR:
case ForgotPasswordState.FORGOT_PASSWORD_SUCCESS:
showResetPasswordModalSuccessOrFail()
apllyDescriptionAccordingToState()
break
default:
console.log('Unknown state')
}
})
const ForgotPasswordState = {
LOGIN_SIGNUP: 1,
FORGOT_PASSWORD_MODAL: 2,
FORGOT_PASSWORD_ERROR: 3,
FORGOT_PASSWORD_SUCCESS: 4
}
function onForgotPassword() {
forgottenPasswordInvoker.setState({
fpassWindowState: ForgotPasswordState.FORGOT_PASSWORD_MODAL
})
}
function onCancelForgotPassword() {
forgottenPasswordInvoker.setState({
fpassWindowState: ForgotPasswordState.LOGIN_SIGNUP
})
}
function onSendForgottenEmailRequest() {
if (document.getElementById('forgot-pass-input').value === '') {
stateManager.setState({
fpassWindowDescription: i18next.t(
'Prosimo vnesite vaš elektronski naslov.'
)
})
forgottenPasswordInvoker.setState({
fpassWindowState: ForgotPasswordState.FORGOT_PASSWORD_ERROR
})
return
}
axios
.post('/api/v1/users/reset-password-init', {
usernameOrEmail: document.getElementById('forgot-pass-input').value
})
.then(res => {
// const EMAIL = 'DUMMY_EMAIL'
// State manager because we don't want to invoker twice
// it is required to update description first before updating state of the invoker
stateManager.setState({
fpassWindowDescription: i18next.t(
'Na vaš elektronski naslov smo vam posredovali povezavo za ponastavitev gesla. Prosimo preverite svoj elektronski predal.'
)
})
forgottenPasswordInvoker.setState({
fpassWindowState: ForgotPasswordState.FORGOT_PASSWORD_SUCCESS
})
})
.catch(err => {
if (err.response && err.response.data) {
stateManager.setState({
fpassWindowDescription: err.response.data
})
} else {
stateManager.setState({
fpassWindowDescription: i18next.t(
'Prišlo je do napake pri pošiljanju sporočila na vaš elektronski naslov. Poskusite ponovno.'
)
})
}
forgottenPasswordInvoker.setState({
fpassWindowState: ForgotPasswordState.FORGOT_PASSWORD_ERROR
})
console.log(err)
})
}
$('#modal-fp-cancel-btn').on('click', onCancelForgotPassword)
$('#modal-fp-use-btn').on('click', onSendForgottenEmailRequest)
$('#modal-fp-info-close').on('click', () => $('#reset-pass-info').modal('hide'))
$('#forgotten-password').on('click', onForgotPassword)