tweb/src/components/poll.ts

666 lines
22 KiB
TypeScript
Raw Normal View History

2021-04-08 15:52:31 +02:00
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import mediaSizes from "../helpers/mediaSizes";
import { isTouchSupported } from "../helpers/touchSupport";
2020-06-16 22:48:08 +02:00
import appImManager from "../lib/appManagers/appImManager";
import appPollsManager, { Poll, PollResults } from "../lib/appManagers/appPollsManager";
2020-06-16 22:48:08 +02:00
import serverTimeManager from "../lib/mtproto/serverTimeManager";
import { RichTextProcessor } from "../lib/richtextprocessor";
2020-11-15 04:33:47 +01:00
import rootScope from "../lib/rootScope";
2021-04-04 17:39:17 +02:00
import { attachClickEvent, cancelEvent, detachClickEvent, replaceContent } from "../helpers/dom";
import { ripple } from "./ripple";
import appSidebarRight from "./sidebarRight";
2021-03-12 17:49:09 +01:00
import AppPollResultsTab from "./sidebarRight/tabs/pollResults";
2021-03-28 20:37:11 +02:00
import { i18n, LangPackKey } from "../lib/langPack";
import { fastRaf } from "../helpers/schedulers";
import SetTransition from "./singleTransition";
2021-04-04 17:39:17 +02:00
import findUpClassName from "../helpers/dom/findUpClassName";
2020-05-09 14:02:07 +02:00
let lineTotalLength = 0;
const tailLength = 9;
const times = 10;
const fullTime = 340;
const oneTime = fullTime / times;
2020-06-16 22:48:08 +02:00
export const roundPercents = (percents: number[]) => {
//console.log('roundPercents before percents:', percents);
2020-06-16 22:48:08 +02:00
const sum = percents.reduce((acc, p) => acc + Math.round(p), 0);
if(sum > 100) {
2020-06-16 22:48:08 +02:00
const diff = sum - 100;
const length = percents.length;
for(let i = 0; i < diff; ++i) {
let minIndex = -1, minRemainder = 1;
for(let k = 0; k < length; ++k) {
let remainder = percents[k] % 1;
if(remainder >= 0.5 && remainder < minRemainder) {
minRemainder = remainder;
minIndex = k;
}
}
2021-02-04 01:30:23 +01:00
if(minIndex === -1) {
2020-06-16 22:48:08 +02:00
//throw new Error('lol chto');
return;
}
percents[minIndex] -= minRemainder;
}
} else if(sum < 100) {
2020-06-16 22:48:08 +02:00
const diff = 100 - sum;
const length = percents.length;
for(let i = 0; i < diff; ++i) {
let minIndex = -1, maxRemainder = 0;
for(let k = 0; k < length; ++k) {
let remainder = percents[k] % 1;
if(remainder < 0.5 && remainder > maxRemainder) {
maxRemainder = remainder;
minIndex = k;
}
}
2021-02-04 01:30:23 +01:00
if(minIndex === -1) {
2020-06-16 22:48:08 +02:00
//throw new Error('lol chto');
return;
}
percents[minIndex] += 1 - maxRemainder;
}
}
//console.log('roundPercents after percents:', percents);
};
/* const connectedPolls: {id: string, element: PollElement}[] = [];
2020-11-15 04:33:47 +01:00
rootScope.on('poll_update', (e) => {
const {poll, results} = e as {poll: Poll, results: PollResults};
2020-06-16 22:48:08 +02:00
//console.log('poll_update', poll, results);
for(const connected of connectedPolls) {
2021-02-04 01:30:23 +01:00
if(connected.id === poll.id) {
2020-06-16 22:48:08 +02:00
const pollElement = connected.element;
pollElement.isClosed = !!poll.pFlags.closed;
pollElement.performResults(results, poll.chosenIndexes);
}
}
}); */
rootScope.on('poll_update', (e) => {
const {poll, results} = e as {poll: Poll, results: PollResults};
const pollElements = Array.from(document.querySelectorAll(`poll-element[poll-id="${poll.id}"]`)) as PollElement[];
pollElements.forEach(pollElement => {
//console.log('poll_update', poll, results);
pollElement.isClosed = !!poll.pFlags.closed;
pollElement.performResults(results, poll.chosenIndexes);
});
});
2020-11-15 04:33:47 +01:00
rootScope.on('peer_changed', () => {
2020-06-16 22:48:08 +02:00
if(prevQuizHint) {
hideQuizHint(prevQuizHint, prevQuizHintOnHide, prevQuizHintTimeout);
}
});
const hideQuizHint = (element: HTMLElement, onHide: () => void, timeout: number) => {
element.classList.remove('active');
clearTimeout(timeout);
setTimeout(() => {
onHide();
element.remove();
2021-02-04 01:30:23 +01:00
if(prevQuizHint === element && prevQuizHintOnHide === onHide && prevQuizHintTimeout === timeout) {
2020-06-16 22:48:08 +02:00
prevQuizHint = prevQuizHintOnHide = null;
prevQuizHintTimeout = 0;
}
}, 200);
};
let prevQuizHint: HTMLElement, prevQuizHintOnHide: () => void, prevQuizHintTimeout: number;
const setQuizHint = (solution: string, solution_entities: any[], onHide: () => void) => {
if(prevQuizHint) {
hideQuizHint(prevQuizHint, prevQuizHintOnHide, prevQuizHintTimeout);
}
const element = document.createElement('div');
element.classList.add('quiz-hint');
const container = document.createElement('div');
container.classList.add('container', 'tgico');
const textEl = document.createElement('div');
textEl.classList.add('text');
container.append(textEl);
element.append(container);
textEl.innerHTML = RichTextProcessor.wrapRichText(solution, {entities: solution_entities});
appImManager.chat.bubbles.bubblesContainer.append(element);
2020-06-16 22:48:08 +02:00
void element.offsetLeft; // reflow
element.classList.add('active');
prevQuizHint = element;
prevQuizHintOnHide = onHide;
2020-09-20 00:38:00 +02:00
prevQuizHintTimeout = window.setTimeout(() => {
2020-06-16 22:48:08 +02:00
hideQuizHint(element, onHide, prevQuizHintTimeout);
}, isTouchSupported ? 5000 : 7000);
2020-06-16 22:48:08 +02:00
};
2020-05-09 14:02:07 +02:00
export default class PollElement extends HTMLElement {
private svgLines: SVGSVGElement[];
private numberDivs: HTMLDivElement[];
private answerDivs: HTMLDivElement[];
2020-06-16 22:48:08 +02:00
private descDiv: HTMLElement;
private typeDiv: HTMLElement;
private avatarsDiv: HTMLElement;
private viewResults: HTMLElement;
private votersCountDiv: HTMLDivElement;
private maxOffset = -46.5;
2020-05-09 14:02:07 +02:00
private maxLength: number;
private maxLengths: number[];
2020-06-16 22:48:08 +02:00
public isClosed = false;
private isQuiz = false;
private isRetracted = false;
2020-06-16 22:48:08 +02:00
private isPublic = false;
private isMultiple = false;
private chosenIndexes: number[] = [];
private percents: number[];
public message: any;
2020-06-16 22:48:08 +02:00
private quizInterval: number;
private quizTimer: SVGSVGElement;
private sendVoteBtn: HTMLElement;
private chosingIndexes: number[] = [];
private sendVotePromise: Promise<void>;
2020-08-19 14:54:08 +02:00
private sentVote = false;
2020-06-16 22:48:08 +02:00
2020-05-09 14:02:07 +02:00
constructor() {
super();
// элемент создан
}
public render() {
2020-05-09 14:02:07 +02:00
// браузер вызывает этот метод при добавлении элемента в документ
// (может вызываться много раз, если элемент многократно добавляется/удаляется)
if(!lineTotalLength) {
lineTotalLength = (document.getElementById('poll-line') as any as SVGPathElement).getTotalLength();
//console.log('line total length:', lineTotalLength);
2020-05-09 14:02:07 +02:00
}
const pollId = this.message.media.poll.id;
const {poll, results} = appPollsManager.getPoll(pollId);
2020-05-09 14:02:07 +02:00
/* const timestamp = Date.now() / 1000 | 0;
if(timestamp < this.message.date) { */
if(this.message.pFlags.is_scheduled) {
this.classList.add('disable-hover');
}
//console.log('pollElement poll:', poll, results);
2020-05-09 14:02:07 +02:00
2021-04-04 17:39:17 +02:00
let descKey: LangPackKey;
2020-05-09 14:02:07 +02:00
if(poll.pFlags) {
2020-06-16 22:48:08 +02:00
this.isPublic = !!poll.pFlags.public_voters;
this.isQuiz = !!poll.pFlags.quiz;
this.isClosed = !!poll.pFlags.closed;
this.isMultiple = !!poll.pFlags.multiple_choice;
if(this.isClosed) {
2021-03-28 20:37:11 +02:00
descKey = 'Chat.Poll.Type.Closed';
2020-06-16 22:48:08 +02:00
this.classList.add('is-closed');
2021-03-28 20:37:11 +02:00
} else if(this.isQuiz) {
descKey = this.isPublic ? 'Chat.Poll.Type.Quiz' : 'Chat.Poll.Type.AnonymousQuiz';
2020-05-09 14:02:07 +02:00
} else {
2021-03-28 20:37:11 +02:00
descKey = this.isPublic ? 'Chat.Poll.Type.Public' : 'Chat.Poll.Type.Anonymous';
2020-05-09 14:02:07 +02:00
}
}
2020-06-16 22:48:08 +02:00
const multipleSelect = this.isMultiple ? '<span class="poll-answer-selected tgico-check"></span>' : '';
const votes = poll.answers.map((answer, idx) => {
2020-05-09 14:02:07 +02:00
return `
<div class="poll-answer" data-index="${idx}">
2020-05-09 14:02:07 +02:00
<div class="circle-hover">
<div class="animation-ring"></div>
<svg class="progress-ring">
<circle class="progress-ring__circle" cx="13" cy="13" r="9"></circle>
</svg>
2020-06-16 22:48:08 +02:00
${multipleSelect}
2020-05-09 14:02:07 +02:00
</div>
<div class="poll-answer-percents"></div>
<div class="poll-answer-text">${RichTextProcessor.wrapEmojiText(answer.text)}</div>
<svg version="1.1" class="poll-line" style="display: none;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 ${mediaSizes.active.regular.width} 35" xml:space="preserve">
2020-05-09 14:02:07 +02:00
<use href="#poll-line"></use>
</svg>
2020-06-16 22:48:08 +02:00
<span class="poll-answer-selected tgico"></span>
2020-05-09 14:02:07 +02:00
</div>
`;
}).join('');
this.innerHTML = `
<div class="poll-title">${poll.rQuestion}</div>
2020-06-16 22:48:08 +02:00
<div class="poll-desc">
2021-03-28 20:37:11 +02:00
<div class="poll-type"></div>
2020-06-16 22:48:08 +02:00
<div class="poll-avatars"></div>
</div>
2021-03-28 20:37:11 +02:00
${votes}`;
2020-05-09 14:02:07 +02:00
2020-06-16 22:48:08 +02:00
this.descDiv = this.firstElementChild.nextElementSibling as HTMLElement;
this.typeDiv = this.descDiv.firstElementChild as HTMLElement;
this.avatarsDiv = this.descDiv.lastElementChild as HTMLElement;
2021-03-28 20:37:11 +02:00
if(descKey) {
this.typeDiv.append(i18n(descKey));
}
2020-06-16 22:48:08 +02:00
if(this.isQuiz) {
this.classList.add('is-quiz');
if(poll.close_period && poll.close_date) {
2020-06-19 13:49:55 +02:00
const timeLeftDiv = document.createElement('div');
timeLeftDiv.classList.add('poll-time');
this.descDiv.append(timeLeftDiv);
2020-06-16 22:48:08 +02:00
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
//svg.setAttributeNS(null, 'viewBox', '0 0 15 15');
svg.classList.add('poll-quiz-timer');
this.quizTimer = svg;
2020-06-16 22:48:08 +02:00
const strokeWidth = 2;
2020-06-19 13:49:55 +02:00
const radius = 7;
2020-06-16 22:48:08 +02:00
const circumference = 2 * Math.PI * radius;
2020-06-16 22:48:08 +02:00
const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
circle.classList.add('poll-quiz-timer-circle');
2020-06-19 13:49:55 +02:00
circle.setAttributeNS(null, 'cx', '16');
circle.setAttributeNS(null, 'cy', '16');
2020-06-16 22:48:08 +02:00
circle.setAttributeNS(null, 'r', '' + radius);
2020-06-19 13:49:55 +02:00
circle.setAttributeNS(null, 'stroke-width', '' + strokeWidth);
2020-06-16 22:48:08 +02:00
svg.append(circle);
this.descDiv.append(svg);
2020-06-19 13:49:55 +02:00
2020-06-16 22:48:08 +02:00
const period = poll.close_period * 1000;
const closeTime = (poll.close_date - serverTimeManager.serverTimeOffset) * 1000;
2020-06-19 13:49:55 +02:00
2020-06-21 14:25:17 +02:00
//console.log('closeTime:', poll.close_date, serverTimeManager.serverTimeOffset, Date.now() / 1000 | 0);
2020-06-19 13:49:55 +02:00
// let time = Date.now();
// let percents = (closeTime - time) / period;
// timeLeftDiv.innerHTML = String((closeTime - time) / 1000 + 1 | 0).toHHMMSS();
// // @ts-ignore
// circle.style.strokeDashoffset = circumference + percents * circumference;
// circle.style.strokeDasharray = ${circumference} ${circumference};
2020-09-20 00:38:00 +02:00
this.quizInterval = window.setInterval(() => {
2020-06-16 22:48:08 +02:00
const time = Date.now();
const percents = (closeTime - time) / period;
2020-06-19 13:49:55 +02:00
const timeLeft = (closeTime - time) / 1000 + 1 | 0;
timeLeftDiv.innerHTML = String(timeLeft).toHHMMSS();
if (timeLeft <= 5) {
timeLeftDiv.style.color = '#ee545c';
circle.style.stroke = '#ee545c';
}
//timeLeftDiv.style.visibility = 'visible';
// @ts-ignore
circle.style.strokeDashoffset = circumference + percents * circumference;
circle.style.strokeDasharray = `${circumference} ${circumference}`;
2020-06-16 22:48:08 +02:00
if(time >= closeTime) {
clearInterval(this.quizInterval);
2020-06-19 13:49:55 +02:00
timeLeftDiv.innerHTML = '';
// @ts-ignore
circle.style.strokeDashoffset = circumference;
2020-06-16 22:48:08 +02:00
this.quizInterval = 0;
2020-06-21 14:25:17 +02:00
setTimeout(() => {
// нужно запросить апдейт чтобы опрос обновился
appPollsManager.getResults(this.message);
2020-06-21 14:25:17 +02:00
}, 3e3);
2020-06-16 22:48:08 +02:00
}
}, 1e3);
}
}
this.answerDivs = Array.from(this.querySelectorAll('.poll-answer')) as HTMLDivElement[];
this.svgLines = Array.from(this.querySelectorAll('.poll-line')) as SVGSVGElement[];
this.numberDivs = Array.from(this.querySelectorAll('.poll-answer-percents')) as HTMLDivElement[];
2021-03-28 20:37:11 +02:00
const footerDiv = document.createElement('div');
footerDiv.classList.add('poll-footer');
this.viewResults = document.createElement('div');
this.viewResults.className = 'poll-footer-button poll-view-results hide';
this.viewResults.append(i18n('Chat.Poll.ViewResults'));
this.votersCountDiv = document.createElement('div');
this.votersCountDiv.className = 'poll-votes-count';
footerDiv.append(this.viewResults, this.votersCountDiv);
this.append(footerDiv);
2020-06-16 22:48:08 +02:00
this.viewResults.addEventListener('click', (e) => {
cancelEvent(e);
2021-03-12 17:49:09 +01:00
if(!appSidebarRight.isTabExists(AppPollResultsTab)) {
new AppPollResultsTab(appSidebarRight).open(this.message);
}
2020-06-16 22:48:08 +02:00
});
ripple(this.viewResults);
if(this.isMultiple) {
this.sendVoteBtn = document.createElement('div');
this.sendVoteBtn.classList.add('poll-footer-button', 'poll-send-vote');
2021-03-28 20:37:11 +02:00
this.sendVoteBtn.append(i18n('Chat.Poll.SubmitVote'));
2020-06-16 22:48:08 +02:00
ripple(this.sendVoteBtn);
if(!poll.chosenIndexes.length) {
this.votersCountDiv.classList.add('hide');
}
2020-12-12 17:30:01 +01:00
attachClickEvent(this.sendVoteBtn, (e) => {
cancelEvent(e);
2020-06-16 22:48:08 +02:00
/* const indexes = this.answerDivs.filter(el => el.classList.contains('is-chosing')).map(el => +el.dataset.index);
if(indexes.length) {
} */
if(this.chosingIndexes.length) {
this.sendVotes(this.chosingIndexes).then(() => {
this.chosingIndexes.length = 0;
this.answerDivs.forEach(el => {
el.classList.remove('is-chosing');
});
});
}
});
footerDiv.append(this.sendVoteBtn);
}
const width = this.getBoundingClientRect().width;
this.maxLength = width + tailLength + this.maxOffset + -13.7; // 13 - position left
2020-06-16 22:48:08 +02:00
if(poll.chosenIndexes.length || this.isClosed) {
this.performResults(results, poll.chosenIndexes);
} else if(!this.isClosed) {
this.setVotersCount(results);
2020-12-12 17:30:01 +01:00
attachClickEvent(this, this.clickHandler);
}
2020-05-09 14:02:07 +02:00
}
connectedCallback() {
this.render();
2020-05-09 14:02:07 +02:00
}
2020-06-16 22:48:08 +02:00
initQuizHint(results: PollResults) {
if(results.solution && results.solution_entities) {
const toggleHint = document.createElement('div');
toggleHint.classList.add('tgico-tip', 'poll-hint');
this.descDiv.append(toggleHint);
//let active = false;
2020-12-12 17:30:01 +01:00
attachClickEvent(toggleHint, (e) => {
2020-06-16 22:48:08 +02:00
cancelEvent(e);
//active = true;
toggleHint.classList.add('active');
setQuizHint(results.solution, results.solution_entities, () => {
//active = false;
toggleHint.classList.remove('active');
});
});
2020-08-19 14:54:08 +02:00
if(this.sentVote) {
const correctResult = results.results.find(r => r.pFlags.correct);
if(correctResult && !correctResult.pFlags.chosen) {
toggleHint.click();
}
}
2020-06-16 22:48:08 +02:00
}
}
clickHandler(e: Event) {
2020-06-16 22:48:08 +02:00
const target = findUpClassName(e.target, 'poll-answer') as HTMLElement;
if(!target) {
return;
2020-05-09 14:02:07 +02:00
}
cancelEvent(e);
2020-06-16 22:48:08 +02:00
const answerIndex = +target.dataset.index;
if(this.isMultiple) {
target.classList.toggle('is-chosing');
const foundIndex = this.chosingIndexes.indexOf(answerIndex);
if(foundIndex !== -1) {
this.chosingIndexes.splice(foundIndex, 1);
} else {
this.chosingIndexes.push(answerIndex);
}
} else {
this.sendVotes([answerIndex]);
}
/* target.classList.add('is-voting');
setTimeout(() => { // simulate
this.setResults([100, 0], answerIndex);
target.classList.remove('is-voting');
}, 1000); */
}
2020-05-09 14:02:07 +02:00
2020-06-16 22:48:08 +02:00
sendVotes(indexes: number[]) {
if(this.sendVotePromise) return this.sendVotePromise;
const targets = this.answerDivs.filter((_, idx) => indexes.includes(idx));
targets.forEach(target => {
target.classList.add('is-voting');
});
this.classList.add('disable-hover');
2020-08-19 14:54:08 +02:00
this.sentVote = true;
return this.sendVotePromise = appPollsManager.sendVote(this.message, indexes).then(() => {
2020-06-16 22:48:08 +02:00
targets.forEach(target => {
target.classList.remove('is-voting');
});
this.classList.remove('disable-hover');
2020-08-19 14:54:08 +02:00
}).catch(() => {
this.sentVote = false;
2020-06-16 22:48:08 +02:00
}).finally(() => {
this.sendVotePromise = null;
});
}
2020-05-09 14:02:07 +02:00
2020-06-16 22:48:08 +02:00
performResults(results: PollResults, chosenIndexes: number[]) {
if(this.isQuiz && (results.results?.length || this.isClosed)) {
this.answerDivs.forEach((el, idx) => {
el.classList.toggle('is-correct', !!results.results[idx].pFlags.correct);
});
if(this.initQuizHint) {
this.initQuizHint(results);
2020-06-21 14:25:17 +02:00
this.initQuizHint = null;
2020-06-16 22:48:08 +02:00
}
if(this.quizInterval) {
clearInterval(this.quizInterval);
this.quizInterval = 0;
}
if(this.quizTimer?.parentElement) {
this.quizTimer.remove();
}
2020-06-21 14:25:17 +02:00
const timeEl = this.descDiv.querySelector('.poll-time');
if(timeEl) {
timeEl.remove();
}
2020-06-16 22:48:08 +02:00
}
if(this.isClosed) {
this.classList.add('is-closed');
2021-03-28 20:37:11 +02:00
replaceContent(this.typeDiv, i18n('Chat.Poll.Type.Closed'));
2020-06-16 22:48:08 +02:00
}
// set chosen
2021-02-04 01:30:23 +01:00
if(this.chosenIndexes.length !== chosenIndexes.length || this.isClosed) { // if we voted
2020-06-16 22:48:08 +02:00
this.isRetracted = this.chosenIndexes.length && !chosenIndexes.length;
this.chosenIndexes = chosenIndexes.slice();
if(this.isRetracted) {
2020-12-12 17:30:01 +01:00
attachClickEvent(this, this.clickHandler);
} else {
2020-12-12 17:30:01 +01:00
detachClickEvent(this, this.clickHandler);
2020-05-09 14:02:07 +02:00
}
}
// is need update
2020-06-16 22:48:08 +02:00
if(this.chosenIndexes.length || this.isRetracted || this.isClosed) {
const percents = results.results.map(v => results.total_voters ? v.voters / results.total_voters * 100 : 0);
SetTransition(this, '', !this.isRetracted, 340);
fastRaf(() => {
this.setResults(this.isRetracted ? this.percents : percents, this.chosenIndexes);
this.percents = percents;
this.isRetracted = false;
});
}
this.setVotersCount(results);
2020-05-09 14:02:07 +02:00
2020-06-16 22:48:08 +02:00
if(this.isPublic) {
if(!this.isMultiple) {
this.viewResults.classList.toggle('hide', !results.total_voters || !this.chosenIndexes.length);
this.votersCountDiv.classList.toggle('hide', !!this.chosenIndexes.length);
}
let html = '';
/**
* MACOS, ANDROID - без реверса
* WINDOWS DESKTOP - реверс
* все приложения накладывают аватарку первую на вторую, а в макете зато вторая на первую, ЛОЛ!
*/
results.recent_voters/* .slice().reverse() */.forEach((userId, idx) => {
2021-02-04 01:30:23 +01:00
const style = idx === 0 ? '' : `style="transform: translateX(-${idx * 3}px);"`;
2021-03-28 20:37:11 +02:00
html += `<avatar-element class="avatar-16" dialog="0" peer="${userId}" ${style}></avatar-element>`;
2020-06-16 22:48:08 +02:00
});
this.avatarsDiv.innerHTML = html;
}
2020-05-09 14:02:07 +02:00
2020-06-16 22:48:08 +02:00
if(this.isMultiple) {
this.sendVoteBtn.classList.toggle('hide', !!this.chosenIndexes.length);
if(!this.chosenIndexes.length) {
this.votersCountDiv.classList.add('hide');
this.viewResults.classList.add('hide');
} else if(this.isPublic) {
this.viewResults.classList.toggle('hide', !results.total_voters || !this.chosenIndexes.length);
this.votersCountDiv.classList.toggle('hide', !!this.chosenIndexes.length);
} else {
this.votersCountDiv.classList.toggle('hide', !this.chosenIndexes.length);
2020-05-09 14:02:07 +02:00
}
}
2020-06-16 22:48:08 +02:00
}
setResults(percents: number[], chosenIndexes: number[]) {
this.svgLines.forEach(svg => svg.style.display = '');
this.answerDivs.forEach((el, idx) => {
el.classList.toggle('is-chosen', chosenIndexes.includes(idx));
});
2020-05-09 14:02:07 +02:00
2020-06-16 22:48:08 +02:00
const maxValue = Math.max(...percents);
this.maxLengths = percents.map(p => p / maxValue * this.maxLength);
2020-05-09 14:02:07 +02:00
// line
if(this.isRetracted) {
2020-05-09 14:02:07 +02:00
this.svgLines.forEach((svg, idx) => {
this.setLineProgress(idx, -1);
2020-05-09 14:02:07 +02:00
});
} else {
this.svgLines.forEach((svg, idx) => {
void svg.getBoundingClientRect(); // reflow
this.setLineProgress(idx, 1);
});
}
percents = percents.slice();
roundPercents(percents);
// numbers
if(this.isRetracted) {
for(let i = (times - 1), k = 0; i >= 0; --i, ++k) {
setTimeout(() => {
percents.forEach((percents, idx) => {
2020-06-16 22:48:08 +02:00
const value = Math.round(percents / times * i);
this.numberDivs[idx].innerText = value + '%';
});
}, oneTime * k);
2020-05-09 14:02:07 +02:00
}
} else {
for(let i = 0; i < times; ++i) {
setTimeout(() => {
percents.forEach((percents, idx) => {
2020-06-16 22:48:08 +02:00
const value = Math.round(percents / times * (i + 1));
this.numberDivs[idx].innerText = value + '%';
});
}, oneTime * i);
}
}
2020-05-09 14:02:07 +02:00
if(this.isRetracted) {
this.classList.add('is-retracting');
this.classList.remove('is-voted');
2020-05-09 14:02:07 +02:00
setTimeout(() => {
this.classList.remove('is-retracting');
this.svgLines.forEach(svg => svg.style.display = 'none');
}, fullTime);
} else {
this.classList.add('is-voted');
2020-05-09 14:02:07 +02:00
}
}
2020-05-09 14:02:07 +02:00
setVotersCount(results: PollResults) {
2020-06-16 22:48:08 +02:00
const votersCount = results.total_voters || 0;
2021-03-28 20:37:11 +02:00
let key: LangPackKey, args = [votersCount];
if(this.isClosed) {
if(this.isQuiz) key = votersCount ? 'Chat.Quiz.TotalVotes' : 'Chat.Quiz.TotalVotesResultEmpty';
else key = votersCount ? 'Chat.Poll.TotalVotes1' : 'Chat.Poll.TotalVotesResultEmpty';
} else {
if(this.isQuiz) key = votersCount ? 'Chat.Quiz.TotalVotes' : 'Chat.Quiz.TotalVotesEmpty';
else key = votersCount ? 'Chat.Poll.TotalVotes1' : 'Chat.Poll.TotalVotesEmpty';
}
replaceContent(this.votersCountDiv, i18n(key, args));
2020-05-09 14:02:07 +02:00
}
setLineProgress(index: number, percents: number) {
2020-06-16 22:48:08 +02:00
const svg = this.svgLines[index];
2021-02-04 01:30:23 +01:00
if(percents === -1) {
svg.style.strokeDasharray = '';
svg.style.strokeDashoffset = '';
} else {
svg.style.strokeDasharray = (percents * this.maxLengths[index]) + ', 485.9';
svg.style.strokeDashoffset = '' + percents * this.maxOffset;
}
2020-05-09 14:02:07 +02:00
}
// у элемента могут быть ещё другие методы и свойства
}
2021-03-28 20:37:11 +02:00
customElements.define("poll-element", PollElement);