class AppManager { #lastAction = null; #customImportance = null; #last = ['rank', null]; #inputCallback = null; parentNode = document.body; #settingBlock = null; #settingPlaceholder = null; #settingblockCloseButton = null; #alreadyFieldBlocks = []; constructor() { console.log('AppManager initialized'); } #showSettingBlock(item, e) { let importance = item; if(importance.tagName != 'INPUT'){ importance = item.parentNode.getElementsByTagName('INPUT')[0]; } const nameMatch = importance.name.match(/^criteria\[(\d+)\]/); if (!nameMatch) { return; } const index = nameMatch[1]; const field = importance.getAttribute('field'); const div = document.querySelector(`div.setting[field="${field}"]`); const parent = div.parentNode; this.#settingBlock = div; this.#positionSettingBlock(); this.#settingblockCloseButton.style.display = 'block'; } #hideSettingBlock() { if(!this.#settingBlock){ return; } this.#settingBlock.style.display = ''; this.#settingBlock.style.position = ''; this.#settingBlock.style.width = ''; this.#settingBlock.style.border = ''; this.#settingBlock.style.backgroundColor = ''; this.#settingBlock.style.padding = ''; this.#settingBlock.style.zIndex = ''; this.#settingBlock.style.left = ''; this.#settingBlock.style.top = ''; this.#settingPlaceholder.style.display = 'none'; this.#settingBlock = null; this.#settingblockCloseButton.style.display = 'none'; } #positionSettingBlock() { if(!this.#settingBlock){ return; } this.#settingBlock.style.display = 'block'; this.#settingBlock.style.position = 'fixed'; this.#settingBlock.style.width = '300px'; this.#settingBlock.style.border = '1px solid #0000001a'; this.#settingBlock.style.backgroundColor = 'white'; this.#settingBlock.style.padding = '60px'; this.#settingBlock.style.zIndex = '10000'; const rect = this.#settingBlock.getBoundingClientRect(); this.#settingBlock.style.left = `CALC(50% - ${rect.width / 2}px)`; this.#settingBlock.style.top = `CALC(50% - ${rect.height / 2}px)`; if(!this.#settingPlaceholder){ this.#settingPlaceholder = document.createElement('DIV'); document.body.appendChild(this.#settingPlaceholder); this.#settingPlaceholder.classList.add('settingPlaceholder'); this.#settingPlaceholder.addEventListener('click',()=>{ this.#hideSettingBlock(); }); } if(!this.#settingblockCloseButton){ this.#settingblockCloseButton = document.createElement('BUTTON'); this.#settingblockCloseButton.classList.add('settingblockCloseButton'); this.#settingblockCloseButton.type = 'button'; this.#settingblockCloseButton.addEventListener('click',()=>{ this.#hideSettingBlock(); }); this.#settingblockCloseButton.innerHTML = 'close'; } this.#settingPlaceholder.style.display = 'block'; this.#settingBlock.appendChild(this.#settingblockCloseButton); } showSettingsWindow(item,e){ if(screen.width < 700){ return; } if(this.#settingBlock){ this.#hideSettingBlock(); }else{ this.#showSettingBlock(item,e); } } trytoshowSettingsWindow(dom){ if(!dom.getAttribute('rendered')){ return false; } const field = dom.getAttribute('field'); if(this.#alreadyFieldBlocks.indexOf(field) == -1){ this.showSettingsWindow(dom); this.#alreadyFieldBlocks.push(field); } } addInputSource(callback){ this.#inputCallback = callback; } clickSomeButton(dom){ const buttons = document.querySelectorAll('button'); const decideButton = Array.from(buttons).find(btn => btn.textContent.trim() === dom.innerText); if(decideButton){ const event = new KeyboardEvent("click", { bubbles: true, cancelable: true, key: "", code: "", keyCode: 13, which: 13 }); decideButton.dispatchEvent(event); } } showSettings(dom) { const parent = dom.parentNode; const buttons = parent.getElementsByTagName('button'); const show = buttons[0] === dom ? buttons[0] : buttons[1]; const hide = buttons[0] === dom ? buttons[1] : buttons[0]; show.style.display = 'none'; hide.style.display = ''; const criteria = this.parentNode.getElementsByClassName('criteria')[0]; if (criteria) { let hideClass = hide.getAttribute('target'); let showClass = show.getAttribute('target'); let hideCollection = criteria.getElementsByClassName(hideClass); Array.from(hideCollection).forEach((item) => { item.style.display = 'none'; }); let showCollection = criteria.getElementsByClassName(showClass); Array.from(showCollection).forEach((item) => { item.style.display = 'block'; }); if (window.rangeRender) window.rangeRender.recalculate() } document.body.dispatchEvent(new Event('resettings')); } getCriteriaData() { let dom = this.parentNode.getElementsByClassName('app-criteria')[0]; if(!dom){ dom = document.body.getElementsByClassName('app-criteria')[0]; } return app.getInputs(dom); } processedInputs(inputs, importance = null, criteria = null) { inputs = inputs || this.getCriteriaData(); let grouped = {}; Object.keys(inputs).forEach(key => { let match = key.match(/criteria\[(\d+)\]\[([a-zA-Z]+)\](?:\[([^\]]+)\])?(?:\[([^\]]+)\])?/); if (match) { let index = match[1], field = match[2], subfield = match[3], subfieldProp = match[4]; if (!grouped[index]) { grouped[index] = { id: "", name: "", importance: 0, value: [], type: "" }; } if (subfield !== undefined) { let enabledKey = `criteria[${index}][val][${subfield}][enabled]`; let numberKey = `criteria[${index}][val][${subfield}][number]`; let isEnabled = (inputs[enabledKey] ?? 'true') === 'true'; let isNumber = (inputs[numberKey] ?? 'true') === 'true'; if (['enabled', 'number'].indexOf(subfieldProp) === -1) { let parsedValue = inputs?.[key]; if (parsedValue != null) { //parsedValue = (!isNumber) ? -1 : isNumber; grouped[index].value.push({ name: subfield, value: parsedValue, enabled: isEnabled, number: isNumber }); } } } else { grouped[index][field] = field === "importance" ? parseInt(inputs[key], 10) : inputs[key]; } } }); let obj = Object.values(grouped).filter(criteria => criteria.value.length > 0 || (criteria.importance !== 0 && criteria.id && criteria.name && criteria.type) ); const filterd = obj.map(node => { if (Array.isArray(node.value)) { node.value = node.value .filter(subNode => subNode.enabled !== false && subNode.value !== "" && subNode.value !== null) .map(({ enabled, ...rest }) => rest); if (node.value.length === 0) { return null; } } else if (node.value === "" || node.value === null) { return null; } return node; }) .filter(Boolean); if (importance) { for (var fieldId in importance) { filterd.forEach(field => { if (field['id'] == fieldId) { field['importance'] = importance[fieldId]; } }) } } if (filterd.every(({ importance }) => importance === 0)) { window.toastalert('All importances cannot be zero'); return null; }; return filterd; } setSettings(data) { var data = (typeof data === 'string') ? JSON.parse(data) : data; const panels = document.body.getElementsByClassName('app-criteria'); Array.from(panels).forEach(panel =>{ const settings = panel.getElementsByClassName('setting'); let exapmles = {}; for (var key in data) { if (data[key]['name'] && data[key]['val']) { exapmles[data[key]['name']] = data[key]['val']; } } Array.from(settings).forEach(element => { const span = element.getElementsByClassName('cname')[0]; if (span) { const name = span.innerText.trim(); if (exapmles[name] && exapmles[name][name]) { const value = exapmles[name][name]; switch (typeof value) { case 'string': element.getElementsByTagName('INPUT')[0].value = value; break; case 'number': element.getElementsByTagName('INPUT')[0].value = value; break; case 'object': if (Array.isArray(value)) {//color or zipcode const inputs = Array.from(element.getElementsByTagName('INPUT')); let valueinpust = []; for (var i = 0; i < inputs.length; i++) { if (inputs[i]) { switch (inputs[i].getAttribute('type').trim()) { case 'color': case 'text': case 'number': case 'range': valueinpust.push(inputs[i]); break; } } } valueinpust.forEach((input, i) => { const hasValue = i < value.length; if (hasValue) { input.value = value[i]; } if (input.getAttribute('type')?.trim() === 'color') { const span = input.closest('span'); const checkbox = span?.querySelector('input[type="checkbox"]'); if (checkbox) { checkbox.checked = hasValue; } } if (!hasValue) { } }); } else { //select or multiselect const inputs = element.querySelectorAll('input[type="range"]'); inputs.forEach(input => { let name = input.name; const match = name.match(/\[([^\]]+)\]$/); name = match ? match[1] : ''; if (value[name]) { input.value = value[name]; } }); } break; } } } }); }); } #setImportance(data, settings = false) { var data = (typeof data === 'string') ? JSON.parse(data) : data; const inputs = document.querySelectorAll('input[type="range"]'); inputs.forEach(input => { var field = input.getAttribute('field'); var place = input.getAttribute('place'); if (field && data[field] && place == 'importance') { input.value = data[field]['importance']; } }); if (window.rangeRender) window.rangeRender.recalculate() } #getRequiredData(params) { console.log('getRequiredData'); const required = document.getElementById('requiredtobesent'); if(required){ const options = app.getInputs(required) ; for(var key in options){ params[key] = options[key]; } } console.log(params); return params; } reload(action = this.#lastAction, inputs, options = {}, includes = null, recalcImportance = false, recalcISettings = false, callback = null) { if (!action) return; includes = includes ? (Array.isArray(includes) ? includes : ['dataset', 'search']) : null; this.#lastAction = action; const doms = document.body.getElementsByClassName('new-app-results-container'); const paginations = document.body.getElementsByClassName('pagination'); for(var i = 0 ; i < doms.length ; i++){ let dom = doms[i]; let pagination = paginations[i] ?? null; dom.classList.add('loading'); let params = Object.assign({ url: action, criteria: inputs }, window.criteria ?? {}); if(this.#inputCallback){ const inputSource = this.#inputCallback(); if(typeof inputSource == 'object'){ Object.assign(params,inputSource) } } for (var key in options) { params[key] = options[key]; } if (includes) { includes.forEach(name => { const element = document.querySelector(`[name="${name}"]`); if (element) { params[name] = element.value; } }); } const $self = this; let url = action + `/${params['current_page'] ?? 1}/${params['dataset'] ?? 'null'}`; url = (params['search']) ? url + '/' + params['search'] : url; url = url.replace('result', 'json').replace('/rank', '/default'); params = this.#getRequiredData(params); app.load(params, function (result) { history.replaceState(null, '', url); if (result['blade']) { dom.innerHTML = result['blade']; dom.classList.remove('loading'); } if (typeof result['pagination'] != 'undefined') { pagination.innerHTML = result['pagination']; } if (result['criteria']) { if (recalcImportance) { $self.setImportance(result['criteria']); } if (recalcISettings) { $self.setSettings(result['criteria']); } } if (callback) { callback(result); } }); } } changePage(dom, options){ let inputs = options; let buttons = Array.from(dom.parentNode.parentNode.getElementsByTagName('button')); let current = 0; buttons.forEach(button => { if (button.parentNode.classList.contains('selected')) { current = button.parentNode.getAttribute('page'); } }); if (buttons.indexOf(dom) == 0 && current == 0) { return; } if (buttons.indexOf(dom) == buttons.length - 1 && current == buttons.length - 2) { return; } if (buttons.indexOf(dom) == 0) { current--; } else if (buttons.indexOf(dom) == buttons.length - 1) { current++; } else { current = dom.parentNode.getAttribute('page'); } buttons.forEach(button => { if (button.parentNode.getAttribute('page') == current) { button.parentNode.classList.add('selected'); } else { button.parentNode.classList.remove('selected'); } }); inputs['page'] = current; const id = dom.getAttribute('appid'); const action = this.#lastAction ?? `https://decisionin.com/public/sparkdit/apps/${id}/rank/result`; const input = document.querySelector(`[name="current_page"]`); input.value = current; let param = {}; switch (this.#last[0]) { case 'rank': param = {}; break; case 'rerank': case 'multirank': param = { 'rerank': this.#last[1] }; break; } window.criteria = window.criteria ?? {}; window.criteria['current_page'] = current; window.criteria['paginate'] = true; this.reload(action, JSON.stringify(inputs), param, true, false, false, function () { delete window.criteria['paginate']; }); } paginate(dom, options = null) { let inputs = options ?? this.processedInputs(); this.changePage(dom,inputs); } autoreload() { window.criteria = window.criteria ?? {}; window.criteria['current_page'] = 1; this.decide(document.body.getElementsByClassName('decide')[0]); } decide(dom, options = null) { const inputs = options ?? this.processedInputs(); if (!inputs) { return; } const id = dom.getAttribute('id'); const action = `https://decisionin.com/public/sparkdit/apps/${id}/rank/result`; this.#last = ['rank', null]; window.criteria = window.criteria ?? {}; window.criteria['current_page'] = 1; this.reload(action, JSON.stringify(inputs), {}, true, false, false, function () { window.criteria = {}; if(window.onDecide){ window.onDecide(); window.onDecide = null; } }); } rerank(dom) { let inputs = this.processedInputs(); const id = dom.getAttribute('id'); const rerank = dom.getAttribute('rerank'); const action = `https://decisionin.com/public/sparkdit/apps/${id}/rerank/result`; this.#last = ['rerank', rerank]; window.criteria = window.criteria ?? {}; window.criteria['current_page'] = 1; this.reload(action, JSON.stringify(inputs), { 'rerank': rerank }, true, true, false, function () { window.criteria = {}; }); } multirank(dom) { const id = dom.getAttribute('appid'); let inputs = this.processedInputs(); const rerank = window.criteria.rerank ?? '[]'; const action = `https://decisionin.com/public/sparkdit/apps/${id}/multirerank/result`; this.#last = ['multirank', rerank]; window.criteria = window.criteria ?? {}; window.criteria['current_page'] = 1; this.reload(action, JSON.stringify(inputs), { 'rerank': rerank }, true, true, true, function () { window.criteria = {}; const button = document.getElementById('thumbsupbutton'); if (button) { button.style.display = 'none'; } if(window.onMultirank){ window.onMultirank(); window.onMultirank = null; } }); } setImportance(data, settings = false) { return (typeof this.#customImportance === 'function') ? this.#customImportance(data, settings) : this.#setImportance(data, settings); } set onSetImportance(value) { this.#customImportance = value; } reset(){ const criteria = document.body.getElementsByClassName('app-criteria'); Array.from(criteria).forEach(dom =>{ const inputs = dom.querySelectorAll('input[type="range"]'); inputs.forEach(input => { input.value = 50; }); if (window.rangeRender) window.rangeRender.recalculate(); }); } } class Recorder { #className = 'fa-microphone'; init() { const inputs = document.querySelectorAll('.' + this.#className); inputs.forEach(input => { if (!input.classList.contains('render')) { input.classList.add('render'); const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; if (SpeechRecognition) { const recognition = new SpeechRecognition(); const searchFormInput = input.parentNode.getElementsByTagName('INPUT')[0]; recognition.continuous = true; recognition.lang = "en-US"; input.addEventListener('click', function () { if (!this.classList.contains("loading")) { recognition.start(); } else { recognition.stop(); } }); recognition.addEventListener("start", function () { input.classList.add("loading"); searchFormInput.focus(); searchFormInput.dispatchEvent(new Event('change')); }); recognition.addEventListener("end", function () { input.classList.remove("loading"); searchFormInput.focus(); }); recognition.addEventListener("result", function () { const current = event.resultIndex; const transcript = event.results[current][0].transcript; if (transcript.toLowerCase().trim() === "stop recording") { recognition.stop(); } else if (!searchFormInput.value) { searchFormInput.value = transcript; searchFormInput.dispatchEvent(new Event('change')); const event = new KeyboardEvent("keyup", { bubbles: true, cancelable: true, key: "Enter", code: "Enter", keyCode: 13, which: 13 }); searchFormInput.dispatchEvent(event); } else { if (transcript.toLowerCase().trim() === "go") { } else if (transcript.toLowerCase().trim() === "reset input") { searchFormInput.value = ""; searchFormInput.dispatchEvent(new Event('change')); } else { searchFormInput.value = transcript; searchFormInput.dispatchEvent(new Event('change')); } } }); } else { input.style.display = 'none'; } } }); } } document.addEventListener('DOMContentLoaded', function () { window.appManager = new AppManager(); window.rangeRender = new RangeRender(window.legacy ?? false, window.maxTriangleWidth ?? null); window.recorder = new Recorder(); rangeRender.init(); recorder.init(); });