mirror of
https://github.com/MvDevsUnion/WPetition.git
synced 2026-01-13 08:59:29 +00:00
702 lines
28 KiB
HTML
702 lines
28 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Petition Details</title>
|
|
<link rel="stylesheet" href="style.css">
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
|
<script src="https://cdn.jsdelivr.net/npm/marked@11.1.1/marked.min.js"></script>
|
|
<link rel="preconnect" href="https://challenges.cloudflare.com">
|
|
<script
|
|
src="https://challenges.cloudflare.com/turnstile/v0/api.js"
|
|
async
|
|
defer></script>
|
|
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<div id="loading" class="loading">Loading petition...</div>
|
|
<div id="error" class="error" style="display: none;"></div>
|
|
<div id="petition-content" style="display: none;">
|
|
<div class="lang-switcher">
|
|
<button id="lang-en" class="lang-btn active">English</button>
|
|
<button id="lang-dv" class="lang-btn">ދިވެހި</button>
|
|
</div>
|
|
|
|
<div class="petition-header">
|
|
<h1 id="petition-name-eng" class="lang-en-content"></h1>
|
|
<h2 id="petition-name-dhiv" class="dhivehi lang-dv-content"></h2>
|
|
<div class="metadata">
|
|
<span class="start-date">Start Date: <span id="start-date"></span></span>
|
|
<span class="signature-count">Signatures: <span id="signature-count"></span></span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="author-details">
|
|
<h3 class="lang-en-content">Author Details</h3>
|
|
<h3 class="dhivehi lang-dv-content">ލިޔުންތެރިގެ މައުލޫމާތު</h3>
|
|
<p><strong class="lang-en-content">Name:</strong><strong class="dhivehi lang-dv-content">ނަން:</strong> <span id="author-name"></span></p>
|
|
<!-- <p><strong class="lang-en-content">NID:</strong><strong class="dhivehi lang-dv-content">ކާޑު ނަންބަރު:</strong> <span id="author-nid"></span></p> -->
|
|
</div>
|
|
|
|
<div class="petition-body">
|
|
<div class="lang-en-content">
|
|
<div id="petition-body-eng" class="body-content"></div>
|
|
</div>
|
|
|
|
<div class="lang-dv-content">
|
|
<div id="petition-body-dhiv" class="body-content dhivehi"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="signature-section">
|
|
<h3 class="lang-en-content">Sign this Petition</h3>
|
|
<h3 class="dhivehi lang-dv-content">މި މައްސަލައިގައި ސޮއި ކުރައްވާ</h3>
|
|
|
|
<form id="signature-form">
|
|
<div class="form-group">
|
|
<label class="lang-en-content">Full Name (As on ID card)</label>
|
|
<label class="dhivehi lang-dv-content">ފުރިހަމަ ނަން</label>
|
|
<input type="text" id="name" name="name" minlength="3" maxlength="30" required>
|
|
</div>
|
|
|
|
<div class="form-group idcard-group">
|
|
<label class="lang-en-content">ID Card Number</label>
|
|
<label class="dhivehi lang-dv-content">ކާޑު ނަންބަރު</label>
|
|
<div class="idcard-input">
|
|
<span class="idcard-prefix">A</span>
|
|
<input type="tel" inputmode="numeric" pattern="\d{6}" id="idCard" name="idCard" maxlength="6" required placeholder="123456" aria-label="ID number, 6 digits" dir="ltr">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label class="lang-en-content">Signature</label>
|
|
<label class="dhivehi lang-dv-content">ސޮއި</label>
|
|
<div class="signature-pad-container">
|
|
<canvas id="signature-pad" width="600" height="200"></canvas>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group consent-group">
|
|
<label class="consent-label">
|
|
<input type="checkbox" id="confirm-consent" name="confirmConsent" required>
|
|
<span class="lang-en-content">I acknowledge my signature and information will be sent to the Parliament Petition Committee, and that the information I provide is true.</span>
|
|
<span class="dhivehi lang-dv-content">I acknowledge my signature and information will be sent to the Parliament Petition Committee, and that the information I provide is true.</span>
|
|
</label>
|
|
</div>
|
|
|
|
<div id="form-message" class="form-message"></div>
|
|
|
|
<!-- Cloudflare Turnstile: add callbacks so auto-render uses our handlers -->
|
|
<div class="cf-turnstile" data-sitekey="0x4AAAAAACHH4QC3wIhkCuhd"
|
|
data-callback="onTurnstileSuccess"
|
|
data-error-callback="onTurnstileError"
|
|
data-expired-callback="onTurnstileExpired"></div>
|
|
|
|
<div class="form-buttons">
|
|
<button type="button" id="clear-signature" class="btn-secondary" title="Clear signature" aria-label="Clear signature">
|
|
<i class="fas fa-eraser"></i> Clear
|
|
</button>
|
|
<button type="submit" class="btn-primary" title="Submit signature" aria-label="Submit signature">
|
|
<i class="fas fa-paper-plane"></i> Submit
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tweet Prompt Modal -->
|
|
<div id="tweet-modal" class="modal">
|
|
<div class="modal-content">
|
|
<span class="close-modal">×</span>
|
|
<h2 id="modal-title">Share this petition!</h2>
|
|
<p id="modal-text">Help spread the word by tweeting about this petition.</p>
|
|
<div class="modal-buttons">
|
|
<button id="tweet-button" class="btn-primary">
|
|
<i class="fab fa-twitter"></i> <span id="tweet-btn-text">Tweet Now</span>
|
|
</button>
|
|
<button id="skip-tweet" class="btn-secondary"><span id="skip-btn-text">Maybe Later</span></button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// API Configuration - Change this for different environments
|
|
const API_CONFIG = {
|
|
baseUrl: '' // Empty for same-origin requests (Nginx proxies /api/* to backend)
|
|
};
|
|
|
|
let currentLang = 'en';
|
|
|
|
// Extract petition ID from URL query parameter
|
|
function getPetitionIdFromUrl() {
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
const id = urlParams.get('id');
|
|
|
|
// Hardcoded mapping for cleaner URLs
|
|
if (id === 'dataprotection') {
|
|
return '7a315446-3c63-40cc-b382-86152bd8e591';
|
|
}
|
|
|
|
return id;
|
|
}
|
|
|
|
// Get language from URL query parameter
|
|
function getLangFromUrl() {
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
const lang = urlParams.get('lang');
|
|
return lang === 'dv' ? 'dv' : 'en';
|
|
}
|
|
|
|
// Update URL with current language
|
|
function updateUrlWithLang(lang) {
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
if (lang === 'en') {
|
|
urlParams.delete('lang');
|
|
} else {
|
|
urlParams.set('lang', lang);
|
|
}
|
|
const newUrl = window.location.pathname + (urlParams.toString() ? '?' + urlParams.toString() : '');
|
|
window.history.pushState({}, '', newUrl);
|
|
}
|
|
|
|
// Switch language
|
|
function switchLanguage(lang) {
|
|
currentLang = lang;
|
|
|
|
// Update button states
|
|
document.getElementById('lang-en').classList.toggle('active', lang === 'en');
|
|
document.getElementById('lang-dv').classList.toggle('active', lang === 'dv');
|
|
|
|
// Show/hide content based on language
|
|
const enContent = document.querySelectorAll('.lang-en-content');
|
|
const dvContent = document.querySelectorAll('.lang-dv-content');
|
|
|
|
enContent.forEach(el => {
|
|
el.style.display = lang === 'en' ? '' : 'none';
|
|
});
|
|
|
|
dvContent.forEach(el => {
|
|
el.style.display = lang === 'dv' ? '' : 'none';
|
|
});
|
|
|
|
// Update URL
|
|
updateUrlWithLang(lang);
|
|
// Set document direction for RTL languages (Dhivehi uses RTL script)
|
|
try {
|
|
document.documentElement.dir = (lang === 'dv') ? 'rtl' : 'ltr';
|
|
} catch (e) { }
|
|
}
|
|
|
|
// Fetch petition data
|
|
async function fetchPetition(petitionId) {
|
|
const apiUrl = `${API_CONFIG.baseUrl}/api/Sign/petition/${petitionId}`;
|
|
|
|
try {
|
|
const response = await fetch(apiUrl);
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
displayPetition(data);
|
|
} catch (error) {
|
|
// If fetching fails, show a visible dev notice and load dummy data
|
|
console.warn('Failed to fetch petition, falling back to dummy data.', error);
|
|
const errorDiv = document.getElementById('error');
|
|
errorDiv.textContent = 'Failed to load petition from server — showing dummy data for development.';
|
|
errorDiv.style.display = 'block';
|
|
displayPetition(getDummyPetition(petitionId));
|
|
}
|
|
}
|
|
|
|
// Return a dummy petition object useful for local development
|
|
function getDummyPetition(petitionId) {
|
|
const now = new Date();
|
|
return {
|
|
id: petitionId || 'dev-petition',
|
|
nameEng: 'Demo Petition: Improve Local Services',
|
|
nameDhiv: 'Demo Petition',
|
|
startDate: now.toLocaleDateString(),
|
|
signatureCount: 42,
|
|
authorDetails: {
|
|
name: 'Demo Author'
|
|
},
|
|
petitionBodyEng: 'This is dummy petition content to enable local development. Replace with real data when the API is available.',
|
|
petitionBodyDhiv: 'Demo petition content (Dhivehi)'
|
|
};
|
|
}
|
|
|
|
// Display petition data
|
|
function displayPetition(data) {
|
|
// Store petition data for tweet generation
|
|
currentPetitionData = data;
|
|
|
|
document.getElementById('loading').style.display = 'none';
|
|
document.getElementById('petition-content').style.display = 'block';
|
|
|
|
document.getElementById('petition-name-eng').textContent = data.nameEng;
|
|
document.getElementById('petition-name-dhiv').textContent = data.nameDhiv;
|
|
document.getElementById('start-date').textContent = data.startDate;
|
|
document.getElementById('signature-count').textContent = data.signatureCount;
|
|
|
|
document.getElementById('author-name').textContent = data.authorDetails.name;
|
|
//document.getElementById('author-nid').textContent = data.authorDetails.nid;
|
|
|
|
// Convert markdown-style formatting to HTML (basic support)
|
|
document.getElementById('petition-body-eng').innerHTML = formatText(data.petitionBodyEng);
|
|
document.getElementById('petition-body-dhiv').innerHTML = formatText(data.petitionBodyDhiv);
|
|
|
|
// Set initial language display
|
|
switchLanguage(currentLang);
|
|
}
|
|
|
|
// Parse Markdown to HTML
|
|
function formatText(text) {
|
|
return marked.parse(text);
|
|
}
|
|
|
|
// Show error message
|
|
function showError(message) {
|
|
document.getElementById('loading').style.display = 'none';
|
|
const errorDiv = document.getElementById('error');
|
|
errorDiv.textContent = message;
|
|
errorDiv.style.display = 'block';
|
|
}
|
|
|
|
// Signature pad functionality
|
|
let isDrawing = false;
|
|
let signaturePaths = [];
|
|
let currentPath = [];
|
|
// Turnstile widget state
|
|
let turnstileWidgetId = null;
|
|
let turnstileToken = null;
|
|
|
|
function onTurnstileSuccess(token) {
|
|
turnstileToken = token;
|
|
}
|
|
|
|
function onTurnstileError() {
|
|
turnstileToken = null;
|
|
}
|
|
|
|
function onTurnstileExpired() {
|
|
turnstileToken = null;
|
|
}
|
|
|
|
// Try to render Turnstile widget when API is available
|
|
function ensureTurnstileRendered() {
|
|
const container = document.querySelector('.cf-turnstile');
|
|
if (!container) return;
|
|
// If Turnstile already auto-rendered an iframe inside the container, don't render again
|
|
if (container.children.length > 0) {
|
|
// mark as auto-rendered
|
|
turnstileWidgetId = -1;
|
|
return;
|
|
}
|
|
|
|
if (window.turnstile && turnstileWidgetId === null) {
|
|
try {
|
|
turnstileWidgetId = turnstile.render(container, {
|
|
sitekey: container.getAttribute('data-sitekey'),
|
|
callback: onTurnstileSuccess,
|
|
'error-callback': onTurnstileError,
|
|
'expired-callback': onTurnstileExpired
|
|
});
|
|
} catch (e) {
|
|
// If render fails, leave the element as-is (script may auto-render)
|
|
}
|
|
} else if (!window.turnstile) {
|
|
// Retry until turnstile script is available
|
|
setTimeout(ensureTurnstileRendered, 200);
|
|
}
|
|
}
|
|
|
|
function initSignaturePad() {
|
|
const canvas = document.getElementById('signature-pad');
|
|
const ctx = canvas.getContext('2d');
|
|
|
|
// Resize canvas to match its display size (fixes coordinate offset bug)
|
|
const rect = canvas.getBoundingClientRect();
|
|
if (rect.width > 0 && rect.height > 0) {
|
|
canvas.width = rect.width;
|
|
canvas.height = rect.height;
|
|
}
|
|
|
|
// Re-apply context settings after resize
|
|
ctx.strokeStyle = '#000';
|
|
ctx.lineWidth = 2;
|
|
ctx.lineCap = 'round';
|
|
ctx.lineJoin = 'round';
|
|
|
|
// Mouse events
|
|
canvas.addEventListener('mousedown', startDrawing);
|
|
canvas.addEventListener('mousemove', draw);
|
|
canvas.addEventListener('mouseup', stopDrawing);
|
|
canvas.addEventListener('mouseout', stopDrawing);
|
|
|
|
// Touch events
|
|
canvas.addEventListener('touchstart', handleTouchStart);
|
|
canvas.addEventListener('touchmove', handleTouchMove);
|
|
canvas.addEventListener('touchend', stopDrawing);
|
|
|
|
// Clear button
|
|
document.getElementById('clear-signature').addEventListener('click', clearSignature);
|
|
}
|
|
|
|
function getMousePos(canvas, evt) {
|
|
const rect = canvas.getBoundingClientRect();
|
|
return {
|
|
x: evt.clientX - rect.left,
|
|
y: evt.clientY - rect.top
|
|
};
|
|
}
|
|
|
|
function getTouchPos(canvas, evt) {
|
|
const rect = canvas.getBoundingClientRect();
|
|
return {
|
|
x: evt.touches[0].clientX - rect.left,
|
|
y: evt.touches[0].clientY - rect.top
|
|
};
|
|
}
|
|
|
|
function startDrawing(e) {
|
|
isDrawing = true;
|
|
const canvas = document.getElementById('signature-pad');
|
|
const pos = getMousePos(canvas, e);
|
|
currentPath = [pos];
|
|
}
|
|
|
|
function draw(e) {
|
|
if (!isDrawing) return;
|
|
|
|
const canvas = document.getElementById('signature-pad');
|
|
const ctx = canvas.getContext('2d');
|
|
const pos = getMousePos(canvas, e);
|
|
|
|
currentPath.push(pos);
|
|
|
|
ctx.beginPath();
|
|
ctx.moveTo(currentPath[currentPath.length - 2].x, currentPath[currentPath.length - 2].y);
|
|
ctx.lineTo(pos.x, pos.y);
|
|
ctx.stroke();
|
|
}
|
|
|
|
function stopDrawing() {
|
|
if (isDrawing && currentPath.length > 0) {
|
|
signaturePaths.push([...currentPath]);
|
|
currentPath = [];
|
|
}
|
|
isDrawing = false;
|
|
}
|
|
|
|
function handleTouchStart(e) {
|
|
e.preventDefault();
|
|
isDrawing = true;
|
|
const canvas = document.getElementById('signature-pad');
|
|
const pos = getTouchPos(canvas, e);
|
|
currentPath = [pos];
|
|
}
|
|
|
|
function handleTouchMove(e) {
|
|
e.preventDefault();
|
|
if (!isDrawing) return;
|
|
|
|
const canvas = document.getElementById('signature-pad');
|
|
const ctx = canvas.getContext('2d');
|
|
const pos = getTouchPos(canvas, e);
|
|
|
|
currentPath.push(pos);
|
|
|
|
ctx.beginPath();
|
|
ctx.moveTo(currentPath[currentPath.length - 2].x, currentPath[currentPath.length - 2].y);
|
|
ctx.lineTo(pos.x, pos.y);
|
|
ctx.stroke();
|
|
}
|
|
|
|
function clearSignature() {
|
|
const canvas = document.getElementById('signature-pad');
|
|
const ctx = canvas.getContext('2d');
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
signaturePaths = [];
|
|
currentPath = [];
|
|
}
|
|
|
|
function generateSVG() {
|
|
if (signaturePaths.length === 0) {
|
|
return null;
|
|
}
|
|
|
|
let pathData = '';
|
|
signaturePaths.forEach(path => {
|
|
if (path.length > 0) {
|
|
pathData += `M ${path[0].x} ${path[0].y} `;
|
|
for (let i = 1; i < path.length; i++) {
|
|
pathData += `L ${path[i].x} ${path[i].y} `;
|
|
}
|
|
}
|
|
});
|
|
|
|
const svg = `<svg width="600" height="200" xmlns="http://www.w3.org/2000/svg"><path d="${pathData}" stroke="black" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
|
|
return svg;
|
|
}
|
|
|
|
// Form submission
|
|
async function submitSignature(e) {
|
|
e.preventDefault();
|
|
|
|
const name = document.getElementById('name').value;
|
|
const idCardDigits = document.getElementById('idCard').value;
|
|
const idCardPattern = /^\d{6}$/;
|
|
const signature = generateSVG();
|
|
|
|
if (!signature) {
|
|
showFormMessage('Please provide your signature.', 'error');
|
|
return;
|
|
}
|
|
|
|
// Ensure the signer has confirmed consent/accuracy
|
|
const consentElem = document.getElementById('confirm-consent');
|
|
const consentChecked = consentElem ? consentElem.checked : true;
|
|
if (!consentChecked) {
|
|
showFormMessage('Please confirm that your submission will be sent to the Parliament Petition Committee and that your information is true.', 'error');
|
|
return;
|
|
}
|
|
|
|
// Validate ID digits (6 digits) and assemble full ID with prefix 'A'
|
|
if (!idCardPattern.test(idCardDigits)) {
|
|
showFormMessage('Please enter your ID number as 6 digits (numbers only).', 'error');
|
|
return;
|
|
}
|
|
const idCard = 'A' + idCardDigits;
|
|
|
|
const petitionId = getPetitionIdFromUrl();
|
|
const apiUrl = `${API_CONFIG.baseUrl}/api/Sign/petition/${petitionId}`;
|
|
|
|
// Ensure Turnstile widget is rendered
|
|
ensureTurnstileRendered();
|
|
|
|
// Obtain token: prefer the callback value, fall back to getResponse or execute
|
|
let token = turnstileToken;
|
|
if ((!token || token.length === 0) && window.turnstile && turnstileWidgetId !== null) {
|
|
try {
|
|
if (typeof turnstile.getResponse === 'function') {
|
|
let resp = null;
|
|
try {
|
|
if (turnstileWidgetId !== null && turnstileWidgetId >= 0) {
|
|
resp = turnstile.getResponse(turnstileWidgetId);
|
|
} else {
|
|
// try without id (auto-rendered widgets may be retrievable this way)
|
|
resp = turnstile.getResponse();
|
|
}
|
|
} catch (e) {
|
|
resp = null;
|
|
}
|
|
if (resp) token = resp;
|
|
}
|
|
|
|
if ((!token || token.length === 0) && typeof turnstile.execute === 'function') {
|
|
// Trigger challenge; wait up to ~5s for callback to set token
|
|
try { turnstile.execute(turnstileWidgetId); } catch (err) { }
|
|
token = await new Promise((resolve) => {
|
|
let attempts = 0;
|
|
const interval = setInterval(() => {
|
|
attempts++;
|
|
if (turnstileToken) {
|
|
clearInterval(interval);
|
|
resolve(turnstileToken);
|
|
} else if (attempts > 25) { // ~5 seconds
|
|
clearInterval(interval);
|
|
resolve(null);
|
|
}
|
|
}, 200);
|
|
});
|
|
}
|
|
} catch (err) {
|
|
token = null;
|
|
}
|
|
}
|
|
|
|
if (!token) {
|
|
showFormMessage('Please complete the captcha challenge.', 'error');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(apiUrl, {
|
|
method: 'POST',
|
|
headers: {
|
|
'accept': '*/*',
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
name: name,
|
|
idCard: idCard,
|
|
signature: signature,
|
|
turnstileToken: token
|
|
})
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
showFormMessage('Signature submitted successfully!', 'success');
|
|
|
|
// Show tweet prompt modal
|
|
showTweetModal();
|
|
|
|
document.getElementById('signature-form').reset();
|
|
clearSignature();
|
|
|
|
// Refresh petition data to update signature count
|
|
setTimeout(() => {
|
|
fetchPetition(petitionId);
|
|
}, 1000);
|
|
|
|
} catch (error) {
|
|
showFormMessage(`Failed to submit signature: ${error.message}`, 'error');
|
|
} finally {
|
|
// Reset the Turnstile widget so a fresh token is required next time
|
|
try {
|
|
if (window.turnstile && turnstileWidgetId !== null) {
|
|
turnstile.reset(turnstileWidgetId);
|
|
}
|
|
} catch (e) { }
|
|
turnstileToken = null;
|
|
}
|
|
}
|
|
|
|
function showFormMessage(message, type) {
|
|
const messageDiv = document.getElementById('form-message');
|
|
messageDiv.textContent = message;
|
|
messageDiv.className = `form-message ${type}`;
|
|
messageDiv.style.display = 'block';
|
|
|
|
setTimeout(() => {
|
|
messageDiv.style.display = 'none';
|
|
}, 5000);
|
|
}
|
|
|
|
// Tweet Modal Functions
|
|
let currentPetitionData = null;
|
|
|
|
function updateModalLanguage() {
|
|
const translations = {
|
|
en: {
|
|
title: 'Share this petition!',
|
|
text: 'Help spread the word by tweeting about this petition.',
|
|
tweetBtn: 'Tweet Now',
|
|
skipBtn: 'Maybe Later'
|
|
},
|
|
dv: {
|
|
title: 'Share this petition!',
|
|
text: 'Help spread the word by tweeting about this petition.',
|
|
tweetBtn: 'Tweet Now',
|
|
skipBtn: 'Maybe Later'
|
|
}
|
|
};
|
|
|
|
const t = translations[currentLang];
|
|
|
|
document.getElementById('modal-title').textContent = t.title;
|
|
document.getElementById('modal-text').textContent = t.text;
|
|
document.getElementById('tweet-btn-text').textContent = t.tweetBtn;
|
|
document.getElementById('skip-btn-text').textContent = t.skipBtn;
|
|
}
|
|
|
|
function showTweetModal() {
|
|
updateModalLanguage();
|
|
const modal = document.getElementById('tweet-modal');
|
|
modal.classList.add('show');
|
|
}
|
|
|
|
function hideTweetModal() {
|
|
const modal = document.getElementById('tweet-modal');
|
|
modal.classList.remove('show');
|
|
}
|
|
|
|
function generateTweetText() {
|
|
if (!currentPetitionData) return '';
|
|
|
|
const petitionName = currentLang === 'dv' ? currentPetitionData.nameDhiv : currentPetitionData.nameEng;
|
|
const petitionUrl = `${window.location.origin}${window.location.pathname}?id=${currentPetitionData.id}`;
|
|
|
|
return `I just signed "${petitionName}"! \n\nAdd your signature: ${petitionUrl}`;
|
|
}
|
|
|
|
function openTwitterIntent() {
|
|
const tweetText = generateTweetText();
|
|
const twitterUrl = `https://twitter.com/intent/tweet?text=${encodeURIComponent(tweetText)}`;
|
|
console.log(twitterUrl);
|
|
window.open(twitterUrl, '_blank');
|
|
hideTweetModal();
|
|
}
|
|
|
|
function setupTweetModalListeners() {
|
|
const modal = document.getElementById('tweet-modal');
|
|
const tweetButton = document.getElementById('tweet-button');
|
|
const skipButton = document.getElementById('skip-tweet');
|
|
const closeButton = document.querySelector('.close-modal');
|
|
|
|
// Tweet button click
|
|
tweetButton.addEventListener('click', openTwitterIntent);
|
|
|
|
// Skip button click
|
|
skipButton.addEventListener('click', hideTweetModal);
|
|
|
|
// Close X click
|
|
closeButton.addEventListener('click', hideTweetModal);
|
|
|
|
// Click outside modal
|
|
modal.addEventListener('click', (e) => {
|
|
if (e.target === modal) {
|
|
hideTweetModal();
|
|
}
|
|
});
|
|
}
|
|
|
|
// Initialize on page load
|
|
window.addEventListener('DOMContentLoaded', () => {
|
|
const petitionId = getPetitionIdFromUrl();
|
|
|
|
if (!petitionId) {
|
|
showError('No petition ID found in URL. Please provide a valid petition URL.');
|
|
return;
|
|
}
|
|
|
|
// Get initial language from URL
|
|
currentLang = getLangFromUrl();
|
|
|
|
// Set up language switcher event listeners
|
|
document.getElementById('lang-en').addEventListener('click', () => switchLanguage('en'));
|
|
document.getElementById('lang-dv').addEventListener('click', () => switchLanguage('dv'));
|
|
|
|
// Initialize signature pad
|
|
initSignaturePad();
|
|
// Render Turnstile (retry until script available)
|
|
ensureTurnstileRendered();
|
|
|
|
// Set up form submission
|
|
document.getElementById('signature-form').addEventListener('submit', submitSignature);
|
|
|
|
// Set up tweet modal listeners
|
|
setupTweetModalListeners();
|
|
|
|
// Make clicking the 'A' prefix focus the ID input
|
|
document.querySelectorAll('.idcard-prefix').forEach(prefix => {
|
|
prefix.addEventListener('click', () => {
|
|
const input = prefix.parentElement.querySelector('input[id="idCard"]');
|
|
if (input) input.focus();
|
|
});
|
|
});
|
|
|
|
fetchPetition(petitionId);
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|