serverless-ircd 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +6 -1
- package/.gitmodules +3 -0
- package/CHANGELOG.md +214 -0
- package/README.md +110 -23
- package/apps/aws-stack/package.json +1 -1
- package/apps/cf-tcp-container/package.json +1 -1
- package/apps/cf-worker/package.json +1 -1
- package/apps/cf-worker/src/origin-allowlist.ts +99 -0
- package/apps/cf-worker/src/worker.ts +89 -9
- package/apps/cf-worker/tests/fixtures/web-dist/app/index.html +18 -0
- package/apps/cf-worker/tests/fixtures/web-dist/index.html +18 -0
- package/apps/cf-worker/tests/origin-allowlist.test.ts +101 -0
- package/apps/cf-worker/tests/smoke.test.ts +28 -2
- package/apps/cf-worker/tests/ws-origin.test.ts +89 -0
- package/apps/cf-worker/wrangler.test.toml +23 -0
- package/apps/cf-worker/wrangler.toml +54 -0
- package/apps/local-cli/package.json +1 -1
- package/apps/web/landing/index.html +217 -0
- package/apps/web/package.json +28 -0
- package/apps/web/scripts/build.mjs +125 -0
- package/apps/web/src/build-env.ts +43 -0
- package/apps/web/src/config-schema.ts +138 -0
- package/apps/web/static/config.json +28 -0
- package/apps/web/static/config.prod.json +28 -0
- package/apps/web/static/config.staging.json +28 -0
- package/apps/web/tests/build-env.test.ts +63 -0
- package/apps/web/tests/build-smoke.test.ts +103 -0
- package/apps/web/tests/config-schema.test.ts +432 -0
- package/apps/web/tests/workspace.test.ts +12 -0
- package/apps/web/tsconfig.json +10 -0
- package/apps/web/upstream/.browserslistrc +3 -0
- package/apps/web/upstream/.editorconfig +9 -0
- package/apps/web/upstream/.eslintignore +3 -0
- package/apps/web/upstream/.eslintrc.js +90 -0
- package/apps/web/upstream/.github/FUNDING.yml +12 -0
- package/apps/web/upstream/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
- package/apps/web/upstream/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- package/apps/web/upstream/.github/workflows/push.yml +26 -0
- package/apps/web/upstream/.github/workflows/release.yml +33 -0
- package/apps/web/upstream/.github/workflows/release_manual.yml +55 -0
- package/apps/web/upstream/.prettierrc.js +9 -0
- package/apps/web/upstream/.stylelintignore +5 -0
- package/apps/web/upstream/.stylelintrc.js +21 -0
- package/apps/web/upstream/LICENSE +201 -0
- package/apps/web/upstream/README.md +76 -0
- package/apps/web/upstream/babel.config.js +25 -0
- package/apps/web/upstream/crowdin.yml +3 -0
- package/apps/web/upstream/index.html +35 -0
- package/apps/web/upstream/jest.config.js +7 -0
- package/apps/web/upstream/jsdoc.json +22 -0
- package/apps/web/upstream/package.json +80 -0
- package/apps/web/upstream/scripts/pre-commit +43 -0
- package/apps/web/upstream/src/components/App.vue +516 -0
- package/apps/web/upstream/src/components/AppSettings.vue +587 -0
- package/apps/web/upstream/src/components/AutoComplete.vue +284 -0
- package/apps/web/upstream/src/components/Avatar.vue +105 -0
- package/apps/web/upstream/src/components/AwayStatusIndicator.vue +77 -0
- package/apps/web/upstream/src/components/BufferKey.vue +121 -0
- package/apps/web/upstream/src/components/BufferSettings.vue +97 -0
- package/apps/web/upstream/src/components/Captcha.vue +85 -0
- package/apps/web/upstream/src/components/ChannelBanlist.vue +96 -0
- package/apps/web/upstream/src/components/ChannelInfo.vue +159 -0
- package/apps/web/upstream/src/components/ChannelInvitelist.vue +276 -0
- package/apps/web/upstream/src/components/ChannelList.vue +345 -0
- package/apps/web/upstream/src/components/Container.vue +401 -0
- package/apps/web/upstream/src/components/ContainerHeader.vue +522 -0
- package/apps/web/upstream/src/components/ControlInput.vue +1016 -0
- package/apps/web/upstream/src/components/LoadingAnimation.vue +104 -0
- package/apps/web/upstream/src/components/MediaViewer.vue +199 -0
- package/apps/web/upstream/src/components/MessageInfo.vue +192 -0
- package/apps/web/upstream/src/components/MessageList.vue +1028 -0
- package/apps/web/upstream/src/components/MessageListAvatar.vue +20 -0
- package/apps/web/upstream/src/components/MessageListMessageCompact.vue +361 -0
- package/apps/web/upstream/src/components/MessageListMessageInline.vue +257 -0
- package/apps/web/upstream/src/components/MessageListMessageModern.vue +430 -0
- package/apps/web/upstream/src/components/NetworkSettings.vue +528 -0
- package/apps/web/upstream/src/components/Nicklist.vue +309 -0
- package/apps/web/upstream/src/components/NicklistUser.vue +181 -0
- package/apps/web/upstream/src/components/NotConnected.vue +271 -0
- package/apps/web/upstream/src/components/SelfUser.vue +283 -0
- package/apps/web/upstream/src/components/ServerSelector.vue +162 -0
- package/apps/web/upstream/src/components/ServerView.vue +126 -0
- package/apps/web/upstream/src/components/SettingsAdvanced.vue +232 -0
- package/apps/web/upstream/src/components/SettingsAliases.vue +121 -0
- package/apps/web/upstream/src/components/Sidebar.vue +429 -0
- package/apps/web/upstream/src/components/SidebarAboutBuffer.vue +288 -0
- package/apps/web/upstream/src/components/SidebarState.vue +145 -0
- package/apps/web/upstream/src/components/StartupError.vue +35 -0
- package/apps/web/upstream/src/components/StateBrowser.vue +420 -0
- package/apps/web/upstream/src/components/StateBrowserBuffer.vue +124 -0
- package/apps/web/upstream/src/components/StateBrowserNetwork.vue +823 -0
- package/apps/web/upstream/src/components/StateBrowserUsermenu.vue +162 -0
- package/apps/web/upstream/src/components/TypingStatusIndicator.vue +34 -0
- package/apps/web/upstream/src/components/TypingUsersList.vue +56 -0
- package/apps/web/upstream/src/components/UrlEmbed.vue +149 -0
- package/apps/web/upstream/src/components/UserBox.vue +728 -0
- package/apps/web/upstream/src/components/inputtools/Emoji.vue +67 -0
- package/apps/web/upstream/src/components/inputtools/TextStyle.vue +142 -0
- package/apps/web/upstream/src/components/startups/CommonLayout.vue +208 -0
- package/apps/web/upstream/src/components/startups/CustomServer.vue +495 -0
- package/apps/web/upstream/src/components/startups/KiwiBnc.vue +361 -0
- package/apps/web/upstream/src/components/startups/Personal.vue +317 -0
- package/apps/web/upstream/src/components/startups/Welcome.vue +544 -0
- package/apps/web/upstream/src/components/startups/ZncLogin.vue +229 -0
- package/apps/web/upstream/src/components/utils/InputConfirm.vue +68 -0
- package/apps/web/upstream/src/components/utils/InputPrompt.vue +118 -0
- package/apps/web/upstream/src/components/utils/InputText.vue +172 -0
- package/apps/web/upstream/src/components/utils/IrcInput.vue +579 -0
- package/apps/web/upstream/src/components/utils/PluginWrapper.vue +26 -0
- package/apps/web/upstream/src/components/utils/TabbedView.vue +149 -0
- package/apps/web/upstream/src/components/utils/TransitionExpand.vue +97 -0
- package/apps/web/upstream/src/helpers/Colours.js +128 -0
- package/apps/web/upstream/src/helpers/IrcdDiffs.js +26 -0
- package/apps/web/upstream/src/helpers/Md5.js +193 -0
- package/apps/web/upstream/src/helpers/Misc.js +401 -0
- package/apps/web/upstream/src/helpers/TextFormatting.js +237 -0
- package/apps/web/upstream/src/libs/AliasRewriter.js +157 -0
- package/apps/web/upstream/src/libs/AudioManager.js +60 -0
- package/apps/web/upstream/src/libs/BouncerMiddleware.js +247 -0
- package/apps/web/upstream/src/libs/BouncerProvider.js +551 -0
- package/apps/web/upstream/src/libs/ChathistoryMiddleware.js +153 -0
- package/apps/web/upstream/src/libs/ConfigLoader.js +94 -0
- package/apps/web/upstream/src/libs/EmojiProvider.js +46 -0
- package/apps/web/upstream/src/libs/GlobalApi.js +346 -0
- package/apps/web/upstream/src/libs/IPC.js +51 -0
- package/apps/web/upstream/src/libs/InputHandler.js +921 -0
- package/apps/web/upstream/src/libs/IrcClient.js +1506 -0
- package/apps/web/upstream/src/libs/Logger.js +71 -0
- package/apps/web/upstream/src/libs/Message.js +169 -0
- package/apps/web/upstream/src/libs/MessageFormatter.js +364 -0
- package/apps/web/upstream/src/libs/MessageParser.js +249 -0
- package/apps/web/upstream/src/libs/Notifications.js +78 -0
- package/apps/web/upstream/src/libs/ServerConnection.js +270 -0
- package/apps/web/upstream/src/libs/ServerSession.js +102 -0
- package/apps/web/upstream/src/libs/SoundBleep.js +20 -0
- package/apps/web/upstream/src/libs/StatePersistence.js +90 -0
- package/apps/web/upstream/src/libs/ThemeManager.js +128 -0
- package/apps/web/upstream/src/libs/TypingMiddleware.js +105 -0
- package/apps/web/upstream/src/libs/WindowTitle.js +63 -0
- package/apps/web/upstream/src/libs/batchedAdd.js +74 -0
- package/apps/web/upstream/src/libs/bufferTools.js +177 -0
- package/apps/web/upstream/src/libs/polyfill/Element.closest.js +18 -0
- package/apps/web/upstream/src/libs/renderers/Html.js +113 -0
- package/apps/web/upstream/src/libs/settingTools.js +31 -0
- package/apps/web/upstream/src/libs/state/BufferState.js +703 -0
- package/apps/web/upstream/src/libs/state/NetworkState.js +158 -0
- package/apps/web/upstream/src/libs/state/UserState.js +89 -0
- package/apps/web/upstream/src/libs/state/common.js +26 -0
- package/apps/web/upstream/src/libs/state.js +961 -0
- package/apps/web/upstream/src/libs/storage/Local.js +51 -0
- package/apps/web/upstream/src/main.js +566 -0
- package/apps/web/upstream/src/res/autocompleteCommands.js +31 -0
- package/apps/web/upstream/src/res/configTemplates.js +373 -0
- package/apps/web/upstream/src/res/globalStyle.css +277 -0
- package/apps/web/upstream/src/res/kiwiLoadingLogo.png +0 -0
- package/apps/web/upstream/src/res/locales/app.af-ZA.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.ar-SA.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.bg-BG.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.bs-BA.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.ca-ES.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.cs-CZ.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.da-DK.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.de-DE.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.dev.po +1246 -0
- package/apps/web/upstream/src/res/locales/app.el-GR.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.en-US.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.es-419.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.es-AR.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.es-EM.po +536 -0
- package/apps/web/upstream/src/res/locales/app.es-ES.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.es-US.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.eu-ES.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.fi-FI.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.fr-FR.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.gl-ES.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.he-IL.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.hi-IN.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.hu-HU.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.id-ID.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.it-IT.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.ja-JP.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.ko-KR.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.nl-NL.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.no-NO.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.pl-PL.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.pt-BR.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.pt-PT.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.ro-RO.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.ru-RU.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.sl-SI.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.sq-AL.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.sr-SP.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.sv-SE.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.tr-TR.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.uk-UA.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.vi-VN.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.zh-CN.po +1145 -0
- package/apps/web/upstream/src/res/locales/app.zh-TW.po +1145 -0
- package/apps/web/upstream/src/res/localesList.json +27 -0
- package/apps/web/upstream/src/res/logo.png +0 -0
- package/apps/web/upstream/src/thirdparty/about.html +43 -0
- package/apps/web/upstream/src/thirdparty/index.js +5 -0
- package/apps/web/upstream/src/thirdparty/kiwiirccom.vue +185 -0
- package/apps/web/upstream/static/config.json +28 -0
- package/apps/web/upstream/static/emoticons/smile.png +0 -0
- package/apps/web/upstream/static/favicon.png +0 -0
- package/apps/web/upstream/static/highlight.mp3 +0 -0
- package/apps/web/upstream/static/highlight.ogg +0 -0
- package/apps/web/upstream/static/locales/.gitignore +2 -0
- package/apps/web/upstream/static/plugins/customise.html.example +10 -0
- package/apps/web/upstream/static/themes/coffee/theme.css +145 -0
- package/apps/web/upstream/static/themes/common/base.css +1064 -0
- package/apps/web/upstream/static/themes/dark/theme.css +196 -0
- package/apps/web/upstream/static/themes/default/theme.css +92 -0
- package/apps/web/upstream/static/themes/elite/theme.css +248 -0
- package/apps/web/upstream/static/themes/grayfox/theme.css +143 -0
- package/apps/web/upstream/static/themes/nightswatch/theme.css +367 -0
- package/apps/web/upstream/static/themes/osprey/theme.css +115 -0
- package/apps/web/upstream/static/themes/radioactive/theme.css +1211 -0
- package/apps/web/upstream/static/themes/sky/theme.css +107 -0
- package/apps/web/upstream/tests/unit/BatchAdd.spec.js +174 -0
- package/apps/web/upstream/tests/unit/MessageParser.spec.js +125 -0
- package/apps/web/upstream/tests/unit/Misc.spec.js +24 -0
- package/apps/web/upstream/tests/unit/NetworkState.spec.js +58 -0
- package/apps/web/upstream/tests/unit/StartupError.spec.js +20 -0
- package/apps/web/upstream/vue.config.js +150 -0
- package/apps/web/upstream/yarn.lock +9767 -0
- package/apps/web/vitest.config.ts +13 -0
- package/biome.json +1 -0
- package/docs/Home.md +1 -0
- package/docs/WebClientGuide.md +535 -0
- package/package.json +2 -2
- package/packages/aws-adapter/package.json +1 -1
- package/packages/cf-adapter/package.json +1 -1
- package/packages/cf-adapter/tests/cf-harness.ts +12 -1
- package/packages/in-memory-runtime/package.json +1 -1
- package/packages/irc-core/package.json +1 -1
- package/packages/irc-core/reports/mutation/mutation.html +342 -0
- package/packages/irc-core/tests/batch.test.ts +15 -0
- package/packages/irc-core/tests/numerics.test.ts +13 -0
- package/packages/irc-core/tests/parser.test.ts +109 -0
- package/packages/irc-server/package.json +1 -1
- package/packages/irc-test-support/package.json +1 -1
- package/packages/irc-test-support/src/scenarios.ts +24 -2
- package/tools/ci-hardening/package.json +1 -1
- package/tools/load-test/package.json +1 -1
- package/tools/tcp-ws-forwarder/package.json +1 -1
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
'kiwi public';
|
|
2
|
+
|
|
3
|
+
const defaultLogger = makeLogger();
|
|
4
|
+
export default defaultLogger;
|
|
5
|
+
|
|
6
|
+
function makeLogger(label, rootLogger) {
|
|
7
|
+
function logger(...args) {
|
|
8
|
+
logger.info(...args);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
logger.LEVEL_DEBUG = 2;
|
|
12
|
+
logger.LEVEL_INFO = 1;
|
|
13
|
+
logger.LEVEL_ERROR = 0;
|
|
14
|
+
logger.level = logger.LEVEL_ERROR;
|
|
15
|
+
|
|
16
|
+
function logLevel(compareLevel) {
|
|
17
|
+
let l = rootLogger || logger;
|
|
18
|
+
return l.level >= compareLevel;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
logger.debug = function logDebug(...args) {
|
|
22
|
+
if (logLevel(logger.LEVEL_DEBUG)) {
|
|
23
|
+
if (label) {
|
|
24
|
+
args[0] = `[${label}] DEBUG ${args[0]}`;
|
|
25
|
+
}
|
|
26
|
+
window.console.log(...args);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
logger.info = function logInfo(...args) {
|
|
31
|
+
if (logLevel(logger.LEVEL_INFO)) {
|
|
32
|
+
if (label) {
|
|
33
|
+
args[0] = `[${label}] INFO ${args[0]}`;
|
|
34
|
+
}
|
|
35
|
+
window.console.log(...args);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
logger.error = function logError(...args) {
|
|
40
|
+
if (logLevel(logger.LEVEL_ERROR)) {
|
|
41
|
+
if (label) {
|
|
42
|
+
args[0] = `[${label}] ERROR ${args[0]}`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
window.console.error(...args);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
logger.assert = function assert(condition, ...args) {
|
|
50
|
+
if (condition) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
this.error('Assertion failed.', ...args);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
logger.setLevel = function setLevel(newLevel) {
|
|
58
|
+
logger.level = newLevel;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
logger.namespace = function namespace(newLabel) {
|
|
62
|
+
let l = newLabel;
|
|
63
|
+
if (label) {
|
|
64
|
+
l = `[${label}][${l}]`;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return makeLogger(l, logger);
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
return logger;
|
|
71
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
'kiwi public';
|
|
2
|
+
|
|
3
|
+
import Vue from 'vue';
|
|
4
|
+
import parseMessage from '@/libs/MessageParser';
|
|
5
|
+
import toHtml from '@/libs/renderers/Html';
|
|
6
|
+
import GlobalApi from '@/libs/GlobalApi';
|
|
7
|
+
import getState from './state';
|
|
8
|
+
|
|
9
|
+
let nextId = 0;
|
|
10
|
+
|
|
11
|
+
function def(target, key, value) {
|
|
12
|
+
Object.defineProperty(target, key, {
|
|
13
|
+
writable: true,
|
|
14
|
+
value,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default class Message {
|
|
19
|
+
constructor(message, user) {
|
|
20
|
+
// instance_num is a running number for all messages created within Kiwi. Used to order
|
|
21
|
+
// messages if the message time is the same.
|
|
22
|
+
def(this, 'instance_num', nextId++);
|
|
23
|
+
def(this, 'id', extractMessageId(message) || nextId++);
|
|
24
|
+
|
|
25
|
+
// internal_time is used to allow for a getter/setter
|
|
26
|
+
// so day_num can be updated if the time is changed
|
|
27
|
+
def(this, 'internal_time', null);
|
|
28
|
+
def(this, 'day_num', null);
|
|
29
|
+
|
|
30
|
+
// Two different times;
|
|
31
|
+
// time = time in the users local time (getter/setter)
|
|
32
|
+
// server_time = time the server gave us
|
|
33
|
+
this.time = message.time || Date.now();
|
|
34
|
+
def(this, 'server_time', message.server_time || this.time);
|
|
35
|
+
def(this, 'nick', message.nick);
|
|
36
|
+
def(this, 'message', message.message);
|
|
37
|
+
def(this, 'tags', message.tags);
|
|
38
|
+
def(this, 'type', message.type || 'message');
|
|
39
|
+
def(this, 'type_extra', message.type_extra);
|
|
40
|
+
def(this, 'ignore', false);
|
|
41
|
+
def(this, 'mentioned_urls', []);
|
|
42
|
+
// If embed.payload is truthy, it will be embedded within the message
|
|
43
|
+
this.embed = { type: 'url', payload: null };
|
|
44
|
+
this.html = '';
|
|
45
|
+
this.blocks = [];
|
|
46
|
+
def(this, 'hasRendered', false);
|
|
47
|
+
// template should be null or a Vue component to render this message
|
|
48
|
+
def(this, 'template', message.template || null);
|
|
49
|
+
def(this, 'templateProps', message.templateProps || {});
|
|
50
|
+
// bodyTemplate should be null or a Vue component to render in the body of the message
|
|
51
|
+
def(this, 'bodyTemplate', message.bodyTemplate || null);
|
|
52
|
+
def(this, 'bodyTemplateProps', message.bodyTemplateProps || {});
|
|
53
|
+
def(this, 'isHighlight', false);
|
|
54
|
+
|
|
55
|
+
// We don't want the user object to be enumerable
|
|
56
|
+
Object.defineProperty(this, 'user', { value: user });
|
|
57
|
+
|
|
58
|
+
Vue.observable(this);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
get time() {
|
|
62
|
+
return this.internal_time;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
set time(newTime) {
|
|
66
|
+
this.internal_time = newTime;
|
|
67
|
+
// txOffset is the milliseconds needed to get localtime to UTC
|
|
68
|
+
// eg UTC+1 = -3,600,000
|
|
69
|
+
const tzOffset = (new Date(newTime)).getTimezoneOffset() * 60000;
|
|
70
|
+
// 68400000 equals one day in milliseconds
|
|
71
|
+
this.day_num = Math.floor((newTime - tzOffset) / 86400000);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
render() {
|
|
75
|
+
// Allow plugins to render their own messages if needed
|
|
76
|
+
GlobalApi.singleton().emit('message.render', { message: this });
|
|
77
|
+
return this;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
toHtml(messageList) {
|
|
81
|
+
if (this.hasRendered) {
|
|
82
|
+
return this.html;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
this.hasRendered = true;
|
|
86
|
+
|
|
87
|
+
let state = getState();
|
|
88
|
+
let showEmoticons = state.setting('buffers.show_emoticons') && !messageList.buffer.isSpecial();
|
|
89
|
+
|
|
90
|
+
this.toBlocks(messageList.buffer, messageList.useExtraFormatting);
|
|
91
|
+
|
|
92
|
+
state.$emit('message.prestyle', { message: this, blocks: this.blocks });
|
|
93
|
+
|
|
94
|
+
let content = toHtml(this.blocks, showEmoticons);
|
|
95
|
+
this.html = content;
|
|
96
|
+
|
|
97
|
+
state.$emit('message.poststyle', { message: this, blocks: this.blocks });
|
|
98
|
+
return this.html;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
toBlocks(buffer, useExtraFormatting) {
|
|
102
|
+
let state = getState();
|
|
103
|
+
let userList = buffer.users;
|
|
104
|
+
|
|
105
|
+
let blocks = parseMessage(
|
|
106
|
+
this.message,
|
|
107
|
+
{
|
|
108
|
+
extras: !buffer.isSpecial() && useExtraFormatting && this.type === 'privmsg',
|
|
109
|
+
},
|
|
110
|
+
userList
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
this.mentioned_urls = blocks.filter((block) => block.type === 'url').map((block) => block.meta.url);
|
|
114
|
+
this.maybeAutoEmbed();
|
|
115
|
+
|
|
116
|
+
state.$emit('message.blocks', { message: this, blocks: blocks });
|
|
117
|
+
this.blocks = blocks;
|
|
118
|
+
return blocks;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
maybeAutoEmbed() {
|
|
122
|
+
if (!this.mentioned_urls || this.mentioned_urls.length === 0) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Only auto preview links on user messages. Traffic, topics, notices, etc would get
|
|
127
|
+
// annoying as they usually contain links of some sort
|
|
128
|
+
if (this.type !== 'privmsg') {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
let url = this.mentioned_urls[0];
|
|
133
|
+
|
|
134
|
+
let whitelistRegex = getState().setting('buffers.inline_link_auto_preview_whitelist');
|
|
135
|
+
whitelistRegex = (whitelistRegex || '').trim();
|
|
136
|
+
try {
|
|
137
|
+
if (!whitelistRegex || !(new RegExp(whitelistRegex, 'i')).test(url)) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
} catch (err) {
|
|
141
|
+
// A bad regex pattern will throw an error
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
this.embed.payload = url;
|
|
146
|
+
this.embed.type = 'url';
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
serialise() {
|
|
150
|
+
return {
|
|
151
|
+
id: this.id,
|
|
152
|
+
time: this.time,
|
|
153
|
+
server_time: this.server_time,
|
|
154
|
+
nick: this.nick,
|
|
155
|
+
message: this.message,
|
|
156
|
+
tags: this.tags,
|
|
157
|
+
type: this.type,
|
|
158
|
+
type_extra: this.type_extra,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function extractMessageId(message) {
|
|
164
|
+
if (!message.tags) {
|
|
165
|
+
return undefined;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return message.tags.msgid || message.tags['draft/msgid'] || undefined;
|
|
169
|
+
}
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
'kiwi public';
|
|
2
|
+
|
|
3
|
+
const tokens = Object.create(null);
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Token functions may return:
|
|
7
|
+
* null - move forward in the input by the length of the token
|
|
8
|
+
* -1 - do not treat this character as a token and continue as normal content
|
|
9
|
+
* 0+ - move to this point in the input
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/* eslint-disable dot-notation */
|
|
13
|
+
tokens['_'] = {
|
|
14
|
+
token: '_',
|
|
15
|
+
extra: true,
|
|
16
|
+
fn: function parseToken(inp, pos, block, prevBlock, openToks) {
|
|
17
|
+
if (openToks[this.token]) {
|
|
18
|
+
delete block.styles.underline;
|
|
19
|
+
openToks[this.token] = null;
|
|
20
|
+
prevBlock.content += this.token;
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// If this style is alrady open by something else, ignore it
|
|
25
|
+
if (block.styles.underline === true) {
|
|
26
|
+
return -1;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Underscores may be part of a word or URL so consider it an opening
|
|
30
|
+
if (pos > 0 && inp[pos - 1] !== ' ') {
|
|
31
|
+
return -1;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// token if it's on it's own
|
|
35
|
+
// Only underline if we have a closing _ further on
|
|
36
|
+
if (inp.substr(pos + 1).indexOf(this.token) === -1) {
|
|
37
|
+
return -1;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
openToks[this.token] = true;
|
|
41
|
+
block.styles.underline = true;
|
|
42
|
+
block.content += this.token;
|
|
43
|
+
|
|
44
|
+
return null;
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
tokens['*'] = {
|
|
48
|
+
token: '*',
|
|
49
|
+
extra: true,
|
|
50
|
+
fn: function parseToken(inp, pos, block, prevBlock, openToks) {
|
|
51
|
+
if (openToks[this.token]) {
|
|
52
|
+
delete block.styles.italic;
|
|
53
|
+
openToks[this.token] = null;
|
|
54
|
+
prevBlock.content += this.token;
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// If this style is alrady open by something else, ignore it
|
|
59
|
+
if (block.styles.italic === true) {
|
|
60
|
+
return -1;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Ignore is after a : character. :* is usually a kiss emoji
|
|
64
|
+
if (inp[pos - 1] === ':') {
|
|
65
|
+
return -1;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// * may be part of a word (ie. pasting code) or URL so only start bolding if * is after a
|
|
69
|
+
// space
|
|
70
|
+
if (pos > 0 && inp[pos - 1] !== ' ') {
|
|
71
|
+
return -1;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Only style if:
|
|
75
|
+
// * we have a closing * further on
|
|
76
|
+
// * the * further on has a space after it or is the last character
|
|
77
|
+
let remainingText = inp.substr(pos + 1);
|
|
78
|
+
let nextPos = remainingText.indexOf(this.token);
|
|
79
|
+
if (
|
|
80
|
+
nextPos === -1 ||
|
|
81
|
+
(nextPos < remainingText.length - 1 && remainingText[nextPos + 1] !== ' ')
|
|
82
|
+
) {
|
|
83
|
+
return -1;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
openToks[this.token] = true;
|
|
87
|
+
block.styles.italic = true;
|
|
88
|
+
block.content += this.token;
|
|
89
|
+
|
|
90
|
+
return null;
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
tokens['**'] = {
|
|
94
|
+
token: '**',
|
|
95
|
+
extra: true,
|
|
96
|
+
fn: function parseToken(inp, pos, block, prevBlock, openToks) {
|
|
97
|
+
if (openToks[this.token]) {
|
|
98
|
+
delete block.styles.bold;
|
|
99
|
+
openToks[this.token] = null;
|
|
100
|
+
prevBlock.content += this.token;
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// If this style is alrady open by something else, ignore it
|
|
105
|
+
if (block.styles.bold === true) {
|
|
106
|
+
return -1;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Only style if we have a closing ** further on
|
|
110
|
+
if (inp.substr(pos + 1).indexOf(this.token) === -1) {
|
|
111
|
+
return -1;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
openToks[this.token] = true;
|
|
115
|
+
block.styles.bold = true;
|
|
116
|
+
block.content += this.token;
|
|
117
|
+
|
|
118
|
+
return null;
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
tokens['`'] = {
|
|
122
|
+
token: '`',
|
|
123
|
+
extra: true,
|
|
124
|
+
fn: function parseToken(inp, pos, block, prevBlock, openToks) {
|
|
125
|
+
if (openToks[this.token]) {
|
|
126
|
+
delete block.styles.quote;
|
|
127
|
+
openToks[this.token] = null;
|
|
128
|
+
prevBlock.content += this.token;
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Backticks may be part of a word or NICK so only consider it a codeblock if
|
|
133
|
+
// it's at the start of a scentence or comes after a space
|
|
134
|
+
if (pos > 0 && inp[pos - 1] !== ' ') {
|
|
135
|
+
return -1;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Find the closing backtick
|
|
139
|
+
let str = inp.substr(pos + 1);
|
|
140
|
+
let endPos = str.indexOf(this.token);
|
|
141
|
+
|
|
142
|
+
// If we don't have a closing backtick further on, don't take this as an opening backtick
|
|
143
|
+
if (endPos === -1) {
|
|
144
|
+
return -1;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Only consider the found closing backtick as closing if it comes before a space or is at
|
|
148
|
+
// the end of the text. If it's in the middle of text then it's highly lickely part of that
|
|
149
|
+
// text and not actually closing. eg. `hello and wel`come
|
|
150
|
+
if (str[endPos + 1] && str[endPos + 1] !== ' ') {
|
|
151
|
+
return -1;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// No styling should appear in this codeblock. Add all the content we can
|
|
155
|
+
// before jumping the position forward in the input
|
|
156
|
+
openToks[this.token] = true;
|
|
157
|
+
block.styles.quote = true;
|
|
158
|
+
block.content += this.token + str.substr(0, endPos);
|
|
159
|
+
block.containsContent = true;
|
|
160
|
+
// The + 1 because:
|
|
161
|
+
// We added 2 ` characters, but we want the last ` character to call this
|
|
162
|
+
// fn again so it can be closed.
|
|
163
|
+
return pos + endPos + 1;
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
// Bold
|
|
168
|
+
tokens['\x02'] = {
|
|
169
|
+
token: '\x02',
|
|
170
|
+
extra: false,
|
|
171
|
+
fn: function parseToken(inp, pos, block, prevBlock, openToks) {
|
|
172
|
+
if (openToks[this.token]) {
|
|
173
|
+
delete block.styles.bold;
|
|
174
|
+
openToks[this.token] = null;
|
|
175
|
+
} else {
|
|
176
|
+
openToks[this.token] = true;
|
|
177
|
+
block.styles.bold = true;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return null;
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
// Italic
|
|
185
|
+
tokens['\x1D'] = {
|
|
186
|
+
token: '\x1D',
|
|
187
|
+
extra: false,
|
|
188
|
+
fn: function parseToken(inp, pos, block, prevBlock, openToks) {
|
|
189
|
+
if (openToks[this.token]) {
|
|
190
|
+
delete block.styles.italic;
|
|
191
|
+
openToks[this.token] = null;
|
|
192
|
+
} else {
|
|
193
|
+
openToks[this.token] = true;
|
|
194
|
+
block.styles.italic = true;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return null;
|
|
198
|
+
},
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
// Underline
|
|
202
|
+
tokens['\x1F'] = {
|
|
203
|
+
token: '\x1F',
|
|
204
|
+
extra: false,
|
|
205
|
+
fn: function parseToken(inp, pos, block, prevBlock, openToks) {
|
|
206
|
+
if (openToks[this.token]) {
|
|
207
|
+
delete block.styles.underline;
|
|
208
|
+
openToks[this.token] = null;
|
|
209
|
+
} else {
|
|
210
|
+
openToks[this.token] = true;
|
|
211
|
+
block.styles.underline = true;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return null;
|
|
215
|
+
},
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
// Clear all styles
|
|
219
|
+
tokens['\x0F'] = {
|
|
220
|
+
token: '\x0F',
|
|
221
|
+
extra: false,
|
|
222
|
+
fn: function parseToken(inp, pos, block, prevBlock, openToks) {
|
|
223
|
+
Object.keys(block.styles).forEach((k) => delete block.styles[k]);
|
|
224
|
+
Object.keys(openToks).forEach((k) => delete openToks[k]);
|
|
225
|
+
|
|
226
|
+
return null;
|
|
227
|
+
},
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
// Colours
|
|
231
|
+
tokens['\x03'] = {
|
|
232
|
+
token: '\x03',
|
|
233
|
+
extra: false,
|
|
234
|
+
fn: function parseToken(inp, pos, block, prevBlock, openToks) {
|
|
235
|
+
let colours = {
|
|
236
|
+
0: 'white',
|
|
237
|
+
1: 'black',
|
|
238
|
+
2: 'blue',
|
|
239
|
+
3: 'green',
|
|
240
|
+
4: 'light-red',
|
|
241
|
+
5: 'brown',
|
|
242
|
+
6: 'purple',
|
|
243
|
+
7: 'orange',
|
|
244
|
+
8: 'yellow',
|
|
245
|
+
9: 'light-green',
|
|
246
|
+
10: 'cyan',
|
|
247
|
+
11: 'light-cyan',
|
|
248
|
+
12: 'light-blue',
|
|
249
|
+
13: 'pink',
|
|
250
|
+
14: 'grey',
|
|
251
|
+
15: 'light-grey',
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
let colourMatchRegexp = /^\x03(([0-9][0-9]?)(,([0-9][0-9]?))?)/;
|
|
255
|
+
let match = colourMatchRegexp.exec(inp.substr(pos, 6));
|
|
256
|
+
if (match) {
|
|
257
|
+
// fg colour = 2, bg colour = 4
|
|
258
|
+
let fgColour = colours[parseInt(match[2], 10)];
|
|
259
|
+
let bgColour = colours[parseInt(match[4], 10)];
|
|
260
|
+
if (typeof fgColour !== 'undefined') {
|
|
261
|
+
block.styles.color = fgColour;
|
|
262
|
+
}
|
|
263
|
+
if (typeof bgColour !== 'undefined') {
|
|
264
|
+
block.styles.background = bgColour;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return pos + match[0].length;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// 03 without a colour = delete any existing colour
|
|
271
|
+
delete block.styles.color;
|
|
272
|
+
delete block.styles.background;
|
|
273
|
+
|
|
274
|
+
return null;
|
|
275
|
+
},
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
// Reverse (unimplemented)
|
|
279
|
+
tokens['\x16'] = {
|
|
280
|
+
token: '\x16',
|
|
281
|
+
extra: false,
|
|
282
|
+
fn: function parseToken(inp, pos, block, prevBlock, openToks) {
|
|
283
|
+
return null;
|
|
284
|
+
},
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
export default function parse(inp, _opts) {
|
|
288
|
+
let opts = _opts || {};
|
|
289
|
+
let block = createNewBlock();
|
|
290
|
+
let blocks = [block];
|
|
291
|
+
let openTokens = Object.create(null);
|
|
292
|
+
|
|
293
|
+
let pos = 0;
|
|
294
|
+
let len = inp.length;
|
|
295
|
+
|
|
296
|
+
while (pos < len) {
|
|
297
|
+
let tok = findTokenAtPosition();
|
|
298
|
+
if (!tok || (!opts.extras && tok.extra)) {
|
|
299
|
+
block.content += inp[pos];
|
|
300
|
+
block.containsContent = true;
|
|
301
|
+
pos++;
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Current character is a token of some sort
|
|
306
|
+
|
|
307
|
+
let newBlock = null;
|
|
308
|
+
|
|
309
|
+
// Consecutive tokens can stack up styles into the same blocks. A consecutive
|
|
310
|
+
// token means that the block before it will not have any content yet
|
|
311
|
+
if (block.containsContent) {
|
|
312
|
+
newBlock = createNewBlock();
|
|
313
|
+
} else {
|
|
314
|
+
newBlock = block;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
Object.assign(newBlock.styles, block.styles);
|
|
318
|
+
let newPos = tok.fn(inp, pos, newBlock, block, openTokens);
|
|
319
|
+
|
|
320
|
+
if (newPos === -1) {
|
|
321
|
+
// The token invalidated itself so treat it as content
|
|
322
|
+
block.content += tok.token;
|
|
323
|
+
block.containsContent = true;
|
|
324
|
+
pos += tok.token.length;
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
block = newBlock;
|
|
329
|
+
|
|
330
|
+
// This block may have already been pushed if this is a consecutive token
|
|
331
|
+
if (blocks[blocks.length - 1] !== newBlock) {
|
|
332
|
+
blocks.push(newBlock);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (typeof newPos === 'number') {
|
|
336
|
+
pos = newPos;
|
|
337
|
+
} else {
|
|
338
|
+
pos += tok.token.length;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
return blocks;
|
|
343
|
+
|
|
344
|
+
function findTokenAtPosition() {
|
|
345
|
+
let tok = tokens[inp.substr(pos, 2)] || tokens[inp[pos]];
|
|
346
|
+
return tok;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
export function createNewBlock(
|
|
351
|
+
content = '',
|
|
352
|
+
styles = {},
|
|
353
|
+
type = 'text',
|
|
354
|
+
meta = {}
|
|
355
|
+
) {
|
|
356
|
+
const newBlock = {
|
|
357
|
+
styles: styles,
|
|
358
|
+
content: content,
|
|
359
|
+
containsContent: !!content,
|
|
360
|
+
type: type,
|
|
361
|
+
meta: meta,
|
|
362
|
+
};
|
|
363
|
+
return newBlock;
|
|
364
|
+
}
|