Initial import

This commit is contained in:
Admin Nasledstvo
2026-05-01 20:52:04 +03:00
commit ac168868ee
10028 changed files with 2337954 additions and 0 deletions
@@ -0,0 +1,294 @@
function updateStatus(e) {
const url = window.location.search ? window.location.href + '&o=u' : window.location.href + '?o=u';
const postData = e.dataset;
postData.value = e.checked ? 1 : null;
const msgYes = e.dataset.yes;
const msgNo = e.dataset.no;
const blinkUpdate = one(`#blink_${e.dataset.id}`);
//const
if (blinkUpdate) {
if (e.checked) {
if(blinkUpdate.dataset.published) {
blinkUpdate.innerHTML = blinkUpdate.dataset.published;
}
blinkUpdate.classList.remove('blink-green')
} else {
if(blinkUpdate.dataset.unpublished) {
blinkUpdate.innerHTML = blinkUpdate.dataset.unpublished;
}
blinkUpdate.classList.add('blink-green')
}
}
request({
url: url,
post: postData,
done: data => {
if (data.successMsg) {
if (e.checked) {
flash.success(msgYes, true)
} else {
flash.success(msgNo, true)
}
}
}
})
}
function symbolInputProtect(e) {
e.value = e.value.replace(':', '');
e.value = e.value.replace('\'', '');
e.value = e.value.replace('\"', '');
}
function searchInCheckList(e) {
all('.check-list label').forEach(l => {
console.log(l.dataset.name);
if (l.dataset.name.indexOf(e.value) !== -1) {
l.style.display = 'block';
} else {
l.style.display = 'none';
}
});
}
function setSingleFileImage(e) {
const [defaultIcon, add, edit, remove] = [
appendElem('i', e.dataset.default, e.parentNode),
appendElem('i', 'la la-plus', e),
appendElem('i', 'la la-pencil', e),
appendElem('i', 'la la-remove', e),
];
let [canvas, img] = [null, null];
if (e.dataset.src) {
add.addClass('hidden');
defaultIcon.addClass('hidden');
img = addImg('appear', e.parentNode, e.dataset.src, 'prepend');
} else {
edit.addClass('hidden');
remove.addClass('hidden');
}
if (add) {
add.title = e.dataset.add;
add.addEventListener('click', function () {
chooseSingleFileImage(add, e.dataset.imageName, function (c) {
defaultIcon.addClass('hidden');
add.addClass('hidden');
edit.removeClass('hidden');
remove.removeClass('hidden');
canvas = c;
flash.warning(e.dataset.warning)
});
});
}
if (edit) {
edit.title = e.dataset.edit;
edit.addEventListener('click', function () {
chooseSingleFileImage(edit, e.dataset.imageName, function (c) {
defaultIcon.addClass('hidden');
add.addClass('hidden');
edit.removeClass('hidden');
remove.removeClass('hidden');
canvas = c;
flash.warning(e.dataset.warning)
});
});
}
if (remove) {
remove.title = e.dataset.remove;
remove.addEventListener('click', function () {
modal.confirm(e.dataset.removeMsg, function () {
if (canvas) {
canvas.remove();
}
if (img) {
img.remove();
}
defaultIcon.removeClass('hidden');
add.removeClass('hidden');
edit.addClass('hidden');
remove.addClass('hidden');
if (e.dataset.src !== '') {
//TODO SEARCH IMAGE AND DELETE IT
request({
url: '/remove-img/',
post: {
hash: e.dataset.src
},
done: r => {
console.log(r);
flash.success(e.dataset.removeReady);
}
})
} else {
flash.success(e.dataset.removeReady);
}
})
});
}
}
function chooseSingleFileImage(e, name, callback) {
const bufferContent = e.innerHTML;
const file = document.createElement('input');
file.type = 'file';
file.accept = 'image/jpeg, image/png';
file.click();
file.addEventListener('change', function () {
const img = document.createElement('img');
img.src = URL.createObjectURL(file.files[0]);
img.style.height = '100%';
img.style.width = 'auto';
const cropper = new Cropper(img, {
autoCrop: false,
aspectRatio: 1,
ready() {
this.cropper.crop();
},
});
modal.confirm(img,
() => {
e = e.parentNode.parentNode;
const canvas = cropper.getCroppedCanvas();
const img = e.querySelector('img');
if (img)
img.remove();
e.prepend(canvas);
canvas.toBlob(function (blob) {
bufferFiles[name] = new File([blob], name + '.png', {type: 'image/png'});
}, 'image/png');
callback(canvas);
},
() => {
},
{
width: '50%',
height: '70%'
}
);
});
}
function setHistoryButton(e) {
e.addEventListener('click', function () {
all('.history-box', box => {
if (e.hasClass('la-history')) {
const b = box.parentNode.querySelector('.historyButton');
b.switchClasses('la-remove', 'la-history');
}
box.remove();
});
if (e.hasClass('la-history')) {
e.switchClasses('la-history', 'la-remove');
const container = e.parentNode;
container.style.position = 'relative';
const historyBox = one('history-box', container);
request({
url: '/get-history/',
post: {
table: e.dataset.table,
id: e.dataset.id
},
done: data => {
data.forEach(row => {
one('history-row', historyBox).innerHTML = row;
});
historyBox.addClass('open');
}
})
} else {
e.switchClasses('la-remove', 'la-history');
}
})
}
function setPositionButton(e) {
e.addEventListener('click', function () {
all('.position-box', box => {
if (e.hasClass('la-stream')) {
const b = box.parentNode.querySelector('.positionButton');
b.switchClasses('la-remove', 'la-stream');
}
box.remove();
});
if (e.hasClass('la-stream')) {
e.switchClasses('la-stream', 'la-remove');
const container = e.parentNode;
container.style.position = 'relative';
const positionBox = one('position-box', container);
request({
url: '/get-article-positions/',
post: {
article_key: e.dataset.articleKey
},
done: data => {
data.forEach(groupRow => {
const row = one('position-row', positionBox);
var positions = '';
groupRow.positions.forEach((p, i) => {
const c = p.checked ? 'checked' : '';
const cfa = p.checked_fa ? 'class="busy" title="Позицията е заета"' : ''
positions += `<label onclick="updateArticlePosition(this)" ${cfa} style="margin-right: 5px"><input ${c} data-id="${p.id}" data-article-key="${e.dataset.articleKey}" type="checkbox"><span>${i + 1}</span></label>`;
});
row.innerHTML = `
<div class="group-row">
<div class="group-name">${groupRow.group}</div>
<div class="group-positions flex-wrap">
${positions}
</div>
</div>
`;
});
//console.log(data);
positionBox.addClass('open');
}
})
} else {
e.switchClasses('la-remove', 'la-stream');
}
})
}
function updateArticlePosition(e) {
e.removeClass('busy');
const check = e.querySelector('input');
request({
url: '/update-article-position/',
post: {
id: check.dataset.id,
article_key: check.dataset.articleKey,
checked: check.checked,
},
done: r => {
flash.success(r.message);
}
})
}
function saveAndBackToList(el) {
event.preventDefault();
const container = el.parentNode;
const back = btoa(container.querySelector('a').href);
history.pushState({}, null, window.location.href + `&back=${back}`);
container.querySelector('#save').click();
}
function updateLabelRequire(e, id) {
if (e.value !== '') {
one(`${id}`).addClass('require')
} else {
one(`${id}`).removeClass('require')
}
}
@@ -0,0 +1,47 @@
const mkPicker = {
setForAll: selector => {
const css = `
.mkPicker {width: 100%; background: #ccc; height: 300px}
.hide {display: none}
`;
const style = document.createElement('style')
style.innerText = css;
document.head.appendChild(style)
const createPicker = (c, o) => {
}
const createInline = (e, o) => {
const c = document.createElement('div')
c.className = 'mkPicker'
e.parentNode.appendChild(c)
createPicker(c, o)
}
const create = e => {
var o = {}
try {
o = JSON.parse(e.dataset.mkPicker)
} catch (exp) {
alert('There is [data-mk-picker] with invalid JSON format')
}
o.type = o.type || 'popup'
if(o.colorContainer)
switch (o.type) {
case 'inline':
createInline(e, o)
break;
case 'popup':
break;
case 'modal':
break;
}
}
document.querySelectorAll(selector).forEach(i => {
create(i)
});
}
}
mkPicker.setForAll('[data-mk-picker]')
@@ -0,0 +1,763 @@
var bufferFiles = {};
//region [PROTOTYPES]
Element.prototype.addClass = function (name) {
this.classList.add(name)
}
Element.prototype.removeClass = function (name) {
this.classList.remove(name)
}
Element.prototype.toggleClass = function (name) {
if (this.classList.contains(name)) {
this.classList.remove(name)
} else {
this.classList.add(name)
}
}
Element.prototype.switchClasses = function (class1, class2) {
if (this.classList.contains(class1)) {
console.log(class1, class2);
this.classList.remove(class1)
this.classList.add(class2)
} else if (this.classList.contains(class2)) {
this.classList.remove(class2)
this.classList.add(class1)
}
}
Element.prototype.hasClass = function (className) {
return this.classList.contains(className);
}
//endregion
const all = (s, f) => {
const elements = document.querySelectorAll(s);
if (f) {
elements.forEach(e => {
f(e);
})
} else {
return elements;
}
};
/** @return Element **/
const one = (s, c) => {
if (c) {
let e = document.createElement('div');
e.className = s;
c.appendChild(e);
return e;
}
return document.querySelector(s);
};
const appendElem = (t, c, p) => {
let e = document.createElement(t);
e.className = c + ' appear';
p.appendChild(e);
setTimeout(t => {
e.addClass('visible');
}, 10)
return e;
};
const prependElem = (t, c, p) => {
let e = document.createElement(t);
e.className = c;
p.prepend(e);
setTimeout(t => {
e.addClass('visible');
}, 10)
return e;
};
const addImg = (c, p, src, type) => {
let e = document.createElement('img');
e.className = c;
e.src = '/get-img/' + src;
if (type === 'prepend') {
p.prepend(e);
} else {
p.appendChild(e);
}
e.addEventListener('load', function () {
setTimeout(t => {
e.addClass('visible');
}, 10)
});
return e;
};
const request = obj => {
let serializer = d => {
return Object.entries(d).map(([key, val]) => `${key}=${val}`).join('&');
};
obj.post = obj.post || '';
obj.get = obj.get ? '?' + serializer(obj.get) : '';
obj.url = obj.url || window.location.href;
obj.dataType = obj.dataType || 'json';
obj.done = obj.done || null;
const type = obj.post !== '' ? 'post' : 'get';
const xhr = new XMLHttpRequest();
xhr.open(type, obj.url + obj.get);
if (!(obj.post instanceof FormData) && type === 'post') {
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
obj.post = serializer(obj.post);
}
xhr.upload.onprogress = function (e) {
if (e.lengthComputable) {
var percentage = Math.round((e.loaded / e.total) * 100);
if (typeof obj.progress !== 'undefined') {
obj.progress(percentage)
}
}
};
xhr.onload = () => {
//console.log(xhr.responseText)
if (typeof obj.done !== 'undefined') {
if (obj.dataType === 'json') {
try {
obj.done(JSON.parse(xhr.responseText));
} catch (e) {
}
} else {
obj.done(xhr.responseText);
}
}
};
xhr.send(obj.post);
};
const error = (name, message) => {
all('.error-bubble', function (e) {
e.remove();
});
const element = one('[name="' + name + '"]');
element.parentNode.classList.add('form-error');
element.focus();
const elementYOffset = element.parentNode.offsetTop;
window.scroll(0, elementYOffset - 100);
console.log(elementYOffset);
//window.pageYOffset = element.parentNode.offsetTop;
const errorMsg = one('error-bubble', element.parentNode);
errorMsg.innerText = message;
setTimeout(() => {
if (errorMsg) {
errorMsg.remove();
}
}, 5000);
element.oninput = function () {
if (errorMsg) {
errorMsg.remove();
element.parentNode.classList.remove('form-error');
}
}
};
const errorElement = (element, message) => {
all('.error-bubble', function (e) {
e.remove();
});
element.parentNode.classList.add('form-error');
element.focus();
const elementYOffset = element.parentNode.offsetTop;
window.scroll(0, elementYOffset - 100);
console.log(elementYOffset);
//window.pageYOffset = element.parentNode.offsetTop;
const errorMsg = one('error-bubble', element.parentNode);
errorMsg.innerText = message;
setTimeout(() => {
if (errorMsg) {
errorMsg.remove();
}
}, 5000);
element.oninput = function () {
if (errorMsg) {
errorMsg.remove();
element.parentNode.classList.remove('form-error');
}
}
};
const ready = () => {
all('form').forEach(e => {
e.onsubmit = () => {
if (e.dataset.type !== 'search') {
event.preventDefault();
if (typeof CKEDITOR !== "undefined") {
for (let instanceName in CKEDITOR.instances) {
CKEDITOR.instances[instanceName].updateElement();
}
}
e.addClass('form-wait');
const waitingType = !one('.waiting-tape') ? one('waiting-tape', document.body) : null;
const formData = new FormData(e);
Object.keys(bufferFiles).forEach(f => {
formData.append(f, bufferFiles[f]);
});
request({
post: formData,
done: data => {
console.log(data);
if (data.error) {
error(data.field, data.message);
}
if (data.html) {
const htmlContent = one('#html_content');
htmlContent.innerHTML = data.html;
}
if (data.redirect) {
window.location.href = data.redirect;
}
if (data.reload) {
window.location.reload();
}
const smartRedirect = function (model_id) {
const params = new URLSearchParams(window.location.search);
if (params.get('back')) {
window.location.href = atob(params.get('back'));
} else {
if (params.get('id')) {
window.location.reload();
} else {
window.location.href = `${window.location.href}&id=${model_id}`
}
}
}
console.log(data, 'test');
if (data.smart_redirect && data.model_id) {
smartRedirect(data.model_id)
} else {
e.removeClass('form-wait');
if (waitingType)
waitingType.remove()
}
}
});
} else {
event.preventDefault();
const formData = new FormData(e);
const d = [];
for (let key of formData.keys()) {
const value = formData.get(key);
if (value) {
d.push(key + ':' + formData.get(key))
}
}
const queryStr = d.join('|');
if (queryStr) {
window.location.href = '?q=' + d.join('|');
} else {
window.location.href = window.location.href.split('?')[0];
}
}
}
});
all('[data-image-name]', e => {
setSingleFileImage(e);
});
all('.historyButton', e => {
setHistoryButton(e);
})
all('.positionButton', e => {
setPositionButton(e);
})
dataFormat();
document.querySelectorAll('[data-pdf]').forEach(pdf => {
pdf.classList.add('pointer');
pdf.addEventListener('click', () => {
modal.modalFrame(pdf.dataset.pdf);
})
})
document.querySelectorAll('[data-model-3d]').forEach(model3d => {
model3d.classList.add('pointer');
model3d.addEventListener('click', () => {
modal.modalFrame(model3d.getAttribute('data-model-3d'));
})
})
};
window.getUri = function (query) {
if (window.location.search) {
return window.location.href + '&' + query;
} else {
return window.location.href + '?' + query;
}
}
window.onload = ready;
const modal = {};
modal.sessionLeft = (msg, time, resetLabel, ev, leftEv) => {
const modalBackground = one('modal-background', document.body);
const modal = one('modal', modalBackground);
setTimeout(() => {
modal.addClass('modal-open');
}, 0)
const message = one('modal-message ct', modal);
if (typeof msg === 'string' || msg instanceof String) {
message.innerHTML = msg;
} else {
message.style.height = 'calc(100% - 40px)';
message.appendChild(msg);
}
const timer = document.createElement('span');
timer.innerHTML = time;
const sec = document.createElement('span');
sec.innerHTML = ' сек.';
var timeOut;
const timeRun = () => {
let ct = parseInt(timer.innerHTML);
timeOut = setTimeout(() => {
ct--;
if (ct === 0) {
modal.removeClass('modal-open');
setTimeout(() => {
modalBackground.remove();
}, 400)
setTimeout(() => {
modal.remove();
}, 1000);
if (leftEv) {
clearTimeout(timeOut)
leftEv();
}
} else {
timer.innerHTML = ct;
timeRun();
}
}, 1000)
}
timeRun();
message.appendChild(timer)
message.appendChild(sec)
const modalButtons = one('modal-buttons ct', modal)
const refresh = one('modal-button-confirm btn-ib btn-default', modalButtons)
resetLabel = resetLabel || 'Обнови сесията'
refresh.innerHTML = '<i class="la la-redo-alt"></i> ' + resetLabel;
refresh.addEventListener('click', () => {
modal.removeClass('modal-open');
setTimeout(() => {
modalBackground.remove();
}, 400)
setTimeout(() => {
modal.remove();
}, 1000);
if (ev) {
clearTimeout(timeOut)
ev();
}
})
}
modal.confirm = (msg, yes, no, free, onload) => {
const modalBackground = one('modal-background', document.body);
const modal = one('modal', modalBackground);
if (free) {
Object.keys(free).forEach(key => {
modal.style[key] = free[key];
})
}
setTimeout(() => {
modal.addClass('modal-open');
}, 0)
const message = one('modal-message ct', modal);
if (typeof msg === 'string' || msg instanceof String) {
message.innerHTML = msg;
} else {
message.style.height = 'calc(100% - 40px)';
message.appendChild(msg);
}
const modalButtons = one('modal-buttons ct', modal)
const cancel = one('modal-button-cancel btn-ib btn-default', modalButtons)
const confirm = one('modal-button-confirm btn-ib btn-default', modalButtons)
cancel.innerHTML = '<i class="la la-ban"></i> Отказ';
confirm.innerHTML = '<i class="la la-check"></i> Потвърждение';
if (typeof onload !== 'undefined') {
onload();
}
addEventListener('keydown', e => {
if (e.keyCode === 27) {
modal.removeClass('modal-open');
setTimeout(() => {
modalBackground.remove();
}, 400)
if (no) {
no();
}
}
})
cancel.onclick = () => {
modal.removeClass('modal-open');
setTimeout(() => {
modalBackground.remove();
}, 400)
if (no) {
no();
}
};
confirm.onclick = () => {
modal.removeClass('modal-open');
setTimeout(() => {
modalBackground.remove();
}, 400)
setTimeout(() => {
modal.remove();
}, 1000);
if (yes) {
yes();
}
}
};
modal.player = (videoSrc) => {
const modalBackground = one('modal-background', document.body);
const modal = one('modal-video', modalBackground);
const closeButton = one('modal-video-close', modal);
closeButton.innerHTML = '<i class="la la-times"></i>';
setTimeout(function () {
modal.addClass('modal-open');
}, 100)
closeButton.addEventListener('click', () => {
modal.removeClass('modal-open');
setTimeout(function () {
modalBackground.remove();
}, 350)
})
var video = document.createElement('video');
video.setAttribute('controls', true)
//
// First check for native browser HLS support
//
if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = videoSrc;
//
// If no native HLS support, check if HLS.js is supported
//
alert('application/vnd.apple.mpegurl')
modal.appendChild(video);
video.play();
} else if (Hls.isSupported()) {
var hls = new Hls();
hls.loadSource(videoSrc);
hls.attachMedia(video);
modal.appendChild(video);
video.play();
}
}
modal.modalFrame = (src) => {
const modalBackground = one('modal-background', document.body);
const modal = one('modal-video', modalBackground);
modal.classList.add('frame')
const closeButton = one('modal-video-close', modal);
closeButton.innerHTML = '<i class="la la-times"></i>';
setTimeout(function () {
modal.addClass('modal-open');
}, 100)
closeButton.addEventListener('click', () => {
modal.removeClass('modal-open');
setTimeout(function () {
modalBackground.remove();
}, 350)
})
var iframe = document.createElement('iframe');
iframe.setAttribute('style', 'border: 0; width: 100%; height: 100%')
iframe.src = src
modal.appendChild(iframe);
}
modal.modalPreview = (src) => {
const modalBackground = one('modal-background', document.body);
const modal = one('modal-video', modalBackground);
modal.classList.add('modalImg')
const closeButton = one('modal-video-close', modal);
closeButton.innerHTML = '<i class="la la-times"></i>';
setTimeout(function () {
modal.addClass('modal-open');
}, 100)
closeButton.addEventListener('click', () => {
modal.removeClass('modal-open');
setTimeout(function () {
modalBackground.remove();
}, 350)
})
var img = document.createElement('img');
img.setAttribute('style', 'height: 100%; display: block')
img.src = src
modal.appendChild(img);
}
modal.modalFrame = (src) => {
const modalBackground = one('modal-background', document.body);
const modal = one('modal-video', modalBackground);
modal.classList.add('frame')
const closeButton = one('modal-video-close', modal);
closeButton.innerHTML = '<i class="la la-times"></i>';
document.body.classList.add('hideScrollbar');
setTimeout(function () {
modal.classList.add('modal-open');
}, 100)
closeButton.addEventListener('click', () => {
modal.classList.remove('modal-open');
setTimeout(function () {
modalBackground.remove();
document.body.classList.remove('hideScrollbar');
}, 350)
})
var iframe = document.createElement('iframe');
iframe.setAttribute('style', 'border: 0; width: 100%; height: 100%')
iframe.setAttribute('allow', 'autoplay; fullscreen')
iframe.src = src
modal.appendChild(iframe);
}
const flash = {};
flash.success = (msg, noTopScroll) => {
if (!one('.flash')) {
const flash = one('flash', document.body);
flash.innerHTML = msg;
setTimeout(() => {
flash.addClass('success');
}, 10)
if (noTopScroll === undefined) {
setTimeout(() => {
window.scroll(0, 0);
}, 100)
}
setTimeout(() => {
all('.flash').forEach(f => {
f.removeClass('success');
setTimeout(() => {
f.remove();
}, 500);
})
}, 4000)
}
}
flash.warning = msg => {
if (!one('.flash')) {
const flash = one('flash', document.body);
flash.innerHTML = msg;
setTimeout(() => {
flash.addClass('warning');
}, 10)
setTimeout(() => {
all('.flash').forEach(f => {
f.removeClass('warning');
setTimeout(() => {
f.remove();
}, 500);
})
}, 7000)
}
}
flash.error = msg => {
if (!one('.flash')) {
const flash = one('flash', document.body);
flash.innerHTML = msg;
setTimeout(() => {
flash.addClass('error');
}, 10)
setTimeout(() => {
all('.flash').forEach(f => {
f.removeClass('warning');
setTimeout(() => {
f.remove();
}, 500);
})
}, 7000)
}
}
const timeRange = (s, o) => {
const createElement = (tag, className, appendTo) => {
var element = document.createElement(tag)
if (className)
element.className = className;
if (appendTo)
appendTo.appendChild(element);
return element;
}
const generate = e => {
o = o || {}
const
dataset = e.dataset || {},
minH = parseInt(o.minH) || parseInt(dataset.minH) || 0,
maxH = parseInt(o.maxH) || parseInt(dataset.maxH) || 23,
minutesStep = parseInt(o.minutesStep) || parseInt(dataset.minutesStep) || 5,
cnt = e.parentNode,
hc = createElement('div', 'time-range', cnt),
h1 = createElement('select', 'time-select', hc),
sh1 = createElement('div', 'sh', hc),
m1 = createElement('select', 'time-select', hc),
d = createElement('div', 'd', hc),
h2 = createElement('select', 'time-select', hc),
sh2 = createElement('div', 'sh', hc),
m2 = createElement('select', 'time-select', hc),
updateValuesFromInput = () => {
if (e.value) {
let t1 = e.value.split('-')[0].split(':');
let t2 = e.value.split('-')[1].split(':');
h1.value = parseInt(t1[0])
m1.value = parseInt(t1[1])
h2.value = parseInt(t2[0])
m2.value = parseInt(t2[1])
check()
}
},
updateInput = (v) => {
e.value = v
},
check = () => {
let
vH1 = parseInt(h1.value),
vM1 = parseInt(m1.value),
vH2 = parseInt(h2.value),
vM2 = parseInt(m2.value)
if (vH1 === vH2 && vM1 >= vM2)
m2.value = (vM1 + minutesStep).toString();
if (vH1 > vH2)
h2.value = vH1.toString()
if (h1.value && m1.value && h2.value && m2.value) {
let
vH1F = String(parseInt(h1.value)).padStart(2, '0'),
vM1F = String(parseInt(m1.value)).padStart(2, '0'),
vH2F = String(parseInt(h2.value)).padStart(2, '0'),
vM2F = String(parseInt(m2.value)).padStart(2, '0')
updateInput(`${vH1F}:${vM1F}-${vH2F}:${vM2F}`)
cnt.classList.remove('form-error')
} else {
updateInput('');
}
}
createElement('option', null, h1).setAttribute('disabled', '')
createElement('option', null, h2).setAttribute('disabled', '')
createElement('option', null, m1).setAttribute('disabled', '')
createElement('option', null, m2).setAttribute('disabled', '')
for (let i = minH; i <= maxH; i++) {
let opt1 = createElement('option', null, h1)
opt1.innerHTML = String(i).padStart(2, '0')
opt1.setAttribute('value', i)
let opt2 = createElement('option', null, h2)
opt2.innerHTML = String(i).padStart(2, '0')
opt2.setAttribute('value', i)
}
for (let i = 0; i <= 59; i += minutesStep) {
let opt1 = createElement('option', null, m1)
opt1.innerHTML = String(i).padStart(2, '0')
opt1.setAttribute('value', i)
let opt2 = createElement('option', null, m2)
opt2.innerHTML = String(i).padStart(2, '0')
opt2.setAttribute('value', i);
}
h1.addEventListener('change', check)
m1.addEventListener('change', check)
h2.addEventListener('change', check)
m2.addEventListener('change', check)
updateValuesFromInput();
}
document.querySelectorAll(s).forEach(e => generate(e));
}
const dataFormat = () => {
all('input[data-format]', e => {
e.min = e.min || 0;
const formatNumber = type => {
var elem = null;
e.addEventListener('focus', () => {
e.select();
const elem_offset = document.getSelection().anchorOffset;
elem = document.getSelection().anchorNode.childNodes[elem_offset];
})
e.addEventListener('keydown', () => {
let kc = event.keyCode;
if (e === elem) {
e.value = '';
elem = null;
}
switch (true) {
case kc > 47 && kc < 58 || kc === 8 || kc === 190:
if (kc === 190 && type === 'integer')
event.preventDefault();
if (kc !== 190 && kc !== 8 && e.value === '0')
event.preventDefault()
if (kc === 190 && e.value.indexOf('.') > -1)
event.preventDefault()
if (type === 'money' && kc !== 8 && e.value.charAt(e.value.length - 3) === '.')
event.preventDefault();
break;
case kc === 13:
event.preventDefault();
blur(type);
break;
default:
event.preventDefault();
}
})
e.addEventListener('blur', () => {
blur(type);
})
e.addEventListener('keyup', (elem) => {
//blur(type);
if (e.dataset.max && type === 'integer') {
if (e.value && parseInt(e.value) > parseInt(e.dataset.max)) {
e.value = e.dataset.max
}
}
})
}
const blur = (type) => {
if (type === 'money' && e.value) {
let n = e.value.split('.');
if (n[1]) {
e.value = n[0] + '.' + String(parseInt(n[1])).padEnd(2, '0')
} else {
e.value = n[0] + '.00';
}
}
e.blur();
}
if (e.dataset && e.dataset.format) {
if (['integer', 'double', 'money'].indexOf(e.dataset.format) > -1)
formatNumber(e.dataset.format);
}
})
}
@@ -0,0 +1,193 @@
class DocumentsModule {
documentRow() {
return `
<td>
<select oninput="updateInput(this)" data-input="document_type">
<option value=""></option>
<option value="pptx">Презентация (pptx)</option>
<option value="pdf">Документ (pdf)</option>
<option value="docx">Документ (docx)</option>
<option value="xlsx">Таблица (xlsx)</option>
<option value="other">Други</option>
</select>
</td>
<td><input oninput="updateInput(this)" data-input="name"></td>
<td><input oninput="updateInput(this)" data-input="name_en"></td>
<td class="ct"><button class="btn-ib btn-default" data-upload-field="file_name" onclick="attachAndUploadFile(this)"><i class="la la-file-upload"></i> Качи файл</button></td>
<td class="ct"><button class="btn-ib btn-default" data-upload-field="file_name_en" onclick="attachAndUploadFile(this)"><i class="la la-file-upload"></i> Качи файл</button></td>
<td><button onclick="deleteDocument(this)" class="btn btn-red btn-ico center"><i class="la la-trash font-20"></i></button></td>
`;
}
addDocument(documentKey, modelClass, modelId) {
const
tbody = document.querySelector('.docs-table tbody'),
tr = document.createElement('tr')
tr.innerHTML = this.documentRow()
this.generateRows();
this.postRequest('/file/document-add/', {documentKey, modelClass, modelId}, r => {
console.log(r)
if (r.document_id)
tr.setAttribute('data-document-id', r.document_id)
})
if (tbody.querySelector('tr.empty')) {
tbody.innerHTML = ''
tbody.appendChild(tr)
} else {
const first = tbody.querySelector('tr:first-child');
tbody.insertBefore(tr, first)
}
}
postRequest(url, data, done) {
const xhr = new XMLHttpRequest();
xhr.responseType = 'json'
xhr.open('post', url)
xhr.onload = () => {
done(xhr.response)
}
xhr.send(JSON.stringify(data));
}
getRequest(url, data, done) {
data = data || {}
let query = [];
Object.keys(data).forEach(d => {
query.push(d + '=' + data[d])
})
if (query.length > 0) url = `${url}?${query.join('&')}`
const xhr = new XMLHttpRequest();
xhr.responseType = 'json'
xhr.open('get', url)
xhr.onload = () => {
done(xhr.response)
}
xhr.send();
}
uploadFile(url, data, done) {
data = data || {}
const formData = new FormData();
Object.keys(data).forEach(d => {
formData.append(d, data[d]);
})
const xhr = new XMLHttpRequest();
xhr.responseType = 'json'
xhr.open('post', url)
xhr.onload = () => {
done(xhr.response)
}
xhr.send(formData);
}
generateRows() {
document.querySelectorAll('[data-input]').forEach(e => {
this.updateInput(e)
})
}
updateInput(e) {
if (e.tagName === 'SELECT') {
e.addEventListener('change', () => {
let id = e.parentNode.parentNode.dataset.documentId;
this.postRequest('/file/document-update/', {id: id, key: e.dataset.input, value: e.value}, done => {
})
})
}
if (e.tagName === 'INPUT') {
e.addEventListener('keypress', () => {
let id = e.parentNode.parentNode.dataset.documentId;
this.postRequest('/file/document-update/', {id: id, key: e.dataset.input, value: e.value}, done => {
})
})
}
}
}
const documentObject = new DocumentsModule();
function addDocument(e) {
documentObject.addDocument(e.dataset.documentKey, e.dataset.modelClass, e.dataset.modelId)
}
function updateInput(e) {
documentObject.updateInput(e)
}
function attachAndUploadFile(e) {
const fileInput = document.createElement('input')
fileInput.setAttribute('type', 'file')
fileInput.addEventListener('change', () => {
let id = e.parentNode.parentNode.dataset.documentId;
let update = e.dataset.uploadField;
let file = fileInput.files[0];
let tdContainer = e.parentNode;
documentObject.uploadFile('/file/document-file-upload/', {
id,
update,
file
}, data => {
console.log(data);
if(data.id && data.file_path) {
if (update === 'file_name') {
tdContainer.innerHTML = `<a href="${data.file_path}" class="download-link"><span class="extension"><i class="la la-download"></i> ${data.extension} сваляне</span></a>
<span data-document-id="${id}" data-delete-field="file_name" onclick="deleteUploadedFile(this)" class="delete-link"><span class="extension"><i class="la la-trash"></i> изтриване</span></span>`;
} else if (update === 'file_name_en') {
tdContainer.innerHTML = `<a href="${data.file_path}" class="download-link"><span class="extension"><i class="la la-download"></i> ${data.extension} сваляне</span></a>
<span data-document-id="${id}" data-delete-field="file_name_en" onclick="deleteUploadedFile(this)" class="delete-link"><span class="extension"><i class="la la-trash"></i> изтриване</span></span>`;
}
flash.success('Файлът е качен');
} else {
flash.error('Грешка при качване на файла');
}
})
})
fileInput.click()
}
function deleteUploadedFile(e) {
let td = e.parentNode;
let id = e.dataset.documentId;
let deleteField = e.dataset.deleteField;
modal.confirm('Сигурни ли сте, че искате да изтриете този файл?', function () {
documentObject.postRequest('/file/document-file-delete/', {id, deleteField}, done => {
td.innerHTML = `<button class="btn-ib btn-default" data-upload-field="${deleteField}" onclick="attachAndUploadFile(this)"><i class="la la-file-upload"></i> Качи файл</button>`
flash.success('Файлът е изтрит');
})
})
}
function deleteDocument(e) {
let id = e.parentNode.parentNode.dataset.documentId;
console.log(id);
if(id) {
modal.confirm('Сигурни ли сте, че искате да изтриете този документ?', function () {
let tr = e.parentNode.parentNode;
documentObject.postRequest('/file/document-delete/', {id}, done => {
tr.remove();
flash.success('Документът е изтрит');
let rows = document.querySelectorAll('.docs-table tbody tr');
if(rows.length === 0) {
let tbody = document.querySelector('.docs-table tbody');
tbody.innerHTML =
`<tr class="empty">
<td colspan="7" class="ct p20" style="">
<strong>Няма добавени документи</strong>
</td>
</tr>`;
}
})
})
}
}
document.addEventListener('DOMContentLoaded', () => {
documentObject.generateRows()
})
@@ -0,0 +1,454 @@
var newFiles = {};
var sl = {};
function checkAll(el) {
const objectKey = el.dataset.objectKey;
sl[objectKey] = [];
all('#' + objectKey + ' .file-img [data-del]', e => {
e.checked = el.checked === true;
if (el.checked) {
if (e.dataset.del) {
sl[objectKey].push(e.dataset.del);
}
e.parentNode.addClass('checked');
} else {
e.parentNode.removeClass('checked');
}
})
updateActionButtons(objectKey);
}
function checkSingle(e) {
const objectKey = e.dataset.objectKey;
sl[objectKey] = sl[objectKey] || [];
if (e.checked) {
if (e.dataset.del) {
sl[objectKey].push(e.dataset.del);
}
e.parentNode.addClass('checked');
} else {
one('#' + e.dataset.objectKey + ' .all-files input').checked = false;
e.parentNode.removeClass('checked');
if (e.dataset.del) {
const f = sl[objectKey].indexOf(e.dataset.del);
sl[objectKey].splice(f, 1);
}
}
updateActionButtons(objectKey);
}
function updateActionButtons(id) {
let checkedCounter = 0;
let checkedCounterUploaded = 0;
all('#' + id + ' .file-img input', c => {
if (c.checked === true)
checkedCounter++;
if (c.checked === true && c.dataset.del)
checkedCounterUploaded++;
})
const btnDelete = one('#' + id + ' .btnDelete');
const delCount = one('#' + id + ' .delCount');
const btnEdit = one('#' + id + ' .btnEdit');
if (btnDelete) {
if (checkedCounter > 0) {
btnDelete.removeClass('disabled');
delCount.innerHTML = '(' + checkedCounter + ')'
} else {
btnDelete.addClass('disabled');
delCount.innerHTML = '(0)'
}
}
if (btnEdit) {
if (checkedCounterUploaded === 1) {
btnEdit.removeClass('disabled');
} else {
btnEdit.addClass('disabled');
}
}
}
function addFileImage(e) {
const max_file_size = one('#' + e.dataset.objectKey + ' .max_file_size').value;
const error_message = one('#' + e.dataset.objectKey + ' .error_message').value;
const file = document.createElement('input');
let filesContainer = one('#' + e.dataset.objectKey + ' .files-container');
newFiles[e.dataset.objectKey] = newFiles[e.dataset.objectKey] || [];
file.type = 'file';
file.name = e.dataset.objectKey
file.multiple = !e.dataset.singleFile;
//file.accept = 'image/jpeg, image/png'
file.click();
file.addEventListener('change', function () {
var cIndex = 0;
for (let i = 0; i < this.files.length; i++) {
const f = this.files[i];
if (f.size > max_file_size * (1024 * 1024)) {
flash.error(error_message);
}
else if(f.type !== 'image/jpeg' && f.type !== 'image/jpg' && f.type !== 'image/png') {
flash.error('Позволените формати са jpeg и png')
}
else {
filesContainer.style.display = 'flex';
const fileContainer = one('file-img', filesContainer);
const imgId = e.dataset.objectKey + '_' + cIndex;
cIndex++;
const img = new Image();
img.src = URL.createObjectURL(f);
img.id = imgId;
const check = document.createElement('input')
check.type = 'checkbox';
check.setAttribute('data-del', '');
check.setAttribute('data-id', imgId);
check.setAttribute('data-object-key', e.dataset.objectKey)
check.addEventListener('click', e => {
checkSingle(check);
})
fileContainer.appendChild(img);
fileContainer.appendChild(check);
one('crops', fileContainer);
const progress = one('progress', fileContainer);
img.addEventListener('load', function () {
fileContainer.addClass('visible');
check.focus();
});
img.addEventListener('click', () => {
editSingleFileImage(img);
})
orderItem(fileContainer, function (img_id, order_index) {
newFiles[img_id][3] = order_index.toString();
})
newFiles[imgId] = [f, progress, e.dataset.objectKey, fileContainer.dataset.index, check];
if (e.dataset.singleFile) {
e.addClass('disabled');
}
}
}
uploadAllFilesByAttach(e.dataset.objectKey, cIndex, e.dataset.editMode);
});
}
function removeFileImage(el) {
let checkedCounter = 0;
let forDelete = [];
all('#' + el.dataset.objectKey + ' .file-img input', c => {
if (c.checked === true) {
checkedCounter++;
forDelete.push(c);
}
});
let message = '';
if (checkedCounter > 1) {
message = 'Сигурни ли сте, че истате да премахнете тези ' + checkedCounter + ' изображения';
} else {
message = 'Сигурни ли сте, че искате да премахнете 1 изображение';
}
modal.confirm(message, function () {
forDelete.forEach(fd => {
fd.parentNode.remove();
delete newFiles[fd.dataset.id];
});
el.querySelector('.delCount').innerHTML = '(0)';
el.addClass('disabled');
one('#' + el.dataset.objectKey + ' .btnEdit').addClass('disabled');
if (sl[el.dataset.objectKey].length > 0) {
let del_ids = JSON.stringify(sl[el.dataset.objectKey]);
request({
url: '/delete-file-cms/',
post: {
del_ids: del_ids
},
done: r => {
if (r.success) {
flash.success(r.success, true);
}
}
});
}
const addButton = one('#' + el.dataset.objectKey + ' [data-single-file]');
if (all('#' + el.dataset.objectKey + ' .file-img input').length === 0) {
one('#' + el.dataset.objectKey + ' .files-container').style.display = 'none';
if (addButton.dataset.singleFile) {
addButton.removeClass('disabled');
}
}
one('#' + el.dataset.objectKey + ' .all-files input').checked = false;
})
}
function uploadAllFilesByAttach(object_key, for_upload, editMode) {
console.log(newFiles);
const
newFilesIds = Object.keys(newFiles),
media_key = one('[name="media_key"]').value,
model_class = one('[name="model_class"]').value,
model_id = one('[name="model_id"]').values
if (newFilesIds.length > 0) {
var cc = 0;
all(`#${object_key} .file-img`).forEach(e => {
e.addClass('no-events');
})
newFilesIds.forEach(id => {
if (newFiles[id][5] === undefined) {
const f = newFiles[id][0];
const progressBar = newFiles[id][1];
const object_key = newFiles[id][2];
const order_index = newFiles[id][3];
const check = newFiles[id][4];
let formData = new FormData();
console.log(object_key);
formData.append('media_key', media_key);
formData.append('model_class', model_class);
formData.append('object_key', object_key);
formData.append('order_index', order_index);
formData.append('model_id', model_id);
formData.append(id, f);
if (editMode) {
formData.append('has_article', 1)
}
request({
url: '/upload-file-cms/',
post: formData,
progress: percentage => {
if (progressBar) {
progressBar.style.width = percentage + '%'
if (percentage < 100) {
progressBar.parentNode.addClass('disabled')
} else {
if (progressBar) {
if (progressBar.parentNode)
progressBar.parentNode.removeClass('disabled')
progressBar.remove()
}
}
}
},
done: data => {
check.setAttribute('data-del', data.id);
check.setAttribute('data-file-type', data.fileType)
check.setAttribute('data-src-raw', data.srcRaw)
check.setAttribute('data-media-key', data.mediaKey)
check.setAttribute('data-file-name', data.fileName)
check.setAttribute('data-crop-files', '[]')
newFiles[id][5] = 'uploaded';
cc++
if (for_upload === cc) {
all(`#${object_key} .file-img`).forEach(e => {
e.removeClass('disabled');
e.removeClass('no-events');
})
}
}
})
}
});
}
}
function editSingleFileImage(e) {
const check = e.parentNode.querySelector('input');
editFileSelectedImage(check, check.dataset.objectKey)
}
function editFileImage(e) {
const check = one('#' + e.dataset.objectKey + ' .file-img input:checked');
editFileSelectedImage(check, e.dataset.objectKey)
}
function editFileSelectedImage(check, objectKey) {
const bufferFiles = {};
const allowed_resolutions = JSON.parse(one('#' + objectKey + ' .allowed_resolutions').value);
const cropFiles = JSON.parse(check.dataset.cropFiles);
const img = document.createElement('img');
img.src = check.dataset.srcRaw;
img.style.height = '100%';
img.style.width = 'auto';
let aspectRation = 1;
let rez = '1:1';
if (allowed_resolutions.length > 0) {
aspectRation = allowed_resolutions[0][0] / allowed_resolutions[0][1];
rez = allowed_resolutions[0][0] + ':' + allowed_resolutions[0][1];
}
const cropContainer = document.createElement('div');
cropContainer.addClass('crop-container');
const cropImgContainer = one('crop-container-img', cropContainer);
const cropsContainer = one('crops-container', cropContainer);
const select = document.createElement('select');
cropImgContainer.addClass('invisible')
const options = [];
allowed_resolutions.forEach(r => {
options.push('<option data-rez="' + r[0] + ':' + r[1] + '" value="' + (r[0] / r[1]) + '">Резолюция ' + r[0] + ':' + r[1] + '</option>');
});
select.innerHTML = options.join('');
cropsContainer.innerHTML = '';
select.addEventListener('change', function () {
cropper.setAspectRatio(parseFloat(this.value));
const s = select.querySelector('option[value="' + this.value + '"]');
rez = s.dataset.rez;
});
cropsContainer.appendChild(select);
const cropBtn = one('btn-ib btn-default', cropsContainer);
cropBtn.innerHTML = '<i class="la la-crop"></i> Изрежи';
cropImgContainer.appendChild(img);
const cropsImgContainer = one('crops-img-container', cropsContainer);
cropsContainer.addClass('disabled');
const cropper = new Cropper(img, {
autoCrop: false,
aspectRatio: aspectRation,
viewMode: 0,
ready() {
this.cropper.crop();
cropImgContainer.removeClass('invisible')
cropImgContainer.removeClass('invisible')
cropsContainer.removeClass('disabled')
},
});
cropBtn.addEventListener('click', function () {
const modalBtnConfirm = one('.modal-button-confirm');
modalBtnConfirm.removeClass('disabled');
const existCrop = one('[data-row-rez="' + rez + '"]');
if (existCrop) {
if (existCrop.querySelector('img'))
existCrop.querySelector('img').remove();
if (existCrop.querySelector('canvas'))
existCrop.querySelector('canvas').remove();
const canvas = cropper.getCroppedCanvas();
existCrop.prepend(canvas);
canvas.toBlob(function (blob) {
bufferFiles[rez] = new File([blob], check.dataset.fileName, {type: check.dataset.fileType});
}, check.dataset.fileType, 0.5)
} else {
createCanvasCropRow(cropper, cropsImgContainer, rez, canvas => {
canvas.toBlob(function (blob) {
bufferFiles[rez] = new File([blob], check.dataset.fileName, {type: check.dataset.fileType});
}, check.dataset.fileType, 0.5)
}, del_rez => {
delete bufferFiles[rez];
if (Object.keys(bufferFiles).length === 0) {
modalBtnConfirm.addClass('disabled');
}
})
}
});
Object.keys(cropFiles).forEach(k => {
createImageCropRow(cropFiles[k], cropsImgContainer, k, check);
})
modal.confirm(cropContainer,
() => {
const keyRez = Object.keys(bufferFiles);
check.checked = false;
check.parentNode.removeClass('checked');
updateActionButtons(check.dataset.objectKey);
const form = one('form');
form.addClass('form-wait');
const waitingType = !one('.waiting-tape') ? one('waiting-tape', document.body) : null;
const fd = new FormData();
fd.append('object_key', check.dataset.objectKey);
fd.append('media_key', check.dataset.mediaKey);
fd.append('file_name', check.dataset.fileName);
fd.append('resolutions', JSON.stringify(keyRez));
keyRez.forEach(rez => {
const file = bufferFiles[rez];
fd.append(rez, file);
});
request({
url: '/upload-crop/',
post: fd,
done: r => {
if (r.resolutions) {
const crops = check.parentNode.querySelector('.crops');
crops.innerHTML = '';
r.resolutions.forEach(rez => {
const cr = document.createElement('span');
cr.innerHTML = rez;
crops.appendChild(cr);
})
}
if (r.files) {
check.setAttribute('data-crop-files', JSON.stringify(r.files))
}
form.removeClass('form-wait');
waitingType.remove();
flash.success('Изображението с резолюцията ' + keyRez.join(', ') + ' е актуализирано успешно', true);
}
})
},
() => {
},
{
width: '80%',
height: '75%'
},
() => {
const modalBtnConfirm = one('.modal-button-confirm');
modalBtnConfirm.addClass('disabled');
}
);
}
function createCanvasCropRow(cropper, cropsImgContainer, rez, callback, callbackDel) {
const canvas = cropper.getCroppedCanvas();
const cropsImgRow = one('crops-img-row', cropsImgContainer);
const cropsImgRez = one('crops-img-rez', cropsImgRow);
cropsImgRez.innerHTML = rez;
const cropsImgDel = one('crops-img-del btn-ib btn-default', cropsImgRow);
cropsImgDel.innerHTML = '<i class="la la-trash"></i>';
cropsImgDel.title = 'Изтрий резолюцията';
cropsImgDel.addEventListener('click', function () {
cropsImgDel.parentNode.remove();
callbackDel(rez);
flash.success('Резолюцията е изтрита');
})
cropsImgRow.prepend(canvas);
cropsImgRow.setAttribute('data-row-rez', rez);
callback(canvas);
}
function createImageCropRow(src, cropsImgContainer, rez, check) {
const img = new Image();
img.src = src + '?t=' + (new Date().getTime());
const cropsImgRow = one('crops-img-row', cropsImgContainer);
const cropsImgRez = one('crops-img-rez', cropsImgRow);
cropsImgRez.innerHTML = rez;
const cropsImgDel = one('crops-img-del btn-ib btn-default', cropsImgRow);
cropsImgDel.innerHTML = '<i class="la la-trash"></i>';
cropsImgDel.title = 'Изтрий резолюцията';
cropsImgDel.addEventListener('click', function () {
cropsImgDel.parentNode.remove();
request({
url: '/delete-crop/',
post: {
del_id: check.dataset.del,
rez: rez
},
done: r => {
if (r.resolutions) {
const crops = check.parentNode.querySelector('.crops');
crops.innerHTML = '';
r.resolutions.forEach(rez => {
const cr = document.createElement('span');
cr.innerHTML = rez;
crops.appendChild(cr);
})
}
if (r.files) {
check.setAttribute('data-crop-files', JSON.stringify(r.files))
}
flash.success('Резолюцията е изтрита', true);
}
})
})
cropsImgRow.prepend(img);
cropsImgRow.setAttribute('data-row-rez', rez);
}
//region [ORDER]
orderItems('.file-img', '/update-file-indexes/');
//endregion
@@ -0,0 +1,361 @@
class SelectorBase {
find(selector, parent) {
const p = parent || document
return parent.querySelector(selector)
}
findAll(selector, parent, callback) {
const p = parent || document,
result = parent.querySelectorAll(selector)
result.forEach((e, i) => {
callback(e, i)
})
return result;
}
set(obj) {
obj = obj || {};
const element = document.createElement(obj.tagName || 'div')
if (obj.type) element.type = obj.type
if (obj.className) element.className = obj.className
if (obj.innerHTML) element.innerHTML = obj.innerHTML
if (obj.name) element.name = obj.name
if (obj.events) {
Object.keys(obj.events).forEach(event => {
element.addEventListener(event, e => {
obj.events[event](element)
})
})
}
if (obj.attributes) {
Object.keys(obj.attributes).forEach(attr => {
element.setAttribute(attr, obj.attributes[attr])
})
}
if (obj.parent) obj.parent.appendChild(element)
return element
}
toggleClass(e, classFrom, classTo) {
e.classList.remove(classFrom)
e.classList.add(classTo)
}
}
class InnerTableItems extends SelectorBase {
updateUrl
constructor() {
super();
this.setDefault()
}
setChangeToSelect(e) {
this.typeValueSelectorChange(e, e.name.replace('user_interface_type', 'select_data'))
}
setChangeDataType(e) {
console.log(e.value)
}
setUpdateUrl(url) {
this.updateUrl = url;
}
setDefault() {
this.findAll('.type-value-selector', document, e => {
e.addEventListener('change', () => {
this.typeValueSelectorChange(e, e.name.replace('user_interface_type', 'select_data'))
})
})
this.findAll('.inner-td-table .add-row', document, e => {
e.addEventListener('click', () => {
this.addNewRow(e)
})
})
this.findAll('.inner-td-table .remove', document, e => {
e.addEventListener('click', () => {
this.deleteRow(e)
})
})
this.findAll('.inner-td-table .add-bg, .inner-td-table .add-en', document, e => {
e.addEventListener('keydown', () => {
this.addNewRow(e)
})
})
this.findAll('.inner-td-table .update-bg, .inner-td-table .update-en', document, e => {
e.addEventListener('keydown', () => {
this.updateRow(e)
})
e.addEventListener('blur', () => {
this.updateRow(e)
})
})
}
addNewRow(e) {
const erd = this.eventRetrieveData(e)
if (erd) {
const lg = !erd.inputEn ? 1 : null;
const row = this.setRow(erd.tbody, erd.dataTable, 'update', lg)
row.inputBg.value = erd.inputBg.value
if (row.inputEn && erd.inputEn) {
row.inputEn.value = erd.inputEn.value
}
if(erd.inputBg.value !== '') {
if (erd.tbody.dataset.id !== 'undefined') {
console.log(erd.tbody.dataset.id)
if (this.updateUrl && erd.tbody.dataset.id) {
erd.tr.classList.add('disabled')
this.request({
url: this.updateUrl,
data: {
parent_id: erd.tbody.dataset.id,
bg: erd.inputBg.value,
en: erd.inputEn ? erd.inputEn.value : '',
},
success: r => {
if (r.id) {
row.tr.setAttribute('data-option-id', r.id);
erd.tbody.insertBefore(row.tr, erd.tr)
erd.inputBg.value = ''
if (erd.inputEn) erd.inputEn.value = ''
erd.tr.classList.remove('disabled')
erd.inputBg.focus()
this.setData(erd.tbody, erd.hidden)
flash.success('Опцията е добавена успешно')
} else {
flash.error('Опцията не беше добавена поради грешка в системата')
}
}
})
}
} else {
erd.tbody.insertBefore(row.tr, erd.tr)
erd.inputBg.value = ''
if (erd.inputEn) erd.inputEn.value = ''
erd.tr.classList.remove('disabled')
erd.inputBg.focus()
this.setData(erd.tbody, erd.hidden)
}
} else {
errorElement(erd.inputBg, 'Стойността не може да бъде празна')
}
}
}
updateRow(e) {
const erd = this.eventRetrieveData(e)
if (erd) {
if(erd.tr && erd.tr.dataset.optionId) {
erd.tr.classList.add('disabled');
this.request({
url: this.updateUrl,
data: {
id: erd.tr.dataset.optionId,
bg: erd.inputBg.value,
en: erd.inputEn ? erd.inputEn.value : '',
},
success: r => {
if(r.id) {
this.setData(erd.tbody, erd.hidden)
flash.success('Опцията е актуализирана успешно')
} else {
flash.error('Опцията не беше актуализирана поради грешка в системата')
}
erd.tr.classList.remove('disabled');
}
})
}
}
}
deleteRow(e) {
const erd = this.eventRetrieveData(e)
if (erd) {
erd.tr.classList.add('disabled');
if(erd.tr && erd.tr.dataset.optionId) {
this.request({
url: this.updateUrl,
data: {
id: erd.tr.dataset.optionId,
remove: 1
},
success: r => {
if(r.success) {
erd.tr.remove()
this.setData(erd.tbody, erd.hidden)
flash.success('Опцията е премахната успешно')
} else {
flash.error('Опцията не беше премахната поради грешка в системата')
erd.tr.classList.remove('disabled')
}
}
})
}
}
}
setRow(tbody, dataTable, type, lg) {
const trObj = {tagName: 'tr', attributes: {"data-table": dataTable}};
if (type === 'add')
trObj.parent = tbody
const
tr = this.set(trObj),
tdBg = this.set({tagName: 'td', parent: tr}),
inputBg = this.set({
tagName: 'input',
parent: tdBg,
className: `${type}-bg`,
events: {
keydown: () => {
if (type === 'add')
this.addNewRow(inputBg)
if (type === 'update')
this.updateRow(inputBg)
}
}
}),
tdEn = this.set({tagName: 'td', parent: tr}),
inputEn = this.set({
tagName: 'input',
parent: tdEn,
className: `${type}-en`,
events: {
keydown: () => {
if (type === 'add')
this.addNewRow(inputEn)
if (type === 'update')
this.updateRow(inputEn)
}
}
})
if (lg === 1) tdEn.remove()
const button = this.set({
tagName: 'td',
className: type === 'add' ? 'add-row' : 'remove',
parent: tr,
innerHTML: `<i class="la la-${type === 'add' ? 'plus' : 'remove'}"></i>`,
events: {
click: () => {
if (type === 'add')
this.addNewRow(button)
if (type === 'update')
this.deleteRow(button)
}
}
})
if (type === 'add')
inputBg.focus()
if (type === 'update') {
tr.className = 'added-row'
tr.setAttribute('data-table', dataTable)
}
return {tr, inputBg, inputEn};
}
eventRetrieveData(e) {
if (event.keyCode && event.keyCode !== 13) return
var tr = "";
if (event.keyCode === 13) event.preventDefault()
if (e.tagName === "INPUT") tr = e.parentNode.parentNode
if (e.tagName === "TD") tr = e.parentNode
const
dataTable = tr.dataset.table,
tbody = document.querySelector(`.inner-td-table[data-table="${dataTable}"] tbody`),
hidden = document.querySelector(`input[name="${dataTable}"]`),
button = this.find('.add-row', tr),
inputBg = this.find('td:nth-child(1) input', tr),
inputEn = this.find('td:nth-child(2) input', tr)
return {dataTable, tr, inputBg, inputEn, tbody, hidden, button}
}
setData(tbody, hidden) {
const data = []
this.findAll('.added-row', tbody, (e, i) => {
e.setAttribute('data-index', i)
const objectRow = {};
const bg = this.find('td:nth-child(1) input', e)
const en = this.find('td:nth-child(2) input', e)
if(e.dataset.optionId) objectRow['id'] = e.dataset.optionId
if (bg) objectRow['bg'] = bg.value
if (en) objectRow['en'] = en.value
data.push(objectRow)
})
hidden.value = JSON.stringify(data)
return data
}
request(o) {
console.log(o);
const xhr = new XMLHttpRequest()
xhr.responseType = 'json'
xhr.onload = () => {
if(o.success) {
o.success(xhr.response)
}
}
xhr.open('post', o.url)
const fd = new FormData()
if(o.data) {
Object.keys(o.data).forEach(key => {
fd.append(key, o.data[key])
})
}
xhr.send(fd)
}
typeValueSelectorChange(elem, dataTable) {
const
existHidden = elem.parentNode.querySelector('input[type="hidden"]'),
existTable = elem.parentNode.querySelector('table.inner-td-table')
if(existHidden) existHidden.remove()
if(existTable) existTable.remove()
if (elem.value === 'list') {
const
hidden = this.set({tagName: 'input', type: 'hidden', name: dataTable}),
table = this.set({
tagName: 'table',
className: 'inner-td-table',
innerHTML:
`<thead>
<tr><td>стойност (bg)</td><td>стойност (en)</td><td></td></tr>
</thead>`,
attributes: {"data-table": dataTable}
}),
tbody = this.set({tagName: 'tbody', parent: table, attributes: {"data-id": elem.dataset.id}})
this.setRow(tbody, dataTable, 'add')
elem.parentNode.appendChild(hidden)
elem.parentNode.appendChild(table)
} else if (elem.value === 'list_simple') {
const
hidden = this.set({tagName: 'input', type: 'hidden', name: dataTable}),
table = this.set({
tagName: 'table',
className: 'inner-td-table',
innerHTML:
`<thead>
<tr><td>стойност</td></tr>
</thead>`,
attributes: {"data-table": dataTable}
}),
tbody = this.set({tagName: 'tbody', parent: table, attributes: {"data-id": elem.dataset.id}})
this.setRow(tbody, dataTable, 'add', 1)
elem.parentNode.appendChild(hidden)
elem.parentNode.appendChild(table)
} else {
const
hidden = this.find('input[type="hidden"]', elem.parentNode),
table = this.find('table.inner-td-table', elem.parentNode)
if (hidden) hidden.remove()
if (table) table.remove()
}
}
}
@@ -0,0 +1,88 @@
var orderIndexUrl = ''
function orderItems(className, orderUrl, callback) {
document.querySelectorAll(className).forEach(item => {
orderItem(item, callback)
})
orderIndexUrl = orderUrl
}
function orderItem(draggable, callback) {
draggable.setAttribute('draggable', true)
draggable.querySelectorAll('input').forEach(input => {
input.addEventListener('focus', () => {
draggable.removeAttribute('draggable')
})
input.addEventListener('blur', () => {
draggable.setAttribute('draggable', true)
})
})
draggable.classList.add('draggable')
draggable.addEventListener('dragstart', () => {
//console.log(event.target);
//return;
draggable.classList.add('dragging');
})
const orderElements = [...draggable.parentNode.querySelectorAll('.draggable')];
orderElements.forEach((e, i) => {
if (typeof e.dataset.fileId === 'undefined') {
e.setAttribute('data-index', i);
}
});
draggable.addEventListener('dragend', (e) => {
e.preventDefault()
draggable.classList.remove('dragging');
const reorderElements = [...container.querySelectorAll('.draggable')];
const orderList = [];
reorderElements.forEach((e, i) => {
e.setAttribute('data-index', i);
const check = e.querySelector('input');
if (typeof callback !== 'undefined') {
callback(check.dataset.id, i);
}
orderList.push({
order_index: i,
id: check.dataset.del
})
});
requestOrderIndexes(orderList);
if(callback)
callback()
})
const container = draggable.parentNode
container.addEventListener('dragover', e => {
e.preventDefault()
const draggable = document.querySelector('.dragging')
const setElement = getDragAfterElement(container, e.clientX, e.clientY)
if (setElement !== null) {
container.insertBefore(draggable, setElement)
}
})
}
function requestOrderIndexes(indexes) {
if (indexes.length > 0 && orderIndexUrl) {
request({
url: orderIndexUrl,
post: {
indexes: JSON.stringify(indexes)
}
})
}
}
function getDragAfterElement(container, x, y) {
const draggableElements = [...container.querySelectorAll('.draggable:not(.dragging)')]
var child = null;
draggableElements.forEach(e => {
var box = e.getBoundingClientRect();
if (x > box.left && x < box.left + box.width / 2) {
if (y > box.top && y < box.top + box.height) {
child = e;
return child;
}
}
})
return child;
}
@@ -0,0 +1,150 @@
/* Copyright 2012 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// eslint-disable-next-line max-len
/** @typedef {import("./display/api").PDFDocumentLoadingTask} PDFDocumentLoadingTask */
/** @typedef {import("./display/api").PDFDocumentProxy} PDFDocumentProxy */
/** @typedef {import("./display/api").PDFPageProxy} PDFPageProxy */
/** @typedef {import("./display/api").RenderTask} RenderTask */
/** @typedef {import("./display/display_utils").PageViewport} PageViewport */
// eslint-disable-next-line max-len
/** @typedef {import("./display/text_layer").TextLayerRenderTask} TextLayerRenderTask */
import {
AnnotationEditorParamsType,
AnnotationEditorType,
AnnotationMode,
CMapCompressionType,
createPromiseCapability,
createValidAbsoluteUrl,
InvalidPDFException,
MissingPDFException,
OPS,
PasswordResponses,
PermissionFlag,
shadow,
UnexpectedResponseException,
UNSUPPORTED_FEATURES,
Util,
VerbosityLevel,
} from "./shared/util.js";
import {
build,
getDocument,
LoopbackPort,
PDFDataRangeTransport,
PDFWorker,
setPDFNetworkStreamFactory,
version,
} from "./display/api.js";
import {
getFilenameFromUrl,
getPdfFilenameFromUrl,
getXfaPageViewport,
isPdfFile,
isValidFetchUrl,
loadScript,
PDFDateString,
PixelsPerInch,
RenderingCancelledException,
} from "./display/display_utils.js";
import { AnnotationEditorLayer } from "./display/editor/annotation_editor_layer.js";
import { AnnotationEditorUIManager } from "./display/editor/tools.js";
import { AnnotationLayer } from "./display/annotation_layer.js";
import { GlobalWorkerOptions } from "./display/worker_options.js";
import { isNodeJS } from "./shared/is_node.js";
import { renderTextLayer } from "./display/text_layer.js";
import { SVGGraphics } from "./display/svg.js";
import { XfaLayer } from "./display/xfa_layer.js";
/* eslint-disable-next-line no-unused-vars */
const pdfjsVersion =
typeof PDFJSDev !== "undefined" ? PDFJSDev.eval("BUNDLE_VERSION") : void 0;
/* eslint-disable-next-line no-unused-vars */
const pdfjsBuild =
typeof PDFJSDev !== "undefined" ? PDFJSDev.eval("BUNDLE_BUILD") : void 0;
if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("PRODUCTION")) {
const streamsPromise = Promise.all([
import("pdfjs/display/network.js"),
import("pdfjs/display/fetch_stream.js"),
]);
setPDFNetworkStreamFactory(async params => {
const [{ PDFNetworkStream }, { PDFFetchStream }] = await streamsPromise;
if (isValidFetchUrl(params.url)) {
return new PDFFetchStream(params);
}
return new PDFNetworkStream(params);
});
} else if (PDFJSDev.test("GENERIC || CHROME")) {
if (PDFJSDev.test("GENERIC") && isNodeJS) {
const { PDFNodeStream } = require("./display/node_stream.js");
setPDFNetworkStreamFactory(params => {
return new PDFNodeStream(params);
});
} else {
const { PDFNetworkStream } = require("./display/network.js");
const { PDFFetchStream } = require("./display/fetch_stream.js");
setPDFNetworkStreamFactory(params => {
if (isValidFetchUrl(params.url)) {
return new PDFFetchStream(params);
}
return new PDFNetworkStream(params);
});
}
}
export {
AnnotationEditorLayer,
AnnotationEditorParamsType,
AnnotationEditorType,
AnnotationEditorUIManager,
AnnotationLayer,
AnnotationMode,
build,
CMapCompressionType,
createPromiseCapability,
createValidAbsoluteUrl,
getDocument,
getFilenameFromUrl,
getPdfFilenameFromUrl,
getXfaPageViewport,
GlobalWorkerOptions,
InvalidPDFException,
isPdfFile,
loadScript,
LoopbackPort,
MissingPDFException,
OPS,
PasswordResponses,
PDFDataRangeTransport,
PDFDateString,
PDFWorker,
PermissionFlag,
PixelsPerInch,
RenderingCancelledException,
renderTextLayer,
shadow,
SVGGraphics,
UnexpectedResponseException,
UNSUPPORTED_FEATURES,
Util,
VerbosityLevel,
version,
XfaLayer,
};
@@ -0,0 +1,215 @@
class SelectorBase {
find(selector, parent) {
const p = parent || document
return parent.querySelector(selector)
}
findAll(selector, parent, callback) {
const p = parent || document,
result = parent.querySelectorAll(selector)
result.forEach((e, i) => {
callback(e, i)
})
return result;
}
set(obj) {
obj = obj || {};
const element = document.createElement(obj.tagName || 'div')
if (obj.type) element.type = obj.type
if (obj.className) element.className = obj.className
if (obj.innerHTML) element.innerHTML = obj.innerHTML
if (obj.name) element.name = obj.name
if (obj.value) element.value = obj.value
if (obj.events) {
Object.keys(obj.events).forEach(event => {
element.addEventListener(event, e => {
obj.events[event](element)
})
})
}
if (obj.attributes) {
Object.keys(obj.attributes).forEach(attr => {
element.setAttribute(attr, obj.attributes[attr])
})
}
if (obj.parent) obj.parent.appendChild(element)
return element
}
toggleClass(e, classFrom, classTo) {
e.classList.remove(classFrom)
e.classList.add(classTo)
}
toggleOpen(e) {
if (e.classList.contains('open-autocomplete')) {
e.classList.remove('open-autocomplete')
} else {
e.classList.add('open-autocomplete')
}
}
request(url, query, callback) {
const xhr = new XMLHttpRequest()
xhr.responseType = 'json'
xhr.open('get', `${url}?${query}`)
xhr.onload = () => {
callback(xhr.response)
}
xhr.send()
}
}
class SearchBoxRemote extends SelectorBase {
constructor(selector, obj) {
super();
this.set({
tagName: 'link',
parent: document.head,
attributes: {href: '/_public/assets/css/search-box-remote.css', rel: 'stylesheet'}
})
document.querySelectorAll(selector).forEach(element => {
new SearchBoxRemoteInitial(element, obj)
})
}
}
class SearchBoxRemoteInitial extends SelectorBase {
url
q
id
columns
selected
hidden
searchBoxContainer
inputSearch
autocompleteList
constructor(selector, obj) {
super();
obj = obj || {};
this.url = obj.url || null
this.q = obj.q || 'q'
this.id = obj.id || 'id'
this.columns = obj.columns || null
this.init(selector)
}
init(e) {
if (e.dataset && e.dataset.sbrName) {
this.hidden = this.set({
tagName: 'input',
type: 'hidden',
name: e.dataset.sbrName,
value: e.dataset.sbrValue,
parent: e.parentNode
})
e.setAttribute('readonly', true)
e.classList.add('pointer')
e.parentNode.classList.add('relative')
this.selected = e
e.addEventListener('click', () => {
if(!event.target.classList.contains('clear-button') && !event.target.classList.contains('add-button')) {
this.setSearchBox(e.parentNode)
}
})
this.setDefaultSelected()
}
}
setSearchBox(container) {
if (container.classList.contains('open-autocomplete')) {
container.classList.remove('open-autocomplete')
container.querySelector('.search-box-container').remove()
} else {
this.searchBoxContainer = this.set({className: 'search-box-container', parent: container})
this.inputSearch = this.set({
tagName: 'input', attributes: {
class: 'input-search',
placeholder: 'Търси ...',
}, parent: this.searchBoxContainer
})
this.inputSearch.focus();
if ((window.innerHeight - this.searchBoxContainer.getBoundingClientRect().top) < 500) {
this.searchBoxContainer.classList.add('up-position')
this.setAutocompleteList('prepend')
} else {
this.searchBoxContainer.classList.add('down-position')
this.setAutocompleteList('append')
}
container.classList.add('open-autocomplete')
}
}
setAutocompleteList(type) {
this.autocompleteList = this.set({className: 'autocomplete-list autocomplete-image-list'})
if (type === 'prepend') this.searchBoxContainer.insertBefore(this.autocompleteList, this.inputSearch)
if (type === 'append') this.searchBoxContainer.append(this.autocompleteList)
this.inputSearch.addEventListener('keydown', () => {
this.keyDown()
})
this.inputSearch.addEventListener('keyup', () => {
this.keyUp()
})
}
setDefaultSelected() {
if(this.hidden.value) {
this.request(this.url, `${this.id}=${this.hidden.value}`, e => {
if(e.settlement_id) {
this.selected.value = `${e.name}`;
}
})
}
}
setAutocompleteValues(data) {
const $this = this
this.autocompleteList.innerHTML = ''
data.forEach(e => {
const resultRow = this.set({
className: 'autocomplete-value',
innerHTML: `${e.name}`,
parent: this.autocompleteList,
events: {
click: function () {
$this.hidden.value = e.object_id;
$this.searchBoxContainer.parentNode.classList.remove('open-autocomplete')
$this.searchBoxContainer.remove();
$this.selected.innerHTML = resultRow.innerHTML + '<div class="flex flex-center top5">' +
'<div class="add-button" onclick="addSelected()"><i class="la la-plus-circle"></i> Добави</div>' +
'<div class="clear-button" onclick="clearSelected()"><i class="la la-remove"></i>Изчисти</div></div>'
$this.selected.querySelector('.row-result').classList.add('panel-result-selected')
}
}
})
})
}
keyDown() {
this.autocompleteList.innerHTML = ''
}
keyUp() {
if (this.inputSearch.value.length > 0) {
this.request(this.url, `${this.q}=${this.inputSearch.value}`, data => {
if (data && data.length > 0) {
this.setAutocompleteValues(data)
this.autocompleteList.classList.add('visible')
} else {
this.closeAutocomplete()
}
})
} else {
this.closeAutocomplete()
}
}
closeAutocomplete() {
this.autocompleteList.classList.remove('visible')
this.autocompleteList.innerHTML = ''
}
}
@@ -0,0 +1,210 @@
class SelectorBase {
find(selector, parent) {
const p = parent || document
return parent.querySelector(selector)
}
findAll(selector, parent, callback) {
const p = parent || document,
result = parent.querySelectorAll(selector)
result.forEach((e, i) => {
callback(e, i)
})
return result;
}
set(obj) {
obj = obj || {};
const element = document.createElement(obj.tagName || 'div')
if (obj.type) element.type = obj.type
if (obj.className) element.className = obj.className
if (obj.innerHTML) element.innerHTML = obj.innerHTML
if (obj.name) element.name = obj.name
if (obj.value) element.value = obj.value
if (obj.events) {
Object.keys(obj.events).forEach(event => {
element.addEventListener(event, e => {
obj.events[event](element)
})
})
}
if (obj.attributes) {
Object.keys(obj.attributes).forEach(attr => {
element.setAttribute(attr, obj.attributes[attr])
})
}
if (obj.parent) obj.parent.appendChild(element)
return element
}
toggleClass(e, classFrom, classTo) {
e.classList.remove(classFrom)
e.classList.add(classTo)
}
toggleOpen(e) {
if (e.classList.contains('open-autocomplete')) {
e.classList.remove('open-autocomplete')
} else {
e.classList.add('open-autocomplete')
}
}
request(url, query, callback) {
const xhr = new XMLHttpRequest()
xhr.responseType = 'json'
xhr.open('get', `${url}?${query}`)
xhr.onload = () => {
callback(xhr.response)
}
xhr.send()
}
}
class SearchBoxRemote extends SelectorBase {
constructor(selector, obj) {
super();
this.set({
tagName: 'link',
parent: document.head,
attributes: {href: '/_public/assets/css/search-box-remote.css', rel: 'stylesheet'}
})
document.querySelectorAll(selector).forEach(element => {
new SearchBoxRemoteInitial(element, obj)
})
}
}
class SearchBoxRemoteInitial extends SelectorBase {
url
q
id
columns
selected
hidden
searchBoxContainer
inputSearch
autocompleteList
constructor(selector, obj) {
super();
obj = obj || {};
this.url = obj.url || null
this.q = obj.q || 'q'
this.id = obj.id || 'id'
this.columns = obj.columns || null
this.init(selector)
}
init(e) {
if (e.dataset && e.dataset.sbrName) {
this.hidden = this.set({
tagName: 'input',
type: 'hidden',
name: e.dataset.sbrName,
value: e.dataset.sbrValue,
parent: e.parentNode
})
e.setAttribute('readonly', true)
e.classList.add('pointer')
e.parentNode.classList.add('relative')
this.selected = e
e.addEventListener('click', () => {
this.setSearchBox(e.parentNode)
})
this.setDefaultSelected()
}
}
setSearchBox(container) {
if (container.classList.contains('open-autocomplete')) {
container.classList.remove('open-autocomplete')
container.querySelector('.search-box-container').remove()
} else {
this.searchBoxContainer = this.set({className: 'search-box-container', parent: container})
this.inputSearch = this.set({
tagName: 'input', attributes: {
class: 'input-search',
placeholder: 'Търси ...',
}, parent: this.searchBoxContainer
})
this.inputSearch.focus();
if ((window.innerHeight - this.searchBoxContainer.getBoundingClientRect().top) < 500) {
this.searchBoxContainer.classList.add('up-position')
this.setAutocompleteList('prepend')
} else {
this.searchBoxContainer.classList.add('down-position')
this.setAutocompleteList('append')
}
container.classList.add('open-autocomplete')
}
}
setAutocompleteList(type) {
this.autocompleteList = this.set({className: 'autocomplete-list'})
if (type === 'prepend') this.searchBoxContainer.insertBefore(this.autocompleteList, this.inputSearch)
if (type === 'append') this.searchBoxContainer.append(this.autocompleteList)
this.inputSearch.addEventListener('keydown', () => {
this.keyDown()
})
this.inputSearch.addEventListener('keyup', () => {
this.keyUp()
})
}
setDefaultSelected() {
if(this.hidden.value) {
this.request(this.url, `${this.id}=${this.hidden.value}`, e => {
if(e.settlement_id) {
this.selected.value = `${e.name}`;
}
})
}
}
setAutocompleteValues(data) {
const $this = this
this.autocompleteList.innerHTML = ''
data.forEach(e => {
const resultRow = this.set({
className: 'autocomplete-value',
innerHTML: `${e.name}`,
parent: this.autocompleteList,
events: {
click: function () {
$this.hidden.value = e.settlement_id;
$this.searchBoxContainer.parentNode.classList.remove('open-autocomplete')
$this.searchBoxContainer.remove();
$this.selected.value = resultRow.innerHTML
}
}
})
})
}
keyDown() {
this.autocompleteList.innerHTML = ''
}
keyUp() {
if (this.inputSearch.value.length > 0) {
this.request(this.url, `${this.q}=${this.inputSearch.value}`, data => {
if (data && data.length > 0) {
this.setAutocompleteValues(data)
this.autocompleteList.classList.add('visible')
} else {
this.closeAutocomplete()
}
})
} else {
this.closeAutocomplete()
}
}
closeAutocomplete() {
this.autocompleteList.classList.remove('visible')
this.autocompleteList.innerHTML = ''
}
}
@@ -0,0 +1,281 @@
class SearchBox {
container
box = document.createElement('div')
list = document.createElement('div')
listItems = document.createElement('div')
selected = document.createElement('div')
searchField = document.createElement('input')
cloneListItems = this.listItems
callback
dynamic = {}
constructor(selector) {
if (typeof selector === "string") {
this.container = document.querySelector(selector)
} else {
this.container = selector;
}
if(this.container) {
if (this.container.nodeName === 'SELECT') {
this.dataRetrieve()
} else {
alert('Html element SELECT is required')
}
addEventListener('keydown', ({keyCode}) => {
if (keyCode === 27) {
this.clear()
}
})
}
}
clear() {
this.box.classList.remove('open')
this.searchField.value = ''
this.listItems.querySelectorAll('.list-item').forEach(e => {
e.classList.add('visible')
e.classList.remove('hover')
e.style.display = 'block'
})
}
getNextSibling(elem, selector) {
var sibling = elem.nextElementSibling;
while (sibling) {
if (sibling.matches(selector)) return sibling;
sibling = sibling.nextElementSibling
}
}
getPreviousSibling(elem, selector) {
var sibling = elem.previousElementSibling;
if (!selector) return sibling;
while (sibling) {
if (sibling.matches(selector)) return sibling;
sibling = sibling.previousElementSibling;
}
}
keyDown() {
this.searchField.addEventListener('keydown', ({keyCode}) => {
if (keyCode === 38 || keyCode === 40) {
event.preventDefault()
const visibleList = this.listItems.querySelectorAll('.visible:not(.hover)');
const firstItem = visibleList[0];
const lastItem = this.listItems.querySelectorAll('.visible:not(.hover)')[visibleList.length - 1];
if (this.listItems.querySelectorAll('.visible.hover').length === 0) {
if (keyCode === 38 && lastItem)
lastItem.classList.add('hover')
if (keyCode === 40 && firstItem)
firstItem.classList.add('hover')
} else {
const hoverElement = this.listItems.querySelector('.visible.hover')
hoverElement.classList.remove('hover')
//up
if (keyCode === 38) {
const prev = this.getPreviousSibling(hoverElement, '.visible')
if (prev && prev.classList.contains('visible')) {
prev.classList.add('hover')
console.log(prev.offsetTop)
this.listItems.scrollTo({
top: prev.offsetTop - 160,
})
} else {
lastItem.classList.add('hover')
this.listItems.scrollTo({
top: lastItem.offsetTop - 160,
})
}
}
//down
if (keyCode === 40) {
const next = this.getNextSibling(hoverElement, '.visible')
if (next && next.classList.contains('visible')) {
next.classList.add('hover')
this.listItems.scrollTo({
top: next.offsetTop - 160
})
} else {
firstItem.classList.add('hover')
this.listItems.scrollTo({
top: firstItem.offsetTop - 160,
})
}
}
}
}
if (keyCode === 13) {
event.preventDefault()
const currentSelected = this.listItems.querySelector('.hover');
if (currentSelected) {
const selected = this.listItems.querySelector('.selected');
if (!this.container.hasAttribute('multiple')) {
if (selected) {
selected.classList.remove('selected')
}
currentSelected.classList.add('selected')
this.selected.innerText = currentSelected.innerHTML
this.container.value = currentSelected.dataset.select
if (this.dynamic.change) {
this.dynamic.change(this.container.value)
}
} else {
this.multipleSelected(currentSelected, this.container.querySelector(`option[value="${currentSelected.dataset.select}"]`))
}
this.container.parentNode.classList.remove('form-error')
this.clear()
}
}
})
}
multipleSelected(listItem, e) {
if (!this.selected.querySelector(`.selected-box[data-id="${e.value}"]`)) {
const sb = document.createElement('div')
const close = document.createElement('div')
sb.className = 'selected-box'
close.className = 'close'
sb.innerText = e.innerText
sb.setAttribute('data-id', e.value)
const sbExists = this.selected.querySelector('.selected-box')
if (!sbExists) {
this.selected.innerHTML = '';
}
sb.appendChild(close)
this.selected.appendChild(sb)
listItem.classList.add('selected')
e.setAttribute('selected', true)
sb.addEventListener('click', () => {
event.preventDefault()
e.removeAttribute('selected')
const listItemSelected = this.listItems.querySelector(`.list-item[data-select="${e.value}"]`)
listItemSelected.classList.remove('selected')
sb.remove()
const sbExists = this.selected.querySelector('.selected-box')
if (!sbExists) {
var s = this.container.querySelector('option:first-child')
if (s)
this.selected.innerHTML = s.innerText;
}
})
}
}
dataRetrieve() {
this.box.classList.add('search-box')
this.list.classList.add('list')
this.selected.classList.add('selected')
this.listItems.classList.add('list-items')
this.list.appendChild(this.searchField)
this.list.appendChild(this.listItems)
this.box.appendChild(this.selected)
this.box.appendChild(this.list)
if (this.container.hasClass('disabled')) {
this.box.classList.add('disabled')
}
this.box.addEventListener('click', e => {
if (
!event.target.classList.contains('selected-box') &&
!event.target.classList.contains('close')
) {
if (this.box.classList.contains('open')) {
this.clear()
} else {
document.querySelectorAll('.search-box').forEach(b => {
b.classList.remove('open')
})
this.box.classList.add('open')
this.searchField.focus()
}
}
})
this.keyDown()
this.updateFromOptionList()
this.searchField.addEventListener('keyup', e => {
this.listItems.querySelectorAll('.list-item').forEach((e, i) => {
if (e.innerText.toLowerCase().indexOf(this.searchField.value.toLowerCase()) !== -1 || this.searchField.value === '') {
e.style.display = 'block'
e.classList.add('visible')
} else {
e.style.display = 'none'
e.classList.remove('visible')
e.classList.remove('hover')
}
})
})
this.container.parentNode.appendChild(this.box);
}
updateFromOptionList() {
this.listItems.innerHTML = '';
this.container.querySelectorAll('option').forEach((e, i) => {
if (i === 0) {
//if (this.selected.innerText !== '')
this.selected.innerText = e.innerText
}
if (e.value) {
const listItem = document.createElement('div');
listItem.className = 'list-item visible'
listItem.setAttribute('data-select', e.value)
listItem.innerText = e.innerText;
this.listItems.appendChild(listItem)
if (e.hasAttribute('selected') && !this.container.hasAttribute('multiple')) {
this.selected.innerText = e.innerText
listItem.classList.add('selected')
this.listItems.scrollTo({
top: listItem.offsetTop - 160,
})
}
if (e.hasAttribute('selected') && this.container.hasAttribute('multiple')) {
this.multipleSelected(listItem, e)
}
listItem.addEventListener('click', l => {
if (!this.container.hasAttribute('multiple')) {
this.container.value = e.value
this.selected.innerText = e.innerText
if (this.dynamic.change) {
this.dynamic.change(this.container.value)
}
} else {
this.multipleSelected(listItem, e)
}
this.container.parentNode.classList.remove('form-error')
})
}
})
}
updateFromObject(object) {
const $this = this;
object.searchBox.dynamic.change = function (value) {
$this.request(object.url, `${object.queryId}=${value}`, data => {
//console.log(data);
$this.container.innerHTML = $this.container.querySelector('option:first-child').outerHTML
data.forEach(o => {
if (o[object.data.id] && o[object.data.name]) {
const option = document.createElement('option')
option.value = o[object.data.id];
option.innerText = o[object.data.name]
$this.container.appendChild(option)
}
})
if (data.length > 0) {
$this.updateFromOptionList()
$this.container.classList.remove('disabled')
$this.box.classList.remove('disabled')
}
})
}
}
request(url, query, callback) {
const xhr = new XMLHttpRequest()
xhr.responseType = 'json'
xhr.open('get', `${url}?${query}`)
xhr.onload = () => {
callback(xhr.response)
}
xhr.send()
}
}
@@ -0,0 +1,56 @@
function idleLogout() {
var t;
var sleep = false;
window.onload = resetTimer;
window.onmousemove = resetTimer;
window.onmousedown = resetTimer; // catches touchscreen presses as well
window.ontouchstart = resetTimer; // catches touchscreen swipes as well
window.ontouchmove = resetTimer; // required by some devices
window.onclick = resetTimer; // catches touchpad clicks as well
window.onkeydown = resetTimer;
window.addEventListener('scroll', resetTimer, true); // improved; see comments
function yourFunction() {
clearTimeout(t);
sleep = true;
modal.sessionLeft('Вашата сесия ще изтече след ', 60, null, () => {
sleep = false;
resetTimer();
}, () => {
let key = document.getElementById('user_type_key');
window.location.href = `/${key.value}/logout/`
});
}
function resetTimer() {
if(!sleep) {
clearTimeout(t);
t = setTimeout(yourFunction, 9*60*1000); // time is in milliseconds
}
}
}
//idleLogout();
function checkActivity() {
const xhr = new XMLHttpRequest();
xhr.open('get', '/remote/check-activity/')
xhr.responseType = 'json';
xhr.onload = () => {
if (xhr.response && xhr.response.status) {
if (xhr.response.status === 'inactive') {
window.location.href = xhr.response.redirect;
//console.log(xhr.response)
} else {
console.log(xhr.response)
setTimeout(function () {
checkActivity()
}, 200000)
}
}
}
xhr.send();
}
checkActivity();