{* TODO *}
-<div id="quote-{if $wysiwygSelector|isset}{$wysiwygSelector}{else}text{/if}" class="jsOnly messageTabMenuContent">
+<div id="quotes_{if $wysiwygSelector|isset}{$wysiwygSelector}{else}text{/if}" class="messageTabMenuContent">
</div>
+
+<script data-relocate="true">
+ require(["WoltLabSuite/Core/Component/Quote/List"], ({ setup }) => {
+ setup("{if $wysiwygSelector|isset}{$wysiwygSelector}{else}text{/if}");
+ });
+</script>
{* TODO *}
-<div id="quote-{if $wysiwygSelector|isset}{$wysiwygSelector}{else}text{/if}" class="jsOnly messageTabMenuContent">
+<div id="quotes_{if $wysiwygSelector|isset}{$wysiwygSelector}{else}text{/if}" class="messageTabMenuContent">
</div>
+
+<script data-relocate="true">
+ require(["WoltLabSuite/Core/Component/Quote/List"], ({ setup }) => {
+ setup("{if $wysiwygSelector|isset}{$wysiwygSelector}{else}text{/if}");
+ });
+</script>
<li data-name="attachments"><button type="button">{icon name='paperclip'} <span>{lang}wcf.attachment.attachments{/lang}</span></button></li>
{/if}
{if $__messageFormSettings}<li data-name="settings"><button type="button">{icon name='gear'} <span>{lang}wcf.message.settings{/lang}</span></button></li>{/if}
- <li data-name="quote">
- {* TODO change count *}
- <button type="button">{icon name='quote-left'} <span>{lang count=10}wcf.message.quote.showQuotes{/lang}</span></button>
+ <li data-name="quotes" hidden>
+ <button type="button">{icon name='quote-left'} <span>{lang}wcf.bbcode.quote{/lang}</span></button>
</li>
{if $__showPoll|isset && $__showPoll}<li data-name="poll"><button type="button">{icon name='chart-bar'} <span>{lang}wcf.poll.management{/lang}</span></button></li>{/if}
{event name='tabMenuTabs'}
<li data-name="attachments"><button type="button">{icon name='paperclip'} <span>{lang}wcf.attachment.attachments{/lang}</span></button></li>
{/if}
{if $__messageFormSettingsInlineContent}<li data-name="settings"><button type="button">{icon name='gear'} <span>{lang}wcf.message.settings{/lang}</span></button></li>{/if}
- <li data-name="quote">
- {* TODO change count *}
- <button type="button">{icon name='quote-left'} <span>{lang count=10}wcf.message.quote.showQuotes{/lang}</span></button>
+ <li data-name="quotes" hidden>
+ <button type="button">{icon name='quote-left'} <span>{lang}wcf.bbcode.quote{/lang}</span></button>
</li>
{if $__showPoll|isset && $__showPoll}<li data-name="poll"><button type="button">{icon name='chart-bar'} <span>{lang}wcf.poll.management{/lang}</span></button></li>{/if}
{event name='tabMenuTabs'}
this.#activeTabName = tabName;
}
+ showTab(tabName: string, title?: string): void {
+ this.#tabs
+ .filter((element) => element.dataset.name === tabName)
+ .forEach((element) => {
+ element.hidden = false;
+
+ // Set new title
+ if (title) {
+ element.querySelector("span")!.textContent = title;
+ }
+ });
+ }
+
+ hideTab(tabName: string): void {
+ this.#tabs
+ .filter((element) => element.dataset.name === tabName)
+ .forEach((element) => {
+ element.hidden = true;
+
+ if (element.classList.contains("active")) {
+ this.#closeAllTabs();
+ }
+ });
+ }
+
#init(): void {
for (let i = 0; i < this.#tabs.length; i++) {
const tab = this.#tabs[i];
--- /dev/null
+/**
+ * Handles quotes for CKEditor 5 message fields.
+ *
+ * @author Olaf Braun
+ * @copyright 2001-2024 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @since 6.2
+ */
+import * as Core from "WoltLabSuite/Core/Core";
+import { listenToCkeditor } from "WoltLabSuite/Core/Component/Ckeditor/Event";
+import type { CKEditor } from "WoltLabSuite/Core/Component/Ckeditor";
+import { getTabMenu } from "WoltLabSuite/Core/Component/Message/MessageTabMenu";
+import { getPhrase } from "WoltLabSuite/Core/Language";
+
+export const STORAGE_KEY = Core.getStoragePrefix() + "quotes";
+const quoteLists = new Map<string, QuoteList>();
+
+class QuoteList {
+ #container: HTMLElement;
+ #editor: CKEditor;
+ #editorId: string;
+
+ constructor(editorId: string, editor: CKEditor) {
+ this.#editorId = editorId;
+ this.#editor = editor;
+ this.#container = document.getElementById(`quotes_${editorId}`)!;
+ if (this.#container === null) {
+ throw new Error(`The quotes container for '${editorId}' does not exist.`);
+ }
+
+ window.addEventListener("storage", (event) => {
+ if (event.key !== STORAGE_KEY) {
+ return;
+ }
+
+ this.renderQuotes(event.newValue);
+ });
+
+ this.renderQuotes(window.localStorage.getItem(STORAGE_KEY));
+ }
+
+ public renderQuotes(template: string | null): void {
+ this.#container.innerHTML = template || "";
+
+ if (template) {
+ getTabMenu(this.#editorId)?.showTab(
+ "quotes",
+ getPhrase("wcf.message.quote.showQuotes", {
+ count: this.#container.childElementCount,
+ }),
+ );
+ } else {
+ getTabMenu(this.#editorId)?.hideTab("quotes");
+ }
+ }
+}
+
+export function getQuoteList(editorId: string): QuoteList | undefined {
+ return quoteLists.get(editorId);
+}
+
+export function setup(editorId: string): void {
+ if (quoteLists.has(editorId)) {
+ return;
+ }
+
+ const editor = document.getElementById(editorId);
+ if (editor === null) {
+ throw new Error(`The editor '${editorId}' does not exist.`);
+ }
+
+ listenToCkeditor(editor).ready(({ ckeditor }) => {
+ if (ckeditor.features.quoteBlock) {
+ quoteLists.set(editorId, new QuoteList(editorId, ckeditor));
+ }
+ });
+}
this.#tabContainers[tabIndex].classList.add("active");
this.#activeTabName = tabName;
}
+ showTab(tabName, title) {
+ this.#tabs
+ .filter((element) => element.dataset.name === tabName)
+ .forEach((element) => {
+ element.hidden = false;
+ // Set new title
+ if (title) {
+ element.querySelector("span").textContent = title;
+ }
+ });
+ }
+ hideTab(tabName) {
+ this.#tabs
+ .filter((element) => element.dataset.name === tabName)
+ .forEach((element) => {
+ element.hidden = true;
+ if (element.classList.contains("active")) {
+ this.#closeAllTabs();
+ }
+ });
+ }
#init() {
for (let i = 0; i < this.#tabs.length; i++) {
const tab = this.#tabs[i];
--- /dev/null
+define(["require", "exports", "tslib", "WoltLabSuite/Core/Core", "WoltLabSuite/Core/Component/Ckeditor/Event", "WoltLabSuite/Core/Component/Message/MessageTabMenu", "WoltLabSuite/Core/Language"], function (require, exports, tslib_1, Core, Event_1, MessageTabMenu_1, Language_1) {
+ "use strict";
+ Object.defineProperty(exports, "__esModule", { value: true });
+ exports.STORAGE_KEY = void 0;
+ exports.getQuoteList = getQuoteList;
+ exports.setup = setup;
+ Core = tslib_1.__importStar(Core);
+ exports.STORAGE_KEY = Core.getStoragePrefix() + "quotes";
+ const quoteLists = new Map();
+ class QuoteList {
+ #container;
+ #editor;
+ #editorId;
+ constructor(editorId, editor) {
+ this.#editorId = editorId;
+ this.#editor = editor;
+ this.#container = document.getElementById(`quotes_${editorId}`);
+ if (this.#container === null) {
+ throw new Error(`The quotes container for '${editorId}' does not exist.`);
+ }
+ window.addEventListener("storage", (event) => {
+ if (event.key !== exports.STORAGE_KEY) {
+ return;
+ }
+ this.renderQuotes(event.newValue);
+ });
+ this.renderQuotes(window.localStorage.getItem(exports.STORAGE_KEY));
+ }
+ renderQuotes(template) {
+ this.#container.innerHTML = template || "";
+ if (template) {
+ (0, MessageTabMenu_1.getTabMenu)(this.#editorId)?.showTab("quotes", (0, Language_1.getPhrase)("wcf.message.quote.showQuotes", {
+ count: this.#container.childElementCount,
+ }));
+ }
+ else {
+ (0, MessageTabMenu_1.getTabMenu)(this.#editorId)?.hideTab("quotes");
+ }
+ }
+ }
+ function getQuoteList(editorId) {
+ return quoteLists.get(editorId);
+ }
+ function setup(editorId) {
+ if (quoteLists.has(editorId)) {
+ return;
+ }
+ const editor = document.getElementById(editorId);
+ if (editor === null) {
+ throw new Error(`The editor '${editorId}' does not exist.`);
+ }
+ (0, Event_1.listenToCkeditor)(editor).ready(({ ckeditor }) => {
+ if (ckeditor.features.quoteBlock) {
+ quoteLists.set(editorId, new QuoteList(editorId, ckeditor));
+ }
+ });
+ }
+});
$event->preload('wcf.message.share.permalink.html');
$event->preload('wcf.message.share.socialMedia');
+ $event->preload('wcf.message.quote.showQuotes');
+
$event->preload('wcf.moderation.report.reportContent');
$event->preload('wcf.page.jumpTo');