212 lines
7.9 KiB
JavaScript
212 lines
7.9 KiB
JavaScript
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) {
|
||
|
||
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();
|
||
}
|
||
|
||
|
||
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();
|
||
});
|
||
});
|
||
|
||
});
|