forked from UKSOURCE/cms.lams
header
This commit is contained in:
+69
-544
@@ -12,25 +12,13 @@
|
||||
<div class="col-12">
|
||||
<div class="content-with-fixed-buttons">
|
||||
<!-- Hidden inputs for JSON data -->
|
||||
<input type="hidden" name="topbarJson" id="topbarJson" />
|
||||
<input type="hidden" name="logo" id="logoInput" />
|
||||
<input type="hidden" name="activeTab" id="activeTabInput" value="topbar" />
|
||||
<input type="hidden" name="menuUpdates" id="menuUpdates" />
|
||||
<input type="hidden" name="activeTab" id="activeTabInput" value="logo" />
|
||||
|
||||
<!-- Navigation Tabs -->
|
||||
<div class="card shadow-sm border-0 mb-4">
|
||||
<div class="card-header bg-white border-bottom">
|
||||
<ul class="nav nav-tabs card-header-tabs" role="tablist">
|
||||
<li class="nav-item">
|
||||
<a
|
||||
class="nav-link <%= activeTab === 'topbar' ? 'active' : '' %>"
|
||||
data-bs-toggle="tab"
|
||||
href="#topbar"
|
||||
role="tab"
|
||||
>
|
||||
<i class="fas fa-bars me-2"></i>Topbar
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a
|
||||
class="nav-link <%= activeTab === 'logo' ? 'active' : '' %>"
|
||||
@@ -41,6 +29,16 @@
|
||||
<i class="fas fa-image me-2"></i>Logo
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a
|
||||
class="nav-link <%= activeTab === 'buttons' ? 'active' : '' %>"
|
||||
data-bs-toggle="tab"
|
||||
href="#buttons"
|
||||
role="tab"
|
||||
>
|
||||
<i class="fas fa-mouse-pointer me-2"></i>Buttons
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a
|
||||
class="nav-link <%= activeTab === 'menu' ? 'active' : '' %>"
|
||||
@@ -56,79 +54,6 @@
|
||||
|
||||
<div class="card-body">
|
||||
<div class="tab-content">
|
||||
<!-- Topbar Tab -->
|
||||
<div class="tab-pane fade <%= activeTab === 'topbar' ? 'show active' : '' %>" id="topbar" role="tabpanel">
|
||||
<div class="row g-4">
|
||||
<!-- Contact Information -->
|
||||
<div class="col-md-12">
|
||||
<div class="card border shadow-sm">
|
||||
<div class="card-header bg-white">
|
||||
<h6 class="mb-0">
|
||||
<i class="fas fa-phone me-2"></i>Contact Information
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label fw-medium">Phone Number</label>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="contactPhone"
|
||||
value="<%= data.topbar.contactInfo.phone %>"
|
||||
placeholder="+1 234 567 890"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label fw-medium">Email Address</label>
|
||||
<input
|
||||
type="email"
|
||||
class="form-control"
|
||||
id="contactEmail"
|
||||
value="<%= data.topbar.contactInfo.email || '' %>"
|
||||
placeholder="info@example.com"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<label class="form-label fw-medium">Location</label>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="contactLocation"
|
||||
value="<%= data.topbar.contactInfo.location || '' %>"
|
||||
placeholder="69 Street, 5th Avenue LA, United States"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Social Links -->
|
||||
<div class="col-md-12">
|
||||
<div class="card border shadow-sm">
|
||||
<div class="card-header bg-white d-flex justify-content-between align-items-center">
|
||||
<h6 class="mb-0">
|
||||
<i class="fas fa-share-alt me-2"></i>Social Media Links
|
||||
</h6>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary btn-sm"
|
||||
id="addSocialLink"
|
||||
>
|
||||
<i class="fas fa-plus me-1"></i>Add Social Link
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="socialLinksContainer" class="social-links-sortable">
|
||||
<!-- Social links will be populated here -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Logo Tab -->
|
||||
<div class="tab-pane fade <%= activeTab === 'logo' ? 'show active' : '' %>" id="logo" role="tabpanel">
|
||||
<div class="row g-4">
|
||||
@@ -179,6 +104,52 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Buttons Tab -->
|
||||
<div class="tab-pane fade <%= activeTab === 'buttons' ? 'show active' : '' %>" id="buttons" role="tabpanel">
|
||||
<div class="row g-4">
|
||||
<!-- Sign In Button -->
|
||||
<div class="col-md-6">
|
||||
<div class="card border shadow-sm">
|
||||
<div class="card-header bg-white">
|
||||
<h6 class="mb-0"><i class="fas fa-sign-in-alt me-2"></i>Sign In Button</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-medium">Label</label>
|
||||
<input type="text" class="form-control" id="signInLabel"
|
||||
value="<%= data.signInButton.label %>" placeholder="Sign In" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-medium">URL</label>
|
||||
<input type="text" class="form-control" id="signInHref"
|
||||
value="<%= data.signInButton.href %>" placeholder="/signin" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- CTA Button -->
|
||||
<div class="col-md-6">
|
||||
<div class="card border shadow-sm">
|
||||
<div class="card-header bg-white">
|
||||
<h6 class="mb-0"><i class="fas fa-mouse-pointer me-2"></i>CTA Button</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-medium">Label</label>
|
||||
<input type="text" class="form-control" id="ctaLabel"
|
||||
value="<%= data.ctaButton.label %>" placeholder="Request Info" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-medium">URL</label>
|
||||
<input type="text" class="form-control" id="ctaHref"
|
||||
value="<%= data.ctaButton.href %>" placeholder="/request" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Menu Structure Tab -->
|
||||
<div class="tab-pane fade <%= activeTab === 'menu' ? 'show active' : '' %>" id="menu" role="tabpanel">
|
||||
<%- include('menu') %>
|
||||
@@ -202,12 +173,6 @@
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
let socialLinkIndex = 0;
|
||||
|
||||
// Initialize social links from data
|
||||
initializeSocialLinks();
|
||||
updateHiddenInputs();
|
||||
|
||||
// Safely remove any lingering modal backdrops on page load/navigation
|
||||
function cleanupModals() {
|
||||
// Basic reset
|
||||
@@ -291,7 +256,7 @@
|
||||
}
|
||||
|
||||
// Attach listeners to all inputs for change detection
|
||||
const headerInputs = document.querySelectorAll('#topbar input, #logo input');
|
||||
const headerInputs = document.querySelectorAll('#logo input, #buttons input');
|
||||
headerInputs.forEach(input => {
|
||||
input.addEventListener('input', markChanged);
|
||||
input.addEventListener('change', markChanged);
|
||||
@@ -338,7 +303,6 @@
|
||||
if (saveHeaderBtn) {
|
||||
saveHeaderBtn.addEventListener('click', async function (e) {
|
||||
console.log('=== TRACE: saveHeaderBtn Clicked (Unified) ===');
|
||||
updateHiddenInputs();
|
||||
|
||||
const submitBtn = this;
|
||||
const originalText = submitBtn.innerHTML;
|
||||
@@ -346,11 +310,17 @@
|
||||
submitBtn.disabled = true;
|
||||
|
||||
try {
|
||||
// 1. Collect and Save Topbar & Logo
|
||||
// 1. Collect and Save Header Data (Logo + Buttons)
|
||||
const headerData = {
|
||||
topbarJson: document.getElementById('topbarJson').value,
|
||||
logo: document.getElementById('logoInput').value,
|
||||
activeTab: document.getElementById('activeTabInput').value
|
||||
logo: document.getElementById('logoImage').value,
|
||||
signInButton: {
|
||||
label: document.getElementById('signInLabel').value,
|
||||
href: document.getElementById('signInHref').value,
|
||||
},
|
||||
ctaButton: {
|
||||
label: document.getElementById('ctaLabel').value,
|
||||
href: document.getElementById('ctaHref').value,
|
||||
},
|
||||
};
|
||||
|
||||
const headerResponse = await fetch('/admin/header/update', {
|
||||
@@ -382,7 +352,7 @@
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('=== TRACE: Unified Save ERROR ===', error);
|
||||
showNotification('Lỗi: ' + error.message, 'error');
|
||||
showNotification('Error: ' + error.message, 'error');
|
||||
} finally {
|
||||
submitBtn.innerHTML = originalText;
|
||||
submitBtn.disabled = false;
|
||||
@@ -390,416 +360,6 @@
|
||||
});
|
||||
}
|
||||
|
||||
function updateHiddenInputs() {
|
||||
const topbarData = {
|
||||
contactInfo: {
|
||||
phone: document.getElementById('contactPhone').value || '',
|
||||
email: document.getElementById('contactEmail').value || '',
|
||||
location: document.getElementById('contactLocation').value || ''
|
||||
},
|
||||
socialLinks: []
|
||||
};
|
||||
|
||||
// Collect social links
|
||||
document.querySelectorAll('.social-platform').forEach((input) => {
|
||||
const platform = input.value.trim();
|
||||
const urlInput = document.querySelector(`.social-url[data-index="${input.dataset.index}"]`);
|
||||
const iconInput = document.querySelector(`.social-icon[data-index="${input.dataset.index}"]`);
|
||||
|
||||
const url = urlInput ? urlInput.value.trim() : '';
|
||||
const icon = iconInput ? iconInput.value.trim() : '';
|
||||
|
||||
if (platform && url) {
|
||||
topbarData.socialLinks.push({
|
||||
platform: platform,
|
||||
url: url,
|
||||
icon: icon
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('topbarJson').value = JSON.stringify(topbarData);
|
||||
document.getElementById('logoInput').value = document.getElementById('logoImage').value || '';
|
||||
|
||||
try {
|
||||
const menuUpdates = collectMenuUpdates();
|
||||
document.getElementById('menuUpdates').value = JSON.stringify(menuUpdates);
|
||||
} catch (e) {
|
||||
console.error('Error collecting menu updates:', e);
|
||||
document.getElementById('menuUpdates').value = '[]';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect menu updates from the menu tree
|
||||
* Returns an empty array if no menu tree exists
|
||||
*/
|
||||
function collectMenuUpdates() {
|
||||
// For now, return empty array as menu structure management is coming soon
|
||||
// This function can be expanded when menu tree functionality is implemented
|
||||
return [];
|
||||
}
|
||||
|
||||
function initializeSocialLinks() {
|
||||
const container = document.getElementById('socialLinksContainer');
|
||||
if (!container) return;
|
||||
|
||||
// Extract social links safely from EJS data
|
||||
let socialLinks = [];
|
||||
try {
|
||||
socialLinks = <%- JSON.stringify(data.topbar.socialLinks || []) %>;
|
||||
} catch (e) {
|
||||
console.error('Error parsing social links data:', e);
|
||||
}
|
||||
|
||||
if (socialLinks.length === 0) {
|
||||
// Add default platforms if no social links exist
|
||||
const platforms = ['linkedin', 'twitter', 'instagram', 'youtube'];
|
||||
platforms.forEach((platform, index) => {
|
||||
addSocialLinkRow(platform, '', `fa-brands fa-${platform}`, index);
|
||||
});
|
||||
socialLinkIndex = platforms.length;
|
||||
} else {
|
||||
// Load existing social links
|
||||
socialLinks.forEach((social, index) => {
|
||||
const platform = social.platform || '';
|
||||
const url = social.url || '';
|
||||
const icon = social.icon || '';
|
||||
addSocialLinkRow(platform, url, icon, index);
|
||||
});
|
||||
socialLinkIndex = socialLinks.length;
|
||||
}
|
||||
}
|
||||
|
||||
function addSocialLinkRow(platform, url, icon, index) {
|
||||
const container = document.getElementById('socialLinksContainer');
|
||||
const socialLink = document.createElement('div');
|
||||
socialLink.className = 'card mb-3 border social-link-item';
|
||||
socialLink.dataset.platform = platform;
|
||||
|
||||
// Escape HTML to prevent XSS
|
||||
const escapedPlatform = (platform || '').replace(/[&<>"']/g, char => ({
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": '''
|
||||
}[char]));
|
||||
|
||||
const escapedUrl = (url || '').replace(/[&<>"']/g, char => ({
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": '''
|
||||
}[char]));
|
||||
|
||||
const escapedIcon = (icon || '').replace(/[&<>"']/g, char => ({
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": '''
|
||||
}[char]));
|
||||
|
||||
socialLink.innerHTML = `
|
||||
<div class="card-body">
|
||||
<div class="row g-3 align-items-end">
|
||||
<div class="col-md-1 d-flex justify-content-center align-items-center w-auto">
|
||||
<label class="form-label fw-medium"> </label>
|
||||
<div class="drag-handle" title="Drag to reorder" style="cursor: grab; font-size: 1.2rem; color: #999; user-select: none;">
|
||||
<i class="fas fa-grip-vertical"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label class="form-label fw-medium">Platform</label>
|
||||
<input type="text" class="form-control social-platform" value="${escapedPlatform}" data-index="${index}" disabled />
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label fw-medium">URL</label>
|
||||
<input type="text" class="form-control social-url" value="${escapedUrl}" data-index="${index}" placeholder="https://..." />
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label fw-medium">Icon Class</label>
|
||||
<input type="text" class="form-control social-icon" value="${escapedIcon}" data-index="${index}" />
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label class="form-label"> </label>
|
||||
<div class="btn-group w-100" role="group">
|
||||
<button type="button" class="btn btn-outline-primary btn-sm edit-social-link mx-3 rounded" style="transform: none" data-index="${index}" title="Edit">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-danger btn-sm remove-social-link rounded" data-index="${index}" title="Delete">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
container.appendChild(socialLink);
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
DRAG & DROP STYLING
|
||||
============================================ */
|
||||
const dragDropStyles = document.createElement('style');
|
||||
dragDropStyles.textContent = `
|
||||
.social-link-item {
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.drag-handle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
transition: all 0.2s ease;
|
||||
cursor: grab !important;
|
||||
}
|
||||
|
||||
.drag-handle:active {
|
||||
cursor: grabbing !important;
|
||||
}
|
||||
|
||||
.drag-handle:hover {
|
||||
background-color: #f0f0f0;
|
||||
color: #0d6efd;
|
||||
}
|
||||
|
||||
/* SortableJS Classes */
|
||||
.social-ghost {
|
||||
opacity: 0.4;
|
||||
border: 2px dashed #0d6efd !important;
|
||||
background-color: #f8f9fa !important;
|
||||
}
|
||||
.social-chosen {
|
||||
background-color: #eef3ff !important;
|
||||
box-shadow: 0 5px 15px rgba(0,0,0,0.1) !important;
|
||||
}
|
||||
.social-drag {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
/* Fix Modal Freeze & Z-Index issues */
|
||||
body.modal-open {
|
||||
overflow: hidden !important;
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(dragDropStyles);
|
||||
|
||||
document.addEventListener('click', function (e) {
|
||||
if (e.target.closest('.remove-social-link')) {
|
||||
e.preventDefault();
|
||||
const btn = e.target.closest('.remove-social-link');
|
||||
const index = btn.dataset.index;
|
||||
const platformInput = document.querySelector(`.social-platform[data-index="${index}"]`);
|
||||
const platform = platformInput.value;
|
||||
|
||||
if (confirm(`Delete ${platform} social link?`)) {
|
||||
deleteSocialLink(platform, btn.closest('.card'));
|
||||
}
|
||||
}
|
||||
|
||||
if (e.target.closest('.edit-social-link')) {
|
||||
e.preventDefault();
|
||||
const btn = e.target.closest('.edit-social-link');
|
||||
const index = btn.dataset.index;
|
||||
const platformInput = document.querySelector(`.social-platform[data-index="${index}"]`);
|
||||
const urlInput = document.querySelector(`.social-url[data-index="${index}"]`);
|
||||
const iconInput = document.querySelector(`.social-icon[data-index="${index}"]`);
|
||||
|
||||
const platform = platformInput.value;
|
||||
const url = urlInput.value;
|
||||
const icon = iconInput.value;
|
||||
|
||||
showEditSocialLinkModal(platform, url, icon);
|
||||
}
|
||||
|
||||
if (e.target.closest('#addSocialLink')) {
|
||||
e.preventDefault();
|
||||
showAddSocialLinkModal();
|
||||
}
|
||||
});
|
||||
|
||||
function deleteSocialLink(platform, cardElement) {
|
||||
if (confirm(`Delete ${platform} social link?`)) {
|
||||
cardElement.remove();
|
||||
updateHiddenInputs();
|
||||
markChanged();
|
||||
}
|
||||
}
|
||||
|
||||
function showAddSocialLinkModal() {
|
||||
const modal = document.createElement('div');
|
||||
modal.className = 'modal fade';
|
||||
modal.id = 'addSocialLinkModal';
|
||||
modal.setAttribute('tabindex', '-1');
|
||||
modal.innerHTML = `
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Add New Social Link</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-medium">Platform <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control" id="newSocialPlatform" placeholder="e.g., linkedin, twitter, instagram, youtube, facebook" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-medium">URL <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control" id="newSocialUrl" placeholder="https://..." />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-medium">Icon Class</label>
|
||||
<input type="text" class="form-control" id="newSocialIcon" placeholder="e.g., fa-brands fa-linkedin" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" id="saveSocialLink">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.body.appendChild(modal);
|
||||
const bsModal = new bootstrap.Modal(modal);
|
||||
|
||||
document.getElementById('saveSocialLink').addEventListener('click', function() {
|
||||
const platform = document.getElementById('newSocialPlatform').value.trim();
|
||||
const url = document.getElementById('newSocialUrl').value.trim();
|
||||
const icon = document.getElementById('newSocialIcon').value.trim();
|
||||
|
||||
if (!platform) {
|
||||
alert('Vui lòng nhập tên nền tảng');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!url) {
|
||||
alert('Vui lòng nhập URL');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if platform already exists
|
||||
const existingPlatforms = Array.from(document.querySelectorAll('.social-platform')).map(el => el.value);
|
||||
if (existingPlatforms.includes(platform)) {
|
||||
alert(`${platform} đã tồn tại`);
|
||||
return;
|
||||
}
|
||||
|
||||
addSocialLinkViaAPI(platform, url, icon || `fa-brands fa-${platform}`, bsModal, modal);
|
||||
});
|
||||
|
||||
bsModal.show();
|
||||
|
||||
// Focus on platform input
|
||||
setTimeout(() => {
|
||||
document.getElementById('newSocialPlatform').focus();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
function showEditSocialLinkModal(platform, url, icon) {
|
||||
const modal = document.createElement('div');
|
||||
modal.className = 'modal fade';
|
||||
modal.id = 'editSocialLinkModal';
|
||||
modal.setAttribute('tabindex', '-1');
|
||||
const platformDisplay = platform ? platform.charAt(0).toUpperCase() + platform.slice(1) : 'Social';
|
||||
modal.innerHTML = `
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Edit ${platformDisplay} Link</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-medium">Platform <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control" id="editSocialPlatform" value="${platform}" placeholder="e.g., linkedin, twitter, instagram" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-medium">URL <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control" id="editSocialUrl" value="${url}" placeholder="https://www.example.com" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-medium">Icon Class</label>
|
||||
<input type="text" class="form-control" id="editSocialIcon" value="${icon}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" id="updateSocialLink">Update</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.body.appendChild(modal);
|
||||
const bsModal = new bootstrap.Modal(modal);
|
||||
|
||||
document.getElementById('updateSocialLink').addEventListener('click', function() {
|
||||
const newPlatform = document.getElementById('editSocialPlatform').value.trim();
|
||||
const newUrl = document.getElementById('editSocialUrl').value.trim();
|
||||
const newIcon = document.getElementById('editSocialIcon').value.trim();
|
||||
|
||||
if (!newPlatform) {
|
||||
alert('Vui lòng nhập tên nền tảng');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!newUrl) {
|
||||
alert('Vui lòng nhập URL');
|
||||
return;
|
||||
}
|
||||
|
||||
updateSocialLinkViaAPIModal(platform, newPlatform, newUrl, newIcon, bsModal, modal);
|
||||
});
|
||||
|
||||
bsModal.show();
|
||||
|
||||
// Focus on platform input
|
||||
setTimeout(() => {
|
||||
document.getElementById('editSocialPlatform').focus();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
function addSocialLinkViaAPI(platform, url, icon, modal, modalElement) {
|
||||
addSocialLinkRow(platform, url, icon, Date.now());
|
||||
updateHiddenInputs();
|
||||
markChanged();
|
||||
modal.hide();
|
||||
modalElement.remove();
|
||||
}
|
||||
|
||||
function updateSocialLinkViaAPIModal(oldPlatform, newPlatform, url, icon, modal, modalElement) {
|
||||
newPlatform = newPlatform.toLowerCase().trim();
|
||||
|
||||
// Update the input fields in the DOM
|
||||
const platformInputs = document.querySelectorAll(`.social-platform`);
|
||||
const urlInputs = document.querySelectorAll(`.social-url`);
|
||||
const iconInputs = document.querySelectorAll(`.social-icon`);
|
||||
|
||||
let found = false;
|
||||
for (let i = 0; i < platformInputs.length; i++) {
|
||||
if (platformInputs[i].value.toLowerCase() === oldPlatform.toLowerCase()) {
|
||||
platformInputs[i].value = newPlatform;
|
||||
urlInputs[i].value = url;
|
||||
if (iconInputs[i]) iconInputs[i].value = icon;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
modal.hide();
|
||||
modalElement.remove();
|
||||
updateHiddenInputs();
|
||||
markChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show toast notification at top of page
|
||||
@@ -990,41 +550,6 @@
|
||||
previewContainer.appendChild(img);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize Sortable for Social Links
|
||||
const socialLinksContainer = document.getElementById('socialLinksContainer');
|
||||
const SortableLib = window.Sortable || Sortable;
|
||||
|
||||
console.log('=== TRACE: Social Sortable Init ===', {
|
||||
containerExists: !!socialLinksContainer,
|
||||
sortableDefined: typeof SortableLib !== 'undefined'
|
||||
});
|
||||
|
||||
if (socialLinksContainer && typeof SortableLib !== 'undefined') {
|
||||
try {
|
||||
new SortableLib(socialLinksContainer, {
|
||||
animation: 150,
|
||||
handle: '.drag-handle',
|
||||
ghostClass: 'social-ghost',
|
||||
chosenClass: 'social-chosen',
|
||||
dragClass: 'social-drag',
|
||||
forceFallback: true, // Use transition-based dragging for better compatibility
|
||||
onStart: function() {
|
||||
console.log('=== TRACE: Social Drag Started ===');
|
||||
},
|
||||
onEnd: function() {
|
||||
console.log('=== TRACE: Social Drag Ended ===');
|
||||
updateHiddenInputs();
|
||||
markChanged();
|
||||
}
|
||||
});
|
||||
console.log('=== TRACE: Sortable initialized for socialLinksContainer ===');
|
||||
} catch (err) {
|
||||
console.error('=== TRACE: Sortable Init Error ===', err);
|
||||
}
|
||||
} else {
|
||||
console.warn('SortableJS not loaded or socialLinksContainer not found');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user