Modernize poll JS
authorjoshuaruesweg <ruesweg@woltlab.com>
Mon, 7 Feb 2022 10:41:55 +0000 (11:41 +0100)
committerjoshuaruesweg <ruesweg@woltlab.com>
Mon, 7 Feb 2022 10:42:22 +0000 (11:42 +0100)
com.woltlab.wcf/templates/poll.tpl
com.woltlab.wcf/templates/pollVote.tpl
ts/WoltLabSuite/Core/Ui/Poll/Manager/Manager.ts [new file with mode: 0644]
wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Poll/Manager/Manager.js [new file with mode: 0644]
wcfsetup/install/files/lib/action/PollAction.class.php

index a897291f212ff1f316ee54ea9b9a9cfda213cc83..69e42e1f3ebed94f657e4423d77c27b1443dd530 100644 (file)
@@ -1,16 +1,22 @@
 {if ($__wcf->getUser()->userID || $poll->canSeeResult() || $poll->canViewParticipants()) && !$__pollLoadedJavaScript|isset}
-       {assign var=__pollLoadedJavaScript value=true}
-       <script data-relocate="true">
-               $(function() {
-                       new WCF.Poll.Manager('.pollContainer');
-               });
+<script data-relocate="true">
+       require(['WoltLabSuite/Core/Ui/Poll/Manager/Manager'], function({ Manager }) {
+               new Manager(
+                       {@$poll->pollID},
+                       {if $poll->canSeeResult()}true{else}false{/if},
+                       {if $poll->canVote()}true{else}false{/if},
+                       {if $poll->isPublic}true{else}false{/if},
+                       {@$poll->maxVotes},
+                       "{$poll->question}"
+               );
+       });
        </script>
 {/if}
 
