Edit your new HTML Content block and drop this into the HTML field. The only thing you might want to change is the very first line, {% assign creditTerm = 'Credit' %}. Swap 'Credit' for 'Segment' (or whatever terminology your team prefers).
{% assign creditTerm = 'Credit' %}
{% raw %}
<style>
#segcalc-popover { border: none; padding: 0; margin: 0; background: transparent; overflow: visible; inset: auto; }
#segcalc-popover::backdrop { background: transparent; }
</style>
<button type="button" class="btn btn-primary pull-right my-3 segcalc-trigger" popovertarget="segcalc-popover" style="display:none;">
SMS Calculator
</button>
<div class="clearfix"></div>
<div id="segcalc-popover" popover>
<div class="panel panel-default" style="width: 360px; margin: 0; box-shadow: 0 12px 40px rgba(0,0,0,0.15);">
<div class="panel-heading segcalc-handle" style="cursor: move; user-select: none;">
<button type="button" class="close" popovertarget="segcalc-popover" popovertargetaction="hide">×</button>
<h3 class="panel-title">SMS <span data-term-plural></span> Calculator</h3>
</div>
<div class="panel-body">
<textarea id="segcalc-input" class="form-control" rows="4" placeholder="Type or paste your message..."></textarea>
<div class="row text-center" style="margin-top: 12px;">
<div class="col-xs-3">
<small class="text-muted">ENCODING</small>
<div><strong id="segcalc-encoding" class="text-success">GSM-7</strong></div>
</div>
<div class="col-xs-3">
<small class="text-muted">CHARS</small>
<div><strong id="segcalc-chars">0</strong></div>
</div>
<div class="col-xs-3">
<small class="text-muted" data-term-plural-upper></small>
<div><strong id="segcalc-credits">0</strong></div>
</div>
<div class="col-xs-3">
<small class="text-muted">LEFT</small>
<div><strong id="segcalc-remaining">160</strong></div>
</div>
</div>
<div id="segcalc-warn" class="alert alert-warning" style="display:none; margin-top: 12px; margin-bottom: 0; padding: 6px 10px; font-size: 12px;"></div>
<div id="segcalc-total" style="display:none; margin-top: 12px; padding-top: 10px; border-top: 1px solid #eee; text-align: center;">
<small class="text-muted">TOTAL FOR <span id="segcalc-recipient-count"></span> RECIPIENTS</small>
<div style="font-size: 18px;"><strong id="segcalc-total-value">0</strong> <span data-term-plural-lower></span></div>
</div>
</div>
</div>
</div>
<script>
(function () {
{% endraw %}
var TERM_SINGULAR = {{ creditTerm | ToJSON }};
var TERM_PLURAL = {{ creditTerm | Pluralize | ToJSON }};
{% raw %}
document.querySelectorAll('[data-term-plural]').forEach(function (el) { el.textContent = TERM_PLURAL; });
document.querySelectorAll('[data-term-plural-upper]').forEach(function (el) { el.textContent = TERM_PLURAL.toUpperCase(); });
document.querySelectorAll('[data-term-plural-lower]').forEach(function (el) { el.textContent = TERM_PLURAL.toLowerCase(); });
var GSM_BASIC = '@£$¥èéùìòÇ\nØø\rÅåΔ_ΦΓΛΩΠΨΣΘΞ\u001bÆæßÉ !"#¤%&\'()*+,-./0123456789:;<=>?¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà';
var GSM_EXT = '\f^{}\\[~]|€';
function analyze(text) {
var isUcs2 = false;
for (var i = 0; i < text.length; i++) {
var ch = text.charAt(i);
if (GSM_BASIC.indexOf(ch) === -1 && GSM_EXT.indexOf(ch) === -1) {
isUcs2 = true;
break;
}
}
var count, singleLimit, concatLimit;
if (isUcs2) {
count = text.length;
singleLimit = 70; concatLimit = 67;
} else {
count = 0;
for (var j = 0; j < text.length; j++) count += GSM_EXT.indexOf(text.charAt(j)) !== -1 ? 2 : 1;
singleLimit = 160; concatLimit = 153;
}
var unicodeChars = [];
if (isUcs2) {
var seen = {};
var graphemes = (typeof Intl !== 'undefined' && Intl.Segmenter)
? Array.from(new Intl.Segmenter('en', { granularity: 'grapheme' }).segment(text), function (s) { return s.segment; })
: Array.from(text);
for (var k = 0; k < graphemes.length; k++) {
var g = graphemes[k];
if (g.length === 1 && (GSM_BASIC.indexOf(g) !== -1 || GSM_EXT.indexOf(g) !== -1)) continue;
if (seen[g]) continue;
seen[g] = true;
unicodeChars.push(g);
}
}
var credits, remaining;
if (count === 0) { credits = 0; remaining = singleLimit; }
else if (count <= singleLimit) { credits = 1; remaining = singleLimit - count; }
else { credits = Math.ceil(count / concatLimit); remaining = (credits * concatLimit) - count; }
return { encoding: isUcs2 ? 'UCS-2' : 'GSM-7', count: count, credits: credits, remaining: remaining, unicodeChars: unicodeChars };
}
var input = document.getElementById('segcalc-input');
var trigger = document.querySelector('.segcalc-trigger');
var popover = document.getElementById('segcalc-popover');
var els = {
enc: document.getElementById('segcalc-encoding'),
chars: document.getElementById('segcalc-chars'),
segs: document.getElementById('segcalc-credits'),
rem: document.getElementById('segcalc-remaining'),
warn: document.getElementById('segcalc-warn'),
totalWrap: document.getElementById('segcalc-total'),
totalValue: document.getElementById('segcalc-total-value'),
recipientCount: document.getElementById('segcalc-recipient-count')
};
var recipientCount = 0;
function readRecipientCount() {
var label = document.querySelector('.sms-editor-panel-title-right .label-info');
if (!label) return 0;
var match = label.textContent.replace(/,/g, '').match(/\d+/);
return match ? parseInt(match[0], 10) : 0;
}
function refreshTotal() {
if (recipientCount > 0) {
els.recipientCount.textContent = recipientCount.toLocaleString();
els.totalWrap.style.display = 'block';
var r = analyze(input.value);
els.totalValue.textContent = (r.credits * recipientCount).toLocaleString();
} else {
els.totalWrap.style.display = 'none';
}
}
function update() {
var r = analyze(input.value);
els.enc.textContent = r.encoding;
els.enc.className = r.encoding === 'UCS-2' ? 'text-warning' : 'text-success';
els.chars.textContent = r.count;
els.segs.textContent = r.credits;
els.rem.textContent = r.remaining;
if (r.encoding === 'UCS-2') {
var preview = r.unicodeChars.slice(0, 6).join(' ');
els.warn.textContent = 'UCS-2 triggered by: ' + preview + (r.unicodeChars.length > 6 ? '…' : '');
els.warn.style.display = 'block';
} else {
els.warn.style.display = 'none';
}
refreshTotal();
}
input.addEventListener('input', update);
popover.addEventListener('toggle', function (e) {
if (e.newState !== 'open') return;
recipientCount = readRecipientCount();
refreshTotal();
var rect = trigger.getBoundingClientRect();
var width = 360;
var left = Math.min(rect.left, window.innerWidth - width - 8);
popover.style.position = 'fixed';
popover.style.top = (rect.bottom + 8) + 'px';
popover.style.left = Math.max(8, left) + 'px';
setTimeout(function () { input.focus(); }, 50);
});
var header = popover.querySelector('.segcalc-handle');
var dragState = null;
header.addEventListener('pointerdown', function (e) {
if (e.target.closest('.close')) return;
e.preventDefault();
var rect = popover.getBoundingClientRect();
dragState = { offsetX: e.clientX - rect.left, offsetY: e.clientY - rect.top };
header.setPointerCapture(e.pointerId);
});
header.addEventListener('pointermove', function (e) {
if (!dragState) return;
var newLeft = e.clientX - dragState.offsetX;
var newTop = e.clientY - dragState.offsetY;
newLeft = Math.max(0, Math.min(window.innerWidth - popover.offsetWidth, newLeft));
newTop = Math.max(0, Math.min(window.innerHeight - popover.offsetHeight, newTop));
popover.style.left = newLeft + 'px';
popover.style.top = newTop + 'px';
});
header.addEventListener('pointerup', function () { dragState = null; });
header.addEventListener('pointercancel', function () { dragState = null; });
var rafScheduled = false;
function syncFromDom() {
if (rafScheduled) return;
rafScheduled = true;
requestAnimationFrame(function () {
rafScheduled = false;
var present = document.querySelector('.sms-editor-panel-title') !== null;
trigger.style.display = present ? '' : 'none';
if (!present && popover.matches(':popover-open')) {
popover.hidePopover();
}
var newCount = readRecipientCount();
if (newCount !== recipientCount) {
recipientCount = newCount;
if (popover.matches(':popover-open')) refreshTotal();
}
});
}
syncFromDom();
new MutationObserver(syncFromDom).observe(document.body, { childList: true, subtree: true });
update();
})();
</script>
{% endraw %}
Save the block, head to a communication that has SMS enabled, and you should see a blue SMS Calculator button float in on the right side of the page. Click it, drag it wherever you want, paste a message, and watch it count.