2026-04-16 16:52:37 +00:00
|
|
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
|
|
|
|
var titleInput = document.getElementById('ansico_wp_basic_meta_title');
|
|
|
|
|
|
var descInput = document.getElementById('ansico_wp_basic_meta_description');
|
|
|
|
|
|
var snippet = document.querySelector('.ansico-wp-basic-snippet');
|
|
|
|
|
|
|
2026-04-17 21:07:12 +00:00
|
|
|
|
if (titleInput && descInput && snippet) {
|
2026-04-16 16:52:37 +00:00
|
|
|
|
|
|
|
|
|
|
var titleTarget = snippet.querySelector('.ansico-wp-basic-snippet-title');
|
|
|
|
|
|
var descTextTarget = snippet.querySelector('.ansico-wp-basic-snippet-description-text');
|
|
|
|
|
|
var urlTarget = snippet.querySelector('.ansico-wp-basic-snippet-url');
|
|
|
|
|
|
var truncationNote = document.querySelector('.ansico-wp-basic-truncation-note');
|
|
|
|
|
|
var titleCounter = document.querySelector('[data-counter-for="title"]');
|
|
|
|
|
|
var descCounter = document.querySelector('[data-counter-for="description"]');
|
|
|
|
|
|
|
|
|
|
|
|
var titleMaxPixels = 580;
|
|
|
|
|
|
var descMaxPixels = 920;
|
|
|
|
|
|
var titleIdealMin = 30;
|
|
|
|
|
|
var titleIdealMax = 60;
|
|
|
|
|
|
var descIdealMin = 70;
|
|
|
|
|
|
var descIdealMax = 155;
|
|
|
|
|
|
|
|
|
|
|
|
var titleCanvas = document.createElement('canvas');
|
|
|
|
|
|
var descCanvas = document.createElement('canvas');
|
|
|
|
|
|
var titleContext = titleCanvas.getContext('2d');
|
|
|
|
|
|
var descContext = descCanvas.getContext('2d');
|
|
|
|
|
|
titleContext.font = '400 22px Arial';
|
|
|
|
|
|
descContext.font = '400 14px Arial';
|
|
|
|
|
|
|
|
|
|
|
|
function measure(context, text) {
|
|
|
|
|
|
return Math.round(context.measureText(text || '').width);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function truncateByPixels(text, maxPixels, context) {
|
|
|
|
|
|
text = (text || '').trim();
|
|
|
|
|
|
var fullWidth = measure(context, text);
|
|
|
|
|
|
|
|
|
|
|
|
if (!text || fullWidth <= maxPixels) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
visible: text,
|
|
|
|
|
|
isTruncated: false,
|
|
|
|
|
|
hiddenChars: 0,
|
|
|
|
|
|
hiddenText: '',
|
|
|
|
|
|
width: fullWidth
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var ellipsis = '…';
|
|
|
|
|
|
var low = 0;
|
|
|
|
|
|
var high = text.length;
|
|
|
|
|
|
var best = '';
|
|
|
|
|
|
|
|
|
|
|
|
while (low <= high) {
|
|
|
|
|
|
var mid = Math.floor((low + high) / 2);
|
|
|
|
|
|
var candidate = text.slice(0, mid).replace(/[\s.,;:-]+$/u, '');
|
|
|
|
|
|
var candidateWithEllipsis = candidate + ellipsis;
|
|
|
|
|
|
if (measure(context, candidateWithEllipsis) <= maxPixels) {
|
|
|
|
|
|
best = candidate;
|
|
|
|
|
|
low = mid + 1;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
high = mid - 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!best) {
|
|
|
|
|
|
best = text.slice(0, 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var hiddenText = text.slice(best.length).trim();
|
|
|
|
|
|
return {
|
|
|
|
|
|
visible: best + ellipsis,
|
|
|
|
|
|
isTruncated: true,
|
|
|
|
|
|
hiddenChars: hiddenText.length,
|
|
|
|
|
|
hiddenText: hiddenText,
|
|
|
|
|
|
width: fullWidth
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function setCounter(el, current, minIdeal, maxIdeal, pxWidth, pxLimit, overflowText) {
|
|
|
|
|
|
if (!el) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
el.classList.remove('is-good', 'is-warning', 'is-danger');
|
|
|
|
|
|
|
|
|
|
|
|
var statusClass = 'is-good';
|
|
|
|
|
|
var notes = [];
|
|
|
|
|
|
|
|
|
|
|
|
if (current === 0) {
|
|
|
|
|
|
statusClass = 'is-warning';
|
|
|
|
|
|
notes.push('empty');
|
|
|
|
|
|
} else if (current < minIdeal) {
|
|
|
|
|
|
statusClass = 'is-warning';
|
|
|
|
|
|
notes.push('a bit short');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (current > maxIdeal || pxWidth > pxLimit) {
|
|
|
|
|
|
statusClass = (current > maxIdeal + 15 || pxWidth > pxLimit + 120) ? 'is-danger' : 'is-warning';
|
|
|
|
|
|
notes.push(overflowText);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
el.classList.add(statusClass);
|
|
|
|
|
|
el.textContent = current + ' chars · ' + pxWidth + ' px';
|
|
|
|
|
|
if (notes.length) {
|
|
|
|
|
|
el.textContent += ' — ' + notes.join(' · ');
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function updateSnippet() {
|
|
|
|
|
|
var rawTitle = titleInput.value.trim() || snippet.dataset.fallbackTitle || '';
|
|
|
|
|
|
var siteName = (snippet.dataset.siteName || '').trim();
|
|
|
|
|
|
var title = rawTitle;
|
|
|
|
|
|
if (siteName && rawTitle.toLowerCase().indexOf(siteName.toLowerCase()) === -1) {
|
|
|
|
|
|
title += ' - ' + siteName;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var desc = descInput.value.trim() || 'This is how your page may appear in Google search results when a meta description is available.';
|
|
|
|
|
|
var permalink;
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
permalink = new URL(snippet.dataset.permalink);
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
permalink = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var host = permalink ? permalink.hostname.replace(/^www\./, '') : '';
|
|
|
|
|
|
var path = permalink ? permalink.pathname.replace(/^\//, '').replace(/\/$/, '') : '';
|
|
|
|
|
|
var prettyUrl = host;
|
|
|
|
|
|
if (path) {
|
|
|
|
|
|
prettyUrl += ' › ' + path.replace(/\//g, ' › ');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var titleResult = truncateByPixels(title, titleMaxPixels, titleContext);
|
|
|
|
|
|
var descResult = truncateByPixels(desc, descMaxPixels, descContext);
|
|
|
|
|
|
var rawTitleWidth = measure(titleContext, title);
|
|
|
|
|
|
var rawDescWidth = measure(descContext, desc);
|
|
|
|
|
|
|
|
|
|
|
|
titleTarget.textContent = titleResult.visible;
|
|
|
|
|
|
descTextTarget.textContent = descResult.visible;
|
|
|
|
|
|
urlTarget.textContent = prettyUrl;
|
|
|
|
|
|
|
|
|
|
|
|
setCounter(titleCounter, rawTitle.length, titleIdealMin, titleIdealMax, rawTitleWidth, titleMaxPixels, 'will truncate in preview');
|
|
|
|
|
|
setCounter(descCounter, desc.length, descIdealMin, descIdealMax, rawDescWidth, descMaxPixels, 'will truncate in preview');
|
|
|
|
|
|
|
|
|
|
|
|
if (truncationNote) {
|
|
|
|
|
|
if (descResult.isTruncated) {
|
|
|
|
|
|
truncationNote.textContent = 'Preview is truncating the meta description. About ' + descResult.hiddenChars + ' characters are no longer visible.';
|
|
|
|
|
|
truncationNote.classList.add('is-warning');
|
|
|
|
|
|
} else {
|
|
|
|
|
|
truncationNote.textContent = 'Preview currently fits within the available description space.';
|
|
|
|
|
|
truncationNote.classList.remove('is-warning');
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
titleInput.addEventListener('input', updateSnippet);
|
|
|
|
|
|
descInput.addEventListener('input', updateSnippet);
|
|
|
|
|
|
updateSnippet();
|
2026-04-17 21:07:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
document.querySelectorAll('.ansico-wp-basic-copy-button').forEach(function (button) {
|
|
|
|
|
|
button.addEventListener('click', function () {
|
|
|
|
|
|
var text = button.getAttribute('data-copy-text') || '';
|
|
|
|
|
|
if (!text) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var resetButtonState = function () {
|
|
|
|
|
|
button.classList.remove('is-copied');
|
|
|
|
|
|
button.setAttribute('title', button.getAttribute('data-original-title') || '');
|
|
|
|
|
|
button.setAttribute('aria-label', button.getAttribute('data-original-label') || '');
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
if (!button.hasAttribute('data-original-title')) {
|
|
|
|
|
|
button.setAttribute('data-original-title', button.getAttribute('title') || '');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!button.hasAttribute('data-original-label')) {
|
|
|
|
|
|
button.setAttribute('data-original-label', button.getAttribute('aria-label') || '');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var markCopied = function () {
|
|
|
|
|
|
button.classList.add('is-copied');
|
|
|
|
|
|
button.setAttribute('title', 'Copied');
|
|
|
|
|
|
button.setAttribute('aria-label', 'Copied');
|
|
|
|
|
|
window.setTimeout(resetButtonState, 1500);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
|
|
|
|
navigator.clipboard.writeText(text).then(markCopied).catch(function () {
|
|
|
|
|
|
var tempInput = document.createElement('input');
|
|
|
|
|
|
tempInput.value = text;
|
|
|
|
|
|
document.body.appendChild(tempInput);
|
|
|
|
|
|
tempInput.select();
|
|
|
|
|
|
document.execCommand('copy');
|
|
|
|
|
|
document.body.removeChild(tempInput);
|
|
|
|
|
|
markCopied();
|
|
|
|
|
|
});
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var tempInput = document.createElement('input');
|
|
|
|
|
|
tempInput.value = text;
|
|
|
|
|
|
document.body.appendChild(tempInput);
|
|
|
|
|
|
tempInput.select();
|
|
|
|
|
|
document.execCommand('copy');
|
|
|
|
|
|
document.body.removeChild(tempInput);
|
|
|
|
|
|
markCopied();
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2026-04-16 16:52:37 +00:00
|
|
|
|
});
|