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 = {
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',
},
}

View file

@ -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)