#1755 - implement monospace formatting with keybinding, tests, and help section
This commit is contained in:
parent
0643d3b4a3
commit
f07c1bef69
@ -80,6 +80,7 @@ button {
|
||||
|
||||
code,
|
||||
kbd,
|
||||
.irc-monospace,
|
||||
textarea#user-specified-css-input {
|
||||
font-family: Consolas, Menlo, Monaco, "Lucida Console", "DejaVu Sans Mono", "Courier New", monospace;
|
||||
}
|
||||
|
@ -73,6 +73,7 @@ const colorsHotkeys = {
|
||||
i: "\x1D",
|
||||
o: "\x0F",
|
||||
s: "\x1e",
|
||||
m: "\x11",
|
||||
};
|
||||
|
||||
for (const hotkey in colorsHotkeys) {
|
||||
|
@ -9,6 +9,7 @@ const REVERSE = "\x16";
|
||||
const ITALIC = "\x1d";
|
||||
const UNDERLINE = "\x1f";
|
||||
const STRIKETHROUGH = "\x1e";
|
||||
const MONOSPACE = "\x11";
|
||||
|
||||
// Color code matcher, with format `XX,YY` where both `XX` and `YY` are
|
||||
// integers, `XX` is the text color and `YY` is an optional background color.
|
||||
@ -23,7 +24,7 @@ const controlCodesRx = /[\u0000-\u001F]/g;
|
||||
// Converts a given text into an array of objects, each of them representing a
|
||||
// similarly styled section of the text. Each object carries the `text`, style
|
||||
// information (`bold`, `textColor`, `bgcolor`, `reverse`, `italic`,
|
||||
// `underline`, `strikethrough`), and `start`/`end` cursors.
|
||||
// `underline`, `strikethrough`, `monospace`), and `start`/`end` cursors.
|
||||
function parseStyle(text) {
|
||||
const result = [];
|
||||
let start = 0;
|
||||
@ -31,7 +32,7 @@ function parseStyle(text) {
|
||||
|
||||
// At any given time, these carry style information since last time a styling
|
||||
// control code was met.
|
||||
let colorCodes, bold, textColor, bgColor, hexColor, hexBgColor, reverse, italic, underline, strikethrough;
|
||||
let colorCodes, bold, textColor, bgColor, hexColor, hexBgColor, reverse, italic, underline, strikethrough, monospace;
|
||||
|
||||
const resetStyle = () => {
|
||||
bold = false;
|
||||
@ -43,6 +44,7 @@ function parseStyle(text) {
|
||||
italic = false;
|
||||
underline = false;
|
||||
strikethrough = false;
|
||||
monospace = false;
|
||||
};
|
||||
resetStyle();
|
||||
|
||||
@ -71,6 +73,7 @@ function parseStyle(text) {
|
||||
italic,
|
||||
underline,
|
||||
strikethrough,
|
||||
monospace,
|
||||
text: processedText,
|
||||
start: fragmentStart,
|
||||
end: fragmentStart + processedText.length,
|
||||
@ -164,6 +167,11 @@ function parseStyle(text) {
|
||||
emitFragment();
|
||||
strikethrough = !strikethrough;
|
||||
break;
|
||||
|
||||
case MONOSPACE:
|
||||
emitFragment();
|
||||
monospace = !monospace;
|
||||
break;
|
||||
}
|
||||
|
||||
// Evaluate the next character at the next iteration
|
||||
@ -176,7 +184,7 @@ function parseStyle(text) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const properties = ["bold", "textColor", "bgColor", "hexColor", "hexBgColor", "italic", "underline", "reverse", "strikethrough"];
|
||||
const properties = ["bold", "textColor", "bgColor", "hexColor", "hexBgColor", "italic", "underline", "reverse", "strikethrough", "monospace"];
|
||||
|
||||
function prepare(text) {
|
||||
return parseStyle(text)
|
||||
|
@ -31,6 +31,9 @@ function createFragment(fragment) {
|
||||
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);
|
||||
|
@ -74,6 +74,15 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="help-item">
|
||||
<div class="subject">
|
||||
<kbd class="key-all">Ctrl</kbd><kbd class="key-apple">⌘</kbd> + <kbd>M</kbd>
|
||||
</div>
|
||||
<div class="description">
|
||||
<p>Mark all text typed after this shortcut as monospaced.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="help-item">
|
||||
<div class="subject">
|
||||
<kbd class="key-all">Ctrl</kbd><kbd class="key-apple">⌘</kbd> + <kbd>O</kbd>
|
||||
|
@ -16,6 +16,7 @@ describe("parseStyle", () => {
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: false,
|
||||
text: "textwithcontrolcodes",
|
||||
|
||||
start: 0,
|
||||
@ -39,6 +40,7 @@ describe("parseStyle", () => {
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: false,
|
||||
text: "bold",
|
||||
|
||||
start: 0,
|
||||
@ -62,6 +64,7 @@ describe("parseStyle", () => {
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: true,
|
||||
monospace: false,
|
||||
text: "strikethrough text",
|
||||
|
||||
start: 0,
|
||||
@ -73,6 +76,192 @@ describe("parseStyle", () => {
|
||||
expect(actual).to.deep.equal(expected);
|
||||
});
|
||||
|
||||
it("should parse monospace", () => {
|
||||
const input = "\x11monospace text\x1e";
|
||||
const expected = [{
|
||||
bold: false,
|
||||
textColor: undefined,
|
||||
bgColor: undefined,
|
||||
hexColor: undefined,
|
||||
hexBgColor: undefined,
|
||||
reverse: false,
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: true,
|
||||
text: "monospace text",
|
||||
|
||||
start: 0,
|
||||
end: 14,
|
||||
}];
|
||||
|
||||
const actual = parseStyle(input);
|
||||
|
||||
expect(actual).to.deep.equal(expected);
|
||||
});
|
||||
|
||||
it("should toggle monospace correctly", () => {
|
||||
const input = "toggling \x11on and \x11off and \x11on again\x11";
|
||||
const expected = [{
|
||||
bold: false,
|
||||
textColor: undefined,
|
||||
bgColor: undefined,
|
||||
hexColor: undefined,
|
||||
hexBgColor: undefined,
|
||||
reverse: false,
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: false,
|
||||
text: "toggling ",
|
||||
|
||||
start: 0,
|
||||
end: 9,
|
||||
}, {
|
||||
bold: false,
|
||||
textColor: undefined,
|
||||
bgColor: undefined,
|
||||
hexColor: undefined,
|
||||
hexBgColor: undefined,
|
||||
reverse: false,
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: true,
|
||||
text: "on and ",
|
||||
|
||||
start: 9,
|
||||
end: 16,
|
||||
}, {
|
||||
bold: false,
|
||||
textColor: undefined,
|
||||
bgColor: undefined,
|
||||
hexColor: undefined,
|
||||
hexBgColor: undefined,
|
||||
reverse: false,
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: false,
|
||||
text: "off and ",
|
||||
|
||||
start: 16,
|
||||
end: 24,
|
||||
}, {
|
||||
bold: false,
|
||||
textColor: undefined,
|
||||
bgColor: undefined,
|
||||
hexColor: undefined,
|
||||
hexBgColor: undefined,
|
||||
reverse: false,
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: true,
|
||||
text: "on again",
|
||||
|
||||
start: 24,
|
||||
end: 32,
|
||||
}];
|
||||
|
||||
const actual = parseStyle(input);
|
||||
|
||||
expect(actual).to.deep.equal(expected);
|
||||
});
|
||||
|
||||
it("should parse monospace and underline", () => {
|
||||
const input = "\x1funderline formatting \x11with monospace\x1f no underline \x11 and vanilla";
|
||||
const expected = [{
|
||||
bold: false,
|
||||
textColor: undefined,
|
||||
bgColor: undefined,
|
||||
hexColor: undefined,
|
||||
hexBgColor: undefined,
|
||||
reverse: false,
|
||||
italic: false,
|
||||
underline: true,
|
||||
strikethrough: false,
|
||||
monospace: false,
|
||||
text: "underline formatting ",
|
||||
|
||||
start: 0,
|
||||
end: 21,
|
||||
}, {
|
||||
bold: false,
|
||||
textColor: undefined,
|
||||
bgColor: undefined,
|
||||
hexColor: undefined,
|
||||
hexBgColor: undefined,
|
||||
reverse: false,
|
||||
italic: false,
|
||||
underline: true,
|
||||
strikethrough: false,
|
||||
monospace: true,
|
||||
text: "with monospace",
|
||||
|
||||
start: 21,
|
||||
end: 35,
|
||||
}, {
|
||||
bold: false,
|
||||
textColor: undefined,
|
||||
bgColor: undefined,
|
||||
hexColor: undefined,
|
||||
hexBgColor: undefined,
|
||||
reverse: false,
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: true,
|
||||
text: " no underline ",
|
||||
|
||||
start: 35,
|
||||
end: 49,
|
||||
}, {
|
||||
bold: false,
|
||||
textColor: undefined,
|
||||
bgColor: undefined,
|
||||
hexColor: undefined,
|
||||
hexBgColor: undefined,
|
||||
reverse: false,
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: false,
|
||||
text: " and vanilla",
|
||||
|
||||
start: 49,
|
||||
end: 61,
|
||||
}];
|
||||
|
||||
const actual = parseStyle(input);
|
||||
|
||||
expect(actual).to.deep.equal(expected);
|
||||
});
|
||||
|
||||
it("should parse monospace and text colors", () => {
|
||||
const input = "\x037,9\x11text with color and monospace\x11\x03";
|
||||
const expected = [{
|
||||
bold: false,
|
||||
textColor: 7,
|
||||
bgColor: 9,
|
||||
hexColor: undefined,
|
||||
hexBgColor: undefined,
|
||||
reverse: false,
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: true,
|
||||
text: "text with color and monospace",
|
||||
|
||||
start: 0,
|
||||
end: 29,
|
||||
}];
|
||||
|
||||
const actual = parseStyle(input);
|
||||
|
||||
expect(actual).to.deep.equal(expected);
|
||||
});
|
||||
|
||||
it("should parse strikethrough and italics", () => {
|
||||
const input = "\x1ditalic formatting \x1ewith strikethrough\x1d no italic \x1e and vanilla";
|
||||
const expected = [{
|
||||
@ -85,6 +274,7 @@ describe("parseStyle", () => {
|
||||
italic: true,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: false,
|
||||
text: "italic formatting ",
|
||||
|
||||
start: 0,
|
||||
@ -99,6 +289,7 @@ describe("parseStyle", () => {
|
||||
italic: true,
|
||||
underline: false,
|
||||
strikethrough: true,
|
||||
monospace: false,
|
||||
text: "with strikethrough",
|
||||
|
||||
start: 18,
|
||||
@ -113,6 +304,7 @@ describe("parseStyle", () => {
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: true,
|
||||
monospace: false,
|
||||
text: " no italic ",
|
||||
|
||||
start: 36,
|
||||
@ -127,6 +319,7 @@ describe("parseStyle", () => {
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: false,
|
||||
text: " and vanilla",
|
||||
|
||||
start: 47,
|
||||
@ -150,6 +343,7 @@ describe("parseStyle", () => {
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: false,
|
||||
text: "text with color ",
|
||||
|
||||
start: 0,
|
||||
@ -164,6 +358,7 @@ describe("parseStyle", () => {
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: true,
|
||||
monospace: false,
|
||||
text: "and strikethrough",
|
||||
|
||||
start: 16,
|
||||
@ -187,6 +382,7 @@ describe("parseStyle", () => {
|
||||
italic: true,
|
||||
underline: false,
|
||||
strikethrough: true,
|
||||
monospace: false,
|
||||
text: "string with multiple unclosed formats",
|
||||
|
||||
start: 0,
|
||||
@ -210,6 +406,7 @@ describe("parseStyle", () => {
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: false,
|
||||
text: "toggling ",
|
||||
|
||||
start: 0,
|
||||
@ -224,6 +421,7 @@ describe("parseStyle", () => {
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: true,
|
||||
monospace: false,
|
||||
text: "on and ",
|
||||
|
||||
start: 9,
|
||||
@ -238,6 +436,7 @@ describe("parseStyle", () => {
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: false,
|
||||
text: "off and ",
|
||||
|
||||
start: 16,
|
||||
@ -252,6 +451,7 @@ describe("parseStyle", () => {
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: true,
|
||||
monospace: false,
|
||||
text: "on again",
|
||||
|
||||
start: 24,
|
||||
@ -275,6 +475,7 @@ describe("parseStyle", () => {
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: false,
|
||||
text: "yellowText",
|
||||
|
||||
start: 0,
|
||||
@ -298,6 +499,7 @@ describe("parseStyle", () => {
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: false,
|
||||
text: "yellowBG redText",
|
||||
|
||||
start: 0,
|
||||
@ -321,6 +523,7 @@ describe("parseStyle", () => {
|
||||
italic: true,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: false,
|
||||
text: "italic",
|
||||
|
||||
start: 0,
|
||||
@ -344,6 +547,7 @@ describe("parseStyle", () => {
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: false,
|
||||
text: "test ",
|
||||
|
||||
start: 0,
|
||||
@ -358,6 +562,7 @@ describe("parseStyle", () => {
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: false,
|
||||
text: "nice ",
|
||||
|
||||
start: 5,
|
||||
@ -372,6 +577,7 @@ describe("parseStyle", () => {
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: false,
|
||||
text: "RES006 ",
|
||||
|
||||
start: 10,
|
||||
@ -386,6 +592,7 @@ describe("parseStyle", () => {
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: false,
|
||||
text: "colored",
|
||||
|
||||
start: 17,
|
||||
@ -400,6 +607,7 @@ describe("parseStyle", () => {
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: false,
|
||||
text: " background",
|
||||
|
||||
start: 24,
|
||||
@ -414,6 +622,7 @@ describe("parseStyle", () => {
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: false,
|
||||
text: "?",
|
||||
|
||||
start: 35,
|
||||
@ -437,6 +646,7 @@ describe("parseStyle", () => {
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: false,
|
||||
text: "bold",
|
||||
|
||||
start: 0,
|
||||
@ -451,6 +661,7 @@ describe("parseStyle", () => {
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: false,
|
||||
text: "yellow",
|
||||
|
||||
start: 4,
|
||||
@ -465,6 +676,7 @@ describe("parseStyle", () => {
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: false,
|
||||
text: "nonBold",
|
||||
|
||||
start: 10,
|
||||
@ -479,6 +691,7 @@ describe("parseStyle", () => {
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: false,
|
||||
text: "default",
|
||||
|
||||
start: 17,
|
||||
@ -502,6 +715,7 @@ describe("parseStyle", () => {
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: false,
|
||||
text: "bold",
|
||||
|
||||
start: 0,
|
||||
@ -516,6 +730,7 @@ describe("parseStyle", () => {
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: false,
|
||||
text: " ",
|
||||
|
||||
start: 4,
|
||||
@ -530,6 +745,7 @@ describe("parseStyle", () => {
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: false,
|
||||
text: "bold",
|
||||
|
||||
start: 5,
|
||||
@ -542,7 +758,7 @@ describe("parseStyle", () => {
|
||||
});
|
||||
|
||||
it("should reset all styles", () => {
|
||||
const input = "\x1e\x02\x034\x16\x1d\x1ffull\x0fnone";
|
||||
const input = "\x11\x1e\x02\x034\x16\x1d\x1ffull\x0fnone";
|
||||
const expected = [{
|
||||
bold: true,
|
||||
textColor: 4,
|
||||
@ -553,6 +769,7 @@ describe("parseStyle", () => {
|
||||
italic: true,
|
||||
underline: true,
|
||||
strikethrough: true,
|
||||
monospace: true,
|
||||
text: "full",
|
||||
|
||||
start: 0,
|
||||
@ -567,6 +784,7 @@ describe("parseStyle", () => {
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: false,
|
||||
text: "none",
|
||||
|
||||
start: 4,
|
||||
@ -590,6 +808,7 @@ describe("parseStyle", () => {
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: false,
|
||||
text: "a",
|
||||
|
||||
start: 0,
|
||||
@ -615,6 +834,7 @@ describe("parseStyle", () => {
|
||||
italic: false,
|
||||
underline: false,
|
||||
strikethrough: false,
|
||||
monospace: false,
|
||||
text: rawString,
|
||||
|
||||
start: 0,
|
||||
|
@ -239,6 +239,10 @@ describe("parse Handlebars helper", () => {
|
||||
name: "strikethrough",
|
||||
input: "\x1estrikethrough",
|
||||
expected: '<span class="irc-strikethrough">strikethrough</span>',
|
||||
}, {
|
||||
name: "monospace",
|
||||
input: "\x11monospace",
|
||||
expected: '<span class="irc-monospace">monospace</span>',
|
||||
}, {
|
||||
name: "resets",
|
||||
input: "\x02bold\x038yellow\x02nonBold\x03default",
|
||||
|
Loading…
Reference in New Issue
Block a user