diff --git a/MassMailer.hta b/MassMailer.hta index d7c1b84..e7f4792 100644 --- a/MassMailer.hta +++ b/MassMailer.hta @@ -43,6 +43,7 @@ var pendingPath = ""; var pendingCampaignReview = null; var campaignTestAccepted = false; + var recipientSelection = {}; var dispatchSessionPid = 0; var dispatchSessionToken = ""; var dispatchSessionPath = ""; @@ -232,7 +233,7 @@ document.getElementById("importMessage").innerText = "Import failed: " + error.message; } finally { if (db !== null && db.State === 1) db.Close(); - if (succeeded) refreshStatus(); + if (succeeded) { refreshStatus(); refreshRecipients(); } } } function addSuppression() { @@ -261,7 +262,7 @@ document.getElementById("suppressMessage").innerText = "Suppression failed: " + error.message; } finally { if (db !== null && db.State === 1) db.Close(); - if (succeeded) refreshStatus(); + if (succeeded) { refreshStatus(); refreshRecipients(); } } } function powerShellHost() { @@ -460,6 +461,87 @@ if (db !== null && db.State === 1) db.Close(); } } + function selectedRecipientIds() { + var ids = []; + for (var id in recipientSelection) { + if (recipientSelection.hasOwnProperty(id) && recipientSelection[id]) ids.push(Number(id)); + } + return ids; + } + function updateRecipientCount() { + var total = 0; + for (var id in recipientSelection) if (recipientSelection.hasOwnProperty(id)) total++; + document.getElementById("recipientCount").innerText = + selectedRecipientIds().length + " of " + total + " eligible contacts selected"; + } + function toggleRecipient(box) { + recipientSelection[box.value] = box.checked; + updateRecipientCount(); + invalidateCampaignReview(); + } + function setVisibleRecipients(checked) { + var boxes = document.getElementById("recipientList").getElementsByTagName("input"); + for (var i = 0; i < boxes.length; i++) { + if (boxes[i].parentNode.parentNode.style.display === "none") continue; + boxes[i].checked = checked; + recipientSelection[boxes[i].value] = checked; + } + updateRecipientCount(); + invalidateCampaignReview(); + } + function filterRecipients() { + var needle = document.getElementById("recipientFilter").value.toLowerCase(); + var rows = document.getElementById("recipientList").getElementsByTagName("tr"); + for (var i = 0; i < rows.length; i++) { + rows[i].style.display = + rows[i].getAttribute("data-text").indexOf(needle) === -1 ? "none" : ""; + } + } + function refreshRecipients() { + var db = null; + try { + db = openDatabase().db; + var rows = db.Execute("SELECT c.[Id],c.[EmailOriginal],c.[BusinessName] FROM [Contact] AS c " + + "LEFT JOIN [Suppression] AS s ON c.[EmailKey]=s.[EmailKey] WHERE s.[EmailKey] IS NULL " + + "AND c.[Country]='US' AND c.[EligibilityBasis]='public_listing' ORDER BY c.[Id]"); + var body = document.getElementById("recipientList"); + while (body.firstChild) body.removeChild(body.firstChild); + var known = recipientSelection; + recipientSelection = {}; + while (!rows.EOF) { + var id = String(rows.Fields("Id").Value); + var email = String(rows.Fields("EmailOriginal").Value); + var business = rows.Fields("BusinessName").Value; + business = business === null ? "" : String(business); + recipientSelection[id] = known.hasOwnProperty(id) ? known[id] : true; + var tr = document.createElement("tr"); + tr.setAttribute("data-text", (email + " " + business).toLowerCase()); + var boxCell = document.createElement("td"); + var box = document.createElement("input"); + box.type = "checkbox"; + box.value = id; + box.checked = recipientSelection[id]; + box.onclick = function () { toggleRecipient(this); }; + boxCell.appendChild(box); + var emailCell = document.createElement("td"); + emailCell.innerText = email; + var businessCell = document.createElement("td"); + businessCell.innerText = business; + tr.appendChild(boxCell); + tr.appendChild(emailCell); + tr.appendChild(businessCell); + body.appendChild(tr); + rows.MoveNext(); + } + rows.Close(); + updateRecipientCount(); + filterRecipients(); + } catch (error) { + document.getElementById("campaignMessage").innerText = "Recipient list failed: " + error.message; + } finally { + if (db !== null && db.State === 1) db.Close(); + } + } function invalidateCampaignReview() { pendingCampaignReview = null; campaignTestAccepted = false; @@ -475,6 +557,7 @@ Name: document.getElementById("campaignName").value, Subject: document.getElementById("campaignSubject").value, TemplateId: document.getElementById("campaignTemplateVersion").value, + ContactIds: selectedRecipientIds(), ReviewToken: pendingCampaignReview ? pendingCampaignReview.Token : "", TestReceived: document.getElementById("confirmReceived").checked }; @@ -577,6 +660,7 @@ refreshStatus(); refreshTemplates(); refreshCampaigns(); + refreshRecipients(); initializeDispatch(); } catch (error) { document.getElementById("dispatchMessage").innerText = @@ -866,10 +950,19 @@
Approval captures currently eligible contacts and the selected template version. It requires a complete postal address in config.ini, a campaign-specific internal test, and your confirmation that you received it. Approved campaigns stay paused until you resume them.
+Approval captures the contacts you select below (from currently eligible, unsuppressed contacts) and the selected template version. It requires a complete postal address in config.ini, a campaign-specific internal test, and your confirmation that you received it. Approved campaigns stay paused until you resume them.
+