| 1 |
/** |
| 2 |
* Cancellation Flow - keep the Reasons tab's list in step with the editor. |
| 3 |
* |
| 4 |
* The list is rendered from the saved option, so on its own it only caught up |
| 5 |
* on Save Changes: a reason added in "Manage reasons" disappeared from the page |
| 6 |
* when the modal closed, which reads as "it was not added". It now mirrors the |
| 7 |
* editor's `wpsubs:change` event (fired after every add, remove and reorder), |
| 8 |
* and a note beside Save Changes says the change is not saved yet. |
| 9 |
*/ |
| 10 |
(function () { |
| 11 |
"use strict"; |
| 12 |
|
| 13 |
var OPTION = "subscrpt_cancellation_reasons"; |
| 14 |
|
| 15 |
var preview = document.querySelector("[data-subscrpt-reason-preview]"); |
| 16 |
if (!preview) { |
| 17 |
return; |
| 18 |
} |
| 19 |
|
| 20 |
var empty = document.querySelector("[data-subscrpt-reason-empty]"); |
| 21 |
var unsaved = document.querySelector("[data-subscrpt-unsaved]"); |
| 22 |
var auto = preview.querySelector("[data-subscrpt-reason-auto]"); |
| 23 |
var field = document.querySelector('input[name="' + OPTION + '"]'); |
| 24 |
|
| 25 |
/** |
| 26 |
* A comparable fingerprint of a reason list: keys and labels, in order. |
| 27 |
* |
| 28 |
* @param {Array<{key?: string, label?: string}>} items Reason items. |
| 29 |
* @return {string} Fingerprint. |
| 30 |
*/ |
| 31 |
function signature(items) { |
| 32 |
return items |
| 33 |
.map(function (item) { |
| 34 |
// Tab and newline cannot occur in a saved label (sanitize_text_field). |
| 35 |
return String(item.key || "") + "\t" + String(item.label || "").trim(); |
| 36 |
}) |
| 37 |
.join("\n"); |
| 38 |
} |
| 39 |
|
| 40 |
// What is saved, read before the editor starts. The editor also fires |
| 41 |
// `wpsubs:change` once while initialising, so "changed" has to mean |
| 42 |
// "differs from this", not "an event arrived" - and undoing an edit hides |
| 43 |
// the note again. |
| 44 |
var saved = ""; |
| 45 |
try { |
| 46 |
saved = signature(JSON.parse((field && field.value) || "[]")); |
| 47 |
} catch (err) { |
| 48 |
saved = ""; |
| 49 |
} |
| 50 |
|
| 51 |
/** |
| 52 |
* Whether an item is a typed "Other". |
| 53 |
* |
| 54 |
* The survey adds its own "Other" and the server drops a typed one on save, |
| 55 |
* so the list leaves it out too rather than show a row that will not be kept. |
| 56 |
* |
| 57 |
* @param {{key?: string, label?: string}} item Editor item. |
| 58 |
* @return {boolean} True for an "Other" entry. |
| 59 |
*/ |
| 60 |
function isOther(item) { |
| 61 |
var key = String(item.key || "").toLowerCase(); |
| 62 |
var label = String(item.label || "") |
| 63 |
.trim() |
| 64 |
.toLowerCase(); |
| 65 |
return key === "other" || label === "other"; |
| 66 |
} |
| 67 |
|
| 68 |
/** |
| 69 |
* Re-render the list from the editor's items, keeping the automatic "Other" last. |
| 70 |
* |
| 71 |
* @param {Array<{key?: string, label?: string}>} items Editor items, in order. |
| 72 |
* @return {void} |
| 73 |
*/ |
| 74 |
function render(items) { |
| 75 |
var rows = items.filter(function (item) { |
| 76 |
return item && String(item.label || "").trim() !== "" && !isOther(item); |
| 77 |
}); |
| 78 |
|
| 79 |
Array.prototype.slice.call(preview.querySelectorAll("li:not([data-subscrpt-reason-auto])")).forEach(function (li) { |
| 80 |
li.remove(); |
| 81 |
}); |
| 82 |
|
| 83 |
rows.forEach(function (item) { |
| 84 |
var li = document.createElement("li"); |
| 85 |
li.textContent = String(item.label).trim(); |
| 86 |
preview.insertBefore(li, auto); |
| 87 |
}); |
| 88 |
|
| 89 |
preview.hidden = rows.length === 0; |
| 90 |
if (empty) { |
| 91 |
empty.hidden = rows.length > 0; |
| 92 |
} |
| 93 |
if (unsaved) { |
| 94 |
unsaved.hidden = signature(items) === saved; |
| 95 |
} |
| 96 |
} |
| 97 |
|
| 98 |
document.addEventListener("wpsubs:change", function (e) { |
| 99 |
var field = e.target && e.target.querySelector ? e.target.querySelector('input[name="' + OPTION + '"]') : null; |
| 100 |
if (!field) { |
| 101 |
return; |
| 102 |
} |
| 103 |
render((e.detail && e.detail.items) || []); |
| 104 |
}); |
| 105 |
})(); |
| 106 |
|