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.
Files changed (247) hide show
  1. package/.github/workflows/ci.yml +6 -1
  2. package/.gitmodules +3 -0
  3. package/CHANGELOG.md +214 -0
  4. package/README.md +110 -23
  5. package/apps/aws-stack/package.json +1 -1
  6. package/apps/cf-tcp-container/package.json +1 -1
  7. package/apps/cf-worker/package.json +1 -1
  8. package/apps/cf-worker/src/origin-allowlist.ts +99 -0
  9. package/apps/cf-worker/src/worker.ts +89 -9
  10. package/apps/cf-worker/tests/fixtures/web-dist/app/index.html +18 -0
  11. package/apps/cf-worker/tests/fixtures/web-dist/index.html +18 -0
  12. package/apps/cf-worker/tests/origin-allowlist.test.ts +101 -0
  13. package/apps/cf-worker/tests/smoke.test.ts +28 -2
  14. package/apps/cf-worker/tests/ws-origin.test.ts +89 -0
  15. package/apps/cf-worker/wrangler.test.toml +23 -0
  16. package/apps/cf-worker/wrangler.toml +54 -0
  17. package/apps/local-cli/package.json +1 -1
  18. package/apps/web/landing/index.html +217 -0
  19. package/apps/web/package.json +28 -0
  20. package/apps/web/scripts/build.mjs +125 -0
  21. package/apps/web/src/build-env.ts +43 -0
  22. package/apps/web/src/config-schema.ts +138 -0
  23. package/apps/web/static/config.json +28 -0
  24. package/apps/web/static/config.prod.json +28 -0
  25. package/apps/web/static/config.staging.json +28 -0
  26. package/apps/web/tests/build-env.test.ts +63 -0
  27. package/apps/web/tests/build-smoke.test.ts +103 -0
  28. package/apps/web/tests/config-schema.test.ts +432 -0
  29. package/apps/web/tests/workspace.test.ts +12 -0
  30. package/apps/web/tsconfig.json +10 -0
  31. package/apps/web/upstream/.browserslistrc +3 -0
  32. package/apps/web/upstream/.editorconfig +9 -0
  33. package/apps/web/upstream/.eslintignore +3 -0
  34. package/apps/web/upstream/.eslintrc.js +90 -0
  35. package/apps/web/upstream/.github/FUNDING.yml +12 -0
  36. package/apps/web/upstream/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
  37. package/apps/web/upstream/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  38. package/apps/web/upstream/.github/workflows/push.yml +26 -0
  39. package/apps/web/upstream/.github/workflows/release.yml +33 -0
  40. package/apps/web/upstream/.github/workflows/release_manual.yml +55 -0
  41. package/apps/web/upstream/.prettierrc.js +9 -0
  42. package/apps/web/upstream/.stylelintignore +5 -0
  43. package/apps/web/upstream/.stylelintrc.js +21 -0
  44. package/apps/web/upstream/LICENSE +201 -0
  45. package/apps/web/upstream/README.md +76 -0
  46. package/apps/web/upstream/babel.config.js +25 -0
  47. package/apps/web/upstream/crowdin.yml +3 -0
  48. package/apps/web/upstream/index.html +35 -0
  49. package/apps/web/upstream/jest.config.js +7 -0
  50. package/apps/web/upstream/jsdoc.json +22 -0
  51. package/apps/web/upstream/package.json +80 -0
  52. package/apps/web/upstream/scripts/pre-commit +43 -0
  53. package/apps/web/upstream/src/components/App.vue +516 -0
  54. package/apps/web/upstream/src/components/AppSettings.vue +587 -0
  55. package/apps/web/upstream/src/components/AutoComplete.vue +284 -0
  56. package/apps/web/upstream/src/components/Avatar.vue +105 -0
  57. package/apps/web/upstream/src/components/AwayStatusIndicator.vue +77 -0
  58. package/apps/web/upstream/src/components/BufferKey.vue +121 -0
  59. package/apps/web/upstream/src/components/BufferSettings.vue +97 -0
  60. package/apps/web/upstream/src/components/Captcha.vue +85 -0
  61. package/apps/web/upstream/src/components/ChannelBanlist.vue +96 -0
  62. package/apps/web/upstream/src/components/ChannelInfo.vue +159 -0
  63. package/apps/web/upstream/src/components/ChannelInvitelist.vue +276 -0
  64. package/apps/web/upstream/src/components/ChannelList.vue +345 -0
  65. package/apps/web/upstream/src/components/Container.vue +401 -0
  66. package/apps/web/upstream/src/components/ContainerHeader.vue +522 -0
  67. package/apps/web/upstream/src/components/ControlInput.vue +1016 -0
  68. package/apps/web/upstream/src/components/LoadingAnimation.vue +104 -0
  69. package/apps/web/upstream/src/components/MediaViewer.vue +199 -0
  70. package/apps/web/upstream/src/components/MessageInfo.vue +192 -0
  71. package/apps/web/upstream/src/components/MessageList.vue +1028 -0
  72. package/apps/web/upstream/src/components/MessageListAvatar.vue +20 -0
  73. package/apps/web/upstream/src/components/MessageListMessageCompact.vue +361 -0
  74. package/apps/web/upstream/src/components/MessageListMessageInline.vue +257 -0
  75. package/apps/web/upstream/src/components/MessageListMessageModern.vue +430 -0
  76. package/apps/web/upstream/src/components/NetworkSettings.vue +528 -0
  77. package/apps/web/upstream/src/components/Nicklist.vue +309 -0
  78. package/apps/web/upstream/src/components/NicklistUser.vue +181 -0
  79. package/apps/web/upstream/src/components/NotConnected.vue +271 -0
  80. package/apps/web/upstream/src/components/SelfUser.vue +283 -0
  81. package/apps/web/upstream/src/components/ServerSelector.vue +162 -0
  82. package/apps/web/upstream/src/components/ServerView.vue +126 -0
  83. package/apps/web/upstream/src/components/SettingsAdvanced.vue +232 -0
  84. package/apps/web/upstream/src/components/SettingsAliases.vue +121 -0
  85. package/apps/web/upstream/src/components/Sidebar.vue +429 -0
  86. package/apps/web/upstream/src/components/SidebarAboutBuffer.vue +288 -0
  87. package/apps/web/upstream/src/components/SidebarState.vue +145 -0
  88. package/apps/web/upstream/src/components/StartupError.vue +35 -0
  89. package/apps/web/upstream/src/components/StateBrowser.vue +420 -0
  90. package/apps/web/upstream/src/components/StateBrowserBuffer.vue +124 -0
  91. package/apps/web/upstream/src/components/StateBrowserNetwork.vue +823 -0
  92. package/apps/web/upstream/src/components/StateBrowserUsermenu.vue +162 -0
  93. package/apps/web/upstream/src/components/TypingStatusIndicator.vue +34 -0
  94. package/apps/web/upstream/src/components/TypingUsersList.vue +56 -0
  95. package/apps/web/upstream/src/components/UrlEmbed.vue +149 -0
  96. package/apps/web/upstream/src/components/UserBox.vue +728 -0
  97. package/apps/web/upstream/src/components/inputtools/Emoji.vue +67 -0
  98. package/apps/web/upstream/src/components/inputtools/TextStyle.vue +142 -0
  99. package/apps/web/upstream/src/components/startups/CommonLayout.vue +208 -0
  100. package/apps/web/upstream/src/components/startups/CustomServer.vue +495 -0
  101. package/apps/web/upstream/src/components/startups/KiwiBnc.vue +361 -0
  102. package/apps/web/upstream/src/components/startups/Personal.vue +317 -0
  103. package/apps/web/upstream/src/components/startups/Welcome.vue +544 -0
  104. package/apps/web/upstream/src/components/startups/ZncLogin.vue +229 -0
  105. package/apps/web/upstream/src/components/utils/InputConfirm.vue +68 -0
  106. package/apps/web/upstream/src/components/utils/InputPrompt.vue +118 -0
  107. package/apps/web/upstream/src/components/utils/InputText.vue +172 -0
  108. package/apps/web/upstream/src/components/utils/IrcInput.vue +579 -0
  109. package/apps/web/upstream/src/components/utils/PluginWrapper.vue +26 -0
  110. package/apps/web/upstream/src/components/utils/TabbedView.vue +149 -0
  111. package/apps/web/upstream/src/components/utils/TransitionExpand.vue +97 -0
  112. package/apps/web/upstream/src/helpers/Colours.js +128 -0
  113. package/apps/web/upstream/src/helpers/IrcdDiffs.js +26 -0
  114. package/apps/web/upstream/src/helpers/Md5.js +193 -0
  115. package/apps/web/upstream/src/helpers/Misc.js +401 -0
  116. package/apps/web/upstream/src/helpers/TextFormatting.js +237 -0
  117. package/apps/web/upstream/src/libs/AliasRewriter.js +157 -0
  118. package/apps/web/upstream/src/libs/AudioManager.js +60 -0
  119. package/apps/web/upstream/src/libs/BouncerMiddleware.js +247 -0
  120. package/apps/web/upstream/src/libs/BouncerProvider.js +551 -0
  121. package/apps/web/upstream/src/libs/ChathistoryMiddleware.js +153 -0
  122. package/apps/web/upstream/src/libs/ConfigLoader.js +94 -0
  123. package/apps/web/upstream/src/libs/EmojiProvider.js +46 -0
  124. package/apps/web/upstream/src/libs/GlobalApi.js +346 -0
  125. package/apps/web/upstream/src/libs/IPC.js +51 -0
  126. package/apps/web/upstream/src/libs/InputHandler.js +921 -0
  127. package/apps/web/upstream/src/libs/IrcClient.js +1506 -0
  128. package/apps/web/upstream/src/libs/Logger.js +71 -0
  129. package/apps/web/upstream/src/libs/Message.js +169 -0
  130. package/apps/web/upstream/src/libs/MessageFormatter.js +364 -0
  131. package/apps/web/upstream/src/libs/MessageParser.js +249 -0
  132. package/apps/web/upstream/src/libs/Notifications.js +78 -0
  133. package/apps/web/upstream/src/libs/ServerConnection.js +270 -0
  134. package/apps/web/upstream/src/libs/ServerSession.js +102 -0
  135. package/apps/web/upstream/src/libs/SoundBleep.js +20 -0
  136. package/apps/web/upstream/src/libs/StatePersistence.js +90 -0
  137. package/apps/web/upstream/src/libs/ThemeManager.js +128 -0
  138. package/apps/web/upstream/src/libs/TypingMiddleware.js +105 -0
  139. package/apps/web/upstream/src/libs/WindowTitle.js +63 -0
  140. package/apps/web/upstream/src/libs/batchedAdd.js +74 -0
  141. package/apps/web/upstream/src/libs/bufferTools.js +177 -0
  142. package/apps/web/upstream/src/libs/polyfill/Element.closest.js +18 -0
  143. package/apps/web/upstream/src/libs/renderers/Html.js +113 -0
  144. package/apps/web/upstream/src/libs/settingTools.js +31 -0
  145. package/apps/web/upstream/src/libs/state/BufferState.js +703 -0
  146. package/apps/web/upstream/src/libs/state/NetworkState.js +158 -0
  147. package/apps/web/upstream/src/libs/state/UserState.js +89 -0
  148. package/apps/web/upstream/src/libs/state/common.js +26 -0
  149. package/apps/web/upstream/src/libs/state.js +961 -0
  150. package/apps/web/upstream/src/libs/storage/Local.js +51 -0
  151. package/apps/web/upstream/src/main.js +566 -0
  152. package/apps/web/upstream/src/res/autocompleteCommands.js +31 -0
  153. package/apps/web/upstream/src/res/configTemplates.js +373 -0
  154. package/apps/web/upstream/src/res/globalStyle.css +277 -0
  155. package/apps/web/upstream/src/res/kiwiLoadingLogo.png +0 -0
  156. package/apps/web/upstream/src/res/locales/app.af-ZA.po +1145 -0
  157. package/apps/web/upstream/src/res/locales/app.ar-SA.po +1145 -0
  158. package/apps/web/upstream/src/res/locales/app.bg-BG.po +1145 -0
  159. package/apps/web/upstream/src/res/locales/app.bs-BA.po +1145 -0
  160. package/apps/web/upstream/src/res/locales/app.ca-ES.po +1145 -0
  161. package/apps/web/upstream/src/res/locales/app.cs-CZ.po +1145 -0
  162. package/apps/web/upstream/src/res/locales/app.da-DK.po +1145 -0
  163. package/apps/web/upstream/src/res/locales/app.de-DE.po +1145 -0
  164. package/apps/web/upstream/src/res/locales/app.dev.po +1246 -0
  165. package/apps/web/upstream/src/res/locales/app.el-GR.po +1145 -0
  166. package/apps/web/upstream/src/res/locales/app.en-US.po +1145 -0
  167. package/apps/web/upstream/src/res/locales/app.es-419.po +1145 -0
  168. package/apps/web/upstream/src/res/locales/app.es-AR.po +1145 -0
  169. package/apps/web/upstream/src/res/locales/app.es-EM.po +536 -0
  170. package/apps/web/upstream/src/res/locales/app.es-ES.po +1145 -0
  171. package/apps/web/upstream/src/res/locales/app.es-US.po +1145 -0
  172. package/apps/web/upstream/src/res/locales/app.eu-ES.po +1145 -0
  173. package/apps/web/upstream/src/res/locales/app.fi-FI.po +1145 -0
  174. package/apps/web/upstream/src/res/locales/app.fr-FR.po +1145 -0
  175. package/apps/web/upstream/src/res/locales/app.gl-ES.po +1145 -0
  176. package/apps/web/upstream/src/res/locales/app.he-IL.po +1145 -0
  177. package/apps/web/upstream/src/res/locales/app.hi-IN.po +1145 -0
  178. package/apps/web/upstream/src/res/locales/app.hu-HU.po +1145 -0
  179. package/apps/web/upstream/src/res/locales/app.id-ID.po +1145 -0
  180. package/apps/web/upstream/src/res/locales/app.it-IT.po +1145 -0
  181. package/apps/web/upstream/src/res/locales/app.ja-JP.po +1145 -0
  182. package/apps/web/upstream/src/res/locales/app.ko-KR.po +1145 -0
  183. package/apps/web/upstream/src/res/locales/app.nl-NL.po +1145 -0
  184. package/apps/web/upstream/src/res/locales/app.no-NO.po +1145 -0
  185. package/apps/web/upstream/src/res/locales/app.pl-PL.po +1145 -0
  186. package/apps/web/upstream/src/res/locales/app.pt-BR.po +1145 -0
  187. package/apps/web/upstream/src/res/locales/app.pt-PT.po +1145 -0
  188. package/apps/web/upstream/src/res/locales/app.ro-RO.po +1145 -0
  189. package/apps/web/upstream/src/res/locales/app.ru-RU.po +1145 -0
  190. package/apps/web/upstream/src/res/locales/app.sl-SI.po +1145 -0
  191. package/apps/web/upstream/src/res/locales/app.sq-AL.po +1145 -0
  192. package/apps/web/upstream/src/res/locales/app.sr-SP.po +1145 -0
  193. package/apps/web/upstream/src/res/locales/app.sv-SE.po +1145 -0
  194. package/apps/web/upstream/src/res/locales/app.tr-TR.po +1145 -0
  195. package/apps/web/upstream/src/res/locales/app.uk-UA.po +1145 -0
  196. package/apps/web/upstream/src/res/locales/app.vi-VN.po +1145 -0
  197. package/apps/web/upstream/src/res/locales/app.zh-CN.po +1145 -0
  198. package/apps/web/upstream/src/res/locales/app.zh-TW.po +1145 -0
  199. package/apps/web/upstream/src/res/localesList.json +27 -0
  200. package/apps/web/upstream/src/res/logo.png +0 -0
  201. package/apps/web/upstream/src/thirdparty/about.html +43 -0
  202. package/apps/web/upstream/src/thirdparty/index.js +5 -0
  203. package/apps/web/upstream/src/thirdparty/kiwiirccom.vue +185 -0
  204. package/apps/web/upstream/static/config.json +28 -0
  205. package/apps/web/upstream/static/emoticons/smile.png +0 -0
  206. package/apps/web/upstream/static/favicon.png +0 -0
  207. package/apps/web/upstream/static/highlight.mp3 +0 -0
  208. package/apps/web/upstream/static/highlight.ogg +0 -0
  209. package/apps/web/upstream/static/locales/.gitignore +2 -0
  210. package/apps/web/upstream/static/plugins/customise.html.example +10 -0
  211. package/apps/web/upstream/static/themes/coffee/theme.css +145 -0
  212. package/apps/web/upstream/static/themes/common/base.css +1064 -0
  213. package/apps/web/upstream/static/themes/dark/theme.css +196 -0
  214. package/apps/web/upstream/static/themes/default/theme.css +92 -0
  215. package/apps/web/upstream/static/themes/elite/theme.css +248 -0
  216. package/apps/web/upstream/static/themes/grayfox/theme.css +143 -0
  217. package/apps/web/upstream/static/themes/nightswatch/theme.css +367 -0
  218. package/apps/web/upstream/static/themes/osprey/theme.css +115 -0
  219. package/apps/web/upstream/static/themes/radioactive/theme.css +1211 -0
  220. package/apps/web/upstream/static/themes/sky/theme.css +107 -0
  221. package/apps/web/upstream/tests/unit/BatchAdd.spec.js +174 -0
  222. package/apps/web/upstream/tests/unit/MessageParser.spec.js +125 -0
  223. package/apps/web/upstream/tests/unit/Misc.spec.js +24 -0
  224. package/apps/web/upstream/tests/unit/NetworkState.spec.js +58 -0
  225. package/apps/web/upstream/tests/unit/StartupError.spec.js +20 -0
  226. package/apps/web/upstream/vue.config.js +150 -0
  227. package/apps/web/upstream/yarn.lock +9767 -0
  228. package/apps/web/vitest.config.ts +13 -0
  229. package/biome.json +1 -0
  230. package/docs/Home.md +1 -0
  231. package/docs/WebClientGuide.md +535 -0
  232. package/package.json +2 -2
  233. package/packages/aws-adapter/package.json +1 -1
  234. package/packages/cf-adapter/package.json +1 -1
  235. package/packages/cf-adapter/tests/cf-harness.ts +12 -1
  236. package/packages/in-memory-runtime/package.json +1 -1
  237. package/packages/irc-core/package.json +1 -1
  238. package/packages/irc-core/reports/mutation/mutation.html +342 -0
  239. package/packages/irc-core/tests/batch.test.ts +15 -0
  240. package/packages/irc-core/tests/numerics.test.ts +13 -0
  241. package/packages/irc-core/tests/parser.test.ts +109 -0
  242. package/packages/irc-server/package.json +1 -1
  243. package/packages/irc-test-support/package.json +1 -1
  244. package/packages/irc-test-support/src/scenarios.ts +24 -2
  245. package/tools/ci-hardening/package.json +1 -1
  246. package/tools/load-test/package.json +1 -1
  247. package/tools/tcp-ws-forwarder/package.json +1 -1
