Handling questions with select element

This commit is contained in:
mrfry 2021-03-14 12:08:27 +01:00
parent 3f641f07cc
commit a437f8f98d
2 changed files with 326 additions and 411 deletions

View file

@ -1,20 +1,22 @@
module.exports = { module.exports = {
env: { env: {
browser: true, browser: true,
es6: true, es6: true,
node: true, node: true,
jest: true, jest: true,
}, },
extends: ["eslint:recommended"], extends: ['eslint:recommended'],
globals: { globals: {
Atomics: "readonly", Atomics: 'readonly',
SharedArrayBuffer: "readonly", SharedArrayBuffer: 'readonly',
}, },
rules: { rules: {
"no-extra-semi": "off", 'no-extra-semi': 'off',
"no-undef": ["warn"], 'no-undef': ['error'],
eqeqeq: ["warn", "smart"], eqeqeq: ['warn', 'smart'],
"no-unused-vars": "off", 'no-unused-vars': 'warn',
"no-prototype-builtins": "off", 'no-prototype-builtins': 'off',
}, 'object-shorthand': ['warn', 'never'],
'prefer-const': 'warn',
},
} }

View file

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