/* * Student Welcome Guide - "Was this page helpful?" feedback. * On a vote the chosen button is highlighted and locked, a thank-you appears, * and (on "No") a short comment box is offered. Voting is locked for the current * page view, so to give feedback again the visitor reloads the page. * * "Yes" is submitted immediately. "No" is submitted together with the comment as * a single row when the visitor clicks Send; if they leave without commenting, * the "No" is still recorded once via sendBeacon on page-leave. This avoids the * "No" and the comment landing on two separate rows. * * Votes are sent to a Google Form (see setup notes at the bottom). If the form * is not configured, the widget still works locally and "No" still routes the * visitor to email / the Viber community. */ (function () { 'use strict'; /* Google Form collection. Fill in all four values to turn it on. */ var GOOGLE_FORM = { action: 'https://docs.google.com/forms/d/e/1FAIpQLSc4i6fdIpR3D8nuEJ_yvxlHUBRRO-8Z-vP4WF-qtk17uzkYog/formResponse', pageField: 'entry.1926483387', // Question 1 (Page) helpfulField: 'entry.971202016', // Question 2 (Helpful) commentField: 'entry.1634915934' // Question 3 (Comment) }; // "No" votes awaiting submission (visitor clicked No but has not sent yet). var pending = []; function pageLabel(slug) { var lang = (document.documentElement.getAttribute('lang') || '').toLowerCase(); return lang ? slug + ' (' + lang + ')' : slug; } function buildParams(slug, value, comment) { var params = new URLSearchParams(); params.append(GOOGLE_FORM.pageField, pageLabel(slug)); if (value) { params.append(GOOGLE_FORM.helpfulField, value); } if (comment && GOOGLE_FORM.commentField) { params.append(GOOGLE_FORM.commentField, comment); } return params; } function submit(slug, value, comment) { if (!GOOGLE_FORM.action) { return; } try { // no-cors: Google Forms returns no CORS headers, so the response cannot be // read, but the submission is recorded. fetch(GOOGLE_FORM.action, { method: 'POST', mode: 'no-cors', body: buildParams(slug, value, comment) }); } catch (e) {} if (typeof window.plausible === 'function') { try { window.plausible('Guide feedback', { props: { page: pageLabel(slug), value: value || 'comment' } }); } catch (e) {} } } function flushPending() { for (var i = 0; i < pending.length; i++) { var slug = pending[i]; if (GOOGLE_FORM.action && navigator.sendBeacon) { try { navigator.sendBeacon(GOOGLE_FORM.action, buildParams(slug, 'no', '')); } catch (e) {} } else { submit(slug, 'no', ''); } } pending = []; } window.addEventListener('pagehide', flushPending); function setup(fb) { if (fb.getAttribute('data-ready')) { return; } fb.setAttribute('data-ready', '1'); var slug = fb.getAttribute('data-slug') || location.pathname; var buttons = fb.querySelectorAll('[data-vote]'); var yesMsg = fb.querySelector('.guide-feedback-yes'); var noMsg = fb.querySelector('.guide-feedback-no'); var comment = fb.querySelector('.guide-feedback-comment'); var commentInput = fb.querySelector('.guide-feedback-comment-input'); var commentSend = fb.querySelector('.guide-feedback-comment-send'); var commentThanks = fb.querySelector('.guide-feedback-comment-thanks'); var voted = false; var noPending = false; function clearPending() { if (!noPending) { return; } noPending = false; var idx = pending.indexOf(slug); if (idx > -1) { pending.splice(idx, 1); } } function onVote() { /* jshint validthis:true */ if (voted) { return; } voted = true; var value = this.getAttribute('data-vote'); for (var i = 0; i < buttons.length; i++) { buttons[i].disabled = true; } this.classList.add('is-selected'); if (value === 'yes') { submit(slug, 'yes', ''); if (yesMsg) { yesMsg.hidden = false; } } else { // Hold the "No" until the comment is sent (or the page is left), so both // land on the same row. noPending = true; pending.push(slug); if (noMsg) { noMsg.hidden = false; } if (comment) { comment.hidden = false; } } } for (var i = 0; i < buttons.length; i++) { buttons[i].addEventListener('click', onVote); } if (commentSend) { commentSend.addEventListener('click', function () { var text = commentInput ? commentInput.value.replace(/^\s+|\s+$/g, '') : ''; if (!text) { if (commentInput) { commentInput.focus(); } return; } clearPending(); submit(slug, 'no', text); commentSend.disabled = true; if (commentInput) { commentInput.disabled = true; } if (commentThanks) { commentThanks.hidden = false; } }); } } function init() { var widgets = document.querySelectorAll('.guide-feedback'); for (var i = 0; i < widgets.length; i++) { setup(widgets[i]); } } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })(); /* * --------------------------------------------------------------------------- * Google Form collection * --------------------------------------------------------------------------- * Three questions are wired: Page, Helpful, Comment (entry IDs above). * The "Page" value sent is the slug plus language, e.g. * "student-residence-permit (mk)". * * Rows you will see: * - Yes vote -> Helpful = yes, Comment empty * - No with a comment -> Helpful = no, Comment = the text (one row) * - No without comment -> Helpful = no, Comment empty (sent on leave) * A "No" produces exactly one row either way. */