font management fixes
This commit is contained in:
parent
847ed92c23
commit
d5ecb31dad
8 changed files with 728 additions and 99 deletions
|
|
@ -71,33 +71,26 @@
|
|||
|
||||
/* Search Input */
|
||||
.mlf-search-wrapper {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
.mlf-search-icon {
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: #646970;
|
||||
font-size: 18px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
.mlf-search-input {
|
||||
flex: 1;
|
||||
padding: 6px 12px !important;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.mlf-search-input {
|
||||
width: 100% !important;
|
||||
max-width: none !important;
|
||||
padding-left: 36px !important;
|
||||
padding-right: 36px !important;
|
||||
.mlf-search-btn {
|
||||
flex-shrink: 0;
|
||||
height: 36px;
|
||||
padding: 0 16px !important;
|
||||
}
|
||||
|
||||
.mlf-search-spinner {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
flex-shrink: 0;
|
||||
float: none !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
|
@ -183,6 +176,14 @@
|
|||
font-style: italic;
|
||||
}
|
||||
|
||||
.mlf-search-error {
|
||||
padding: 16px 24px;
|
||||
text-align: center;
|
||||
color: #8b6914;
|
||||
background: #fcf9e8;
|
||||
border-bottom: 1px solid #f0e6c8;
|
||||
}
|
||||
|
||||
/* Selected Font */
|
||||
.mlf-selected-font {
|
||||
margin-top: 16px;
|
||||
|
|
@ -313,6 +314,26 @@
|
|||
margin-top: 1px;
|
||||
}
|
||||
|
||||
/* Section Header */
|
||||
.mlf-section-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.mlf-section-header h2 {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.mlf-check-updates-btn {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Font List */
|
||||
.mlf-font-list {
|
||||
display: flex;
|
||||
|
|
@ -334,17 +355,61 @@
|
|||
flex: 1;
|
||||
}
|
||||
|
||||
.mlf-font-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.mlf-font-name {
|
||||
margin: 0 0 4px 0;
|
||||
margin: 0;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.mlf-update-badge {
|
||||
display: inline-block;
|
||||
padding: 2px 8px;
|
||||
background: #fcf9e8;
|
||||
border: 1px solid #d4b106;
|
||||
border-radius: 3px;
|
||||
color: #8b6914;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.mlf-font-variants {
|
||||
margin: 0;
|
||||
margin: 0 0 4px 0;
|
||||
color: #646970;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.mlf-font-meta {
|
||||
margin: 0;
|
||||
color: #8c8f94;
|
||||
font-size: 0.8em;
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.mlf-font-version {
|
||||
font-family: monospace;
|
||||
background: #f0f0f1;
|
||||
padding: 1px 6px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.mlf-update-btn {
|
||||
color: #2271b1;
|
||||
border-color: #2271b1;
|
||||
}
|
||||
|
||||
.mlf-update-btn:hover {
|
||||
background: #2271b1;
|
||||
color: #fff;
|
||||
border-color: #2271b1;
|
||||
}
|
||||
|
||||
.mlf-font-actions {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,12 @@
|
|||
*/
|
||||
selectedFont: null,
|
||||
|
||||
/**
|
||||
* Currently selected font version info.
|
||||
*/
|
||||
selectedFontVersion: null,
|
||||
selectedFontLastModified: null,
|
||||
|
||||
/**
|
||||
* Loaded font preview stylesheets.
|
||||
*/
|
||||
|
|
@ -34,19 +40,25 @@
|
|||
* Bind event handlers.
|
||||
*/
|
||||
bindEvents: function() {
|
||||
// Search input
|
||||
$('#mlf-font-search').on('input', this.handleSearchInput.bind(this));
|
||||
// Search button click
|
||||
$('#mlf-search-btn').on('click', this.handleSearchClick.bind(this));
|
||||
|
||||
// Search on Enter key
|
||||
$('#mlf-font-search').on('keypress', this.handleSearchKeypress.bind(this));
|
||||
|
||||
// Click outside to close search results
|
||||
$(document).on('click', this.handleDocumentClick.bind(this));
|
||||
|
||||
// Prevent closing when clicking inside search area
|
||||
// Prevent closing when clicking inside search area (but not on result items)
|
||||
$('.mlf-import-section').on('click', function(e) {
|
||||
e.stopPropagation();
|
||||
// Don't stop propagation if clicking on a result item
|
||||
if (!$(e.target).closest('.mlf-result-item').length) {
|
||||
e.stopPropagation();
|
||||
}
|
||||
});
|
||||
|
||||
// Font selection from results
|
||||
$(document).on('click', '.mlf-result-item', this.handleFontSelect.bind(this));
|
||||
// Font selection from results - bind to results container
|
||||
$('#mlf-search-results').on('click', '.mlf-result-item', this.handleFontSelect.bind(this));
|
||||
|
||||
// Change font button
|
||||
$('#mlf-change-font').on('click', this.handleChangeFont.bind(this));
|
||||
|
|
@ -56,31 +68,48 @@
|
|||
|
||||
// Delete button clicks
|
||||
$(document).on('click', '.mlf-delete-btn', this.handleDelete.bind(this));
|
||||
|
||||
// Check for updates button
|
||||
$('#mlf-check-updates').on('click', this.handleCheckUpdates.bind(this));
|
||||
|
||||
// Update button clicks
|
||||
$(document).on('click', '.mlf-update-btn', this.handleUpdateFont.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle search input (debounced).
|
||||
* Handle search button click.
|
||||
*
|
||||
* @param {Event} e Input event.
|
||||
* @param {Event} e Click event.
|
||||
*/
|
||||
handleSearchInput: function(e) {
|
||||
var query = $(e.target).val().trim();
|
||||
handleSearchClick: function(e) {
|
||||
e.preventDefault();
|
||||
this.triggerSearch();
|
||||
},
|
||||
|
||||
// Clear previous timer
|
||||
if (this.searchTimer) {
|
||||
clearTimeout(this.searchTimer);
|
||||
/**
|
||||
* Handle Enter key in search input.
|
||||
*
|
||||
* @param {Event} e Keypress event.
|
||||
*/
|
||||
handleSearchKeypress: function(e) {
|
||||
if (e.which === 13) {
|
||||
e.preventDefault();
|
||||
this.triggerSearch();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Trigger a search with the current input value.
|
||||
*/
|
||||
triggerSearch: function() {
|
||||
var query = $('#mlf-font-search').val().trim();
|
||||
|
||||
// Hide results if query too short
|
||||
if (query.length < 2) {
|
||||
this.hideSearchResults();
|
||||
this.displayError(mapleLocalFontsData.strings.minChars || 'Please enter at least 2 characters.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Debounce: wait 300ms before searching
|
||||
this.searchTimer = setTimeout(function() {
|
||||
MLF.performSearch(query);
|
||||
}, 300);
|
||||
this.performSearch(query);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -90,11 +119,11 @@
|
|||
*/
|
||||
performSearch: function(query) {
|
||||
var $spinner = $('#mlf-search-spinner');
|
||||
var $results = $('#mlf-search-results');
|
||||
var $list = $('#mlf-results-list');
|
||||
var $button = $('#mlf-search-btn');
|
||||
|
||||
// Show spinner
|
||||
// Show spinner, disable button
|
||||
$spinner.addClass('is-active');
|
||||
$button.prop('disabled', true);
|
||||
|
||||
// Send AJAX request
|
||||
$.ajax({
|
||||
|
|
@ -106,17 +135,30 @@
|
|||
query: query
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success && response.data.fonts) {
|
||||
MLF.displaySearchResults(response.data.fonts);
|
||||
if (response.success && response.data && response.data.fonts) {
|
||||
if (response.data.fonts.length > 0) {
|
||||
MLF.displaySearchResults(response.data.fonts);
|
||||
} else {
|
||||
MLF.displayNoResults();
|
||||
}
|
||||
} else {
|
||||
MLF.displayNoResults();
|
||||
// Handle error response
|
||||
var errorMsg = (response.data && response.data.message)
|
||||
? response.data.message
|
||||
: (mapleLocalFontsData.strings.error || 'An error occurred.');
|
||||
MLF.displayError(errorMsg);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
MLF.displayNoResults();
|
||||
error: function(xhr) {
|
||||
var errorMsg = mapleLocalFontsData.strings.error || 'An error occurred.';
|
||||
if (xhr.responseJSON && xhr.responseJSON.data && xhr.responseJSON.data.message) {
|
||||
errorMsg = xhr.responseJSON.data.message;
|
||||
}
|
||||
MLF.displayError(errorMsg);
|
||||
},
|
||||
complete: function() {
|
||||
$spinner.removeClass('is-active');
|
||||
$button.prop('disabled', false);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
|
@ -130,15 +172,21 @@
|
|||
var $results = $('#mlf-search-results');
|
||||
var $list = $('#mlf-results-list');
|
||||
|
||||
if (fonts.length === 0) {
|
||||
if (!fonts || fonts.length === 0) {
|
||||
this.displayNoResults();
|
||||
return;
|
||||
}
|
||||
|
||||
var html = '';
|
||||
var previewText = mapleLocalFontsData.strings.previewText || 'Maple Fonts Preview';
|
||||
var validFonts = 0;
|
||||
|
||||
fonts.forEach(function(font) {
|
||||
// Skip fonts with missing family name
|
||||
if (!font || !font.family) {
|
||||
return;
|
||||
}
|
||||
|
||||
var fontFamily = font.family;
|
||||
var category = font.category || 'sans-serif';
|
||||
var categoryLabel = MLF.getCategoryLabel(category);
|
||||
|
|
@ -148,7 +196,7 @@
|
|||
badges.push('<span class="mlf-badge mlf-badge-variable">Variable</span>');
|
||||
}
|
||||
|
||||
html += '<div class="mlf-result-item" data-font-family="' + MLF.escapeHtml(fontFamily) + '">';
|
||||
html += '<div class="mlf-result-item" data-font-family="' + MLF.escapeHtml(fontFamily) + '" data-font-version="' + MLF.escapeHtml(font.version || '') + '" data-font-modified="' + MLF.escapeHtml(font.lastModified || '') + '">';
|
||||
html += ' <div class="mlf-result-info">';
|
||||
html += ' <span class="mlf-result-name">' + MLF.escapeHtml(fontFamily) + '</span>';
|
||||
html += ' <span class="mlf-result-category">' + MLF.escapeHtml(categoryLabel) + '</span>';
|
||||
|
|
@ -163,8 +211,15 @@
|
|||
|
||||
// Load font for preview
|
||||
MLF.loadFontPreview(fontFamily);
|
||||
validFonts++;
|
||||
});
|
||||
|
||||
// If no valid fonts were found, show no results
|
||||
if (validFonts === 0) {
|
||||
this.displayNoResults();
|
||||
return;
|
||||
}
|
||||
|
||||
$list.html(html);
|
||||
$results.show();
|
||||
},
|
||||
|
|
@ -175,12 +230,25 @@
|
|||
displayNoResults: function() {
|
||||
var $results = $('#mlf-search-results');
|
||||
var $list = $('#mlf-results-list');
|
||||
var message = mapleLocalFontsData.strings.noResults || 'No fonts found.';
|
||||
var message = mapleLocalFontsData.strings.noResults || 'No fonts found. Try a different search term.';
|
||||
|
||||
$list.html('<div class="mlf-no-results">' + MLF.escapeHtml(message) + '</div>');
|
||||
$results.show();
|
||||
},
|
||||
|
||||
/**
|
||||
* Display an error message in search results.
|
||||
*
|
||||
* @param {string} message Error message.
|
||||
*/
|
||||
displayError: function(message) {
|
||||
var $results = $('#mlf-search-results');
|
||||
var $list = $('#mlf-results-list');
|
||||
|
||||
$list.html('<div class="mlf-search-error">' + MLF.escapeHtml(message) + '</div>');
|
||||
$results.show();
|
||||
},
|
||||
|
||||
/**
|
||||
* Hide search results.
|
||||
*/
|
||||
|
|
@ -212,9 +280,9 @@
|
|||
// Mark as loading
|
||||
this.loadedFonts[fontFamily] = true;
|
||||
|
||||
// Create Google Fonts link
|
||||
// Create Google Fonts link (spaces become %20 which Google accepts)
|
||||
var fontUrl = 'https://fonts.googleapis.com/css2?family=' +
|
||||
encodeURIComponent(fontFamily.replace(/ /g, '+')) +
|
||||
encodeURIComponent(fontFamily) +
|
||||
':wght@400&display=swap';
|
||||
|
||||
// Create and append link element
|
||||
|
|
@ -235,8 +303,10 @@
|
|||
var $item = $(e.currentTarget);
|
||||
var fontFamily = $item.data('font-family');
|
||||
|
||||
// Store selected font
|
||||
// Store selected font and version info
|
||||
this.selectedFont = fontFamily;
|
||||
this.selectedFontVersion = $item.data('font-version') || '';
|
||||
this.selectedFontLastModified = $item.data('font-modified') || '';
|
||||
|
||||
// Update UI
|
||||
$('#mlf-font-name').val(fontFamily);
|
||||
|
|
@ -351,7 +421,9 @@
|
|||
action: 'mlf_download_font',
|
||||
nonce: mapleLocalFontsData.downloadNonce,
|
||||
font_name: fontName,
|
||||
include_italic: includeItalic
|
||||
include_italic: includeItalic,
|
||||
font_version: this.selectedFontVersion || '',
|
||||
font_last_modified: this.selectedFontLastModified || ''
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
|
|
@ -456,6 +528,135 @@
|
|||
.addClass('mlf-message-' + type)
|
||||
.text(message)
|
||||
.show();
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle check for updates button click.
|
||||
*
|
||||
* @param {Event} e Click event.
|
||||
*/
|
||||
handleCheckUpdates: function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var $button = $('#mlf-check-updates');
|
||||
var originalText = $button.text();
|
||||
|
||||
// Disable button and show checking state
|
||||
$button.prop('disabled', true).text(mapleLocalFontsData.strings.checking || 'Checking...');
|
||||
|
||||
// Send AJAX request
|
||||
$.ajax({
|
||||
url: mapleLocalFontsData.ajaxUrl,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'mlf_check_updates',
|
||||
nonce: mapleLocalFontsData.checkUpdatesNonce
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
var updates = response.data.updates || {};
|
||||
var updateCount = Object.keys(updates).length;
|
||||
|
||||
// Update UI for each font
|
||||
$('.mlf-font-item').each(function() {
|
||||
var $item = $(this);
|
||||
var fontId = $item.data('font-id');
|
||||
var $badge = $item.find('.mlf-update-badge');
|
||||
var $updateBtn = $item.find('.mlf-update-btn');
|
||||
|
||||
if (updates[fontId]) {
|
||||
// Show update available badge and button
|
||||
$badge.show();
|
||||
$updateBtn.show();
|
||||
|
||||
// Store the latest version info on the button
|
||||
$updateBtn.data('latest-version', updates[fontId].latest_version);
|
||||
} else {
|
||||
// Hide update badge and button
|
||||
$badge.hide();
|
||||
$updateBtn.hide();
|
||||
}
|
||||
});
|
||||
|
||||
// Show summary message
|
||||
if (updateCount > 0) {
|
||||
var message = mapleLocalFontsData.strings.updatesFound || 'Updates available for %d font(s).';
|
||||
alert(message.replace('%d', updateCount));
|
||||
} else {
|
||||
alert(mapleLocalFontsData.strings.noUpdates || 'All fonts are up to date.');
|
||||
}
|
||||
} else {
|
||||
alert(response.data.message || mapleLocalFontsData.strings.error);
|
||||
}
|
||||
},
|
||||
error: function(xhr) {
|
||||
var message = mapleLocalFontsData.strings.error;
|
||||
if (xhr.responseJSON && xhr.responseJSON.data && xhr.responseJSON.data.message) {
|
||||
message = xhr.responseJSON.data.message;
|
||||
}
|
||||
alert(message);
|
||||
},
|
||||
complete: function() {
|
||||
$button.prop('disabled', false).text(originalText);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle font update button click.
|
||||
*
|
||||
* @param {Event} e Click event.
|
||||
*/
|
||||
handleUpdateFont: function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var $button = $(e.currentTarget);
|
||||
var fontId = $button.data('font-id');
|
||||
var fontName = $button.data('font-name');
|
||||
var $fontItem = $button.closest('.mlf-font-item');
|
||||
|
||||
// Confirm update
|
||||
if (!confirm('Update ' + fontName + ' to the latest version?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Store original button text
|
||||
var originalText = $button.text();
|
||||
|
||||
// Disable button and show updating state
|
||||
$button.prop('disabled', true).text(mapleLocalFontsData.strings.updating || 'Updating...');
|
||||
$fontItem.addClass('mlf-loading');
|
||||
|
||||
// Send AJAX request
|
||||
$.ajax({
|
||||
url: mapleLocalFontsData.ajaxUrl,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'mlf_update_font',
|
||||
nonce: mapleLocalFontsData.updateFontNonce,
|
||||
font_id: fontId
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
// Reload page to show updated font
|
||||
alert(response.data.message);
|
||||
window.location.reload();
|
||||
} else {
|
||||
alert(response.data.message || mapleLocalFontsData.strings.error);
|
||||
$button.prop('disabled', false).text(originalText);
|
||||
$fontItem.removeClass('mlf-loading');
|
||||
}
|
||||
},
|
||||
error: function(xhr) {
|
||||
var message = mapleLocalFontsData.strings.error;
|
||||
if (xhr.responseJSON && xhr.responseJSON.data && xhr.responseJSON.data.message) {
|
||||
message = xhr.responseJSON.data.message;
|
||||
}
|
||||
alert(message);
|
||||
$button.prop('disabled', false).text(originalText);
|
||||
$fontItem.removeClass('mlf-loading');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue