Remove HTML version of parse()
This commit is contained in:
parent
d83dcc35e2
commit
e3ff385ae0
@ -28,8 +28,9 @@
|
||||
<span class="title">{{ channel.name }}</span>
|
||||
<span
|
||||
:title="channel.topic"
|
||||
class="topic"
|
||||
v-html="$options.filters.parse(channel.topic)"/>
|
||||
class="topic"><ParsedMessage
|
||||
v-if="channel.topic"
|
||||
:text="channel.topic"/></span>
|
||||
<button
|
||||
class="menu"
|
||||
aria-label="Open the context menu"
|
||||
@ -86,6 +87,7 @@
|
||||
<script>
|
||||
require("intersection-observer");
|
||||
const socket = require("../js/socket");
|
||||
import ParsedMessage from "./ParsedMessage.vue";
|
||||
import MessageList from "./MessageList.vue";
|
||||
import ChatInput from "./ChatInput.vue";
|
||||
import ChatUserList from "./ChatUserList.vue";
|
||||
@ -96,6 +98,7 @@ import ListIgnored from "./Special/ListIgnored.vue";
|
||||
export default {
|
||||
name: "Chat",
|
||||
components: {
|
||||
ParsedMessage,
|
||||
MessageList,
|
||||
ChatInput,
|
||||
ChatUserList,
|
||||
|
@ -28,9 +28,7 @@
|
||||
</template>
|
||||
</span>
|
||||
<span class="content">
|
||||
<span
|
||||
ref="text"
|
||||
class="text"><ParsedMessage :message="message"/></span>
|
||||
<span class="text"><ParsedMessage :message="message"/></span>
|
||||
|
||||
<LinkPreview
|
||||
v-for="preview in message.previews"
|
||||
|
@ -1,24 +1,24 @@
|
||||
<template>
|
||||
<span class="content">
|
||||
<template v-if="message.self">
|
||||
<i v-html="$options.filters.parse(message.text)"/>
|
||||
</template>
|
||||
<ParsedMessage
|
||||
v-if="message.self"
|
||||
:message="message"/>
|
||||
<template v-else>
|
||||
<Username :user="message.from"/>
|
||||
is away
|
||||
<i
|
||||
class="away-message"
|
||||
v-html="'(' + $options.filters.parse(message.text) + ')'"/>
|
||||
<i class="away-message">(<ParsedMessage :message="message"/>)</i>
|
||||
</template>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ParsedMessage from "../ParsedMessage.vue";
|
||||
import Username from "../Username.vue";
|
||||
|
||||
export default {
|
||||
name: "MessageTypeAway",
|
||||
components: {
|
||||
ParsedMessage,
|
||||
Username,
|
||||
},
|
||||
props: {
|
||||
|
@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<span class="content">
|
||||
<template v-if="message.self">
|
||||
<i v-html="$options.filters.parse(message.text)"/>
|
||||
</template>
|
||||
<ParsedMessage
|
||||
v-if="message.self"
|
||||
:message="message"/>
|
||||
<template v-else>
|
||||
<Username :user="message.from"/>
|
||||
is back
|
||||
|
@ -1,18 +1,18 @@
|
||||
<template>
|
||||
<span class="content">
|
||||
<Username :user="message.from"/>
|
||||
<span
|
||||
class="ctcp-message"
|
||||
v-html="$options.filters.parse(message.ctcpMessage)"/>
|
||||
<span class="ctcp-message"><ParsedMessage :text="message.ctcpMessage"/></span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ParsedMessage from "../ParsedMessage.vue";
|
||||
import Username from "../Username.vue";
|
||||
|
||||
export default {
|
||||
name: "MessageTypeCTCP",
|
||||
components: {
|
||||
ParsedMessage,
|
||||
Username,
|
||||
},
|
||||
props: {
|
||||
|
@ -2,18 +2,18 @@
|
||||
<span class="content">
|
||||
<Username :user="message.from"/>
|
||||
sent a <abbr title="Client-to-client protocol">CTCP</abbr> request:
|
||||
<span
|
||||
class="ctcp-message"
|
||||
v-html="$options.filters.parse(message.ctcpMessage)"/>
|
||||
<span class="ctcp-message"><ParsedMessage :text="message.ctcpMessage"/></span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ParsedMessage from "../ParsedMessage.vue";
|
||||
import Username from "../Username.vue";
|
||||
|
||||
export default {
|
||||
name: "MessageTypeRequestCTCP",
|
||||
components: {
|
||||
ParsedMessage,
|
||||
Username,
|
||||
},
|
||||
props: {
|
||||
|
@ -6,16 +6,18 @@
|
||||
<Username
|
||||
v-else
|
||||
:user="message.target"/>
|
||||
to <span v-html="$options.filters.parse(message.channel)"/>
|
||||
to <ParsedMessage :text="message.channel"/>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ParsedMessage from "../ParsedMessage.vue";
|
||||
import Username from "../Username.vue";
|
||||
|
||||
export default {
|
||||
name: "MessageTypeInvite",
|
||||
components: {
|
||||
ParsedMessage,
|
||||
Username,
|
||||
},
|
||||
props: {
|
||||
|
@ -5,17 +5,18 @@
|
||||
<Username :user="message.target"/>
|
||||
<i
|
||||
v-if="message.text"
|
||||
class="part-reason"
|
||||
v-html="'(' + $options.filters.parse(message.text) + ')'"/>
|
||||
class="part-reason">(<ParsedMessage :message="message"/>)</i>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ParsedMessage from "../ParsedMessage.vue";
|
||||
import Username from "../Username.vue";
|
||||
|
||||
export default {
|
||||
name: "MessageTypeKick",
|
||||
components: {
|
||||
ParsedMessage,
|
||||
Username,
|
||||
},
|
||||
props: {
|
||||
|
@ -2,16 +2,18 @@
|
||||
<span class="content">
|
||||
<Username :user="message.from"/>
|
||||
sets mode
|
||||
<span v-html="$options.filters.parse(message.text)"/>
|
||||
<ParsedMessage :message="message"/>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ParsedMessage from "../ParsedMessage.vue";
|
||||
import Username from "../Username.vue";
|
||||
|
||||
export default {
|
||||
name: "MessageTypeMode",
|
||||
components: {
|
||||
ParsedMessage,
|
||||
Username,
|
||||
},
|
||||
props: {
|
||||
|
@ -5,17 +5,18 @@
|
||||
has left the channel
|
||||
<i
|
||||
v-if="message.text"
|
||||
class="part-reason"
|
||||
v-html="'(' + $options.filters.parse(message.text) + ')'"/>
|
||||
class="part-reason">(<ParsedMessage :message="message"/>)</i>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ParsedMessage from "../ParsedMessage.vue";
|
||||
import Username from "../Username.vue";
|
||||
|
||||
export default {
|
||||
name: "MessageTypePart",
|
||||
components: {
|
||||
ParsedMessage,
|
||||
Username,
|
||||
},
|
||||
props: {
|
||||
|
@ -5,17 +5,18 @@
|
||||
has quit
|
||||
<i
|
||||
v-if="message.text"
|
||||
class="quit-reason"
|
||||
v-html="'(' + $options.filters.parse(message.text) + ')'"/>
|
||||
class="quit-reason">(<ParsedMessage :message="message"/>)</i>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ParsedMessage from "../ParsedMessage.vue";
|
||||
import Username from "../Username.vue";
|
||||
|
||||
export default {
|
||||
name: "MessageTypeQuit",
|
||||
components: {
|
||||
ParsedMessage,
|
||||
Username,
|
||||
},
|
||||
props: {
|
||||
|
@ -9,17 +9,18 @@
|
||||
</template>
|
||||
<span
|
||||
v-if="message.text"
|
||||
class="new-topic"
|
||||
v-html="$options.filters.parse(message.text)"/>
|
||||
class="new-topic"><ParsedMessage :message="message"/></span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ParsedMessage from "../ParsedMessage.vue";
|
||||
import Username from "../Username.vue";
|
||||
|
||||
export default {
|
||||
name: "MessageTypeTopic",
|
||||
components: {
|
||||
ParsedMessage,
|
||||
Username,
|
||||
},
|
||||
props: {
|
||||
|
@ -27,7 +27,7 @@
|
||||
|
||||
<template v-if="message.whois.real_name">
|
||||
<dt>Real name:</dt>
|
||||
<dd v-html="$options.filters.parse(message.whois.real_name)"/>
|
||||
<dd><ParsedMessage :text="message.whois.real_name"/></dd>
|
||||
</template>
|
||||
|
||||
<template v-if="message.whois.registered_nick">
|
||||
@ -37,7 +37,7 @@
|
||||
|
||||
<template v-if="message.whois.channels">
|
||||
<dt>Channels:</dt>
|
||||
<dd v-html="$options.filters.parse(message.whois.channels)"/>
|
||||
<dd><ParsedMessage :text="message.whois.channels"/></dd>
|
||||
</template>
|
||||
|
||||
<template v-if="message.whois.modes">
|
||||
@ -67,7 +67,7 @@
|
||||
|
||||
<template v-if="message.whois.away">
|
||||
<dt>Away:</dt>
|
||||
<dd v-html="$options.filters.parse(message.whois.away)"/>
|
||||
<dd><ParsedMessage :text="message.whois.away"/></dd>
|
||||
</template>
|
||||
|
||||
<template v-if="message.whois.secure">
|
||||
@ -94,11 +94,13 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ParsedMessage from "../ParsedMessage.vue";
|
||||
import Username from "../Username.vue";
|
||||
|
||||
export default {
|
||||
name: "MessageTypeWhois",
|
||||
components: {
|
||||
ParsedMessage,
|
||||
Username,
|
||||
},
|
||||
props: {
|
||||
|
@ -5,10 +5,15 @@ export default {
|
||||
name: "ParsedMessage",
|
||||
functional: true,
|
||||
props: {
|
||||
text: String,
|
||||
message: Object,
|
||||
},
|
||||
render(createElement, context) {
|
||||
return parse(context.props.message.text, context.props.message, createElement);
|
||||
if (typeof context.props.text !== "undefined") {
|
||||
return parse(createElement, context.props.text);
|
||||
}
|
||||
|
||||
return parse(createElement, context.props.message.text, context.props.message);
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -12,9 +12,7 @@
|
||||
v-for="ban in channel.data"
|
||||
:key="ban.hostmask">
|
||||
<td class="hostmask">{{ ban.hostmask }}</td>
|
||||
<td
|
||||
class="banned_by"
|
||||
v-html="$options.filters.parse(ban.banned_by)"/>
|
||||
<td class="banned_by">{{ ban.banned_by }}</td>
|
||||
<td class="banned_at">{{ ban.banned_at | localetime }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
@ -14,21 +14,22 @@
|
||||
<tr
|
||||
v-for="chan in channel.data"
|
||||
:key="chan.channel">
|
||||
<td
|
||||
class="channel"
|
||||
v-html="$options.filters.parse(chan.channel)"/>
|
||||
<td class="channel"><ParsedMessage :text="chan.channel"/></td>
|
||||
<td class="users">{{ chan.num_users }}</td>
|
||||
<td
|
||||
class="topic"
|
||||
v-html="$options.filters.parse(chan.topic)"/>
|
||||
<td class="topic"><ParsedMessage :text="chan.topic"/></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ParsedMessage from "../ParsedMessage.vue";
|
||||
|
||||
export default {
|
||||
name: "ListChannels",
|
||||
components: {
|
||||
ParsedMessage,
|
||||
},
|
||||
props: {
|
||||
channel: Object,
|
||||
},
|
||||
|
@ -1,6 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
const Handlebars = require("handlebars/runtime");
|
||||
const parseStyle = require("./ircmessageparser/parseStyle");
|
||||
const findChannels = require("./ircmessageparser/findChannels");
|
||||
const findLinks = require("./ircmessageparser/findLinks");
|
||||
@ -12,58 +11,7 @@ const emojiMap = require("../fullnamemap.json");
|
||||
const LinkPreviewToggle = require("../../../components/LinkPreviewToggle.vue").default;
|
||||
|
||||
// Create an HTML `span` with styling information for a given fragment
|
||||
function createFragment(fragment) {
|
||||
const classes = [];
|
||||
|
||||
if (fragment.bold) {
|
||||
classes.push("irc-bold");
|
||||
}
|
||||
|
||||
if (fragment.textColor !== undefined) {
|
||||
classes.push("irc-fg" + fragment.textColor);
|
||||
}
|
||||
|
||||
if (fragment.bgColor !== undefined) {
|
||||
classes.push("irc-bg" + fragment.bgColor);
|
||||
}
|
||||
|
||||
if (fragment.italic) {
|
||||
classes.push("irc-italic");
|
||||
}
|
||||
|
||||
if (fragment.underline) {
|
||||
classes.push("irc-underline");
|
||||
}
|
||||
|
||||
if (fragment.strikethrough) {
|
||||
classes.push("irc-strikethrough");
|
||||
}
|
||||
|
||||
if (fragment.monospace) {
|
||||
classes.push("irc-monospace");
|
||||
}
|
||||
|
||||
let attributes = classes.length ? ` class="${classes.join(" ")}"` : "";
|
||||
const escapedText = Handlebars.Utils.escapeExpression(fragment.text);
|
||||
|
||||
if (fragment.hexColor) {
|
||||
attributes += ` style="color:#${fragment.hexColor}`;
|
||||
|
||||
if (fragment.hexBgColor) {
|
||||
attributes += `;background-color:#${fragment.hexBgColor}`;
|
||||
}
|
||||
|
||||
attributes += '"';
|
||||
}
|
||||
|
||||
if (attributes.length) {
|
||||
return `<span${attributes}>${escapedText}</span>`;
|
||||
}
|
||||
|
||||
return escapedText;
|
||||
}
|
||||
|
||||
function createVueFragment(fragment, createElement) {
|
||||
function createFragment(fragment, createElement) {
|
||||
const classes = [];
|
||||
|
||||
if (fragment.bold) {
|
||||
@ -109,7 +57,7 @@ function createVueFragment(fragment, createElement) {
|
||||
|
||||
// Transform an IRC message potentially filled with styling control codes, URLs,
|
||||
// nicknames, and channels into a string of HTML elements to display on the client.
|
||||
module.exports = function parse(text, message = null, createElement = null) {
|
||||
module.exports = function parse(createElement, text, message = null) {
|
||||
// Extract the styling information and get the plain text version from it
|
||||
const styleFragments = parseStyle(text);
|
||||
const cleanText = styleFragments.map((fragment) => fragment.text).join("");
|
||||
@ -129,97 +77,69 @@ module.exports = function parse(text, message = null, createElement = null) {
|
||||
.concat(emojiParts)
|
||||
.concat(nameParts);
|
||||
|
||||
if (createElement) {
|
||||
return merge(parts, styleFragments, cleanText).map((textPart) => {
|
||||
const fragments = textPart.fragments.map((fragment) => createVueFragment(fragment, createElement));
|
||||
|
||||
// Wrap these potentially styled fragments with links and channel buttons
|
||||
if (textPart.link) {
|
||||
const preview = message && message.previews.find((p) => p.link === textPart.link);
|
||||
const link = createElement("a", {
|
||||
class: [
|
||||
"inline-channel",
|
||||
],
|
||||
attrs: {
|
||||
href: textPart.link,
|
||||
target: "_blank",
|
||||
rel: "noopener",
|
||||
},
|
||||
}, fragments);
|
||||
|
||||
if (!preview) {
|
||||
return link;
|
||||
}
|
||||
|
||||
return [link, createElement(LinkPreviewToggle, {
|
||||
class: ["toggle-button", "toggle-preview"],
|
||||
props: {
|
||||
link: preview,
|
||||
},
|
||||
}, fragments)];
|
||||
} else if (textPart.channel) {
|
||||
return createElement("span", {
|
||||
class: [
|
||||
"inline-channel",
|
||||
],
|
||||
attrs: {
|
||||
"role": "button",
|
||||
"tabindex": 0,
|
||||
"data-chan": textPart.channel,
|
||||
},
|
||||
}, fragments);
|
||||
} else if (textPart.emoji) {
|
||||
return createElement("span", {
|
||||
class: [
|
||||
"emoji",
|
||||
],
|
||||
attrs: {
|
||||
"role": "img",
|
||||
"aria-label": emojiMap[textPart.emoji] ? `Emoji: ${emojiMap[textPart.emoji]}` : null,
|
||||
},
|
||||
}, fragments);
|
||||
} else if (textPart.nick) {
|
||||
return createElement("span", {
|
||||
class: [
|
||||
"user",
|
||||
colorClass(textPart.nick),
|
||||
],
|
||||
attrs: {
|
||||
"role": "button",
|
||||
"data-name": textPart.nick,
|
||||
},
|
||||
}, fragments);
|
||||
}
|
||||
|
||||
return fragments;
|
||||
});
|
||||
}
|
||||
|
||||
// Merge the styling information with the channels / URLs / nicks / text objects and
|
||||
// generate HTML strings with the resulting fragments
|
||||
return merge(parts, styleFragments, cleanText).map((textPart) => {
|
||||
// Create HTML strings with styling information
|
||||
const fragments = textPart.fragments.map(createFragment).join("");
|
||||
const fragments = textPart.fragments.map((fragment) => createFragment(fragment, createElement));
|
||||
|
||||
// Wrap these potentially styled fragments with links and channel buttons
|
||||
if (textPart.link) {
|
||||
const escapedLink = Handlebars.Utils.escapeExpression(textPart.link);
|
||||
return `<a href="${escapedLink}" target="_blank" rel="noopener">${fragments}</a>` +
|
||||
`<button class="toggle-button toggle-preview" data-url="${escapedLink}" hidden></button>`;
|
||||
} else if (textPart.channel) {
|
||||
const escapedChannel = Handlebars.Utils.escapeExpression(textPart.channel);
|
||||
return `<span class="inline-channel" role="button" tabindex="0" data-chan="${escapedChannel}">${fragments}</span>`;
|
||||
} else if (textPart.emoji) {
|
||||
if (!emojiMap[textPart.emoji]) {
|
||||
return `<span class="emoji" role="img">${fragments}</span>`;
|
||||
const preview = message && message.previews.find((p) => p.link === textPart.link);
|
||||
const link = createElement("a", {
|
||||
class: [
|
||||
"inline-channel",
|
||||
],
|
||||
attrs: {
|
||||
href: textPart.link,
|
||||
target: "_blank",
|
||||
rel: "noopener",
|
||||
},
|
||||
}, fragments);
|
||||
|
||||
if (!preview) {
|
||||
return link;
|
||||
}
|
||||
|
||||
return `<span class="emoji" role="img" aria-label="Emoji: ${emojiMap[textPart.emoji]}" title="${emojiMap[textPart.emoji]}">${fragments}</span>`;
|
||||
return [link, createElement(LinkPreviewToggle, {
|
||||
class: ["toggle-button", "toggle-preview"],
|
||||
props: {
|
||||
link: preview,
|
||||
},
|
||||
}, fragments)];
|
||||
} else if (textPart.channel) {
|
||||
return createElement("span", {
|
||||
class: [
|
||||
"inline-channel",
|
||||
],
|
||||
attrs: {
|
||||
"role": "button",
|
||||
"tabindex": 0,
|
||||
"data-chan": textPart.channel,
|
||||
},
|
||||
}, fragments);
|
||||
} else if (textPart.emoji) {
|
||||
return createElement("span", {
|
||||
class: [
|
||||
"emoji",
|
||||
],
|
||||
attrs: {
|
||||
"role": "img",
|
||||
"aria-label": emojiMap[textPart.emoji] ? `Emoji: ${emojiMap[textPart.emoji]}` : null,
|
||||
},
|
||||
}, fragments);
|
||||
} else if (textPart.nick) {
|
||||
const nick = Handlebars.Utils.escapeExpression(textPart.nick);
|
||||
return `<span role="button" class="user ${colorClass(textPart.nick)}" data-name="${nick}">${fragments}</span>`;
|
||||
return createElement("span", {
|
||||
class: [
|
||||
"user",
|
||||
colorClass(textPart.nick),
|
||||
],
|
||||
attrs: {
|
||||
"role": "button",
|
||||
"data-name": textPart.nick,
|
||||
},
|
||||
}, fragments);
|
||||
}
|
||||
|
||||
return fragments;
|
||||
}).join("");
|
||||
});
|
||||
};
|
||||
|
@ -3,7 +3,6 @@
|
||||
const Vue = require("vue").default;
|
||||
const App = require("../components/App.vue").default;
|
||||
const roundBadgeNumber = require("./libs/handlebars/roundBadgeNumber");
|
||||
const parse = require("./libs/handlebars/parse");
|
||||
const tz = require("./libs/handlebars/tz");
|
||||
const localetime = require("./libs/handlebars/localetime");
|
||||
const localedate = require("./libs/handlebars/localedate");
|
||||
@ -11,7 +10,6 @@ const friendlydate = require("./libs/handlebars/friendlydate");
|
||||
const friendlysize = require("./libs/handlebars/friendlysize");
|
||||
const colorClass = require("./libs/handlebars/colorClass");
|
||||
|
||||
Vue.filter("parse", parse);
|
||||
Vue.filter("tz", tz);
|
||||
Vue.filter("localetime", localetime);
|
||||
Vue.filter("localedate", localedate);
|
||||
|
Loading…
Reference in New Issue
Block a user