Merge pull request #3387 from uniquePWD/patch-19

Update script.js
This commit is contained in:
AdeHub
2025-08-03 20:56:18 +12:00
committed by GitHub

View File

@@ -1,386 +1,539 @@
function getThumb(imgElem,id,type) {
if ( type == 'artist' ) {
var thumbURL = "getThumb?ArtistID=" + id;
// var imgURL = "getArtwork?ArtistID=" + id;
} else {
var thumbURL = "getThumb?AlbumID=" + id;
// var imgURL = "getArtwork?AlbumID=" + id;
}
// Get Data from the cache by Artist ID
$.ajax({
url: thumbURL,
cache: true,
success: function(data){
if ( data == "" ) {
var imageUrl = "interfaces/default/images/no-cover-artist.png";
}
else {
var imageUrl = data;
}
$(imgElem).attr("src",imageUrl).hide().fadeIn();
// $(imgElem).wrap('<a href="'+ imgURL +'" rel="dialog" title="' + name + '"></a>');
}
});
/**
* @file headphones.js
* @brief Main JavaScript file for Headphones web interface.
* Contains core UI, API, and utility functions.
*/
var Headphones = Headphones || {};
// --- Configuration ---
Headphones.config = {
fallbackImage: "interfaces/default/images/no-cover-art.png", // Generic fallback
fallbackArtistImage: "interfaces/default/images/no-cover-artist.png", // Specific artist fallback
messageTimeout: 3000 // Default timeout for messages in milliseconds
};
// --- UI Messaging Module ---
Headphones.UI = Headphones.UI || {};
Headphones.UI.Message = (function() {
var $ajaxMsg = $("#ajaxMsg");
var $ajaxMsg2 = $("#ajaxMsg2"); // Assuming this is for artist-specific messages
var $updateBar = $("#updatebar");
/**
* Shows a feedback message to the user.
* @param {string} msg - The message to display.
* @param {string} type - Type of message ('success', 'error', 'info', 'loading').
* @param {number} [timeout=Headphones.config.messageTimeout] - Duration to display the message (in ms). Set to 0 for no timeout.
* @param {HTMLElement} [$targetElement=$ajaxMsg] - The jQuery element to display the message in.
*/
function showMessage(msg, type, timeout, $targetElement) {
timeout = typeof timeout !== 'undefined' ? timeout : Headphones.config.messageTimeout;
$targetElement = $targetElement || $ajaxMsg;
// Adjust position if update bar is visible
if ($updateBar.is(":visible")) {
var height = $updateBar.height() + 35;
$targetElement.css("bottom", height + "px");
} else {
$targetElement.removeAttr("style");
}
$targetElement.fadeIn();
$targetElement.removeClass('success error info'); // Clear previous states
var iconClass = '';
switch (type) {
case 'success':
iconClass = 'fa-check';
$targetElement.addClass('success');
break;
case 'error':
iconClass = 'fa-exclamation-triangle';
$targetElement.addClass('error');
break;
case 'loading':
iconClass = 'fa-refresh fa-spin';
break;
default: // info
iconClass = 'fa-info-circle';
$targetElement.addClass('info');
}
var $message = $("<div class='msg'><i class='fa " + iconClass + "'></i> " + msg + "</div>");
$targetElement.empty().append($message); // Clear and append new message
if (timeout > 0) {
setTimeout(function() {
$message.fadeOut(function() {
$(this).remove();
$targetElement.fadeOut();
});
}, timeout);
}
}
/**
* Specific function for artist messages (if still needed, otherwise consolidate into showMessage)
* @param {string} msg - The message to display.
*/
function showArtistMessage(msg) {
showMessage(msg, 'loading', 0, $ajaxMsg2); // No timeout for loading message
}
return {
show: showMessage,
showArtist: showArtistMessage // Consider removing if not distinct enough
};
})();
// --- API / AJAX Module ---
Headphones.API = (function() {
/**
* Performs an AJAX call with standardized messaging and reload options.
* @param {object} options - Configuration options for the AJAX call.
* @param {string} options.url - The URL for the AJAX request.
* @param {object|string} [options.data] - Data to send with the request.
* @param {string} [options.type='POST'] - HTTP method ('GET' or 'POST').
* @param {string} [options.successMessage='Success!'] - Message to display on success.
* @param {string} [options.errorMessage='There was an error'] - Message to display on error.
* @param {string} [options.reloadType] - Type of reload after success ('table', 'tabs', 'page', 'submenu', 'submenu&table').
* @param {HTMLElement} [options.contextElement] - The DOM element that triggered the action (for data-attributes).
* @param {function} [options.beforeSendCallback] - Custom function to call before sending.
* @param {function} [options.successCallback] - Custom function to call on success.
* @param {function} [options.errorCallback] - Custom function to call on error.
* @param {function} [options.completeCallback] - Custom function to call on completion.
*/
function doAjaxCall(options) {
var opts = $.extend(true, {
url: '',
data: {},
type: 'POST',
successMessage: 'Success!',
errorMessage: 'There was an error',
reloadType: null, // 'table', 'tabs', 'page', 'submenu', 'submenu&table'
contextElement: null,
beforeSendCallback: null,
successCallback: null,
errorCallback: null,
completeCallback: null
}, options);
// Get messages from data attributes if context element provided
if (opts.contextElement) {
var $elem = $(opts.contextElement);
opts.successMessage = $elem.data('success') || opts.successMessage;
opts.errorMessage = $elem.data('error') || opts.errorMessage;
}
$.ajax({
url: opts.url,
data: opts.data,
type: opts.type,
beforeSend: function(jqXHR, settings) {
Headphones.UI.Message.show('Loading...', 'loading', 0); // Show loading message indefinitely
if (opts.beforeSendCallback) opts.beforeSendCallback(jqXHR, settings);
},
error: function(jqXHR, textStatus, errorThrown) {
Headphones.UI.Message.show(opts.errorMessage, 'error');
if (opts.errorCallback) opts.errorCallback(jqXHR, textStatus, errorThrown);
},
success: function(data, textStatus, jqXHR) {
Headphones.UI.Message.show(opts.successMessage, 'success');
if (opts.successCallback) opts.successCallback(data, textStatus, jqXHR);
// Handle reloads based on reloadType
setTimeout(function() { // Wait for message to fade out
if (opts.reloadType === 'table') {
Headphones.UI.Content.refreshTable();
} else if (opts.reloadType === 'tabs') {
Headphones.UI.Content.refreshTab();
} else if (opts.reloadType === 'page') {
location.reload();
} else if (opts.reloadType === 'submenu') {
Headphones.UI.Content.refreshSubmenu();
} else if (opts.reloadType === 'submenu&table') {
Headphones.UI.Content.refreshSubmenu();
Headphones.UI.Content.refreshTable();
}
}, Headphones.config.messageTimeout + 100); // Wait for message fade out
},
complete: function(jqXHR, textStatus) {
// The message will fade out automatically by showMessage
if (opts.completeCallback) opts.completeCallback(jqXHR, textStatus);
}
});
}
/**
* Performs a simple GET AJAX call without complex messaging or reload.
* @param {string} url - The URL for the GET request.
*/
function doSimpleAjaxCall(url) {
$.ajax({ url: url, type: 'GET' });
}
return {
call: doAjaxCall,
simpleCall: doSimpleAjaxCall
};
})();
// --- Image Loading Module ---
Headphones.Images = (function() {
/**
* Loads artwork/thumbnail for an element, handling lazy load and fallbacks.
* @param {jQuery} $imgElem - The jQuery image element.
* @param {string} id - The ID (AlbumID or ArtistID).
* @param {string} type - 'album' or 'artist'.
* @param {boolean} [unveil=false] - Whether to use data-src and unveil for lazy loading.
*/
function loadImage($imgElem, id, type, unveil) {
var infoURL = "getImageLinks?" + (type === 'artist' ? "ArtistID=" : "AlbumID=") + id;
$.ajax({
url: infoURL,
cache: true,
dataType: "json",
success: function(data) {
var imageUrl = Headphones.config.fallbackImage;
var artworkUrl = Headphones.config.fallbackImage;
if (data) {
imageUrl = data.thumbnail || (type === 'artist' ? Headphones.config.fallbackArtistImage : Headphones.config.fallbackImage);
artworkUrl = data.artwork || (type === 'artist' ? Headphones.config.fallbackArtistImage : Headphones.config.fallbackImage);
}
if (unveil) {
$imgElem.attr("data-src", imageUrl);
$imgElem.unveil(); // Trigger unveil for lazy loading
} else {
$imgElem.attr("src", imageUrl).hide().fadeIn(); // Direct load with fade
}
// If element has a rel="dialog" parent, update href for Fancybox
var $wrapper = $imgElem.closest('a[rel="dialog"]');
if ($wrapper.length) {
$wrapper.attr('href', artworkUrl); // Link to full artwork
}
},
error: function() {
// On error, set to fallback image if not already set or handled by onerror on HTML
if (unveil) {
$imgElem.attr("data-src", Headphones.config.fallbackImage);
$imgElem.unveil();
} else {
$imgElem.attr("src", Headphones.config.fallbackImage).hide().fadeIn();
}
}
});
}
/**
* Fetches and appends summary information.
* @param {jQuery} $elem - The element to append summary to.
* @param {string} id - The ID (AlbumID or ArtistID).
* @param {string} type - 'album' or 'artist'.
*/
function getInfo($elem, id, type) {
var infoURL = "getInfo?" + (type === 'artist' ? "ArtistID=" : "AlbumID=") + id;
$.ajax({
url: infoURL,
cache: true,
dataType: "json",
success: function(data) {
if (data && data.Summary) {
$elem.append(data.Summary);
}
}
});
}
return {
load: loadImage,
getInfo: getInfo
};
})();
// --- UI Content Refresh Module ---
Headphones.UI.Content = (function() {
/**
* Refreshes a specific part of the page content.
* @param {string} targetSelector - jQuery selector for the element to load content into.
* @param {string} sourceContentSelector - jQuery selector for the content to extract from the source URL.
* @param {function} [initCallback] - Callback function to run after content is loaded.
*/
function refreshPart(targetSelector, sourceContentSelector, initCallback) {
var url = window.location.href;
$(targetSelector).load(url + " " + sourceContentSelector, function(response, status, xhr) {
if (status === "error") {
console.error("Failed to load content for " + targetSelector + ": " + xhr.status + " " + xhr.statusText);
Headphones.UI.Message.show("Failed to refresh content.", 'error');
} else if (initCallback) {
// Ensure the callback is part of the Headphones object if it relies on it
if (typeof initCallback === 'string' && Headphones.hasOwnProperty(initCallback)) {
Headphones[initCallback](); // Call the global Headphones function
} else if (typeof initCallback === 'function') {
initCallback();
}
}
});
}
/** Refreshes the submenu by reloading its content. */
function refreshSubmenu() {
refreshPart("#subhead_container", "#subhead_menu", Headphones.UI.initActions); // Pass initActions to re-apply handlers
}
/** Refreshes the main table content. */
function refreshTable() {
// This assumes there's one main .display table. If multiple, refine selector.
// The original also reloaded tbody and thead separately, which is fine.
refreshPart("table.display", "table.display tbody, table.display thead", function() {
// Re-initialize DataTables after table refresh.
// This might need specific DataTable re-initialization logic for each page.
// A more robust solution would be to destroy and recreate the DataTable.
// The template-specific `initThisPage()` usually contains this.
// We need to call the appropriate initThisPage for the current page.
// As `initThisPage` is defined per HTML file, we rely on the specific page's ready handler
// to call its own initThisPage, or pass it as a parameter if this is called generically.
// For now, let's assume `initThisPage` exists in the global scope where refreshTable is called.
if (typeof initThisPage === 'function') {
initThisPage();
} else if (typeof SearchResultsPage !== 'undefined' && typeof SearchResultsPage.initDataTable === 'function') {
SearchResultsPage.initDataTable();
}
// ... add more page-specific re-initializations as needed
});
}
/** Refreshes the currently active tab content. */
function refreshTab() {
var tabId = $('.ui-tabs-panel:visible').attr("id");
if (tabId) {
refreshPart('.ui-tabs-panel:visible', "#" + tabId, function() {
// Similar to refreshTable, re-initialize specific tab content
if (typeof initThisPage === 'function') { // assuming initThisPage handles tab content
initThisPage();
}
});
}
}
/**
* Polls for status changes on rows with 'gradeL' class (loading state).
* This is an older polling pattern; consider WebSockets for real-time updates if performance is critical.
*/
function refreshLoadArtist() {
var $loadingRows = $("table.display tr.gradeL");
if ($loadingRows.length > 0) {
$loadingRows.each(function() {
var $row = $(this);
// Reload only the row's content to check status
var rowIndex = $row.index() + 1; // 1-based index
var url = window.location.href;
$row.load(url + " table.display tbody tr:nth-child(" + rowIndex + ") td", function(response, status, xhr) {
if (status === "error") {
console.error("Failed to load row status: " + xhr.status + " " + xhr.statusText);
// Optional: Show a message to the user
} else {
// Check status after loading the updated row content
if ($row.find(".column-status").text() === 'Active') { // Assuming a status column with this text
$row.removeClass('gradeL').addClass('gradeZ');
// Re-initialize relevant JS if needed for the row (e.g., DataTables redrawing)
if (typeof initThisPage === 'function') initThisPage(); // Re-initialize the table/page
} else {
// If still loading, set timeout for next check
setTimeout(refreshLoadArtist, 3000);
}
}
});
});
}
}
return {
refreshSubmenu: refreshSubmenu,
refreshTable: refreshTable,
refreshTab: refreshTab,
refreshLoadArtist: refreshLoadArtist
};
})();
// --- UI Element Initialization Module ---
Headphones.UI.Elements = (function() {
/** Initializes the header scroll-fade effect. */
function initHeader() {
var $header = $("#container header");
var fadeSpeed = 100,
fadeTo = 0.5,
topDistance = 20;
var inside = false;
$(window).on('scroll', function() {
var position = $(window).scrollTop();
if (position > topDistance && !inside) {
//add events
$header.fadeTo(fadeSpeed, fadeTo);
$header.on('mouseenter', function() {
$header.fadeTo(fadeSpeed, 1);
});
$header.on('mouseleave', function() {
$header.fadeTo(fadeSpeed, fadeTo);
});
$("#toTop").fadeIn();
inside = true;
} else if (position < topDistance && inside) { // Added '&& inside' to prevent re-triggering
$header.fadeTo(fadeSpeed, 1); // Ensure it's fully visible at top
$header.off('mouseenter mouseleave'); // Remove events when at top
$("#toTop").fadeOut();
inside = false;
}
});
}
/**
* Initializes config checkboxes to show/hide sibling content.
* @param {HTMLElement} elem - The checkbox DOM element.
*/
function initConfigCheckbox(elem) {
var $checkbox = $(elem);
var $configContent = $checkbox.parent().next();
// Initial state
if ($checkbox.is(":checked")) {
$configContent.show();
} else {
$configContent.hide();
}
// Click handler
$checkbox.on('click', function() {
if ($(this).is(":checked")) {
$configContent.slideDown();
} else {
$configContent.slideUp();
}
});
}
/** Initializes various action buttons with jQuery UI button styling. */
function initActions() {
// Select all menu links under #subhead_menu and apply button()
// This assumes jQuery UI Button widget is available and desired.
$("#subhead_menu a[id^='menu_link_'], #subhead_menu .menu_link_edit").button();
}
return {
initHeader: initHeader,
initConfigCheckbox: initConfigCheckbox,
initActions: initActions
};
})();
// --- Utility Functions Module ---
Headphones.Utils = (function() {
/**
* Sets placeholder text for DataTables search input.
* @param {string} text - The placeholder text.
*/
function resetFilters(text) {
// Ensure this targets the correct search input for DataTables
if ($(".dataTables_filter input").length > 0) {
$(".dataTables_filter input").attr("placeholder", "filter " + text + "");
}
}
/** Initializes Fancybox for dialog links. */
function initFancybox() {
// Check if Fancybox script is already loaded or needs to be loaded dynamically
if ($.fn.fancybox) { // Check if fancybox function exists on jQuery object
$("a[rel=dialog]").fancybox();
} else if ($("a[rel=dialog]").length > 0) {
// Dynamically load Fancybox script and CSS if elements with rel=dialog exist
$.getScript('interfaces/default/js/fancybox/jquery.fancybox-1.3.4.js', function() {
$("head").append("<link rel='stylesheet' href='interfaces/default/js/fancybox/jquery.fancybox-1.3.4.css'>");
$("a[rel=dialog]").fancybox();
}).fail(function(jqxhr, settings, exception) {
console.error("Failed to load Fancybox script: ", exception);
});
}
}
return {
resetFilters: resetFilters,
initFancybox: initFancybox
};
})();
// --- Global Functions (for backward compatibility if needed, but prefer to call from Headphones object) ---
// These global functions would ideally be removed and replaced with direct calls to Headphones.API, Headphones.UI, etc.
// For a gradual transition, they can act as wrappers.
// Original getThumb / getImageLinks replacement
function getImageLinks(elem, id, type, unveil) {
Headphones.Images.load($(elem), id, type, unveil);
}
function getArtwork(imgElem,id,name,type) {
if ( type == 'artist' ) {
var artworkURL = "getArtwork?ArtistID=" + id;
} else {
var artworkURL = "getArtwork?AlbumID=" + id;
}
// Get Data from the cache by Artist ID
$.ajax({
url: artworkURL,
cache: true,
success: function(data){
if ( data == "" || data == undefined ) {
var imageUrl = "interfaces/default/images/no-cover-artist.png";
}
else {
var imageUrl = data;
}
$(imgElem).attr("src",imageUrl).hide().fadeIn();
$(imgElem).wrap('<a href="'+ imageUrl +'" rel="dialog" title="' + name + '"></a>');
}
});
// Original getInfo replacement
function getInfo(elem, id, type) {
Headphones.Images.getInfo($(elem), id, type);
}
function getInfo(elem,id,type) {
if ( type == 'artist' ) {
var infoURL = "getInfo?ArtistID=" + id;
} else {
var infoURL = "getInfo?AlbumID=" + id;
}
// Get Data from the cache by ID
$.ajax({
url: infoURL,
cache: true,
dataType: "json",
success: function(data){
var summary = data.Summary;
$(elem).append(summary);
}
});
}
// Original doAjaxCall replacement (needs careful integration with new params)
// The HTML templates are passing doAjaxCall(url,elem,reload,form).
// This wrapper needs to convert those to the new options object.
function doAjaxCall(url, elem, reloadType, isFormSubmission) {
var options = {
url: url,
contextElement: elem,
reloadType: reloadType
};
function getImageLinks(elem,id,type,unveil) {
if ( type == 'artist' ) {
var infoURL = "getImageLinks?ArtistID=" + id;
} else {
var infoURL = "getImageLinks?AlbumID=" + id;
}
// Get Data from the cache by ID
$.ajax({
url: infoURL,
cache: true,
dataType: "json",
success: function(data){
if (!data) {
// Invalid response
return;
}
if (!data.thumbnail) {
var thumbnail = "interfaces/default/images/no-cover-artist.png";
}
else {
var thumbnail = data.thumbnail;
}
if (!data.artwork) {
var artwork = "interfaces/default/images/no-cover-artist.png";
}
else {
var artwork = data.artwork;
}
if (unveil) {
$(elem).attr("data-src", thumbnail);
$(elem).unveil();
}
else {
$(elem).attr("src", thumbnail);
}
}
});
}
function initHeader() {
//settings
var header = $("#container header");
var fadeSpeed = 100, fadeTo = 0.5, topDistance = 20;
var topbarME = function() { $(header).fadeTo(fadeSpeed,1); }, topbarML = function() { $(header).fadeTo(fadeSpeed,fadeTo); };
var inside = false;
//do
$(window).scroll(function() {
position = $(window).scrollTop();
if(position > topDistance && !inside) {
//add events
topbarML();
$(header).bind('mouseenter',topbarME);
$(header).bind('mouseleave',topbarML);
$("#toTop").fadeIn();
inside = true;
}
else if (position < topDistance){
topbarME();
$(header).unbind('mouseenter',topbarME);
$(header).unbind('mouseleave',topbarML);
$("#toTop").fadeOut();
inside = false;
}
});
}
function initConfigCheckbox(elem) {
var config = $(elem).parent().next();
if ( $(elem).is(":checked") ) {
config.show();
} else {
config.hide();
}
$(elem).click(function(){
var config = $(this).parent().next();
if ( $(this).is(":checked") ) {
config.slideDown();
} else {
config.slideUp();
}
});
}
function initActions() {
$("#subhead_menu #menu_link_refresh").button();
$("#subhead_menu #menu_link_edit").button();
$("#subhead_menu .menu_link_edit").button();
$("#subhead_menu #menu_link_delete" ).button();
$("#subhead_menu #menu_link_pauze").button();
$("#subhead_menu #menu_link_resume").button();
$("#subhead_menu #menu_link_getextra").button();
$("#subhead_menu #menu_link_removeextra").button();
$("#subhead_menu #menu_link_wanted" ).button();
$("#subhead_menu #menu_link_check").button();
$("#subhead_menu #menu_link_skipped").button();
$("#subhead_menu #menu_link_retry").button();
$("#subhead_menu #menu_link_new").button();
$("#subhead_menu #menu_link_shutdown").button();
$("#subhead_menu #menu_link_scan").button();
}
function refreshSubmenu() {
var url = $(location).attr('href');
$("#subhead_container").load(url + " #subhead_menu",function(){
initActions();
});
}
function refreshTable() {
var url = $(location).attr('href');
$("table.display").load(url + " table.display tbody, table.display thead", function() {
initThisPage();
});
}
function refreshLoadArtist() {
if ( $(".gradeL").length > 0 ) {
var url = $(location).attr('href');
var loadingRow = $("table.display tr.gradeL")
loadingRow.each(function(){
var row = $(this).index() + 1;
var rowLoad = $("table.display tbody tr:nth-child("+row+")");
$(rowLoad).load(url + " table.display tbody tr:nth-child("+ row +") td", function() {
if ( $(rowLoad).children("#status").text() == 'Active' ) {
// Active
$(rowLoad).removeClass('gradeL').addClass('gradeZ');
initThisPage();
} else {
// Still loading
setTimeout(function(){
refreshLoadArtist();
},3000);
}
});
});
}
}
function refreshTab() {
var url = $(location).attr('href');
var tabId = $('.ui-tabs-panel:visible').attr("id");
$('.ui-tabs-panel:visible').load(url + " #"+ tabId, function() {
initThisPage();
});
}
function showMsg(msg,loader,timeout,ms) {
var feedback = $("#ajaxMsg");
update = $("#updatebar");
if ( update.is(":visible") ) {
var height = update.height() + 35;
feedback.css("bottom",height + "px");
} else {
feedback.removeAttr("style");
}
feedback.fadeIn();
var message = $("<div class='msg'>" + msg + "</div>");
if (loader) {
var message = $("<i class='fa fa-refresh fa-spin'></i> " + msg + "</div>");
feedback.css("padding","14px 10px")
}
$(feedback).prepend(message);
if (timeout) {
setTimeout(function(){
message.fadeOut(function(){
$(this).remove();
feedback.fadeOut();
});
},ms);
}
}
function showArtistMsg(msg) {
var feedback = $("#ajaxMsg2");
update = $("#updatebar");
if ( update.is(":visible") ) {
var height = update.height() + 35;
feedback.css("bottom",height + "px");
} else {
feedback.removeAttr("style");
}
feedback.fadeIn();
var message = $("<i class='fa fa-refresh fa-spin'></i> " + msg + "</div>");
feedback.css("padding","14px 10px")
$(feedback).prepend(message);
}
function doAjaxCall(url,elem,reload,form) {
// Set Message
feedback = $("#ajaxMsg");
update = $("#updatebar");
if ( update.is(":visible") ) {
var height = update.height() + 35;
feedback.css("bottom",height + "px");
} else {
feedback.removeAttr("style");
}
feedback.fadeIn();
// Get Form data
var formID = "#"+url;
if ( form == true ) {
var dataString = $(formID).serialize();
}
// Loader Image
var loader = $("<i class='fa fa-refresh fa-spin'></i>");
// Data Success Message
var dataSucces = $(elem).data('success');
if (typeof dataSucces === "undefined") {
// Standard Message when variable is not set
var dataSucces = "Success!";
}
// Data Errror Message
var dataError = $(elem).data('error');
if (typeof dataError === "undefined") {
// Standard Message when variable is not set
var dataError = "There was an error";
}
// Get Success & Error message from inline data, else use standard message
var succesMsg = $("<div class='msg'><i class='fa fa-check'></i> " + dataSucces + "</div>");
var errorMsg = $("<div class='msg'><i class='fa fa-exclamation-triangle'></i> " + dataError + "</div>");
// Check if checkbox is selected
if ( form ) {
if ( $('td#select input[type=checkbox]').length > 0 && !$('td#select input[type=checkbox]').is(':checked') || $('#importLastFM #username:visible').length > 0 && $("#importLastFM #username" ).val().length === 0 ) {
feedback.addClass('error')
$(feedback).prepend(errorMsg);
setTimeout(function(){
errorMsg.fadeOut(function(){
$(this).remove();
feedback.fadeOut(function(){
feedback.removeClass('error');
});
})
$(formID + " select").children('option[disabled=disabled]').attr('selected','selected');
},2000);
return false;
}
}
// Ajax Call
$.ajax({
url: url,
data: dataString,
type: 'POST',
beforeSend: function(jqXHR, settings) {
// Start loader etc.
feedback.prepend(loader);
},
error: function(jqXHR, textStatus, errorThrown) {
feedback.addClass('error')
feedback.prepend(errorMsg);
setTimeout(function(){
errorMsg.fadeOut(function(){
$(this).remove();
feedback.fadeOut(function(){
feedback.removeClass('error')
});
})
},2000);
},
success: function(data,jqXHR) {
feedback.prepend(succesMsg);
feedback.addClass('success')
setTimeout(function(e){
succesMsg.fadeOut(function(){
$(this).remove();
feedback.fadeOut(function(){
feedback.removeClass('success');
});
if ( reload == true ) refreshSubmenu();
if ( reload == "table") {
console.log('refresh'); refreshTable();
}
if ( reload == "tabs") refreshTab();
if ( reload == "page") location.reload();
if ( reload == "submenu&table") {
refreshSubmenu();
refreshTable();
}
if ( form ) {
// Change the option to 'choose...'
$(formID + " select").children('option[disabled=disabled]').attr('selected','selected');
}
})
},2000);
},
complete: function(jqXHR, textStatus) {
// Remove loaders and stuff, ajax request is complete!
loader.remove();
}
});
if (isFormSubmission) {
// This part needs careful migration. The original `doAjaxCall`
// had logic like `var formID = "#"+url; var dataString = $(formID).serialize();`
// and validation like `if ( $('td#select input[type=checkbox]').length > 0 && !$('td#select input[type=checkbox]').is(':checked') ... )`.
// This validation MUST be done *before* calling doAjaxCall in the specific HTML template's JS.
// Here, we assume `url` is the form ID if `isFormSubmission` is true.
var $form = $('#' + url); // Assuming url is the form ID
if ($form.length) {
options.data = $form.serialize();
} else {
console.warn("doAjaxCall: form with ID '" + url + "' not found for submission.");
// If the form cannot be found, it should likely be an error.
Headphones.UI.Message.show("Form not found for submission.", 'error');
return false;
}
}
Headphones.API.call(options);
}
function doSimpleAjaxCall(url) {
$.ajax(url);
Headphones.API.simpleCall(url);
}
function resetFilters(text){
if ( $(".dataTables_filter").length > 0 ) {
$(".dataTables_filter input").attr("placeholder","filter " + text + "");
}
function resetFilters(text) {
Headphones.Utils.resetFilters(text);
}
function initFancybox() {
if ( $("a[rel=dialog]").length > 0 ) {
$.getScript('interfaces/default/js/fancybox/jquery.fancybox-1.3.4.js', function() {
$("head").append("<link rel='stylesheet' href='interfaces/default/js/fancybox/jquery.fancybox-1.3.4.css'>");
$("a[rel=dialog]").fancybox();
});
}
Headphones.Utils.initFancybox();
}
$(document).ready(function(){
initHeader();
// Placeholder for `initThisPage` - this function is typically defined per HTML template.
// It's called by `$(document).ready` in many templates.
// This should be removed from `headphones.js` and defined in each template.
// function initThisPage() { /* defined in each HTML template */ }
// --- Document Ready ---
$(document).ready(function() {
Headphones.UI.Elements.initHeader(); // Initialize global header effects
Headphones.UI.Elements.initActions(); // Initialize global action buttons (jQuery UI)
// Ensure `initThisPage()` is called from the individual HTML template's ready handler.
// This `script.js` file should be included *before* the template's specific script block.
});