diff --git a/.eslintrc.js b/.eslintrc.js index 15e495b..a19f6e7 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,20 +1,22 @@ module.exports = { - env: { - browser: true, - es6: true, - node: true, - jest: true, - }, - extends: ["eslint:recommended"], - globals: { - Atomics: "readonly", - SharedArrayBuffer: "readonly", - }, - rules: { - "no-extra-semi": "off", - "no-undef": ["warn"], - eqeqeq: ["warn", "smart"], - "no-unused-vars": "off", - "no-prototype-builtins": "off", - }, + env: { + browser: true, + es6: true, + node: true, + jest: true, + }, + extends: ['eslint:recommended'], + globals: { + Atomics: 'readonly', + SharedArrayBuffer: 'readonly', + }, + rules: { + 'no-extra-semi': 'off', + 'no-undef': ['error'], + eqeqeq: ['warn', 'smart'], + 'no-unused-vars': 'warn', + 'no-prototype-builtins': 'off', + 'object-shorthand': ['warn', 'never'], + 'prefer-const': 'warn', + }, } diff --git a/stable.user.js b/stable.user.js index 4f47dba..17f50ae 100755 --- a/stable.user.js +++ b/stable.user.js @@ -90,8 +90,8 @@ function delVal(name) { return GM_deleteValue(name) } - function openInTab(address, options) { - GM_openInTab(address, options) + function openInTab(address) { + GM_openInTab(address, false) } function xmlhttpRequest(opts) { GM_xmlhttpRequest(opts) @@ -105,22 +105,25 @@ // : Constants and global variables {{{ - const logElementGetting = false - const logEnabled = true - const showErrors = true + // ------------------------------------------------------------------------------ + // Devel vars + // ------------------------------------------------------------------------------ // forcing pages for testing. unless you test, do not set these to true! setVal('ISDEVEL', false) // only one of these should be true for testing const forceTestPage = false const forceResultPage = false const forceDefaultPage = false + // ------------------------------------------------------------------------------ + + const logElementGetting = false + const logEnabled = true + const showErrors = true var addEventListener // add event listener function let serverAdress = 'https://qmining.frylabs.net/' let apiAdress = 'https://api.frylabs.net/' - const ircAddress = 'https://kiwiirc.com/nextclient/irc.sub.fm/#qmining' - const correctSource = - 'https://qmining.frylabs.net/moodle-test-userscript/stable.user.js?up' + // const ircAddress = 'https://kiwiirc.com/nextclient/irc.sub.fm/#qmining' const motdShowCount = 3 /* Ammount of times to show motd */ const messageOpacityDelta = 0.1 @@ -147,6 +150,29 @@ ? 'https://elearning.uni-obuda.hu/' : location.href + const menuButtons = { + website: { + title: 'Weboldal', + onClick: () => { + openInTab(serverAdress + 'menuClick') + }, + }, + help: { + title: 'Help', + onClick: () => { + ShowHelp() + }, + }, + donate: { + title: 'Donate', + onClick: () => { + openInTab(serverAdress + 'donate?scriptMenu', { + active: true, + }) + }, + }, + } + // : Localisation {{{ const huTexts = { @@ -172,8 +198,6 @@ retry: 'Újrapróbálás', dataEditor: 'Data editor', dataEditorTitle: 'Adatbázisban lévő kérdések szerkesztése', - ircButton: 'IRC chat', - ircButtonTitle: 'IRC chat', invalidPW: 'Hibás jelszó: ', search: 'Keresés ...', loading: 'Betöltés ...', @@ -181,7 +205,7 @@ newPWTitle: 'Új jelszó új felhasználónak', pwRequest: 'Jelszó új felhasználónak', noServer: 'Nem elérhető a szerver!', - noUser: 'Nem vagy bejelentkezve!', + pwHere: 'Jelszó ...', noServerConsoleMessage: `Nem elérhető a szerver, vagy kis eséllyel kezeletlen hiba történt! Ha elérhető a weboldal, akkor ott meg bírod nézni a kérdéseket itt: ${serverAdress}legacy`, noParseableQuestionResult: 'A tesztben nem találhatók kérdések, amit fel lehet dolgozni, vagy hiba történt feldolgozásuk közben', @@ -219,9 +243,19 @@ } } - let select = elem.tagName ? elem.getElementsByTagName('select') : [] + const select = elem.tagName ? elem.getElementsByTagName('select') : [] if (select.length > 0) { - promises.push({ type: 'txt', val: '...', node: select[0] }) + const question = [] + Array.from(elem.childNodes).forEach(cn => { + if (cn.nodeValue) { + question.push(cn.nodeValue) + } + }) + promises.push({ + type: 'txt', + val: question.join('...'), + node: select[0], + }) return promises } @@ -302,10 +336,6 @@ return document.getElementById('page-header').innerText.split('\n')[0] || '' } - function uniq(a) { - return [...new Set(a)] - } - // : }}} // : Test page processing functions {{{ @@ -405,44 +435,63 @@ } function getPossibleAnswersFromTest(node) { - const promises = [] - let answerRoot = node.getElementsByClassName('answer')[0] + try { + const promises = [] + let answerRoot = node.getElementsByClassName('answer')[0] - if (!answerRoot) { - answerRoot = node.getElementsByClassName('subquestion')[0] - const options = Array.from(answerRoot.getElementsByTagName('option')) - const possibleAnswers = options.reduce((acc, option) => { - if (!emptyOrWhiteSpace(option.innerText)) { - acc.push(option.innerText) + if (!answerRoot) { + answerRoot = node.getElementsByClassName('subquestion')[0] + if (answerRoot) { + // FIXME: is this needed, what is this lol + const options = Array.from(answerRoot.getElementsByTagName('option')) + const possibleAnswers = options.reduce((acc, option) => { + if (!emptyOrWhiteSpace(option.innerText)) { + acc.push([{ type: 'txt', val: option.innerText }]) + } + return acc + }, []) + + return possibleAnswers + } else { + const select = node.getElementsByTagName('select')[0] + if (select) { + const options = [] + Array.from(select).forEach(opt => { + if (!emptyOrWhiteSpace(opt.innerText)) { + options.push([{ type: 'txt', val: opt.innerText }]) + } + }) + return options + } } - return acc - }, []) + } else if (answerRoot.tagName === 'DIV') { + const answers = Array.from(answerRoot.childNodes) - return possibleAnswers - } else if (answerRoot.tagName === 'DIV') { - const answers = Array.from(answerRoot.childNodes) + answers.forEach(answer => { + if (answer.tagName) { + promises.push(getTextPromisesFromNode(answer)) + } + }) - answers.forEach(answer => { - if (answer.tagName) { - promises.push(getTextPromisesFromNode(answer)) - } - }) + return promises + } else if (answerRoot.tagName === 'TABLE') { + const answers = Array.from(answerRoot.childNodes[0].childNodes) - return promises - } else if (answerRoot.tagName === 'TABLE') { - const answers = Array.from(answerRoot.childNodes[0].childNodes) + answers.forEach(answer => { + if (answer.tagName) { + promises.push( + getTextPromisesFromNode(answer.getElementsByClassName('text')[0]) + ) + // here elements with classname 'control' could be added too. Those should be a dropdown, + // containing possible choices + } + }) - answers.forEach(answer => { - if (answer.tagName) { - promises.push( - getTextPromisesFromNode(answer.getElementsByClassName('text')[0]) - ) - // here elements with classname 'control' could be added too. Those should be a dropdown, - // containing possible choices - } - }) - - return promises + return promises + } + } catch (e) { + warn('Error in getPossibleAnswersFromTest()!') + warn(e) } } @@ -494,7 +543,7 @@ x.reduce(makeTextFromElements, []).join(' ') ) }) - let images = getImagesFromElements([ + const images = getImagesFromElements([ ...question, ...possibleAnswerArray.reduce((acc, x) => { return [...acc, ...x] @@ -598,43 +647,52 @@ function getQuizFromNode(node) { return new Promise(resolve => { - const questionPromises = getPromisesThatMeetsRequirements( - questionGetters, - node - ) - const answerPromises = getPromisesThatMeetsRequirements( - answerGetters, - node - ) - const possibleAnswers = getPossibleAnswers(node) + try { + const questionPromises = getPromisesThatMeetsRequirements( + questionGetters, + node + ) + const answerPromises = getPromisesThatMeetsRequirements( + answerGetters, + node + ) + const possibleAnswers = getPossibleAnswers(node) - if (!answerPromises || !questionPromises) { - log('Answer or question array is empty, skipping question') - resolve({ success: false }) - } - - Promise.all([Promise.all(questionPromises), Promise.all(answerPromises)]) - .then(([question, answer]) => { - const questionText = question - .reduce(makeTextFromElements, []) - .join(' ') - const answerText = answer.reduce(makeTextFromElements, []).join(' ') - let images = getImagesFromElements([...question, ...answer]) - - const result = { - Q: removeUnnecesarySpaces(questionText), - A: removeUnnecesarySpaces(answerText), - data: getDataFromResultImages(images), - success: true, - } - result.data.possibleAnswers = possibleAnswers - resolve(result) - }) - .catch(err => { - warn('Error in getQuizFromNode()') - warn(err) + if (!answerPromises || !questionPromises) { + log('Answer or question array is empty, skipping question') resolve({ success: false }) - }) + } + + Promise.all([ + Promise.all(questionPromises), + Promise.all(answerPromises), + ]) + .then(([question, answer]) => { + const questionText = question + .reduce(makeTextFromElements, []) + .join(' ') + const answerText = answer.reduce(makeTextFromElements, []).join(' ') + const images = getImagesFromElements([...question, ...answer]) + + const result = { + Q: removeUnnecesarySpaces(questionText), + A: removeUnnecesarySpaces(answerText), + data: getDataFromResultImages(images), + success: true, + } + result.data.possibleAnswers = possibleAnswers + resolve(result) + }) + .catch(err => { + warn('Error in getQuizFromNode()') + warn(err) + resolve({ success: false }) + }) + } catch (e) { + warn('Error in getQuizFromNode()!') + warn(e) + warn(node) + } }) } @@ -660,7 +718,7 @@ return node.getElementsByClassName('qtext').length > 0 }, getterFunction: node => { - let question = node.getElementsByClassName('qtext')[0] + const question = node.getElementsByClassName('qtext')[0] return getTextPromisesFromNode(question) }, }, @@ -673,7 +731,7 @@ return node.getElementsByClassName('rightanswer').length > 0 }, getterFunction: node => { - let answer = node.getElementsByClassName('rightanswer')[0] + const answer = node.getElementsByClassName('rightanswer')[0] return getTextPromisesFromNode(answer) }, }, @@ -755,33 +813,52 @@ } function getPossibleAnswers(node) { - const answerNodes = Array.from( - node.getElementsByClassName('answer')[0].childNodes - ) + try { + if (node.getElementsByClassName('answer').length > 0) { + const answerNodes = Array.from( + node.getElementsByClassName('answer')[0].childNodes + ) - return answerNodes.reduce((acc, answerNode) => { - let selectedByUser - if (answerNode.childNodes.length > 0) { - selectedByUser = answerNode.childNodes[0].checked + return answerNodes.reduce((acc, answerNode) => { + let selectedByUser + if (answerNode.childNodes.length > 0) { + selectedByUser = answerNode.childNodes[0].checked + } + + const text = removeUnnecesarySpaces(answerNode.innerText) + + if (text !== '') { + acc.push({ + text: text, + selectedByUser: selectedByUser, + }) + } + return acc + }, []) + } else { + const select = node.getElementsByTagName('select')[0] + if (select) { + const options = [] + Array.from(select.childNodes).forEach(opt => { + if (!emptyOrWhiteSpace(opt.innerText)) { + options.push(opt.innerText) + } + }) + return options + } } - - const text = removeUnnecesarySpaces(answerNode.innerText) - - if (text !== '') { - acc.push({ - text: text, - selectedByUser: selectedByUser, - }) - } - return acc - }, []) + } catch (e) { + warn('Error in getPossibleAnswers()!') + warn(e) + warn(node) + } } function digestMessage(message) { return new Promise(resolve => { const encoder = new TextEncoder() const data = encoder.encode(message) - const hash = crypto.subtle.digest('SHA-256', data).then(buf => { + crypto.subtle.digest('SHA-256', data).then(buf => { let res = String.fromCharCode.apply(null, new Uint8Array(buf)) res = btoa(res) .replace(/=/g, '') @@ -928,7 +1005,6 @@ if (elementUpdaterInterval === -1) { elementUpdaterInterval = setInterval(() => { updatableElements.forEach(({ elem, target }) => { - let currX, currY, currWidth, currHeight let { left, top, width, height } = target.getBoundingClientRect() left += window.scrollX top += window.scrollY @@ -1124,13 +1200,10 @@ } function resetMenu() { - SafeGetElementById('menuButtonDiv', elem => { + SafeGetElementById('scriptMenuDiv', elem => { elem.style.backgroundColor = '#262626' }) - SafeGetElementById('ircButton', elem => { - elem.style.display = 'none' - }) - SafeGetElementById('retryButton', elem => { + SafeGetElementById('retryContainer', elem => { elem.style.display = 'none' }) SafeGetElementById('loginDiv', elem => { @@ -1176,32 +1249,26 @@ } function NoUserAction() { - SafeGetElementById('menuButtonDiv', elem => { + SafeGetElementById('scriptMenuDiv', elem => { elem.style.backgroundColor = '#44cc00' }) SafeGetElementById('infoMainDiv', elem => { - elem.innerText = texts.noUser - if (getCid()) { - elem.innerText += ` (${getCid()})` - } + elem.innerText = '' }) SafeGetElementById('loginDiv', elem => { - elem.style.display = '' + elem.style.display = 'flex' }) } function NoServerAction() { - SafeGetElementById('menuButtonDiv', elem => { + SafeGetElementById('scriptMenuDiv', elem => { elem.style.backgroundColor = 'red' }) SafeGetElementById('infoMainDiv', elem => { elem.innerText = texts.noServer }) - SafeGetElementById('ircButton', elem => { - elem.style.display = '' - }) - SafeGetElementById('retryButton', elem => { - elem.style.display = '' + SafeGetElementById('retryContainer', elem => { + elem.style.display = 'flex' }) log(texts.noServerConsoleMessage) } @@ -1237,7 +1304,7 @@ } } - function HandleUI(url) { + function HandleUI() { const newVersion = info().script.version !== getVal('lastVerson') const showMOTD = shouldShowMotd() const isNewVersionAvaible = @@ -1263,10 +1330,6 @@ greetMsg.push(texts.versionUpdated + info().script.version) setVal('lastVerson', info().script.version) // setting lastVersion } - if (!installedFromCorrectSource(correctSource)) { - greetMsg.push(texts.reinstallFromCorrectSource) - log(`update url:${info().script.updateURL}`) - } if (showMOTD) { greetMsg.push(texts.motd + motd) timeout = null @@ -1359,7 +1422,7 @@ // : Quiz saving {{{ - function HandleResults(url) { + function HandleResults() { getQuiz().then(res => { SaveQuiz(res, ShowSaveQuizDialog) // saves the quiz questions and answers }) @@ -1433,15 +1496,6 @@ // : Misc {{{ - // : Install source checker {{{ - - function installedFromCorrectSource(source) { - // https://qmining.frylabs.net/moodle-test-userscript/stable.user.js?up - return info().script.updateURL === correctSource - } - - // : }}} - // : Version action functions {{{ function FreshStart() { @@ -1494,7 +1548,7 @@ // : Video hotkey stuff {{{ // this function adds basic hotkeys for video controll. - function AddVideoHotkeys(url) { + function AddVideoHotkeys() { var seekTime = 20 document.addEventListener('keydown', function(e) { try { @@ -1666,7 +1720,7 @@ mainDiv.offsetTop - e.clientY, ] }) - mainDiv.addEventListener('mouseup', e => { + mainDiv.addEventListener('mouseup', () => { isMouseDown = false }) mainDiv.addEventListener('mousemove', e => { @@ -1848,13 +1902,12 @@ const buttonStyle = { color: 'white', backgroundColor: 'transparent', - margin: buttonMargin, + margin: '2px', border: 'none', fontSize: '30px', cursor: 'pointer', userSelect: 'none', } - var buttonMargin = '2px 2px 2px 2px' // uniform button margin if (msgItem[currItem].length > 1) { // PREV SUGG BUTTON ------------------------------------------------------------------------------------------------------------ var prevSuggButton = CreateNodeWithText( @@ -1952,53 +2005,59 @@ // shows a fancy menu function ShowMenu() { try { - const appedtTo = overlay // will be appended here - const menuButtonDiv = document.createElement('div') - const id = 'menuButtonDiv' - menuButtonDiv.setAttribute('id', id) - SetStyle(menuButtonDiv, { - width: '600px', - // height: buttonHeight + 'px', - top: window.innerHeight - 160 + 'px', + // Script menu ----------------------------------------------------------------- + const scriptMenuDiv = document.createElement('div') + const id = 'scriptMenuDiv' + scriptMenuDiv.setAttribute('id', id) + SetStyle(scriptMenuDiv, { + width: '300px', + height: '90px', + position: 'fixed', + bottom: '10px', left: '10px', zIndex: 999999, - position: 'fixed', - textAlign: 'center', - padding: '0px', - margin: '0px', background: '#262626', border: '3px solid #99f', borderRadius: '5px', opacity: getVal(`${id}_opacity`), + fontSize: '14px', }) - // ------------------------------------------------------------------ - // transparencity - // ------------------------------------------------------------------ - addOpacityChangeEvent(menuButtonDiv) - const xButton = CreateNodeWithText(menuButtonDiv, '❌', 'div') - SetStyle(xButton, { - cursor: 'pointer', - position: 'absolute', - right: '0px', - display: 'inline', - margin: '5px', + addEventListener(scriptMenuDiv, 'mousedown', function(e) { + if (e.which === 2) { + scriptMenuDiv.parentNode.removeChild(scriptMenuDiv) + } }) + addOpacityChangeEvent(scriptMenuDiv) + + // X button -------------------------------------------------------------------- + const xButton = CreateNodeWithText(scriptMenuDiv, '❌', 'div') + SetStyle(xButton, { + position: 'absolute', + display: 'inline', + right: '0px', + margin: '5px', + cursor: 'pointer', + fontSize: '18px', + }) + xButton.addEventListener('mousedown', e => { e.stopPropagation() - menuButtonDiv.parentNode.removeChild(menuButtonDiv) + scriptMenuDiv.parentNode.removeChild(scriptMenuDiv) }) - const mailButton = CreateNodeWithText(menuButtonDiv, '📭', 'div') + // Mail button ----------------------------------------------------------------- + const mailButton = CreateNodeWithText(scriptMenuDiv, '📭', 'div') mailButton.setAttribute('id', 'mailButton') SetStyle(mailButton, { - fontSize: '30px', position: 'absolute', + display: 'inline', left: '0px', bottom: '0px', - display: 'inline', margin: '5px', + fontSize: '30px', }) + mailButton.addEventListener('mousedown', e => { e.stopPropagation() if (userSpecificMotd && !userSpecificMotd.seen) { @@ -2016,215 +2075,111 @@ ) }) - var tbl = document.createElement('table') - tbl.style.margin = '5px 5px 5px 5px' - tbl.style.textAlign = 'left' - tbl.style.width = '98%' - menuButtonDiv.appendChild(tbl) + // ----------------------------------------------------------------------------- + // BUTTONS + // ----------------------------------------------------------------------------- + const buttonContainer = document.createElement('div') + SetStyle(buttonContainer, { + display: 'flex', + justifyContent: 'center', + }) - var buttonRow = tbl.insertRow() - var buttonCell = buttonRow.insertCell() - buttonCell.style.textAlign = 'center' + scriptMenuDiv.appendChild(buttonContainer) - var buttonRow2 = tbl.insertRow() - var buttonCell2 = buttonRow2.insertCell() - buttonCell2.style.textAlign = 'center' - - let buttonStyle = { + const buttonStyle = { position: '', - margin: '5px 5px 5px 5px', - border: 'none', - backgroundColor: '#333333', - padding: '4px', + margin: '3px', + padding: '4px 8px', + border: '1px solid #333', borderRadius: '2px', color: '#ffffff', cursor: 'pointer', } - // site link ---------------------------------------------------------------------------------------------------------------- - let siteLink = CreateNodeWithText( - buttonCell, - texts.websiteBugreport, - 'button' - ) - SetStyle(siteLink, buttonStyle) - - siteLink.addEventListener('click', function() { - openInTab(serverAdress + 'menuClick', { - active: true, - }) + Object.keys(menuButtons).forEach(key => { + const buttonData = menuButtons[key] + const button = CreateNodeWithText( + buttonContainer, + buttonData.title, + 'div' + ) + SetStyle(button, buttonStyle) + if (buttonData.onClick) { + button.addEventListener('click', function() { + buttonData.onClick() + }) + } }) - // help button ---------------------------------------------------------------------------------------------------------------- - let helpButton = CreateNodeWithText(buttonCell, texts.help, 'button') - SetStyle(helpButton, buttonStyle) - - helpButton.addEventListener('click', function() { - ShowHelp() - }) // adding clicktextNode - - // site link ---------------------------------------------------------------------------------------------------------------- - - let contributeLink = CreateNodeWithText( - buttonCell, - texts.contribute, - 'button' - ) - SetStyle(contributeLink, buttonStyle) - - contributeLink.addEventListener('click', function() { - openInTab(serverAdress + 'contribute?scriptMenu', { - active: true, - }) - }) - - // pw request ---------------------------------------------------------------------------------------------------------------- - - let pwRequest = CreateNodeWithText(buttonCell2, texts.pwRequest, 'button') - pwRequest.title = texts.newPWTitle - SetStyle(pwRequest, buttonStyle) - - pwRequest.addEventListener('click', function() { - openInTab(serverAdress + 'pwRequest?scriptMenu', { - active: true, - }) - }) - // IRC ---------------------------------------------------------------------------------------------------------------- - - let ircButton2 = CreateNodeWithText( - buttonCell2, - texts.ircButton, - 'button' - ) - ircButton2.title = texts.ircButtonTitle - SetStyle(ircButton2, buttonStyle) - ircButton2.addEventListener('click', function() { - openInTab(serverAdress + 'irc?scriptMenu', { - active: true, - }) - }) - // Dataeditor ---------------------------------------------------------------------------------------------------------------- - - let ranklistButton = CreateNodeWithText( - buttonCell2, - texts.ranklist, - 'button' - ) - SetStyle(ranklistButton, buttonStyle) - ranklistButton.addEventListener('click', function() { - openInTab(serverAdress + 'ranklist?scriptMenu', { - active: true, - }) - }) - // Dataeditor ---------------------------------------------------------------------------------------------------------------- - - let dataEditorButton = CreateNodeWithText( - buttonCell2, - texts.dataEditor, - 'button' - ) - dataEditorButton.title = texts.dataEditorTitle - SetStyle(dataEditorButton, buttonStyle) - dataEditorButton.addEventListener('click', function() { - openInTab(serverAdress + 'dataeditor?scriptMenu', { - active: true, - }) - }) - - // donate link ---------------------------------------------------------------------------------------------------------------- - let donateLink = CreateNodeWithText(buttonCell, texts.donate, 'button') - SetStyle(donateLink, buttonStyle) - - donateLink.addEventListener('click', function() { - openInTab(serverAdress + 'donate?scriptMenu', { - active: true, - }) - }) - - addEventListener(window, 'resize', function() { - menuButtonDiv.style.top = window.innerHeight - 70 + 'px' - }) - - // INFO TABEL -------------------------------------------------------------------- - var itbl = document.createElement('table') - SetStyle(itbl, { - margin: '5px 5px 5px 5px', - textAlign: 'left', - width: '98%', - }) - menuButtonDiv.appendChild(itbl) - var ibuttonRow = tbl.insertRow() - var ibuttonCell = ibuttonRow.insertCell() - ibuttonCell.style.textAlign = 'center' - - // INFO DIV --------------------------------------------------------------------------------- - let infoDiv = CreateNodeWithText(ibuttonCell, texts.loading, 'span') + // ----------------------------------------------------------------------------- + // Info text + // ----------------------------------------------------------------------------- + const infoDiv = CreateNodeWithText(scriptMenuDiv, texts.loading, 'div') infoDiv.setAttribute('id', 'infoMainDiv') SetStyle(infoDiv, { color: '#ffffff', - margin: '5px', + margin: '0px 50px', + textAlign: 'center', + }) + + // ----------------------------------------------------------------------------- + // Login stuff (if user is not logged in) + // ----------------------------------------------------------------------------- + const loginContainer = document.createElement('div') + scriptMenuDiv.appendChild(loginContainer) + loginContainer.setAttribute('id', 'loginDiv') + SetStyle(loginContainer, { + display: 'none', + margin: '0px 50px', }) - // login div ---------------------------------------------------------------------------------------------------------------- - const loginDiv = document.createElement('div') - loginDiv.style.display = 'none' - loginDiv.setAttribute('id', 'loginDiv') - const loginButton = document.createElement('button') - loginButton.innerText = texts.login const loginInput = document.createElement('input') + loginContainer.appendChild(loginInput) loginInput.type = 'text' - loginInput.style.width = '400px' - loginInput.style.textAlign = 'center' - loginDiv.appendChild(loginInput) - loginDiv.appendChild(loginButton) + loginInput.placeholder = texts.pwHere + SetStyle(loginInput, { + width: '100%', + textAlign: 'center', + }) + const loginButton = document.createElement('div') + loginContainer.appendChild(loginButton) + loginButton.innerText = texts.login SetStyle(loginButton, buttonStyle) - loginButton.addEventListener('click', function() { Auth(loginInput.value) }) - ibuttonCell.appendChild(loginDiv) - - // irc button ---------------------------------------------------------------------------------------------------------------- - let ircButton = CreateNodeWithText(ibuttonCell, texts.ircButton, 'button') - SetStyle(ircButton, buttonStyle) - ircButton.style.display = 'none' - ircButton.setAttribute('id', 'ircButton') - - ircButton.addEventListener('click', function() { - openInTab(ircAddress, { - active: true, - }) + // ----------------------------------------------------------------------------- + // Retry connection button (if server is not available) + // ----------------------------------------------------------------------------- + const retryContainer = CreateNodeWithText(scriptMenuDiv, '', 'div') + SetStyle(retryContainer, { + display: 'hidden', + justifyContent: 'center', }) + retryContainer.style.display = 'none' + retryContainer.setAttribute('id', 'retryContainer') - // retry button ---------------------------------------------------------------------------------------------------------------- - let retryButton = CreateNodeWithText(ibuttonCell, texts.retry, 'button') - SetStyle(retryButton, buttonStyle) - retryButton.style.display = 'none' - retryButton.setAttribute('id', 'retryButton') - + const retryButton = CreateNodeWithText(retryContainer, texts.retry, 'div') + retryContainer.appendChild(retryButton) + SetStyle(retryButton, { + position: '', + padding: '0px 8px', + border: '1px solid #333', + borderRadius: '2px', + color: '#ffffff', + cursor: 'pointer', + }) retryButton.addEventListener('click', function() { - menuButtonDiv.style.background = '#262626' + scriptMenuDiv.style.background = '#262626' infoDiv.innerText = texts.loading - retryButton.style.display = 'none' - ircButton.style.display = 'none' + retryContainer.style.display = 'none' ConnectToServer(AfterLoad) }) - // window resize event listener --------------------------------------- - addEventListener(window, 'resize', function() { - menuButtonDiv.style.top = window.innerHeight - 70 + 'px' - }) - // APPEND EVERYTHING - appedtTo.appendChild(menuButtonDiv) - - addEventListener(menuButtonDiv, 'mousedown', function(e) { - if (e.which === 2) { - menuButtonDiv.parentNode.removeChild(menuButtonDiv) - } - }) + overlay.appendChild(scriptMenuDiv) } catch (e) { Exception(e, 'script error at showing menu:') } @@ -2264,17 +2219,15 @@ return ( value - .replace(/\n/g, '') + .replace(/\s/g, '') .replace(/\t/g, '') .replace(/ /g, '') - .replace(/\s/g, ' ') === '' + .replace(/\n/g, ' ') === '' ) } // : }}} - const specialChars = ['&', '\\+'] - const assert = val => { if (!val) { throw new Error('Assertion failed') @@ -2324,7 +2277,7 @@ } function SafeGetElementById(id, next) { - let element = overlay.querySelector('#' + id) + const element = overlay.querySelector('#' + id) if (element) { next(element) } else { @@ -2419,46 +2372,6 @@ } } - function GetXHRQuestionAnswer(question) { - log('QUESTIONS', question) - return new Promise((resolve, reject) => { - let url = apiAdress + 'ask?' - let params = [] - Object.keys(question).forEach(key => { - let val = question[key] - if (typeof val !== 'string') { - val = JSON.stringify(val) - } - params.push(key + '=' + encodeURIComponent(val)) - }) - url += - params.join('&') + - '&cversion=' + - info().script.version + - '&cid=' + - getCid() - - xmlhttpRequest({ - method: 'GET', - url: url, - onload: function(response) { - try { - let res = JSON.parse(response.responseText) - resolve(res.result) - } catch (e) { - reject(e) - } - }, - onerror: e => { - log('Errro paring JSON in GetXHRQuestionAnswer') - log(e) - reject(e) - reject(e) - }, - }) - }) - } - function post(path, message) { if (typeof message === 'object') { message = JSON.stringify(message)