jQuery(document).ready(function($) { 'use strict'; const MSD_Widgets = { init() { this.loadAllWidgets(); this.bindEvents(); }, bindEvents() { $(document) .on('click', '.msd-user-action-btn', this.handleUserAction.bind(this)) .on('click', '.msd-todo-add-btn', this.showTodoForm.bind(this)) .on('click', '.msd-todo-checkbox', this.toggleTodoComplete.bind(this)) .on('click', '.msd-todo-edit', this.editTodo.bind(this)) .on('click', '.msd-todo-delete', this.deleteTodo.bind(this)) .on('click', '.msd-todo-save', this.saveTodo.bind(this)) .on('click', '.msd-todo-cancel', this.cancelTodoForm.bind(this)); }, loadAllWidgets() { if (window.MSD_Core && window.MSD_Core.isRefreshing) return; if (window.MSD_Core) { window.MSD_Core.isRefreshing = true; } const widgets = ['network_overview', 'site_list', 'storage_data', 'version_info', 'custom_news', 'network_settings', 'user_management', 'last_edits', 'todo_items']; widgets.forEach(widget => { this.loadWidget(widget); }); setTimeout(() => { if (window.MSD_Core) { window.MSD_Core.isRefreshing = false; } }, 1000); }, loadWidget(widgetType) { const $container = $(`[data-widget="${widgetType}"]`); if ($container.length === 0) return; const actionMap = { network_overview: 'msd_get_network_overview', site_list: 'msd_get_site_list', storage_data: 'msd_get_storage_data', version_info: 'msd_get_version_info', custom_news: 'msd_get_custom_news', network_settings: 'msd_get_network_settings', user_management: 'msd_get_user_management', last_edits: 'msd_get_last_edits', todo_items: 'msd_get_todo_items' }; const action = actionMap[widgetType]; if (!action) return; if (window.MSD_Core) { window.MSD_Core.makeAjaxRequest(action, {}, (response) => { this.renderWidget(widgetType, $container, response.data); if (window.MSD_Core) { window.MSD_Core.retryCount = 0; } }, (error) => { this.handleWidgetError($container, error, widgetType); }); } }, renderWidget(widgetType, $container, data) { const renderers = { network_overview: this.renderNetworkOverview, site_list: this.renderQuickSites, storage_data: this.renderStorageData, version_info: this.renderVersionInfo, custom_news: this.renderCustomNews, network_settings: this.renderNetworkSettings, user_management: this.renderUserManagement, last_edits: this.renderLastEdits, todo_items: this.renderTodoItems }; const renderer = renderers[widgetType]; if (renderer) { renderer.call(this, $container, data); $container.addClass('fade-in'); } }, renderNetworkOverview($container, data) { const html = `
${this.formatNumber(data.total_posts || 0)} Posts
${this.formatNumber(data.total_pages || 0)} Pages
Multisite Configuration
Installation Type: ${this.escapeHtml(data.multisite_config?.installation_type_label || 'Unknown')}
Network Admin Email: ${this.escapeHtml(data.network_info?.network_admin_email || 'Not set')}
Site Upload Quota: ${data.network_info?.blog_upload_space_formatted || '0 MB'}
Max Upload Size: ${data.network_info?.fileupload_maxk_formatted || 'Unknown'}
Default Language: ${this.escapeHtml(data.network_info?.default_language || 'en_US')}
Registration: ${this.escapeHtml(data.network_info?.registration_label || 'Unknown')}
`; $container.html(html); // 重新初始化 sortable 功能 setTimeout(() => { if (window.MSD_Modals && window.MSD_Modals.initSortable) { window.MSD_Modals.initSortable(); } }, 100); }, renderQuickSites($container, sites) { let html = ''; if (!sites || sites.length === 0) { html += '

No active sites found.

'; } else { html += '
'; sites.forEach(site => { html += `
${this.escapeHtml(site.name)}
${this.escapeHtml(site.name)}
${site.users || 0} users ${site.last_activity_human || 'No activity'}
`; }); html += '
'; } $container.html(html); }, renderStorageData($container, data) { let html = ''; if (!data || !data.sites || data.sites.length === 0) { html += '

No storage data available.

'; } else { html += '
'; html += `
Total Network Storage: ${data.total_formatted || '0 B'}
`; if (data.summary) { html += `
Top 5 sites by storage usage
`; } html += '
'; html += '
'; data.sites.forEach(site => { const fillWidth = Math.min(site.usage_percentage || 0, 100); const fillClass = this.getStorageStatusClass(site.status); html += `
${this.escapeHtml(site.name)}
${this.escapeHtml(site.domain)}
${site.storage_formatted || '0 B'}
${site.usage_percentage || 0}%
`; }); html += '
'; } $container.html(html); }, renderVersionInfo($container, data) { let html = `

${this.escapeHtml(data.plugin_name || 'WP Multisite Dashboard')}

${data.update_available && data.update_info ? `
Version ${this.escapeHtml(data.update_info.version)} available! ${data.update_info.details_url ? `View Details` : ''}
` : ''}
Plugin Version ${this.escapeHtml(data.plugin_version || '')}
Author URI ${this.escapeHtml(data.plugin_uri || '')}
Required PHP ${this.escapeHtml(data.required_php || '')}
Database Tables ${data.database_status === 'active' ? '✓' : '⚠'} ${this.escapeHtml(data.database_message || 'Unknown')}
`; $container.html(html); }, renderCustomNews($container, news) { let html = ` `; if (!news || news.length === 0) { html += `

No news items available.

Configure news sources to see updates.

`; } else { html += '
'; news.forEach(item => { const date = item.date ? this.formatNewsDate(item.date) : ''; const cleanTitle = this.decodeHtmlEntities(item.title || ''); const cleanDescription = this.decodeHtmlEntities(item.description || ''); html += `
${this.escapeHtml(item.source || '')} ${date}

${this.escapeHtml(cleanTitle)}

${this.escapeHtml(cleanDescription)}

`; }); html += '
'; } html += `
`; $container.html(html); }, renderNetworkSettings($container, data) { let html = `
Network: ${this.escapeHtml(data.network_info?.network_name || 'N/A')}
Registration: ${this.getRegistrationLabel(data.network_info?.registration || 'none')}
Upload Limit: ${data.network_info?.blog_upload_space || 0} MB
Active Plugins: ${data.theme_plugin_settings?.network_active_plugins || 0}
Network Themes: ${data.theme_plugin_settings?.network_themes || 0}
Settings Sites Users Themes Plugins Updates
`; $container.html(html); }, renderUserManagement($container, data) { let html = `
${data.total_users || 0} users (${data.super_admin_count || 0} admins) ${data.registration_status?.description || 'Unknown'}
`; if (data.recent_registrations && data.recent_registrations.length > 0) { data.recent_registrations.slice(0, 5).forEach(user => { const statusClass = this.getUserStatusClass(user.status); html += `
${this.escapeHtml(user.display_name)}
${this.escapeHtml(user.display_name)}
`; }); } else { html += '
No recent registrations
'; } html += '
'; if (data.pending_activations && data.pending_activations.length > 0) { html += `
${data.pending_activations.length} pending activation(s)
`; data.pending_activations.slice(0, 3).forEach(signup => { html += `
${this.escapeHtml(signup.user_email)}
Activate
`; }); html += '
'; } html += '
'; $container.html(html); }, renderLastEdits($container, activities) { let html = ''; if (!activities || activities.length === 0) { html += '

No recent network activity found.

'; } else { html += '
'; activities.forEach(activity => { const truncatedContent = activity.content ? this.truncateText(activity.content, 30) : ''; html += `
${this.escapeHtml(activity.site_name)} ${activity.date_human}
${truncatedContent ? `

${this.escapeHtml(truncatedContent)}

` : ''}
`; }); html += '
'; } $container.html(html); }, renderTodoItems($container, todos) { let html = `
${todos.length} total
${todos.filter(t => t.completed).length} done
`; if (todos.length === 0) { html += `

No todos yet. Click "Add Todo" to get started!

`; } else { html += '
'; todos.forEach(todo => { const completedClass = todo.completed ? 'completed' : ''; html += `
${this.escapeHtml(todo.title)}
${todo.description ? `
${this.escapeHtml(todo.description)}
` : ''}
${todo.priority} ${todo.created_at_human}
`; }); html += '
'; } html += `
`; $container.html(html); }, showTodoForm() { $('#msd-todo-form').addClass('active'); $('#msd-todo-title').focus(); }, cancelTodoForm() { $('#msd-todo-form').removeClass('active'); this.clearTodoForm(); }, clearTodoForm() { $('#msd-todo-title').val(''); $('#msd-todo-description').val(''); $('#msd-todo-priority').val('medium'); $('#msd-todo-form').removeData('edit-id'); }, saveTodo() { const title = $('#msd-todo-title').val().trim(); if (!title) { if (window.MSD_Core) { window.MSD_Core.showNotice('Title is required', 'error'); } return; } const data = { title: title, description: $('#msd-todo-description').val().trim(), priority: $('#msd-todo-priority').val() }; const editId = $('#msd-todo-form').data('edit-id'); const action = editId ? 'msd_update_todo_item' : 'msd_save_todo_item'; if (editId) { data.id = editId; } if (window.MSD_Core) { window.MSD_Core.makeAjaxRequest(action, data, (response) => { window.MSD_Core.showNotice(response.data.message, 'success'); this.cancelTodoForm(); this.loadWidget('todo_items'); }, (error) => { window.MSD_Core.showNotice(error || 'Failed to save todo', 'error'); }); } }, editTodo(e) { const $item = $(e.currentTarget).closest('.msd-todo-item'); const id = $item.data('id'); const title = $item.find('.msd-todo-title').text(); const description = $item.find('.msd-todo-description').text(); $('#msd-todo-title').val(title); $('#msd-todo-description').val(description); $('#msd-todo-form').data('edit-id', id).addClass('active'); $('#msd-todo-title').focus(); }, deleteTodo(e) { if (!confirm(msdAjax.strings.confirm_delete)) { return; } const $item = $(e.currentTarget).closest('.msd-todo-item'); const id = $item.data('id'); if (window.MSD_Core) { window.MSD_Core.makeAjaxRequest('msd_delete_todo_item', { id }, (response) => { window.MSD_Core.showNotice(response.data.message, 'success'); this.loadWidget('todo_items'); }, (error) => { window.MSD_Core.showNotice(error || 'Failed to delete todo', 'error'); }); } }, toggleTodoComplete(e) { const $item = $(e.currentTarget).closest('.msd-todo-item'); const id = $item.data('id'); if (window.MSD_Core) { window.MSD_Core.makeAjaxRequest('msd_toggle_todo_complete', { id }, (response) => { this.loadWidget('todo_items'); }, (error) => { window.MSD_Core.showNotice(error || 'Failed to update todo', 'error'); }); } }, handleUserAction(e) { e.preventDefault(); const $btn = $(e.currentTarget); const action = $btn.data('action'); const userId = $btn.data('user-id'); if (!action || !userId) { if (window.MSD_Core) { window.MSD_Core.showNotice('Invalid action or user ID', 'error'); } return; } if (!confirm('Are you sure you want to perform this action?')) { return; } $btn.prop('disabled', true).text('Processing...'); if (window.MSD_Core) { window.MSD_Core.makeAjaxRequest('msd_manage_user_action', { user_action: action, user_id: userId }, (response) => { window.MSD_Core.showNotice(response.data.message || 'Action completed successfully', 'success'); this.loadWidget('user_management'); }, (error) => { window.MSD_Core.showNotice(error || 'Action failed', 'error'); }).always(() => { $btn.prop('disabled', false).text($btn.data('original-text') || 'Action'); }); } }, handleWidgetError($container, error, widgetType) { if (window.MSD_Core) { window.MSD_Core.retryCount++; if (window.MSD_Core.retryCount <= window.MSD_Core.maxRetries) { setTimeout(() => { this.loadWidget(widgetType); }, 2000 * window.MSD_Core.retryCount); return; } } const html = `

Unable to load data

`; $container.html(html); }, formatNumber: window.MSD_Core ? window.MSD_Core.formatNumber : function(num) { return num.toString(); }, escapeHtml: window.MSD_Core ? window.MSD_Core.escapeHtml : function(text) { return text; }, decodeHtmlEntities: window.MSD_Core ? window.MSD_Core.decodeHtmlEntities : function(text) { return text; }, truncateText: window.MSD_Core ? window.MSD_Core.truncateText : function(text, maxLength) { return text; }, getDefaultFavicon: window.MSD_Core ? window.MSD_Core.getDefaultFavicon : function() { return ''; }, getDefaultAvatar: window.MSD_Core ? window.MSD_Core.getDefaultAvatar : function() { return ''; }, formatNewsDate: window.MSD_Core ? window.MSD_Core.formatNewsDate : function(date) { return date; }, getUserStatusClass: window.MSD_Core ? window.MSD_Core.getUserStatusClass : function(status) { return status; }, getUserStatusLabel: window.MSD_Core ? window.MSD_Core.getUserStatusLabel : function(status) { return status; }, getRegistrationLabel: window.MSD_Core ? window.MSD_Core.getRegistrationLabel : function(reg) { return reg; }, getStorageStatusClass: window.MSD_Core ? window.MSD_Core.getStorageStatusClass : function(status) { return status; } }; window.MSD_Widgets = MSD_Widgets; MSD_Widgets.init(); });