-<div class="pollContainer{if POLL_FULL_WIDTH} pollContainerFullWidth{/if}" data-poll-id="{@$poll->pollID}" data-can-vote="{if $poll->canVote()}1{else}0{/if}" data-can-view-result="{if $poll->canSeeResult()}1{else}0{/if}" data-can-view-participants="{if $poll->canViewParticipants()}true{else}false{/if}" data-in-vote="{if $poll->canVote() && !$poll->isParticipant()}1{else}0{/if}" data-question="{$poll->question}" data-max-votes="{@$poll->maxVotes}" data-is-public="{if $poll->isPublic}true{else}false{/if}">
+<div id="poll{@$poll->pollID}" class="pollContainer{if POLL_FULL_WIDTH} pollContainerFullWidth{/if}" data-poll-id="{@$poll->pollID}" data-can-vote="{if $poll->canVote()}1{else}0{/if}" data-can-view-result="{if $poll->canSeeResult()}1{else}0{/if}" data-can-view-participants="{if $poll->canViewParticipants()}true{else}false{/if}" data-in-vote="{if $poll->canVote() && !$poll->isParticipant()}1{else}0{/if}" data-question="{$poll->question}" data-max-votes="{@$poll->maxVotes}" data-is-public="{if $poll->isPublic}true{else}false{/if}">
        <section>
                <h2>{$poll->question} <span class="badge jsTooltip jsPollTotalVotes" title="{lang}wcf.poll.totalVotes{/lang}">{#$poll->votes}</span></h2>
-               
+
                <div class="pollInnerContainer">
                        {if !$__wcf->getUser()->userID}
                                {if $poll->canSeeResult()}
                                        {include file='pollResult'}
                                {/if}
                        {/if}
-                       
+
                        {event name='pollData'}
                </div>
        </section>
-       
+
        {hascontent}
                <div class="formSubmit jsOnly"{if !$poll->canVote() && $__pollView === 'result' && !$poll->canSeeResult()} style="display: none"{/if}>
                        {content}
                                {if $__wcf->getUser()->userID}
-                                       <button class="small jsButtonPollVote"{if $poll->canVote()} disabled{else} style="display: none;"{/if}>{lang}wcf.poll.button.vote{/lang}</button>
-                                       <button class="small jsButtonPollShowVote"{if !$poll->canVote() || $__pollView === 'vote'} style="display: none;"{/if}>{lang}wcf.poll.button.showVote{/lang}</button>
-                                       <button class="small jsButtonPollShowResult"{if $__pollView === 'result'} style="display: none;"{/if}>{lang}wcf.poll.button.showResult{/lang}</button>
+                                       <button class="small votePollButton"{if $poll->canVote() && $__pollView === 'vote'} disabled{else} hidden{/if}>{lang}wcf.poll.button.vote{/lang}</button>
+                                       <button class="small showVoteFormButton"{if $__pollView === 'vote' || !$poll->canVote()} hidden{/if}>{lang}wcf.poll.button.showVote{/lang}</button>
+                                       <button class="small showResultsButton"{if $__pollView === 'result' || !$poll->canSeeResult()} hidden{/if}>{lang}wcf.poll.button.showResult{/lang}</button>
                                {/if}
                                {if $poll->canViewParticipants() || ($poll->canVote() && $poll->isPublic)}
                                        <button class="small jsButtonPollShowParticipants"{if $__pollView === 'vote' || !$poll->canSeeResult()} style="display: none"{/if}>{lang}wcf.poll.button.showParticipants{/lang}</button>
                                {/if}
-                               
+
                                {event name='pollButtons'}
                        {/content}
                </div>
index f2701a307c7a56832df84e8e3c68d7d54489dbd1..4af72af273a8cde717341f440f109e3458362308 100644 (file)
@@ -1,9 +1,9 @@
-<dl class="wide jsPollVote" data-max-votes="{@$poll->maxVotes}">
+<dl class="wide pollVoteContainer" data-max-votes="{@$poll->maxVotes}">
        {foreach from=$poll->getOptions() item=option}
                <dt></dt>
                <dd>
                        <label>
-                               {if $poll->canVote()}<input type="{if $poll->maxVotes > 1}checkbox{else}radio{/if}" name="pollOptions{@$poll->pollID}[]" value="{$option->optionValue}" data-option-id="{@$option->optionID}"{if $option->voted} checked{/if}>{/if}
+                               {if $poll->canVote()}<input type="{if $poll->maxVotes > 1}checkbox{else}radio{/if}" name="pollOptions{@$poll->pollID}[]" value="{@$option->optionID}"{if $option->voted} checked{/if}>{/if}
                                {$option->optionValue}
                        </label>
                </dd>
diff --git a/ts/WoltLabSuite/Core/Ui/Poll/Manager/Manager.ts b/ts/WoltLabSuite/Core/Ui/Poll/Manager/Manager.ts
new file mode 100644 (file)
index 0000000..798ff60
--- /dev/null
@@ -0,0 +1,106 @@
+/**
+ * Handles the poll UI.
+ *
+ * @author  Joshua Ruesweg
+ * @copyright  2001-2022 WoltLab GmbH
+ * @license  GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module  WoltLabSuite/Core/Ui/Poll/Manager/Manager
+ * @since   5.5
+ */
+
+import DomUtil from "../../../Dom/Util";
+import Results from "./View/Results";
+import VoteView from "./View/Vote";
+import VoteHandler from "./Vote";
+
+export enum PollViews {
+  vote = "vote",
+  results = "results",
+}
+
+export class Manager {
+  public readonly pollID: number;
+  public readonly canViewResults: boolean;
+  public readonly canVote: boolean;
+  public readonly isPublic: boolean;
+  public readonly maxVotes: number;
+  public readonly question: string;
+  protected poll: HTMLElement;
+
+  private voteView?: VoteView;
+  private resultsView?: Results;
+
+  private voteHandler?: VoteHandler;
+
+  private activeView?: PollViews;
+
+  public constructor(
+    pollID: number,
+    canViewResults: boolean,
+    canVote: boolean,
+    isPublic: boolean,
+    maxVotes: number,
+    question: string,
+  ) {
+    this.pollID = pollID;
+    this.canViewResults = canViewResults;
+    this.canVote = canVote;
+    this.isPublic = isPublic;
+    this.maxVotes = maxVotes;
+    this.question = question;
+
+    const poll = document.getElementById(`poll${pollID}`);
+
+    if (poll === null) {
+      throw new Error(`Could not find poll with id "${pollID}".`);
+    }
+
+    this.poll = poll;
+
+    if (this.canViewResults) {
+      this.resultsView = new Results(this);
+    }
+
+    if (this.canVote) {
+      this.voteView = new VoteView(this);
+      this.voteHandler = new VoteHandler(this);
+    }
+  }
+
+  public getPollContainer(): HTMLElement {
+    return this.poll;
+  }
+
+  public changeView(view: PollViews, html: string): void {
+    this.activeView = view;
+
+    this.voteView?.checkVisibility(view);
+    this.resultsView?.checkVisibility(view);
+    this.voteHandler?.checkVisibility(view);
+    this.setInnerContainer(html);
+
+    if (view === PollViews.vote) {
+      this.voteHandler?.initSelects();
+    }
+  }
+
+  private canViewParticipants(): boolean {
+    return this.canViewResults && this.isPublic;
+  }
+
+  private getInnerContainer(): HTMLElement {
+    const innerContainer = (this.poll.querySelector(".pollInnerContainer") as HTMLElement) || null;
+
+    if (!innerContainer) {
+      throw new Error(`Could not find inner container for poll "${this.pollID}"`);
+    }
+
+    return innerContainer;
+  }
+
+  protected setInnerContainer(html: string): void {
+    DomUtil.setInnerHtml(this.getInnerContainer(), html);
+  }
+}
+
+export default Manager;
diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Poll/Manager/Manager.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Poll/Manager/Manager.js
new file mode 100644 (file)
index 0000000..dddae02
--- /dev/null
@@ -0,0 +1,74 @@
+/**
+ * Handles the poll UI.
+ *
+ * @author  Joshua Ruesweg
+ * @copyright  2001-2022 WoltLab GmbH
+ * @license  GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module  WoltLabSuite/Core/Ui/Poll/Manager/Manager
+ * @since   5.5
+ */
+define(["require", "exports", "tslib", "../../../Dom/Util", "./View/Results", "./View/Vote", "./Vote"], function (require, exports, tslib_1, Util_1, Results_1, Vote_1, Vote_2) {
+    "use strict";
+    Object.defineProperty(exports, "__esModule", { value: true });
+    exports.Manager = exports.PollViews = void 0;
+    Util_1 = (0, tslib_1.__importDefault)(Util_1);
+    Results_1 = (0, tslib_1.__importDefault)(Results_1);
+    Vote_1 = (0, tslib_1.__importDefault)(Vote_1);
+    Vote_2 = (0, tslib_1.__importDefault)(Vote_2);
+    var PollViews;
+    (function (PollViews) {
+        PollViews["vote"] = "vote";
+        PollViews["results"] = "results";
+    })(PollViews = exports.PollViews || (exports.PollViews = {}));
+    class Manager {
+        constructor(pollID, canViewResults, canVote, isPublic, maxVotes, question) {
+            this.pollID = pollID;
+            this.canViewResults = canViewResults;
+            this.canVote = canVote;
+            this.isPublic = isPublic;
+            this.maxVotes = maxVotes;
+            this.question = question;
+            const poll = document.getElementById(`poll${pollID}`);
+            if (poll === null) {
+                throw new Error(`Could not find poll with id "${pollID}".`);
+            }
+            this.poll = poll;
+            if (this.canViewResults) {
+                this.resultsView = new Results_1.default(this);
+            }
+            if (this.canVote) {
+                this.voteView = new Vote_1.default(this);
+                this.voteHandler = new Vote_2.default(this);
+            }
+        }
+        getPollContainer() {
+            return this.poll;
+        }
+        changeView(view, html) {
+            var _a, _b, _c, _d;
+            this.activeView = view;
+            (_a = this.voteView) === null || _a === void 0 ? void 0 : _a.checkVisibility(view);
+            (_b = this.resultsView) === null || _b === void 0 ? void 0 : _b.checkVisibility(view);
+            (_c = this.voteHandler) === null || _c === void 0 ? void 0 : _c.checkVisibility(view);
+            this.setInnerContainer(html);
+            if (view === PollViews.vote) {
+                (_d = this.voteHandler) === null || _d === void 0 ? void 0 : _d.initSelects();
+            }
+        }
+        canViewParticipants() {
+            return this.canViewResults && this.isPublic;
+        }
+        getInnerContainer() {
+            const innerContainer = this.poll.querySelector(".pollInnerContainer") || null;
+            if (!innerContainer) {
+                throw new Error(`Could not find inner container for poll "${this.pollID}"`);
+            }
+            return innerContainer;
+        }
+        setInnerContainer(html) {
+            Util_1.default.setInnerHtml(this.getInnerContainer(), html);
+        }
+    }
+    exports.Manager = Manager;
+    exports.default = Manager;
+});
index 7604ff7c5ed81bcda97963d58014375939884d96..0fcccc39e0fefe2b76bdd120aba80656eb9d17f2 100644 (file)
@@ -166,7 +166,7 @@ class PollAction extends AJAXProxyAction
             'poll' => $this->poll,
         ]);
 
-        $returnValues['resultTemplate'] = WCF::getTPL()->fetch('pollResult');
+        $returnValues['template'] = WCF::getTPL()->fetch('pollResult');
     }
 
     /**
@@ -180,7 +180,7 @@ class PollAction extends AJAXProxyAction
             'poll' => $this->poll,
         ]);
 
-        $returnValues['voteTemplate'] = WCF::getTPL()->fetch('pollVote');
+        $returnValues['template'] = WCF::getTPL()->fetch('pollVote');
     }
 
     /**
@@ -205,7 +205,7 @@ class PollAction extends AJAXProxyAction
 
         // render vote template if votes are changeable
         if ($this->poll->isChangeable) {
-            $this->getVote($returnValues);
+            $this->getResult($returnValues);
         }
 
         $returnValues['canVote'] = $this->poll->isChangeable ? 1 : 0;