Add polls feature: Beep_Polls class, poll UI in composer, voting support
This commit is contained in:
+184
@@ -91,9 +91,18 @@
|
||||
if (pendingVoice && data.id) {
|
||||
tasks.push(uploadPendingVoice(data.id, pendingVoice, compose));
|
||||
}
|
||||
// Create poll if poll data exists
|
||||
if (data.id) {
|
||||
tasks.push(createPoll(data.id, compose).then(function() {
|
||||
clearPoll(compose);
|
||||
}));
|
||||
}
|
||||
|
||||
if (tasks.length) {
|
||||
Promise.all(tasks).then(uploadDone);
|
||||
} else {
|
||||
// No uploads, just clear poll if present
|
||||
clearPoll(compose);
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
@@ -275,6 +284,50 @@
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Poll button - toggle poll section
|
||||
var pollBtn = t.closest('[data-beep-poll-btn]');
|
||||
if (pollBtn) {
|
||||
e.preventDefault();
|
||||
var compose = pollBtn.closest('[data-beep-compose]');
|
||||
if (compose) openPollSection(compose);
|
||||
return;
|
||||
}
|
||||
|
||||
// Poll add option
|
||||
var pollAddOptionBtn = t.closest('[data-beep-poll-add-option]');
|
||||
if (pollAddOptionBtn) {
|
||||
e.preventDefault();
|
||||
var compose = pollAddOptionBtn.closest('[data-beep-compose]');
|
||||
if (compose) addPollOption(compose);
|
||||
return;
|
||||
}
|
||||
|
||||
// Poll remove option
|
||||
var pollRemoveOptionBtn = t.closest('[data-beep-poll-remove-option]');
|
||||
if (pollRemoveOptionBtn) {
|
||||
e.preventDefault();
|
||||
var compose = pollRemoveOptionBtn.closest('[data-beep-compose]');
|
||||
if (compose) removePollOption(compose);
|
||||
return;
|
||||
}
|
||||
|
||||
// Poll remove
|
||||
var pollRemoveBtn = t.closest('[data-beep-poll-remove]');
|
||||
if (pollRemoveBtn) {
|
||||
e.preventDefault();
|
||||
var compose = pollRemoveBtn.closest('[data-beep-compose]');
|
||||
if (compose) clearPoll(compose);
|
||||
return;
|
||||
}
|
||||
|
||||
// Poll vote button
|
||||
var pollVoteBtn = t.closest('[data-beep-poll-vote]');
|
||||
if (pollVoteBtn) {
|
||||
e.preventDefault();
|
||||
if (requireLogin()) handlePollVote(pollVoteBtn);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function onInput(e) {
|
||||
@@ -786,3 +839,134 @@
|
||||
}
|
||||
closeGifPicker();
|
||||
}
|
||||
|
||||
/* ---------- Poll helpers ---------- */
|
||||
function openPollSection(compose) {
|
||||
var pollSection = compose.querySelector('[data-beep-compose-poll]');
|
||||
if (!pollSection) return;
|
||||
pollSection.hidden = false;
|
||||
// Focus question input
|
||||
var questionInput = pollSection.querySelector('[data-beep-poll-question]');
|
||||
if (questionInput) questionInput.focus();
|
||||
// Ensure we have at least 2 options
|
||||
var options = pollSection.querySelectorAll('[data-beep-poll-option]');
|
||||
if (options.length < 2) {
|
||||
while (options.length < 2) {
|
||||
addPollOption(compose);
|
||||
options = pollSection.querySelectorAll('[data-beep-poll-option]');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addPollOption(compose) {
|
||||
var pollSection = compose.querySelector('[data-beep-compose-poll]');
|
||||
if (!pollSection) return;
|
||||
var optionsContainer = pollSection.querySelector('[data-beep-poll-options]');
|
||||
if (!optionsContainer) return;
|
||||
var optionCount = optionsContainer.querySelectorAll('[data-beep-poll-option]').length;
|
||||
if (optionCount >= 6) return; // Max 6 options
|
||||
var newRow = document.createElement('div');
|
||||
newRow.className = 'beep-poll-option-row';
|
||||
newRow.innerHTML = '<input type="text" class="beep-poll-option" data-beep-poll-option placeholder="Option ' + (optionCount + 1) + '" maxlength="100">';
|
||||
optionsContainer.appendChild(newRow);
|
||||
updatePollButtons(compose);
|
||||
}
|
||||
|
||||
function removePollOption(compose) {
|
||||
var pollSection = compose.querySelector('[data-beep-compose-poll]');
|
||||
if (!pollSection) return;
|
||||
var options = pollSection.querySelectorAll('[data-beep-poll-option]');
|
||||
if (options.length <= 2) return; // Min 2 options
|
||||
var lastOption = options[options.length - 1];
|
||||
if (lastOption) lastOption.parentElement.remove();
|
||||
updatePollButtons(compose);
|
||||
}
|
||||
|
||||
function updatePollButtons(compose) {
|
||||
var pollSection = compose.querySelector('[data-beep-compose-poll]');
|
||||
if (!pollSection) return;
|
||||
var options = pollSection.querySelectorAll('[data-beep-poll-option]');
|
||||
var addBtn = pollSection.querySelector('[data-beep-poll-add-option]');
|
||||
var removeBtn = pollSection.querySelector('[data-beep-poll-remove-option]');
|
||||
if (addBtn) addBtn.hidden = options.length >= 6;
|
||||
if (removeBtn) removeBtn.hidden = options.length <= 2;
|
||||
}
|
||||
|
||||
function clearPoll(compose) {
|
||||
if (!compose) return;
|
||||
compose._beepPoll = null;
|
||||
var pollSection = compose.querySelector('[data-beep-compose-poll]');
|
||||
if (pollSection) {
|
||||
pollSection.hidden = true;
|
||||
var question = pollSection.querySelector('[data-beep-poll-question]');
|
||||
if (question) question.value = '';
|
||||
var options = pollSection.querySelectorAll('[data-beep-poll-option]');
|
||||
// Reset to 2 options
|
||||
if (options.length > 2) {
|
||||
for (var i = options.length - 1; i >= 2; i--) {
|
||||
if (options[i].parentElement) options[i].parentElement.remove();
|
||||
}
|
||||
}
|
||||
options = pollSection.querySelectorAll('[data-beep-poll-option]');
|
||||
for (var j = 0; j < options.length; j++) {
|
||||
options[j].value = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function collectPollData(compose) {
|
||||
if (!compose) return null;
|
||||
var pollSection = compose.querySelector('[data-beep-compose-poll]');
|
||||
if (!pollSection || pollSection.hidden) return null;
|
||||
var questionInput = pollSection.querySelector('[data-beep-poll-question]');
|
||||
var question = questionInput ? questionInput.value.trim() : '';
|
||||
if (!question) return null;
|
||||
var optionInputs = pollSection.querySelectorAll('[data-beep-poll-option]');
|
||||
var options = [];
|
||||
for (var i = 0; i < optionInputs.length; i++) {
|
||||
var val = optionInputs[i].value.trim();
|
||||
if (val) options.push(val);
|
||||
}
|
||||
if (options.length < 2) return null;
|
||||
return { question: question, options: options };
|
||||
}
|
||||
|
||||
function createPoll(beepId, compose) {
|
||||
var pollData = collectPollData(compose);
|
||||
if (!pollData) return Promise.resolve();
|
||||
return fetch(config.restUrl + 'poll/' + beepId, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': config.nonce },
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify(pollData)
|
||||
})
|
||||
.then(handleResponse)
|
||||
.catch(function(err) {
|
||||
console.warn('Poll creation failed:', err);
|
||||
});
|
||||
}
|
||||
|
||||
function handlePollVote(btn) {
|
||||
var beepId = btn.dataset.beepPollBeep;
|
||||
var optionIndex = parseInt(btn.dataset.beepPollVote, 10);
|
||||
if (!beepId || isNaN(optionIndex)) return;
|
||||
btn.disabled = true;
|
||||
fetch(config.restUrl + 'poll/' + beepId + '/vote', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': config.nonce },
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({ option_index: optionIndex })
|
||||
})
|
||||
.then(handleResponse)
|
||||
.then(function(data) {
|
||||
// Refresh the beep post to show updated poll results
|
||||
var postEl = btn.closest('[data-beep-post]');
|
||||
if (postEl) {
|
||||
var list = postEl.closest('[data-beep-list]');
|
||||
if (list) reloadFeed(list.closest('[data-beep-feed]'), 'latest');
|
||||
}
|
||||
})
|
||||
.catch(function() {
|
||||
btn.disabled = false;
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user