PageSourceSearch

https://xn--forbrukslno-58a.no/wp-content/plugins/em-poll-plugin/inc/webcomponents/PollVoteComponent.js

js xn--forbrukslno-58a.no collected 2026-10-05 09:34:13 UTC 8,815 bytes, 282 lines download raw bytes

1(() => {
2  class PollVoteComponent extends HTMLElement {
3    constructor() {
4      super();
5    }
6
7    static template = document.createElement("template");
8    static {
9      PollVoteComponent.template.innerHTML = `
10        <style>
11            /* Poll Visibility Transitions */
12            .pollvote-hidden {
13              opacity: 0;
14              visibility: hidden;
15            }
16
17            .pollvote-visible {
18              opacity: 1;
19              visibility: visible;
20            }
21
22            /* Linear Fade-in Background Effect */
23            .pollvote-linear-fadein {
24              position: relative;
25              background-color: var(--cc-slider-bg); /* Base background color */
26              overflow: hidden;
27            }
28
29            .pollvote-linear-fadein::before {
30              content: "";
31              position: absolute;
32              top: 0;
33              left: 0;
34              width: 0%; /* Start from 0 */
35              height: 100%;
36              background: var(--cc-slider-track); /* Gradient color */
37              transition: width 1s linear;
38            }
39
40            /* Fade-in Animation */
41            .pollvote-fadein {
42              transition: opacity 0.3s ease-in-out, visibility 0.3s ease-in-out;
43            }        
44          </style>
45
46        <div class="w-full p-4 bg-white rounded-2xl shadow-md not-prose" data-name="pollvote-container">
47          <!-- Poll Title -->
48          <div class="text-lg font-semibold text-gray-900 mb-3" data-name="pollvote-title">
49            Poll Title
50          </div>
51
52          <!-- Poll Options -->
53          <ul class="space-y-2" data-name="pollvote-options">
54          </ul>
55
56          <!-- Total Votes -->
57          <div class="mt-4 flex gap-1 text-sm text-gray-600 pollvote-hidden pollvote-fadein" data-name="pollvote-total">
58            <span class="font-semibold" data-name="pollvote-total-count"></span> 
59            <div data-name="pollvote-total-text"></div>
60          </div>
61        </div>
62        `;
63    }
64
65    connectedCallback() {
66      // console.log('connectedCallback');
67      this.appendChild(PollVoteComponent.template.content.cloneNode(true));
68
69      // TODO: Implement dynamic CSS variable for background color
70      // const pollBgColor = getComputedStyle(document.documentElement).getPropertyValue('--pollvote-bg').trim();
71      // console.log(pollBgColor);
72      // console.log(getComputedStyle(document.documentElement).cssText);
73
74      this.cookies = document.cookie.split(";");
75
76      this.pollTitleElement = document.querySelector(
77        '[data-name="pollvote-title"]',
78      );
79      this.pollTotalCountElement = document.querySelector(
80        '[data-name="pollvote-total-count"]',
81      );
82      this.pollTotalTextElement = document.querySelector(
83        '[data-name="pollvote-total-text"]',
84      );
85      this.pollVoteOptions = document.querySelector(
86        '[data-name="pollvote-options"]',
87      );
88
89      // Store the shortcode variables in instances
90      this.pollData = Object.values(pollData) ?? [];
91      this.pollTitle = pollTitle ?? "Tittel";
92      this.pollId = pollId;
93      this.pollText = pollText;
94
95      // console.log(this.pollData);
96      // console.log(this.getTotalVotes());
97
98      this.initializePollState();
99    }
100
101    async handleVoteSubmission(event) {
102      // Rest API call
103      const res = await fetch(
104        `/wp-json/em-poll-plugin/v1/${this.pollId}/${event.currentTarget.dataset.id}`,
105        {
106          method: "POST",
107          headers: {
108            "Content-Type": "application/json",
109          },
110          body: JSON.stringify({}),
111        },
112      );
113
114      const data = await res.json();
115      // console.log(data);
116
117      if (data) {
118        this.pollData = Object.values(data.votes);
119        document.cookie = `pollvote=${this.pollId}|${data.option}`;
120        this.updatePollUI(data.option);
121      }
122    }
123
124    getTotalVotes() {
125      return this.pollData.reduce(
126        (acc, option) => acc + Number(option.count) + Number(option.organic),
127        0,
128      );
129    }
130
131    getOptionVotes(option) {
132      // console.log(option);
133      return Number(option.count) + Number(option.organic);
134    }
135
136    getColor() {
137      return this.pollColor;
138    }
139
140    initializePollState() {
141      // console.log('initializePollState');
142      this.pollTitleElement.textContent = this.pollTitle;
143      this.pollTotalCountElement.textContent = this.getTotalVotes();
144      this.pollTotalTextElement.textContent = this.pollText;
145      this.createPollOptions(this.hasUserVoted(), this.getCookieId());
146    }
147
148    updatePollUI(selectedOptionId) {
149      this.pollTotalCountElement.textContent = this.getTotalVotes();
150
151      this.createPollOptions(true, selectedOptionId);
152    }
153
154    hasUserVoted() {
155      // console.log('hasUserVoted');
156      return this.cookies.find((cookie) =>
157        cookie.includes(`pollvote=${this.pollId}`),
158      );
159    }
160
161    getCookieId() {
162      // console.log('getCookieId');
163      if (this.hasUserVoted()) {
164        return this.cookies
165          .find((cookie) => cookie.includes(`pollvote=${this.pollId}`))
166          .split("|")[1];
167      }
168    }
169
170    createPollOptions(voted, selectedOptionId = "") {
171      // console.log('createPollOptions');
172      // console.log(voted);
173
174      // Clear list before re-populating
175      this.pollVoteOptions.innerHTML = "";
176
177      this.pollData
178        .sort((a, b) => {
179          return Number(a.order) - Number(b.order);
180        })
181        .forEach((option) => {
182          this.getOptionVotes(option);
183          // Store dom elements
184          const li = document.createElement("li");
185          const text = document.createElement("span");
186          const percentage = document.createElement("span");
187
188          // Set the dataset
189          text.setAttribute("data-name", "pollvote-option");
190          percentage.setAttribute("data-name", "pollvote-percentage");
191          li.setAttribute("data-id", option.id);
192
193          // Set the styling tailwindcss & css
194          li.classList.add(
195            "flex",
196            "items-center",
197            "justify-between",
198            "p-3",
199            "bg-gray-100",
200            "rounded-lg",
201            "cursor-pointer",
202            "hover:bg-gray-200",
203            "transition",
204            "pollvote-option-text",
205          );
206          percentage.classList.add(
207            "text-gray-700",
208            "text-sm",
209            "font-medium",
210            "pollvote-hidden",
211            "pollvote-fadein",
212            "pollvote-option-percentage",
213          );
214
215          // Set the text content
216          text.textContent = option.text;
217          percentage.textContent = `${this.getOptionVotes(option) === 0 ? 0 : this.getVotePercentage(this.getOptionVotes(option))} %`;
218
219          if (!voted) {
220            li.addEventListener("click", this.handleVoteSubmission.bind(this));
221          }
222
223          // Append text and percentage to the list item
224          li.appendChild(text);
225          li.appendChild(percentage);
226
227          // Append the list item to the poll vote options
228          this.pollVoteOptions.appendChild(li);
229        });
230
231      if (voted) {
232        // Highlight the selected option
233        this.pollVoteOptions
234          .querySelectorAll(`li[data-id="${selectedOptionId}"]`)
235          .forEach((element) => {
236            element.classList.add(
237              "border-green-500",
238              "border-2",
239              "border-opacity-50",
240              "font-semibold",
241            );
242          });
243
244        // Show the total count and percentage
245        this.querySelectorAll('[data-name="pollvote-percentage"]').forEach(
246          (element) => {
247            element.classList.replace("pollvote-hidden", "pollvote-visible");
248          },
249        );
250        this.querySelector('[data-name="pollvote-total"]').classList.replace(
251          "pollvote-hidden",
252          "pollvote-visible",
253        );
254
255        // Update the list background color to match %
256        this.querySelectorAll('[data-name="pollvote-options"] > li').forEach(
257          (element) => {
258            const currentOption = this.pollData.find(
259              (option) => option.id === element.dataset.id,
260            );
261            const percentage = this.getVotePercentage(
262              this.getOptionVotes(currentOption),
263            );
264
265            element.classList.add("shadow-md");
266            element.style.transition = "background 1s linear";
267            element.style.background = `linear-gradient(to right, var(--pollvote-bg) ${percentage}%, #fff ${percentage}%)`;
268            element.style.color = "var(--pollvote-text)";
269          },
270        );
271      }
272    }
273
274    getVotePercentage(count) {
275      const total = this.getTotalVotes();
276
277      return Math.round((count / total) * 100);
278    }
279  }
280
281  customElements.define("poll-vote", PollVoteComponent);
282})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.