@@ -0,0 +1,823 @@
1
+ <template>
2
+ <div
3
+ :class="[
4
+ isActiveNetwork ? 'kiwi-statebrowser-network--active' : '',
5
+ ]" class="kiwi-statebrowser-network"
6
+ >
7
+ <div class="kiwi-statebrowser-network-header">
8
+ <a
9
+ class="kiwi-statebrowser-network-name u-link"
10
+ @click="setActiveBuffer(serverBuffer)"
11
+ >
12
+ {{ network.name }}
13
+ </a>
14
+ <div class="kiwi-statebrowser-buffer-actions">
15
+ <div class="kiwi-statebrowser-channel-labels">
16
+ <div
17
+ v-if="serverUnread && showMessageCounts(serverBuffer)"
18
+ :class="[
19
+ serverHighlight ?
20
+ 'kiwi-statebrowser-channel-label--highlight' :
21
+ ''
22
+ ]"
23
+ class="kiwi-statebrowser-channel-label"
24
+ >
25
+ {{ serverUnread > 999 ? "999+": serverUnread }}
26
+ </div>
27
+ </div>
28
+ </div>
29
+ <div class="kiwi-network-name-options">
30
+ <div
31
+ v-if="totalNetworkCount > 1"
32
+ class="kiwi-network-name-option kiwi-network-name-option-collapse"
33
+ @click="collapsed=!collapsed"
34
+ >
35
+ <i :class="[collapsed?'fa-plus-square-o':'fa-minus-square-o']" class="fa" />
36
+ </div>
37
+ </div>
38
+ </div>
39
+
40
+ <transition-expand>
41
+ <div v-if="channel_filter_display" class="kiwi-statebrowser-channelfilter">
42
+ <input
43
+ v-model="channel_filter"
44
+ v-focus
45
+ :placeholder="$t('filter_channels')"
46
+ type="text"
47
+ @blur="onChannelFilterInputBlur"
48
+ @keyup.esc="closeFilterChannel"
49
+ >
50
+ <p>
51
+ <a @click="closeFilterChannel(); showNetworkChannels(network)">
52
+ {{ $t('find_more_channels') }}
53
+ </a>
54
+ </p>
55
+ </div>
56
+ <div v-if="channel_add_display" class="kiwi-statebrowser-channels-info">
57
+ <form
58
+ class="kiwi-statebrowser-newchannel"
59
+ @submit.prevent="submitNewChannelForm"
60
+ >
61
+ <div
62
+ v-focus
63
+ :class="[
64
+ channel_add_input_has_focus ?
65
+ 'kiwi-statebrowser-newchannel-inputwrap--focus' :
66
+ ''
67
+ ]"
68
+ class="kiwi-statebrowser-newchannel-inputwrap"
69
+ >
70
+ <input
71
+ v-model="channel_add_input"
72
+ :placeholder="$t('state_join')"
73
+ type="text"
74
+ @focus="onNewChannelInputFocus"
75
+ @blur="onNewChannelInputBlur"
76
+ >
77
+ </div>
78
+ </form>
79
+ </div>
80
+ </transition-expand>
81
+
82
+ <div
83
+ :class="[
84
+ collapsed ? 'kiwi-statebrowser-network-toggable-area--collapsed' : '',
85
+ ]" class="kiwi-statebrowser-network-toggable-area"
86
+ >
87
+ <transition-expand>
88
+ <div v-if="network.state !== 'connected'" class="kiwi-statebrowser-network-status">
89
+ <template v-if="network.state_error">
90
+ <i class="fa fa-exclamation-triangle" aria-hidden="true" />
91
+ <a class="u-link" @click="showNetworkSettings(network)">
92
+ {{ $t('state_configure') }}
93
+ </a>
94
+ </template>
95
+ <template v-else-if="!network.connection.server">
96
+ <a class="u-link" @click="showNetworkSettings(network)">
97
+ {{ $t('state_configure') }}
98
+ </a>
99
+ </template>
100
+ <template v-else-if="network.state === 'disconnected'">
101
+ {{ $t('state_disconnected') }}
102
+ <a class="u-link" @click="network.ircClient.connect()">
103
+ {{ $t('connect') }}
104
+ </a>
105
+ </template>
106
+ <template v-else-if="network.state === 'connecting'">
107
+ {{ $t('connecting') }}
108
+ </template>
109
+ </div>
110
+ <div
111
+ v-if="!showBufferGroups && !channel_filter_display && !channel_add_display"
112
+ class="kiwi-statebrowser-network-options"
113
+ >
114
+ <div
115
+ :class="{ active: !!channel_add_display }"
116
+ class="kiwi-statebrowser-network-option"
117
+ @click="toggleAddChannel()"
118
+ >
119
+ <i class="fa fa-plus" aria-hidden="true" />
120
+ </div>
121
+ <div
122
+ :class="{ active: !!channel_filter_display }"
123
+ class="kiwi-statebrowser-network-option"
124
+ @click="onSearchChannelClick()"
125
+ >
126
+ <i class="fa fa-search" aria-hidden="true" />
127
+ </div>
128
+ </div>
129
+ </transition-expand>
130
+ <div
131
+ v-for="(itemBuffers, type) in filteredBuffersByType"
132
+ :key="type"
133
+ :data-name="type"
134
+ class="kiwi-statebrowser-buffers"
135
+ >
136
+ <div
137
+ v-if="!channel_filter_display && showBufferGroups && type !== 'other'"
138
+ class="kiwi-statebrowser-channels-header"
139
+ >
140
+ <div class="kiwi-statebrowser-buffertype" @click="toggleSection(type)">
141
+ <i
142
+ class="fa kiwi-statebrowser-channels-toggle"
143
+ :class="[
144
+ (show_channels && type === 'channels') ||
145
+ (show_queries && type === 'queries') ?
146
+ 'fa-caret-down' :
147
+ 'fa-caret-right'
148
+ ]"
149
+ />
150
+ {{ type === 'channels' ? $t('channels') : $t('messages') }}
151
+ </div>
152
+
153
+ <div v-if="type === 'channels'" class="kiwi-statebrowser-channels-options">
154
+ <div
155
+ :class="{ active: !!channel_add_display }"
156
+ class="kiwi-statebrowser-channels-option"
157
+ @click="toggleAddChannel()"
158
+ >
159
+ <i class="fa fa-plus" aria-hidden="true" />
160
+ </div>
161
+ <div
162
+ :class="{ active: !!channel_filter_display }"
163
+ class="kiwi-statebrowser-channels-option"
164
+ @click="onSearchChannelClick()"
165
+ >
166
+ <i class="fa fa-search" aria-hidden="true" />
167
+ </div>
168
+ </div>
169
+ <div v-else-if="type === 'queries'" class="kiwi-statebrowser-channels-options">
170
+ <div
171
+ v-if="itemBuffers.length > 1"
172
+ class="kiwi-statebrowser-channels-option
173
+ kiwi-statebrowser-queries-close"
174
+ @click.stop.prevent="promptClose()"
175
+ >
176
+ <i class="fa fa-times" aria-hidden="true" />
177
+ </div>
178
+ </div>
179
+ <div class="kiwi-statebrowser-buffer-actions">
180
+ <div class="kiwi-statebrowser-channel-labels">
181
+ <div
182
+ v-if="!show_channels &&
183
+ type === 'channels' &&
184
+ channelActivity.unread > 0"
185
+
186
+ :class="[
187
+ channelActivity.highlights ?
188
+ 'kiwi-statebrowser-channel-label--highlight' :
189
+ ''
190
+ ]"
191
+ class="kiwi-statebrowser-channel-label"
192
+ >
193
+ {{ channelActivity.unread > 999 ?
194
+ '999+' : channelActivity.unread }}
195
+ </div>
196
+ <div
197
+ v-else-if="!show_queries &&
198
+ type === 'queries' &&
199
+ queryActivity.unread > 0"
200
+
201
+ :class="[
202
+ queryActivity.highlights ?
203
+ 'kiwi-statebrowser-channel-label--highlight' :
204
+ ''
205
+ ]"
206
+ class="kiwi-statebrowser-channel-label"
207
+ >
208
+ {{ queryActivity.unread > 999 ?
209
+ '999+' : queryActivity.unread }}
210
+ </div>
211
+ </div>
212
+ </div>
213
+ </div>
214
+ <transition-expand v-if="type === 'queries'">
215
+ <div v-if="showPromptClose" class="kiwi-statebrowser-prompt-close">
216
+ <span>{{ $t('prompt_close_queries') }}</span>
217
+ <input-confirm
218
+ :flip-connotation="true"
219
+ @ok="closeQueries(itemBuffers)"
220
+ @submit="promptClose()"
221
+ />
222
+ </div>
223
+ </transition-expand>
224
+ <transition-expand>
225
+ <div
226
+ v-if="itemBuffers.length && (
227
+ (show_channels && type === 'channels') ||
228
+ (show_queries && type === 'queries') ||
229
+ type === 'other'
230
+ )"
231
+ class="kiwi-statebrowser-buffers-container"
232
+ >
233
+ <buffer
234
+ v-for="buffer in itemBuffers"
235
+ :key="buffer.name"
236
+ :buffer="buffer"
237
+ :active-prompt="activePrompt"
238
+ @selected="setActiveBuffer(buffer)"
239
+ />
240
+ </div>
241
+ </transition-expand>
242
+ </div>
243
+ </div>
244
+ </div>
245
+ </template>
246
+
247
+ <script>
248
+ 'kiwi public';
249
+
250
+ import _ from 'lodash';
251
+ import * as Misc from '@/helpers/Misc';
252
+ import * as bufferTools from '@/libs/bufferTools';
253
+ import BufferSettings from './BufferSettings';
254
+ import StateBrowserBuffer from './StateBrowserBuffer';
255
+
256
+ export default {
257
+ components: {
258
+ BufferSettings,
259
+ Buffer: StateBrowserBuffer,
260
+ },
261
+ props: ['network', 'sidebarState', 'activePrompt'],
262
+ data: function data() {
263
+ return {
264
+ collapsed: false,
265
+ channel_filter: '',
266
+ channel_filter_display: false,
267
+ channel_add_display: false,
268
+ channel_add_input_has_focus: false,
269
+ channel_add_input: '',
270
+ show_channels: true,
271
+ show_queries: true,
272
+ };
273
+ },
274
+ computed: {
275
+ serverBuffer() {
276
+ return this.network.serverBuffer();
277
+ },
278
+ isActiveNetwork: function isActiveNetwork() {
279
+ return this.$state.getActiveNetwork() === this.network;
280
+ },
281
+ totalNetworkCount() {
282
+ return this.$state.networks.length;
283
+ },
284
+ serverUnread() {
285
+ if (!this.collapsed) {
286
+ return this.serverBuffer.flags.unread;
287
+ }
288
+ let totalUnread = 0;
289
+ this.network.buffers.forEach((buffer) => {
290
+ if (buffer.isSpecial()) {
291
+ return;
292
+ }
293
+ totalUnread += buffer.flags.unread;
294
+ });
295
+ return totalUnread;
296
+ },
297
+ serverHighlight() {
298
+ if (!this.collapsed) {
299
+ return this.serverBuffer.flags.highlight;
300
+ }
301
+ let highlight = false;
302
+ this.network.buffers.forEach((buffer) => {
303
+ if (buffer.isSpecial()) {
304
+ return;
305
+ }
306
+ if (buffer.flags.highlight) {
307
+ highlight = true;
308
+ }
309
+ });
310
+ return highlight;
311
+ },
312
+ filteredBuffers() {
313
+ let filter = this.channel_filter;
314
+ let filtered = [];
315
+
316
+ if (!filter) {
317
+ filtered = this.network.buffers;
318
+ } else {
319
+ filtered = _.filter(this.network.buffers, (buffer) => {
320
+ let name = buffer.name.toLowerCase();
321
+ return name.indexOf(filter) > -1;
322
+ });
323
+ }
324
+
325
+ return bufferTools.orderBuffers(filtered);
326
+ },
327
+ filteredBuffersByType() {
328
+ let types = {
329
+ other: [],
330
+ channels: [],
331
+ queries: [],
332
+ };
333
+
334
+ this.filteredBuffers.forEach((bufferObj) => {
335
+ if (bufferObj.isChannel()) {
336
+ types.channels.push(bufferObj);
337
+ } else if (bufferObj.isQuery()) {
338
+ types.queries.push(bufferObj);
339
+ } else {
340
+ // This is buffers like *raw, *bnc, *status etc
341
+ types.other.push(bufferObj);
342
+ }
343
+ });
344
+
345
+ Object.entries(types).forEach(([type, buffers]) => {
346
+ // Always show channels type as it has join controls
347
+ if (type !== 'channels' && !buffers.length) {
348
+ delete types[type];
349
+ }
350
+ });
351
+
352
+ return types;
353
+ },
354
+ channelActivity() {
355
+ return this.activityFromBuffers(this.filteredBuffersByType.channels);
356
+ },
357
+ queryActivity() {
358
+ return this.activityFromBuffers(this.filteredBuffersByType.queries);
359
+ },
360
+ showBufferGroups() {
361
+ return this.$state.setting('buffers.show_buffer_groups');
362
+ },
363
+ showPromptClose() {
364
+ return (this.activePrompt &&
365
+ this.activePrompt.type === 'queries' &&
366
+ this.activePrompt.value === this.network);
367
+ },
368
+ },
369
+ methods: {
370
+ activityFromBuffers(buffers) {
371
+ let totalUnread = 0;
372
+ let highlight = false;
373
+ buffers.forEach((buffer) => {
374
+ if (buffer.isSpecial() || buffer.setting('hide_message_counts')) {
375
+ return;
376
+ }
377
+ totalUnread += buffer.flags.unread;
378
+ if (!highlight && buffer.flags.highlight) {
379
+ highlight = true;
380
+ }
381
+ });
382
+ return {
383
+ highlights: highlight,
384
+ unread: totalUnread,
385
+ };
386
+ },
387
+ onNewChannelInputFocus() {
388
+ // Auto insert the # if no value is already in. Easier for mobile users
389
+ if (!this.channel_add_input) {
390
+ this.channel_add_input = '#';
391
+ }
392
+
393
+ this.channel_add_input_has_focus = true;
394
+ },
395
+ onNewChannelInputBlur() {
396
+ // Remove the # since we may have auto inserted it as they tabbed past
397
+ if (this.channel_add_input === '#') {
398
+ this.channel_add_input = '';
399
+ }
400
+
401
+ // If nothing was entered into the input box, hide it just to clean up the UI
402
+ if (!this.channel_add_input) {
403
+ this.channel_add_display = false;
404
+ }
405
+
406
+ this.channel_add_input_has_focus = false;
407
+ },
408
+ submitNewChannelForm() {
409
+ let newChannelVal = this.channel_add_input;
410
+ this.channel_add_input = '#';
411
+
412
+ let network = this.network;
413
+ let bufferObjs = Misc.extractBuffers(newChannelVal);
414
+
415
+ // Only switch to the first channel we join if multiple are being joined
416
+ let hasSwitchedActiveBuffer = false;
417
+ bufferObjs.forEach((bufferObj) => {
418
+ let chanName = bufferObj.name;
419
+ let ignoreNames = ['#0', '0', '&0'];
420
+ if (ignoreNames.indexOf(chanName) > -1 || chanName.replace(/[#&]/g, '') === '') {
421
+ return;
422
+ }
423
+
424
+ let newBuffer = this.$state.addBuffer(network.id, chanName);
425
+ if (newBuffer && !hasSwitchedActiveBuffer) {
426
+ this.$state.setActiveBuffer(network.id, newBuffer.name);
427
+ hasSwitchedActiveBuffer = true;
428
+ }
429
+
430
+ if (bufferObj.key) {
431
+ newBuffer.key = bufferObj.key;
432
+ }
433
+
434
+ if (network.isChannelName(chanName)) {
435
+ network.ircClient.join(chanName, bufferObj.key);
436
+ }
437
+ });
438
+ },
439
+ onChannelFilterInputBlur() {
440
+ // Hacky, but if we remove the channel filter UI at this blur event and the user
441
+ // clicked a link in this filter UI, then the click event will not hit the target
442
+ // link as it has been removed before the event reaches it.
443
+ setTimeout(() => {
444
+ this.closeFilterChannel();
445
+ }, 200);
446
+ },
447
+ showMessageCounts(buffer) {
448
+ return !buffer.setting('hide_message_counts');
449
+ },
450
+ setActiveBuffer(buffer) {
451
+ // Clear any active component to show the buffer again
452
+ this.$state.$emit('active.component', null);
453
+ this.$state.setActiveBuffer(buffer.networkid, buffer.name);
454
+ if (this.$state.ui.is_narrow) {
455
+ this.$state.$emit('statebrowser.hide');
456
+ }
457
+ },
458
+ showNetworkSettings(network) {
459
+ network.showServerBuffer('settings');
460
+ if (this.$state.ui.is_narrow) {
461
+ this.$state.$emit('statebrowser.hide');
462
+ }
463
+ },
464
+ showNetworkChannels(network) {
465
+ network.showServerBuffer('channels');
466
+ if (this.$state.ui.is_narrow) {
467
+ this.$state.$emit('statebrowser.hide');
468
+ }
469
+ },
470
+ onSearchChannelClick() {
471
+ // If we have no other buffers than the server buffer, take them straight
472
+ // to the channel list for searching
473
+ if (this.network.buffers.length > 1) {
474
+ this.toggleFilterChannel();
475
+ } else {
476
+ this.network.showServerBuffer('channels');
477
+ }
478
+ },
479
+ toggleAddChannel() {
480
+ this.channel_add_display = !this.channel_add_display;
481
+ this.channel_filter_display = false;
482
+ },
483
+ toggleFilterChannel() {
484
+ this.channel_filter_display = !this.channel_filter_display;
485
+ this.channel_add_display = false;
486
+ },
487
+ toggleSection(type) {
488
+ if (type === 'channels') {
489
+ this.show_channels = !this.show_channels;
490
+ } else if (type === 'queries') {
491
+ this.show_queries = !this.show_queries;
492
+ }
493
+ },
494
+ promptClose() {
495
+ const prompt = this.activePrompt;
496
+ if (this.showPromptClose) {
497
+ // Prompt is currently visible so close it
498
+ prompt.type = undefined;
499
+ prompt.value = undefined;
500
+ } else {
501
+ prompt.type = 'queries';
502
+ prompt.value = this.network;
503
+ }
504
+ },
505
+ closeQueries(buffers) {
506
+ buffers.forEach((buffer) => {
507
+ this.$state.removeBuffer(buffer);
508
+ });
509
+ },
510
+ closeFilterChannel() {
511
+ this.channel_filter = '';
512
+ this.channel_filter_display = false;
513
+ },
514
+ },
515
+ };
516
+ </script>
517
+
518
+ <style>
519
+ .kiwi-channel-options-header {
520
+ text-align: left;
521
+ padding: 0 0 0 10px;
522
+ margin: 0;
523
+ opacity: 1;
524
+ cursor: default;
525
+ float: left;
526
+ width: 100%;
527
+ box-sizing: border-box;
528
+ }
529
+
530
+ .kiwi-channel-options-header span {
531
+ padding: 5px 0;
532
+ float: left;
533
+ font-size: 1.2em;
534
+ font-weight: 600;
535
+ }
536
+
537
+ .kiwi-statebrowser-network-header {
538
+ display: block;
539
+ padding-right: 0;
540
+ position: relative;
541
+ overflow: hidden;
542
+ height: auto;
543
+ box-sizing: border-box;
544
+ }
545
+
546
+ .kiwi-statebrowser-network-name {
547
+ flex: 1;
548
+ font-size: 1.1em;
549
+ text-align: center;
550
+ display: block;
551
+ padding: 4px 0;
552
+ box-sizing: border-box;
553
+ overflow-x: hidden;
554
+ white-space: nowrap;
555
+ text-overflow: ellipsis;
556
+ }
557
+
558
+ .kiwi-network-name-options {
559
+ position: absolute;
560
+ top: 0;
561
+ height: 45px;
562
+ z-index: 10;
563
+ right: -300px;
564
+ transition: all 0.15s;
565
+ }
566
+
567
+ .kiwi-statebrowser-network-header:hover .kiwi-network-name-options {
568
+ right: 0;
569
+ opacity: 1;
570
+ }
571
+
572
+ .kiwi-network-name-option {
573
+ float: right;
574
+ width: 35px;
575
+ transition: all 0.15s;
576
+ padding: 0;
577
+ line-height: 45px;
578
+ text-align: center;
579
+ cursor: pointer;
580
+ }
581
+
582
+ .kiwi-statebrowser-network-toggable-area--collapsed {
583
+ display: none;
584
+ }
585
+
586
+ .kiwi-statebrowser-network-status {
587
+ text-align: center;
588
+ padding: 4px 4px 6px 4px;
589
+ overflow: hidden;
590
+ position: relative;
591
+ height: 1.5em;
592
+ font-size: 0.9em;
593
+ }
594
+
595
+ .kiwi-statebrowser-network-options {
596
+ line-height: 1em;
597
+ text-align: right;
598
+ }
599
+
600
+ .kiwi-statebrowser-network-option {
601
+ display: inline-block;
602
+ width: 38px;
603
+ line-height: 30px;
604
+ text-align: center;
605
+ cursor: pointer;
606
+ opacity: 0.8;
607
+ -webkit-transition: opacity 0.2s;
608
+ transition: opacity 0.2s;
609
+ }
610
+
611
+ .kiwi-statebrowser-channels-header {
612
+ line-height: 35px;
613
+ display: flex;
614
+ font-size: 0.8em;
615
+ text-transform: uppercase;
616
+ cursor: pointer;
617
+ }
618
+
619
+ .kiwi-statebrowser-channels-toggle {
620
+ width: 10px;
621
+ line-height: 35px;
622
+ }
623
+
624
+ .kiwi-statebrowser-channels-option {
625
+ display: inline-block;
626
+ width: 35px;
627
+ line-height: 35px;
628
+ text-align: center;
629
+ cursor: pointer;
630
+ opacity: 0.8;
631
+ transition: opacity 0.2s;
632
+ }
633
+
634
+ .kiwi-statebrowser-channels-option:hover {
635
+ opacity: 1;
636
+ }
637
+
638
+ .kiwi-statebrowser-channel {
639
+ position: relative;
640
+ display: flex;
641
+ border-left: 3px solid transparent;
642
+ }
643
+
644
+ .kiwi-statebrowser-channel:hover .kiwi-statebrowser-channel-name {
645
+ text-decoration: underline;
646
+ }
647
+
648
+ .kiwi-statebrowser-channel-name,
649
+ .kiwi-statebrowser-buffertype {
650
+ cursor: pointer;
651
+ flex: 1;
652
+ word-break: break-all;
653
+ text-align: left;
654
+ margin-left: 5px;
655
+ user-select: none;
656
+ transition: padding 0.1s, border 0.1s;
657
+ }
658
+
659
+ /* Contains the labels and close icons */
660
+ .kiwi-statebrowser-buffer-actions {
661
+ flex: 0;
662
+ }
663
+
664
+ .kiwi-statebrowser-channel-labels {
665
+ height: 100%;
666
+ line-height: 1em;
667
+ display: flex;
668
+ box-sizing: border-box;
669
+ }
670
+
671
+ .kiwi-statebrowser-channel-label {
672
+ padding: 0 10px;
673
+ margin: 5px;
674
+ font-weight: 600;
675
+ border-radius: 4px;
676
+
677
+ /* Vertical+horizontaly center align text */
678
+ display: flex;
679
+ text-align: center;
680
+ align-items: center;
681
+ }
682
+
683
+ .kiwi-statebrowser-network-header .kiwi-statebrowser-buffer-actions {
684
+ padding-right: 10px;
685
+ }
686
+
687
+ .kiwi-statebrowser-network-header .kiwi-statebrowser-channel-label {
688
+ margin: 10px 0 10px 10px;
689
+ }
690
+
691
+ .kiwi-statebrowser-channel-leave {
692
+ width: 38px; /* Visualy the same width as a single digit label */
693
+ cursor: pointer;
694
+ margin-right: 0;
695
+ z-index: 10;
696
+ display: none;
697
+ }
698
+
699
+ .kiwi-statebrowser-prompt-close,
700
+ .kiwi-statebrowser-prompt-close .u-input-confirm {
701
+ padding-top: 6px;
702
+ display: block;
703
+ }
704
+
705
+ /*
706
+ Hovering over the buffer name should show the close icon, but hide labels
707
+ An active buffer should always show the close icon
708
+ */
709
+ .kiwi-statebrowser-channel:hover .kiwi-statebrowser-channel-leave,
710
+ .kiwi-statebrowser-channel-active .kiwi-statebrowser-channel-leave {
711
+ display: block;
712
+ }
713
+
714
+ .kiwi-statebrowser-channel:hover .kiwi-statebrowser-channel-labels,
715
+ .kiwi-statebrowser-channel-active .kiwi-statebrowser-channel-labels {
716
+ display: none;
717
+ }
718
+
719
+ /* Add channel input */
720
+ .kiwi-statebrowser-newchannel-inputwrap {
721
+ position: relative;
722
+ opacity: 1;
723
+ transition: opacity 0.3s;
724
+ background: none;
725
+ padding: 0;
726
+ margin: 0 0 0 0;
727
+ box-sizing: border-box;
728
+ }
729
+
730
+ .kiwi-statebrowser-newchannel-inputwrap input[type='text'] {
731
+ width: 100%;
732
+ height: 40px;
733
+ padding: 0 15px;
734
+ line-height: 40px;
735
+ font-size: 0.8em;
736
+ box-sizing: border-box;
737
+ border: none;
738
+ margin: 0;
739
+ border-radius: 0;
740
+ min-height: none;
741
+ overflow-x: hidden;
742
+ overflow-y: auto;
743
+ max-width: none;
744
+ }
745
+
746
+ .kiwi-statebrowser-newchannel-inputwrap--focus {
747
+ opacity: 1;
748
+ }
749
+
750
+ /* Channel search input */
751
+ .kiwi-statebrowser-channelfilter {
752
+ width: 100%;
753
+ padding: 0;
754
+ box-sizing: border-box;
755
+ position: relative;
756
+ opacity: 1;
757
+ transition: all 0.3s;
758
+ margin-bottom: 0;
759
+ }
760
+
761
+ .kiwi-statebrowser-channelfilter:hover {
762
+ opacity: 1;
763
+ }
764
+
765
+ .kiwi-statebrowser-channelfilter input {
766
+ width: 100%;
767
+ height: 42px;
768
+ line-height: 42px;
769
+ padding: 0 15px;
770
+ border: none;
771
+ border-radius: 0;
772
+ box-sizing: border-box;
773
+ }
774
+
775
+ .kiwi-statebrowser-channelfilter p {
776
+ text-align: center;
777
+ font-size: 0.9em;
778
+ margin: 10px 0 10px 0;
779
+ cursor: pointer;
780
+ transition: all 0.3s;
781
+ }
782
+
783
+ .kiwi-statebrowser-channelfilter p:hover {
784
+ text-decoration: underline;
785
+ }
786
+
787
+ @media screen and (max-width: 769px) {
788
+ .kiwi-network-name-options {
789
+ right: 0;
790
+ opacity: 1;
791
+ }
792
+
793
+ .kiwi-statebrowser-channel-name {
794
+ line-height: 40px;
795
+ }
796
+
797
+ .kiwi-network-name-option {
798
+ width: 50px;
799
+ }
800
+
801
+ .kiwi-statebrowser-channel-leave {
802
+ opacity: 1;
803
+ line-height: 40px;
804
+ width: 50px;
805
+ }
806
+
807
+ .kiwi-statebrowser-channel-labels {
808
+ right: 50px;
809
+ top: 0;
810
+ }
811
+
812
+ .kiwi-statebrowser-channel-label {
813
+ line-height: 41px;
814
+ height: 40px;
815
+ }
816
+
817
+ /* Ensure that on mobile devices, when hovering this is visible */
818
+ .kiwi-statebrowser-channel:hover .kiwi-statebrowser-channel-labels {
819
+ opacity: 1;
820
+ }
821
+ }
822
+
823
+ </style>