From 1899c8058fde577318c1911a35108ea8d91cd1a7 Mon Sep 17 00:00:00 2001 From: "caleb.mabry.15@cnu.edu" Date: Thu, 17 Mar 2022 20:00:07 -0400 Subject: Adding blip sounds to actual audio tags --- webAO/client.js | 11 ++--------- webAO/client/aoHost.js | 5 +++++ webAO/components/__tests__/blips.test.js | 9 +++++++++ webAO/components/blip.js | 17 +++++++++++++++++ 4 files changed, 33 insertions(+), 9 deletions(-) create mode 100644 webAO/client/aoHost.js create mode 100644 webAO/components/__tests__/blips.test.js create mode 100644 webAO/components/blip.js (limited to 'webAO') diff --git a/webAO/client.js b/webAO/client.js index 8bac1cc..7e82d91 100644 --- a/webAO/client.js +++ b/webAO/client.js @@ -1674,15 +1674,8 @@ class Viewport { ]; // Allocate multiple blip audio channels to make blips less jittery - - this.blipChannels = new Array( - new Audio(`${AO_HOST}sounds/general/sfx-blipmale.opus`), - new Audio(`${AO_HOST}sounds/general/sfx-blipmale.opus`), - new Audio(`${AO_HOST}sounds/general/sfx-blipmale.opus`), - new Audio(`${AO_HOST}sounds/general/sfx-blipmale.opus`), - new Audio(`${AO_HOST}sounds/general/sfx-blipmale.opus`), - new Audio(`${AO_HOST}sounds/general/sfx-blipmale.opus`), - ); + const blipSelectors = document.getElementsByClassName('blipSound') + this.blipChannels = [...blipSelectors]; this.blipChannels.forEach((channel) => channel.volume = 0.5); this.blipChannels.forEach((channel) => channel.onerror = opusCheck(channel)); this.currentBlipChannel = 0; diff --git a/webAO/client/aoHost.js b/webAO/client/aoHost.js new file mode 100644 index 0000000..b387608 --- /dev/null +++ b/webAO/client/aoHost.js @@ -0,0 +1,5 @@ +import queryParser from '../utils/queryParser' +let { asset } = queryParser(); +const DEFAULT_HOST = 'http://attorneyoffline.de/base/'; +const AO_HOST = asset || DEFAULT_HOST +export default AO_HOST diff --git a/webAO/components/__tests__/blips.test.js b/webAO/components/__tests__/blips.test.js new file mode 100644 index 0000000..9c57e78 --- /dev/null +++ b/webAO/components/__tests__/blips.test.js @@ -0,0 +1,9 @@ +import createBlip from "../blip"; + +describe('createBlip', () => { + test('create 3 blips audios', () => { + document.body.innerHTML = `` + createBlip(3) + expect(document.getElementsByClassName('blipSound').length).toBe(3) + }) +}) \ No newline at end of file diff --git a/webAO/components/blip.js b/webAO/components/blip.js new file mode 100644 index 0000000..409b907 --- /dev/null +++ b/webAO/components/blip.js @@ -0,0 +1,17 @@ +import AO_HOST from '../client/aoHost' + +/** + * + * @param {number} amountOfBlips Amount of Blips to put on page + */ +const createBlip = (amountOfBlips) => { + for (let i = 0; i < amountOfBlips; i++) { + const audio = document.createElement('audio') + const blipUrl = `${AO_HOST}sounds/general/sfx-blipmale.opus` + audio.setAttribute('class', 'blipSound') + audio.setAttribute('src', blipUrl) + document.body.appendChild(audio) + } +} +createBlip(3) +export default createBlip \ No newline at end of file -- cgit From 47ab340c76e6174f0f94fb4cbfec1540b6a18807 Mon Sep 17 00:00:00 2001 From: "caleb.mabry.15@cnu.edu" Date: Fri, 18 Mar 2022 00:06:11 -0400 Subject: Moving to audio tags --- webAO/client.js | 12 ++++++------ webAO/components/audioChannels.js | 13 +++++++++++++ 2 files changed, 19 insertions(+), 6 deletions(-) create mode 100644 webAO/components/audioChannels.js (limited to 'webAO') diff --git a/webAO/client.js b/webAO/client.js index 34a1b4b..739f170 100644 --- a/webAO/client.js +++ b/webAO/client.js @@ -1698,12 +1698,8 @@ class Viewport { this.testimonyAudio = document.getElementById('client_testimonyaudio'); this.testimonyAudio.src = `${AO_HOST}sounds/general/sfx-guilty.opus`; - this.music = new Array( - new Audio(`${AO_HOST}sounds/music/trial (aa).opus`), - new Audio(`${AO_HOST}sounds/music/trial (aa).opus`), - new Audio(`${AO_HOST}sounds/music/trial (aa).opus`), - new Audio(`${AO_HOST}sounds/music/trial (aa).opus`), - ); + const audioChannels = document.getElementsByClassName('audioChannel') + this.music = [...audioChannels]; this.music.forEach((channel) => channel.volume = 0.5); this.music.forEach((channel) => channel.onerror = opusCheck(channel)); @@ -2621,6 +2617,10 @@ window.imgError = imgError; * @param {HTMLImageElement} image the element containing the missing sound */ export function opusCheck(channel) { + const audio = channel.src + if (audio === '') { + return + } console.info(`failed to load sound ${channel.src}`); let oldsrc = ''; oldsrc = channel.src; diff --git a/webAO/components/audioChannels.js b/webAO/components/audioChannels.js new file mode 100644 index 0000000..1979653 --- /dev/null +++ b/webAO/components/audioChannels.js @@ -0,0 +1,13 @@ +/** + * + * @param {number} amountOfChannels Amount of Blips to put on page + */ +const createAudioChannels = (amountOfChannels) => { + for (let i = 0; i < amountOfChannels; i++) { + const audioChannel = document.createElement('audio') + audioChannel.setAttribute('class', 'audioChannel') + document.body.appendChild(audioChannel) + } +} +createAudioChannels(4) +export default createAudioChannels -- cgit From 0b6b4b085cee48248fe2025a2514252ee20ee774 Mon Sep 17 00:00:00 2001 From: "caleb.mabry.15@cnu.edu" Date: Fri, 18 Mar 2022 00:34:25 -0400 Subject: unit tests --- webAO/components/__tests__/audioChannels.test.js | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 webAO/components/__tests__/audioChannels.test.js (limited to 'webAO') diff --git a/webAO/components/__tests__/audioChannels.test.js b/webAO/components/__tests__/audioChannels.test.js new file mode 100644 index 0000000..243d870 --- /dev/null +++ b/webAO/components/__tests__/audioChannels.test.js @@ -0,0 +1,9 @@ +import createAudioChannels from "../audioChannels"; + +describe('createAudioChannels', () => { + test('Should create 4 channels', () => { + document.body.innerHTML = '' + createAudioChannels(4) + expect(document.getElementsByClassName('audioChannel').length).toBe(4) + }) +}) \ No newline at end of file -- cgit From 38739ca7ad89a3b743696e9b3b95c26d1a50b07a Mon Sep 17 00:00:00 2001 From: "caleb.mabry.15@cnu.edu" Date: Sun, 20 Mar 2022 14:08:10 -0400 Subject: Adding custom markdown based on asset file --- webAO/client.js | 10 ++++-- webAO/utils/aoml.js | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 webAO/utils/aoml.js (limited to 'webAO') diff --git a/webAO/client.js b/webAO/client.js index 14bfd08..a59508e 100644 --- a/webAO/client.js +++ b/webAO/client.js @@ -10,7 +10,7 @@ import fileExistsSync from './utils/fileExistsSync'; import { escapeChat, encodeChat, prepChat, safeTags, } from './encoding.js'; - +import mlConfig from './utils/aoml'; // Load some defaults for the background and evidence dropdowns import vanilla_character_arr from './constants/characters.js'; import vanilla_music_arr from './constants/music.js'; @@ -43,6 +43,8 @@ const DEFAULT_HOST = 'http://attorneyoffline.de/base/'; let AO_HOST = asset || DEFAULT_HOST; const THEME = theme || 'default'; +const attorneyMarkdown = mlConfig(AO_HOST) + const UPDATE_INTERVAL = 60; /** @@ -1938,6 +1940,7 @@ class Viewport { * @param {object} chatmsg the new chat message */ async say(chatmsg) { + this.chatmsg = chatmsg; this.textnow = ''; this.sfxplayed = 0; @@ -2089,7 +2092,7 @@ class Viewport { if (soundChecks.some((check) => this.chatmsg.sound === check)) { this.chatmsg.sound = this.chatmsg.effects[2]; } - + this.chatmsg.parsed = attorneyMarkdown.applyMarkdown(chatmsg.content) this.tick(); } @@ -2242,7 +2245,7 @@ class Viewport { } this.textnow = this.chatmsg.content.substring(0, this.textnow.length + 1); - chatBoxInner.innerText = this.textnow; + chatBoxInner.appendChild(this.chatmsg.parsed[this.textnow.length - 1]); // scroll to bottom chatBox.scrollTop = chatBox.scrollHeight; @@ -2325,6 +2328,7 @@ export function onEnter(event) { if (emote_mod === 0) { emote_mod = 1; } } else if (emote_mod === 1) { emote_mod = 0; } + client.sendIC( 'chat', myemo.preanim, diff --git a/webAO/utils/aoml.js b/webAO/utils/aoml.js new file mode 100644 index 0000000..6c4cafb --- /dev/null +++ b/webAO/utils/aoml.js @@ -0,0 +1,100 @@ +import request from "../services/request" + + +const aomlParser = (text) => { + let parsed = {} + let currentHeader = '' + for (const line of text.split(/\r?\n/)) { + if (line === '') { + currentHeader = '' + continue; + } + const content = line.split(' = ') + const contentName = content[0] + const contentValue = content[1] + if (currentHeader === '') { + currentHeader = contentName + parsed[currentHeader] = { + color: contentValue + } + } else { + const contentKey = contentName.split('_')[1] + parsed[currentHeader][contentKey] = contentValue + } + } + return parsed +} + + + + +const mlConfig = (AO_HOST) => { + const defaultUrl = `${AO_HOST}themes/default/chat_config.ini` + let aomlParsed = {} + + request(defaultUrl).then((data) => { + aomlParsed = aomlParser(data) + } + ); + + const createIdentifiers = () => { + const identifiers = new Map() + for (const [ruleName, value] of Object.entries(aomlParsed)) { + if (identifiers.has(value.start)) { + throw new Error() + } + else if (value.start) { + identifiers.set(value.start, value.end) + } + } + return identifiers + } + const colorIdentifiers = () => { + let colorIdentifier = {} + for (const [ruleName, value] of Object.entries(aomlParsed)) { + colorIdentifier[value.start] = value.color + } + return colorIdentifier + } + const applyMarkdown = (text) => { + const identifiers = createIdentifiers(aomlParsed) + const startIdentifiers = new Set(identifiers.keys()) + const colorIdentifier = colorIdentifiers() + const identifierClosingStack = [] + const colorStack = [[255, 255, 255]] + // each value in output will be an html element + let output = [] + for (const letter of text) { + let currentSelector = document.createElement('span') + + const lastItem = identifierClosingStack.length + const closingToLookFor = identifierClosingStack[lastItem-1] + if (letter === closingToLookFor) { + identifierClosingStack.pop() + colorStack.pop() + } + else if (startIdentifiers.has(letter)) { + identifierClosingStack.push(identifiers.get(letter)) + const colors = colorIdentifier[letter].split(',') + const r = colors[0] + const g = colors[1] + const b = colors[2] + colorStack.push([r,g,b]) + } else { + currentSelector.innerHTML = letter + } + const r = colorStack[colorStack.length-1][0] + const g = colorStack[colorStack.length-1][1] + const b = colorStack[colorStack.length-1][2] + const currentColor = `color: rgb(${r},${g},${b});` + currentSelector.setAttribute('style', currentColor) + output.push(currentSelector) + } + return output + } + return { + applyMarkdown + } +} + +export default mlConfig \ No newline at end of file -- cgit From 79db229a94aa3f407399158470e3d027d2b035e8 Mon Sep 17 00:00:00 2001 From: "caleb.mabry.15@cnu.edu" Date: Mon, 21 Mar 2022 17:26:05 -0400 Subject: Fixing bugs --- webAO/client.js | 3 +-- webAO/utils/aoml.js | 48 ++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 39 insertions(+), 12 deletions(-) (limited to 'webAO') diff --git a/webAO/client.js b/webAO/client.js index a59508e..87db272 100644 --- a/webAO/client.js +++ b/webAO/client.js @@ -2092,7 +2092,7 @@ class Viewport { if (soundChecks.some((check) => this.chatmsg.sound === check)) { this.chatmsg.sound = this.chatmsg.effects[2]; } - this.chatmsg.parsed = attorneyMarkdown.applyMarkdown(chatmsg.content) + this.chatmsg.parsed = attorneyMarkdown.applyMarkdown(chatmsg.content, this.colors[this.chatmsg.color]) this.tick(); } @@ -2244,7 +2244,6 @@ class Viewport { this.currentBlipChannel %= this.blipChannels.length; } this.textnow = this.chatmsg.content.substring(0, this.textnow.length + 1); - chatBoxInner.appendChild(this.chatmsg.parsed[this.textnow.length - 1]); // scroll to bottom diff --git a/webAO/utils/aoml.js b/webAO/utils/aoml.js index 6c4cafb..9506fbf 100644 --- a/webAO/utils/aoml.js +++ b/webAO/utils/aoml.js @@ -43,9 +43,12 @@ const mlConfig = (AO_HOST) => { if (identifiers.has(value.start)) { throw new Error() } - else if (value.start) { - identifiers.set(value.start, value.end) + else if (value.start && value.end) { + identifiers.set(value.start, value) + identifiers.set(value.end, value) } + + } return identifiers } @@ -56,38 +59,63 @@ const mlConfig = (AO_HOST) => { } return colorIdentifier } - const applyMarkdown = (text) => { + const applyMarkdown = (text, defaultColor) => { const identifiers = createIdentifiers(aomlParsed) const startIdentifiers = new Set(identifiers.keys()) const colorIdentifier = colorIdentifiers() const identifierClosingStack = [] + const colorStack = [[255, 255, 255]] // each value in output will be an html element let output = [] for (const letter of text) { let currentSelector = document.createElement('span') - + let letterIdentifier = identifiers.get(letter) const lastItem = identifierClosingStack.length const closingToLookFor = identifierClosingStack[lastItem-1] + const keepChar = Number(letterIdentifier?.remove) === 0 + if (letter === closingToLookFor) { identifierClosingStack.pop() + if (keepChar) { + currentSelector.innerHTML = letter + if (colorStack.length === 1){ + currentSelector.className = `text_${defaultColor}` + } else { + const r = colorStack[colorStack.length-1][0] + const g = colorStack[colorStack.length-1][1] + const b = colorStack[colorStack.length-1][2] + const currentColor = `color: rgb(${r},${g},${b});` + currentSelector.setAttribute('style', currentColor) + } + output.push(currentSelector) + } colorStack.pop() + continue; } else if (startIdentifiers.has(letter)) { - identifierClosingStack.push(identifiers.get(letter)) + identifierClosingStack.push(identifiers.get(letter).end) const colors = colorIdentifier[letter].split(',') const r = colors[0] const g = colors[1] const b = colors[2] colorStack.push([r,g,b]) + if (keepChar) { + currentSelector.innerHTML = letter + } + } else { currentSelector.innerHTML = letter } - const r = colorStack[colorStack.length-1][0] - const g = colorStack[colorStack.length-1][1] - const b = colorStack[colorStack.length-1][2] - const currentColor = `color: rgb(${r},${g},${b});` - currentSelector.setAttribute('style', currentColor) + if (colorStack.length === 1) { + currentSelector.className = `test_${defaultColor}` + } else { + const r = colorStack[colorStack.length-1][0] + const g = colorStack[colorStack.length-1][1] + const b = colorStack[colorStack.length-1][2] + const currentColor = `color: rgb(${r},${g},${b});` + currentSelector.setAttribute('style', currentColor) + } output.push(currentSelector) } return output -- cgit From a5d85f1e7cdbf144e2793da3bb5183eff9c6a7bc Mon Sep 17 00:00:00 2001 From: "caleb.mabry.15@cnu.edu" Date: Tue, 22 Mar 2022 00:16:34 -0400 Subject: converted to typescript --- webAO/utils/aoml.js | 128 -------------------------------------------------- webAO/utils/aoml.ts | 133 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+), 128 deletions(-) delete mode 100644 webAO/utils/aoml.js create mode 100644 webAO/utils/aoml.ts (limited to 'webAO') diff --git a/webAO/utils/aoml.js b/webAO/utils/aoml.js deleted file mode 100644 index 9506fbf..0000000 --- a/webAO/utils/aoml.js +++ /dev/null @@ -1,128 +0,0 @@ -import request from "../services/request" - - -const aomlParser = (text) => { - let parsed = {} - let currentHeader = '' - for (const line of text.split(/\r?\n/)) { - if (line === '') { - currentHeader = '' - continue; - } - const content = line.split(' = ') - const contentName = content[0] - const contentValue = content[1] - if (currentHeader === '') { - currentHeader = contentName - parsed[currentHeader] = { - color: contentValue - } - } else { - const contentKey = contentName.split('_')[1] - parsed[currentHeader][contentKey] = contentValue - } - } - return parsed -} - - - - -const mlConfig = (AO_HOST) => { - const defaultUrl = `${AO_HOST}themes/default/chat_config.ini` - let aomlParsed = {} - - request(defaultUrl).then((data) => { - aomlParsed = aomlParser(data) - } - ); - - const createIdentifiers = () => { - const identifiers = new Map() - for (const [ruleName, value] of Object.entries(aomlParsed)) { - if (identifiers.has(value.start)) { - throw new Error() - } - else if (value.start && value.end) { - identifiers.set(value.start, value) - identifiers.set(value.end, value) - } - - - } - return identifiers - } - const colorIdentifiers = () => { - let colorIdentifier = {} - for (const [ruleName, value] of Object.entries(aomlParsed)) { - colorIdentifier[value.start] = value.color - } - return colorIdentifier - } - const applyMarkdown = (text, defaultColor) => { - const identifiers = createIdentifiers(aomlParsed) - const startIdentifiers = new Set(identifiers.keys()) - const colorIdentifier = colorIdentifiers() - const identifierClosingStack = [] - - const colorStack = [[255, 255, 255]] - // each value in output will be an html element - let output = [] - for (const letter of text) { - let currentSelector = document.createElement('span') - let letterIdentifier = identifiers.get(letter) - const lastItem = identifierClosingStack.length - const closingToLookFor = identifierClosingStack[lastItem-1] - const keepChar = Number(letterIdentifier?.remove) === 0 - - if (letter === closingToLookFor) { - identifierClosingStack.pop() - if (keepChar) { - currentSelector.innerHTML = letter - if (colorStack.length === 1){ - currentSelector.className = `text_${defaultColor}` - } else { - const r = colorStack[colorStack.length-1][0] - const g = colorStack[colorStack.length-1][1] - const b = colorStack[colorStack.length-1][2] - const currentColor = `color: rgb(${r},${g},${b});` - currentSelector.setAttribute('style', currentColor) - } - output.push(currentSelector) - } - colorStack.pop() - continue; - } - else if (startIdentifiers.has(letter)) { - identifierClosingStack.push(identifiers.get(letter).end) - const colors = colorIdentifier[letter].split(',') - const r = colors[0] - const g = colors[1] - const b = colors[2] - colorStack.push([r,g,b]) - if (keepChar) { - currentSelector.innerHTML = letter - } - - } else { - currentSelector.innerHTML = letter - } - if (colorStack.length === 1) { - currentSelector.className = `test_${defaultColor}` - } else { - const r = colorStack[colorStack.length-1][0] - const g = colorStack[colorStack.length-1][1] - const b = colorStack[colorStack.length-1][2] - const currentColor = `color: rgb(${r},${g},${b});` - currentSelector.setAttribute('style', currentColor) - } - output.push(currentSelector) - } - return output - } - return { - applyMarkdown - } -} - -export default mlConfig \ No newline at end of file diff --git a/webAO/utils/aoml.ts b/webAO/utils/aoml.ts new file mode 100644 index 0000000..898d8fb --- /dev/null +++ b/webAO/utils/aoml.ts @@ -0,0 +1,133 @@ +import request from "../services/request" + +interface Aoml { + name: string; + start: string; + end: string; + remove: number; + talking: number; + color: string; +} +const aomlParser = (text: string) => { + let parsed: {[key: string]: Aoml}= {} + let currentHeader = '' + for (const line of text.split(/\r?\n/)) { + if (line === '') { + currentHeader = '' + continue; + } + const content = line.split(' = ') + const contentName = content[0] + const contentValue = content[1] + if (currentHeader === '') { + currentHeader = contentName + parsed[currentHeader] = { + color: contentValue + } as Aoml + } else { + const contentKey = contentName.split('_')[1] + parsed[currentHeader][contentKey] = contentValue + } + } + return parsed +} + + + + +const mlConfig = (AO_HOST) => { + const defaultUrl = `${AO_HOST}themes/default/chat_config.ini` + let aomlParsed: {[key: string]: Aoml} = {} + + request(defaultUrl).then((data) => { + aomlParsed = aomlParser(data) + } + ); + + const createIdentifiers = () => { + const identifiers = new Map() + for (const [ruleName, value] of Object.entries(aomlParsed)) { + if (identifiers.has(value.start)) { + throw new Error() + } + else if (value.start && value.end) { + identifiers.set(value.start, value) + identifiers.set(value.end, value) + } + + + } + return identifiers + } + const createStartIdentifiers = () => { + const startingIdentifiers = new Set() + for (const [ruleName, value] of Object.entries(aomlParsed)) { + if (value?.start && value?.end) { + startingIdentifiers.add(value.start) + } + } + return startingIdentifiers + } + + const applyMarkdown = (text: string, defaultColor: string) => { + const identifiers = createIdentifiers() + const startIdentifiers = createStartIdentifiers() + const closingStack = [] + const colorStack = [] + // each value in output will be an html element + let output: HTMLSpanElement[] = [] + for (const letter of text) { + let currentSelector = document.createElement('span') + let currentIdentifier = identifiers.get(letter) + const currentClosingLetter = closingStack[closingStack.length-1] + const keepChar = Number(currentIdentifier?.remove) === 0 + console.log(startIdentifiers) + if (startIdentifiers.has(letter)) { + const color = identifiers.get(letter).color.split(',') + const r = color[0] + const g = color[1] + const b = color[2] + colorStack.push([r,g,b]) + closingStack.push(currentIdentifier.end) + const currentColor = `color: rgb(${r},${g},${b});` + currentSelector.setAttribute('style', currentColor) + if (keepChar) { + currentSelector.innerHTML = letter + } + } else if (currentClosingLetter === letter) { + if (colorStack.length === 0) { + currentSelector.className = `test_${defaultColor}` + } else { + const r = colorStack[colorStack.length-1][0] + const g = colorStack[colorStack.length-1][1] + const b = colorStack[colorStack.length-1][2] + const currentColor = `color: rgb(${r},${g},${b});` + currentSelector.setAttribute('style', currentColor) + } + closingStack.pop() + colorStack.pop() + if (keepChar) { + currentSelector.innerHTML = letter + } + } else { + currentSelector.innerHTML = letter + if (colorStack.length === 0) { + currentSelector.className = `text_${defaultColor}` + } else { + const r = colorStack[colorStack.length-1][0] + const g = colorStack[colorStack.length-1][1] + const b = colorStack[colorStack.length-1][2] + const currentColor = `color: rgb(${r},${g},${b});` + currentSelector.setAttribute('style', currentColor) + } + } + output.push(currentSelector) + } + return output + } + return { + applyMarkdown + } +} + +export default mlConfig \ No newline at end of file -- cgit From 4d09a4a7105de76189fae41e86c9186ba7ff76fd Mon Sep 17 00:00:00 2001 From: "caleb.mabry.15@cnu.edu" Date: Tue, 22 Mar 2022 00:16:52 -0400 Subject: ez error handling --- webAO/client.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'webAO') diff --git a/webAO/client.js b/webAO/client.js index 87db272..44cc8bd 100644 --- a/webAO/client.js +++ b/webAO/client.js @@ -2244,7 +2244,10 @@ class Viewport { this.currentBlipChannel %= this.blipChannels.length; } this.textnow = this.chatmsg.content.substring(0, this.textnow.length + 1); - chatBoxInner.appendChild(this.chatmsg.parsed[this.textnow.length - 1]); + const characterElement = this.chatmsg.parsed[this.textnow.length - 1] + if (characterElement) { + chatBoxInner.appendChild(this.chatmsg.parsed[this.textnow.length - 1]); + } // scroll to bottom chatBox.scrollTop = chatBox.scrollHeight; -- cgit From 7c88c0bcca6e47cca4e2632df8ced778fa38c341 Mon Sep 17 00:00:00 2001 From: "caleb.mabry.15@cnu.edu" Date: Wed, 23 Mar 2022 00:33:18 -0400 Subject: Final commit --- webAO/client.js | 2 +- webAO/utils/__tests__/aoml.test.ts | 113 +++++++++++++++++++++++++++++++++++++ webAO/utils/aoml.ts | 51 ++++++----------- 3 files changed, 132 insertions(+), 34 deletions(-) create mode 100644 webAO/utils/__tests__/aoml.test.ts (limited to 'webAO') diff --git a/webAO/client.js b/webAO/client.js index 44cc8bd..eed1293 100644 --- a/webAO/client.js +++ b/webAO/client.js @@ -2092,7 +2092,7 @@ class Viewport { if (soundChecks.some((check) => this.chatmsg.sound === check)) { this.chatmsg.sound = this.chatmsg.effects[2]; } - this.chatmsg.parsed = attorneyMarkdown.applyMarkdown(chatmsg.content, this.colors[this.chatmsg.color]) + this.chatmsg.parsed = await attorneyMarkdown.applyMarkdown(chatmsg.content, this.colors[this.chatmsg.color]) this.tick(); } diff --git a/webAO/utils/__tests__/aoml.test.ts b/webAO/utils/__tests__/aoml.test.ts new file mode 100644 index 0000000..fa8ade4 --- /dev/null +++ b/webAO/utils/__tests__/aoml.test.ts @@ -0,0 +1,113 @@ +import request from '../../services/request' +import mlConfig from '../aoml'; + +jest.mock('../../services/request') +const networkRequest = ` +c0 = 247, 247, 247 +c0_name = White +c0_talking = 1 + +c2 = 247, 0, 57 +c2_name = Red +c2_start = ~ +c2_end = ~ +c2_remove = 1 +c2_talking = 1 + +c4 = 107, 198, 247 +c4_name = Blue +c4_start = ( +c4_end = ) +c4_remove = 0 +c4_talking = 0 + +c5 = 107, 198, 247 +c5_name = Blue +c5_start = [ +c5_end = ] +c5_remove = 1 +c5_talking = 0 + +c6 = 107, 198, 247 +c6_name = Blue +c6_start = | +c6_end = | +c6_remove = 0 +c6_talking = 0 +` + +const mockRequest = request as jest.MockedFunction; +mockRequest.mockReturnValue(Promise.resolve(networkRequest)) + + describe('mlConfig', () => { + beforeEach(() => { + // Clear all instances and calls to constructor and all methods: + mockRequest.mockClear(); + + }); + + it('Should make a network request', () => { + mlConfig('localhost') + expect(mockRequest).toHaveBeenCalledTimes(1); + }); + }) + describe('applyMarkdown', () => { + const config = mlConfig('localhost') + + beforeEach(() => { + // Clear all instances and calls to constructor and all methods: + mockRequest.mockClear(); + + }); + + it('Should create an array of spans containing letters', async () => { + const word = `hello` + const actual = await config.applyMarkdown(`hello`, `blue`) + let index = 0 + for (const element of actual) { + expect(element.innerHTML).toBe(word[index]) + index++ + } + }) + it('Should add colors based on settings', async () => { + const config = mlConfig('localhost') + const actual = await config.applyMarkdown(`(heya)`, `blue`) + expect(actual[0].getAttribute('style')).toBe('color: rgb(107, 198, 247);') + }) + it('Should keep a letter if remove = 0', async () => { + const config = mlConfig('localhost') + + const actual = await config.applyMarkdown(`(What())Hey!`, `white`) + const expected = `(` + expect(actual[5].innerHTML).toBe(expected) + }) + it('Should remove a letter if remove = 1', async () => { + const config = mlConfig('localhost') + + const actual = await config.applyMarkdown(`~What~()Hey!`, `white`) + const expected = `` + expect(actual[0].innerHTML).toBe(expected) + }) + it('Should remove a letter if remove = 1', async () => { + const config = mlConfig('localhost') + + const actual = await config.applyMarkdown(`~What~()Hey!`, `white`) + const expected = `` + expect(actual[0].innerHTML).toBe(expected) + }) + it('Should keep a closing letter if remove = 0', async () => { + const config = mlConfig('localhost') + + const actual = await config.applyMarkdown(`~NO[]~!`, `white`) + const expected = `]` + expect(actual[4].innerHTML).toBe(expected) + }) + it('Should remove a closing letter if remove = 1', async () => { + const config = mlConfig('localhost') + const actual = await config.applyMarkdown(`~NO||~!`, `white`) + const expected = `` + expect(actual[5].innerHTML).toBe(expected) + }) + + }) + diff --git a/webAO/utils/aoml.ts b/webAO/utils/aoml.ts index 898d8fb..fb26db8 100644 --- a/webAO/utils/aoml.ts +++ b/webAO/utils/aoml.ts @@ -32,46 +32,34 @@ const aomlParser = (text: string) => { return parsed } - - - const mlConfig = (AO_HOST) => { const defaultUrl = `${AO_HOST}themes/default/chat_config.ini` - let aomlParsed: {[key: string]: Aoml} = {} + let aomlParsed: Promise<{[key: string]: Aoml}> = request(defaultUrl).then((data) => aomlParser(data)); - request(defaultUrl).then((data) => { - aomlParsed = aomlParser(data) - } - ); + - const createIdentifiers = () => { + const createIdentifiers = async () => { const identifiers = new Map() - for (const [ruleName, value] of Object.entries(aomlParsed)) { - if (identifiers.has(value.start)) { - throw new Error() - } - else if (value.start && value.end) { + for (const [ruleName, value] of Object.entries(await aomlParsed)) { + if (value.start && value.end) { identifiers.set(value.start, value) identifiers.set(value.end, value) - } - - + } } return identifiers } - const createStartIdentifiers = () => { + const createStartIdentifiers = async () => { const startingIdentifiers = new Set() - for (const [ruleName, value] of Object.entries(aomlParsed)) { + for (const [ruleName, value] of Object.entries(await aomlParsed)) { if (value?.start && value?.end) { startingIdentifiers.add(value.start) } } return startingIdentifiers } - - const applyMarkdown = (text: string, defaultColor: string) => { - const identifiers = createIdentifiers() - const startIdentifiers = createStartIdentifiers() + const applyMarkdown = async (text: string, defaultColor: string) => { + const identifiers = await createIdentifiers() + const startIdentifiers = await createStartIdentifiers() const closingStack = [] const colorStack = [] // each value in output will be an html element @@ -81,7 +69,8 @@ const mlConfig = (AO_HOST) => { let currentIdentifier = identifiers.get(letter) const currentClosingLetter = closingStack[closingStack.length-1] const keepChar = Number(currentIdentifier?.remove) === 0 - console.log(startIdentifiers) + console.log(currentClosingLetter, letter, keepChar) + if (startIdentifiers.has(letter)) { const color = identifiers.get(letter).color.split(',') const r = color[0] @@ -95,15 +84,11 @@ const mlConfig = (AO_HOST) => { currentSelector.innerHTML = letter } } else if (currentClosingLetter === letter) { - if (colorStack.length === 0) { - currentSelector.className = `test_${defaultColor}` - } else { - const r = colorStack[colorStack.length-1][0] - const g = colorStack[colorStack.length-1][1] - const b = colorStack[colorStack.length-1][2] - const currentColor = `color: rgb(${r},${g},${b});` - currentSelector.setAttribute('style', currentColor) - } + const r = colorStack[colorStack.length-1][0] + const g = colorStack[colorStack.length-1][1] + const b = colorStack[colorStack.length-1][2] + const currentColor = `color: rgb(${r},${g},${b});` + currentSelector.setAttribute('style', currentColor) closingStack.pop() colorStack.pop() if (keepChar) { -- cgit From efe16e1c1e7d4b0ea13c04b816d046ad21eeadb0 Mon Sep 17 00:00:00 2001 From: "caleb.mabry.15@cnu.edu" Date: Wed, 23 Mar 2022 00:38:26 -0400 Subject: Artifacts from testing --- webAO/utils/__tests__/aoml.test.ts | 2 +- webAO/utils/aoml.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'webAO') diff --git a/webAO/utils/__tests__/aoml.test.ts b/webAO/utils/__tests__/aoml.test.ts index fa8ade4..90967d7 100644 --- a/webAO/utils/__tests__/aoml.test.ts +++ b/webAO/utils/__tests__/aoml.test.ts @@ -99,7 +99,7 @@ mockRequest.mockReturnValue(Promise.resolve(networkRequest)) const config = mlConfig('localhost') const actual = await config.applyMarkdown(`~NO[]~!`, `white`) - const expected = `]` + const expected = `` expect(actual[4].innerHTML).toBe(expected) }) it('Should remove a closing letter if remove = 1', async () => { diff --git a/webAO/utils/aoml.ts b/webAO/utils/aoml.ts index fb26db8..da66d0c 100644 --- a/webAO/utils/aoml.ts +++ b/webAO/utils/aoml.ts @@ -69,7 +69,6 @@ const mlConfig = (AO_HOST) => { let currentIdentifier = identifiers.get(letter) const currentClosingLetter = closingStack[closingStack.length-1] const keepChar = Number(currentIdentifier?.remove) === 0 - console.log(currentClosingLetter, letter, keepChar) if (startIdentifiers.has(letter)) { const color = identifiers.get(letter).color.split(',') -- cgit From 313d3db36e5252cfa06e9a48ef681385730bb7a4 Mon Sep 17 00:00:00 2001 From: Caleb Mabry <36182383+caleb-mabry@users.noreply.github.com> Date: Wed, 23 Mar 2022 15:27:14 -0400 Subject: Update webAO/components/blip.js Co-authored-by: stonedDiscord --- webAO/components/blip.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'webAO') diff --git a/webAO/components/blip.js b/webAO/components/blip.js index 409b907..eacbeaf 100644 --- a/webAO/components/blip.js +++ b/webAO/components/blip.js @@ -13,5 +13,5 @@ const createBlip = (amountOfBlips) => { document.body.appendChild(audio) } } -createBlip(3) +createBlip(6) export default createBlip \ No newline at end of file -- cgit From 415eff55a9db8da9077e0e1dd5d3c3672ff66e8a Mon Sep 17 00:00:00 2001 From: stonedDiscord Date: Wed, 23 Mar 2022 21:45:57 +0100 Subject: remove unused settings --- webAO/client.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'webAO') diff --git a/webAO/client.js b/webAO/client.js index dfba169..6a2947c 100644 --- a/webAO/client.js +++ b/webAO/client.js @@ -9,7 +9,7 @@ import { EventEmitter } from 'events'; import fileExistsSync from './utils/fileExistsSync'; import { escapeChat, encodeChat, prepChat, safeTags, -} from './encoding.js'; +} from './encoding'; import mlConfig from './utils/aoml'; // Load some defaults for the background and evidence dropdowns import vanilla_character_arr from './constants/characters.js'; @@ -2957,7 +2957,7 @@ window.updateActionCommands = updateActionCommands; */ export function changeBackgroundOOC() { const selectedBG = document.getElementById('bg_select'); - const changeBGCommand = document.getElementById('bg_command').value; + const changeBGCommand = "bg $1"; const bgFilename = document.getElementById('bg_filename'); let filename = ''; @@ -2987,7 +2987,7 @@ window.changeRoleOOC = changeRoleOOC; * Random character via OOC. */ export function randomCharacterOOC() { - client.sendOOC(`/${document.getElementById('randomchar_command').value}`); + client.sendOOC(`/randomchar`); } window.randomCharacterOOC = randomCharacterOOC; -- cgit From e93fa6110bfe510216b558e1b256fac4c267b1a2 Mon Sep 17 00:00:00 2001 From: stonedDiscord Date: Wed, 23 Mar 2022 21:46:28 +0100 Subject: sort of convert encoding to typescript --- webAO/encoding.js | 85 ------------------------------------------------------- webAO/encoding.ts | 64 +++++++++++++++++++++++++++++++++++++++++ webAO/master.ts | 2 +- 3 files changed, 65 insertions(+), 86 deletions(-) delete mode 100644 webAO/encoding.js create mode 100644 webAO/encoding.ts (limited to 'webAO') diff --git a/webAO/encoding.js b/webAO/encoding.js deleted file mode 100644 index e6cc3ae..0000000 --- a/webAO/encoding.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * Escapes a string to AO1 escape codes. - * @param {string} estring the string to be escaped - */ -export function escapeChat(estring) { - return estring - .replace(/#/g, '') - .replace(/&/g, '') - .replace(/%/g, '') - .replace(/\$/g, ''); -} - -/** - * Unescapes a string to AO1 escape codes. - * @param {string} estring the string to be unescaped - */ -export function unescapeChat(estring) { - return estring - .replace(//g, '#') - .replace(//g, '&') - .replace(//g, '%') - .replace(//g, '$'); -} - -/** - * Escapes a string to be HTML-safe. - * - * XXX: This is unnecessary if we use `createTextNode` instead! - * @param {string} unsafe an unsanitized string - */ -export function safeTags(unsafe) { - if (unsafe) { - return unsafe - .replace(/>/g, '>') - .replace(/ `\\u${(`000${ch.charCodeAt().toString(16)}`).slice(-4)}`); - } if (selectedEncoding === 'utf16') { - // Source: https://developers.google.com/web/updates/2012/06/How-to-convert-ArrayBuffer-to-and-from-String - const buffer = new ArrayBuffer(estring.length * 2); - const result = new Uint16Array(buffer); - for (let i = 0, strLen = estring.length; i < strLen; i++) { - result[i] = estring.charCodeAt(i); - } - return String(result); - } - return estring; -} - -/** - * Decodes text on client side. - * @param {string} estring the string to be decoded - */ -export function decodeChat(estring) { - const selectedDecoding = document.getElementById('client_decoding').value; - if (selectedDecoding === 'unicode') { - // Source: https://stackoverflow.com/questions/7885096/how-do-i-decode-a-string-with-escaped-unicode - return estring.replace(/\\u([\d\w]{1,})/gi, (match, group) => String.fromCharCode(parseInt(group, 16))); - } if (selectedDecoding === 'utf16') { - // Source: https://developers.google.com/web/updates/2012/06/How-to-convert-ArrayBuffer-to-and-from-String - return String.fromCharCode.apply(null, new Uint16Array(estring.split(','))); - } - return estring; -} - -/** - * XXX: a nasty hack made by gameboyprinter. - * @param {string} msg chat message to prepare for display - */ -export function prepChat(msg) { - // TODO: make this less awful - return unescapeChat(decodeChat(msg)); -} diff --git a/webAO/encoding.ts b/webAO/encoding.ts new file mode 100644 index 0000000..930886f --- /dev/null +++ b/webAO/encoding.ts @@ -0,0 +1,64 @@ +/** + * Escapes a string to AO1 escape codes. + * @param {string} estring the string to be escaped + */ +export function escapeChat(estring: string) { + return estring + .replace(/#/g, '') + .replace(/&/g, '') + .replace(/%/g, '') + .replace(/\$/g, ''); +} + +/** + * Unescapes a string to AO1 escape codes. + * @param {string} estring the string to be unescaped + */ +export function unescapeChat(estring: string) { + return estring + .replace(//g, '#') + .replace(//g, '&') + .replace(//g, '%') + .replace(//g, '$'); +} + +/** + * Escapes a string to be HTML-safe. + * + * XXX: This is unnecessary if we use `createTextNode` instead! + * @param {string} unsafe an unsanitized string + */ +export function safeTags(unsafe: string) { + if (unsafe) { + return unsafe + .replace(/>/g, '>') + .replace(/ String.fromCharCode(parseInt(group, 16))); +} + +/** + * XXX: a nasty hack made by gameboyprinter. + * @param {string} msg chat message to prepare for display + */ +export function prepChat(msg: string) { + // TODO: make this less awful + return unescapeChat(decodeChat(msg)); +} diff --git a/webAO/master.ts b/webAO/master.ts index 8fd8779..8c850c2 100644 --- a/webAO/master.ts +++ b/webAO/master.ts @@ -1,6 +1,6 @@ import FingerprintJS from '@fingerprintjs/fingerprintjs'; -import { unescapeChat, safeTags } from './encoding.js'; +import { unescapeChat, safeTags } from './encoding'; declare global { interface Window { -- cgit From 810c1d22b1e52c1662bb3cac518ebfa14ea2d59f Mon Sep 17 00:00:00 2001 From: stonedDiscord Date: Wed, 23 Mar 2022 21:52:05 +0100 Subject: type the encoding functions --- webAO/encoding.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'webAO') diff --git a/webAO/encoding.ts b/webAO/encoding.ts index 930886f..1018144 100644 --- a/webAO/encoding.ts +++ b/webAO/encoding.ts @@ -2,7 +2,7 @@ * Escapes a string to AO1 escape codes. * @param {string} estring the string to be escaped */ -export function escapeChat(estring: string) { +export function escapeChat(estring: string): string { return estring .replace(/#/g, '') .replace(/&/g, '') @@ -14,7 +14,7 @@ export function escapeChat(estring: string) { * Unescapes a string to AO1 escape codes. * @param {string} estring the string to be unescaped */ -export function unescapeChat(estring: string) { +export function unescapeChat(estring: string): string { return estring .replace(//g, '#') .replace(//g, '&') @@ -28,7 +28,7 @@ export function unescapeChat(estring: string) { * XXX: This is unnecessary if we use `createTextNode` instead! * @param {string} unsafe an unsanitized string */ -export function safeTags(unsafe: string) { +export function safeTags(unsafe: string): string { if (unsafe) { return unsafe .replace(/>/g, '>') @@ -41,7 +41,7 @@ export function safeTags(unsafe: string) { * Encode text on client side. * @param {string} estring the string to be encoded */ -export function encodeChat(estring: string) { +export function encodeChat(estring: string): string { return estring; } @@ -49,7 +49,7 @@ export function encodeChat(estring: string) { * Decodes text on client side. * @param {string} estring the string to be decoded */ -export function decodeChat(estring: string) { +export function decodeChat(estring: string): string { // Source: https://stackoverflow.com/questions/7885096/how-do-i-decode-a-string-with-escaped-unicode return estring.replace(/\\u([\d\w]{1,})/gi, (match, group) => String.fromCharCode(parseInt(group, 16))); } @@ -58,7 +58,7 @@ export function decodeChat(estring: string) { * XXX: a nasty hack made by gameboyprinter. * @param {string} msg chat message to prepare for display */ -export function prepChat(msg: string) { +export function prepChat(msg: string): string { // TODO: make this less awful return unescapeChat(decodeChat(msg)); } -- cgit From 63410fd71e31e0de21aed41016983146405e2e9d Mon Sep 17 00:00:00 2001 From: stonedDiscord Date: Wed, 23 Mar 2022 21:52:13 +0100 Subject: ao host is a string --- webAO/utils/aoml.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'webAO') diff --git a/webAO/utils/aoml.ts b/webAO/utils/aoml.ts index da66d0c..154274d 100644 --- a/webAO/utils/aoml.ts +++ b/webAO/utils/aoml.ts @@ -32,7 +32,7 @@ const aomlParser = (text: string) => { return parsed } -const mlConfig = (AO_HOST) => { +const mlConfig = (AO_HOST: string) => { const defaultUrl = `${AO_HOST}themes/default/chat_config.ini` let aomlParsed: Promise<{[key: string]: Aoml}> = request(defaultUrl).then((data) => aomlParser(data)); -- cgit From 93212647c7775358ecd7366423d706a5efae95dc Mon Sep 17 00:00:00 2001 From: stonedDiscord Date: Wed, 23 Mar 2022 22:04:45 +0100 Subject: fix strict errors in master.ts --- webAO/master.ts | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'webAO') diff --git a/webAO/master.ts b/webAO/master.ts index 8c850c2..a48f4e9 100644 --- a/webAO/master.ts +++ b/webAO/master.ts @@ -67,10 +67,10 @@ export function setServ(ID: number) { window.setServ = setServ; function checkOnline(serverID: number, coIP: string) { - let oserv; + let serverConnection: WebSocket; if (serverID !== -2) { try { - oserv = new WebSocket(`ws://${coIP}`); + serverConnection = new WebSocket(`ws://${coIP}`); } catch (SecurityError) { document.getElementById(`server${serverID}`).className = 'unavailable'; return; @@ -78,24 +78,24 @@ function checkOnline(serverID: number, coIP: string) { } // define what the callbacks do - function onCOOpen(_e) { + function onCOOpen() { document.getElementById(`server${serverID}`).className = 'available'; - oserv.send(`HI#${hdid}#%`); - oserv.send('ID#webAO#webAO#%'); + serverConnection.send(`HI#${hdid}#%`); + serverConnection.send('ID#webAO#webAO#%'); } - function onCOMessage(e) { + function onCOMessage(e: MessageEvent) { const comsg = e.data; const coheader = comsg.split('#', 2)[0]; const coarguments = comsg.split('#').slice(1); if (coheader === 'PN') { servers[serverID].online = `Online: ${Number(coarguments[0])}/${Number(coarguments[1])}`; - oserv.close(); + serverConnection.close(); return; } if (coheader === 'BD') { servers[serverID].online = 'Banned'; servers[serverID].description = coarguments[0]; - oserv.close(); + serverConnection.close(); return; } if (serverID === selectedServer) { @@ -104,15 +104,15 @@ function checkOnline(serverID: number, coIP: string) { } // assign the callbacks - oserv.onopen = function (evt) { - onCOOpen(evt); + serverConnection.onopen = function () { + onCOOpen(); }; - oserv.onmessage = function (evt) { + serverConnection.onmessage = function (evt: MessageEvent) { onCOMessage(evt); }; - oserv.onerror = function (_evt) { + serverConnection.onerror = function (_evt: Event) { document.getElementById(`server${serverID}`).className = 'unavailable'; }; } -- cgit