v1-pre
This commit is contained in:
parent
572552ff13
commit
847ed92c23
10 changed files with 1232 additions and 591 deletions
|
|
@ -6,7 +6,17 @@
|
|||
|
||||
/* Container */
|
||||
.mlf-wrap {
|
||||
max-width: 900px;
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
.mlf-wrap > h1 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.mlf-description {
|
||||
color: #646970;
|
||||
margin-top: 8px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.mlf-container {
|
||||
|
|
@ -18,14 +28,16 @@
|
|||
background: #fff;
|
||||
border: 1px solid #c3c4c7;
|
||||
border-radius: 4px;
|
||||
padding: 20px;
|
||||
padding: 20px 24px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.mlf-section h2 {
|
||||
margin-top: 0;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #c3c4c7;
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
/* Form */
|
||||
|
|
@ -33,7 +45,11 @@
|
|||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.mlf-form-row label {
|
||||
.mlf-form-row:last-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.mlf-form-row > label {
|
||||
display: block;
|
||||
font-weight: 600;
|
||||
margin-bottom: 8px;
|
||||
|
|
@ -43,126 +59,212 @@
|
|||
width: 100%;
|
||||
max-width: 400px;
|
||||
padding: 8px 12px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.mlf-form-row .description {
|
||||
margin-top: 8px;
|
||||
color: #646970;
|
||||
font-style: italic;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* Checkbox Grid */
|
||||
.mlf-checkbox-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
|
||||
gap: 10px;
|
||||
/* Search Input */
|
||||
.mlf-search-wrapper {
|
||||
position: relative;
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
.mlf-checkbox-grid-small {
|
||||
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
|
||||
max-width: 300px;
|
||||
.mlf-search-icon {
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: #646970;
|
||||
font-size: 18px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.mlf-checkbox-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 12px;
|
||||
background: #f6f7f7;
|
||||
border: 1px solid #dcdcde;
|
||||
.mlf-search-input {
|
||||
width: 100% !important;
|
||||
max-width: none !important;
|
||||
padding-left: 36px !important;
|
||||
padding-right: 36px !important;
|
||||
}
|
||||
|
||||
.mlf-search-spinner {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
float: none !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
/* Search Results */
|
||||
.mlf-search-results {
|
||||
margin-top: 12px;
|
||||
border: 1px solid #c3c4c7;
|
||||
border-radius: 4px;
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.mlf-results-list {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.mlf-result-item {
|
||||
padding: 16px;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.15s ease;
|
||||
}
|
||||
|
||||
.mlf-checkbox-label:hover {
|
||||
background: #f0f0f1;
|
||||
.mlf-result-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.mlf-checkbox-label input[type="checkbox"] {
|
||||
margin: 0;
|
||||
.mlf-result-item:hover {
|
||||
background: #f0f6fc;
|
||||
}
|
||||
|
||||
.mlf-checkbox-label input[type="checkbox"]:checked + span {
|
||||
.mlf-result-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.mlf-result-name {
|
||||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
color: #1d2327;
|
||||
}
|
||||
|
||||
/* File Count */
|
||||
.mlf-form-row-info {
|
||||
padding: 12px 16px;
|
||||
.mlf-result-category {
|
||||
font-size: 12px;
|
||||
color: #646970;
|
||||
padding: 2px 8px;
|
||||
background: #f0f0f1;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.mlf-result-badges {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.mlf-badge {
|
||||
font-size: 11px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 3px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.mlf-badge-variable {
|
||||
background: #d4edda;
|
||||
color: #155724;
|
||||
}
|
||||
|
||||
.mlf-result-preview {
|
||||
font-size: 22px;
|
||||
color: #50575e;
|
||||
line-height: 1.3;
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
.mlf-no-results {
|
||||
padding: 24px;
|
||||
text-align: center;
|
||||
color: #646970;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* Selected Font */
|
||||
.mlf-selected-font {
|
||||
margin-top: 16px;
|
||||
padding: 16px;
|
||||
background: #f0f6fc;
|
||||
border: 1px solid #c5d9ed;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.mlf-file-count {
|
||||
.mlf-selected-font-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid #c5d9ed;
|
||||
}
|
||||
|
||||
.mlf-selected-label {
|
||||
color: #646970;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.mlf-selected-name {
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
color: #1d2327;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.mlf-change-font {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #2271b1;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
.mlf-file-count strong {
|
||||
font-size: 1.1em;
|
||||
.mlf-change-font:hover {
|
||||
color: #135e96;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Font Preview */
|
||||
.mlf-preview-section {
|
||||
margin-top: 20px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #dcdcde;
|
||||
.mlf-italic-row {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.mlf-preview-box {
|
||||
/* Italic Toggle */
|
||||
.mlf-italic-toggle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 10px 16px;
|
||||
background: #fff;
|
||||
border: 1px solid #dcdcde;
|
||||
border-radius: 4px;
|
||||
padding: 24px;
|
||||
min-height: 100px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
font-weight: normal !important;
|
||||
transition: background-color 0.15s ease;
|
||||
}
|
||||
|
||||
.mlf-preview-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
.mlf-italic-toggle:hover {
|
||||
background: #f6f7f7;
|
||||
}
|
||||
|
||||
.mlf-preview-sample {
|
||||
display: block;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.mlf-preview-heading {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.mlf-preview-paragraph {
|
||||
font-size: 16px;
|
||||
color: #50575e;
|
||||
}
|
||||
|
||||
.mlf-preview-loading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
color: #646970;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.mlf-preview-loading .spinner {
|
||||
float: none;
|
||||
.mlf-italic-toggle input[type="checkbox"] {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.mlf-preview-error {
|
||||
color: #b32d2e;
|
||||
padding: 20px 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Submit Row */
|
||||
.mlf-form-row-submit {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.mlf-selected-font .mlf-form-row-submit {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.mlf-form-row-submit .spinner {
|
||||
|
|
@ -189,6 +291,28 @@
|
|||
color: #721c24;
|
||||
}
|
||||
|
||||
/* Info Note */
|
||||
.mlf-info-note {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
margin-top: 20px;
|
||||
padding: 12px 16px;
|
||||
background: #f0f6fc;
|
||||
border: 1px solid #c5d9ed;
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
color: #1d2327;
|
||||
}
|
||||
|
||||
.mlf-info-note .dashicons {
|
||||
color: #2271b1;
|
||||
font-size: 18px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
/* Font List */
|
||||
.mlf-font-list {
|
||||
display: flex;
|
||||
|
|
@ -245,10 +369,11 @@
|
|||
.mlf-no-fonts {
|
||||
color: #646970;
|
||||
font-style: italic;
|
||||
padding: 20px;
|
||||
padding: 24px;
|
||||
text-align: center;
|
||||
background: #f6f7f7;
|
||||
border-radius: 4px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Info Box */
|
||||
|
|
@ -264,12 +389,18 @@
|
|||
|
||||
.mlf-info-box .dashicons {
|
||||
color: #2271b1;
|
||||
font-size: 20px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.mlf-info-box p {
|
||||
margin: 0;
|
||||
color: #1d2327;
|
||||
margin: 0 0 8px 0;
|
||||
}
|
||||
|
||||
.mlf-info-box p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.mlf-info-box a {
|
||||
|
|
@ -332,10 +463,6 @@
|
|||
|
||||
/* Responsive */
|
||||
@media screen and (max-width: 782px) {
|
||||
.mlf-checkbox-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.mlf-font-item {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
|
|
@ -345,10 +472,12 @@
|
|||
.mlf-font-actions {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
.mlf-checkbox-grid {
|
||||
grid-template-columns: 1fr;
|
||||
.mlf-result-info {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.mlf-selected-font-header {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,182 +9,304 @@
|
|||
|
||||
var MLF = {
|
||||
/**
|
||||
* Preview debounce timer.
|
||||
* Search debounce timer.
|
||||
*/
|
||||
previewTimer: null,
|
||||
searchTimer: null,
|
||||
|
||||
/**
|
||||
* Currently loaded preview font.
|
||||
* Currently selected font.
|
||||
*/
|
||||
currentPreviewFont: null,
|
||||
selectedFont: null,
|
||||
|
||||
/**
|
||||
* Loaded font preview stylesheets.
|
||||
*/
|
||||
loadedFonts: {},
|
||||
|
||||
/**
|
||||
* Initialize the admin functionality.
|
||||
*/
|
||||
init: function() {
|
||||
this.bindEvents();
|
||||
this.updateFileCount();
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind event handlers.
|
||||
*/
|
||||
bindEvents: function() {
|
||||
// Search input
|
||||
$('#mlf-font-search').on('input', this.handleSearchInput.bind(this));
|
||||
|
||||
// Click outside to close search results
|
||||
$(document).on('click', this.handleDocumentClick.bind(this));
|
||||
|
||||
// Prevent closing when clicking inside search area
|
||||
$('.mlf-import-section').on('click', function(e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
// Font selection from results
|
||||
$(document).on('click', '.mlf-result-item', this.handleFontSelect.bind(this));
|
||||
|
||||
// Change font button
|
||||
$('#mlf-change-font').on('click', this.handleChangeFont.bind(this));
|
||||
|
||||
// Form submission
|
||||
$('#mlf-import-form').on('submit', this.handleDownload.bind(this));
|
||||
|
||||
// Delete button clicks
|
||||
$(document).on('click', '.mlf-delete-btn', this.handleDelete.bind(this));
|
||||
|
||||
// Update file count on checkbox change
|
||||
$('#mlf-import-form').on('change', 'input[type="checkbox"]', this.updateFileCount.bind(this));
|
||||
|
||||
// Font name input for preview (debounced)
|
||||
$('#mlf-font-name').on('input', this.handleFontNameInput.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle font name input for preview (debounced).
|
||||
* Handle search input (debounced).
|
||||
*
|
||||
* @param {Event} e Input event.
|
||||
*/
|
||||
handleFontNameInput: function(e) {
|
||||
var fontName = $(e.target).val().trim();
|
||||
handleSearchInput: function(e) {
|
||||
var query = $(e.target).val().trim();
|
||||
|
||||
// Clear previous timer
|
||||
if (this.previewTimer) {
|
||||
clearTimeout(this.previewTimer);
|
||||
if (this.searchTimer) {
|
||||
clearTimeout(this.searchTimer);
|
||||
}
|
||||
|
||||
// Hide preview if empty
|
||||
if (!fontName) {
|
||||
this.hidePreview();
|
||||
// Hide results if query too short
|
||||
if (query.length < 2) {
|
||||
this.hideSearchResults();
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate font name (only allowed characters)
|
||||
if (!/^[a-zA-Z0-9\s\-]+$/.test(fontName)) {
|
||||
this.hidePreview();
|
||||
return;
|
||||
}
|
||||
|
||||
// Debounce: wait 500ms before loading preview
|
||||
this.previewTimer = setTimeout(function() {
|
||||
MLF.loadFontPreview(fontName);
|
||||
}, 500);
|
||||
// Debounce: wait 300ms before searching
|
||||
this.searchTimer = setTimeout(function() {
|
||||
MLF.performSearch(query);
|
||||
}, 300);
|
||||
},
|
||||
|
||||
/**
|
||||
* Load font preview from Google Fonts.
|
||||
* Perform the search.
|
||||
*
|
||||
* @param {string} fontName Font family name.
|
||||
* @param {string} query Search query.
|
||||
*/
|
||||
loadFontPreview: function(fontName) {
|
||||
var $section = $('#mlf-preview-section');
|
||||
var $text = $('#mlf-preview-text');
|
||||
var $loading = $('#mlf-preview-loading');
|
||||
var $error = $('#mlf-preview-error');
|
||||
performSearch: function(query) {
|
||||
var $spinner = $('#mlf-search-spinner');
|
||||
var $results = $('#mlf-search-results');
|
||||
var $list = $('#mlf-results-list');
|
||||
|
||||
// Skip if same font already loaded
|
||||
if (this.currentPreviewFont === fontName) {
|
||||
// Show spinner
|
||||
$spinner.addClass('is-active');
|
||||
|
||||
// Send AJAX request
|
||||
$.ajax({
|
||||
url: mapleLocalFontsData.ajaxUrl,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'mlf_search_fonts',
|
||||
nonce: mapleLocalFontsData.searchNonce,
|
||||
query: query
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success && response.data.fonts) {
|
||||
MLF.displaySearchResults(response.data.fonts);
|
||||
} else {
|
||||
MLF.displayNoResults();
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
MLF.displayNoResults();
|
||||
},
|
||||
complete: function() {
|
||||
$spinner.removeClass('is-active');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Display search results.
|
||||
*
|
||||
* @param {Array} fonts Array of font objects.
|
||||
*/
|
||||
displaySearchResults: function(fonts) {
|
||||
var $results = $('#mlf-search-results');
|
||||
var $list = $('#mlf-results-list');
|
||||
|
||||
if (fonts.length === 0) {
|
||||
this.displayNoResults();
|
||||
return;
|
||||
}
|
||||
|
||||
// Show section with loading state
|
||||
$section.show();
|
||||
$text.hide();
|
||||
$loading.show();
|
||||
$error.hide();
|
||||
var html = '';
|
||||
var previewText = mapleLocalFontsData.strings.previewText || 'Maple Fonts Preview';
|
||||
|
||||
// Remove previous preview font link
|
||||
$('#mlf-preview-font-link').remove();
|
||||
fonts.forEach(function(font) {
|
||||
var fontFamily = font.family;
|
||||
var category = font.category || 'sans-serif';
|
||||
var categoryLabel = MLF.getCategoryLabel(category);
|
||||
var badges = [];
|
||||
|
||||
// Build Google Fonts URL for preview (just 400 weight for preview)
|
||||
var fontFamily = fontName.replace(/\s+/g, '+');
|
||||
var previewUrl = 'https://fonts.googleapis.com/css2?family=' + encodeURIComponent(fontFamily) + ':wght@400&display=swap';
|
||||
|
||||
// Create link element
|
||||
var $link = $('<link>', {
|
||||
id: 'mlf-preview-font-link',
|
||||
rel: 'stylesheet',
|
||||
href: previewUrl
|
||||
});
|
||||
|
||||
// Handle load success
|
||||
$link.on('load', function() {
|
||||
MLF.currentPreviewFont = fontName;
|
||||
$text.css('font-family', '"' + fontName + '", sans-serif');
|
||||
$loading.hide();
|
||||
$text.show();
|
||||
});
|
||||
|
||||
// Handle load error
|
||||
$link.on('error', function() {
|
||||
MLF.currentPreviewFont = null;
|
||||
$loading.hide();
|
||||
$error.show();
|
||||
});
|
||||
|
||||
// Append to head
|
||||
$('head').append($link);
|
||||
|
||||
// Fallback timeout (5 seconds)
|
||||
setTimeout(function() {
|
||||
if ($loading.is(':visible')) {
|
||||
// Check if font actually loaded by measuring text width
|
||||
var testSpan = $('<span>').text('test').css({
|
||||
'font-family': '"' + fontName + '", monospace',
|
||||
'position': 'absolute',
|
||||
'visibility': 'hidden'
|
||||
}).appendTo('body');
|
||||
|
||||
var testWidth = testSpan.width();
|
||||
|
||||
var fallbackSpan = $('<span>').text('test').css({
|
||||
'font-family': 'monospace',
|
||||
'position': 'absolute',
|
||||
'visibility': 'hidden'
|
||||
}).appendTo('body');
|
||||
|
||||
var fallbackWidth = fallbackSpan.width();
|
||||
|
||||
testSpan.remove();
|
||||
fallbackSpan.remove();
|
||||
|
||||
if (testWidth !== fallbackWidth) {
|
||||
// Font loaded successfully
|
||||
MLF.currentPreviewFont = fontName;
|
||||
$text.css('font-family', '"' + fontName + '", sans-serif');
|
||||
$loading.hide();
|
||||
$text.show();
|
||||
} else {
|
||||
// Font failed to load
|
||||
MLF.currentPreviewFont = null;
|
||||
$loading.hide();
|
||||
$error.show();
|
||||
}
|
||||
if (font.has_variable) {
|
||||
badges.push('<span class="mlf-badge mlf-badge-variable">Variable</span>');
|
||||
}
|
||||
}, 5000);
|
||||
|
||||
html += '<div class="mlf-result-item" data-font-family="' + MLF.escapeHtml(fontFamily) + '">';
|
||||
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>';
|
||||
if (badges.length > 0) {
|
||||
html += ' <span class="mlf-result-badges">' + badges.join('') + '</span>';
|
||||
}
|
||||
html += ' </div>';
|
||||
html += ' <div class="mlf-result-preview" style="font-family: \'' + MLF.escapeHtml(fontFamily) + '\', ' + category + ';">';
|
||||
html += MLF.escapeHtml(previewText);
|
||||
html += ' </div>';
|
||||
html += '</div>';
|
||||
|
||||
// Load font for preview
|
||||
MLF.loadFontPreview(fontFamily);
|
||||
});
|
||||
|
||||
$list.html(html);
|
||||
$results.show();
|
||||
},
|
||||
|
||||
/**
|
||||
* Hide the font preview section.
|
||||
* Display no results message.
|
||||
*/
|
||||
hidePreview: function() {
|
||||
this.currentPreviewFont = null;
|
||||
$('#mlf-preview-section').hide();
|
||||
$('#mlf-preview-font-link').remove();
|
||||
displayNoResults: function() {
|
||||
var $results = $('#mlf-search-results');
|
||||
var $list = $('#mlf-results-list');
|
||||
var message = mapleLocalFontsData.strings.noResults || 'No fonts found.';
|
||||
|
||||
$list.html('<div class="mlf-no-results">' + MLF.escapeHtml(message) + '</div>');
|
||||
$results.show();
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the file count display.
|
||||
* Hide search results.
|
||||
*/
|
||||
updateFileCount: function() {
|
||||
var weights = $('input[name="weights[]"]:checked').length;
|
||||
var styles = $('input[name="styles[]"]:checked').length;
|
||||
var count = weights * styles;
|
||||
hideSearchResults: function() {
|
||||
$('#mlf-search-results').hide();
|
||||
},
|
||||
|
||||
$('#mlf-file-count').text(count);
|
||||
/**
|
||||
* Maximum number of font previews to load.
|
||||
*/
|
||||
maxLoadedFonts: 50,
|
||||
|
||||
/**
|
||||
* Load a font for preview from Google Fonts.
|
||||
*
|
||||
* @param {string} fontFamily Font family name.
|
||||
*/
|
||||
loadFontPreview: function(fontFamily) {
|
||||
// Skip if already loaded
|
||||
if (this.loadedFonts[fontFamily]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Limit number of loaded fonts to prevent memory accumulation
|
||||
if (Object.keys(this.loadedFonts).length >= this.maxLoadedFonts) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Mark as loading
|
||||
this.loadedFonts[fontFamily] = true;
|
||||
|
||||
// Create Google Fonts link
|
||||
var fontUrl = 'https://fonts.googleapis.com/css2?family=' +
|
||||
encodeURIComponent(fontFamily.replace(/ /g, '+')) +
|
||||
':wght@400&display=swap';
|
||||
|
||||
// Create and append link element
|
||||
var $link = $('<link>', {
|
||||
rel: 'stylesheet',
|
||||
href: fontUrl
|
||||
});
|
||||
|
||||
$('head').append($link);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle font selection.
|
||||
*
|
||||
* @param {Event} e Click event.
|
||||
*/
|
||||
handleFontSelect: function(e) {
|
||||
var $item = $(e.currentTarget);
|
||||
var fontFamily = $item.data('font-family');
|
||||
|
||||
// Store selected font
|
||||
this.selectedFont = fontFamily;
|
||||
|
||||
// Update UI
|
||||
$('#mlf-font-name').val(fontFamily);
|
||||
$('#mlf-selected-name').text(fontFamily);
|
||||
|
||||
// Hide search, show selected font panel
|
||||
this.hideSearchResults();
|
||||
$('#mlf-font-search').closest('.mlf-form-row').hide();
|
||||
$('#mlf-selected-font').show();
|
||||
|
||||
// Clear search input
|
||||
$('#mlf-font-search').val('');
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle change font button.
|
||||
*
|
||||
* @param {Event} e Click event.
|
||||
*/
|
||||
handleChangeFont: function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
// Clear selection
|
||||
this.selectedFont = null;
|
||||
$('#mlf-font-name').val('');
|
||||
|
||||
// Show search, hide selected font panel
|
||||
$('#mlf-selected-font').hide();
|
||||
$('#mlf-font-search').closest('.mlf-form-row').show();
|
||||
$('#mlf-font-search').focus();
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle document click (close search results).
|
||||
*
|
||||
* @param {Event} e Click event.
|
||||
*/
|
||||
handleDocumentClick: function(e) {
|
||||
if (!$(e.target).closest('.mlf-import-section').length) {
|
||||
this.hideSearchResults();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get human-readable category label.
|
||||
*
|
||||
* @param {string} category Category slug.
|
||||
* @return {string} Category label.
|
||||
*/
|
||||
getCategoryLabel: function(category) {
|
||||
var labels = {
|
||||
'sans-serif': 'Sans Serif',
|
||||
'serif': 'Serif',
|
||||
'display': 'Display',
|
||||
'handwriting': 'Handwriting',
|
||||
'monospace': 'Monospace'
|
||||
};
|
||||
return labels[category] || category;
|
||||
},
|
||||
|
||||
/**
|
||||
* Escape HTML entities.
|
||||
*
|
||||
* @param {string} str String to escape.
|
||||
* @return {string} Escaped string.
|
||||
*/
|
||||
escapeHtml: function(str) {
|
||||
var div = document.createElement('div');
|
||||
div.textContent = str;
|
||||
return div.innerHTML;
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -202,31 +324,17 @@
|
|||
|
||||
// Get form values
|
||||
var fontName = $('#mlf-font-name').val().trim();
|
||||
var weights = [];
|
||||
var styles = [];
|
||||
|
||||
$('input[name="weights[]"]:checked').each(function() {
|
||||
weights.push($(this).val());
|
||||
});
|
||||
|
||||
$('input[name="styles[]"]:checked').each(function() {
|
||||
styles.push($(this).val());
|
||||
});
|
||||
var includeItalic = $('#mlf-include-italic').is(':checked') ? '1' : '0';
|
||||
|
||||
// Validate
|
||||
if (!fontName) {
|
||||
this.showMessage($message, mapleLocalFontsData.strings.enterFontName, 'error');
|
||||
this.showMessage($message, mapleLocalFontsData.strings.selectFont || 'Please select a font.', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
if (weights.length === 0) {
|
||||
this.showMessage($message, mapleLocalFontsData.strings.selectWeight, 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
if (styles.length === 0) {
|
||||
this.showMessage($message, mapleLocalFontsData.strings.selectStyle, 'error');
|
||||
return;
|
||||
// Store original button text
|
||||
if (!$button.data('original-text')) {
|
||||
$button.data('original-text', $button.text());
|
||||
}
|
||||
|
||||
// Disable form
|
||||
|
|
@ -243,8 +351,7 @@
|
|||
action: 'mlf_download_font',
|
||||
nonce: mapleLocalFontsData.downloadNonce,
|
||||
font_name: fontName,
|
||||
weights: weights,
|
||||
styles: styles
|
||||
include_italic: includeItalic
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
|
|
@ -257,20 +364,19 @@
|
|||
MLF.showMessage($message, response.data.message || mapleLocalFontsData.strings.error, 'error');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
MLF.showMessage($message, mapleLocalFontsData.strings.error, 'error');
|
||||
error: function(xhr) {
|
||||
var message = mapleLocalFontsData.strings.error;
|
||||
if (xhr.responseJSON && xhr.responseJSON.data && xhr.responseJSON.data.message) {
|
||||
message = xhr.responseJSON.data.message;
|
||||
}
|
||||
MLF.showMessage($message, message, 'error');
|
||||
},
|
||||
complete: function() {
|
||||
$form.removeClass('mlf-loading');
|
||||
$button.prop('disabled', false).text($button.data('original-text') || 'Download & Install');
|
||||
$button.prop('disabled', false).text($button.data('original-text'));
|
||||
$spinner.removeClass('is-active');
|
||||
}
|
||||
});
|
||||
|
||||
// Store original button text
|
||||
if (!$button.data('original-text')) {
|
||||
$button.data('original-text', $button.text());
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -290,6 +396,9 @@
|
|||
return;
|
||||
}
|
||||
|
||||
// Store original button text
|
||||
var originalText = $button.text();
|
||||
|
||||
// Disable button
|
||||
$button.prop('disabled', true).text(mapleLocalFontsData.strings.deleting);
|
||||
$fontItem.addClass('mlf-loading');
|
||||
|
|
@ -311,20 +420,24 @@
|
|||
|
||||
// Check if any fonts remain
|
||||
if ($('.mlf-font-item').length === 0) {
|
||||
$('#mlf-font-list').html(
|
||||
'<p class="mlf-no-fonts">No fonts installed yet.</p>'
|
||||
$('#mlf-font-list').replaceWith(
|
||||
'<p class="mlf-no-fonts">No fonts installed yet. Search and select a font above to get started.</p>'
|
||||
);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
alert(response.data.message || mapleLocalFontsData.strings.error);
|
||||
$button.prop('disabled', false).text('Delete');
|
||||
$button.prop('disabled', false).text(originalText);
|
||||
$fontItem.removeClass('mlf-loading');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
alert(mapleLocalFontsData.strings.error);
|
||||
$button.prop('disabled', false).text('Delete');
|
||||
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