| 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 |
|
| 107 |
/** |
| 108 |
* Cancellation Flow - show only the discount input the chosen type uses. |
| 109 |
*/ |
| 110 |
(function () { |
| 111 |
"use strict"; |
| 112 |
|
| 113 |
var type = document.querySelector('input[name="subscrpt_cancellation_offer_type"]'); |
| 114 |
if (!type) { |
| 115 |
return; |
| 116 |
} |
| 117 |
|
| 118 |
var percent = document.getElementById("subscrpt_cancellation_offer_percent"); |
| 119 |
var amount = document.getElementById("subscrpt_cancellation_offer_amount"); |
| 120 |
|
| 121 |
/** |
| 122 |
* Toggle the two discount inputs for a type. |
| 123 |
* |
| 124 |
* @param {string} value `percent` or `fixed`. |
| 125 |
* @return {void} |
| 126 |
*/ |
| 127 |
function toggle(value) { |
| 128 |
if (percent) { |
| 129 |
percent.style.display = value === "fixed" ? "none" : ""; |
| 130 |
} |
| 131 |
if (amount) { |
| 132 |
amount.style.display = value === "fixed" ? "" : "none"; |
| 133 |
} |
| 134 |
} |
| 135 |
|
| 136 |
type.closest(".wpsubs-adv-select").addEventListener("wpsubs:select", function (e) { |
| 137 |
toggle((e.detail && e.detail.value) || type.value); |
| 138 |
}); |
| 139 |
})(); |
| 140 |
|