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.