mirror of
https://github.com/thelounge/thelounge.git
synced 2024-06-01 13:22:29 +02:00
Chat is rendering
This commit is contained in:
parent
52c13f49c1
commit
f189e9766c
|
@ -14,7 +14,10 @@
|
||||||
id="context-menu"
|
id="context-menu"
|
||||||
ref="contextMenu"
|
ref="contextMenu"
|
||||||
role="menu"
|
role="menu"
|
||||||
:style="style"
|
:style="{
|
||||||
|
top: style.top + 'px',
|
||||||
|
left: style.left + 'px',
|
||||||
|
}"
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
@mouseleave="activeItem = -1"
|
@mouseleave="activeItem = -1"
|
||||||
@keydown.enter.prevent="clickActiveItem"
|
@keydown.enter.prevent="clickActiveItem"
|
||||||
|
|
|
@ -24,11 +24,6 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
focused: Boolean,
|
focused: Boolean,
|
||||||
},
|
},
|
||||||
// methods: {
|
|
||||||
// forceUpdate(){
|
|
||||||
// this.$forceUpdate()
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const localeDate = computed(() => dayjs(props.message.time).format("D MMMM YYYY"));
|
const localeDate = computed(() => dayjs(props.message.time).format("D MMMM YYYY"));
|
||||||
|
|
||||||
|
|
|
@ -66,6 +66,7 @@ import Message from "./Message.vue";
|
||||||
import MessageCondensed from "./MessageCondensed.vue";
|
import MessageCondensed from "./MessageCondensed.vue";
|
||||||
import DateMarker from "./DateMarker.vue";
|
import DateMarker from "./DateMarker.vue";
|
||||||
import {
|
import {
|
||||||
|
defineExpose,
|
||||||
computed,
|
computed,
|
||||||
defineComponent,
|
defineComponent,
|
||||||
nextTick,
|
nextTick,
|
||||||
|
@ -247,7 +248,7 @@ export default defineComponent({
|
||||||
message: Msg | ClientMessage | CondensedMessageContainer,
|
message: Msg | ClientMessage | CondensedMessageContainer,
|
||||||
id: number
|
id: number
|
||||||
) => {
|
) => {
|
||||||
const previousMessage = condensedMessages[id - 1];
|
const previousMessage = condensedMessages.value[id - 1];
|
||||||
|
|
||||||
if (!previousMessage) {
|
if (!previousMessage) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -431,6 +432,7 @@ export default defineComponent({
|
||||||
shouldDisplayUnreadMarker,
|
shouldDisplayUnreadMarker,
|
||||||
keepScrollPosition,
|
keepScrollPosition,
|
||||||
isPreviousSource,
|
isPreviousSource,
|
||||||
|
jumpToBottom,
|
||||||
onLinkPreviewToggle,
|
onLinkPreviewToggle,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {defineComponent, PropType} from "vue";
|
import {computed, defineComponent, PropType} from "vue";
|
||||||
import collapseNetwork from "../js/helpers/collapseNetwork";
|
import collapseNetwork from "../js/helpers/collapseNetwork";
|
||||||
import roundBadgeNumber from "../js/helpers/roundBadgeNumber";
|
import roundBadgeNumber from "../js/helpers/roundBadgeNumber";
|
||||||
import ChannelWrapper from "./ChannelWrapper.vue";
|
import ChannelWrapper from "./ChannelWrapper.vue";
|
||||||
|
@ -68,24 +68,34 @@ export default defineComponent({
|
||||||
isFiltering: Boolean,
|
isFiltering: Boolean,
|
||||||
},
|
},
|
||||||
emits: ["toggle-join-channel"],
|
emits: ["toggle-join-channel"],
|
||||||
computed: {
|
setup(props) {
|
||||||
channel(): ClientChan {
|
const channel = computed(() => {
|
||||||
return this.network.channels[0];
|
return props.network.channels[0];
|
||||||
},
|
});
|
||||||
joinChannelLabel(): string {
|
|
||||||
return this.isJoinChannelShown ? "Cancel" : "Join a channel…";
|
const joinChannelLabel = computed(() => {
|
||||||
},
|
return props.isJoinChannelShown ? "Cancel" : "Join a channel…";
|
||||||
unreadCount(): string {
|
});
|
||||||
return roundBadgeNumber(this.channel.unread);
|
|
||||||
},
|
const unreadCount = computed(() => {
|
||||||
},
|
return roundBadgeNumber(channel.value.unread);
|
||||||
methods: {
|
});
|
||||||
onCollapseClick(): void {
|
|
||||||
collapseNetwork(this.network, !this.network.isCollapsed);
|
const onCollapseClick = () => {
|
||||||
},
|
collapseNetwork(props.network, !props.network.isCollapsed);
|
||||||
getExpandLabel(network: ClientNetwork): string {
|
};
|
||||||
|
|
||||||
|
const getExpandLabel = (network: ClientNetwork) => {
|
||||||
return network.isCollapsed ? "Expand" : "Collapse";
|
return network.isCollapsed ? "Expand" : "Collapse";
|
||||||
},
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
channel,
|
||||||
|
joinChannelLabel,
|
||||||
|
unreadCount,
|
||||||
|
onCollapseClick,
|
||||||
|
getExpandLabel,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import ParsedMessage from "../ParsedMessage.vue";
|
import ParsedMessage from "../ParsedMessage.vue";
|
||||||
import localetime from "../../js/helpers/localetime";
|
import localeTime from "../../js/helpers/localetime";
|
||||||
import {defineComponent, PropType} from "vue";
|
import {defineComponent, PropType} from "vue";
|
||||||
import type {ClientNetwork, ClientChan} from "../../js/types";
|
import type {ClientNetwork, ClientChan} from "../../js/types";
|
||||||
|
|
||||||
|
@ -32,10 +32,14 @@ export default defineComponent({
|
||||||
network: {type: Object as PropType<ClientNetwork>, required: true},
|
network: {type: Object as PropType<ClientNetwork>, required: true},
|
||||||
channel: {type: Object as PropType<ClientChan>, required: true},
|
channel: {type: Object as PropType<ClientChan>, required: true},
|
||||||
},
|
},
|
||||||
methods: {
|
setup() {
|
||||||
localetime(date: number | Date): string {
|
const localetime = (date: number | Date) => {
|
||||||
return localetime(date);
|
return localeTime(date);
|
||||||
},
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
localetime,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -59,48 +59,65 @@
|
||||||
import storage from "../../js/localStorage";
|
import storage from "../../js/localStorage";
|
||||||
import socket from "../../js/socket";
|
import socket from "../../js/socket";
|
||||||
import RevealPassword from "../RevealPassword.vue";
|
import RevealPassword from "../RevealPassword.vue";
|
||||||
import {defineComponent} from "vue";
|
import {defineComponent, onBeforeUnmount, onMounted, ref} from "vue";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "SignIn",
|
name: "SignIn",
|
||||||
components: {
|
components: {
|
||||||
RevealPassword,
|
RevealPassword,
|
||||||
},
|
},
|
||||||
data() {
|
setup() {
|
||||||
return {
|
const inFlight = ref(false);
|
||||||
inFlight: false,
|
const errorShown = ref(false);
|
||||||
errorShown: false,
|
|
||||||
|
const username = ref<HTMLInputElement | null>(null);
|
||||||
|
const password = ref<HTMLInputElement | null>(null);
|
||||||
|
|
||||||
|
const onAuthFailed = () => {
|
||||||
|
inFlight.value = false;
|
||||||
|
errorShown.value = true;
|
||||||
};
|
};
|
||||||
},
|
|
||||||
mounted() {
|
const onSubmit = (event: Event) => {
|
||||||
socket.on("auth:failed", this.onAuthFailed);
|
|
||||||
},
|
|
||||||
beforeUnmount() {
|
|
||||||
socket.off("auth:failed", this.onAuthFailed);
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
onAuthFailed() {
|
|
||||||
this.inFlight = false;
|
|
||||||
this.errorShown = true;
|
|
||||||
},
|
|
||||||
onSubmit(event) {
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
this.inFlight = true;
|
if (!username.value || !password.value) {
|
||||||
this.errorShown = false;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
inFlight.value = true;
|
||||||
|
errorShown.value = false;
|
||||||
|
|
||||||
const values = {
|
const values = {
|
||||||
user: this.$refs.username.value,
|
user: username.value?.value,
|
||||||
password: this.$refs.password.value,
|
password: password.value?.value,
|
||||||
};
|
};
|
||||||
|
|
||||||
storage.set("user", values.user);
|
storage.set("user", values.user);
|
||||||
|
|
||||||
socket.emit("auth:perform", values);
|
socket.emit("auth:perform", values);
|
||||||
},
|
};
|
||||||
getStoredUser() {
|
|
||||||
|
const getStoredUser = () => {
|
||||||
return storage.get("user");
|
return storage.get("user");
|
||||||
},
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
socket.on("auth:failed", onAuthFailed);
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
socket.off("auth:failed", onAuthFailed);
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
inFlight,
|
||||||
|
errorShown,
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
onSubmit,
|
||||||
|
getStoredUser,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -587,6 +587,12 @@ p {
|
||||||
|
|
||||||
/* End icons */
|
/* End icons */
|
||||||
|
|
||||||
|
|
||||||
|
#app {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
#viewport {
|
#viewport {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Generates a string from "color-1" to "color-32" based on an input string
|
// Generates a string from "color-1" to "color-32" based on an input string
|
||||||
export default (str) => {
|
export default (str: string) => {
|
||||||
let hash = 0;
|
let hash = 0;
|
||||||
|
|
||||||
for (let i = 0; i < str.length; i++) {
|
for (let i = 0; i < str.length; i++) {
|
||||||
|
@ -11,5 +11,5 @@ export default (str) => {
|
||||||
due to A being ascii 65 (100 0001)
|
due to A being ascii 65 (100 0001)
|
||||||
while a being ascii 97 (110 0001)
|
while a being ascii 97 (110 0001)
|
||||||
*/
|
*/
|
||||||
return "color-" + (1 + (hash % 32));
|
return "color-" + (1 + (hash % 32)).toString();
|
||||||
};
|
};
|
||||||
|
|
|
@ -120,7 +120,7 @@ function parse(text: string, message?: ClientMessage, network?: ClientNetwork) {
|
||||||
rel: "noopener",
|
rel: "noopener",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
fragments
|
() => fragments
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!preview) {
|
if (!preview) {
|
||||||
|
@ -159,8 +159,9 @@ function parse(text: string, message?: ClientMessage, network?: ClientNetwork) {
|
||||||
dir: "auto",
|
dir: "auto",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
linkEls
|
() => linkEls
|
||||||
);
|
);
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
} else if (textPart.channel) {
|
} else if (textPart.channel) {
|
||||||
return createElement(
|
return createElement(
|
||||||
|
@ -171,8 +172,9 @@ function parse(text: string, message?: ClientMessage, network?: ClientNetwork) {
|
||||||
channel: textPart.channel,
|
channel: textPart.channel,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
fragments
|
() => fragments
|
||||||
);
|
);
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
} else if (textPart.emoji) {
|
} else if (textPart.emoji) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -191,7 +193,7 @@ function parse(text: string, message?: ClientMessage, network?: ClientNetwork) {
|
||||||
title: title,
|
title: title,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
fragments
|
() => fragments
|
||||||
);
|
);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
} else if (textPart.nick) {
|
} else if (textPart.nick) {
|
||||||
|
@ -205,14 +207,14 @@ function parse(text: string, message?: ClientMessage, network?: ClientNetwork) {
|
||||||
nick: textPart.nick,
|
nick: textPart.nick,
|
||||||
},
|
},
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
channel: messageChannel,
|
channel: textPart.channel,
|
||||||
network,
|
network,
|
||||||
},
|
},
|
||||||
attrs: {
|
attrs: {
|
||||||
dir: "auto",
|
dir: "auto",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
fragments
|
() => fragments
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
11
client/js/types.d.ts
vendored
11
client/js/types.d.ts
vendored
|
@ -79,13 +79,10 @@ declare module "*.vue" {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module "vue" {
|
declare module "vue" {
|
||||||
interface ComponentCustomProperties {
|
// interface ComponentCustomProperties {
|
||||||
// vue-router should do this for us
|
// // TODO: Vue struggles with typing using the options API, so we should switch to composition API
|
||||||
$router: import("vue-router").Router;
|
// // $root
|
||||||
|
// }
|
||||||
// TODO: Vue struggles with typing using the options API, so we should switch to composition API
|
|
||||||
// $root
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module "vue-router" {
|
declare module "vue-router" {
|
||||||
|
|
|
@ -43,7 +43,7 @@ self.addEventListener("fetch", function (event) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
event.respondWith(networkOrCache(event));
|
return event.respondWith(networkOrCache(event));
|
||||||
});
|
});
|
||||||
|
|
||||||
async function putInCache(request, response) {
|
async function putInCache(request, response) {
|
||||||
|
|
|
@ -1,29 +1,27 @@
|
||||||
import {expect} from "chai";
|
import {expect} from "chai";
|
||||||
|
|
||||||
import {renderToString} from "@vue/server-test-utils";
|
import {mount} from "@vue/test-utils";
|
||||||
import ParsedMessageTestWrapper from "../../components/ParsedMessageTestWrapper.vue";
|
import ParsedMessage from "../../../../client/components/ParsedMessage.vue";
|
||||||
|
import {ClientMessage} from "../../../../client/js/types";
|
||||||
|
|
||||||
async function getParsedMessageContents(text: any, message: any) {
|
function getParsedMessageContents(text: string, message?: any) {
|
||||||
let contents = await renderToString(ParsedMessageTestWrapper, {
|
const wrapper = mount(ParsedMessage, {
|
||||||
propsData: {
|
props: {
|
||||||
text,
|
text,
|
||||||
message,
|
message,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// The wrapper adds a surrounding div to the message html, so we clean that out here
|
return wrapper.html();
|
||||||
contents = contents.replace(/^<div data-server-rendered="true">([^]+)<\/div>$/m, "$1");
|
|
||||||
|
|
||||||
return contents;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("IRC formatted message parser", () => {
|
describe("IRC formatted message parser", () => {
|
||||||
it("should not introduce xss", async () => {
|
it("should not introduce xss", () => {
|
||||||
const testCases = [
|
const testCases = [
|
||||||
{
|
{
|
||||||
input: "<img onerror='location.href=\"//youtube.com\"'>",
|
input: "<img onerror='location.href=\"//youtube.com\"'>",
|
||||||
expected:
|
expected:
|
||||||
'<img onerror=\'location.href="<a href="http://youtube.com" dir="auto" target="_blank" rel="noopener">//youtube.com</a>"\'>',
|
'<img onerror=\'location.href="<a href="http://youtube.com" dir="auto" target="_blank" rel="noopener">//youtube.com</a>"\'>',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: '#&">bug',
|
input: '#&">bug',
|
||||||
|
@ -32,16 +30,13 @@ describe("IRC formatted message parser", () => {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = await Promise.all(
|
const actual = testCases.map((testCase) => getParsedMessageContents(testCase.input));
|
||||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
|
||||||
testCases.map((testCase) => getParsedMessageContents(testCase.input))
|
|
||||||
);
|
|
||||||
const expected = testCases.map((testCase) => testCase.expected);
|
const expected = testCases.map((testCase) => testCase.expected);
|
||||||
|
|
||||||
expect(actual).to.deep.equal(expected);
|
expect(actual).to.deep.equal(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should skip all <32 ASCII codes except linefeed", async () => {
|
it("should skip all <32 ASCII codes except linefeed", () => {
|
||||||
const testCases = [
|
const testCases = [
|
||||||
{
|
{
|
||||||
input: "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1B\x1D\x1D\x1E\x1Ftext\x0Awithcontrolcodestest",
|
input: "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1B\x1D\x1D\x1E\x1Ftext\x0Awithcontrolcodestest",
|
||||||
|
@ -50,16 +45,13 @@ describe("IRC formatted message parser", () => {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = await Promise.all(
|
const actual = testCases.map((testCase) => getParsedMessageContents(testCase.input));
|
||||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
|
||||||
testCases.map((testCase) => getParsedMessageContents(testCase.input))
|
|
||||||
);
|
|
||||||
const expected = testCases.map((testCase) => testCase.expected);
|
const expected = testCases.map((testCase) => testCase.expected);
|
||||||
|
|
||||||
expect(actual).to.deep.equal(expected);
|
expect(actual).to.deep.equal(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should find urls", async () => {
|
it("should find urls", () => {
|
||||||
const testCases = [
|
const testCases = [
|
||||||
{
|
{
|
||||||
input: "irc://irc.example.com/thelounge",
|
input: "irc://irc.example.com/thelounge",
|
||||||
|
@ -102,16 +94,13 @@ describe("IRC formatted message parser", () => {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = await Promise.all(
|
const actual = testCases.map((testCase) => getParsedMessageContents(testCase.input));
|
||||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
|
||||||
testCases.map((testCase) => getParsedMessageContents(testCase.input))
|
|
||||||
);
|
|
||||||
const expected = testCases.map((testCase) => testCase.expected);
|
const expected = testCases.map((testCase) => testCase.expected);
|
||||||
|
|
||||||
expect(actual).to.deep.equal(expected);
|
expect(actual).to.deep.equal(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("url with a dot parsed correctly", async () => {
|
it("url with a dot parsed correctly", () => {
|
||||||
const input =
|
const input =
|
||||||
"bonuspunkt: your URL parser misparses this URL: https://msdn.microsoft.com/en-us/library/windows/desktop/ms644989(v=vs.85).aspx";
|
"bonuspunkt: your URL parser misparses this URL: https://msdn.microsoft.com/en-us/library/windows/desktop/ms644989(v=vs.85).aspx";
|
||||||
const correctResult =
|
const correctResult =
|
||||||
|
@ -120,13 +109,12 @@ describe("IRC formatted message parser", () => {
|
||||||
"https://msdn.microsoft.com/en-us/library/windows/desktop/ms644989(v=vs.85).aspx" +
|
"https://msdn.microsoft.com/en-us/library/windows/desktop/ms644989(v=vs.85).aspx" +
|
||||||
"</a>";
|
"</a>";
|
||||||
|
|
||||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
const actual = getParsedMessageContents(input);
|
||||||
const actual = await getParsedMessageContents(input);
|
|
||||||
|
|
||||||
expect(actual).to.deep.equal(correctResult);
|
expect(actual).to.deep.equal(correctResult);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should balance brackets", async () => {
|
it("should balance brackets", () => {
|
||||||
const testCases = [
|
const testCases = [
|
||||||
{
|
{
|
||||||
input: "<https://theos.kyriasis.com/~kyrias/stats/archlinux.html>",
|
input: "<https://theos.kyriasis.com/~kyrias/stats/archlinux.html>",
|
||||||
|
@ -162,16 +150,13 @@ describe("IRC formatted message parser", () => {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = await Promise.all(
|
const actual = testCases.map((testCase) => getParsedMessageContents(testCase.input));
|
||||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
|
||||||
testCases.map((testCase) => getParsedMessageContents(testCase.input))
|
|
||||||
);
|
|
||||||
const expected = testCases.map((testCase) => testCase.expected);
|
const expected = testCases.map((testCase) => testCase.expected);
|
||||||
|
|
||||||
expect(actual).to.deep.equal(expected);
|
expect(actual).to.deep.equal(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not find urls", async () => {
|
it("should not find urls", () => {
|
||||||
const testCases = [
|
const testCases = [
|
||||||
{
|
{
|
||||||
input: "text www. text",
|
input: "text www. text",
|
||||||
|
@ -183,16 +168,13 @@ describe("IRC formatted message parser", () => {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = await Promise.all(
|
const actual = testCases.map((testCase) => getParsedMessageContents(testCase.input));
|
||||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
|
||||||
testCases.map((testCase) => getParsedMessageContents(testCase.input))
|
|
||||||
);
|
|
||||||
const expected = testCases.map((testCase) => testCase.expected);
|
const expected = testCases.map((testCase) => testCase.expected);
|
||||||
|
|
||||||
expect(actual).to.deep.equal(expected);
|
expect(actual).to.deep.equal(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should find channels", async () => {
|
it("should find channels", () => {
|
||||||
const testCases = [
|
const testCases = [
|
||||||
{
|
{
|
||||||
input: "#a",
|
input: "#a",
|
||||||
|
@ -241,16 +223,13 @@ describe("IRC formatted message parser", () => {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = await Promise.all(
|
const actual = testCases.map((testCase) => getParsedMessageContents(testCase.input));
|
||||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
|
||||||
testCases.map((testCase) => getParsedMessageContents(testCase.input))
|
|
||||||
);
|
|
||||||
const expected = testCases.map((testCase) => testCase.expected);
|
const expected = testCases.map((testCase) => testCase.expected);
|
||||||
|
|
||||||
expect(actual).to.deep.equal(expected);
|
expect(actual).to.deep.equal(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not find channels", async () => {
|
it("should not find channels", () => {
|
||||||
const testCases = [
|
const testCases = [
|
||||||
{
|
{
|
||||||
input: "hi#test",
|
input: "hi#test",
|
||||||
|
@ -262,10 +241,7 @@ describe("IRC formatted message parser", () => {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = await Promise.all(
|
const actual = testCases.map((testCase) => getParsedMessageContents(testCase.input));
|
||||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
|
||||||
testCases.map((testCase) => getParsedMessageContents(testCase.input))
|
|
||||||
);
|
|
||||||
const expected = testCases.map((testCase) => testCase.expected);
|
const expected = testCases.map((testCase) => testCase.expected);
|
||||||
|
|
||||||
expect(actual).to.deep.equal(expected);
|
expect(actual).to.deep.equal(expected);
|
||||||
|
@ -362,9 +338,8 @@ describe("IRC formatted message parser", () => {
|
||||||
'<span class="irc-bold">bold</span>' + " " + '<span class="irc-bold">bold</span>',
|
'<span class="irc-bold">bold</span>' + " " + '<span class="irc-bold">bold</span>',
|
||||||
},
|
},
|
||||||
].forEach(({name, input, expected}) => {
|
].forEach(({name, input, expected}) => {
|
||||||
it(`should handle style characters: ${name}`, async () => {
|
it(`should handle style characters: ${name}`, () => {
|
||||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
expect(getParsedMessageContents(input)).to.equal(expected);
|
||||||
expect(await getParsedMessageContents(input)).to.equal(expected);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -391,7 +366,7 @@ describe("IRC formatted message parser", () => {
|
||||||
expect(actual).to.deep.equal(expected);
|
expect(actual).to.deep.equal(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not find nicks", async () => {
|
it("should not find nicks", () => {
|
||||||
const testCases = [
|
const testCases = [
|
||||||
{
|
{
|
||||||
users: ["MaxLeiter, test"],
|
users: ["MaxLeiter, test"],
|
||||||
|
@ -411,16 +386,13 @@ describe("IRC formatted message parser", () => {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = await Promise.all(
|
const actual = testCases.map((testCase) => getParsedMessageContents(testCase.input));
|
||||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
|
||||||
testCases.map((testCase) => getParsedMessageContents(testCase.input))
|
|
||||||
);
|
|
||||||
const expected = testCases.map((testCase) => testCase.expected);
|
const expected = testCases.map((testCase) => testCase.expected);
|
||||||
|
|
||||||
expect(actual).to.deep.equal(expected);
|
expect(actual).to.deep.equal(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should go bonkers like mirc", async () => {
|
it("should go bonkers like mirc", () => {
|
||||||
const testCases = [
|
const testCases = [
|
||||||
{
|
{
|
||||||
input: "\x02irc\x0f://\x1dirc.example.com\x0f/\x034,8thelounge",
|
input: "\x02irc\x0f://\x1dirc.example.com\x0f/\x034,8thelounge",
|
||||||
|
@ -443,10 +415,7 @@ describe("IRC formatted message parser", () => {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = await Promise.all(
|
const actual = testCases.map((testCase) => getParsedMessageContents(testCase.input));
|
||||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
|
||||||
testCases.map((testCase) => getParsedMessageContents(testCase.input))
|
|
||||||
);
|
|
||||||
const expected = testCases.map((testCase) => testCase.expected);
|
const expected = testCases.map((testCase) => testCase.expected);
|
||||||
|
|
||||||
expect(actual).to.deep.equal(expected);
|
expect(actual).to.deep.equal(expected);
|
||||||
|
@ -521,13 +490,12 @@ describe("IRC formatted message parser", () => {
|
||||||
'<span dir="auto" role="button" tabindex="0" class="inline-channel">#i❤️thelounge</span>',
|
'<span dir="auto" role="button" tabindex="0" class="inline-channel">#i❤️thelounge</span>',
|
||||||
},
|
},
|
||||||
].forEach(({name, input, expected}) => {
|
].forEach(({name, input, expected}) => {
|
||||||
it(`should find emoji: ${name}`, async () => {
|
it(`should find emoji: ${name}`, () => {
|
||||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
expect(getParsedMessageContents(input)).to.equal(expected);
|
||||||
expect(await getParsedMessageContents(input)).to.equal(expected);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should optimize generated html", async () => {
|
it("should optimize generated html", () => {
|
||||||
const testCases = [
|
const testCases = [
|
||||||
{
|
{
|
||||||
input: 'test \x0312#\x0312\x0312"te\x0312st\x0312\x0312\x0312\x0312\x0312\x0312\x0312\x0312\x0312\x0312\x0312a',
|
input: 'test \x0312#\x0312\x0312"te\x0312st\x0312\x0312\x0312\x0312\x0312\x0312\x0312\x0312\x0312\x0312\x0312a',
|
||||||
|
@ -539,16 +507,13 @@ describe("IRC formatted message parser", () => {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = await Promise.all(
|
const actual = testCases.map((testCase) => getParsedMessageContents(testCase.input));
|
||||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
|
||||||
testCases.map((testCase) => getParsedMessageContents(testCase.input))
|
|
||||||
);
|
|
||||||
const expected = testCases.map((testCase) => testCase.expected);
|
const expected = testCases.map((testCase) => testCase.expected);
|
||||||
|
|
||||||
expect(actual).to.deep.equal(expected);
|
expect(actual).to.deep.equal(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should trim common protocols", async () => {
|
it("should trim common protocols", () => {
|
||||||
const testCases = [
|
const testCases = [
|
||||||
{
|
{
|
||||||
input: "like..http://example.com",
|
input: "like..http://example.com",
|
||||||
|
@ -568,16 +533,13 @@ describe("IRC formatted message parser", () => {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = await Promise.all(
|
const actual = testCases.map((testCase) => getParsedMessageContents(testCase.input));
|
||||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
|
||||||
testCases.map((testCase) => getParsedMessageContents(testCase.input))
|
|
||||||
);
|
|
||||||
const expected = testCases.map((testCase) => testCase.expected);
|
const expected = testCases.map((testCase) => testCase.expected);
|
||||||
|
|
||||||
expect(actual).to.deep.equal(expected);
|
expect(actual).to.deep.equal(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not find channel in fragment", async () => {
|
it("should not find channel in fragment", () => {
|
||||||
const testCases = [
|
const testCases = [
|
||||||
{
|
{
|
||||||
input: "http://example.com/#hash",
|
input: "http://example.com/#hash",
|
||||||
|
@ -588,19 +550,15 @@ describe("IRC formatted message parser", () => {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const actual = await Promise.all(
|
const actual = testCases.map((testCase) => getParsedMessageContents(testCase.input));
|
||||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
|
||||||
testCases.map((testCase) => getParsedMessageContents(testCase.input))
|
|
||||||
);
|
|
||||||
const expected = testCases.map((testCase) => testCase.expected);
|
const expected = testCases.map((testCase) => testCase.expected);
|
||||||
|
|
||||||
expect(actual).to.deep.equal(expected);
|
expect(actual).to.deep.equal(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not overlap parts", async () => {
|
it("should not overlap parts", () => {
|
||||||
const input = "Url: http://example.com/path Channel: ##channel";
|
const input = "Url: http://example.com/path Channel: ##channel";
|
||||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
const actual = getParsedMessageContents(input);
|
||||||
const actual = await getParsedMessageContents(input);
|
|
||||||
|
|
||||||
expect(actual).to.equal(
|
expect(actual).to.equal(
|
||||||
'Url: <a href="http://example.com/path" dir="auto" target="_blank" rel="noopener">http://example.com/path</a> ' +
|
'Url: <a href="http://example.com/path" dir="auto" target="_blank" rel="noopener">http://example.com/path</a> ' +
|
||||||
|
@ -608,10 +566,9 @@ describe("IRC formatted message parser", () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should handle overlapping parts by using first starting", async () => {
|
it("should handle overlapping parts by using first starting", () => {
|
||||||
const input = "#test-https://example.com";
|
const input = "#test-https://example.com";
|
||||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
const actual = getParsedMessageContents(input);
|
||||||
const actual = await getParsedMessageContents(input);
|
|
||||||
|
|
||||||
expect(actual).to.equal(
|
expect(actual).to.equal(
|
||||||
'<span dir="auto" role="button" tabindex="0" class="inline-channel">' +
|
'<span dir="auto" role="button" tabindex="0" class="inline-channel">' +
|
||||||
|
@ -620,10 +577,9 @@ describe("IRC formatted message parser", () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should find links separated by tab character", async () => {
|
it("should find links separated by tab character", () => {
|
||||||
const input = "example.com\texample.org";
|
const input = "example.com\texample.org";
|
||||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
const actual = getParsedMessageContents(input);
|
||||||
const actual = await getParsedMessageContents(input);
|
|
||||||
|
|
||||||
expect(actual).to.equal(
|
expect(actual).to.equal(
|
||||||
'<a href="http://example.com" dir="auto" target="_blank" rel="noopener">example.com</a>' +
|
'<a href="http://example.com" dir="auto" target="_blank" rel="noopener">example.com</a>' +
|
||||||
|
|
Loading…
Reference in a new issue