Ansico-SEO/ansico-wp-basic/assets/admin.js

161 lines
5.8 KiB
JavaScript
Raw Normal View History

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');
if (!titleInput || !descInput || !snippet) {
return;
}
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();
});