From 9bbc1302acc98d08e8fa67341fabf572db871278 Mon Sep 17 00:00:00 2001
From: Paul <203217+uniquePWD@users.noreply.github.com>
Date: Sun, 6 Jul 2025 15:28:55 +0100
Subject: [PATCH] Update script.js
Modernised this too
---
data/interfaces/default/js/script.js | 893 ++++++++++++++++-----------
1 file changed, 523 insertions(+), 370 deletions(-)
diff --git a/data/interfaces/default/js/script.js b/data/interfaces/default/js/script.js
index 3f926f90..4f0894ac 100644
--- a/data/interfaces/default/js/script.js
+++ b/data/interfaces/default/js/script.js
@@ -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('');
- }
- });
+/**
+ * @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 = $("
" + msg + "
");
+ $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("");
+ $("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('');
- }
- });
+// 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 = $("" + msg + "
");
- if (loader) {
- var message = $(" " + msg + "");
- 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 = $(" " + msg + "");
- 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 = $("");
- // 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 = $(" " + dataSucces + "
");
- var errorMsg = $(" " + dataError + "
");
-
- // 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("");
- $("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.
});