PHP Classes

File: assets/js/admin.js

Recommend this page to a friend!
  Packages of Abed Nego Ragil Putra   The Mulia Smart Test Plugin for Wordpress   assets/js/admin.js   Download  
File: assets/js/admin.js
Role: Auxiliary data
Content type: text/plain
Description: Auxiliary data
Class: The Mulia Smart Test Plugin for Wordpress
Show and process quizes in a WordPress site
Author: By
Last change:
Date: 3 months ago
Size: 33,094 bytes
 

Contents

Class file image Download
jQuery(document).ready(function($) { 'use strict'; let questionIndex = $('.quicktestwp-question-item').length; // Save test $('#quicktestwp-test-form').on('submit', function(e) { e.preventDefault(); // Get selected roles const allowedRoles = []; $('input[name="allowed_roles[]"]:checked').each(function() { allowedRoles.push($(this).val()); }); const formData = { action: 'quicktestwp_save_test', nonce: $('#quicktestwp_nonce').val(), test_id: $('#test_id').val(), title: $('#test_title').val(), description: $('#test_description').val(), time_limit: $('#test_time_limit').val() || 0, allowed_roles: JSON.stringify(allowedRoles) }; $.ajax({ url: ajaxurl, type: 'POST', data: formData, success: function(response) { if (response.success) { QTestPopup.success('Test saved successfully! You can now add questions.', function() { if (formData.test_id == 0) { // Reload page with test_id to show question form window.location.href = 'admin.php?page=quicktestwp-new&test_id=' + response.data.test_id; } else { // Update hidden field $('#test_id').val(response.data.test_id); // Show question section if hidden if ($('#quicktestwp-questions-list').length === 0) { location.reload(); } } }); } else { QTestPopup.error(response.data.message || 'Failed to save test'); } }, error: function(xhr, status, error) { QTestPopup.error('An error occurred. Please try again. Error: ' + error); } }); }); // Add question $('#quicktestwp-add-question').on('click', function() { const template = $('#quicktestwp-question-template').html(); const newQuestion = $(template.replace(/\{\{INDEX\}\}/g, questionIndex)); newQuestion.find('[data-question-id]').attr('data-question-id', 0); newQuestion.find('[data-index]').attr('data-index', questionIndex); newQuestion.find('.question-number').text(questionIndex + 1); // Update IDs to be unique const uniqueId = 'new_' + questionIndex; newQuestion.find('textarea, input, select, label').each(function() { const $this = $(this); const id = $this.attr('id'); const forAttr = $this.attr('for'); if (id) { // Replace all occurrences of _0 with uniqueId, handling all ID patterns let newId = id; // Replace specific patterns first newId = newId.replace(/question_text_0/g, 'question_text_' + uniqueId); newId = newId.replace(/option_a_0/g, 'option_a_' + uniqueId); newId = newId.replace(/option_b_0/g, 'option_b_' + uniqueId); newId = newId.replace(/option_c_0/g, 'option_c_' + uniqueId); newId = newId.replace(/option_d_0/g, 'option_d_' + uniqueId); newId = newId.replace(/correct_answer_0/g, 'correct_answer_' + uniqueId); newId = newId.replace(/correct_answer_sa_0/g, 'correct_answer_sa_' + uniqueId); newId = newId.replace(/correct_answer_tf_0/g, 'correct_answer_tf_' + uniqueId); newId = newId.replace(/question_order_0/g, 'question_order_' + uniqueId); newId = newId.replace(/question_type_0/g, 'question_type_' + uniqueId); // Fallback: replace _0 at the end if not already replaced if (newId === id && id.endsWith('_0')) { newId = id.replace(/_0$/, '_' + uniqueId); } $this.attr('id', newId); } if (forAttr) { // Update 'for' attribute in labels let newFor = forAttr; newFor = newFor.replace(/question_text_0/g, 'question_text_' + uniqueId); newFor = newFor.replace(/option_a_0/g, 'option_a_' + uniqueId); newFor = newFor.replace(/option_b_0/g, 'option_b_' + uniqueId); newFor = newFor.replace(/option_c_0/g, 'option_c_' + uniqueId); newFor = newFor.replace(/option_d_0/g, 'option_d_' + uniqueId); newFor = newFor.replace(/correct_answer_0/g, 'correct_answer_' + uniqueId); newFor = newFor.replace(/correct_answer_sa_0/g, 'correct_answer_sa_' + uniqueId); newFor = newFor.replace(/correct_answer_tf_0/g, 'correct_answer_tf_' + uniqueId); newFor = newFor.replace(/question_order_0/g, 'question_order_' + uniqueId); newFor = newFor.replace(/question_type_0/g, 'question_type_' + uniqueId); if (newFor === forAttr && forAttr.endsWith('_0')) { newFor = forAttr.replace(/_0$/, '_' + uniqueId); } $this.attr('for', newFor); } }); $('#quicktestwp-questions-list').append(newQuestion); questionIndex++; // Initialize image upload for new question initImageUpload(newQuestion); // Initialize question type handler for new question newQuestion.find('.quicktestwp-question-type').trigger('change'); // Scroll to new question $('html, body').animate({ scrollTop: newQuestion.offset().top - 100 }, 500); }); // Handle question type change $(document).on('change', '.quicktestwp-question-type', function() { const questionItem = $(this).closest('.quicktestwp-question-item'); const questionType = $(this).val(); const optionsContainer = questionItem.find('.quicktestwp-options-container'); // Hide all option containers optionsContainer.hide(); // Show relevant option container const activeContainer = questionItem.find('.quicktestwp-options-container[data-question-type="' + questionType + '"]'); activeContainer.show(); // Update required attributes if (questionType === 'multiple_choice') { questionItem.find('.quicktestwp-option-row input').prop('required', true); questionItem.find('.quicktestwp-correct-answer-row select').prop('required', true); questionItem.find('.quicktestwp-options-container[data-question-type="true_false"] input, .quicktestwp-options-container[data-question-type="short_answer"] input').prop('required', false); } else if (questionType === 'true_false') { questionItem.find('.quicktestwp-option-row input').prop('required', false); questionItem.find('.quicktestwp-options-container[data-question-type="true_false"] select[name="correct_answer"]').prop('required', true); questionItem.find('.quicktestwp-options-container[data-question-type="multiple_choice"] select, .quicktestwp-options-container[data-question-type="short_answer"] input').prop('required', false); } else if (questionType === 'short_answer') { questionItem.find('.quicktestwp-option-row input').prop('required', false); questionItem.find('.quicktestwp-options-container[data-question-type="short_answer"] input[name="correct_answer"]').prop('required', true); questionItem.find('.quicktestwp-options-container[data-question-type="multiple_choice"] select, .quicktestwp-options-container[data-question-type="true_false"] select').prop('required', false); } }); // Initialize question type on page load $('.quicktestwp-question-type').each(function() { $(this).trigger('change'); }); // Save question $(document).on('click', '.quicktestwp-save-question', function() { const questionItem = $(this).closest('.quicktestwp-question-item'); const questionId = questionItem.data('question-id'); const testId = $('#test_id').val(); const questionType = questionItem.find('.quicktestwp-question-type').val(); let correctAnswer = ''; if (questionType === 'multiple_choice') { correctAnswer = questionItem.find('.quicktestwp-correct-answer-row select[name="correct_answer"]').val() || ''; } else if (questionType === 'true_false') { correctAnswer = questionItem.find('[data-question-type="true_false"] select[name="correct_answer"]').val() || ''; } else if (questionType === 'short_answer') { // For short_answer, find the input in the short_answer container // Try multiple methods to ensure we find it // Method 1: Find by ID pattern (most reliable for existing questions) const qId = questionItem.data('question-id'); if (qId && qId > 0) { const idInput = questionItem.find('#correct_answer_sa_' + qId); if (idInput.length > 0) { correctAnswer = $.trim(idInput.val()) || ''; } } // Method 2: Find any input with ID containing "correct_answer_sa" (for new questions or if ID method failed) if (!correctAnswer) { questionItem.find('input').each(function() { const $input = $(this); const id = $input.attr('id') || ''; if (id.indexOf('correct_answer_sa') >= 0) { const val = $.trim($input.val()); // Accept any value, even if it's "0" (but not empty) if (val !== '') { correctAnswer = val; return false; // break } } }); } // Method 3: Find by container and name attribute (works even if container is hidden) if (!correctAnswer) { const shortAnswerContainer = questionItem.find('.quicktestwp-options-container[data-question-type="short_answer"]'); if (shortAnswerContainer.length > 0) { const input = shortAnswerContainer.find('input[name="correct_answer"]'); if (input.length > 0) { const val = $.trim(input.val()); if (val !== '') { correctAnswer = val; } } } } // Method 4: Find all text inputs with name="correct_answer" and check container if (!correctAnswer) { questionItem.find('input[type="text"][name="correct_answer"]').each(function() { const $input = $(this); const $container = $input.closest('.quicktestwp-options-container'); if ($container.length > 0 && $container.data('question-type') === 'short_answer') { const val = $.trim($input.val()); if (val !== '') { correctAnswer = val; return false; // break } } }); } } // Validate required fields based on question type // Note: correctAnswer can be "0" which is a valid value, so we check for empty string if (questionType === 'short_answer' && (correctAnswer === '' || correctAnswer === null || correctAnswer === undefined)) { QTestPopup.error('Please enter a correct answer for short answer questions'); return; } const formData = { action: 'quicktestwp_save_question', nonce: $('#quicktestwp_nonce').val(), question_id: questionId, test_id: testId, question_type: questionType, question_text: questionItem.find('[name="question_text"]').val(), question_image: questionItem.find('.quicktestwp-image-url').val(), option_a: questionItem.find('[name="option_a"]').val() || '', option_b: questionItem.find('[name="option_b"]').val() || '', option_c: questionItem.find('[name="option_c"]').val() || '', option_d: questionItem.find('[name="option_d"]').val() || '', correct_answer: correctAnswer, question_order: questionItem.find('[name="question_order"]').val() || 0 }; $.ajax({ url: ajaxurl, type: 'POST', data: formData, success: function(response) { if (response.success) { // Show success message const statusSpan = questionItem.find('.quicktestwp-save-status'); statusSpan.show().fadeOut(3000); // Update question ID if new if (questionId == 0) { const newQuestionId = response.data.question_id; questionItem.attr('data-question-id', newQuestionId); questionItem.find('[data-question-id]').attr('data-question-id', newQuestionId); questionItem.find('.quicktestwp-delete-question').attr('data-question-id', newQuestionId); // Update all IDs in the question item to use the new question ID questionItem.find('input, select, textarea, label').each(function() { const $el = $(this); const id = $el.attr('id'); const forAttr = $el.attr('for'); if (id) { // Replace patterns like _0, _new_X, etc. with new question ID let newId = id; // Handle specific patterns first if (id.indexOf('_0') >= 0) { newId = id.replace(/_0/g, '_' + newQuestionId); } else if (id.indexOf('_new_') >= 0) { newId = id.replace(/_new_\d+/g, '_' + newQuestionId); } // Also handle patterns like correct_answer_sa_0 if (id.indexOf('correct_answer_sa_0') >= 0) { newId = id.replace(/correct_answer_sa_0/g, 'correct_answer_sa_' + newQuestionId); } if (newId !== id) { $el.attr('id', newId); } } if (forAttr) { let newFor = forAttr; if (forAttr.indexOf('_0') >= 0) { newFor = forAttr.replace(/_0/g, '_' + newQuestionId); } else if (forAttr.indexOf('_new_') >= 0) { newFor = forAttr.replace(/_new_\d+/g, '_' + newQuestionId); } // Also handle patterns like correct_answer_sa_0 if (forAttr.indexOf('correct_answer_sa_0') >= 0) { newFor = forAttr.replace(/correct_answer_sa_0/g, 'correct_answer_sa_' + newQuestionId); } if (newFor !== forAttr) { $el.attr('for', newFor); } } }); } } else { QTestPopup.error(response.data.message || 'Failed to save question'); } }, error: function(xhr, status, error) { QTestPopup.error('An error occurred. Please try again. Error: ' + error); } }); }); // Delete question $(document).on('click', '.quicktestwp-delete-question', function() { const questionId = parseInt($(this).data('question-id'), 10); const questionItem = $(this).closest('.quicktestwp-question-item'); QTestPopup.confirm('Are you sure you want to delete this question?', function(confirmed) { if (!confirmed) { return; } if (questionId == 0 || isNaN(questionId)) { questionItem.remove(); return; } $.ajax({ url: ajaxurl, type: 'POST', data: { action: 'quicktestwp_delete_question', nonce: $('#quicktestwp_nonce').val(), question_id: questionId }, success: function(response) { if (response.success) { questionItem.fadeOut(300, function() { $(this).remove(); }); } else { QTestPopup.error(response.data.message || 'Failed to delete question'); } }, error: function(xhr, status, error) { let errorMessage = 'An error occurred. Please try again.'; if (xhr.responseJSON && xhr.responseJSON.data && xhr.responseJSON.data.message) { errorMessage = xhr.responseJSON.data.message; } else if (error) { errorMessage += ' Error: ' + error; } QTestPopup.error(errorMessage); } }); }); }); // Delete test $(document).on('click', '.quicktestwp-delete-test', function(e) { e.preventDefault(); const testId = $(this).data('test-id'); QTestPopup.confirm('Are you sure you want to delete this test? All questions will also be deleted. This action cannot be undone.', function(confirmed) { if (!confirmed) { return; } $.ajax({ url: ajaxurl, type: 'POST', data: { action: 'quicktestwp_delete_test', nonce: $('#quicktestwp_nonce').val(), test_id: testId }, success: function(response) { if (response.success) { QTestPopup.success('Test deleted successfully!', function() { location.reload(); }); } else { QTestPopup.error(response.data.message || 'Failed to delete test'); } }, error: function(xhr, status, error) { QTestPopup.error('An error occurred. Please try again. Error: ' + error); } }); }); }); // Image upload function initImageUpload(container) { container.find('.quicktestwp-upload-image').on('click', function(e) { e.preventDefault(); const button = $(this); const imageUrlInput = button.siblings('.quicktestwp-image-url'); const imagePreview = button.siblings('.quicktestwp-image-preview'); const removeButton = button.siblings('.quicktestwp-remove-image'); const mediaUploader = wp.media({ title: 'Select Question Image', button: { text: 'Use this image' }, multiple: false }); mediaUploader.on('select', function() { const attachment = mediaUploader.state().get('selection').first().toJSON(); imageUrlInput.val(attachment.url); imagePreview.html('<img src="' + attachment.url + '" style="max-width: 300px; display: block; margin-bottom: 10px;">'); removeButton.show(); }); mediaUploader.open(); }); container.find('.quicktestwp-remove-image').on('click', function(e) { e.preventDefault(); const button = $(this); const imageUrlInput = button.siblings('.quicktestwp-image-url'); const imagePreview = button.siblings('.quicktestwp-image-preview'); imageUrlInput.val(''); imagePreview.html(''); button.hide(); }); } // Initialize image upload for existing questions $('.quicktestwp-question-item').each(function() { initImageUpload($(this)); }); // Copy shortcode button $(document).on('click', '.quicktestwp-copy-shortcode', function() { const shortcode = $(this).data('shortcode'); const temp = $('<textarea>'); $('body').append(temp); temp.val(shortcode).select(); document.execCommand('copy'); temp.remove(); // Show feedback const button = $(this); const originalText = button.text(); button.text('Copied!').css('background-color', '#46b450').css('color', '#fff'); setTimeout(function() { button.text(originalText).css('background-color', '').css('color', ''); }, 2000); }); // Send email button (Results page) $(document).on('click', '.quicktestwp-send-email', function() { const button = $(this); const resultId = button.data('result-id'); const email = button.data('email'); // Disable button button.prop('disabled', true); $.ajax({ url: ajaxurl, type: 'POST', data: { action: 'quicktestwp_resend_email', nonce: $('#quicktestwp_nonce').val(), result_id: resultId }, success: function(response) { if (response.success) { QTestPopup.success(response.data.message || 'Email sent successfully!'); } else { QTestPopup.error(response.data.message || 'Failed to send email'); } }, error: function(xhr, status, error) { QTestPopup.error('An error occurred. Please try again. Error: ' + error); }, complete: function() { // Re-enable button button.prop('disabled', false); } }); }); // Delete result button (Results page) $(document).on('click', '.quicktestwp-delete-result', function() { const button = $(this); const resultId = button.data('result-id'); const row = button.closest('tr'); QTestPopup.confirm('Are you sure you want to delete this result? This action cannot be undone.', function(confirmed) { if (!confirmed) { return; } // Disable button button.prop('disabled', true); $.ajax({ url: ajaxurl, type: 'POST', data: { action: 'quicktestwp_delete_result', nonce: $('#quicktestwp_nonce').val(), result_id: resultId }, success: function(response) { if (response.success) { QTestPopup.success('Result deleted successfully!', function() { row.fadeOut(300, function() { $(this).remove(); }); }); } else { QTestPopup.error(response.data.message || 'Failed to delete result'); button.prop('disabled', false); } }, error: function(xhr, status, error) { QTestPopup.error('An error occurred. Please try again. Error: ' + error); button.prop('disabled', false); } }); }); }); // Import questions form $('#quicktestwp-import-form').on('submit', function(e) { e.preventDefault(); const testId = $('#import_test_id').val(); const fileInput = $('#import_csv_file')[0]; if (!testId) { QTestPopup.error('Please select a test'); return; } if (!fileInput.files || fileInput.files.length === 0) { QTestPopup.error('Please select a CSV file'); return; } const formData = new FormData(); formData.append('action', 'quicktestwp_import_questions'); formData.append('nonce', $('#quicktestwp_nonce').val()); formData.append('test_id', testId); formData.append('csv_file', fileInput.files[0]); // Show loading const submitBtn = $(this).find('button[type="submit"]'); const originalText = submitBtn.text(); submitBtn.prop('disabled', true).text('Importing...'); $.ajax({ url: ajaxurl, type: 'POST', data: formData, processData: false, contentType: false, success: function(response) { if (response.success) { QTestPopup.success(response.data.message, function() { if (response.data.imported > 0) { // Redirect to test edit page window.location.href = 'admin.php?page=quicktestwp-new&test_id=' + testId; } }); } else { QTestPopup.error(response.data.message || 'Failed to import questions'); } }, error: function(xhr, status, error) { QTestPopup.error('An error occurred. Please try again. Error: ' + error); }, complete: function() { submitBtn.prop('disabled', false).text(originalText); } }); }); // Sequence form $('#quicktestwp-sequence-form').on('submit', function(e) { e.preventDefault(); const formData = { action: 'quicktestwp_save_sequence', nonce: $('#quicktestwp_nonce').val(), sequence_id: $('#sequence_id').val(), title: $('#sequence_title').val(), description: $('#sequence_description').val() }; $.ajax({ url: ajaxurl, type: 'POST', data: formData, success: function(response) { if (response.success) { QTestPopup.success('Sequence saved successfully!', function() { if (formData.sequence_id == 0) { window.location.href = 'admin.php?page=quicktestwp-sequences&sequence_id=' + response.data.sequence_id; } else { location.reload(); } }); } else { QTestPopup.error(response.data.message || 'Failed to save sequence'); } }, error: function(xhr, status, error) { QTestPopup.error('An error occurred. Please try again. Error: ' + error); } }); }); // Add test to sequence $('#quicktestwp-add-sequence-test').on('click', function() { const testId = $('#add_test_id').val(); const testOrder = $('#add_test_order').val(); const autoContinue = $('#add_auto_continue').is(':checked') ? 1 : 0; const sequenceId = $('#sequence_id').val(); if (!testId) { QTestPopup.error('Please select a test'); return; } if (!sequenceId) { QTestPopup.error('Please save the sequence first'); return; } $.ajax({ url: ajaxurl, type: 'POST', data: { action: 'quicktestwp_add_sequence_test', nonce: $('#quicktestwp_nonce').val(), sequence_id: sequenceId, test_id: testId, test_order: testOrder, auto_continue: autoContinue }, success: function(response) { if (response.success) { QTestPopup.success('Test added to sequence!', function() { location.reload(); }); } else { QTestPopup.error(response.data.message || 'Failed to add test to sequence'); } }, error: function(xhr, status, error) { QTestPopup.error('An error occurred. Please try again. Error: ' + error); } }); }); // Remove test from sequence $(document).on('click', '.quicktestwp-remove-sequence-test', function() { const sequenceTestId = parseInt($(this).data('sequence-test-id'), 10); const item = $(this).closest('.quicktestwp-sequence-test-item'); if (isNaN(sequenceTestId) || sequenceTestId <= 0) { QTestPopup.error('Invalid sequence test ID'); return; } QTestPopup.confirm('Are you sure you want to remove this test from the sequence?', function(confirmed) { if (!confirmed) { return; } $.ajax({ url: ajaxurl, type: 'POST', data: { action: 'quicktestwp_remove_sequence_test', nonce: $('#quicktestwp_nonce').val(), sequence_test_id: sequenceTestId }, success: function(response) { if (response.success) { item.fadeOut(300, function() { $(this).remove(); }); } else { QTestPopup.error(response.data.message || 'Failed to remove test from sequence'); } }, error: function(xhr, status, error) { let errorMessage = 'An error occurred. Please try again.'; if (xhr.responseJSON && xhr.responseJSON.data && xhr.responseJSON.data.message) { errorMessage = xhr.responseJSON.data.message; } else if (error) { errorMessage += ' Error: ' + error; } QTestPopup.error(errorMessage); } }); }); }); // Delete sequence $(document).on('click', '.quicktestwp-delete-sequence', function() { const sequenceId = $(this).data('sequence-id'); QTestPopup.confirm('Are you sure you want to delete this sequence? All tests in the sequence will be removed. This action cannot be undone.', function(confirmed) { if (!confirmed) { return; } $.ajax({ url: ajaxurl, type: 'POST', data: { action: 'quicktestwp_delete_sequence', nonce: $('#quicktestwp_nonce').val(), sequence_id: sequenceId }, success: function(response) { if (response.success) { QTestPopup.success('Sequence deleted successfully!', function() { location.reload(); }); } else { QTestPopup.error(response.data.message || 'Failed to delete sequence'); } }, error: function(xhr, status, error) { QTestPopup.error('An error occurred. Please try again. Error: ' + error); } }); }); }); });